lokinet/llarp/util/aligned.hpp

290 lines
5.4 KiB
C++
Raw Normal View History

2018-06-01 14:08:54 +00:00
#ifndef LLARP_ALIGNED_HPP
#define LLARP_ALIGNED_HPP
#include <util/bencode.h>
#include <util/encode.hpp>
#include <util/logger.hpp>
2019-02-24 23:46:37 +00:00
#include <util/printer.hpp>
#include <util/traits.hpp>
2018-12-12 01:02:36 +00:00
#include <array>
#include <cstddef>
2018-06-01 14:24:58 +00:00
#include <iomanip>
2018-06-01 14:08:54 +00:00
#include <iostream>
#include <memory>
#include <numeric>
#include <type_traits>
2018-12-20 17:25:11 +00:00
#include <algorithm>
2018-06-01 14:08:54 +00:00
2018-10-23 12:40:34 +00:00
extern "C"
{
extern void
randombytes(unsigned char* const ptr, unsigned long long sz);
}
2018-06-01 14:08:54 +00:00
namespace llarp
{
/// aligned buffer that is sz bytes long and aligns to the nearest Alignment
template < size_t sz >
2018-06-01 14:08:54 +00:00
struct AlignedBuffer
{
static constexpr size_t SIZE = sz;
using Data = std::array< byte_t, SIZE >;
2018-07-26 21:08:56 +00:00
AlignedBuffer()
{
new(&val) Data;
Zero();
2018-06-22 00:25:30 +00:00
}
explicit AlignedBuffer(const byte_t* data)
2018-06-01 14:08:54 +00:00
{
new(&val) Data;
auto& b = as_array();
for(size_t idx = 0; idx < sz; ++idx)
{
2018-07-17 04:37:50 +00:00
b[idx] = data[idx];
}
}
explicit AlignedBuffer(const Data& buf)
{
new(&val) Data;
std::copy(buf.begin(), buf.end(), begin());
2018-06-01 14:08:54 +00:00
}
AlignedBuffer&
operator=(const byte_t* data)
2018-06-01 14:08:54 +00:00
{
auto& b = as_array();
for(size_t idx = 0; idx < sz; ++idx)
{
2018-07-17 04:37:50 +00:00
b[idx] = data[idx];
}
2018-06-01 14:08:54 +00:00
return *this;
}
friend std::ostream&
operator<<(std::ostream& out, const AlignedBuffer& self)
2018-06-01 14:08:54 +00:00
{
2018-12-20 16:03:55 +00:00
char tmp[(sz * 2) + 1] = {0};
2018-06-13 13:18:18 +00:00
return out << HexEncode(self, tmp);
2018-06-01 14:08:54 +00:00
}
2018-09-24 14:31:58 +00:00
/// bitwise NOT
AlignedBuffer< sz >
operator~() const
{
AlignedBuffer< sz > ret;
std::transform(begin(), end(), ret.begin(), [](byte_t a) { return ~a; });
2018-09-24 14:31:58 +00:00
return ret;
}
2018-06-01 14:08:54 +00:00
bool
operator==(const AlignedBuffer& other) const
{
return as_array() == other.as_array();
2018-06-01 14:08:54 +00:00
}
bool
operator!=(const AlignedBuffer& other) const
{
return as_array() != other.as_array();
2018-06-01 14:08:54 +00:00
}
bool
operator<(const AlignedBuffer& other) const
{
return as_array() < other.as_array();
}
2018-08-10 21:34:11 +00:00
bool
operator>(const AlignedBuffer& other) const
{
return as_array() > other.as_array();
2018-08-10 21:34:11 +00:00
}
bool
operator<=(const AlignedBuffer& other) const
{
return as_array() <= other.as_array();
2018-08-10 21:34:11 +00:00
}
bool
operator>=(const AlignedBuffer& other) const
{
return as_array() >= other.as_array();
2018-08-10 21:34:11 +00:00
}
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;
2018-06-01 14:08:54 +00:00
}
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;
}
2018-06-14 14:04:42 +00:00
void
Fill(byte_t f)
{
as_array().fill(f);
2018-06-14 14:04:42 +00:00
}
2018-12-20 16:03:55 +00:00
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
{
2018-12-20 16:03:55 +00:00
auto notZero = [](byte_t b) { return b != 0; };
return std::find_if(begin(), end(), notZero) == end();
}
2018-06-14 14:04:42 +00:00
2018-06-01 14:08:54 +00:00
void
Zero()
{
as_array().fill(0);
2018-06-01 14:08:54 +00:00
}
void
Randomize()
{
randombytes(data(), SIZE);
2018-06-01 14:08:54 +00:00
}
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();
}
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)
{
2018-09-04 19:15:06 +00:00
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};
2018-10-25 19:06:16 +00:00
return std::string(HexEncode(*this, strbuf));
}
2019-02-24 23:46:37 +00:00
std::ostream&
print(std::ostream& stream, int level, int spaces) const
{
Printer printer(stream, level, spaces);
printer.printValue(ToHex());
return stream;
}
2018-07-19 04:58:39 +00:00
struct Hash
{
size_t
operator()(const AlignedBuffer& buf) const
2018-07-19 04:58:39 +00:00
{
return std::accumulate(buf.begin(), buf.end(), 0,
std::bit_xor< size_t >());
2018-07-19 04:58:39 +00:00
}
};
private:
2018-12-23 13:29:11 +00:00
using AlignedStorage = typename std::aligned_storage< sizeof(Data),
alignof(uint64_t) >::
type; // why did we align to the nearest double-precision float
AlignedStorage val;
2018-06-01 14:08:54 +00:00
};
2018-06-18 22:03:50 +00:00
} // namespace llarp
2018-06-01 14:08:54 +00:00
#endif