Add ability to generate and specialize DNA class templates

This commit is contained in:
Jack Andersen 2018-02-21 21:18:59 -10:00
parent 80c945af6d
commit 62b6d6792a
9 changed files with 1866 additions and 1697 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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))

View File

@ -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)