Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7b622a7
feature: coding of aggregate
xDimon Jan 24, 2025
2b2969e
refactor: use concepts
xDimon Jan 25, 2025
397f5db
fix: incomplete concepts
xDimon Jan 27, 2025
6baec5c
fix: SomeSpan concept
xDimon Jan 28, 2025
9a01004
update: version of used hunter
xDimon Jan 28, 2025
c4c2383
fix: CI
xDimon Jan 28, 2025
fdc1663
fix: CI
xDimon Jan 28, 2025
b81ba08
fix: CI
xDimon Jan 28, 2025
f325334
update: hunter and qtils
xDimon Jan 28, 2025
eb74ac4
refactor: used macros
xDimon Jan 28, 2025
3bb4394
fix: try to fix CI (update macos)
xDimon Jan 28, 2025
c997a5c
update: qtils
xDimon Jan 28, 2025
a401adc
refactor: rename as_decomposed
xDimon Jan 30, 2025
0a74ea0
feature: generate aggregate.hpp in according MAX_AGGREGATE_FIELDS cma…
xDimon Jan 30, 2025
7eaee7f
update: qtils
xDimon Jan 30, 2025
c5349eb
update: qtils
xDimon Jan 30, 2025
8a0e43c
fix: redundant decay_t using
xDimon Jan 30, 2025
965bf3f
feature: custom discomposing
xDimon Jan 30, 2025
9ea5b57
fix: review issues
xDimon Jan 30, 2025
4d35097
don't overwrite aggregate.hpp
turuslan Jan 30, 2025
5769acc
fix constructible on macos
turuslan Jan 30, 2025
f89839d
Revert "don't overwrite aggregate.hpp"
turuslan Jan 30, 2025
88988d4
don't overwrite aggregate.hpp
turuslan Jan 30, 2025
1461bb4
fix makefile
turuslan Jan 30, 2025
fb0a319
update: qtils
xDimon Jan 30, 2025
6bdc80b
configure_file definitions
turuslan Jan 30, 2025
08122a3
update: qtils
xDimon Feb 3, 2025
7a418d9
update: qtils hunter config
xDimon Feb 3, 2025
04bea1a
update: qtils
xDimon Feb 3, 2025
2dde730
update: qtils
xDimon Feb 3, 2025
6dbe202
update: qtils
xDimon Feb 3, 2025
e31f904
refactor: complete support fixed-width and compact integers
xDimon Feb 5, 2025
c30e4a7
feature: CompactReflection for coding int value as compact
xDimon Feb 5, 2025
9576c5d
fix: review issues
xDimon Feb 6, 2025
312aaae
update: qtils
xDimon Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,7 @@ if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.27")
endif ()

if (PACKAGE_MANAGER STREQUAL "hunter")
include(cmake/HunterGate.cmake)
HunterGate(
URL https://github.com/qdrvm/hunter/archive/refs/tags/v0.25.3-qdrvm28.tar.gz
SHA1 a4f1b0f42464e07790b7f90b783a822d71be6c6d
)
include("cmake/Hunter/init.cmake")
endif ()

if(BUILD_TESTS)
Expand All @@ -56,7 +52,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if (PACKAGE_MANAGER STREQUAL "hunter")
hunter_add_package(Boost)
find_package(Boost)
else()
else()
find_package(Boost CONFIG REQUIRED COMPONENTS endian multiprecision)
endif ()

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,13 @@ try {
## Convenience functions
Convenience functions
```c++
template<class T>
template <typename T>
outcome::result<std::vector<uint8_t>> encode(T &&t);

template <class T>
template <typename T>
outcome::result<T> decode(const RangeOfBytes auto& span)

template <class T>
template <typename T>
outcome::result<T> decode(ScaleDecoderStream &s)
```
are wrappers over ```<<``` and ```>>``` operators described above.
Expand Down
File renamed without changes.
24 changes: 24 additions & 0 deletions cmake/Hunter/config.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Template for a custom hunter configuration Useful when there is a need for a
# non-default version or arguments of a dependency, or when a project not
# registered in soramitsu-hunter should be added.
#
# hunter_config(
# package-name
# VERSION 0.0.0-package-version
# CMAKE_ARGS
# CMAKE_VARIABLE=value
# )
#
# hunter_config(
# package-name
# URL https://github.com/organization/repository/archive/hash.tar.gz
# SHA1 1234567890abcdef1234567890abcdef12345678
# CMAKE_ARGS
# CMAKE_VARIABLE=value
# )

hunter_config(
qtils
URL https://github.com/qdrvm/qtils/archive/198a40443b838a421db3ad8fc8dbf72e8ec4a665.tar.gz
SHA1 da91eaeec936ee572a1310024dfcd7b91ee5e5bf
)
5 changes: 5 additions & 0 deletions cmake/Hunter/hunter-gate-url.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
HunterGate(
URL https://github.com/qdrvm/hunter/archive/refs/tags/v0.25.3-qdrvm29.tar.gz
SHA1 025920fa980ba81a150deaa534a0248dde25fd54
LOCAL
)
42 changes: 42 additions & 0 deletions cmake/Hunter/init.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# specify GITHUB_HUNTER_TOKEN and GITHUB_HUNTER_USERNAME to automatically upload binary cache to github.com/qdrvm/hunter-binary-cache
# https://hunter.readthedocs.io/en/latest/user-guides/hunter-user/github-cache-server.html
string(COMPARE EQUAL "$ENV{GITHUB_HUNTER_USERNAME}" "" username_is_empty)
string(COMPARE EQUAL "$ENV{GITHUB_HUNTER_TOKEN}" "" password_is_empty)

# binary cache can be uploaded to qdrvm/hunter-binary-cache so others will not build same dependencies twice
if (NOT password_is_empty AND NOT username_is_empty)
option(HUNTER_RUN_UPLOAD "Upload cache binaries" YES)
message("Binary cache uploading is ENABLED.")
else ()
option(HUNTER_RUN_UPLOAD "Upload cache binaries" NO)
message(AUTHOR_WARNING " Binary cache uploading is DISABLED.
Define environment variables GITHUB_HUNTER_USERNAME and GITHUB_HUNTER_TOKEN
for binary cache activation. To generate github token follow the instructions:
https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
Make sure `read:packages` and `write:packages` permissions are granted (step 7 in instructions).")
endif ()

set(HUNTER_PASSWORDS_PATH
"${CMAKE_CURRENT_LIST_DIR}/passwords.cmake"
CACHE FILEPATH "Hunter passwords"
)

set(HUNTER_CACHE_SERVERS
"https://github.com/qdrvm/hunter-binary-cache"
CACHE STRING "Binary cache server"
)

# https://hunter.readthedocs.io/en/latest/reference/user-variables.html#hunter-use-cache-servers
# set(
# HUNTER_USE_CACHE_SERVERS NO
# CACHE STRING "Disable binary cache"
# )

# https://hunter.readthedocs.io/en/latest/reference/user-variables.html#hunter-status-debug
# set(
# HUNTER_STATUS_DEBUG ON
# CACHE STRING "Enable output lot of info for debugging"
# )

include(${CMAKE_CURRENT_LIST_DIR}/HunterGate.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/hunter-gate-url.cmake)
11 changes: 11 additions & 0 deletions cmake/Hunter/passwords.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
hunter_upload_password(
# REPO_OWNER + REPO = https://github.com/forexample/hunter-cache
REPO_OWNER "qdrvm"
REPO "hunter-binary-cache"

# USERNAME = warchant
USERNAME "$ENV{GITHUB_HUNTER_USERNAME}"

# PASSWORD = GitHub token saved as a secure environment variable
PASSWORD "$ENV{GITHUB_HUNTER_TOKEN}"
)
87 changes: 87 additions & 0 deletions include/scale/detail/aggregate.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <scale/types.hpp>

namespace scale::detail {

template <typename T, typename F>
requires SimpleCodeableAggregate<T>
auto &as_decomposed(T &&v, const F &f) {
constexpr auto N = field_number_of<T>;
// clang-format off
if constexpr (N == 0) {
return f();
} else if constexpr (N == 1) {
auto &[v1] = v;
return f(v1);
} else if constexpr (N == 2) {
auto &[v1, v2] = v;
return f(v1, v2);
} else if constexpr (N == 3) {
auto &[v1, v2, v3] = v;
return f(v1, v2, v3);
} else if constexpr (N == 4) {
auto &[v1, v2, v3, v4] = v;
return f(v1, v2, v3, v4);
} else if constexpr (N == 5) {
auto &[v1, v2, v3, v4, v5] = v;
return f(v1, v2, v3, v4, v5);
} else if constexpr (N == 6) {
auto &[v1, v2, v3, v4, v5, v6] = v;
return f(v1, v2, v3, v4, v5, v6);
} else if constexpr (N == 7) {
auto &[v1, v2, v3, v4, v5, v6, v7] = v;
return f(v1, v2, v3, v4, v5, v6, v7);
} else if constexpr (N == 8) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8);
} else if constexpr (N == 9) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9);
} else if constexpr (N == 10) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10);
} else if constexpr (N == 11) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
} else if constexpr (N == 12) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
} else if constexpr (N == 13) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
} else if constexpr (N == 14) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14);
} else if constexpr (N == 15) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15);
} else if constexpr (N == 16) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16);
} else if constexpr (N == 17) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17);
} else if constexpr (N == 18) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18);
} else if constexpr (N == 19) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
} else if constexpr (N == 20) {
auto &[v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20] = v;
return f(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
} else {
// We mustn't fall in here
static_assert(N <= MAX_FIELD_NUM, "Inconsistent value of MAX_FIELD_NUM");
static_assert(N > MAX_FIELD_NUM, "No code for cover aggregate with such big amount of fields");
}
// clang-format on
}

} // namespace scale::detail
36 changes: 22 additions & 14 deletions include/scale/detail/compact_integer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
#include <scale/outcome/outcome_throw.hpp>
#include <scale/scale_error.hpp>
#include <scale/types.hpp>
#include <scale/unreachable.hpp>

namespace scale {
class ScaleDecoderStream;
}

namespace scale::detail {

Expand Down Expand Up @@ -45,8 +50,10 @@ namespace scale::detail {
* @return byte array representation of value as compact-integer
*/
template <typename T, typename S>
requires(std::integral<T> or std::is_same_v<T, CompactInteger>)
void encodeCompactInteger(T integer, S &s) {
requires(std::unsigned_integral<std::decay_t<T>>
or std::is_same_v<std::decay_t<T>, CompactInteger>)
and std::is_base_of_v<ScaleEncoderStream, S>
void encodeCompactInteger(T integer, S &stream) {
boost::multiprecision::cpp_int value{integer};

// cannot encode negative numbers
Expand All @@ -57,19 +64,19 @@ namespace scale::detail {

if (value < kMinUint16) {
uint8_t v = (value.convert_to<uint8_t>() << 2u) | 0b00;
return encodeInteger(v, s);
return encodeInteger(v, stream);
}

else if (value < kMinUint32) {
if (value < kMinUint32) {
// only values from [kMinUint16, kMinUint32) can be put here
uint16_t v = (value.convert_to<uint16_t>() << 2u) | 0b01;
return encodeInteger(v, s);
return encodeInteger(v, stream);
}

else if (value < kMinBigInteger) {
if (value < kMinBigInteger) {
// only values from [kMinUint32, kMinBigInteger) can be put here
uint32_t v = (value.convert_to<uint32_t>() << 2u) | 0b10;
return encodeInteger(v, s);
return encodeInteger(v, stream);
}

// number of bytes required to represent value
Expand All @@ -91,20 +98,21 @@ namespace scale::detail {
// to the result of the previous operations.
uint8_t header = ((significant_bytes_n - 4) << 2u) | 0b11;

s << header;
stream << header;

for (auto v = value; v != 0; v >>= 8) {
// push back the least significant byte
s << static_cast<uint8_t>(v & 0xff);
stream << static_cast<uint8_t>(v & 0xff);
}
}

template <typename T, typename S>
requires std::is_same_v<T, CompactInteger>
and std::is_base_of_v<ScaleDecoderStream, S>
T decodeCompactInteger(S &stream) {
auto first_byte = stream.nextByte();

const uint8_t flag = (first_byte)&0b00000011u;
const uint8_t flag = (first_byte) & 0b00000011u;

size_t number = 0u;

Expand All @@ -117,7 +125,7 @@ namespace scale::detail {
case 0b01u: {
auto second_byte = stream.nextByte();

number = (static_cast<size_t>((first_byte)&0b11111100u)
number = (static_cast<size_t>((first_byte) & 0b11111100u)
+ static_cast<size_t>(second_byte) * 256u)
>> 2u;
if ((number >> 6) == 0) {
Expand Down Expand Up @@ -186,14 +194,14 @@ namespace scale::detail {
*/
template <typename T, typename S>
requires std::unsigned_integral<T>
T decodeCompactInteger(S &s) {
auto integer = decodeCompactInteger<CompactInteger>(s);
and std::is_base_of_v<ScaleDecoderStream, S>
T decodeCompactInteger(S &stream) {
auto integer = decodeCompactInteger<CompactInteger>(stream);
if (not integer.is_zero()
and msb(integer) >= std::numeric_limits<T>::digits) {
raise(DecodeError::DECODED_VALUE_OVERFLOWS_TARGET);
}
return static_cast<T>(integer);
}


} // namespace scale::detail
29 changes: 13 additions & 16 deletions include/scale/detail/fixed_width_integer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,34 @@

#pragma once

#include <algorithm>
#include <array>
#include <cstdint>
#include <vector>

#include <boost/endian/arithmetic.hpp>

#include <scale/outcome/outcome_throw.hpp>
#include <scale/scale_error.hpp>
#include <scale/unreachable.hpp>
namespace scale {
class ScaleEncoderStream;
}

namespace scale::detail {

/**
* encodeInteger encodes any integer type to little-endian representation
* @tparam T integer type
* @tparam S output stream type
* @tparam S output stream type, derived from ScaleEncoderStream
* @param value integer value
* @return byte array representation of value
* @param stream output stream
*/
template <class T,
class S,
typename I = std::decay_t<T>,
typename = std::enable_if_t<std::is_integral<I>::value>>
void encodeInteger(T value, S &out) { // no need to take integers by &&
template <typename T, typename S>
requires std::is_integral_v<std::decay_t<T>>
&& std::is_base_of_v<ScaleEncoderStream, S>
void encodeInteger(T value, S &stream) {
using I = std::decay_t<T>;
constexpr size_t size = sizeof(I);
constexpr size_t bits = size * 8;
boost::endian::endian_buffer<boost::endian::order::little, I, bits> buf{};
buf = value; // cannot initialize, only assign
for (size_t i = 0; i < size; ++i) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
out << buf.data()[i];
stream << buf.data()[i];
}
}

} // namespace scale::detail
6 changes: 4 additions & 2 deletions include/scale/detail/jam_compact_integer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ namespace scale::detail {
* @return byte array representation of value as jam-compact-integer
*/
template <typename T, typename S>
requires(std::unsigned_integral<T> or std::is_same_v<T, CompactInteger>)
requires(std::unsigned_integral<std::decay_t<T>>
or std::is_same_v<std::decay_t<T>, CompactInteger>)
void encodeJamCompactInteger(T integer, S &s) {
size_t value;

Expand Down Expand Up @@ -100,7 +101,8 @@ namespace scale::detail {
val_mask >>= 1;
val_bits &= val_mask;

if ((len_bits & static_cast<uint8_t>(0x80)) == 0) { // no more significant bytes
if ((len_bits & static_cast<uint8_t>(0x80))
== 0) { // no more significant bytes
value |= static_cast<size_t>(val_bits) << (8 * i);
break;
}
Expand Down
Loading
Loading