Kagome
Polkadot Runtime Engine in C++17
blob.hpp
Go to the documentation of this file.
1 
6 #ifndef KAGOME_BLOB_HPP
7 #define KAGOME_BLOB_HPP
8 
9 #include <array>
10 
11 #include <fmt/format.h>
12 #include <boost/functional/hash.hpp>
13 #include <scale/scale.hpp>
14 
15 #include "common/buffer.hpp"
16 #include "common/hexutil.hpp"
18 
19 #define KAGOME_BLOB_STRICT_TYPEDEF(space_name, class_name, blob_size) \
20  namespace space_name { \
21  struct class_name : public ::kagome::common::Blob<blob_size> { \
22  using Base = ::kagome::common::Blob<blob_size>; \
23  \
24  class_name() = default; \
25  class_name(const class_name &) = default; \
26  class_name(class_name &&) = default; \
27  class_name &operator=(const class_name &) = default; \
28  class_name &operator=(class_name &&) = default; \
29  \
30  explicit class_name(const Base &blob) : Base{blob} {} \
31  explicit class_name(Base &&blob) : Base{std::move(blob)} {} \
32  \
33  ~class_name() = default; \
34  \
35  class_name &operator=(const Base &blob) { \
36  Blob::operator=(blob); \
37  return *this; \
38  } \
39  \
40  class_name &operator=(Base &&blob) { \
41  Blob::operator=(std::move(blob)); \
42  return *this; \
43  } \
44  \
45  static ::outcome::result<class_name> fromString(std::string_view data) { \
46  OUTCOME_TRY(blob, Base::fromString(data)); \
47  return class_name{std::move(blob)}; \
48  } \
49  \
50  static ::outcome::result<class_name> fromHex(std::string_view hex) { \
51  OUTCOME_TRY(blob, Base::fromHex(hex)); \
52  return class_name{std::move(blob)}; \
53  } \
54  \
55  static ::outcome::result<class_name> fromHexWithPrefix( \
56  std::string_view hex) { \
57  OUTCOME_TRY(blob, Base::fromHexWithPrefix(hex)); \
58  return class_name{std::move(blob)}; \
59  } \
60  \
61  static ::outcome::result<class_name> fromSpan( \
62  const gsl::span<const uint8_t> &span) { \
63  OUTCOME_TRY(blob, Base::fromSpan(span)); \
64  return class_name{std::move(blob)}; \
65  } \
66  \
67  friend inline ::scale::ScaleEncoderStream &operator<<( \
68  ::scale::ScaleEncoderStream &s, \
69  const space_name::class_name &data) { \
70  return s << static_cast<const Base &>(data); \
71  } \
72  \
73  friend inline ::scale::ScaleDecoderStream &operator>>( \
74  ::scale::ScaleDecoderStream &s, space_name::class_name &data) { \
75  return s >> static_cast<Base &>(data); \
76  } \
77  }; \
78  }; \
79  \
80  template <> \
81  struct std::hash<space_name::class_name> { \
82  auto operator()(const space_name::class_name &key) const { \
83  /* NOLINTNEXTLINE */ \
84  return boost::hash_range(key.cbegin(), key.cend()); \
85  } \
86  }; \
87  \
88  template <> \
89  struct fmt::formatter<space_name::class_name> \
90  : fmt::formatter<space_name::class_name::Base> { \
91  template <typename FormatCtx> \
92  auto format(const space_name::class_name &blob, FormatCtx &ctx) { \
93  return fmt::formatter<space_name::class_name::Base>::format(blob, ctx); \
94  } \
95  };
96 
97 namespace kagome::common {
98 
102  enum class BlobError { INCORRECT_LENGTH = 1 };
103 
104  using byte_t = uint8_t;
105 
114  template <size_t size_>
115  class Blob : public std::array<byte_t, size_> {
116  public:
117  // Next line is required at least for the scale-codec
118  static constexpr bool is_static_collection = true;
119 
120  using const_narref = const byte_t (&)[size_];
121  using const_narptr = const byte_t (*)[size_];
125  Blob() {
126  this->fill(0);
127  }
128 
130  return *const_narptr(this->data());
131  }
132 
137  explicit Blob(const std::array<byte_t, size_> &l) {
138  std::copy(l.begin(), l.end(), this->begin());
139  }
140 
141  virtual ~Blob() = default;
142 
146  constexpr static size_t size() {
147  return size_;
148  }
149 
153  std::string toString() const noexcept {
154  return std::string{this->begin(), this->end()};
155  }
156 
160  std::string toHex() const noexcept {
161  return hex_lower({this->begin(), this->end()});
162  }
163 
169  static outcome::result<Blob<size_>> fromString(std::string_view data) {
170  if (data.size() != size_) {
172  }
173 
174  Blob<size_> b;
175  std::copy(data.begin(), data.end(), b.begin());
176 
177  return b;
178  }
179 
186  static outcome::result<Blob<size_>> fromHex(std::string_view hex) {
187  OUTCOME_TRY(res, unhex(hex));
188  return fromSpan(res);
189  }
190 
197  static outcome::result<Blob<size_>> fromHexWithPrefix(
198  std::string_view hex) {
199  OUTCOME_TRY(res, unhexWith0x(hex));
200  return fromSpan(res);
201  }
202 
208  static outcome::result<Blob<size_>> fromSpan(
209  const gsl::span<const uint8_t> &span) {
210  if (span.size() != size_) {
212  }
213 
214  Blob<size_> blob;
215  std::copy(span.begin(), span.end(), blob.begin());
216  return blob;
217  }
218  };
219 
220  // extern specification of the most frequently instantiated blob
221  // specializations, used mostly for Hash instantiation
222  extern template class Blob<8ul>;
223  extern template class Blob<16ul>;
224  extern template class Blob<32ul>;
225  extern template class Blob<64ul>;
226 
227  // Hash specializations
228  using Hash64 = Blob<8>;
229  using Hash128 = Blob<16>;
230  using Hash256 = Blob<32>;
231  using Hash512 = Blob<64>;
232 
233  template <size_t N>
234  inline std::ostream &operator<<(std::ostream &os, const Blob<N> &blob) {
235  return os << blob.toHex();
236  }
237 
238 } // namespace kagome::common
239 
240 template <size_t N>
241 struct std::hash<kagome::common::Blob<N>> {
242  auto operator()(const kagome::common::Blob<N> &blob) const {
243  return boost::hash_range(blob.data(), blob.data() + N); // NOLINT
244  }
245 };
246 
247 template <size_t N>
248 struct fmt::formatter<kagome::common::Blob<N>> {
249  // Presentation format: 's' - short, 'l' - long.
250  char presentation = N > 4 ? 's' : 'l';
251 
252  // Parses format specifications of the form ['s' | 'l'].
253  constexpr auto parse(format_parse_context &ctx) -> decltype(ctx.begin()) {
254  // Parse the presentation format and store it in the formatter:
255  auto it = ctx.begin(), end = ctx.end();
256  if (it != end && (*it == 's' || *it == 'l')) {
257  presentation = *it++;
258  }
259 
260  // Check if reached the end of the range:
261  if (it != end && *it != '}') {
262  throw format_error("invalid format");
263  }
264 
265  // Return an iterator past the end of the parsed range:
266  return it;
267  }
268 
269  // Formats the Blob using the parsed format specification (presentation)
270  // stored in this formatter.
271  template <typename FormatContext>
272  auto format(const kagome::common::Blob<N> &blob, FormatContext &ctx)
273  -> decltype(ctx.out()) {
274  // ctx.out() is an output iterator to write to.
275 
276  if (presentation == 's') {
277  return format_to(
278  ctx.out(),
279  "0x{:04x}…{:04x}",
280  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
281  htobe16(*reinterpret_cast<const uint16_t *>(blob.data())),
282  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
283  htobe16(*reinterpret_cast<const uint16_t *>(blob.data() + blob.size()
284  - sizeof(uint16_t))));
285  }
286 
287  return format_to(ctx.out(), "0x{}", blob.toHex());
288  }
289 };
290 
292 
293 #endif // KAGOME_BLOB_HPP
Blob(const std::array< byte_t, size_ > &l)
constructor enabling initializer list
Definition: blob.hpp:137
std::string hex_lower(const gsl::span< const uint8_t > bytes) noexcept
Converts bytes to hex representation.
Definition: hexutil.cpp:52
constexpr auto parse(format_parse_context &ctx) -> decltype(ctx.begin())
Definition: blob.hpp:253
outcome::result< std::vector< uint8_t > > unhexWith0x(std::string_view hex_with_prefix)
Unhex hex-string with 0x in the begining.
Definition: hexutil.cpp:89
auto format(const kagome::common::Blob< N > &blob, FormatContext &ctx) -> decltype(ctx.out())
Definition: blob.hpp:272
const byte_t(&)[size_] const_narref
Definition: blob.hpp:120
const_narref internal_array_reference() const
Definition: blob.hpp:129
uint8_t byte_t
Definition: blob.hpp:104
std::string toString() const noexcept
Definition: blob.hpp:153
static outcome::result< Blob< size_ > > fromHexWithPrefix(std::string_view hex)
Definition: blob.hpp:197
static outcome::result< Blob< size_ > > fromString(std::string_view data)
Definition: blob.hpp:169
const byte_t(*)[size_] const_narptr
Definition: blob.hpp:121
static outcome::result< Blob< size_ > > fromSpan(const gsl::span< const uint8_t > &span)
Definition: blob.hpp:208
OUTCOME_HPP_DECLARE_ERROR(kagome::common, BlobError)
std::string toHex() const noexcept
Definition: blob.hpp:160
auto operator()(const kagome::common::Blob< N > &blob) const
Definition: blob.hpp:242
outcome::result< std::vector< uint8_t > > unhex(std::string_view hex)
Converts hex representation to bytes.
Definition: hexutil.cpp:70
static constexpr size_t size()
Definition: blob.hpp:146
static outcome::result< Blob< size_ > > fromHex(std::string_view hex)
Definition: blob.hpp:186