Skip to content

Commit 57314c4

Browse files
committed
MOD: Improve FlagSet in C++
1 parent bde3e96 commit 57314c4

File tree

8 files changed

+175
-121
lines changed

8 files changed

+175
-121
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
## 0.18.0 - TBD
44

55
### Breaking changes
6+
- Changed `FlagSet` to be more class-like:
7+
- Added predicate methods and setters for each bit flag
8+
- Improved string formatting
9+
- Removed bitwise operators. Bitwise operations can be performed by first casting to a
10+
`std::uint8_t` or calling the `Raw()` method
611
- Changed format of `display_factor` and `price_ratio` to a fixed-precision decimal for
712
`InstrumentDefMsg` and `InstrumentDefMsgV1` to match existing values and DBN crate
813
- Changed format of `unit_of_measure_qty` to a fixed-precision decimal for

cmake/SourcesAndHeaders.cmake

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ set(headers
66
include/databento/dbn.hpp
77
include/databento/dbn_decoder.hpp
88
include/databento/dbn_file_store.hpp
9+
include/databento/detail/file_stream.hpp
10+
include/databento/detail/http_client.hpp
11+
include/databento/detail/json_helpers.hpp
12+
include/databento/detail/scoped_fd.hpp
13+
include/databento/detail/scoped_thread.hpp
14+
include/databento/detail/shared_channel.hpp
15+
include/databento/detail/tcp_client.hpp
16+
include/databento/detail/zstd_stream.hpp
917
include/databento/enums.hpp
1018
include/databento/exceptions.hpp
1119
include/databento/fixed_price.hpp
@@ -23,14 +31,6 @@ set(headers
2331
include/databento/symbology.hpp
2432
include/databento/timeseries.hpp
2533
include/databento/with_ts_out.hpp
26-
include/databento/detail/file_stream.hpp
27-
include/databento/detail/http_client.hpp
28-
include/databento/detail/json_helpers.hpp
29-
include/databento/detail/scoped_fd.hpp
30-
include/databento/detail/scoped_thread.hpp
31-
include/databento/detail/shared_channel.hpp
32-
include/databento/detail/tcp_client.hpp
33-
include/databento/detail/zstd_stream.hpp
3434
src/stream_op_helper.hpp
3535
)
3636

@@ -40,10 +40,18 @@ set(sources
4040
src/datetime.cpp
4141
src/dbn.cpp
4242
src/dbn_decoder.cpp
43+
src/dbn_file_store.cpp
44+
src/detail/file_stream.cpp
45+
src/detail/http_client.cpp
46+
src/detail/json_helpers.cpp
47+
src/detail/scoped_fd.cpp
48+
src/detail/shared_channel.cpp
49+
src/detail/tcp_client.cpp
50+
src/detail/zstd_stream.cpp
4351
src/enums.cpp
4452
src/exceptions.cpp
45-
src/dbn_file_store.cpp
4653
src/fixed_price.cpp
54+
src/flag_set.cpp
4755
src/historical.cpp
4856
src/live.cpp
4957
src/live_blocking.cpp
@@ -54,11 +62,4 @@ set(sources
5462
src/record.cpp
5563
src/symbol_map.cpp
5664
src/symbology.cpp
57-
src/detail/file_stream.cpp
58-
src/detail/http_client.cpp
59-
src/detail/json_helpers.cpp
60-
src/detail/scoped_fd.cpp
61-
src/detail/shared_channel.cpp
62-
src/detail/tcp_client.cpp
63-
src/detail/zstd_stream.cpp
6465
)

include/databento/flag_set.hpp

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#pragma once
22

3-
#include <bitset>
43
#include <cstdint>
54
#include <ostream>
5+
#include <string>
66

77
namespace databento {
88
// Transparent wrapper around the bit flags used in several DBN record types.
@@ -11,77 +11,92 @@ class FlagSet {
1111
using Repr = std::uint8_t;
1212
// Indicates it's the last message in the packet from the venue for a given
1313
// `instrument_id`.
14-
static constexpr Repr kLast = 1 << 7;
14+
static inline constexpr Repr kLast = 1 << 7;
1515
// Indicates a top-of-book message, not an individual order.
16-
static constexpr Repr kTob = 1 << 6;
16+
static inline constexpr Repr kTob = 1 << 6;
1717
// Indicates the message was sourced from a replay, such as a snapshot
1818
// server.
19-
static constexpr Repr kSnapshot = 1 << 5;
19+
static inline constexpr Repr kSnapshot = 1 << 5;
2020
// Indicates an aggregated price level message, not an individual order.
21-
static constexpr Repr kMbp = 1 << 4;
21+
static inline constexpr Repr kMbp = 1 << 4;
2222
// Indicates the `ts_recv` value is inaccurate due to clock issues or packet
2323
// reordering.
24-
static constexpr Repr kBadTsRecv = 1 << 3;
24+
static inline constexpr Repr kBadTsRecv = 1 << 3;
2525
// Indicates an unrecoverable gap was detected in the channel.
26-
static constexpr Repr kMaybeBadBook = 1 << 2;
26+
static inline constexpr Repr kMaybeBadBook = 1 << 2;
2727

2828
friend std::ostream& operator<<(std::ostream&, FlagSet);
2929

30-
constexpr FlagSet() = default;
30+
constexpr FlagSet() : repr_{0} {};
3131

32-
constexpr FlagSet( // cppcheck-suppress noExplicitConstructor
33-
std::uint8_t repr)
34-
: repr_{repr} {}
32+
explicit constexpr FlagSet(Repr repr) : repr_{repr} {}
3533

3634
explicit constexpr operator std::uint8_t() const { return repr_; }
3735

38-
constexpr FlagSet operator~() const {
39-
return FlagSet{static_cast<Repr>(~repr_)};
40-
}
36+
constexpr bool operator==(FlagSet rhs) const { return repr_ == rhs.repr_; }
37+
constexpr bool operator!=(FlagSet rhs) const { return repr_ != rhs.repr_; }
4138

42-
constexpr FlagSet operator|(FlagSet rhs) const {
43-
return FlagSet{static_cast<Repr>(repr_ | rhs.repr_)};
39+
FlagSet Clear() {
40+
repr_ = 0;
41+
return *this;
4442
}
4543

46-
constexpr FlagSet operator&(FlagSet rhs) const {
47-
return FlagSet{static_cast<Repr>(repr_ & rhs.repr_)};
48-
}
44+
constexpr Repr Raw() const { return repr_; }
45+
void SetRaw(Repr raw) { repr_ = raw; }
4946

50-
constexpr FlagSet operator^(FlagSet rhs) const {
51-
return FlagSet{static_cast<Repr>(repr_ ^ rhs.repr_)};
47+
// Checks if any flags are set.
48+
constexpr bool Any() const { return repr_ != 0; }
49+
constexpr bool IsEmpty() const { return repr_ == 0; }
50+
constexpr bool IsLast() const { return bits_.last; }
51+
FlagSet SetLast() {
52+
bits_.last = true;
53+
return *this;
5254
}
53-
54-
FlagSet operator|=(FlagSet rhs) {
55-
repr_ = repr_ | rhs.repr_;
55+
constexpr bool IsTob() const { return bits_.tob; }
56+
FlagSet SetTob() {
57+
bits_.tob = true;
5658
return *this;
5759
}
58-
59-
FlagSet operator&=(FlagSet rhs) {
60-
repr_ = repr_ & rhs.repr_;
60+
constexpr bool IsSnapshot() const { return bits_.snapshot; }
61+
FlagSet SetSnapshot() {
62+
bits_.snapshot = true;
6163
return *this;
6264
}
63-
64-
FlagSet operator^=(FlagSet rhs) {
65-
repr_ = repr_ ^ rhs.repr_;
65+
constexpr bool IsMbp() const { return bits_.mbp; }
66+
FlagSet SetMbp() {
67+
bits_.mbp = true;
68+
return *this;
69+
}
70+
constexpr bool IsBadTsRecv() const { return bits_.bad_ts_recv; }
71+
FlagSet SetBadTsRecv() {
72+
bits_.bad_ts_recv = true;
73+
return *this;
74+
}
75+
constexpr bool IsMaybeBadBook() const { return bits_.maybe_bad_book; }
76+
FlagSet SetMaybeBadBook() {
77+
bits_.maybe_bad_book = true;
6678
return *this;
6779
}
68-
69-
constexpr bool operator==(FlagSet rhs) const { return repr_ == rhs.repr_; }
70-
71-
constexpr bool operator!=(FlagSet rhs) const { return repr_ != rhs.repr_; }
72-
73-
// Checks if any flags are set.
74-
constexpr bool Any() const { return repr_ != 0; }
7580

7681
private:
77-
Repr repr_{};
82+
struct BitFlags {
83+
bool reserved0 : 1;
84+
bool reserved1 : 1;
85+
bool maybe_bad_book : 1;
86+
bool bad_ts_recv : 1;
87+
bool mbp : 1;
88+
bool snapshot : 1;
89+
bool tob : 1;
90+
bool last : 1;
91+
};
92+
union {
93+
BitFlags bits_;
94+
Repr repr_;
95+
};
7896
};
7997

80-
inline std::ostream& operator<<(std::ostream& stream, FlagSet flag) {
81-
// print as binary
82-
stream << "0b" << std::bitset<8>{flag.repr_};
83-
return stream;
84-
}
98+
std::ostream& operator<<(std::ostream& stream, FlagSet flag_set);
99+
std::string ToString(FlagSet flags);
85100

86101
static_assert(sizeof(FlagSet) == sizeof(std::uint8_t),
87102
"FlagSet must be a transparent wrapper around std::uint8_t");

src/flag_set.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include "databento/flag_set.hpp"
2+
3+
#include <array>
4+
5+
#include "stream_op_helper.hpp"
6+
7+
namespace databento {
8+
std::ostream& operator<<(std::ostream& stream, FlagSet flag_set) {
9+
constexpr std::array<std::pair<bool (FlagSet::*)() const, const char*>, 6>
10+
kFlagsAndNames = {{
11+
{&FlagSet::IsLast, "LAST"},
12+
{&FlagSet::IsTob, "TOB"},
13+
{&FlagSet::IsSnapshot, "SNAPSHOT"},
14+
{&FlagSet::IsMbp, "MBP"},
15+
{&FlagSet::IsBadTsRecv, "BAD_TS_RECV"},
16+
{&FlagSet::IsMaybeBadBook, "MAYBE_BAD_BOOK"},
17+
}};
18+
19+
bool has_written_flag = false;
20+
for (const auto& pair : kFlagsAndNames) {
21+
if ((flag_set.*pair.first)()) {
22+
if (has_written_flag) {
23+
stream << " | " << pair.second;
24+
} else {
25+
stream << pair.second;
26+
has_written_flag = true;
27+
}
28+
}
29+
}
30+
// Cast to uint16_t to avoid being formatted as char
31+
const auto raw = static_cast<std::uint16_t>(flag_set.Raw());
32+
if (has_written_flag) {
33+
stream << " (" << raw << ')';
34+
} else {
35+
stream << raw;
36+
}
37+
return stream;
38+
}
39+
40+
std::string ToString(FlagSet flags) { return MakeString(flags); }
41+
} // namespace databento

test/src/dbn_decoder_tests.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbo) {
256256
EXPECT_EQ(ch_mbo1.order_id, 647784973705);
257257
EXPECT_EQ(ch_mbo1.price, 3722750000000);
258258
EXPECT_EQ(ch_mbo1.size, 1);
259-
EXPECT_EQ(ch_mbo1.flags, 128);
259+
EXPECT_EQ(ch_mbo1.flags.Raw(), 128);
260260
EXPECT_EQ(ch_mbo1.channel_id, 0);
261261
EXPECT_EQ(ch_mbo1.action, Action::Cancel);
262262
EXPECT_EQ(ch_mbo1.side, Side::Ask);
@@ -280,7 +280,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbo) {
280280
EXPECT_EQ(ch_mbo2.order_id, 647784973631);
281281
EXPECT_EQ(ch_mbo2.price, 3723000000000);
282282
EXPECT_EQ(ch_mbo2.size, 1);
283-
EXPECT_EQ(ch_mbo2.flags, 128);
283+
EXPECT_EQ(ch_mbo2.flags.Raw(), 128);
284284
EXPECT_EQ(ch_mbo2.channel_id, 0);
285285
EXPECT_EQ(ch_mbo2.action, Action::Cancel);
286286
EXPECT_EQ(ch_mbo2.side, Side::Ask);
@@ -327,7 +327,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbp1) {
327327
EXPECT_EQ(ch_mbp1.size, 1);
328328
EXPECT_EQ(ch_mbp1.action, Action::Add);
329329
EXPECT_EQ(ch_mbp1.side, Side::Ask);
330-
EXPECT_EQ(ch_mbp1.flags, 128);
330+
EXPECT_EQ(ch_mbp1.flags.Raw(), 128);
331331
EXPECT_EQ(ch_mbp1.depth, 0);
332332
EXPECT_EQ(ch_mbp1.ts_recv.time_since_epoch().count(), 1609160400006136329);
333333
EXPECT_EQ(ch_mbp1.ts_in_delta.count(), 17214);
@@ -356,7 +356,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbp1) {
356356
EXPECT_EQ(ch_mbp2.size, 1);
357357
EXPECT_EQ(ch_mbp2.action, Action::Add);
358358
EXPECT_EQ(ch_mbp2.side, Side::Ask);
359-
EXPECT_EQ(ch_mbp2.flags, 128);
359+
EXPECT_EQ(ch_mbp2.flags.Raw(), 128);
360360
EXPECT_EQ(ch_mbp2.depth, 0);
361361
EXPECT_EQ(ch_mbp2.ts_recv.time_since_epoch().count(), 1609160400006246513);
362362
EXPECT_EQ(ch_mbp2.ts_in_delta.count(), 18858);
@@ -407,7 +407,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbp10) {
407407
EXPECT_EQ(ch_mbp1.size, 1);
408408
EXPECT_EQ(ch_mbp1.action, Action::Cancel);
409409
EXPECT_EQ(ch_mbp1.side, Side::Ask);
410-
EXPECT_EQ(ch_mbp1.flags, 128);
410+
EXPECT_EQ(ch_mbp1.flags.Raw(), 128);
411411
EXPECT_EQ(ch_mbp1.depth, 9);
412412
EXPECT_EQ(ch_mbp1.ts_recv.time_since_epoch().count(), 1609160400000704060);
413413
EXPECT_EQ(ch_mbp1.ts_in_delta.count(), 22993);
@@ -448,7 +448,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeMbp10) {
448448
EXPECT_EQ(ch_mbp2.size, 1);
449449
EXPECT_EQ(ch_mbp2.action, Action::Cancel);
450450
EXPECT_EQ(ch_mbp2.side, Side::Bid);
451-
EXPECT_EQ(ch_mbp2.flags, 128);
451+
EXPECT_EQ(ch_mbp2.flags.Raw(), 128);
452452
EXPECT_EQ(ch_mbp2.depth, 1);
453453
EXPECT_EQ(ch_mbp2.ts_recv.time_since_epoch().count(), 1609160400000750544);
454454
EXPECT_EQ(ch_mbp2.ts_in_delta.count(), 20625);
@@ -511,7 +511,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeCbbo) {
511511
EXPECT_EQ(ch_cbbo1.size, 1);
512512
EXPECT_EQ(ch_cbbo1.action, Action::Add);
513513
EXPECT_EQ(ch_cbbo1.side, Side::Ask);
514-
EXPECT_EQ(ch_cbbo1.flags, 128);
514+
EXPECT_EQ(ch_cbbo1.flags.Raw(), 128);
515515
EXPECT_EQ(ch_cbbo1.ts_recv.time_since_epoch().count(), 1609160400006136329);
516516
EXPECT_EQ(ch_cbbo1.ts_in_delta.count(), 17214);
517517
EXPECT_EQ(ch_cbbo1.sequence, 1170362);
@@ -539,7 +539,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeCbbo) {
539539
EXPECT_EQ(ch_cbbo2.size, 1);
540540
EXPECT_EQ(ch_cbbo2.action, Action::Add);
541541
EXPECT_EQ(ch_cbbo2.side, Side::Ask);
542-
EXPECT_EQ(ch_cbbo2.flags, 128);
542+
EXPECT_EQ(ch_cbbo2.flags.Raw(), 128);
543543
EXPECT_EQ(ch_cbbo2.ts_recv.time_since_epoch().count(), 1609160400006246513);
544544
EXPECT_EQ(ch_cbbo2.ts_in_delta.count(), 18858);
545545
EXPECT_EQ(ch_cbbo2.sequence, 1170364);
@@ -589,7 +589,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeTbbo) {
589589
EXPECT_EQ(ch_tbbo1.size, 5);
590590
EXPECT_EQ(ch_tbbo1.action, Action::Trade);
591591
EXPECT_EQ(ch_tbbo1.side, Side::Ask);
592-
EXPECT_EQ(ch_tbbo1.flags, 129);
592+
EXPECT_EQ(ch_tbbo1.flags.Raw(), 129);
593593
EXPECT_EQ(ch_tbbo1.depth, 0);
594594
EXPECT_EQ(ch_tbbo1.ts_recv.time_since_epoch().count(), 1609160400099150057);
595595
EXPECT_EQ(ch_tbbo1.ts_in_delta.count(), 19251);
@@ -618,7 +618,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeTbbo) {
618618
EXPECT_EQ(ch_tbbo2.size, 21);
619619
EXPECT_EQ(ch_tbbo2.action, Action::Trade);
620620
EXPECT_EQ(ch_tbbo2.side, Side::Ask);
621-
EXPECT_EQ(ch_tbbo2.flags, 129);
621+
EXPECT_EQ(ch_tbbo2.flags.Raw(), 129);
622622
EXPECT_EQ(ch_tbbo2.depth, 0);
623623
EXPECT_EQ(ch_tbbo2.ts_recv.time_since_epoch().count(), 1609160400108142648);
624624
EXPECT_EQ(ch_tbbo2.ts_in_delta.count(), 20728);
@@ -669,7 +669,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeTrades) {
669669
EXPECT_EQ(ch_trade1.size, 5);
670670
EXPECT_EQ(ch_trade1.action, Action::Trade);
671671
EXPECT_EQ(ch_trade1.side, Side::Ask);
672-
EXPECT_EQ(ch_trade1.flags, 129);
672+
EXPECT_EQ(ch_trade1.flags.Raw(), 129);
673673
EXPECT_EQ(ch_trade1.depth, 0);
674674
EXPECT_EQ(ch_trade1.ts_recv.time_since_epoch().count(), 1609160400099150057);
675675
EXPECT_EQ(ch_trade1.ts_in_delta.count(), 19251);
@@ -692,7 +692,7 @@ TEST_P(DbnDecoderSchemaTests, TestDecodeTrades) {
692692
EXPECT_EQ(ch_trade2.size, 21);
693693
EXPECT_EQ(ch_trade2.action, Action::Trade);
694694
EXPECT_EQ(ch_trade2.side, Side::Ask);
695-
EXPECT_EQ(ch_trade2.flags, 129);
695+
EXPECT_EQ(ch_trade2.flags.Raw(), 129);
696696
EXPECT_EQ(ch_trade2.depth, 0);
697697
EXPECT_EQ(ch_trade2.ts_recv.time_since_epoch().count(), 1609160400108142648);
698698
EXPECT_EQ(ch_trade2.ts_in_delta.count(), 20728);

0 commit comments

Comments
 (0)