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:

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.

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.

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)