From bf09e2b7ef21ec2e1b8cc9e62efaa05cb601820c Mon Sep 17 00:00:00 2001 From: Stephane Janel Date: Mon, 11 Nov 2024 19:13:25 +0100 Subject: [PATCH] Add insert_or_assign for MonetaryAmountByCurrencySet --- cmake/CoincenterUtils.cmake | 4 +-- src/api/common/src/exchangeprivateapi.cpp | 1 + src/api/common/src/exchangepublicapi.cpp | 1 + src/api/exchanges/src/binancepublicapi.cpp | 1 - src/basic-objects/CMakeLists.txt | 9 +++++ src/basic-objects/include/cct_const.hpp | 8 ++--- .../include/monetaryamountbycurrencyset.hpp | 36 +++++++++++++++---- .../test/monetaryamountbycurrencyset_test.cpp | 31 ++++++++++++++++ src/schema/include/read-json.hpp | 18 +++++----- 9 files changed, 88 insertions(+), 21 deletions(-) rename src/{objects => basic-objects}/include/monetaryamountbycurrencyset.hpp (65%) create mode 100644 src/basic-objects/test/monetaryamountbycurrencyset_test.cpp diff --git a/cmake/CoincenterUtils.cmake b/cmake/CoincenterUtils.cmake index 19932696..b9c9d7dc 100644 --- a/cmake/CoincenterUtils.cmake +++ b/cmake/CoincenterUtils.cmake @@ -20,7 +20,7 @@ function (target_set_coincenter_options name) endif() else() if(MSVC) - target_compile_options(${name} PRIVATE /W1) + target_compile_options(${name} PRIVATE /W1) else() target_compile_options(${name} PRIVATE -Wdisabled-optimization -Winline) endif() @@ -46,4 +46,4 @@ function(add_coincenter_executable name) add_executable(${name} ${MY_UNPARSED_ARGUMENTS}) target_set_coincenter_options(${name}) -endfunction() \ No newline at end of file +endfunction() diff --git a/src/api/common/src/exchangeprivateapi.cpp b/src/api/common/src/exchangeprivateapi.cpp index bae4b54d..733e02a6 100644 --- a/src/api/common/src/exchangeprivateapi.cpp +++ b/src/api/common/src/exchangeprivateapi.cpp @@ -34,6 +34,7 @@ #include "monetaryamount.hpp" #include "monetaryamountbycurrencyset.hpp" #include "orderid.hpp" +#include "permanentcurloptions.hpp" #include "priceoptions.hpp" #include "priceoptionsdef.hpp" #include "recentdeposit.hpp" diff --git a/src/api/common/src/exchangepublicapi.cpp b/src/api/common/src/exchangepublicapi.cpp index 0b377ca4..8a5d384e 100644 --- a/src/api/common/src/exchangepublicapi.cpp +++ b/src/api/common/src/exchangepublicapi.cpp @@ -33,6 +33,7 @@ #include "market.hpp" #include "marketorderbook.hpp" #include "monetaryamount.hpp" +#include "permanentcurloptions.hpp" #include "priceoptions.hpp" #include "priceoptionsdef.hpp" #include "public-trade-vector.hpp" diff --git a/src/api/exchanges/src/binancepublicapi.cpp b/src/api/exchanges/src/binancepublicapi.cpp index a515cd67..ddf5e35d 100644 --- a/src/api/exchanges/src/binancepublicapi.cpp +++ b/src/api/exchanges/src/binancepublicapi.cpp @@ -40,7 +40,6 @@ #include "permanentcurloptions.hpp" #include "public-trade-vector.hpp" #include "request-retry.hpp" -#include "runmodes.hpp" #include "timedef.hpp" #include "tradeside.hpp" #include "volumeandpricenbdecimals.hpp" diff --git a/src/basic-objects/CMakeLists.txt b/src/basic-objects/CMakeLists.txt index 92247654..ea9c681f 100644 --- a/src/basic-objects/CMakeLists.txt +++ b/src/basic-objects/CMakeLists.txt @@ -30,4 +30,13 @@ add_unit_test( coincenter_basic-objects DEFINITIONS CCT_DISABLE_SPDLOG +) + +add_unit_test( + monetaryamountbycurrencyset_test + test/monetaryamountbycurrencyset_test.cpp + LIBRARIES + coincenter_basic-objects + DEFINITIONS + CCT_DISABLE_SPDLOG ) \ No newline at end of file diff --git a/src/basic-objects/include/cct_const.hpp b/src/basic-objects/include/cct_const.hpp index 54776de8..763e2d7b 100644 --- a/src/basic-objects/include/cct_const.hpp +++ b/src/basic-objects/include/cct_const.hpp @@ -9,7 +9,7 @@ namespace cct { -enum class SupportedExchangeName : int8_t { binance, bithumb, huobi, kraken, kucoin, upbit }; +enum class ExchangeNameEnum : int8_t { binance, bithumb, huobi, kraken, kucoin, upbit }; static constexpr std::string_view kDefaultDataDir = CCT_DATA_DIR; @@ -32,8 +32,8 @@ static constexpr std::string_view kExchangeConfigFileName = "exchangeconfig.json // To make enum serializable as strings template <> -struct glz::meta { - using enum cct::SupportedExchangeName; +struct glz::meta { + using enum cct::ExchangeNameEnum; static constexpr auto value = enumerate(binance, bithumb, huobi, kraken, kucoin, upbit); }; @@ -41,7 +41,7 @@ struct glz::meta { namespace cct { /// Ordered list of supported exchange names. -static constexpr auto kSupportedExchanges = json::reflect::keys; +static constexpr auto kSupportedExchanges = json::reflect::keys; static_assert(std::ranges::is_sorted(kSupportedExchanges)); diff --git a/src/objects/include/monetaryamountbycurrencyset.hpp b/src/basic-objects/include/monetaryamountbycurrencyset.hpp similarity index 65% rename from src/objects/include/monetaryamountbycurrencyset.hpp rename to src/basic-objects/include/monetaryamountbycurrencyset.hpp index dde603e5..a7ee5c7a 100644 --- a/src/objects/include/monetaryamountbycurrencyset.hpp +++ b/src/basic-objects/include/monetaryamountbycurrencyset.hpp @@ -45,8 +45,8 @@ class MonetaryAmountByCurrencySet { void clear() noexcept { _set.clear(); } - const_iterator find(const MonetaryAmount &v) const { return _set.find(v); } - bool contains(const MonetaryAmount &v) const { return find(v) != end(); } + const_iterator find(const value_type &v) const { return _set.find(v); } + bool contains(const value_type &v) const { return find(v) != end(); } const_iterator find(CurrencyCode standardCode) const { // This is possible as MonetaryAmount are ordered by standard code @@ -65,22 +65,46 @@ class MonetaryAmountByCurrencySet { bool contains(CurrencyCode standardCode) const { return find(standardCode) != end(); } - std::pair insert(const MonetaryAmount &v) { return _set.insert(v); } - std::pair insert(MonetaryAmount &&v) { return _set.insert(std::move(v)); } + std::pair insert(const value_type &v) { return _set.insert(v); } + std::pair insert(value_type &&v) { return _set.insert(std::move(v)); } - iterator insert(const_iterator hint, const MonetaryAmount &v) { return _set.insert(hint, v); } - iterator insert(const_iterator hint, MonetaryAmount &&v) { return _set.insert(hint, std::move(v)); } + iterator insert(const_iterator hint, const value_type &v) { return _set.insert(hint, v); } + iterator insert(const_iterator hint, value_type &&v) { return _set.insert(hint, std::move(v)); } template void insert(InputIt first, InputIt last) { _set.insert(first, last); } + iterator insert_or_assign(const value_type &v) { + auto [it, inserted] = _set.insert(v); + // We only change the amount, not the currency, so the order is still valid + const_cast(*it) = v; + return it; + } + + // Inserts elements in the set as if by insert, but if an amount in the range [first, last) already exists in the + // set for a given currency, assigns the amount of that element with the amount of this MonetaryAmount being inserted. + template + void insert_or_assign(InputIt first, InputIt last) { + iterator insertHint = begin(); + while (first != last) { + insertHint = _set.insert(insertHint, *first); + + // We only change the amount, not the currency, so the order is still valid + const_cast(*insertHint) = *first; + + ++first; + } + } + template std::pair emplace(Args &&...args) { return _set.emplace(std::forward(args)...); } + auto operator<=>(const MonetaryAmountByCurrencySet &) const = default; + using trivially_relocatable = is_trivially_relocatable::type; private: diff --git a/src/basic-objects/test/monetaryamountbycurrencyset_test.cpp b/src/basic-objects/test/monetaryamountbycurrencyset_test.cpp new file mode 100644 index 00000000..550de53c --- /dev/null +++ b/src/basic-objects/test/monetaryamountbycurrencyset_test.cpp @@ -0,0 +1,31 @@ +#include "monetaryamountbycurrencyset.hpp" + +#include + +namespace cct { + +class MonetaryAmountByCurrencySetTest : public ::testing::Test { + protected: + MonetaryAmountByCurrencySet set{MonetaryAmount("1.5 EUR"), MonetaryAmount("2.5 DOGE"), MonetaryAmount("3.5 BTC")}; +}; + +TEST_F(MonetaryAmountByCurrencySetTest, InsertOrAssign) { + set.insert_or_assign(MonetaryAmount("2.5 EUR")); + auto it = set.find(CurrencyCode("EUR")); + ASSERT_NE(it, set.end()); + EXPECT_EQ(*it, MonetaryAmount("2.5 EUR")); +} + +TEST_F(MonetaryAmountByCurrencySetTest, InsertOrAssignRange) { + MonetaryAmountByCurrencySet other{MonetaryAmount("4 ETH"), MonetaryAmount("5.5 DOGE"), MonetaryAmount("6.5 POW")}; + set.insert_or_assign(other.begin(), other.end()); // Inserting the same currency as in set should overwrite the value + + EXPECT_EQ(set.size(), 5U); + + MonetaryAmountByCurrencySet expected{MonetaryAmount("1.5 EUR"), MonetaryAmount("4 ETH"), MonetaryAmount("5.5 DOGE"), + MonetaryAmount("6.5 POW"), MonetaryAmount("3.5 BTC")}; + + EXPECT_EQ(set, expected); +} + +} // namespace cct \ No newline at end of file diff --git a/src/schema/include/read-json.hpp b/src/schema/include/read-json.hpp index 42f9191e..89dd40b7 100644 --- a/src/schema/include/read-json.hpp +++ b/src/schema/include/read-json.hpp @@ -9,11 +9,13 @@ namespace cct { namespace { -constexpr auto JsonOptions = json::opts{.raw_string = true}; // NOLINT(readability-implicit-bool-conversion) +constexpr auto kJsonOptions = + json::opts{.error_on_const_read = true, .raw_string = true}; // NOLINT(readability-implicit-bool-conversion) } +template void ReadJsonOrThrow(std::string_view strContent, auto &outObject) { - auto ec = json::read(outObject, strContent); + auto ec = json::read(outObject, strContent); if (ec) { std::string_view prefixJsonContent = strContent.substr(0, std::min(strContent.size(), 20)); @@ -22,23 +24,23 @@ void ReadJsonOrThrow(std::string_view strContent, auto &outObject) { } } -template +template T ReadJsonOrThrow(std::string_view strContent) { T outObject; - ReadJsonOrThrow(strContent, outObject); + ReadJsonOrThrow(strContent, outObject); return outObject; } -template +template T ReadJsonOrThrow(const Reader &reader) { - return ReadJsonOrThrow(reader.readAll()); + return ReadJsonOrThrow(reader.readAll()); } -template +template T ReadJsonOrCreateFile(const File &file) { T outObject; if (file.exists()) { - ReadJsonOrThrow(file.readAll(), outObject); + ReadJsonOrThrow(file.readAll(), outObject); } else { file.write(WriteJsonOrThrow(outObject)); }