#pragma once #ifndef MESSMER_CPPUTILS_DATA_FIXEDSIZEDATA_H_ #define MESSMER_CPPUTILS_DATA_FIXEDSIZEDATA_H_ #include #include #include #include "../assert/assert.h" namespace cpputils { template class FixedSizeData final { public: //Non-virtual destructor because we want objects to be small ~FixedSizeData() = default; static constexpr size_t BINARY_LENGTH = SIZE; static constexpr size_t STRING_LENGTH = 2 * BINARY_LENGTH; // Hex encoding //TODO Test Null() static FixedSizeData Null(); static FixedSizeData FromString(const std::string &data); std::string ToString() const; static FixedSizeData FromBinary(const void *source); void ToBinary(void *target) const; const unsigned char *data() const; unsigned char *data(); template FixedSizeData take() const; template FixedSizeData drop() const; private: FixedSizeData(): _data() {} template friend class FixedSizeData; unsigned char _data[BINARY_LENGTH]; }; template bool operator==(const FixedSizeData &lhs, const FixedSizeData &rhs); template bool operator!=(const FixedSizeData &lhs, const FixedSizeData &rhs); // ----- Implementation ----- template constexpr size_t FixedSizeData::BINARY_LENGTH; template constexpr size_t FixedSizeData::STRING_LENGTH; template FixedSizeData FixedSizeData::Null() { FixedSizeData result; std::memset(result._data, 0, BINARY_LENGTH); return result; } template FixedSizeData FixedSizeData::FromString(const std::string &data) { ASSERT(data.size() == STRING_LENGTH, "Wrong string size for parsing FixedSizeData"); FixedSizeData result; { CryptoPP::StringSource _1(data, true, new CryptoPP::HexDecoder( new CryptoPP::ArraySink(result._data, BINARY_LENGTH) ) ); } return result; } template std::string FixedSizeData::ToString() const { std::string result; CryptoPP::ArraySource(_data, BINARY_LENGTH, true, new CryptoPP::HexEncoder( new CryptoPP::StringSink(result) ) ); ASSERT(result.size() == STRING_LENGTH, "Created wrongly sized string"); return result; } template const unsigned char *FixedSizeData::data() const { return _data; } template unsigned char *FixedSizeData::data() { return const_cast(const_cast*>(this)->data()); } template void FixedSizeData::ToBinary(void *target) const { std::memcpy(target, _data, BINARY_LENGTH); } template FixedSizeData FixedSizeData::FromBinary(const void *source) { FixedSizeData result; std::memcpy(result._data, source, BINARY_LENGTH); return result; } template template FixedSizeData FixedSizeData::take() const { static_assert(size <= SIZE, "Out of bounds"); FixedSizeData result; std::memcpy(result._data, _data, size); return result; } template template FixedSizeData FixedSizeData::drop() const { static_assert(size <= SIZE, "Out of bounds"); FixedSizeData result; std::memcpy(result._data, _data+size, SIZE-size); return result; } template bool operator==(const FixedSizeData &lhs, const FixedSizeData &rhs) { return 0 == std::memcmp(lhs.data(), rhs.data(), FixedSizeData::BINARY_LENGTH); } template bool operator!=(const FixedSizeData &lhs, const FixedSizeData &rhs) { return !operator==(lhs, rhs); } } #endif