Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 42 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,44 @@

cmake_minimum_required(VERSION 3.12)

option(JAM_COMPATIBLE "Build compatible with JAM-codec" OFF)
option(CUSTOM_CONFIG_SUPPORT "Support custom config of streams" OFF)

option(BUILD_TESTS "Whether to include the test suite in build" OFF)

if (PACKAGE_MANAGER)
if(PACKAGE_MANAGER NOT MATCHES "^(hunter|vcpkg)$")
message(FATAL_ERROR "PACKAGE_MANAGER must be set to 'hunter', 'vcpkg' or isn't set")
endif ()
else ()
set(PACKAGE_MANAGER "hunter")
if (CMAKE_TOOLCHAIN_FILE)
get_filename_component(ACTUAL_NAME ${CMAKE_TOOLCHAIN_FILE} NAME)
if(ACTUAL_NAME STREQUAL "vcpkg.cmake")
message(STATUS "vcpkg will be used because vcpkg.cmake has found")
set(PACKAGE_MANAGER "vcpkg")
endif ()
endif ()
endif ()
message(STATUS "Selected package manager: ${PACKAGE_MANAGER}")

if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.27")
cmake_policy(SET CMP0144 NEW)
endif ()

include(${CMAKE_CURRENT_LIST_DIR}/cmake/HunterGate.cmake)
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
)
endif ()

HunterGate(
URL https://github.com/qdrvm/hunter/archive/refs/tags/v0.25.3-qdrvm25.tar.gz
SHA1 bf5742041306c4b2c8b65b9c2d2af712a36ac3f9
)
if(BUILD_TESTS)
if (PACKAGE_MANAGER STREQUAL "vcpkg")
list(APPEND VCPKG_MANIFEST_FEATURES scale-tests)
endif()
endif()

project(Scale LANGUAGES CXX VERSION 1.1.0)

Expand All @@ -25,15 +53,16 @@ set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

option(JAM_COMPATIBLE "Build compatible with JAM-codec" OFF)
option(CUSTOM_CONFIG_SUPPORT "Support custom config of streams" OFF)

option(BUILD_TESTS "Whether to include the test suite in build" OFF)

hunter_add_package(Boost)
find_package(Boost CONFIG REQUIRED)
if (PACKAGE_MANAGER STREQUAL "hunter")
hunter_add_package(Boost)
find_package(Boost)
else()
find_package(Boost CONFIG REQUIRED COMPONENTS endian multiprecision)
endif ()

hunter_add_package(qtils)
if (PACKAGE_MANAGER STREQUAL "hunter")
hunter_add_package(qtils)
endif ()
find_package(qtils CONFIG REQUIRED)

set(DEFINITION_PATH "${CMAKE_CURRENT_SOURCE_DIR}/include/scale/definitions.hpp")
Expand Down
48 changes: 47 additions & 1 deletion include/scale/scale_decoder_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@
#include <optional>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>

#ifdef __has_include
#if __has_include(<boost/variant.hpp>)
#include <boost/variant.hpp>
#define USE_BOOST_VARIANT
#endif
#endif

#include <scale/bitvec.hpp>
#include <scale/definitions.hpp>
Expand Down Expand Up @@ -91,7 +97,29 @@ namespace scale {

/**
* @brief scale-decoding of variant
* @tparam T enumeration of various types
* @tparam Ts enumeration of various types
* @param v reference to variant
* @return reference to stream
*/
template <class... Ts>
ScaleDecoderStream &operator>>(std::variant<Ts...> &v) {
// first byte means type index
uint8_t type_index = 0u;
*this >> type_index; // decode type index

// ensure that index is in [0, types_count)
if (type_index >= sizeof...(Ts)) {
raise(DecodeError::WRONG_TYPE_INDEX);
}

tryDecodeAsOneOfVariant<0>(v, type_index);
return *this;
}

#ifdef USE_BOOST_VARIANT
/**
* @brief scale-decoding of variant
* @tparam Ts enumeration of various types
* @param v reference to variant
* @return reference to stream
*/
Expand All @@ -109,6 +137,7 @@ namespace scale {
tryDecodeAsOneOfVariant<0>(v, type_index);
return *this;
}
#endif // USE_BOOST_VARIANT

/**
* @brief scale-decodes shared_ptr value
Expand Down Expand Up @@ -382,6 +411,22 @@ namespace scale {
}
}

template <size_t I, class... Ts>
void tryDecodeAsOneOfVariant(std::variant<Ts...> &v, size_t i) {
using T = std::remove_const_t<std::tuple_element_t<I, std::tuple<Ts...>>>;
static_assert(std::is_default_constructible_v<T>);
if (I == i) {
T val;
*this >> val;
v = std::forward<T>(val);
return;
}
if constexpr (sizeof...(Ts) > I + 1) {
tryDecodeAsOneOfVariant<I + 1>(v, i);
}
}

#ifdef USE_BOOST_VARIANT
template <size_t I, class... Ts>
void tryDecodeAsOneOfVariant(boost::variant<Ts...> &v, size_t i) {
using T = std::remove_const_t<std::tuple_element_t<I, std::tuple<Ts...>>>;
Expand All @@ -396,6 +441,7 @@ namespace scale {
tryDecodeAsOneOfVariant<I + 1>(v, i);
}
}
#endif // USE_BOOST_VARIANT

ByteSpan span_;

Expand Down
34 changes: 34 additions & 0 deletions include/scale/scale_encoder_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@
#include <optional>
#include <string>
#include <utility>
#include <variant>
#include <vector>

#ifdef __has_include
#if __has_include(<boost/variant.hpp>)
#include <boost/variant.hpp>
#define USE_BOOST_VARIANT
#endif
#endif

#include <scale/bitvec.hpp>
#include <scale/definitions.hpp>
Expand Down Expand Up @@ -117,6 +123,19 @@ namespace scale {
return *this;
}

/**
* @brief scale-encodes variant value
* @tparam T type list
* @param v value to encode
* @return reference to stream
*/
template <class... T>
ScaleEncoderStream &operator<<(const std::variant<T...> &v) {
tryEncodeAsOneOfVariant<0>(v);
return *this;
}

#ifdef USE_BOOST_VARIANT
/**
* @brief scale-encodes variant value
* @tparam T type list
Expand All @@ -128,6 +147,7 @@ namespace scale {
tryEncodeAsOneOfVariant<0>(v);
return *this;
}
#endif // USE_BOOST_VARIANT

/**
* @brief scale-encodes sharead_ptr value
Expand Down Expand Up @@ -260,6 +280,19 @@ namespace scale {
}
}

template <uint8_t I, class... Ts>
void tryEncodeAsOneOfVariant(const std::variant<Ts...> &v) {
using T = std::tuple_element_t<I, std::tuple<Ts...>>;
if (v.index() == I) {
*this << I << std::get<T>(v);
return;
}
if constexpr (sizeof...(Ts) > I + 1) {
tryEncodeAsOneOfVariant<I + 1>(v);
}
}

#ifdef USE_BOOST_VARIANT
template <uint8_t I, class... Ts>
void tryEncodeAsOneOfVariant(const boost::variant<Ts...> &v) {
using T = std::tuple_element_t<I, std::tuple<Ts...>>;
Expand All @@ -271,6 +304,7 @@ namespace scale {
tryEncodeAsOneOfVariant<I + 1>(v);
}
}
#endif // USE_BOOST_VARIANT

/**
* @brief scale-encodes any dynamic collection
Expand Down
7 changes: 5 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ if (POLICY CMP0076)
cmake_policy(SET CMP0076 NEW)
endif ()

hunter_add_package(GTest)
if (PACKAGE_MANAGER STREQUAL "hunter")
hunter_add_package(GTest)
endif ()
find_package(GTest CONFIG REQUIRED)

function(disable_clang_tidy target)
Expand Down Expand Up @@ -104,7 +106,8 @@ target_link_libraries(scale_collection_test
)

addtest(scale_variant_test
scale_variant_test.cpp
scale_std_variant_test.cpp
scale_boost_variant_test.cpp
)
target_link_libraries(scale_variant_test
scale
Expand Down
6 changes: 4 additions & 2 deletions test/installation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ set(CMAKE_CXX_STANDARD 20)
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}/scale-install/")
find_package(scale REQUIRED)

hunter_add_package(Boost COMPONENTS random)
find_package(Boost CONFIG REQUIRED random)
if (PACKAGE_MANAGER STREQUAL "hunter")
hunter_add_package(Boost COMPONENTS random)
endif ()
find_package(Boost CONFIG REQUIRED COMPONENTS random)

add_executable(scale_test scale_test.cpp)
target_link_libraries(scale_test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
#include <gtest/gtest.h>
#include <scale/scale.hpp>

#ifdef USE_BOOST_VARIANT

using scale::ByteArray;
using scale::decode;
using scale::encode;
using scale::ScaleDecoderStream;
using scale::ScaleEncoderStream;

class VariantFixture
class BoostVariantFixture
: public testing::TestWithParam<
std::pair<boost::variant<uint8_t, uint32_t>, ByteArray>> {
protected:
Expand All @@ -32,14 +34,14 @@ namespace {
* @when value is scale-encoded
* @then encoded bytes match predefined byte array
*/
TEST_P(VariantFixture, EncodeSuccessTest) {
TEST_P(BoostVariantFixture, EncodeSuccessTest) {
const auto &[value, match] = GetParam();
ASSERT_NO_THROW(s << value);
ASSERT_EQ(s.to_vector(), match);
}

INSTANTIATE_TEST_SUITE_P(CompactTestCases,
VariantFixture,
BoostVariantFixture,
::testing::Values(make_pair(uint8_t(1), {0, 1}),
make_pair(uint32_t(2),
{1, 2, 0, 0, 0})));
Expand All @@ -51,7 +53,7 @@ INSTANTIATE_TEST_SUITE_P(CompactTestCases,
* @then obtained varian has alternative type uint8_t and is equal to encoded
* uint8_t value
*/
TEST(ScaleVariant, DecodeU8Success) {
TEST(ScaleBoostVariant, DecodeU8Success) {
ByteArray match = {0, 1}; // uint8_t{1}
ScaleDecoderStream s(match);
boost::variant<uint8_t, uint32_t> val{};
Expand All @@ -66,10 +68,12 @@ TEST(ScaleVariant, DecodeU8Success) {
* @then obtained varian has alternative type uint32_t and is equal to encoded
* uint32_t value
*/
TEST(ScaleVariant, DecodeU32Success) {
TEST(ScaleBoostVariant, DecodeU32Success) {
ByteArray match = {1, 1, 0, 0, 0}; // uint32_t{1}
ScaleDecoderStream s(match);
boost::variant<uint8_t, uint32_t> val{};
ASSERT_NO_THROW(s >> val);
ASSERT_EQ(boost::get<uint32_t>(val), 1);
}

#endif
74 changes: 74 additions & 0 deletions test/scale_std_variant_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Copyright Quadrivium LLC
* All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*/

#include <gtest/gtest.h>
#include <scale/scale.hpp>

using scale::ByteArray;
using scale::decode;
using scale::encode;
using scale::ScaleDecoderStream;
using scale::ScaleEncoderStream;

class StdVariantFixture
: public testing::TestWithParam<
std::pair<std::variant<uint8_t, uint32_t>, ByteArray>> {
protected:
ScaleEncoderStream s;
};
namespace {
std::pair<std::variant<uint8_t, uint32_t>, ByteArray> make_pair(
std::variant<uint8_t, uint32_t> v, ByteArray m) {
return {v, std::move(m)};
}
} // namespace

/**
* @given variant value and byte array
* @when value is scale-encoded
* @then encoded bytes match predefined byte array
*/
TEST_P(StdVariantFixture, EncodeSuccessTest) {
const auto &[value, match] = GetParam();
ASSERT_NO_THROW(s << value);
ASSERT_EQ(s.to_vector(), match);
}

INSTANTIATE_TEST_SUITE_P(CompactTestCases,
StdVariantFixture,
::testing::Values(make_pair(uint8_t(1), {0, 1}),
make_pair(uint32_t(2),
{1, 2, 0, 0, 0})));

/**
* @given byte array of encoded variant of types uint8_t and uint32_t
* containing uint8_t value
* @when variant decoded from scale decoder stream
* @then obtained varian has alternative type uint8_t and is equal to encoded
* uint8_t value
*/
TEST(ScaleStdVariant, DecodeU8Success) {
ByteArray match = {0, 1}; // uint8_t{1}
ScaleDecoderStream s(match);
std::variant<uint8_t, uint32_t> val{};
ASSERT_NO_THROW(s >> val);
ASSERT_EQ(std::get<uint8_t>(val), 1);
}

/**
* @given byte array of encoded variant of types uint8_t and uint32_t
* containing uint32_t value
* @when variant decoded from scale decoder stream
* @then obtained varian has alternative type uint32_t and is equal to encoded
* uint32_t value
*/
TEST(ScaleStdVariant, DecodeU32Success) {
ByteArray match = {1, 1, 0, 0, 0}; // uint32_t{1}
ScaleDecoderStream s(match);
std::variant<uint8_t, uint32_t> val{};
ASSERT_NO_THROW(s >> val);
ASSERT_EQ(std::get<uint32_t>(val), 1);
}
Loading
Loading