JayBeams  0.1
Another project to have fun coding.
short_string_field.hpp
Go to the documentation of this file.
1 #ifndef jb_itch5_short_string_field_hpp
2 #define jb_itch5_short_string_field_hpp
3 
4 #include <jb/itch5/decoder.hpp>
6 #include <jb/p2ceil.hpp>
7 
8 #include <boost/functional/hash.hpp>
9 #include <boost/operators.hpp>
10 
11 #include <cstring>
12 #include <iostream>
13 
14 namespace jb {
15 namespace itch5 {
16 
17 /**
18  * A helper type to define short (and fixed sized) string fields.
19  *
20  * The ITCH-5.0 protocol uses many fields that are short strings, that
21  * is, fixed-length alpha numeric fields. While it is normally easy
22  * to treat these fields as character strings, the fields may not be
23  * NUL terminated. In fact, the protocol spec specifically states
24  * that the fields will be left justified, and padded with spaces.
25  *
26  * We want an in-memory representation that is NUL terminated (for
27  * compatibility with all the C/C++ libraries), and we do not wish to
28  * allocate memory for these fields (as we would do if we used
29  * std::string).
30  *
31  * @tparam wire_size_value the size of the field on the wire, in
32  * bytes.
33  * @tparam value_validator a functor to validate the value for those
34  * fields that are only supposed to assume a known set of values.
35  */
36 template <
37  std::size_t wire_size_value,
38  typename value_validator = noop_validator<char const*>>
40  : public boost::less_than_comparable<
41  short_string_field<wire_size_value, value_validator>>,
42  public boost::less_than_comparable<
43  short_string_field<wire_size_value, value_validator>, char const*>,
44  public boost::equality_comparable<
45  short_string_field<wire_size_value, value_validator>>,
46  public boost::equality_comparable<
47  short_string_field<wire_size_value, value_validator>, char const*> {
48 public:
49  /// The size of the field on the wire
50  constexpr static std::size_t wire_size = wire_size_value;
51 
52  /// The size of the field in memory
53  constexpr static std::size_t buffer_size = jb::p2ceil(wire_size_value);
54 
55  /// The type of validator
56  typedef value_validator value_validator_t;
57 
58  /// Constructor
60  value_validator_t const& validator = value_validator_t())
61  : buffer_()
62  , value_validator_(validator) {
63  }
64 
65  /// Constructor from a std::string
67  std::string const& rhs,
68  value_validator_t const& validator = value_validator_t())
69  : buffer_()
70  , value_validator_(validator) {
71  std::strncpy(buffer_, rhs.c_str(), wire_size);
72  nul_terminate();
73  }
74 
75  /// Return the C-string representation
76  char const* c_str() const {
77  return buffer_;
78  }
79 
80  //@{
81  /**
82  * @name Base comparison operators
83  */
84  /// compare vs another short_string_field
85  bool operator==(short_string_field const& rhs) const {
86  return std::strncmp(buffer_, rhs.buffer_, buffer_size) == 0;
87  }
88 
89  /// compare vs another short_string_field
90  bool operator<(short_string_field const& rhs) const {
91  return std::strncmp(buffer_, rhs.buffer_, buffer_size) < 0;
92  }
93 
94  /// compare vs a C string
95  bool operator==(char const* rhs) const {
96  return std::strncmp(buffer_, rhs, buffer_size) == 0;
97  }
98 
99  /// compare vs a C string
100  bool operator<(char const* rhs) const {
101  return std::strncmp(buffer_, rhs, buffer_size) == 0;
102  }
103  //@}
104 
105  //@{
106  /// @name default assignment and copy operators
107  short_string_field(short_string_field const& rhs) = default;
108  short_string_field(short_string_field&& rhs) = default;
109  short_string_field& operator=(short_string_field const& rhs) = default;
111  //@}
112 
113 private:
115  friend struct jb::itch5::decoder<false, short_string_field>;
116  /// Assignment from a character buffer
117  void assign(char const* buf) {
118  std::memcpy(buffer_, buf, wire_size);
119  nul_terminate();
120  }
121 
122  /// NUL terminate the string
123  void nul_terminate() {
124  // ... write a NUL character at one past the expected length on
125  // the wire, we know this is safe because the buffer is always
126  // larger than the wire size (by construction) ...
127  buffer_[wire_size] = '\0';
128  // ... find the first space character, on the wire the strings are
129  // padded with spaces, we want to NUL terminate on the first
130  // space. We know this will not got beyond the buffer's end
131  // because of the previous NUL terminator ...
132  char* p = std::strchr(buffer_, u' ');
133  // ... if there was a space, put a NUL character there ...
134  if (p != nullptr) {
135  *p = '\0';
136  }
137  }
138 
139  /**
140  * Validate the value using the functor.
141  *
142  * @tparam enabled if false, disable all validation
143  */
144  void validate() const {
145  if (not value_validator_(buffer_)) {
146  jb::itch5::raise_validation_failed("short_string_field<>", buffer_);
147  }
148  }
149 
150 private:
151  /// The in-memory representation
153 
154  /// The validator
155  value_validator_t value_validator_;
156 };
157 
158 /// Specialize decoder<bool,T> for short_string_field.
159 template <bool validate, std::size_t wsize, typename F>
160 struct decoder<validate, short_string_field<wsize, F>> {
161  /// Please see the generic documentation for jb::itch5::decoder<>::r()
163  r(std::size_t size, void const* buffer, std::size_t offset) {
164  jb::itch5::check_offset<validate>(
165  "short_string_field<>", size, offset, wsize);
166 
168  tmp.assign(static_cast<char const*>(buffer) + offset);
169  if (validate) {
170  tmp.validate();
171  }
172  return tmp;
173  }
174 };
175 
176 /// Streaming operator for jb::itch5::short_string_field<>
177 template <std::size_t size, typename F>
178 std::ostream&
179 operator<<(std::ostream& os, short_string_field<size, F> const& x) {
180  return os << x.c_str();
181 }
182 
183 /// Implement a hash function and integrate with boost::hash
184 template <std::size_t size, typename F>
186  return boost::hash_range(x.c_str(), x.c_str() + size);
187 }
188 
189 } // namespace itch5
190 } // namespace jb
191 
192 #endif // jb_itch5_short_string_field_hpp
bool operator<(short_string_field const &rhs) const
compare vs another short_string_field
bool operator<(char const *rhs) const
compare vs a C string
char const * c_str() const
Return the C-string representation.
bool operator==(short_string_field const &rhs) const
compare vs another short_string_field
short_string_field(value_validator_t const &validator=value_validator_t())
Constructor.
void raise_validation_failed(char const *where, char const *what)
Convenience function to raise an exception upon a validation error.
static constexpr std::size_t wire_size
The size of the field on the wire.
value_validator_t value_validator_
The validator.
short_string_field(std::string const &rhs, value_validator_t const &validator=value_validator_t())
Constructor from a std::string.
static short_string_field< wsize, F > r(std::size_t size, void const *buffer, std::size_t offset)
Please see the generic documentation for jb::itch5::decoder<>::r()
std::size_t hash_value(short_string_field< size, F > const &x)
Implement a hash function and integrate with boost::hash.
bool operator==(char const *rhs) const
compare vs a C string
void assign(char const *buf)
Assignment from a character buffer.
static constexpr std::size_t buffer_size
The size of the field in memory.
Define the interface to decode ITCH-5.0 messages and message fields.
Definition: decoder.hpp:24
char buffer_[buffer_size]
The in-memory representation.
void validate() const
Validate the value using the functor.
short_string_field & operator=(short_string_field const &rhs)=default
value_validator value_validator_t
The type of validator.
A helper type to define short (and fixed sized) string fields.
void nul_terminate()
NUL terminate the string.
constexpr std::uint64_t p2ceil(std::uint64_t n)
Find the smallest power of 2 larger than n for a 64-bit integer.
Definition: p2ceil.hpp:34
The top-level namespace for the JayBeams library.
Definition: as_hhmmss.hpp:7