View interface
Introduction
bview
is a sum type that provides access to the values stored in a bencoded buffer.
It holds two pointers, one to a descriptor
, and one to the buffer contained the
bencoded data.
The descriptor
describes the type and content of the bencoded token the
bview
points to and where the data can be found in the bencoded buffer.
This information allows bview
to navigate through the bencoded buffer and
provide access to the values using an interface similar to standard C++ containers.
bview
is used together with four subclasses:
Each subclass provides an extra interface over bview
for the corresponding bencode data type.
These four classes satisfy the concept bview_alternative_type
.
integer_bview
is implicitly convertible to std::int64_t
.
The value stored can also be retrieved using integer_bview::value()
string_bview
provides an interface equal to that of std::string_view
.
It has an implicit conversion operator to std::string_view
.
list_bview
provides and interface similar to
std::vector
. Its iterators are only
bidirectional_iterator
instead of contiguous_iterator
.
Access to the elements is linear in the size of the list_bview
.
dict_bview
provides the interface similar to
std::map<bc::string_bview, bc::bview>
.
Access to the elements is linear in the size of the dict_bview
.
The API reference provides more information on how to use these types
Important
The reference returned by the dereference operator for
list_bview::iterator
and dict_bview::iterator
is only valid until the next dereference.
Construction
bview
should rarely be constructed directly. bview
is the result of calling
get_root()
on a descriptor_table
instance which is the result of parsing
a bencoded string with decode_view()
.
const std::string data = "d3:cow3:moo4:spam4:eggse";
bc::descriptor_table desc_table = bencode::decode_view(data);
bc::bview root_element = desc_table.get_root();
Type checking
Checking the alternative type of a bview
can be done using the following functions:
template <enum bencode_type E> bool holds_alternative(const bview&)
template <bview_alternative_type T> bool holds_alternative(const bview&)
holds_integer(root_element) // returns false
holds_dict(root_element) // returns true
// type tag based check
bc::holds_alternative<bc::type::dict>(root_element); // returns true
// bview type based check
bc::holds_alternative<bc::dict_bview>(root_element); // returns true
Accessors
Retrieving the alternative type from the bview
instance is done using accessor functions.
Throwing accessor function will throw bad_bview_access
when trying to
convert a bview
to an alternative type that does not match the bencode data type.
template <enum bencode_type E> const bview_alternative_t<E>& get(const bview&)
template <bview_alternative_type T> const T& get(const bview&)
Non throwing accessor function will return a nullptr when trying to convert a bview to a bview alternative type that does not match the bencode data type.
template <enum bencode_type E> const bview_alternative_t<E>* get_if(const bview*)
template <bview_alternative_type T> const T* get_if(const bview&)
auto dict_view = get_dict(root_element); // return dict_bview instance
auto list_view = get_list(root_element) // throws bad_bview_access
// type tag based check
auto get<bc::btype::dict>(root_element); // return dict_bview instance
// bview type based check
auto get<bc::dict_bview>(root_element); // return dict_bview instance
Conversion
To copy the content of a bview
value to a specific type, generic converters are used.
The throwing converter will throw bad_conversion
when an error occurs.
The non throwing converter will return a instance of nonstd::expected
with the converted value or a conversion_errc
.
bview
values can be converted to any type that satisfies retrievable_from_bview
.
Conversion to standard library types can be enabled by including the corresponding trait header.
Conversion to user-defined types can be enabled by implementing
the necessary customization points.
#include <bencode/traits/map.hpp>
#include <bencode/traits/string.hpp>
// copy a view to a std::map
auto d = get_as<std::map<std::string, bc::bvalue>>(root_element); //
// copy a view to a std::map
auto d2 = try_get_as<std::map<std::string, int>>(root_element);
if (!d2) {
// returns conversion_errc::dict_mapped_type_construction_error
// and assign it to a generic std::error_code
std::error_code ec = d2.error()
}
Comparison
Most types can be compared with bview
instances.
Comparison is deep and will compare the content of the bencode data type.
When the bencode type of bview
is not
the same as the bencode type of the the type you compare with when serialized,
the fallback order is integer < string < list < dict
Conversion to standard library types can be enabled by including the corresponding trait header. Comparison to user-defined types can be enabled by implementing the necessary customization point.
bview b; // b points to a bencoded string with text "foo";
b == "foo"; // return true
b > "aa"; // returns true
b > 3; // return true (integer < string)
b > std::map<std::string, int> {{"foo", 1}}; // return false (string < dict)