This pages shows some simple examples, most of things they demostrate are also shown on other pages.
Here's the schema:
<?xml version="1.0" encoding="UTF-8"?>
<sbe:messageSchema package="market" id="1" version="0" byteOrder="littleEndian">
<types>
<composite name="messageHeader">
<type name="blockLength" primitiveType="uint16"/>
<type name="templateId" primitiveType="uint16"/>
<type name="schemaId" primitiveType="uint16"/>
<type name="version" primitiveType="uint16"/>
</composite>
<composite name="groupSizeEncoding">
<type name="blockLength" primitiveType="uint16"/>
<type name="numInGroup" primitiveType="uint16"/>
</composite>
<composite name="varDataEncoding">
<type name="length" primitiveType="uint32"/>
<type name="varData" primitiveType="uint8" length="0"/>
</composite>
<type name="uint32_opt" primitiveType="uint32" presence="optional"/>
<enum name="numbers" encodingType="uint8">
<validValue name="One">1</validValue>
<validValue name="Two">2</validValue>
</enum>
<set name="options" encodingType="uint8">
<choice name="A">0</choice>
<choice name="B">2</choice>
</set>
</types>
<sbe:message name="msg" id="1">
<field name="field" id="1" type="uint32_opt"/>
<field name="number" id="2" type="numbers"/>
<field name="option" id="3" type="options"/>
<group name="group" id="4">
<field name="field" id="1" type="uint32"/>
</group>
<data name="data" id="5" type="varDataEncoding"/>
</sbe:message>
</sbe:messageSchema>
Encoding a message using normal accessors
std::array<char, 1024> buf{};
auto m = sbepp::make_view<market::messages::msg>(buf.data(), buf.size());
m.option(market::types::options{}.B(true));
m.field(3);
m.number(market::types::numbers::Two);
auto d = m.data();
d.assign_string("hi!");
auto g = m.group();
g.resize(2);
for(const auto entry : g)
{
entry.field(1);
}
constexpr auto fill_message_header(Message m) noexcept -> decltype(m(detail::fill_message_header_tag{}))
Fill message header.
Definition sbepp.hpp:3990
constexpr auto fill_group_header(Group g, Size num_in_group) noexcept -> decltype(g(detail::fill_group_header_tag{}, num_in_group))
Fill group header.
Definition sbepp.hpp:4010
constexpr auto addressof(T v) noexcept -> decltype(v(detail::addressof_tag{}))
Returns pointer to the underlying data referenced by a view.
Definition sbepp.hpp:1619
constexpr std::size_t size_bytes(T v) noexcept
Returns the size of the underlying data represented by message/group/entry/data/composite view,...
Definition sbepp.hpp:1580
Encoding a message using cursor-based accessors
std::array<char, 1024> buf{};
auto m = sbepp::make_view<market::messages::msg>(buf.data(), buf.size());
m.field(1, c);
m.number(market::types::numbers::Two, c);
m.option(market::types::options{}.B(true), c);
auto g = m.group(c);
for(const auto entry : g.cursor_range(c))
{
entry.field(1, c);
}
d.assign_string("hi!");
constexpr detail::skip_cursor_wrapper< Byte > skip(cursor< Byte > &c) noexcept
Returns a wrapper which moves the cursor to the end of field/group/data without returning the accesse...
Definition sbepp.hpp:1728
constexpr detail::dont_move_cursor_wrapper< Byte > dont_move(cursor< Byte > &c) noexcept
Returns a wrapper which doesn't advance the cursor when it's used.
Definition sbepp.hpp:1694
constexpr cursor< byte_type_t< View > > init_cursor(View view) noexcept
Initializes cursor from a message/group view with the same byte type.
Definition sbepp.hpp:2846
Decoding a message using normal accessors
std::array<char, 1024> buf{};
buf.data(), buf.size());
if(*header.templateId()
{
std::cerr << "unknown message id: " << *header.templateId() << '\n';
return;
}
auto m = sbepp::make_const_view<market::messages::msg>(buf.data(), buf.size());
if(!checked_size.valid)
{
std::cerr << "bad message\n";
return;
}
auto d = m.data();
std::cout.write(d.data(), d.size());
const auto field = m.field();
if(field.has_value())
{
if(field.in_range())
{
std::cout << *field << '\n';
}
else
{
std::cout << "field value is out of range \n";
}
}
else
{
std::cout << "field is null\n";
}
std::cout << *m.option() << '\n';
auto g = m.group();
std::cout << "group size: " << g.size() << '\n';
for(const auto entry : g)
{
std::cout << *entry.field() << '\n';
}
static constexpr message_id_t id() noexcept
Returns id attribute.
HeaderComposite< Byte > header_type
Message header composite type.
Definition sbepp.hpp:4136
constexpr std::underlying_type< Enum >::type to_underlying(Enum e) noexcept
Converts an enumeration to its underlying type. Equivalent to C++23 std::to_underlying()
Definition sbepp.hpp:2827
constexpr size_bytes_checked_result size_bytes_checked(View view, std::size_t size) noexcept
Calculate view size with additional safety checks.
Definition sbepp.hpp:5526
constexpr View< typename std::add_const< Byte >::type > make_const_view(Byte *ptr, const std::size_t size) noexcept
Construct read-only view from memory buffer.
Definition sbepp.hpp:4922
Decoding a message using cursor-based accessors
std::array<char, 1024> buf{};
auto m = sbepp::make_const_view<market::messages::msg>(buf.data(), buf.size());
{
std::cerr << "not a `market::messages::msg`" << '\n';
return;
}
const auto field = m.field(c);
if(field.has_value())
{
if(field.in_range())
{
std::cout << *field << '\n';
}
else
{
std::cout << "field value is out of range \n";
}
}
else
{
std::cout << "field is null\n";
}
std::cout << *m.option(c) << '\n';
auto g = m.group(c);
std::cout << "group size: " << g.size() << '\n';
for(const auto entry : g.cursor_range(c))
{
std::cout << *entry.field(c) << '\n';
}
auto d = m.data(c);
std::cout.write(d.data(), d.size());
Provides various traits/attributes of a <message> element.
Definition sbepp.hpp:4334
constexpr auto get_header(T v) noexcept -> decltype(v(detail::get_header_tag{}))
Returns the header of a message/group.
Definition sbepp.hpp:1607
Decoding message header
There are couple of ways to decode message header from an incoming data.
Using sbepp::schema_traits::header_type
to get header type:
Using hardcoded header type(messageHeader
here):
auto header = sbepp::make_const_view<market::types::messageHeader>(
buf.data(), buf.size());
And finally, when one knows for sure what schema they're working with, it's legal to create any message view from that schema and use sbepp::get_header()
to get the header. This works because header is the same for all messages within the schema. Of course access anything beyond the header still requires message type check.
auto m = sbepp::make_const_view<market::messages::msg>(
buf.data(), buf.size());
Estimating buffer size to encode a message
It is possible to estimate how much memory is required to represent encoded message using sbepp::message_traits::size_bytes()
. To do this, one needs to know message structure details, the number of entries for each group and the total size of <data>
element(s) payload. Here's how it can be done at compile-time:
constexpr auto max_group_entries = 5;
constexpr auto max_data_size = 256;
market::schema::messages:msg>::size_bytes(
max_group_entries, max_data_size);
std::array<char, max_msg_size> buf{};
auto m = sbepp::make_view<market::messages::msg>(buf.data(), buf.size());
or at run-time:
void make_msg(
const std::vector<std::uint32_t>& group_entries,
const std::vector<std::uint8_t>& data_payload)
{
market::schema::messages:msg>::size_bytes(
group_entries.size(), max_data_size.size());
std::vector<char> buf;
buf.resize(msg_size);
auto m = sbepp::make_view<market::messages::msg>(buf.data(), buf.size());
}
Stringification
Here's an example of how to build stringification visitor using fmt and Visit API (you can find the full example in stringification.test.cpp
):
class to_string_visitor
{
public:
template<typename T, typename Cursor, typename Tag>
void on_message(T m, Cursor& c, Tag)
{
append_line("content: ");
indentation++;
indentation--;
}
template<typename T, typename Cursor, typename Tag>
bool on_group(T g, Cursor& c, Tag)
{
indentation++;
indentation--;
return {};
}
template<typename T, typename Cursor>
bool on_entry(T entry, Cursor& c)
{
append_line("entry:");
indentation++;
indentation--;
return {};
}
template<typename T, typename Tag>
bool on_data(T d, Tag)
{
return {};
}
template<typename T, typename Tag>
bool on_field(T f, Tag)
{
return {};
}
template<typename T, typename Tag>
bool on_type(T t, Tag)
{
return {};
}
template<typename T, typename Tag>
bool on_enum(T e, Tag)
{
return {};
}
template<typename T, typename Tag>
bool on_set(T s, Tag)
{
return {};
}
template<typename T, typename Tag>
bool on_composite(T c, Tag)
{
return {};
}
template<typename Tag>
void on_enum_value(auto , Tag)
{
}
{
}
template<typename Tag>
void on_set_choice(const bool value, Tag)
{
if(value)
{
if(!is_first_choice)
{
append(", ");
}
is_first_choice = false;
}
}
const std::string& str() const
{
return res;
}
private:
std::string res;
std::size_t indentation{};
bool is_first_choice{};
void indent()
{
fmt::format_to(std::back_inserter(res), "{:{}}", "", indentation * 4);
}
template<typename... Args>
void append(fmt::format_string<Args...> fmt, Args&&... args)
{
fmt::format_to(
std::back_inserter(res), fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void append_line(fmt::format_string<Args...> fmt, Args&&... args)
{
indent();
append(fmt, std::forward<Args>(args)...);
res.push_back('\n');
}
{
append_line("{}: {}", name, *t);
}
{
if(t)
{
append_line("{}: {}", name, *t);
}
else
{
append_line("{}: null", name);
}
}
{
on_array(a, name);
}
template<typename T>
void on_array(T a, const char* name)
{
if constexpr(std::is_same_v<typename T::value_type, char>)
{
append_line("{}: {:.{}}", name, a.data(), a.size());
}
else
{
append_line("{}: {}", name, a);
}
}
{
indent();
append("{}: ", name);
}
void on_encoding(
sbepp::set auto s,
const char* name)
{
indent();
append("{}: (", name);
is_first_choice = true;
append(")\n");
}
{
append_line("{}:", name);
indentation++;
indentation--;
}
};
auto res = sbepp::visit<to_string_visitor>(message);
fmt::print("{}", res.str());
Provides various traits/attributes of a <composite> element.
Definition sbepp.hpp:4290
Provides various traits/attributes of a <data> element.
Definition sbepp.hpp:4575
Provides various traits/attributes of an <enum> element.
Definition sbepp.hpp:4156
Provides various traits/attributes of a <validValue> element.
Definition sbepp.hpp:4193
Provides various traits/attributes of a <field> element.
Definition sbepp.hpp:4456
Provides various traits/attributes of a <group> element.
Definition sbepp.hpp:4505
Provides various traits/attributes of a <choice> element.
Definition sbepp.hpp:4260
Provides various traits/attributes of a <set> element.
Definition sbepp.hpp:4223
Provides various traits and attributes of a <type> element.
Definition sbepp.hpp:4035
Concept for sbepp::is_array_type<T>::value
Definition sbepp.hpp:5122
Concept for sbepp::is_composite<T>::value
Definition sbepp.hpp:5150
Concept for sbepp::is_enum<T>::value
Definition sbepp.hpp:5142
Concept for sbepp::is_optional_type<T>::value
Definition sbepp.hpp:5130
Concept for sbepp::is_required_type<T>::value
Definition sbepp.hpp:5126
Concept for sbepp::is_set<T>::value
Definition sbepp.hpp:5146
constexpr Visitor && visit_children(View view, Cursor &c, Visitor &&visitor={})
Visit view's children using provided cursor.
Definition sbepp.hpp:5301
constexpr Visitor && visit(View view, Cursor &c, Visitor &&visitor={})
Visit a view using given cursor.
Definition sbepp.hpp:5199
Tag for unknown enum values.
Definition sbepp.hpp:4934
Now, for a message like:
<enum name="numbers_enum" encodingType="uint8">
<validValue name="One">1</validValue>
<validValue name="Two">2</validValue>
</enum>
<set name="options_set" encodingType="uint8">
<choice name="A">0</choice>
<choice name="B">2</choice>
</set>
<sbe:message name="msg28" id="28">
<field name="required" id="1" type="uint32"/>
<field name="optional1" id="2" type="uint32_opt"/>
<field name="optional2" id="3" type="uint32_opt"/>
<field name="number" id="4" type="numbers_enum"/>
<field name="option" id="5" type="options_set"/>
<field name="string" id="6" type="str128"/>
<field name="array" id="7" type="arr8"/>
<group name="group" id="8">
<field name="number" id="1" type="uint32"/>
</group>
<data name="varData" id="9" type="varDataEncoding"/>
<data name="varStr" id="10" type="varStrEncoding"/>
</sbe:message>
we can get the following output:
message: msg28
messageHeader:
blockLength: 150
templateId: 28
schemaId: 1
version: 0
content:
required: 1
optional1: 2
optional2: null
number: One
option: (A, B)
string: hi
array: [1, 0, 2, 0, 0, 0, 0, 0]
group:
entry:
number: 1
entry:
number: 2
varData: [1, 2]
varStr: ab