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
2367
atdna/main.cpp
2367
atdna/main.cpp
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@
|
|||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
TESTFile file = {};
|
||||
TESTFile<atUint32, 2> file = {};
|
||||
file.arrCount[0] = 2;
|
||||
file.array.push_back(42);
|
||||
file.array.push_back(64);
|
||||
|
|
|
@ -3,26 +3,29 @@
|
|||
using namespace athena;
|
||||
typedef io::DNA<Big> BigDNA;
|
||||
|
||||
struct TESTSubFile : public BigDNA
|
||||
enum ETest : atUint8
|
||||
{
|
||||
ZERO,
|
||||
ONE,
|
||||
TWO,
|
||||
THREE
|
||||
};
|
||||
|
||||
template <ETest EVal>
|
||||
struct AT_SPECIALIZE_PARMS(ETest::ZERO, ETest::ONE, ETest::TWO, ETest::THREE)
|
||||
TESTSubFile : public BigDNA
|
||||
{
|
||||
AT_DECL_DNA
|
||||
enum ETest : atUint8
|
||||
{
|
||||
ZERO,
|
||||
ONE,
|
||||
TWO,
|
||||
THREE
|
||||
};
|
||||
Value<ETest> varE;
|
||||
Value<ETest> varE = EVal;
|
||||
Value<atUint32> sub1;
|
||||
Value<atUint32> sub2;
|
||||
};
|
||||
|
||||
struct TESTSubClassFile : public TESTSubFile
|
||||
struct TESTSubClassFile : public TESTSubFile<ETest::ONE>
|
||||
{
|
||||
AT_DECL_DNA
|
||||
Value<atUint32> sub3;
|
||||
Value<atUint32> sub4;
|
||||
Value<atUint16> sub4;
|
||||
};
|
||||
|
||||
struct TESTSubSubClassFile : public TESTSubClassFile
|
||||
|
@ -32,11 +35,13 @@ struct TESTSubSubClassFile : public TESTSubClassFile
|
|||
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
|
||||
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;
|
||||
Value<atVec3f> vec3;
|
||||
Value<atVec4f> vec4;
|
||||
|
@ -48,25 +53,32 @@ struct TESTFile : public BigDNA
|
|||
Value<atUint32> nestSub2;
|
||||
} nestedSubFile;
|
||||
|
||||
using TESTSubFileUsing = TESTSubFile;
|
||||
using TESTSubFileUsing = TESTSubFile<ETest::TWO>;
|
||||
TESTSubFileUsing subFile;
|
||||
|
||||
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
|
||||
Value<atUint32> explSub1;
|
||||
Value<atUint32> explSub2;
|
||||
} explSubFile;
|
||||
Value<NestedTp> explSub1 = NestedVal;
|
||||
Value<Var32Tp> explSub2 = Var32Val;
|
||||
};
|
||||
TESTTemplateSubFile<atInt32, 36> nestedTemplate1;
|
||||
TESTTemplateSubFile<atInt64, 96> nestedTemplate2;
|
||||
|
||||
Value<atUint32, Little> arrCount[2];
|
||||
Vector<atUint32, DNA_COUNT(arrCount[0])> array;
|
||||
|
||||
Value<atUint32> arrAltCount;
|
||||
Vector<atUint32, DNA_COUNT(arrAltCount)> arrayAlt;
|
||||
|
||||
Seek<21, Current> seek;
|
||||
|
||||
Value<atUint32> arrCount2;
|
||||
Vector<TESTSubFile, DNA_COUNT(arrCount[1] + arrCount2)> array2;
|
||||
Vector<TESTSubFile<ETest::ZERO>, DNA_COUNT(arrCount[1] + arrCount2)> array2;
|
||||
|
||||
Value<atUint32> bufSz;
|
||||
Buffer<DNA_COUNT(bufSz)> buf;
|
||||
|
|
|
@ -94,6 +94,51 @@ struct DNA
|
|||
* @brief Meta Template preventing atdna from emitting read/write implementations
|
||||
*/
|
||||
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 */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,10 +10,24 @@
|
|||
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>
|
||||
static inline std::string ToYAMLString(const T& dna)
|
||||
{
|
||||
YAMLDocWriter docWriter(dna.DNAType());
|
||||
YAMLDocWriter docWriter(__GetDNAName(dna));
|
||||
|
||||
std::string 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>
|
||||
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_width(docWriter.getEmitter(), -1);
|
||||
|
@ -65,12 +79,12 @@ template <class T>
|
|||
static inline bool ToYAMLStream(const T& dna, athena::io::IStreamWriter& fout,
|
||||
void(T::*fn)(YAMLDocWriter& out)const)
|
||||
{
|
||||
YAMLDocWriter docWriter(dna.DNAType());
|
||||
YAMLDocWriter docWriter(__GetDNAName(dna));
|
||||
|
||||
yaml_emitter_set_unicode(docWriter.getEmitter(), true);
|
||||
yaml_emitter_set_width(docWriter.getEmitter(), -1);
|
||||
|
||||
(dna->*fn)(docWriter);
|
||||
(dna.*fn)(docWriter);
|
||||
return docWriter.finish(&fout);
|
||||
}
|
||||
|
||||
|
@ -91,7 +105,7 @@ static inline bool FromYAMLStream(T& dna, athena::io::IStreamReader& fin,
|
|||
YAMLDocReader docReader;
|
||||
if (!docReader.parse(&fin))
|
||||
return false;
|
||||
(dna->*fn)(docReader);
|
||||
(dna.*fn)(docReader);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -99,7 +113,7 @@ template <class T, typename NameT>
|
|||
static inline bool MergeToYAMLFile(const T& dna, const NameT& filename)
|
||||
{
|
||||
athena::io::FileReader r(filename);
|
||||
YAMLDocWriter docWriter(dna.DNAType(), r.isOpen() ? &r : nullptr);
|
||||
YAMLDocWriter docWriter(__GetDNAName(dna), r.isOpen() ? &r : nullptr);
|
||||
r.close();
|
||||
|
||||
dna.write(docWriter);
|
||||
|
|
|
@ -137,6 +137,27 @@ enum Endian
|
|||
Little,
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
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))
|
||||
record.read(*this);
|
||||
|
@ -70,10 +71,10 @@ public:
|
|||
|
||||
template <class T>
|
||||
size_t enumerate(const char* name, std::vector<T>& vector,
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value &&
|
||||
!std::is_same<T, atVec2f>::value &&
|
||||
!std::is_same<T, atVec3f>::value &&
|
||||
!std::is_same<T, atVec4f>::value>::type* = 0)
|
||||
typename std::enable_if_t<!std::is_arithmetic<T>::value &&
|
||||
!std::is_same<T, atVec2f>::value &&
|
||||
!std::is_same<T, atVec3f>::value &&
|
||||
!std::is_same<T, atVec4f>::value>* = 0)
|
||||
{
|
||||
size_t countOut;
|
||||
if (auto v = enterSubVector(name, countOut))
|
||||
|
@ -92,10 +93,10 @@ public:
|
|||
|
||||
template <class T>
|
||||
size_t enumerate(const char* name, std::vector<T>& vector,
|
||||
typename std::enable_if<std::is_arithmetic<T>::value ||
|
||||
std::is_same<T, atVec2f>::value ||
|
||||
std::is_same<T, atVec3f>::value ||
|
||||
std::is_same<T, atVec4f>::value>::type* = 0)
|
||||
typename std::enable_if_t<std::is_arithmetic<T>::value ||
|
||||
std::is_same<T, atVec2f>::value ||
|
||||
std::is_same<T, atVec3f>::value ||
|
||||
std::is_same<T, atVec4f>::value>* = 0)
|
||||
{
|
||||
size_t countOut;
|
||||
if (auto v = enterSubVector(name, countOut))
|
||||
|
|
|
@ -39,7 +39,8 @@ public:
|
|||
RecordRAII enterSubRecord(const char* name);
|
||||
|
||||
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))
|
||||
record.write(*this);
|
||||
|
@ -61,13 +62,13 @@ public:
|
|||
|
||||
template <class T>
|
||||
void enumerate(const char* name, const std::vector<T>& vector,
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value &&
|
||||
!std::is_same<T, atVec2f>::value &&
|
||||
!std::is_same<T, atVec3f>::value &&
|
||||
!std::is_same<T, atVec4f>::value &&
|
||||
!std::is_same<T, atVec2d>::value &&
|
||||
!std::is_same<T, atVec3d>::value &&
|
||||
!std::is_same<T, atVec4d>::value>::type* = 0)
|
||||
typename std::enable_if_t<!std::is_arithmetic<T>::value &&
|
||||
!std::is_same<T, atVec2f>::value &&
|
||||
!std::is_same<T, atVec3f>::value &&
|
||||
!std::is_same<T, atVec4f>::value &&
|
||||
!std::is_same<T, atVec2d>::value &&
|
||||
!std::is_same<T, atVec3d>::value &&
|
||||
!std::is_same<T, atVec4d>::value>* = 0)
|
||||
{
|
||||
if (auto v = enterSubVector(name))
|
||||
for (const T& item : vector)
|
||||
|
@ -77,13 +78,13 @@ public:
|
|||
|
||||
template <class T>
|
||||
void enumerate(const char* name, const std::vector<T>& vector,
|
||||
typename std::enable_if<std::is_arithmetic<T>::value ||
|
||||
std::is_same<T, atVec2f>::value ||
|
||||
std::is_same<T, atVec3f>::value ||
|
||||
std::is_same<T, atVec4f>::value ||
|
||||
std::is_same<T, atVec2d>::value ||
|
||||
std::is_same<T, atVec3d>::value ||
|
||||
std::is_same<T, atVec4d>::value>::type* = 0)
|
||||
typename std::enable_if_t<std::is_arithmetic<T>::value ||
|
||||
std::is_same<T, atVec2f>::value ||
|
||||
std::is_same<T, atVec3f>::value ||
|
||||
std::is_same<T, atVec4f>::value ||
|
||||
std::is_same<T, atVec2d>::value ||
|
||||
std::is_same<T, atVec3d>::value ||
|
||||
std::is_same<T, atVec4d>::value>* = 0)
|
||||
{
|
||||
if (auto v = enterSubVector(name))
|
||||
for (T item : vector)
|
||||
|
|
Loading…
Reference in New Issue