Initial commit

This commit is contained in:
Martin Felis
2021-11-11 21:22:24 +01:00
commit b78045ffe7
812 changed files with 421882 additions and 0 deletions
+440
View File
@@ -0,0 +1,440 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_IO_ARCHIVE_H_
#define OZZ_OZZ_BASE_IO_ARCHIVE_H_
// Provides input (IArchive) and output (OArchive) serialization containers.
// Archive are similar to c++ iostream. Data can be saved to a OArchive with
// the << operator, or loaded from a IArchive with the >> operator.
// Primitive data types are simply saved/loaded to/from archives, while struct
// and class are saved/loaded through Save/Load intrusive or non-intrusive
// functions:
// - The intrusive function prototypes are "void Save(ozz::io::OArchive*) const"
// and "void Load(ozz::io::IArchive*)".
// - The non-intrusive functions allow to work on arrays of objects. They must
// be implemented in ozz::io namespace, by specializing the following template
// struct:
// template <typename _Ty>
// struct Extern {
// static void Save(OArchive& _archive, const _Ty* _ty, size_t _count);
// static void Load(IArchive& _archive, _Ty* _ty, size_t _count,
// uint32_t _version);
// };
//
// Arrays of struct/class or primitive types can be saved/loaded with the
// helper function ozz::io::MakeArray() that is then streamed in or out using
// << and >> archive operators: archive << ozz::io::MakeArray(my_array, count);
//
// Versioning can be done using OZZ_IO_TYPE_VERSION macros. Type version
// is saved in the OArchive, and is given back to Load functions to allow to
// manually handle version modifications. Versioning can be disabled using
// OZZ_IO_TYPE_NOT_VERSIONABLE like macros. It can not be re-enabled afterward.
//
// Objects can be assigned a tag using OZZ_IO_TYPE_TAG macros. A tag allows to
// check the type of the next object to read from an archive. An automatic
// assertion check is performed for each object that has a tag. It can also be
// done manually to ensure an archive has the expected content.
//
// Endianness (big-endian or little-endian) can be specified while constructing
// an output archive (ozz::io::OArchive). Input archives automatically handle
// endianness conversion if the native platform endian mode differs from the
// archive one.
//
// IArchive and OArchive expect valid streams as argument, respectively opened
// for reading and writing. Archives do NOT perform error detection while
// reading or writing. All errors are considered programming errors. This leads
// to the following assertions on the user side:
// - When writing: the stream must be big (or grow-able) enough to support the
// data being written.
// - When reading: Stream's tell (position in the stream) must match the object
// being read. To help with this requirement, archives provide a tag mechanism
// that allows to check the tag (ie the type) of the next object to read. Stream
// integrity, like data corruption or file truncation, must also be validated on
// the user side.
#include "ozz/base/endianness.h"
#include "ozz/base/io/stream.h"
#include "ozz/base/platform.h"
#include "ozz/base/span.h"
#include <stdint.h>
#include <cassert>
#include "ozz/base/io/archive_traits.h"
namespace ozz {
namespace io {
namespace internal {
// Defines Tagger helper object struct.
// The boolean template argument is used to automatically select a template
// specialization, whether _Ty has a tag or not.
template <typename _Ty,
bool _HasTag = internal::Tag<const _Ty>::kTagLength != 0>
struct Tagger;
} // namespace internal
// Implements output archive concept used to save/serialize data from a Stream.
// The output endianness mode is set at construction time. It is written to the
// stream to allow the IArchive to perform the required conversion to the native
// endianness mode while reading.
class OArchive {
public:
// Constructs an output archive from the Stream _stream that must be valid
// and opened for writing.
explicit OArchive(Stream* _stream,
Endianness _endianness = GetNativeEndianness());
// Returns true if an endian swap is required while writing.
bool endian_swap() const { return endian_swap_; }
// Saves _size bytes of binary data from _data.
size_t SaveBinary(const void* _data, size_t _size) {
return stream_->Write(_data, _size);
}
// Class type saving.
template <typename _Ty>
void operator<<(const _Ty& _ty) {
internal::Tagger<const _Ty>::Write(*this);
SaveVersion<_Ty>();
Extern<_Ty>::Save(*this, &_ty, 1);
}
// Primitive type saving.
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
void operator<<(_type _v) { \
_type v = endian_swap_ ? EndianSwapper<_type>::Swap(_v) : _v; \
OZZ_IF_DEBUG(size_t size =) stream_->Write(&v, sizeof(v)); \
assert(size == sizeof(v)); \
}
OZZ_IO_PRIMITIVE_TYPE(char)
OZZ_IO_PRIMITIVE_TYPE(int8_t)
OZZ_IO_PRIMITIVE_TYPE(uint8_t)
OZZ_IO_PRIMITIVE_TYPE(int16_t)
OZZ_IO_PRIMITIVE_TYPE(uint16_t)
OZZ_IO_PRIMITIVE_TYPE(int32_t)
OZZ_IO_PRIMITIVE_TYPE(uint32_t)
OZZ_IO_PRIMITIVE_TYPE(int64_t)
OZZ_IO_PRIMITIVE_TYPE(uint64_t)
OZZ_IO_PRIMITIVE_TYPE(bool)
OZZ_IO_PRIMITIVE_TYPE(float)
#undef OZZ_IO_PRIMITIVE_TYPE
// Returns output stream.
Stream* stream() const { return stream_; }
private:
template <typename _Ty>
void SaveVersion() {
// Compilation could fail here if the version is not defined for _Ty, or if
// the .h file containing its definition is not included by the caller of
// this function.
if (void(0), internal::Version<const _Ty>::kValue != 0) {
uint32_t version = internal::Version<const _Ty>::kValue;
*this << version;
}
}
// The output stream.
Stream* stream_;
// Endian swap state, true if a conversion is required while writing.
bool endian_swap_;
};
// Implements input archive concept used to load/de-serialize data to a Stream.
// Endianness conversions are automatically performed according to the Archive
// and the native formats.
class IArchive {
public:
// Constructs an input archive from the Stream _stream that must be opened for
// reading, at the same tell (position in the stream) as when it was passed to
// the OArchive.
explicit IArchive(Stream* _stream);
// Returns true if an endian swap is required while reading.
bool endian_swap() const { return endian_swap_; }
// Loads _size bytes of binary data to _data.
size_t LoadBinary(void* _data, size_t _size) {
return stream_->Read(_data, _size);
}
// Class type loading.
template <typename _Ty>
void operator>>(_Ty& _ty) {
// Only uses tag validation for assertions, as reading cannot fail.
OZZ_IF_DEBUG(bool valid =) internal::Tagger<const _Ty>::Validate(*this);
assert(valid && "Type tag does not match archive content.");
// Loads instance.
uint32_t version = LoadVersion<_Ty>();
Extern<_Ty>::Load(*this, &_ty, 1, version);
}
// Primitive type loading.
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
void operator>>(_type& _v) { \
_type v; \
OZZ_IF_DEBUG(size_t size =) stream_->Read(&v, sizeof(v)); \
assert(size == sizeof(v)); \
_v = endian_swap_ ? EndianSwapper<_type>::Swap(v) : v; \
}
OZZ_IO_PRIMITIVE_TYPE(char)
OZZ_IO_PRIMITIVE_TYPE(int8_t)
OZZ_IO_PRIMITIVE_TYPE(uint8_t)
OZZ_IO_PRIMITIVE_TYPE(int16_t)
OZZ_IO_PRIMITIVE_TYPE(uint16_t)
OZZ_IO_PRIMITIVE_TYPE(int32_t)
OZZ_IO_PRIMITIVE_TYPE(uint32_t)
OZZ_IO_PRIMITIVE_TYPE(int64_t)
OZZ_IO_PRIMITIVE_TYPE(uint64_t)
OZZ_IO_PRIMITIVE_TYPE(bool)
OZZ_IO_PRIMITIVE_TYPE(float)
#undef OZZ_IO_PRIMITIVE_TYPE
template <typename _Ty>
bool TestTag() {
// Only tagged types can be tested. If compilations fails here, it can
// mean the file containing tag declaration is not included.
static_assert(internal::Tag<const _Ty>::kTagLength != 0,
"Tag unknown for type.");
const int tell = stream_->Tell();
bool valid = internal::Tagger<const _Ty>::Validate(*this);
stream_->Seek(tell, Stream::kSet); // Rewinds before the tag test.
return valid;
}
// Returns input stream.
Stream* stream() const { return stream_; }
private:
template <typename _Ty>
uint32_t LoadVersion() {
uint32_t version = 0;
if (void(0), internal::Version<const _Ty>::kValue != 0) {
*this >> version;
}
return version;
}
// The input stream.
Stream* stream_;
// Endian swap state, true if a conversion is required while reading.
bool endian_swap_;
};
// Primitive type are not versionable.
OZZ_IO_TYPE_NOT_VERSIONABLE(char)
OZZ_IO_TYPE_NOT_VERSIONABLE(int8_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(uint8_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(int16_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(uint16_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(int32_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(uint32_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(int64_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(uint64_t)
OZZ_IO_TYPE_NOT_VERSIONABLE(bool)
OZZ_IO_TYPE_NOT_VERSIONABLE(float)
// Default loading and saving external implementation.
template <typename _Ty>
struct Extern {
inline static void Save(OArchive& _archive, const _Ty* _ty, size_t _count) {
for (size_t i = 0; i < _count; ++i) {
_ty[i].Save(_archive);
}
}
inline static void Load(IArchive& _archive, _Ty* _ty, size_t _count,
uint32_t _version) {
for (size_t i = 0; i < _count; ++i) {
_ty[i].Load(_archive, _version);
}
}
};
// Wrapper for dynamic array serialization.
// Must be used through ozz::io::MakeArray.
namespace internal {
template <typename _Ty>
struct Array {
OZZ_INLINE void Save(OArchive& _archive) const {
ozz::io::Extern<_Ty>::Save(_archive, array, count);
}
OZZ_INLINE void Load(IArchive& _archive, uint32_t _version) const {
ozz::io::Extern<_Ty>::Load(_archive, array, count, _version);
}
_Ty* array;
size_t count;
};
// Specialize for const _Ty which can only be saved.
template <typename _Ty>
struct Array<const _Ty> {
OZZ_INLINE void Save(OArchive& _archive) const {
ozz::io::Extern<_Ty>::Save(_archive, array, count);
}
const _Ty* array;
size_t count;
};
// Array copies version from the type it contains.
// Definition of Array of _Ty version: _Ty version.
template <typename _Ty>
struct Version<const Array<_Ty>> {
enum { kValue = Version<const _Ty>::kValue };
};
// Specializes Array Save/Load for primitive types.
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
template <> \
inline void Array<const _type>::Save(OArchive& _archive) const { \
if (_archive.endian_swap()) { \
/* Save element by element as swapping in place the whole buffer is*/ \
/* not possible.*/ \
for (size_t i = 0; i < count; ++i) { \
_archive << array[i]; \
} \
} else { \
OZZ_IF_DEBUG(size_t size =) \
_archive.SaveBinary(array, count * sizeof(_type)); \
assert(size == count * sizeof(_type)); \
} \
} \
\
template <> \
inline void Array<_type>::Save(OArchive& _archive) const { \
if (_archive.endian_swap()) { \
/* Save element by element as swapping in place the whole buffer is*/ \
/* not possible.*/ \
for (size_t i = 0; i < count; ++i) { \
_archive << array[i]; \
} \
} else { \
OZZ_IF_DEBUG(size_t size =) \
_archive.SaveBinary(array, count * sizeof(_type)); \
assert(size == count * sizeof(_type)); \
} \
} \
\
template <> \
inline void Array<_type>::Load(IArchive& _archive, uint32_t /*_version*/) \
const { \
OZZ_IF_DEBUG(size_t size =) \
_archive.LoadBinary(array, count * sizeof(_type)); \
assert(size == count * sizeof(_type)); \
if (_archive.endian_swap()) { /*Can swap in-place.*/ \
EndianSwapper<_type>::Swap(array, count); \
} \
}
OZZ_IO_PRIMITIVE_TYPE(char)
OZZ_IO_PRIMITIVE_TYPE(int8_t)
OZZ_IO_PRIMITIVE_TYPE(uint8_t)
OZZ_IO_PRIMITIVE_TYPE(int16_t)
OZZ_IO_PRIMITIVE_TYPE(uint16_t)
OZZ_IO_PRIMITIVE_TYPE(int32_t)
OZZ_IO_PRIMITIVE_TYPE(uint32_t)
OZZ_IO_PRIMITIVE_TYPE(int64_t)
OZZ_IO_PRIMITIVE_TYPE(uint64_t)
OZZ_IO_PRIMITIVE_TYPE(bool)
OZZ_IO_PRIMITIVE_TYPE(float)
#undef OZZ_IO_PRIMITIVE_TYPE
} // namespace internal
// Utility function that instantiates Array wrapper.
template <typename _Ty>
OZZ_INLINE const internal::Array<_Ty> MakeArray(_Ty* _array, size_t _count) {
const internal::Array<_Ty> array = {_array, _count};
return array;
}
template <typename _Ty>
OZZ_INLINE const internal::Array<const _Ty> MakeArray(const _Ty* _array,
size_t _count) {
const internal::Array<const _Ty> array = {_array, _count};
return array;
}
template <typename _Ty>
OZZ_INLINE const internal::Array<_Ty> MakeArray(span<_Ty> _array) {
const internal::Array<_Ty> array = {_array.data(), _array.size()};
return array;
}
template <typename _Ty>
OZZ_INLINE const internal::Array<const _Ty> MakeArray(span<const _Ty> _array) {
const internal::Array<const _Ty> array = {_array.data(), _array.size()};
return array;
}
template <typename _Ty, size_t _count>
OZZ_INLINE const internal::Array<_Ty> MakeArray(_Ty (&_array)[_count]) {
const internal::Array<_Ty> array = {_array, _count};
return array;
}
template <typename _Ty, size_t _count>
OZZ_INLINE const internal::Array<const _Ty> MakeArray(
const _Ty (&_array)[_count]) {
const internal::Array<const _Ty> array = {_array, _count};
return array;
}
namespace internal {
// Specialization of the Tagger helper for tagged types.
template <typename _Ty>
struct Tagger<_Ty, true> {
static void Write(OArchive& _archive) {
typedef internal::Tag<const _Ty> Tag;
OZZ_IF_DEBUG(size_t size =)
_archive.SaveBinary(Tag::Get(), Tag::kTagLength);
assert(size == Tag::kTagLength);
}
static bool Validate(IArchive& _archive) {
typedef internal::Tag<const _Ty> Tag;
char buf[Tag::kTagLength];
if (Tag::kTagLength != _archive.LoadBinary(buf, Tag::kTagLength)) {
return false;
}
const char* tag = Tag::Get();
size_t i = 0;
for (; i < Tag::kTagLength && buf[i] == tag[i]; ++i) {
}
return i == Tag::kTagLength;
}
};
// Specialization of the Tagger helper for types with no tag.
template <typename _Ty>
struct Tagger<_Ty, false> {
static void Write(OArchive& /*_archive*/) {}
static bool Validate(IArchive& /*_archive*/) { return true; }
};
} // namespace internal
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_IO_ARCHIVE_H_
@@ -0,0 +1,220 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_IO_ARCHIVE_TRAITS_H_
#define OZZ_OZZ_BASE_IO_ARCHIVE_TRAITS_H_
// Provides traits for customizing archive serialization properties: version,
// tag... See archive.h for more details.
#include <stdint.h>
#include <cstddef>
namespace ozz {
namespace io {
// Forward declaration of archive types.
class OArchive;
class IArchive;
// Default loading and saving external declaration.
// Those template implementations aim to be specialized at compilation time by
// non-member Load and save functions. For example the specialization of the
// Save() function for a type Type is:
// void Save(OArchive& _archive, const Extrusive* _test, size_t _count) {
// }
// The Load() function receives the version _version of type _Ty at the time the
// archive was saved.
// This uses polymorphism rather than template specialization to avoid
// including the file that contains the template definition.
//
// This default function call member _Ty::Load/Save function.
template <typename _Ty>
struct Extern;
// Declares the current (compile time) version of _type.
// This macro must be used inside namespace ozz::io.
// Syntax is: OZZ_IO_TYPE_VERSION(46, Foo).
#define OZZ_IO_TYPE_VERSION(_version, _type) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <> \
struct Version<const _type> { \
enum { kValue = _version }; \
}; \
} // internal
// Declares the current (compile time) version of a template _type.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_VERSION_T1(46, typename _T1, Foo<_T1>).
#define OZZ_IO_TYPE_VERSION_T1(_version, _arg0, ...) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <_arg0> \
struct Version<const __VA_ARGS__> { \
enum { kValue = _version }; \
}; \
} // internal
// Declares the current (compile time) version of a template _type.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_VERSION_T2(46, typename _T1, typename _T2, Foo<_T1, _T2>).
#define OZZ_IO_TYPE_VERSION_T2(_version, _arg0, _arg1, ...) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <_arg0, _arg1> \
struct Version<const __VA_ARGS__> { \
enum { kValue = _version }; \
}; \
\
} // internal
// Declares the current (compile time) version of a template _type.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_VERSION_T3(
// 46, typename _T1, typename _T2, typename _T3, Foo<_T1, _T2, _T3>).
#define OZZ_IO_TYPE_VERSION_T3(_version, _arg0, _arg1, _arg2, ...) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <_arg0, _arg1, _arg2> \
struct Version<const __VA_ARGS__> { \
enum { kValue = _version }; \
}; \
\
} // internal
// Declares the current (compile time) version of a template _type.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_VERSION_T4(
// 46, typename _T1, typename _T2, typename _T3, typename _T4,
// Foo<_T1, _T2, _T3, _T4>).
#define OZZ_IO_TYPE_VERSION_T4(_version, _arg0, _arg1, _arg2, _arg3, ...) \
static_assert(_version > 0, "Version number must be > 0"); \
namespace internal { \
template <_arg0, _arg1, _arg2, _arg3> \
struct Version<const __VA_ARGS__> { \
enum { kValue = _version }; \
}; \
} // internal
// Declares that _type is not versionable. Its version number is 0.
// Once a type has been declared not versionable, it cannot be changed without
// braking versioning.
// This macro must be used inside namespace ozz::io.
// Syntax is: OZZ_IO_TYPE_NOT_VERSIONABLE(Foo).
#define OZZ_IO_TYPE_NOT_VERSIONABLE(_type) \
namespace internal { \
template <> \
struct Version<const _type> { \
enum { kValue = 0 }; \
}; \
} // internal
// Declares that a template _type is not versionable. Its version number is 0.
// Once a type has been declared not versionable, it cannot be changed without
// braking versioning.
// This macro must be used inside namespace ozz::io.
// Syntax is:
// OZZ_IO_TYPE_NOT_VERSIONABLE_T1(typename _T1, Foo<_T1>).
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T1(_arg0, ...) \
namespace internal { \
template <_arg0> \
struct Version<const __VA_ARGS__> { \
enum { kValue = 0 }; \
}; \
} // internal
// Decline non-versionable template declaration to 2 template arguments.
// Syntax is:
// OZZ_IO_TYPE_NOT_VERSIONABLE_T2(typename _T1, typename _T2, Foo<_T1, _T2>).
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T2(_arg0, _arg1, ...) \
namespace internal { \
template <_arg0, _arg1> \
struct Version<const __VA_ARGS__> { \
enum { kValue = 0 }; \
}; \
} // internal
// Decline non-versionable template declaration to 3 template arguments.
// Syntax is:
// OZZ_IO_TYPE_NOT_VERSIONABLE_T3(
// typename _T1, typename _T2, typename _T3, Foo<_T1, _T2, _T3>).
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T3(_arg0, _arg1, _arg2, ...) \
namespace internal { \
template <_arg0, _arg1, _arg2> \
struct Version<const __VA_ARGS__> { \
enum { kValue = 0 }; \
}; \
} // internal
// Decline non-versionable template declaration to 4 template arguments.
// Syntax is:
// OZZ_IO_TYPE_NOT_VERSIONABLE_T4(
// typename _T1, typename _T2, typename _T3, typename _T4,
// Foo<_T1, _T2, _T3, _T4>).
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T4(_arg0, _arg1, _arg2, _arg3, ...) \
namespace internal { \
template <_arg0, _arg1, _arg2, _arg3> \
struct Version<const __VA_ARGS__> { \
enum { kValue = 0 }; \
}; \
} // internal
// Declares the tag of a template _type.
// A tag is a c-string that can be used to check the type (through its tag) of
// the next object to be read from an archive. If no tag is defined, then no
// check is performed.
// This macro must be used inside namespace ozz::io.
// OZZ_IO_TYPE_TAG("Foo", Foo).
#define OZZ_IO_TYPE_TAG(_tag, _type) \
namespace internal { \
template <> \
struct Tag<const _type> { \
/* Length includes null terminated character to detect partial */ \
/* tag mapping.*/ \
enum { kTagLength = OZZ_ARRAY_SIZE(_tag) }; \
static const char* Get() { return _tag; } \
}; \
} // internal
namespace internal {
// Definition of version specializable template struct.
// There's no default implementation in order to force user to define it, which
// in turn forces those who want to serialize an object to include the file that
// defines it's version. This helps with detecting issues at compile time.
template <typename _Ty>
struct Version;
// Defines default tag value, which is disabled.
template <typename _Ty>
struct Tag {
enum { kTagLength = 0 };
};
} // namespace internal
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_IO_ARCHIVE_TRAITS_H_
+189
View File
@@ -0,0 +1,189 @@
//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#ifndef OZZ_OZZ_BASE_IO_STREAM_H_
#define OZZ_OZZ_BASE_IO_STREAM_H_
// Provides Stream interface used to read/write a memory buffer or a file with
// Crt fread/fwrite/fseek/ftell like functions.
#include "ozz/base/platform.h"
#include <cstddef>
namespace ozz {
namespace io {
// Declares a stream access interface that conforms with CRT FILE API.
// This interface should be used to remap io operations.
class Stream {
public:
// Tests whether a file is opened.
virtual bool opened() const = 0;
// Reads _size bytes of data to _buffer from the stream. _buffer must be big
// enough to store _size bytes. The position indicator of the stream is
// advanced by the total amount of bytes read.
// Returns the number of bytes actually read, which may be less than _size.
virtual size_t Read(void* _buffer, size_t _size) = 0;
// Writes _size bytes of data from _buffer to the stream. The position
// indicator of the stream is advanced by the total number of bytes written.
// Returns the number of bytes actually written, which may be less than _size.
virtual size_t Write(const void* _buffer, size_t _size) = 0;
// Declares seeking origin enumeration.
enum Origin {
kCurrent, // Current position of the stream pointer.
kEnd, // End of stream.
kSet, // Beginning of stream.
};
// Sets the position indicator associated with the stream to a new position
// defined by adding _offset to a reference position specified by _origin.
// Returns a zero value if successful, otherwise returns a non-zero value.
virtual int Seek(int _offset, Origin _origin) = 0;
// Returns the current value of the position indicator of the stream.
// Returns -1 if an error occurs.
virtual int Tell() const = 0;
// Returns the current size of the stream.
virtual size_t Size() const = 0;
protected:
Stream() {}
// Required virtual destructor.
virtual ~Stream() {}
private:
Stream(const Stream&);
void operator=(const Stream&);
};
// Implements Stream of type File.
class File : public Stream {
public:
// Test if a file at path _filename exists.
// Note that this function is costly. If you aim to open the file right after,
// then open it and use File::opened() to test if it's actually existing.
static bool Exist(const char* _filename);
// Open a file at path _filename with mode * _mode, in conformance with fopen
// specifications.
// Use opened() function to test opening result.
File(const char* _filename, const char* _mode);
// Gives _file ownership to the FileStream, which will be in charge of closing
// it. _file must be nullptr or a valid std::FILE pointer.
explicit File(void* _file);
// Close the file if it is opened.
virtual ~File();
// Close the file if it is opened.
void Close();
// See Stream::opened for details.
virtual bool opened() const;
// See Stream::Read for details.
virtual size_t Read(void* _buffer, size_t _size);
// See Stream::Write for details.
virtual size_t Write(const void* _buffer, size_t _size);
// See Stream::Seek for details.
virtual int Seek(int _offset, Origin _origin);
// See Stream::Tell for details.
virtual int Tell() const;
// See Stream::Tell for details.
virtual size_t Size() const;
private:
// The CRT file pointer.
void* file_;
};
// Implements an in-memory Stream. Allows to use a memory buffer as a Stream.
// The opening mode is equivalent to fopen w+b (binary read/write).
class MemoryStream : public Stream {
public:
// Construct an empty memory stream opened in w+b mode.
MemoryStream();
// Closes the stream and deallocates memory buffer.
virtual ~MemoryStream();
// See Stream::opened for details.
virtual bool opened() const;
// See Stream::Read for details.
virtual size_t Read(void* _buffer, size_t _size);
// See Stream::Write for details.
virtual size_t Write(const void* _buffer, size_t _size);
// See Stream::Seek for details.
virtual int Seek(int _offset, Origin _origin);
// See Stream::Tell for details.
virtual int Tell() const;
// See Stream::Tell for details.
virtual size_t Size() const;
private:
// Resizes buffers size to _size bytes. If _size is less than the actual
// buffer size, then it remains unchanged.
// Returns true if the buffer can contains _size bytes.
bool Resize(size_t _size);
// Size of the buffer increment.
static const size_t kBufferSizeIncrement;
// Maximum stream size.
static const size_t kMaxSize;
// Buffer of data.
char* buffer_;
// The size of the buffer, which is greater or equal to the size of the data
// it contains (end_).
size_t alloc_size_;
// The effective size of the data in the buffer.
int end_;
// The cursor position in the buffer of data.
int tell_;
};
} // namespace io
} // namespace ozz
#endif // OZZ_OZZ_BASE_IO_STREAM_H_