diff --git a/CHANGELOG.md b/CHANGELOG.md index e1c4bd3..ba6ac02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.18.0 - 2024-05-14 + +### Breaking changes +- Changed `FlagSet` to be more class-like: + - Added predicate methods and setters for each bit flag + - Improved string formatting + - Removed bitwise operators. Bitwise operations can be performed by first casting to a + `std::uint8_t` or calling the `Raw()` method +- Changed format of `display_factor` and `price_ratio` to a fixed-precision decimal for + `InstrumentDefMsg` and `InstrumentDefMsgV1` to match existing values and DBN crate +- Changed format of `unit_of_measure_qty` to a fixed-precision decimal for + `InstrumentDefMsgV1` to match `InstrumentDefMsg` + ## 0.17.1 - 2024-04-08 ### Enhancements diff --git a/CMakeLists.txt b/CMakeLists.txt index e5a3ccc..b875053 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.14) # Project details # -project("databento" VERSION 0.17.1 LANGUAGES CXX) +project("databento" VERSION 0.18.0 LANGUAGES CXX) string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERCASE) # diff --git a/cmake/SourcesAndHeaders.cmake b/cmake/SourcesAndHeaders.cmake index dc775dc..0c8d686 100644 --- a/cmake/SourcesAndHeaders.cmake +++ b/cmake/SourcesAndHeaders.cmake @@ -6,6 +6,14 @@ set(headers include/databento/dbn.hpp include/databento/dbn_decoder.hpp include/databento/dbn_file_store.hpp + include/databento/detail/file_stream.hpp + include/databento/detail/http_client.hpp + include/databento/detail/json_helpers.hpp + include/databento/detail/scoped_fd.hpp + include/databento/detail/scoped_thread.hpp + include/databento/detail/shared_channel.hpp + include/databento/detail/tcp_client.hpp + include/databento/detail/zstd_stream.hpp include/databento/enums.hpp include/databento/exceptions.hpp include/databento/fixed_price.hpp @@ -23,14 +31,6 @@ set(headers include/databento/symbology.hpp include/databento/timeseries.hpp include/databento/with_ts_out.hpp - include/databento/detail/file_stream.hpp - include/databento/detail/http_client.hpp - include/databento/detail/json_helpers.hpp - include/databento/detail/scoped_fd.hpp - include/databento/detail/scoped_thread.hpp - include/databento/detail/shared_channel.hpp - include/databento/detail/tcp_client.hpp - include/databento/detail/zstd_stream.hpp src/stream_op_helper.hpp ) @@ -40,10 +40,18 @@ set(sources src/datetime.cpp src/dbn.cpp src/dbn_decoder.cpp + src/dbn_file_store.cpp + src/detail/file_stream.cpp + src/detail/http_client.cpp + src/detail/json_helpers.cpp + src/detail/scoped_fd.cpp + src/detail/shared_channel.cpp + src/detail/tcp_client.cpp + src/detail/zstd_stream.cpp src/enums.cpp src/exceptions.cpp - src/dbn_file_store.cpp src/fixed_price.cpp + src/flag_set.cpp src/historical.cpp src/live.cpp src/live_blocking.cpp @@ -54,11 +62,4 @@ set(sources src/record.cpp src/symbol_map.cpp src/symbology.cpp - src/detail/file_stream.cpp - src/detail/http_client.cpp - src/detail/json_helpers.cpp - src/detail/scoped_fd.cpp - src/detail/shared_channel.cpp - src/detail/tcp_client.cpp - src/detail/zstd_stream.cpp ) diff --git a/include/databento/flag_set.hpp b/include/databento/flag_set.hpp index 83b5ab0..e933412 100644 --- a/include/databento/flag_set.hpp +++ b/include/databento/flag_set.hpp @@ -1,15 +1,15 @@ #pragma once -#include #include #include +#include namespace databento { // Transparent wrapper around the bit flags used in several DBN record types. class FlagSet { public: using Repr = std::uint8_t; - // Indicates it's the last message in the packet from the venue for a given + // Indicates it's the last message in the event from the venue for a given // `instrument_id`. static constexpr Repr kLast = 1 << 7; // Indicates a top-of-book message, not an individual order. @@ -27,61 +27,76 @@ class FlagSet { friend std::ostream& operator<<(std::ostream&, FlagSet); - constexpr FlagSet() = default; + constexpr FlagSet() : repr_{0} {}; - constexpr FlagSet( // cppcheck-suppress noExplicitConstructor - std::uint8_t repr) - : repr_{repr} {} + explicit constexpr FlagSet(Repr repr) : repr_{repr} {} explicit constexpr operator std::uint8_t() const { return repr_; } - constexpr FlagSet operator~() const { - return FlagSet{static_cast(~repr_)}; - } + constexpr bool operator==(FlagSet rhs) const { return repr_ == rhs.repr_; } + constexpr bool operator!=(FlagSet rhs) const { return repr_ != rhs.repr_; } - constexpr FlagSet operator|(FlagSet rhs) const { - return FlagSet{static_cast(repr_ | rhs.repr_)}; + FlagSet Clear() { + repr_ = 0; + return *this; } - constexpr FlagSet operator&(FlagSet rhs) const { - return FlagSet{static_cast(repr_ & rhs.repr_)}; - } + constexpr Repr Raw() const { return repr_; } + void SetRaw(Repr raw) { repr_ = raw; } - constexpr FlagSet operator^(FlagSet rhs) const { - return FlagSet{static_cast(repr_ ^ rhs.repr_)}; + // Checks if any flags are set. + constexpr bool Any() const { return repr_ != 0; } + constexpr bool IsEmpty() const { return repr_ == 0; } + constexpr bool IsLast() const { return bits_.last; } + FlagSet SetLast() { + bits_.last = true; + return *this; } - - FlagSet operator|=(FlagSet rhs) { - repr_ = repr_ | rhs.repr_; + constexpr bool IsTob() const { return bits_.tob; } + FlagSet SetTob() { + bits_.tob = true; return *this; } - - FlagSet operator&=(FlagSet rhs) { - repr_ = repr_ & rhs.repr_; + constexpr bool IsSnapshot() const { return bits_.snapshot; } + FlagSet SetSnapshot() { + bits_.snapshot = true; return *this; } - - FlagSet operator^=(FlagSet rhs) { - repr_ = repr_ ^ rhs.repr_; + constexpr bool IsMbp() const { return bits_.mbp; } + FlagSet SetMbp() { + bits_.mbp = true; + return *this; + } + constexpr bool IsBadTsRecv() const { return bits_.bad_ts_recv; } + FlagSet SetBadTsRecv() { + bits_.bad_ts_recv = true; + return *this; + } + constexpr bool IsMaybeBadBook() const { return bits_.maybe_bad_book; } + FlagSet SetMaybeBadBook() { + bits_.maybe_bad_book = true; return *this; } - - constexpr bool operator==(FlagSet rhs) const { return repr_ == rhs.repr_; } - - constexpr bool operator!=(FlagSet rhs) const { return repr_ != rhs.repr_; } - - // Checks if any flags are set. - constexpr bool Any() const { return repr_ != 0; } private: - Repr repr_{}; + struct BitFlags { + bool reserved0 : 1; + bool reserved1 : 1; + bool maybe_bad_book : 1; + bool bad_ts_recv : 1; + bool mbp : 1; + bool snapshot : 1; + bool tob : 1; + bool last : 1; + }; + union { + BitFlags bits_; + Repr repr_; + }; }; -inline std::ostream& operator<<(std::ostream& stream, FlagSet flag) { - // print as binary - stream << "0b" << std::bitset<8>{flag.repr_}; - return stream; -} +std::ostream& operator<<(std::ostream& stream, FlagSet flag_set); +std::string ToString(FlagSet flags); static_assert(sizeof(FlagSet) == sizeof(std::uint8_t), "FlagSet must be a transparent wrapper around std::uint8_t"); diff --git a/pkg/PKGBUILD b/pkg/PKGBUILD index 9702407..9dca420 100644 --- a/pkg/PKGBUILD +++ b/pkg/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Databento _pkgname=databento-cpp pkgname=databento-cpp-git -pkgver=0.17.1 +pkgver=0.18.0 pkgrel=1 pkgdesc="Official C++ client for Databento" arch=('any') diff --git a/src/compat.cpp b/src/compat.cpp index 4f34d45..398a5c5 100644 --- a/src/compat.cpp +++ b/src/compat.cpp @@ -110,10 +110,12 @@ SymbolMappingMsgV2 SymbolMappingMsgV1::ToV2() const { RecordHeader{sizeof(SymbolMappingMsgV2) / RecordHeader::kLengthMultiplier, RType::SymbolMapping, hd.publisher_id, hd.instrument_id, hd.ts_event}, - // invalid + // Intentionally invalid + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) static_cast(std::numeric_limits::max()), {}, - // invalid + // Intentionally invalid + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) static_cast(std::numeric_limits::max()), {}, start_ts, @@ -205,7 +207,7 @@ std::ostream& operator<<(std::ostream& stream, .AddField("hd", instr_def_msg.hd) .AddField("ts_recv", instr_def_msg.ts_recv) .AddField("min_price_increment", FixPx{instr_def_msg.min_price_increment}) - .AddField("display_factor", instr_def_msg.display_factor) + .AddField("display_factor", FixPx{instr_def_msg.display_factor}) .AddField("expiration", instr_def_msg.expiration) .AddField("activation", instr_def_msg.activation) .AddField("high_limit_price", FixPx{instr_def_msg.high_limit_price}) @@ -213,10 +215,10 @@ std::ostream& operator<<(std::ostream& stream, .AddField("max_price_variation", FixPx{instr_def_msg.max_price_variation}) .AddField("trading_reference_price", FixPx{instr_def_msg.trading_reference_price}) - .AddField("unit_of_measure_qty", instr_def_msg.unit_of_measure_qty) + .AddField("unit_of_measure_qty", FixPx{instr_def_msg.unit_of_measure_qty}) .AddField("min_price_increment_amount", FixPx{instr_def_msg.min_price_increment_amount}) - .AddField("price_ratio", instr_def_msg.price_ratio) + .AddField("price_ratio", FixPx{instr_def_msg.price_ratio}) .AddField("inst_attrib_value", instr_def_msg.inst_attrib_value) .AddField("underlying_id", instr_def_msg.underlying_id) .AddField("raw_instrument_id", instr_def_msg.raw_instrument_id) diff --git a/src/flag_set.cpp b/src/flag_set.cpp new file mode 100644 index 0000000..b988a62 --- /dev/null +++ b/src/flag_set.cpp @@ -0,0 +1,48 @@ +#include "databento/flag_set.hpp" + +#include + +#include "stream_op_helper.hpp" + +namespace databento { +constexpr FlagSet::Repr FlagSet::kLast; +constexpr FlagSet::Repr FlagSet::kTob; +constexpr FlagSet::Repr FlagSet::kSnapshot; +constexpr FlagSet::Repr FlagSet::kMbp; +constexpr FlagSet::Repr FlagSet::kBadTsRecv; +constexpr FlagSet::Repr FlagSet::kMaybeBadBook; + +std::ostream& operator<<(std::ostream& stream, FlagSet flag_set) { + const std::array, 6> + kFlagsAndNames = {{ + {&FlagSet::IsLast, "LAST"}, + {&FlagSet::IsTob, "TOB"}, + {&FlagSet::IsSnapshot, "SNAPSHOT"}, + {&FlagSet::IsMbp, "MBP"}, + {&FlagSet::IsBadTsRecv, "BAD_TS_RECV"}, + {&FlagSet::IsMaybeBadBook, "MAYBE_BAD_BOOK"}, + }}; + + bool has_written_flag = false; + for (const auto& pair : kFlagsAndNames) { + if ((flag_set.*pair.first)()) { + if (has_written_flag) { + stream << " | " << pair.second; + } else { + stream << pair.second; + has_written_flag = true; + } + } + } + // Cast to uint16_t to avoid being formatted as char + const auto raw = static_cast(flag_set.Raw()); + if (has_written_flag) { + stream << " (" << raw << ')'; + } else { + stream << raw; + } + return stream; +} + +std::string ToString(FlagSet flags) { return MakeString(flags); } +} // namespace databento diff --git a/src/live_threaded.cpp b/src/live_threaded.cpp index c7365bd..0cbe4d2 100644 --- a/src/live_threaded.cpp +++ b/src/live_threaded.cpp @@ -28,6 +28,7 @@ struct LiveThreaded::Impl { } ILogReceiver* log_receiver; + std::atomic thread_id_{}; // Set to false when destructor is called std::atomic keep_going{true}; KeepGoing last_cb_ret{KeepGoing::Continue}; @@ -114,7 +115,7 @@ void LiveThreaded::Start(MetadataCallback metadata_callback, RecordCallback record_callback, ExceptionCallback exception_callback) { // Deadlock check - if (std::this_thread::get_id() == thread_.Id()) { + if (std::this_thread::get_id() == impl_->thread_id_) { std::ostringstream log_ss; log_ss << "[LiveThreaded::Start] Called Start from callback thread, which " "would cause a deadlock. Ignoring."; @@ -161,6 +162,7 @@ void LiveThreaded::ProcessingThread(Impl* impl, static constexpr auto kMethodName = "LiveThreaded::ProcessingThread"; constexpr std::chrono::milliseconds kTimeout{50}; + impl->thread_id_ = std::this_thread::get_id(); const auto metadata_cb{std::move(metadata_callback)}; const auto record_cb{std::move(record_callback)}; const auto exception_cb{std::move(exception_callback)}; diff --git a/src/record.cpp b/src/record.cpp index 5a05753..cfe82a1 100644 --- a/src/record.cpp +++ b/src/record.cpp @@ -382,7 +382,7 @@ std::ostream& operator<<(std::ostream& stream, .AddField("hd", instr_def_msg.hd) .AddField("ts_recv", instr_def_msg.ts_recv) .AddField("min_price_increment", FixPx{instr_def_msg.min_price_increment}) - .AddField("display_factor", instr_def_msg.display_factor) + .AddField("display_factor", FixPx{instr_def_msg.display_factor}) .AddField("expiration", instr_def_msg.expiration) .AddField("activation", instr_def_msg.activation) .AddField("high_limit_price", FixPx{instr_def_msg.high_limit_price}) @@ -393,7 +393,7 @@ std::ostream& operator<<(std::ostream& stream, .AddField("unit_of_measure_qty", FixPx{instr_def_msg.unit_of_measure_qty}) .AddField("min_price_increment_amount", FixPx{instr_def_msg.min_price_increment_amount}) - .AddField("price_ratio", instr_def_msg.price_ratio) + .AddField("price_ratio", FixPx{instr_def_msg.price_ratio}) .AddField("strike_price", FixPx{instr_def_msg.strike_price}) .AddField("inst_attrib_value", instr_def_msg.inst_attrib_value) .AddField("underlying_id", instr_def_msg.underlying_id) diff --git a/test/src/dbn_decoder_tests.cpp b/test/src/dbn_decoder_tests.cpp index 72d354b..34ca6b1 100644 --- a/test/src/dbn_decoder_tests.cpp +++ b/test/src/dbn_decoder_tests.cpp @@ -6,6 +6,7 @@ #include #include // ifstream #include // streamsize, ios::binary, ios::ate +#include #include #include "databento/compat.hpp" @@ -164,6 +165,10 @@ TEST_F(DbnDecoderTests, TestUpgradeSymbolMappingWithTsOut) { EXPECT_EQ(orig.ts_out, upgraded.ts_out); EXPECT_STREQ(orig.rec.STypeInSymbol(), upgraded.rec.STypeInSymbol()); EXPECT_STREQ(orig.rec.STypeOutSymbol(), upgraded.rec.STypeOutSymbol()); + EXPECT_EQ(static_cast(upgraded.rec.stype_in), + std::numeric_limits::max()); + EXPECT_EQ(static_cast(upgraded.rec.stype_out), + std::numeric_limits::max()); // `length` properly set EXPECT_EQ(upgraded.rec.hd.Size(), sizeof(upgraded)); // used compat buffer @@ -256,7 +261,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbo) { EXPECT_EQ(ch_mbo1.order_id, 647784973705); EXPECT_EQ(ch_mbo1.price, 3722750000000); EXPECT_EQ(ch_mbo1.size, 1); - EXPECT_EQ(ch_mbo1.flags, 128); + EXPECT_EQ(ch_mbo1.flags.Raw(), 128); EXPECT_EQ(ch_mbo1.channel_id, 0); EXPECT_EQ(ch_mbo1.action, Action::Cancel); EXPECT_EQ(ch_mbo1.side, Side::Ask); @@ -280,7 +285,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbo) { EXPECT_EQ(ch_mbo2.order_id, 647784973631); EXPECT_EQ(ch_mbo2.price, 3723000000000); EXPECT_EQ(ch_mbo2.size, 1); - EXPECT_EQ(ch_mbo2.flags, 128); + EXPECT_EQ(ch_mbo2.flags.Raw(), 128); EXPECT_EQ(ch_mbo2.channel_id, 0); EXPECT_EQ(ch_mbo2.action, Action::Cancel); EXPECT_EQ(ch_mbo2.side, Side::Ask); @@ -327,7 +332,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbp1) { EXPECT_EQ(ch_mbp1.size, 1); EXPECT_EQ(ch_mbp1.action, Action::Add); EXPECT_EQ(ch_mbp1.side, Side::Ask); - EXPECT_EQ(ch_mbp1.flags, 128); + EXPECT_EQ(ch_mbp1.flags.Raw(), 128); EXPECT_EQ(ch_mbp1.depth, 0); EXPECT_EQ(ch_mbp1.ts_recv.time_since_epoch().count(), 1609160400006136329); EXPECT_EQ(ch_mbp1.ts_in_delta.count(), 17214); @@ -356,7 +361,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbp1) { EXPECT_EQ(ch_mbp2.size, 1); EXPECT_EQ(ch_mbp2.action, Action::Add); EXPECT_EQ(ch_mbp2.side, Side::Ask); - EXPECT_EQ(ch_mbp2.flags, 128); + EXPECT_EQ(ch_mbp2.flags.Raw(), 128); EXPECT_EQ(ch_mbp2.depth, 0); EXPECT_EQ(ch_mbp2.ts_recv.time_since_epoch().count(), 1609160400006246513); EXPECT_EQ(ch_mbp2.ts_in_delta.count(), 18858); @@ -407,7 +412,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbp10) { EXPECT_EQ(ch_mbp1.size, 1); EXPECT_EQ(ch_mbp1.action, Action::Cancel); EXPECT_EQ(ch_mbp1.side, Side::Ask); - EXPECT_EQ(ch_mbp1.flags, 128); + EXPECT_EQ(ch_mbp1.flags.Raw(), 128); EXPECT_EQ(ch_mbp1.depth, 9); EXPECT_EQ(ch_mbp1.ts_recv.time_since_epoch().count(), 1609160400000704060); EXPECT_EQ(ch_mbp1.ts_in_delta.count(), 22993); @@ -448,7 +453,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbp10) { EXPECT_EQ(ch_mbp2.size, 1); EXPECT_EQ(ch_mbp2.action, Action::Cancel); EXPECT_EQ(ch_mbp2.side, Side::Bid); - EXPECT_EQ(ch_mbp2.flags, 128); + EXPECT_EQ(ch_mbp2.flags.Raw(), 128); EXPECT_EQ(ch_mbp2.depth, 1); EXPECT_EQ(ch_mbp2.ts_recv.time_since_epoch().count(), 1609160400000750544); EXPECT_EQ(ch_mbp2.ts_in_delta.count(), 20625); @@ -511,7 +516,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeCbbo) { EXPECT_EQ(ch_cbbo1.size, 1); EXPECT_EQ(ch_cbbo1.action, Action::Add); EXPECT_EQ(ch_cbbo1.side, Side::Ask); - EXPECT_EQ(ch_cbbo1.flags, 128); + EXPECT_EQ(ch_cbbo1.flags.Raw(), 128); EXPECT_EQ(ch_cbbo1.ts_recv.time_since_epoch().count(), 1609160400006136329); EXPECT_EQ(ch_cbbo1.ts_in_delta.count(), 17214); EXPECT_EQ(ch_cbbo1.sequence, 1170362); @@ -539,7 +544,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeCbbo) { EXPECT_EQ(ch_cbbo2.size, 1); EXPECT_EQ(ch_cbbo2.action, Action::Add); EXPECT_EQ(ch_cbbo2.side, Side::Ask); - EXPECT_EQ(ch_cbbo2.flags, 128); + EXPECT_EQ(ch_cbbo2.flags.Raw(), 128); EXPECT_EQ(ch_cbbo2.ts_recv.time_since_epoch().count(), 1609160400006246513); EXPECT_EQ(ch_cbbo2.ts_in_delta.count(), 18858); EXPECT_EQ(ch_cbbo2.sequence, 1170364); @@ -589,7 +594,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeTbbo) { EXPECT_EQ(ch_tbbo1.size, 5); EXPECT_EQ(ch_tbbo1.action, Action::Trade); EXPECT_EQ(ch_tbbo1.side, Side::Ask); - EXPECT_EQ(ch_tbbo1.flags, 129); + EXPECT_EQ(ch_tbbo1.flags.Raw(), 129); EXPECT_EQ(ch_tbbo1.depth, 0); EXPECT_EQ(ch_tbbo1.ts_recv.time_since_epoch().count(), 1609160400099150057); EXPECT_EQ(ch_tbbo1.ts_in_delta.count(), 19251); @@ -618,7 +623,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeTbbo) { EXPECT_EQ(ch_tbbo2.size, 21); EXPECT_EQ(ch_tbbo2.action, Action::Trade); EXPECT_EQ(ch_tbbo2.side, Side::Ask); - EXPECT_EQ(ch_tbbo2.flags, 129); + EXPECT_EQ(ch_tbbo2.flags.Raw(), 129); EXPECT_EQ(ch_tbbo2.depth, 0); EXPECT_EQ(ch_tbbo2.ts_recv.time_since_epoch().count(), 1609160400108142648); EXPECT_EQ(ch_tbbo2.ts_in_delta.count(), 20728); @@ -669,7 +674,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeTrades) { EXPECT_EQ(ch_trade1.size, 5); EXPECT_EQ(ch_trade1.action, Action::Trade); EXPECT_EQ(ch_trade1.side, Side::Ask); - EXPECT_EQ(ch_trade1.flags, 129); + EXPECT_EQ(ch_trade1.flags.Raw(), 129); EXPECT_EQ(ch_trade1.depth, 0); EXPECT_EQ(ch_trade1.ts_recv.time_since_epoch().count(), 1609160400099150057); EXPECT_EQ(ch_trade1.ts_in_delta.count(), 19251); @@ -692,7 +697,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeTrades) { EXPECT_EQ(ch_trade2.size, 21); EXPECT_EQ(ch_trade2.action, Action::Trade); EXPECT_EQ(ch_trade2.side, Side::Ask); - EXPECT_EQ(ch_trade2.flags, 129); + EXPECT_EQ(ch_trade2.flags.Raw(), 129); EXPECT_EQ(ch_trade2.depth, 0); EXPECT_EQ(ch_trade2.ts_recv.time_since_epoch().count(), 1609160400108142648); EXPECT_EQ(ch_trade2.ts_in_delta.count(), 20728); diff --git a/test/src/flag_set_tests.cpp b/test/src/flag_set_tests.cpp index 9413c78..e6fd147 100644 --- a/test/src/flag_set_tests.cpp +++ b/test/src/flag_set_tests.cpp @@ -1,70 +1,62 @@ #include -#include - #include "databento/flag_set.hpp" namespace databento { namespace test { -TEST(FlagSetTests, TestBitwiseNot) { +TEST(FlagSetTests, TestBasic) { const FlagSet no_flags{}; - ASSERT_FALSE(no_flags.Any()); - const auto all_flags = ~no_flags; - ASSERT_TRUE(all_flags.Any()); - ASSERT_TRUE((all_flags & FlagSet::kLast).Any()); - ASSERT_TRUE((all_flags & FlagSet::kMbp).Any()); - ASSERT_TRUE((all_flags & FlagSet::kBadTsRecv).Any()); + EXPECT_FALSE(no_flags.Any()); + EXPECT_TRUE(no_flags.IsEmpty()); + const FlagSet all_flags{255}; + EXPECT_TRUE(all_flags.Any()); + EXPECT_FALSE(all_flags.IsEmpty()); + EXPECT_TRUE((all_flags.IsLast())); + EXPECT_TRUE((all_flags.IsMbp())); + EXPECT_TRUE((all_flags.IsBadTsRecv())); } -TEST(FlagSetTests, TestBitwiseOr) { - const FlagSet flag = FlagSet::kMbp; - const FlagSet no_flags{}; - ASSERT_NE(flag, no_flags); - ASSERT_EQ(flag, no_flags | FlagSet::kMbp); +TEST(FlagSetTests, TestAny) { + FlagSet flag{}; + ASSERT_FALSE(flag.Any()); + flag.SetBadTsRecv(); + ASSERT_TRUE(flag.Any()); } -TEST(FlagSetTests, TestBitwiseAnd) { - const auto flag = static_cast(0b10011000); - ASSERT_TRUE(flag.Any()); - ASSERT_TRUE((flag & FlagSet::kLast).Any()); - ASSERT_TRUE((flag & FlagSet::kMbp).Any()); - ASSERT_TRUE((flag & FlagSet::kBadTsRecv).Any()); +TEST(FlagSetTests, TestConversionOperator) { + constexpr FlagSet kFlagSet{FlagSet::kMbp | FlagSet::kTob}; + const auto raw = std::uint8_t{kFlagSet}; + ASSERT_EQ(raw, 0b01010000); } -TEST(FlagSetTests, TestBitwiseAndAssignment) { - FlagSet flag{}; - flag &= FlagSet::kLast; - ASSERT_FALSE((flag & FlagSet::kLast).Any()); - flag = ~flag & FlagSet::kLast; - ASSERT_TRUE((flag & FlagSet::kLast).Any()); +TEST(FlagSetTests, ToStringEmpty) { + constexpr FlagSet kTarget{}; + ASSERT_EQ(ToString(kTarget), "0"); } -TEST(FlagSetTests, TestBitwiseXor) { - FlagSet flag = ~FlagSet{}; - flag ^= FlagSet::kLast; - ASSERT_FALSE((flag & FlagSet::kLast).Any()); - ASSERT_TRUE((flag & FlagSet::kMbp).Any()); - ASSERT_TRUE((flag & FlagSet::kBadTsRecv).Any()); +TEST(FlagSetTests, ToStringOneSet) { + const auto target = FlagSet{}.SetMbp(); + ASSERT_EQ(ToString(target), "MBP (16)"); } -TEST(FlagSetTests, TestAny) { - FlagSet flag{}; - ASSERT_FALSE(flag.Any()); - flag = FlagSet::kBadTsRecv; - ASSERT_TRUE(flag.Any()); +TEST(FlagSetTests, ToStringThreeSet) { + const auto target = FlagSet{}.SetTob().SetSnapshot().SetMaybeBadBook(); + ASSERT_EQ(ToString(target), "TOB | SNAPSHOT | MAYBE_BAD_BOOK (100)"); } -TEST(FlagSetTests, TestToString) { - constexpr FlagSet kFlagSet = FlagSet::kMbp; - std::ostringstream ss; - ss << kFlagSet; - ASSERT_EQ(ss.str(), "0b00010000"); +TEST(FlagSetTests, ToStringReservedSet) { + constexpr FlagSet kTarget{255}; + ASSERT_EQ(ToString(kTarget), + "LAST | TOB | SNAPSHOT | MBP | BAD_TS_RECV | MAYBE_BAD_BOOK (255)"); } -TEST(FlagSetTests, TestConversionOperator) { - constexpr FlagSet kFlagSet = FlagSet::kMbp | FlagSet::kTob; - const auto raw = std::uint8_t{kFlagSet}; - ASSERT_EQ(raw, 0b01010000); +TEST(FlagSetTests, ConstantBitFieldEquivalence) { + EXPECT_EQ(FlagSet::kLast, FlagSet{}.SetLast().Raw()); + EXPECT_EQ(FlagSet::kTob, FlagSet{}.SetTob().Raw()); + EXPECT_EQ(FlagSet::kSnapshot, FlagSet{}.SetSnapshot().Raw()); + EXPECT_EQ(FlagSet::kMbp, FlagSet{}.SetMbp().Raw()); + EXPECT_EQ(FlagSet::kBadTsRecv, FlagSet{}.SetBadTsRecv().Raw()); + EXPECT_EQ(FlagSet::kMaybeBadBook, FlagSet{}.SetMaybeBadBook().Raw()); } } // namespace test } // namespace databento diff --git a/test/src/live_threaded_tests.cpp b/test/src/live_threaded_tests.cpp index ee5a558..ce5d97e 100644 --- a/test/src/live_threaded_tests.cpp +++ b/test/src/live_threaded_tests.cpp @@ -42,7 +42,7 @@ TEST_F(LiveThreadedTests, TestBasic) { 1, 2, 3, - 0, + {}, 4, Action::Add, Side::Bid, @@ -76,7 +76,7 @@ TEST_F(LiveThreadedTests, TestTimeoutRecovery) { 1, 2, 3, - 0, + {}, 4, Action::Add, Side::Bid, @@ -120,7 +120,7 @@ TEST_F(LiveThreadedTests, TestStop) { 1, 2, 3, - 0, + {}, 4, Action::Add, Side::Bid, diff --git a/test/src/record_tests.cpp b/test/src/record_tests.cpp index 7c7e6dd..e257aca 100644 --- a/test/src/record_tests.cpp +++ b/test/src/record_tests.cpp @@ -60,7 +60,7 @@ TEST(RecordTests, TestMbp10MsgToString) { size = 10, action = Add, side = Bid, - flags = 0b00000000, + flags = 0, depth = 0, ts_recv = 2023-10-10T16:57:52.000020500Z, ts_in_delta = 100, @@ -150,7 +150,7 @@ TEST(RecordTests, TestInstrumentDefMsgToString) { hd = RecordHeader { length = 100, rtype = InstrumentDef, publisher_id = 1, instrument_id = 1, ts_event = 1970-01-01T00:00:00.000000000Z }, ts_recv = 1970-01-01T00:00:00.000000000Z, min_price_increment = 0.000000001, - display_factor = 2, + display_factor = 0.000000002, expiration = 1970-01-01T00:00:00.000000000Z, activation = 1970-01-01T00:00:00.000000000Z, high_limit_price = 0.000000005, @@ -159,7 +159,7 @@ TEST(RecordTests, TestInstrumentDefMsgToString) { trading_reference_price = 0.000000008, unit_of_measure_qty = 0.000000009, min_price_increment_amount = 0.000000010, - price_ratio = 11, + price_ratio = 0.000000011, strike_price = kUndefPrice, inst_attrib_value = 12, underlying_id = 13,