veriblock-pop-cpp
C++11 Libraries for leveraging VeriBlock Proof-Of-Proof blockchain technology.
blob.hpp
1// Copyright (c) 2019-2022 Xenios SEZC
2// https://www.veriblock.org
3// Distributed under the MIT software license, see the accompanying
4// file LICENSE or http://www.opensource.org/licenses/mit-license.php.
5
6#ifndef ALT_INTEGRATION_VERIBLOCK_BLOB_HPP_
7#define ALT_INTEGRATION_VERIBLOCK_BLOB_HPP_
8
9#include <algorithm>
10#include <array>
11#include <cstring>
12#include <string>
13
14#include "assert.hpp"
15#include "slice.hpp"
16#include "strutil.hpp"
17
18namespace altintegration {
19
24template <size_t N>
25struct Blob {
26 using value_type = uint8_t;
27 using storage_t = std::array<value_type, N>;
28 using pointer = typename storage_t::pointer;
29 using const_pointer = typename storage_t::const_pointer;
30 using reference = typename storage_t::reference;
31 using const_reference = typename storage_t::const_reference;
32 using iterator = typename storage_t::iterator;
33 using const_iterator = typename storage_t::const_iterator;
34 using size_type = typename storage_t::size_type;
35 using difference_type = typename storage_t::difference_type;
36 using reverse_iterator = typename storage_t::reverse_iterator;
37 using const_reverse_iterator = typename storage_t::const_reverse_iterator;
38
39 Blob() { data_.fill(0); };
40
41 Blob(const std::initializer_list<uint8_t>& list) {
42 data_.fill(0);
43 assign(list);
44 }
45
47 data_.fill(0);
48 assign(slice);
49 }
50 Blob(const std::vector<uint8_t>& v) {
51 data_.fill(0);
52 assign(v);
53 }
54 explicit Blob(const std::string& hex) {
55 data_.fill(0);
56 auto data = ParseHex(hex);
57 assign(data);
58 }
59 template <size_t M, typename = typename std::enable_if<M <= N>::type>
60 explicit Blob(const Blob<M>& other) {
61 data_.fill(0);
62 assign(other);
63 }
64
65 Blob(const Blob<N>& other) : data_(other.data_) {}
66
67 Blob(Blob<N>&& other) noexcept : data_(std::move(other.data_)) {}
68
69 explicit operator std::vector<uint8_t>() const {
70 std::vector<uint8_t> ret(begin(), end());
71 return ret;
72 }
73
74 void fill(uint8_t value) { std::fill(begin(), end(), value); }
75
76 iterator begin() noexcept { return data_.begin(); }
77 const_iterator begin() const noexcept { return data_.begin(); }
78 iterator end() noexcept { return data_.end(); }
79 const_iterator end() const noexcept { return data_.end(); }
80 reverse_iterator rbegin() noexcept { return data_.rbegin(); }
81 const_reverse_iterator rbegin() const noexcept { return data_.rbegin(); }
82 reverse_iterator rend() noexcept { return data_.rend(); }
83 const_reverse_iterator rend() const noexcept { return data_.rend(); }
84
85 static constexpr size_type size() noexcept { return N; }
86
87 pointer data() noexcept { return data_.data(); }
88
89 const_pointer data() const noexcept { return data_.data(); }
90
91 std::string toHex() const { return HexStr(data_.begin(), data_.end()); }
92
93 static Blob<N> fromHex(const std::string& hex) {
94 auto data = ParseHex(hex);
95 // Blob should set parsed hex in normal order
96 return Blob<N>(data);
97 }
98
99 static Blob<N> assertFromHex(const std::string& hex) {
100 VBK_ASSERT(hex.size() / 2 == N);
101 return fromHex(hex);
102 }
103
104 void setNull() { fill(0); }
105
106 bool isNull() const {
107 for (uint8_t i : data_) {
108 if (i != 0) {
109 return false;
110 }
111 }
112
113 return true;
114 }
115
116 Blob<N>& operator=(const Blob<N>& other) {
117 this->data_ = other.data_;
118 return *this;
119 }
120
121 Blob<N>& operator=(const Slice<const uint8_t> slice) {
122 assign(slice);
123 return *this;
124 }
125
126 Blob<N>& operator=(const std::vector<uint8_t>& vec) {
127 *this = Blob<N>(vec);
128 return *this;
129 }
130
131 Blob<N> reverse() const {
132 Blob<N> ret = *this;
133 std::reverse(ret.begin(), ret.end());
134 return ret;
135 }
136
137 Blob<N>& operator~() {
138 for (unsigned i = 0; i < N; ++i) data_[i] = ~data_[i];
139 return *this;
140 }
141
142 std::vector<value_type> asVector() const {
143 return std::vector<value_type>{data_.begin(), data_.end()};
144 }
145
146 std::string asString() const {
147 return std::string{data_.begin(), data_.end()};
148 }
149
150 const value_type& operator[](size_t index) noexcept {
151 VBK_ASSERT(index < N);
152 return data_[index];
153 }
154 const value_type& operator[](size_t index) const noexcept {
155 VBK_ASSERT(index < N);
156 return data_[index];
157 }
158
159 int compareTo(const Blob<N>& b) const {
160 for (int i = N - 1; i >= 0; i--) {
161 if (data_[i] < b.data_[i]) {
162 return -1;
163 }
164 if (data_[i] > b.data_[i]) {
165 return 1;
166 }
167 }
168 return 0;
169 }
170
171 friend bool operator==(const Blob<N>& a, const Blob<N>& b) {
172 return memcmp(a.data_.data(), b.data_.data(), a.size()) == 0;
173 }
174 friend bool operator!=(const Blob<N>& a, const Blob<N>& b) {
175 return memcmp(a.data_.data(), b.data_.data(), a.size()) != 0;
176 }
177 friend bool operator>(const Blob<N>& a, const Blob<N>& b) {
178 return a.compareTo(b) > 0;
179 }
180 friend bool operator<(const Blob<N>& a, const Blob<N>& b) {
181 return a.compareTo(b) < 0;
182 }
183 friend bool operator>=(const Blob<N>& a, const Blob<N>& b) {
184 return a.compareTo(b) >= 0;
185 }
186 friend bool operator<=(const Blob<N>& a, const Blob<N>& b) {
187 return a.compareTo(b) <= 0;
188 }
189
190 template <size_t M, typename = typename std::enable_if<M <= N>::type>
191 Blob<M> trim() const {
192 Blob<M> m;
193 std::copy(data(), data() + M, m.begin());
194 return m;
195 }
196
197 template <size_t M, typename = typename std::enable_if<M <= N>::type>
198 Blob<M> trimLE() const {
199 Blob<M> m;
200 std::copy(data() + size() - M, data() + size(), m.begin());
201 return m;
202 }
203
204 uint64_t getLow64() const {
205 uint64_t ret = 0;
206 memcpy(&ret, &data_[0], sizeof(uint64_t));
207 return ret;
208 }
209
210 std::string toPrettyString() const {
211 return format("Blob<{}>({})", N, toHex());
212 }
213
215 void resize(size_t size) {
216 VBK_ASSERT_MSG(size == N, "Size=%d N=%d", size, N);
217 }
218
219 protected:
220 inline void assign(const std::initializer_list<uint8_t>& list) {
221 if (list.size() > N) {
222 throw std::domain_error(
223 fmt::format("Blob({}) invalid input size: {}", N, list.size()));
224 }
225
226 std::copy(list.begin(), list.end(), data_.begin());
227 }
228
229 inline void assign(Slice<const uint8_t> slice) {
230 if (slice.size() > N) {
231 throw std::domain_error(
232 fmt::format("Blob({}) invalid input size: {}", N, slice.size()));
233 }
234
235 std::copy(slice.begin(), slice.end(), data_.begin());
236 }
237
238 storage_t data_;
239};
240
242template <size_t size>
243void PrintTo(const Blob<size>& blob, ::std::ostream* os) {
244 *os << blob.toHex();
245}
246
248template <typename Value, size_t N>
249inline Value ToJSON(const Blob<N>& blob) {
250 return ToJSON<Value>(blob.toHex());
251}
252
253} // namespace altintegration
254
256template <size_t N>
257struct std::hash<altintegration::Blob<N>> {
258 size_t operator()(std::true_type, const altintegration::Blob<N>& x) const {
259 return x.getLow64();
260 }
261
262 size_t operator()(std::false_type, const altintegration::Blob<N>& x) const {
263 return std::hash<std::string>{}(std::string(x.begin(), x.end()));
264 }
265
266 size_t operator()(const altintegration::Blob<N>& x) const {
267 // if N >= 8, use getLow64 impl
268 // else use std::string hasher
269 typename std::conditional<N >= 8, std::true_type, std::false_type>::type f;
270 return operator()(f, x);
271 }
272};
273
275namespace fmt {
276template <size_t N>
277struct formatter<altintegration::Blob<N>> {
278 auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
279 auto it = ctx.begin(), end = ctx.end();
280 // Check if reached the end of the range:
281 VBK_ASSERT_MSG(it == end || *it == '}', "invalid format");
282
283 // Return an iterator past the end of the parsed range:
284 return it;
285 }
286
287 template <typename FormatContext>
288 auto format(const altintegration::Blob<N>& val, FormatContext& ctx)
289 -> decltype(ctx.out()) {
290 return format_to(ctx.out(), "{:s}", val.toHex());
291 }
292};
293} // namespace fmt
294
295#endif // ALT_INTEGRATION_INCLUDE_VERIBLOCK_BLOB_HPP_
Defines logging helpers.
Definition: block.hpp:14
std::string HexStr(const T itbegin, const T itend)
Convert bytes to hex.
Definition: strutil.hpp:44
void PrintTo(const ArithUint256 &uint, ::std::ostream *os)
custom gtest printer, which prints Blob of any size as hexstring @ private
std::vector< uint8_t > ParseHex(const char *psz)
Parse bytes from hex.
Contiguous byte array of fixed size.
Definition: blob.hpp:25
Non-owning contiguous array.
Definition: slice.hpp:22