Skip to content

src/base/util.hpp

Utilities functions header file. More...

Namespaces

Name
sgns

Functions

Name
std::string to_string(const std::vector< unsigned char > & bytes)
Convert a byte array to a hexadecimal string.
bool isLittleEndian()
Checks if the architecture is little endian.
template <typename T >
T
Vector2Num(const std::vector< uint8_t > & bytes)
Converts a little-endian byte vector into a number.
uint128_t Vector2Num(const std::vector< uint8_t > & bytes)
uint256_t Vector2Num(const std::vector< uint8_t > & bytes)
template <typename T >
std::vector< uint8_t >
Num2Vector(const T & num, std::size_t num_bytes_resolution =sizeof(T))
Converts a number into a byte vector (little-endian).
template <typename T >
T
HexASCII2Num(const char * p_char, std::size_t num_nibbles_resolution =sizeof(T) *2)
Converts a hexadecimal ASCII char array into a number.
template <typename T >
std::vector< T >
HexASCII2NumStr(const char * p_char, std::size_t char_ptr_size)
Converts a hexadecimal ASCII char array into a vector of numbers.
template <typename T >
std::enable_if_t< std::is_same_v< typename T::value_type, uint8_t > >
AdjustEndianess(T & data, std::optional< typename T::iterator > start =std::nullopt, std::optional< typename T::iterator > finish =std::nullopt)
Adjust endianess if needed.
std::string Uint256ToString(const uint256_t & value)
template <typename Condition >
bool
waitForCondition(Condition condition, std::chrono::milliseconds timeout, std::chrono::milliseconds * actualDuration =nullptr, std::chrono::milliseconds check_interval =std::chrono::milliseconds(10))

Detailed Description

Utilities functions header file.

Date: 2024-01-12 Super Genius ([email protected]) Henrique A. Klein ([email protected])

Functions Documentation

function to_string

static std::string to_string(
    const std::vector< unsigned char > & bytes
)

Convert a byte array to a hexadecimal string.

Parameters:

  • bytes A vector of bytes to be converted.

Return: A hexadecimal string representation of the bytes.

function isLittleEndian

static bool isLittleEndian()

Checks if the architecture is little endian.

Return: true if little endian, false otherwise

function Vector2Num

template <typename T >
static T Vector2Num(
    const std::vector< uint8_t > & bytes
)

Converts a little-endian byte vector into a number.

Parameters:

  • bytes Byte vector to convert.

Template Parameters:

  • T uint8_t, uint16_t, uint32_t, uint64_t, or supported multiprecision integer types.

Return: The converted number.

function Vector2Num

uint128_t Vector2Num(
    const std::vector< uint8_t > & bytes
)

function Vector2Num

uint256_t Vector2Num(
    const std::vector< uint8_t > & bytes
)

function Num2Vector

template <typename T >
static std::vector< uint8_t > Num2Vector(
    const T & num,
    std::size_t num_bytes_resolution =sizeof(T)
)

Converts a number into a byte vector (little-endian).

Parameters:

  • num Number to convert.
  • num_bytes_resolution Optional byte resolution (defaults to sizeof(T)).

Template Parameters:

  • T uint8_t, uint16_t, uint32_t or uint64_t

Return: The converted byte vector.

function HexASCII2Num

template <typename T >
static T HexASCII2Num(
    const char * p_char,
    std::size_t num_nibbles_resolution =sizeof(T) *2
)

Converts a hexadecimal ASCII char array into a number.

Parameters:

  • p_char Hexadecimal ASCII char array
  • num_nibbles_resolution How many nibbles will constitute a number

Template Parameters:

  • T uint8_t, uint16_t, uint32_t or uint64_t

Return: The converted number (8-64 bit variable)

function HexASCII2NumStr

template <typename T >
static std::vector< T > HexASCII2NumStr(
    const char * p_char,
    std::size_t char_ptr_size
)

Converts a hexadecimal ASCII char array into a vector of numbers.

Parameters:

  • p_char Hexadecimal ASCII char array
  • char_ptr_size Size of the char array

Template Parameters:

  • T uint8_t, uint16_t, uint32_t or uint64_t

Return: The vector of converted numbers

function AdjustEndianess

template <typename T >
static std::enable_if_t< std::is_same_v< typename T::value_type, uint8_t > > AdjustEndianess(
    T & data,
    std::optional< typename T::iterator > start =std::nullopt,
    std::optional< typename T::iterator > finish =std::nullopt
)

Adjust endianess if needed.

Parameters:

  • data The container of data (vector/array)
  • start Optional beginning of the valid data
  • finish Optional ending of the valid data

Template Parameters:

  • T std::vector or std::array

function Uint256ToString

static std::string Uint256ToString(
    const uint256_t & value
)

function waitForCondition

template <typename Condition >
bool waitForCondition(
    Condition condition,
    std::chrono::milliseconds timeout,
    std::chrono::milliseconds * actualDuration =nullptr,
    std::chrono::milliseconds check_interval =std::chrono::milliseconds(10)
)

Parameters:

  • condition a callable that returns bool, true when condition is met
  • timeout maximum time to wait
  • actualDuration optional pointer to store the actual wait duration
  • check_interval time to wait between condition checks

Return: true if condition became true before timeout, false if timeout occurred

Wait for a condition to become true with timeout

Source code

#ifndef _UTIL_HPP
#define _UTIL_HPP

#include <string>
#include <vector>
#include <type_traits>
#include <optional>
#include <algorithm>
#include <cmath>
#include <charconv>
#include <boost/random.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include "outcome/outcome.hpp"

namespace sgns
{
    using namespace boost::multiprecision;
    namespace br = boost::random;

    static std::string to_string( const std::vector<unsigned char> &bytes )
    {
        std::string out_str;
        char        temp_buf[3];
        for ( auto it = bytes.rbegin(); it != bytes.rend(); ++it )
        {
            snprintf( temp_buf, sizeof( temp_buf ), "%02x", *it );
            out_str.append( temp_buf, sizeof( temp_buf ) - 1 );
        }
        return out_str;
    }

    static bool isLittleEndian()
    {
        std::uint32_t num     = 1;
        auto         *bytePtr = reinterpret_cast<std::uint8_t *>( &num );

        return *bytePtr == 1;
    }


    template <typename T>
    static T Vector2Num( const std::vector<uint8_t> &bytes )
    {
        static_assert(
            std::is_integral_v<T> || std::is_same_v<T, boost::multiprecision::uint128_t> ||
                std::is_same_v<T, boost::multiprecision::uint256_t>,
            "T must be an integral type or boost::multiprecision::uint128_t or boost::multiprecision::uint256_t" );
        if ( bytes.size() > sizeof( T ) )
        {
            throw std::invalid_argument( "Byte vector too large for conversion" );
        }

        T value = 0;
        for ( size_t i = 0; i < bytes.size(); ++i )
        {
            value |= static_cast<T>( bytes[i] ) << ( i * 8 );
        }
        return value;
    }

    template <>
    uint128_t Vector2Num( const std::vector<uint8_t> &bytes )
    {
        if ( bytes.size() > 16 )
        {
            throw std::invalid_argument( "Byte vector too large for conversion" );
        }

        uint128_t value = 0;
        for ( size_t i = 0; i < bytes.size(); ++i )
        {
            value |= static_cast<uint128_t>( bytes[i] ) << ( i * 8 );
        }
        return value;
    }

    template <>
    uint256_t Vector2Num( const std::vector<uint8_t> &bytes )
    {
        if ( bytes.size() > 32 )
        {
            throw std::invalid_argument( "Byte vector too large for conversion" );
        }

        uint256_t value = 0;
        for ( size_t i = 0; i < bytes.size(); ++i )
        {
            value |= static_cast<uint256_t>( bytes[i] ) << ( i * 8 );
        }
        return value;
    }

    template <typename T>
    static std::vector<uint8_t> Num2Vector( const T &num, std::size_t num_bytes_resolution = sizeof( T ) )
    {
        const auto *bytesPtr = reinterpret_cast<const uint8_t *>( &num );
        return std::vector<uint8_t>( bytesPtr, bytesPtr + sizeof( T ) );
    }

    template <typename T>
    static T HexASCII2Num( const char *p_char, std::size_t num_nibbles_resolution = sizeof( T ) * 2 )
    {
        T sum = 0;

        for ( std::size_t i = 0; i < num_nibbles_resolution; ++i )
        {
            if ( std::isdigit( p_char[i] ) )
            {
                sum += ( ( p_char[i] - '0' ) << ( 4 * ( num_nibbles_resolution - i - 1 ) ) );
            }
            else
            {
                sum += ( ( std::toupper( p_char[i] ) - 'A' + 10 ) << ( 4 * ( num_nibbles_resolution - i - 1 ) ) );
            }
        }

        return sum;
    }

    template <typename T>
    static std::vector<T> HexASCII2NumStr( const char *p_char, std::size_t char_ptr_size )
    {
        static_assert( std::is_same_v<T, uint8_t> || std::is_same_v<T, uint16_t> || std::is_same_v<T, uint32_t> ||
                       std::is_same_v<T, uint64_t> );
        std::vector<T> out_vect;
        std::size_t    num_nibbles_resolution = ( sizeof( T ) * 2 );
        auto           point_of_insertion     = [&]()
        {
            if ( isLittleEndian() )
            {
                return out_vect.begin();
            }

            return out_vect.end();
        };

        for ( std::size_t i = 0; i < char_ptr_size; i += num_nibbles_resolution )
        {
            out_vect.insert( point_of_insertion(), static_cast<T>( HexASCII2Num<T>( &p_char[i] ) ) );
        }
        return out_vect;
    }

    template <typename T>
    static std::enable_if_t<std::is_same_v<typename T::value_type, uint8_t>> AdjustEndianess(
        T                                  &data,
        std::optional<typename T::iterator> start  = std::nullopt,
        std::optional<typename T::iterator> finish = std::nullopt )
    {
        if ( !start )
        {
            start = data.begin();
        }
        if ( !finish )
        {
            finish = data.end();
        }
        if ( !isLittleEndian() )
        {
            std::reverse( start.value(), finish.value() );
        }
    }

    static std::string Uint256ToString( const uint256_t &value )
    {
        std::ostringstream oss;
        oss << "0x";
        oss << std::hex << std::setw( 64 ) << std::setfill( '0' ) << value;
        return oss.str();
    }
}

template <typename Condition>
bool waitForCondition(Condition condition,
                     std::chrono::milliseconds timeout,
                     std::chrono::milliseconds* actualDuration = nullptr,
                     std::chrono::milliseconds check_interval = std::chrono::milliseconds(10)) {
    auto startTime = std::chrono::steady_clock::now();
    while (!condition()) {
        if (std::chrono::steady_clock::now() - startTime > timeout) {
            if (actualDuration) {
                *actualDuration = std::chrono::duration_cast<std::chrono::milliseconds>(
                    std::chrono::steady_clock::now() - startTime);
            }
            return false; // Timeout occurred
        }
        std::this_thread::sleep_for(check_interval);
    }

    if (actualDuration) {
        *actualDuration = std::chrono::duration_cast<std::chrono::milliseconds>(
            std::chrono::steady_clock::now() - startTime);
    }
    return true; // Condition met within timeout
}


#endif //_UTIL_HPP

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