#ifndef LLARP_ALIGNED_HPP #define LLARP_ALIGNED_HPP #include #include #include #include #include #include #include #include #include #include #include extern "C" { extern void randombytes(unsigned char* const ptr, unsigned long long sz); } namespace llarp { /// aligned buffer that is sz bytes long and aligns to the nearest Alignment template < size_t sz > struct AlignedBuffer { static constexpr size_t SIZE = sz; using Data = std::array< byte_t, SIZE >; AlignedBuffer() { new(&val) Data; Zero(); } explicit AlignedBuffer(const byte_t* data) { new(&val) Data; auto& b = as_array(); for(size_t idx = 0; idx < sz; ++idx) { b[idx] = data[idx]; } } AlignedBuffer(const Data& buf) { new(&val) Data; std::copy(buf.begin(), buf.end(), begin()); } AlignedBuffer& operator=(const byte_t* data) { auto& b = as_array(); for(size_t idx = 0; idx < sz; ++idx) { b[idx] = data[idx]; } return *this; } friend std::ostream& operator<<(std::ostream& out, const AlignedBuffer& self) { char tmp[(sz * 2) + 1] = {0}; return out << HexEncode(self, tmp); } /// bitwise NOT AlignedBuffer< sz > operator~() const { AlignedBuffer< sz > ret; std::transform(begin(), end(), ret.begin(), [](byte_t a) { return ~a; }); return ret; } bool operator==(const AlignedBuffer& other) const { return as_array() == other.as_array(); } bool operator!=(const AlignedBuffer& other) const { return as_array() != other.as_array(); } bool operator<(const AlignedBuffer& other) const { return as_array() < other.as_array(); } bool operator>(const AlignedBuffer& other) const { return as_array() > other.as_array(); } bool operator<=(const AlignedBuffer& other) const { return as_array() <= other.as_array(); } bool operator>=(const AlignedBuffer& other) const { return as_array() >= other.as_array(); } AlignedBuffer operator^(const AlignedBuffer& other) const { AlignedBuffer< sz > ret; std::transform(begin(), end(), other.begin(), ret.begin(), std::bit_xor< byte_t >()); return ret; } AlignedBuffer& operator^=(const AlignedBuffer& other) { // Mutate in place instead. for(size_t i = 0; i < as_array().size(); ++i) { as_array()[i] ^= other.as_array()[i]; } return *this; } byte_t& operator[](size_t idx) { assert(idx < SIZE); return as_array()[idx]; } const byte_t& operator[](size_t idx) const { assert(idx < SIZE); return as_array()[idx]; } static constexpr size_t size() { return sz; } void Fill(byte_t f) { as_array().fill(f); } Data& as_array() { return reinterpret_cast< Data& >(val); } const Data& as_array() const { return reinterpret_cast< const Data& >(val); } byte_t* data() { return as_array().data(); } const byte_t* data() const { return as_array().data(); } bool IsZero() const { auto notZero = [](byte_t b) { return b != 0; }; return std::find_if(begin(), end(), notZero) == end(); } void Zero() { as_array().fill(0); } void Randomize() { randombytes(data(), SIZE); } typename Data::iterator begin() { return as_array().begin(); } typename Data::iterator end() { return as_array().end(); } typename Data::const_iterator begin() const { return as_array().cbegin(); } typename Data::const_iterator end() const { return as_array().cend(); } llarp_buffer_t as_buffer() { llarp_buffer_t buff; buff.base = data(); buff.cur = buff.base; buff.sz = size(); return buff; } bool BEncode(llarp_buffer_t* buf) const { return bencode_write_bytestring(buf, data(), sz); } bool BDecode(llarp_buffer_t* buf) { llarp_buffer_t strbuf; if(!bencode_read_string(buf, &strbuf)) { return false; } if(strbuf.sz != sz) { llarp::LogError("bdecode buffer size missmatch ", strbuf.sz, "!=", sz); return false; } memcpy(data(), strbuf.base, sz); return true; } std::string ToHex() const { char strbuf[(1 + sz) * 2] = {0}; return std::string(HexEncode(*this, strbuf)); } struct Hash { size_t operator()(const AlignedBuffer& buf) const { return std::accumulate(buf.begin(), buf.end(), 0, std::bit_xor< size_t >()); } }; private: using AlignedStorage = typename std::aligned_storage< sizeof(Data), alignof(uint64_t) >:: type; // why did we align to the nearest double-precision float AlignedStorage val; }; } // namespace llarp #endif