#ifndef DNA_HPP #define DNA_HPP /* BIG FAT WARNING!!! * * The type-structure of this file is expected to remain consistent for 'atdna' * Any changes to the types or namespacing must be reflected in 'atdna/main.cpp' */ #include "Global.hpp" #include "IStreamReader.hpp" #include "IStreamWriter.hpp" #include #include namespace Athena { namespace io { /* forward-declaration dance for recursively-derived types */ template struct Buffer; template struct String; template struct WString; template struct WStringAsString; /** * @brief Base DNA class used against 'atdna' * @tparam DNAE Default-endianness for contained DNA values * * Athena bundles a build-tool called 'atdna'. This tool functions * just like the 'clang' compiler, except it emits a full .cpp implementation * with all read/write calls necessary to marshal the DNA structure to/from * a streamed medium */ template struct DNA { /** * @brief Common virtual read function for all DNA types */ virtual void read(IStreamReader&)=0; /** * @brief Common virtual write function for all DNA types */ virtual void write(IStreamWriter&) const=0; /** * @brief Template type signaling atdna to capture the value where it's used * @tparam T The type of the value. Can be any numeric type or atVec* type * @tparam VE Endianness of the value */ template using Value = T; /** * @brief Template type wrapping std::vector and signaling atdna to manipulate it where it's used * @tparam T The type of contained elements. Can be any numeric type, atVec* type, or another DNA subclass * @tparam cntVar C++ expression wrapped in DNA_COUNT macro to determine number of elements for vector * @tparam VE Endianness of the contained values */ template using Vector = std::vector; /** * @brief Template type wrapping std::unique_ptr and signaling atdna to read a * raw byte-buffer where it's used * @tparam sizeVar C++ expression wrapped in DNA_COUNT macro to determine number of bytes for buffer */ template using Buffer = struct Athena::io::Buffer; /** * @brief Template type wrapping std::string and signaling atdna to read string data where it's used * @tparam sizeVar C++ expression wrapped in DNA_COUNT macro to determine number of characters for string * -1 literal indicates null-terminated string */ template using String = struct Athena::io::String; /** * @brief Template type wrapping std::wstring and signaling atdna to read wstring data where it's used * @tparam sizeVar C++ expression wrapped in DNA_COUNT macro to determine number of characters for wstring * -1 literal indicates null-terminated wstring */ template using WString = struct Athena::io::WString; /** * @brief Template type wrapping std::string and signaling atdna to read wstring data where it's used * @tparam sizeVar C++ expression wrapped in DNA_COUNT macro to determine number of characters for string * -1 literal indicates null-terminated string */ template using WStringAsString = struct Athena::io::WStringAsString; /** * @brief Meta Template signaling atdna to insert a stream seek where it's used * @tparam offset C++ expression wrapped in DNA_COUNT macro to determine number of bytes to seek * @tparam direction SeekOrigin to seek relative to */ template struct Seek {}; /** * @brief Meta Template signaling atdna to insert an aligning stream seek where it's used * @tparam align Number of bytes to align to */ template struct Align {}; /** * @brief Meta Template preventing atdna from emitting read/write implementations */ struct Delete {}; }; /** * @brief Concrete buffer type used by DNA::Buffer */ template struct Buffer : public DNA, public std::unique_ptr { typename DNA::Delete expl; inline void read(IStreamReader& reader) { reset(new atUint8[sizeVar]); reader.readUBytesToBuf(get(), sizeVar); } inline void write(IStreamWriter& writer) const { writer.writeUBytes(get(), sizeVar); } }; /** * @brief Concrete string type used by DNA::String */ template struct String : public DNA, public std::string { typename DNA::Delete expl; inline void read(IStreamReader& reader) {this->assign(std::move(reader.readString(sizeVar)));} inline void write(IStreamWriter& writer) const {writer.writeString(*this, sizeVar);} inline std::string& operator=(const std::string& __str) {return this->assign(__str);} inline std::string& operator=(std::string&& __str) {this->swap(__str); return *this;} }; /** * @brief Concrete wstring type used by DNA::WString */ template struct WString : public DNA, public std::wstring { typename DNA::Delete expl; inline void read(IStreamReader& reader) { reader.setEndian(VE); this->assign(std::move(reader.readWString(sizeVar))); } inline void write(IStreamWriter& writer) const { writer.setEndian(VE); writer.writeWString(*this, sizeVar); } inline std::wstring& operator=(const std::wstring& __str) {return this->assign(__str);} inline std::wstring& operator=(std::wstring&& __str) {this->swap(__str); return *this;} }; /** * @brief Concrete converting-wstring type used by DNA::WStringAsString */ template struct WStringAsString : public DNA, public std::string { typename DNA::Delete expl; inline void read(IStreamReader& reader) {*this = reader.readWStringAsString(sizeVar);} inline void write(IStreamWriter& writer) const {writer.writeStringAsWString(*this, sizeVar);} inline std::string& operator=(const std::string& __str) {return this->assign(__str);} inline std::string& operator=(std::string&& __str) {this->swap(__str); return *this;} }; /** Macro to automatically declare read/write methods in subclasses */ #define DECL_DNA \ void read(Athena::io::IStreamReader&); \ void write(Athena::io::IStreamWriter&) const; \ /** Macro to automatically declare read/write methods and prevent outputting implementation */ #define DECL_EXPLICIT_DNA \ void read(Athena::io::IStreamReader&); \ void write(Athena::io::IStreamWriter&) const; \ Delete __dna_delete; /** Macro to supply count variable to atdna and mute it for other compilers */ #ifdef __clang__ #define DNA_COUNT(cnt) sizeof(cnt) #else #define DNA_COUNT(cnt) 0 #endif } } #endif // DNA_HPP