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)
{
TESTFile file = {};
TESTFile<atUint32, 2> file = {};
file.arrCount[0] = 2;
file.array.push_back(42);
file.array.push_back(64);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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