mirror of https://github.com/libAthena/athena.git
Add ability to generate and specialize DNA class templates
This commit is contained in:
parent
80c945af6d
commit
62b6d6792a
931
atdna/main.cpp
931
atdna/main.cpp
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
int main(int argc, const char** argv)
|
int main(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
TESTFile file = {};
|
TESTFile<atUint32, 2> file = {};
|
||||||
file.arrCount[0] = 2;
|
file.arrCount[0] = 2;
|
||||||
file.array.push_back(42);
|
file.array.push_back(42);
|
||||||
file.array.push_back(64);
|
file.array.push_back(64);
|
||||||
|
|
|
@ -3,26 +3,29 @@
|
||||||
using namespace athena;
|
using namespace athena;
|
||||||
typedef io::DNA<Big> BigDNA;
|
typedef io::DNA<Big> BigDNA;
|
||||||
|
|
||||||
struct TESTSubFile : public BigDNA
|
enum ETest : atUint8
|
||||||
{
|
{
|
||||||
AT_DECL_DNA
|
|
||||||
enum ETest : atUint8
|
|
||||||
{
|
|
||||||
ZERO,
|
ZERO,
|
||||||
ONE,
|
ONE,
|
||||||
TWO,
|
TWO,
|
||||||
THREE
|
THREE
|
||||||
};
|
};
|
||||||
Value<ETest> varE;
|
|
||||||
|
template <ETest EVal>
|
||||||
|
struct AT_SPECIALIZE_PARMS(ETest::ZERO, ETest::ONE, ETest::TWO, ETest::THREE)
|
||||||
|
TESTSubFile : public BigDNA
|
||||||
|
{
|
||||||
|
AT_DECL_DNA
|
||||||
|
Value<ETest> varE = EVal;
|
||||||
Value<atUint32> sub1;
|
Value<atUint32> sub1;
|
||||||
Value<atUint32> sub2;
|
Value<atUint32> sub2;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TESTSubClassFile : public TESTSubFile
|
struct TESTSubClassFile : public TESTSubFile<ETest::ONE>
|
||||||
{
|
{
|
||||||
AT_DECL_DNA
|
AT_DECL_DNA
|
||||||
Value<atUint32> sub3;
|
Value<atUint32> sub3;
|
||||||
Value<atUint32> sub4;
|
Value<atUint16> sub4;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TESTSubSubClassFile : public TESTSubClassFile
|
struct TESTSubSubClassFile : public TESTSubClassFile
|
||||||
|
@ -32,11 +35,13 @@ struct TESTSubSubClassFile : public TESTSubClassFile
|
||||||
Value<atUint32> sub6;
|
Value<atUint32> sub6;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TESTFile : public BigDNA
|
template <class Var32Tp, int Var32Val>
|
||||||
|
struct AT_SPECIALIZE_PARMS(atUint16, 42, atUint32, 87, atUint32, 2)
|
||||||
|
TESTFile : public BigDNA
|
||||||
{
|
{
|
||||||
AT_DECL_DNA
|
AT_DECL_DNA
|
||||||
Value<bool> varBool;
|
Value<bool> varBool;
|
||||||
AT_OVERRIDE_RCRC32(12345678) Value<atUint32> x4_var32;
|
AT_OVERRIDE_RCRC32(12345678) Value<Var32Tp> x4_var32 = Var32Val;
|
||||||
AT_OVERRIDE_RCRC32(deadbabe) Value<atUint16> x8_var16;
|
AT_OVERRIDE_RCRC32(deadbabe) Value<atUint16> x8_var16;
|
||||||
Value<atVec3f> vec3;
|
Value<atVec3f> vec3;
|
||||||
Value<atVec4f> vec4;
|
Value<atVec4f> vec4;
|
||||||
|
@ -48,25 +53,32 @@ struct TESTFile : public BigDNA
|
||||||
Value<atUint32> nestSub2;
|
Value<atUint32> nestSub2;
|
||||||
} nestedSubFile;
|
} nestedSubFile;
|
||||||
|
|
||||||
using TESTSubFileUsing = TESTSubFile;
|
using TESTSubFileUsing = TESTSubFile<ETest::TWO>;
|
||||||
TESTSubFileUsing subFile;
|
TESTSubFileUsing subFile;
|
||||||
|
|
||||||
Align<4> align;
|
Align<4> align;
|
||||||
|
|
||||||
struct TESTExplicitSubFile : public BigDNA
|
template <class NestedTp, int NestedVal>
|
||||||
|
struct AT_SPECIALIZE_PARMS(atInt32, 36, atInt64, 96)
|
||||||
|
TESTTemplateSubFile : public BigDNA
|
||||||
{
|
{
|
||||||
AT_DECL_DNA
|
AT_DECL_DNA
|
||||||
Value<atUint32> explSub1;
|
Value<NestedTp> explSub1 = NestedVal;
|
||||||
Value<atUint32> explSub2;
|
Value<Var32Tp> explSub2 = Var32Val;
|
||||||
} explSubFile;
|
};
|
||||||
|
TESTTemplateSubFile<atInt32, 36> nestedTemplate1;
|
||||||
|
TESTTemplateSubFile<atInt64, 96> nestedTemplate2;
|
||||||
|
|
||||||
Value<atUint32, Little> arrCount[2];
|
Value<atUint32, Little> arrCount[2];
|
||||||
Vector<atUint32, DNA_COUNT(arrCount[0])> array;
|
Vector<atUint32, DNA_COUNT(arrCount[0])> array;
|
||||||
|
|
||||||
|
Value<atUint32> arrAltCount;
|
||||||
|
Vector<atUint32, DNA_COUNT(arrAltCount)> arrayAlt;
|
||||||
|
|
||||||
Seek<21, Current> seek;
|
Seek<21, Current> seek;
|
||||||
|
|
||||||
Value<atUint32> arrCount2;
|
Value<atUint32> arrCount2;
|
||||||
Vector<TESTSubFile, DNA_COUNT(arrCount[1] + arrCount2)> array2;
|
Vector<TESTSubFile<ETest::ZERO>, DNA_COUNT(arrCount[1] + arrCount2)> array2;
|
||||||
|
|
||||||
Value<atUint32> bufSz;
|
Value<atUint32> bufSz;
|
||||||
Buffer<DNA_COUNT(bufSz)> buf;
|
Buffer<DNA_COUNT(bufSz)> buf;
|
||||||
|
|
|
@ -94,6 +94,51 @@ struct DNA
|
||||||
* @brief Meta Template preventing atdna from emitting read/write implementations
|
* @brief Meta Template preventing atdna from emitting read/write implementations
|
||||||
*/
|
*/
|
||||||
struct Delete {};
|
struct Delete {};
|
||||||
|
|
||||||
|
/* Bring fundamental operations into DNA subclasses for easier per-op overrides */
|
||||||
|
using Read = athena::io::Read<PropType::None>;
|
||||||
|
using Write = athena::io::Write<PropType::None>;
|
||||||
|
using BinarySize = athena::io::BinarySize<PropType::None>;
|
||||||
|
using PropCount = athena::io::PropCount<PropType::None>;
|
||||||
|
using ReadYaml = athena::io::ReadYaml<PropType::None>;
|
||||||
|
using WriteYaml = athena::io::WriteYaml<PropType::None>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Virtual DNA wrapper for subclasses that utilize virtual method calls
|
||||||
|
* @tparam DNAE Default-endianness for contained DNA values
|
||||||
|
*
|
||||||
|
* Typically, static template-based DNA resolution is sufficient; however, formats
|
||||||
|
* with a tree of variously-typed data structures would benefit from having a vtable.
|
||||||
|
*
|
||||||
|
* Note: It's not recommended to implement these directly. Instead, use the AT_DECL_DNA or
|
||||||
|
* AT_DECL_EXPLCIT_DNA macro in the subclasses. Specializing the Enumerate method
|
||||||
|
* is the proper way to override individual I/O operations. Owners of the virtualized
|
||||||
|
* subclass will typically use a unique_ptr to reference the data; specializing their own
|
||||||
|
* Enumerate methods as such:
|
||||||
|
*
|
||||||
|
* template <> void MySubclass::Enumerate<Read>(typename Read::StreamT& r)
|
||||||
|
* { (Do stuff with `r`) }
|
||||||
|
*/
|
||||||
|
template <Endian DNAE>
|
||||||
|
struct DNAV : DNA<DNAE>
|
||||||
|
{
|
||||||
|
virtual ~DNAV() = default;
|
||||||
|
virtual void read(athena::io::IStreamReader& r) = 0;
|
||||||
|
virtual void write(athena::io::IStreamWriter& w) const = 0;
|
||||||
|
virtual void binarySize(size_t& s) const = 0;
|
||||||
|
virtual const char* DNATypeV() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <Endian DNAE>
|
||||||
|
struct DNAVYaml : DNAV<DNAE>
|
||||||
|
{
|
||||||
|
virtual ~DNAVYaml() = default;
|
||||||
|
virtual void read(athena::io::IStreamReader& r) = 0;
|
||||||
|
virtual void write(athena::io::IStreamWriter& w) const = 0;
|
||||||
|
virtual void binarySize(size_t& s) const = 0;
|
||||||
|
virtual void read(athena::io::YAMLDocReader& r) = 0;
|
||||||
|
virtual void write(athena::io::YAMLDocWriter& w) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Macro to supply count variable to atdna and mute it for other compilers */
|
/** Macro to supply count variable to atdna and mute it for other compilers */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,10 +10,24 @@
|
||||||
namespace athena::io
|
namespace athena::io
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static inline const char* __GetDNAName(const T& dna,
|
||||||
|
typename std::enable_if_t<athena::io::__IsDNAVRecord<T>()>* = 0)
|
||||||
|
{
|
||||||
|
return dna.DNATypeV();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static inline const char* __GetDNAName(const T& dna,
|
||||||
|
typename std::enable_if_t<!athena::io::__IsDNAVRecord<T>()>* = 0)
|
||||||
|
{
|
||||||
|
return dna.DNAType();
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
static inline std::string ToYAMLString(const T& dna)
|
static inline std::string ToYAMLString(const T& dna)
|
||||||
{
|
{
|
||||||
YAMLDocWriter docWriter(dna.DNAType());
|
YAMLDocWriter docWriter(__GetDNAName(dna));
|
||||||
|
|
||||||
std::string res;
|
std::string res;
|
||||||
yaml_emitter_set_output(docWriter.getEmitter(), (yaml_write_handler_t*)YAMLStdStringWriter, &res);
|
yaml_emitter_set_output(docWriter.getEmitter(), (yaml_write_handler_t*)YAMLStdStringWriter, &res);
|
||||||
|
@ -52,7 +66,7 @@ static inline bool ValidateFromYAMLString(std::string_view str)
|
||||||
template <class T>
|
template <class T>
|
||||||
static inline bool ToYAMLStream(const T& dna, athena::io::IStreamWriter& fout)
|
static inline bool ToYAMLStream(const T& dna, athena::io::IStreamWriter& fout)
|
||||||
{
|
{
|
||||||
YAMLDocWriter docWriter(dna.DNAType());
|
YAMLDocWriter docWriter(__GetDNAName(dna));
|
||||||
|
|
||||||
yaml_emitter_set_unicode(docWriter.getEmitter(), true);
|
yaml_emitter_set_unicode(docWriter.getEmitter(), true);
|
||||||
yaml_emitter_set_width(docWriter.getEmitter(), -1);
|
yaml_emitter_set_width(docWriter.getEmitter(), -1);
|
||||||
|
@ -65,12 +79,12 @@ template <class T>
|
||||||
static inline bool ToYAMLStream(const T& dna, athena::io::IStreamWriter& fout,
|
static inline bool ToYAMLStream(const T& dna, athena::io::IStreamWriter& fout,
|
||||||
void(T::*fn)(YAMLDocWriter& out)const)
|
void(T::*fn)(YAMLDocWriter& out)const)
|
||||||
{
|
{
|
||||||
YAMLDocWriter docWriter(dna.DNAType());
|
YAMLDocWriter docWriter(__GetDNAName(dna));
|
||||||
|
|
||||||
yaml_emitter_set_unicode(docWriter.getEmitter(), true);
|
yaml_emitter_set_unicode(docWriter.getEmitter(), true);
|
||||||
yaml_emitter_set_width(docWriter.getEmitter(), -1);
|
yaml_emitter_set_width(docWriter.getEmitter(), -1);
|
||||||
|
|
||||||
(dna->*fn)(docWriter);
|
(dna.*fn)(docWriter);
|
||||||
return docWriter.finish(&fout);
|
return docWriter.finish(&fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +105,7 @@ static inline bool FromYAMLStream(T& dna, athena::io::IStreamReader& fin,
|
||||||
YAMLDocReader docReader;
|
YAMLDocReader docReader;
|
||||||
if (!docReader.parse(&fin))
|
if (!docReader.parse(&fin))
|
||||||
return false;
|
return false;
|
||||||
(dna->*fn)(docReader);
|
(dna.*fn)(docReader);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +113,7 @@ template <class T, typename NameT>
|
||||||
static inline bool MergeToYAMLFile(const T& dna, const NameT& filename)
|
static inline bool MergeToYAMLFile(const T& dna, const NameT& filename)
|
||||||
{
|
{
|
||||||
athena::io::FileReader r(filename);
|
athena::io::FileReader r(filename);
|
||||||
YAMLDocWriter docWriter(dna.DNAType(), r.isOpen() ? &r : nullptr);
|
YAMLDocWriter docWriter(__GetDNAName(dna), r.isOpen() ? &r : nullptr);
|
||||||
r.close();
|
r.close();
|
||||||
|
|
||||||
dna.write(docWriter);
|
dna.write(docWriter);
|
||||||
|
|
|
@ -137,6 +137,27 @@ enum Endian
|
||||||
Little,
|
Little,
|
||||||
Big
|
Big
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace io
|
||||||
|
{
|
||||||
|
template <Endian DNAE>
|
||||||
|
struct DNA;
|
||||||
|
template <Endian DNAE>
|
||||||
|
struct DNAV;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static inline constexpr bool __IsDNARecord()
|
||||||
|
{
|
||||||
|
return std::is_base_of_v<DNA<Endian::Big>, T> ||
|
||||||
|
std::is_base_of_v<DNA<Endian::Little>, T>;
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
static inline constexpr bool __IsDNAVRecord()
|
||||||
|
{
|
||||||
|
return std::is_base_of_v<DNAV<Endian::Big>, T> ||
|
||||||
|
std::is_base_of_v<DNAV<Endian::Little>, T>;
|
||||||
|
}
|
||||||
|
}
|
||||||
} // Athena
|
} // Athena
|
||||||
|
|
||||||
typedef void (*atEXCEPTION_HANDLER)(athena::error::Level level, const char* file, const char* function, int line,
|
typedef void (*atEXCEPTION_HANDLER)(athena::error::Level level, const char* file, const char* function, int line,
|
||||||
|
|
|
@ -48,7 +48,8 @@ public:
|
||||||
RecordRAII enterSubRecord(const char* name);
|
RecordRAII enterSubRecord(const char* name);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void enumerate(const char* name, T& record)
|
void enumerate(const char* name, T& record,
|
||||||
|
typename std::enable_if_t<__IsDNARecord<T>()>* = 0)
|
||||||
{
|
{
|
||||||
if (auto rec = enterSubRecord(name))
|
if (auto rec = enterSubRecord(name))
|
||||||
record.read(*this);
|
record.read(*this);
|
||||||
|
@ -70,10 +71,10 @@ public:
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
size_t enumerate(const char* name, std::vector<T>& vector,
|
size_t enumerate(const char* name, std::vector<T>& vector,
|
||||||
typename std::enable_if<!std::is_arithmetic<T>::value &&
|
typename std::enable_if_t<!std::is_arithmetic<T>::value &&
|
||||||
!std::is_same<T, atVec2f>::value &&
|
!std::is_same<T, atVec2f>::value &&
|
||||||
!std::is_same<T, atVec3f>::value &&
|
!std::is_same<T, atVec3f>::value &&
|
||||||
!std::is_same<T, atVec4f>::value>::type* = 0)
|
!std::is_same<T, atVec4f>::value>* = 0)
|
||||||
{
|
{
|
||||||
size_t countOut;
|
size_t countOut;
|
||||||
if (auto v = enterSubVector(name, countOut))
|
if (auto v = enterSubVector(name, countOut))
|
||||||
|
@ -92,10 +93,10 @@ public:
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
size_t enumerate(const char* name, std::vector<T>& vector,
|
size_t enumerate(const char* name, std::vector<T>& vector,
|
||||||
typename std::enable_if<std::is_arithmetic<T>::value ||
|
typename std::enable_if_t<std::is_arithmetic<T>::value ||
|
||||||
std::is_same<T, atVec2f>::value ||
|
std::is_same<T, atVec2f>::value ||
|
||||||
std::is_same<T, atVec3f>::value ||
|
std::is_same<T, atVec3f>::value ||
|
||||||
std::is_same<T, atVec4f>::value>::type* = 0)
|
std::is_same<T, atVec4f>::value>* = 0)
|
||||||
{
|
{
|
||||||
size_t countOut;
|
size_t countOut;
|
||||||
if (auto v = enterSubVector(name, countOut))
|
if (auto v = enterSubVector(name, countOut))
|
||||||
|
|
|
@ -39,7 +39,8 @@ public:
|
||||||
RecordRAII enterSubRecord(const char* name);
|
RecordRAII enterSubRecord(const char* name);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void enumerate(const char* name, T& record)
|
void enumerate(const char* name, T& record,
|
||||||
|
typename std::enable_if_t<__IsDNARecord<T>()>* = 0)
|
||||||
{
|
{
|
||||||
if (auto rec = enterSubRecord(name))
|
if (auto rec = enterSubRecord(name))
|
||||||
record.write(*this);
|
record.write(*this);
|
||||||
|
@ -61,13 +62,13 @@ public:
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void enumerate(const char* name, const std::vector<T>& vector,
|
void enumerate(const char* name, const std::vector<T>& vector,
|
||||||
typename std::enable_if<!std::is_arithmetic<T>::value &&
|
typename std::enable_if_t<!std::is_arithmetic<T>::value &&
|
||||||
!std::is_same<T, atVec2f>::value &&
|
!std::is_same<T, atVec2f>::value &&
|
||||||
!std::is_same<T, atVec3f>::value &&
|
!std::is_same<T, atVec3f>::value &&
|
||||||
!std::is_same<T, atVec4f>::value &&
|
!std::is_same<T, atVec4f>::value &&
|
||||||
!std::is_same<T, atVec2d>::value &&
|
!std::is_same<T, atVec2d>::value &&
|
||||||
!std::is_same<T, atVec3d>::value &&
|
!std::is_same<T, atVec3d>::value &&
|
||||||
!std::is_same<T, atVec4d>::value>::type* = 0)
|
!std::is_same<T, atVec4d>::value>* = 0)
|
||||||
{
|
{
|
||||||
if (auto v = enterSubVector(name))
|
if (auto v = enterSubVector(name))
|
||||||
for (const T& item : vector)
|
for (const T& item : vector)
|
||||||
|
@ -77,13 +78,13 @@ public:
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void enumerate(const char* name, const std::vector<T>& vector,
|
void enumerate(const char* name, const std::vector<T>& vector,
|
||||||
typename std::enable_if<std::is_arithmetic<T>::value ||
|
typename std::enable_if_t<std::is_arithmetic<T>::value ||
|
||||||
std::is_same<T, atVec2f>::value ||
|
std::is_same<T, atVec2f>::value ||
|
||||||
std::is_same<T, atVec3f>::value ||
|
std::is_same<T, atVec3f>::value ||
|
||||||
std::is_same<T, atVec4f>::value ||
|
std::is_same<T, atVec4f>::value ||
|
||||||
std::is_same<T, atVec2d>::value ||
|
std::is_same<T, atVec2d>::value ||
|
||||||
std::is_same<T, atVec3d>::value ||
|
std::is_same<T, atVec3d>::value ||
|
||||||
std::is_same<T, atVec4d>::value>::type* = 0)
|
std::is_same<T, atVec4d>::value>* = 0)
|
||||||
{
|
{
|
||||||
if (auto v = enterSubVector(name))
|
if (auto v = enterSubVector(name))
|
||||||
for (T item : vector)
|
for (T item : vector)
|
||||||
|
|
Loading…
Reference in New Issue