Skip to content

src/base/blob.hpp

Namespaces

Name
sgns
sgns::base

Classes

Name
class sgns::base::Blob
struct std::hash< sgns::base::Blob< N > >

Types

Name
enum class BlobError
using Blob< 8 > Hash64
using Blob< 16 > Hash128
using Blob< 32 > Hash256
using Blob< 64 > Hash512

Functions

Name
template <class Stream ,size_t size,typename =std::enable_if_t>
Stream &
operator<<(Stream & s, const Blob< size > & blob)
scale-encodes blob instance to stream
template <class Stream ,size_t size,typename =std::enable_if_t>
Stream &
operator>>(Stream & s, Blob< size > & blob)
decodes blob instance from stream
template <size_t N>
std::ostream &
operator<<(std::ostream & os, const Blob< N > & blob)
OUTCOME_HPP_DECLARE_ERROR_2(sgns::base , BlobError )

Types Documentation

enum BlobError

Enumerator Value Description
INCORRECT_LENGTH 1

Error codes for exceptions that may occur during blob initialization

using Hash64

using sgns::base::Hash64 = Blob<8>;

using Hash128

using sgns::base::Hash128 = Blob<16>;

using Hash256

using sgns::base::Hash256 = Blob<32>;

using Hash512

using sgns::base::Hash512 = Blob<64>;

Functions Documentation

function operator<<

template <class Stream ,
size_t size,
typename  =std::enable_if_t<Stream::is_encoder_stream>>
Stream & operator<<(
    Stream & s,
    const Blob< size > & blob
)

scale-encodes blob instance to stream

Parameters:

  • s output stream reference
  • blob value to encode

Template Parameters:

  • Stream output stream type
  • size blob size

Return: reference to stream

function operator>>

template <class Stream ,
size_t size,
typename  =std::enable_if_t<Stream::is_decoder_stream>>
Stream & operator>>(
    Stream & s,
    Blob< size > & blob
)

decodes blob instance from stream

Parameters:

  • s input stream reference
  • blob value to encode

Template Parameters:

  • Stream output stream type
  • size blob size

Return: reference to stream

function operator<<

template <size_t N>
inline std::ostream & operator<<(
    std::ostream & os,
    const Blob< N > & blob
)

function OUTCOME_HPP_DECLARE_ERROR_2

OUTCOME_HPP_DECLARE_ERROR_2(
    sgns::base ,
    BlobError 
)

Source code

#ifndef SUPERGENIUS_BLOB_HPP
#define SUPERGENIUS_BLOB_HPP

#include <cstddef>
#include <array>

#include <boost/functional/hash.hpp>
#include "base/hexutil.hpp"
#include <iostream>

namespace sgns::base {

  enum class BlobError { INCORRECT_LENGTH = 1 };

  template <size_t size_>
  class Blob : public std::array<uint8_t, size_> {
   public:
    Blob() {
      this->fill(0);
    }

    explicit constexpr Blob( const std::array<uint8_t, size_> &l )
    {
        std::copy( l.begin(), l.end(), this->begin() );
    }

    constexpr static size_t size() {
      return size_;
    }

    [[nodiscard]] std::string toString() const noexcept
    {
        return std::string{ this->begin(), this->end() };
    }

    [[nodiscard]] std::string toReadableString() const noexcept
    {
        std::string out_str;
        char        temp_buf[3];

        for ( auto it = this->begin(); it != this->end(); ++it )
        {
            snprintf( temp_buf, sizeof( temp_buf ), "%02x", *it );
            out_str.append( temp_buf, sizeof( temp_buf ) - 1 );
        }

        return out_str;
    }

    [[nodiscard]] std::string toHex() const noexcept
    {
        // return hex_lower({this->begin(), this->end()});
        return hex_lower( gsl::make_span( *this ) );
    }

    static outcome::result<Blob<size_>> fromString(std::string_view data) {
      if (data.size() != size_) {
        return BlobError::INCORRECT_LENGTH;
      }

      Blob<size_> b;
      std::copy(data.begin(), data.end(), b.begin());

      return b;
    }


    static outcome::result<Blob<size_>> fromReadableString(std::string_view data) {
      if (data.size()/2 != size_) {
        return BlobError::INCORRECT_LENGTH;
      }
      Blob<size_> b;

      for ( std::size_t i = 0; i < data.size(); i+=2 )
      {
          std::string byteString = std::string(data).substr(i, 2);
          char byte = static_cast<char>(std::stoul(byteString, nullptr, 16));
          b[i/2] = static_cast<uint8_t>(byte);
      }


      return b;
    }

    static outcome::result<Blob<size_>> fromHex(std::string_view hex) {
      OUTCOME_TRY((auto &&, res), unhex(hex));
      return fromSpan(res);
    }

    static outcome::result<Blob<size_>> fromHexWithPrefix(
        std::string_view hex) {
      OUTCOME_TRY((auto &&, res), unhexWith0x(hex));
      return fromSpan(res);
    }

    static outcome::result<Blob<size_>> fromSpan(
        gsl::span<uint8_t> span) {
      if (span.size() != size_) {
        return BlobError::INCORRECT_LENGTH;
      }

      Blob<size_> blob;
      std::copy(span.begin(), span.end(), blob.begin());
      return blob;
    }

    [[nodiscard]] std::vector<uint8_t> ToVec() const
    {
        return { this->begin(), this->end() };
    }
  };

  // extern specification of the most frequently instantiated blob
  // specializations, used mostly for Hash instantiation
  extern template class Blob<8ul>;
  extern template class Blob<16ul>;
  extern template class Blob<32ul>;
  extern template class Blob<64ul>;

  // Hash specializations
  using Hash64 = Blob<8>;
  using Hash128 = Blob<16>;
  using Hash256 = Blob<32>;
  using Hash512 = Blob<64>;

  template <class Stream,
            size_t size,
            typename = std::enable_if_t<Stream::is_encoder_stream>>
  Stream &operator<<(Stream &s, const Blob<size> &blob) {
    for (auto &&it = blob.begin(), end = blob.end(); it != end; ++it) {
      s << *it;
    }
    return s;
  }

  template <class Stream,
            size_t size,
            typename = std::enable_if_t<Stream::is_decoder_stream>>
  Stream &operator>>(Stream &s, Blob<size> &blob) {
    for (auto &&it = blob.begin(), end = blob.end(); it != end; ++it) {
      s >> *it;
    }
    return s;
  }

  template <size_t N>
  inline std::ostream &operator<<(std::ostream &os, const Blob<N> &blob) {
    return os << blob.toHex();
  }

}  // namespace sgns::base

template <size_t N>
struct std::hash<sgns::base::Blob<N>> {
  auto operator()(const sgns::base::Blob<N> &blob) const {
    return boost::hash_range(blob.data(), blob.data() + N);  // NOLINT
  }
};

OUTCOME_HPP_DECLARE_ERROR_2(sgns::base, BlobError);

#endif  // SUPERGENIUS_BLOB_HPP

Updated on 2026-03-04 at 13:10:44 -0800