Skip to content

Commit

Permalink
Merge branch 'dev' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
jagerman committed Jul 27, 2022
2 parents 79193e5 + b596f23 commit 707a836
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 13 deletions.
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ if(CCACHE_PROGRAM)
endif()

project(oxenc
VERSION 1.0.3
VERSION 1.0.4
DESCRIPTION "oxenc - Base 16/32/64 and Bittorrent Encoding/Decoding Header Only Library"
LANGUAGES CXX)

Expand Down Expand Up @@ -51,6 +51,8 @@ target_include_directories(oxenc
$<INSTALL_INTERFACE:>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)

add_library(oxenc::oxenc ALIAS oxenc)

export(
TARGETS oxenc
NAMESPACE oxenc::
Expand Down
35 changes: 24 additions & 11 deletions oxenc/bt_producer.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ namespace oxenc {
const char* to;

// Sublist constructors
inline bt_list_producer(bt_list_producer* parent, std::string_view prefix = "l"sv);
inline bt_list_producer(bt_dict_producer* parent, std::string_view prefix = "l"sv);
bt_list_producer(bt_list_producer* parent, std::string_view prefix = "l"sv);
bt_list_producer(bt_dict_producer* parent, std::string_view prefix = "l"sv);

// Common constructor for both list and dict producer
bt_list_producer(char* begin, char* end, std::string_view prefix);

// Does the actual appending to the buffer, and throwing if we'd overrun. If advance is false
// then we append without moving the buffer pointer (primarily when we append intermediate `e`s
Expand Down Expand Up @@ -131,17 +134,17 @@ namespace oxenc {
bt_list_producer(const bt_list_producer&) = delete;
bt_list_producer& operator=(const bt_list_producer&) = delete;
bt_list_producer& operator=(bt_list_producer&&) = delete;
inline bt_list_producer(bt_list_producer&& other);
bt_list_producer(bt_list_producer&& other);

/// Constructs a list producer that writes into the range [begin, end). If a write would go
/// beyond the end of the buffer an exception is raised. Note that this will happen during
/// construction if the given buffer is not large enough to contain the `le` encoding of an
/// empty list.
inline bt_list_producer(char* begin, char* end);
bt_list_producer(char* begin, char* end) : bt_list_producer{begin, end, "l"sv} {}

/// Constructs a list producer that writes into the range [begin, begin+size). If a write would
/// go beyond the end of the buffer an exception is raised.
bt_list_producer(char* begin, size_t len) : bt_list_producer{begin, begin + len} {}
bt_list_producer(char* begin, size_t len) : bt_list_producer{begin, begin + len, "l"sv} {}

~bt_list_producer();

Expand Down Expand Up @@ -201,15 +204,15 @@ namespace oxenc {
///
/// If doing more complex lifetime management, take care not to allow the child instance to
/// outlive the parent.
inline bt_list_producer append_list();
bt_list_producer append_list();

/// Appends a dict to this list. Returns a new bt_dict_producer that references the parent
/// list. The parent cannot be added to until the subdict is destroyed. This is meant to be
/// used via RAII (see append_list() for details).
///
/// If doing more complex lifetime management, take care not to allow the child instance to
/// outlive the parent.
inline bt_dict_producer append_dict();
bt_dict_producer append_dict();
};


Expand Down Expand Up @@ -242,14 +245,24 @@ namespace oxenc {
#endif

public:
// Construction is identical to bt_list_producer
using bt_list_producer::bt_list_producer;
/// Constructs a dict producer that writes into the range [begin, end). If a write would go
/// beyond the end of the buffer an exception is raised. Note that this will happen during
/// construction if the given buffer is not large enough to contain the `de` encoding of an
/// empty list.
bt_dict_producer(char* begin, char* end) : bt_list_producer{begin, end, "d"sv} {}

/// Constructs a list producer that writes into the range [begin, begin+size). If a write would
/// go beyond the end of the buffer an exception is raised.
bt_dict_producer(char* begin, size_t len) : bt_list_producer{begin, begin + len, "d"sv} {}

/// Returns a string_view into the currently serialized data buffer. Note that the returned
/// view includes the `e` dict end serialization markers which will be overwritten if the dict
/// (or an active sublist/subdict) is appended to.
std::string_view view() const { return bt_list_producer::view(); }

/// Returns the end position in the buffer.
const char* end() const { return bt_list_producer::end(); }

/// Appends a key-value pair with a string or integer value. The key must be > the last key
/// added, but this is only enforced (with an assertion) in debug builds.
template <typename T, std::enable_if_t<std::is_convertible_v<T, std::string_view> || std::is_integral_v<T>, int> = 0>
Expand Down Expand Up @@ -403,9 +416,9 @@ namespace oxenc {
data);
}

inline bt_list_producer::bt_list_producer(char* begin, char* end)
inline bt_list_producer::bt_list_producer(char* begin, char* end, std::string_view prefix)
: data{buf_span{begin, end}}, buffer{*std::get_if<buf_span>(&data)}, from{buffer.first} {
buffer_append("l"sv);
buffer_append(prefix);
append_intermediate_ends();
}

Expand Down
38 changes: 37 additions & 1 deletion tests/test_bt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ TEST_CASE("bt allocation-free consumer", "[bt][dict][list][consumer]") {
std::make_pair("b"sv, std::make_tuple(1, 2, 3)) );
}

TEST_CASE("bt allocation-free producer", "[bt][dict][list][producer]") {
TEST_CASE("bt allocation-free list producer", "[bt][list][producer]") {

char smallbuf[16];
bt_list_producer toosmall{smallbuf, 16}; // le, total = 2
Expand Down Expand Up @@ -286,6 +286,42 @@ TEST_CASE("bt allocation-free producer", "[bt][dict][list][producer]") {
CHECK( dict.view() == "d3:foo3:bar1:gi42e1:hld1:ad1:Ali999eeeeee" );
CHECK( lp.view() == "l3:abci42ei1ei17ei-999eli0e0:elll3:omgeeed3:foo3:bar1:gi42e1:hld1:ad1:Ali999eeeeeee" );
}

}

TEST_CASE("bt allocation-free dict producer", "[bt][dict][producer]") {

char buf[1024];
bt_dict_producer dp{buf, sizeof(buf)};
CHECK( dp.view() == "de" );
CHECK( (void*) dp.end() == (void*) (buf + 2) );

dp.append("foo", "bar");
CHECK( dp.view() == "d3:foo3:bare" );
dp.append("foo\0"sv, -333222111);
CHECK( dp.view() == "d3:foo3:bar4:foo\0i-333222111ee"sv );
{
auto sublist = dp.append_list("myList");
((sublist += "") += 2) += 42;
CHECK( sublist.view() == "l0:i2ei42ee" );
}
CHECK( dp.view() == "d3:foo3:bar4:foo\0i-333222111e6:myListl0:i2ei42eee"sv );
{
auto subd = dp.append_dict("p");
subd.append("", "");
CHECK( subd.view() == "d0:0:e" );
}
CHECK( dp.view() == "d3:foo3:bar4:foo\0i-333222111e6:myListl0:i2ei42ee1:pd0:0:ee"sv );

std::map<std::string, int> to_append{
{"q", 1},
{"r", 2},
{"~", 3},
{"~1", 4}};
dp.append(to_append.begin(), to_append.end());

CHECK( dp.view() ==
"d3:foo3:bar4:foo\0i-333222111e6:myListl0:i2ei42ee1:pd0:0:e1:qi1e1:ri2e1:~i3e2:~1i4ee"sv );
}

#ifdef OXENC_APPLE_TO_CHARS_WORKAROUND
Expand Down

0 comments on commit 707a836

Please sign in to comment.