Skip to content

Commit 3ebb369

Browse files
Added void pointer construction and append
1 parent b219c2f commit 3ebb369

File tree

2 files changed

+100
-33
lines changed

2 files changed

+100
-33
lines changed

include/buffer/shared_buffer.hpp

+78-24
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
* constructing a @c const_shared_buffer for writing to the network.
3333
*
3434
* Besides the data buffer lifetime management, these utility classes eliminate data
35-
* copies and (obviously) can be utilized in use cases other than networking.
35+
* buffer copies and (obviously) can be utilized in use cases other than networking
36+
* (for example reading and writing disk files).
3637
*
3738
* ### Additional Details
3839
*
@@ -53,10 +54,6 @@
5354
* @c mutable_shared_buffer class as well as adding convenience methods to the
5455
* @c const_shared_buffer class.
5556
*
56-
* It is likely that this shared buffer design and code will change as the C++
57-
* Networking TS buffer features are expanded, changed, or better understood. Currently
58-
* there are no direct ties to Networking TS buffer features.
59-
*
6057
* @note Everything is declared @c noexcept except for the methods that allocate
6158
* memory and might throw a memory exception. This is tighter than the @c noexcept
6259
* declarations on the underlying @c std::vector methods, since @c std::byte
@@ -79,6 +76,7 @@
7976
#include <memory> // std::shared_ptr
8077
#include <compare> // spaceship operator
8178
#include <span>
79+
#include <bit> // std::bit_cast
8280

8381
#include <utility> // std::move, std::swap
8482
#include <algorithm> // std::copy
@@ -99,7 +97,7 @@ class const_shared_buffer;
9997
* This class provides ownership, copying, and lifetime management for byte oriented
10098
* buffers. In particular, it is designed to be used in conjunction with the
10199
* @c const_shared_buffer class for efficient transfer and correct lifetime management
102-
* of buffers in asynchronous libraries (such as the C++ Networking TS). In particular,
100+
* of buffers in asynchronous libraries (such as Asio). In particular,
103101
* a reference counted buffer can be passed among multiple layers of software without
104102
* any one layer "owning" the buffer.
105103
*
@@ -223,17 +221,37 @@ class mutable_shared_buffer {
223221
*
224222
* The pointer passed into this constructor is cast into a @c std::byte pointer and bytes
225223
* are then copied. In particular, this method can be used for @c char pointers,
226-
* @c void pointers, @c unsigned @c char pointers, etc.
224+
* @c unsigned @c char pointers, @c std::uint8_t pointers, etc. Non character types that
225+
* are trivially copyable are also allowed, although the usual care must be taken
226+
* (padding bytes, alignment, etc).
227227
*
228228
* @pre Size cannot be greater than the source buffer.
229229
*
230-
* @param buf Non-null pointer to a buffer of data.
230+
* @param buf Non-null pointer to a contiguous array of data.
231231
*
232-
* @param sz Size of buffer, in bytes.
232+
* @param num Number of elements in the array.
233+
*
234+
* @note For @c void pointers, see specific constructor taking a @c void pointer.
233235
*/
234236
template <typename T>
235-
mutable_shared_buffer(const T* buf, size_type sz) :
236-
mutable_shared_buffer(std::as_bytes(std::span<const T>{buf, sz})) { }
237+
mutable_shared_buffer(const T* buf, size_type num) :
238+
mutable_shared_buffer(std::as_bytes(std::span<const T>{buf, num})) { }
239+
240+
/**
241+
* @brief Construct by copying bytes from a void pointer.
242+
*
243+
* The pointer passed into this constructor is cast into a @c std::byte pointer and bytes
244+
* are then copied.
245+
*
246+
* @pre Size cannot be greater than the source buffer.
247+
*
248+
* @param buf Non-null @c void pointer to a buffer of data.
249+
*
250+
* @param sz Size of buffer, in bytes.
251+
*/
252+
mutable_shared_buffer(const void* buf, size_type sz) :
253+
mutable_shared_buffer(std::as_bytes(
254+
std::span<const std::byte>{std::bit_cast<const std::byte*>(buf), sz})) { }
237255

238256
/**
239257
* @brief Construct from input iterators.
@@ -345,7 +363,7 @@ class mutable_shared_buffer {
345363
}
346364

347365
/**
348-
* @brief Append a @c std::span to the end of the internal buffer.
366+
* @brief Append a @c std::span of @c std::bytes to the end of the internal buffer.
349367
*
350368
* @param sp @c std::span of @c std::byte data.
351369
*
@@ -361,15 +379,33 @@ class mutable_shared_buffer {
361379
*
362380
* The pointer passed into this method is cast into a @c std::byte pointer and bytes
363381
* are then copied. In particular, this method can be used for @c char pointers,
364-
* @c void pointers, @ unsigned @c char pointers, etc.
382+
* @c void pointers, @c unsigned @c char pointers, @c std::uint8_t pointers, etc.
383+
* Non character types that are layout compatible with @c std::byte are allowed.
365384
*
366-
* @param buf Non-null pointer to a buffer of data.
385+
* @param buf Non-null pointer to an array of data.
367386
*
368-
* @param sz Size of buffer, in bytes.
387+
* @param num Number of elements in the array.
369388
*/
370389
template <typename T>
371-
mutable_shared_buffer& append(const T* buf, std::size_t sz) {
372-
return append(std::as_bytes(std::span<const T>{buf, sz}));
390+
mutable_shared_buffer& append(const T* buf, std::size_t num) {
391+
return append(std::as_bytes(std::span<const T>{buf, num}));
392+
}
393+
394+
/**
395+
* @brief Append by copying bytes from a void pointer.
396+
*
397+
* The pointer passed into this constructor is cast into a @c std::byte pointer and bytes
398+
* are then appended.
399+
*
400+
* @pre Size cannot be greater than the source buffer.
401+
*
402+
* @param buf Non-null @c void pointer to a buffer of data.
403+
*
404+
* @param sz Size of buffer, in bytes.
405+
*/
406+
mutable_shared_buffer& append(const void* buf, size_type sz) {
407+
return append(std::as_bytes(
408+
std::span<const std::byte>{std::bit_cast<const std::byte*>(buf), sz}));
373409
}
374410

375411
/**
@@ -549,20 +585,38 @@ class const_shared_buffer {
549585
*
550586
* The pointer passed into this constructor is cast into a @c std::byte pointer and bytes
551587
* are then copied. In particular, this method can be used for @c char pointers,
552-
* @c void pointers, @c unsigned @c char pointers, etc.
588+
* @c unsigned @c char pointers, @c std::uint8_t pointers, etc. Non character types that
589+
* are trivially copyable are also allowed, although the usual care must be taken
590+
* (padding bytes, alignment, etc).
553591
*
554592
* The type of the span must be convertible to or be layout compatible with
555593
* @c std::byte.
556594
*
557595
* @pre Size cannot be greater than the source buffer.
558596
*
559-
* @param buf Non-null pointer to a buffer of data.
597+
* @param buf Non-null pointer to an array of data.
560598
*
561-
* @param sz Size of buffer, in bytes.
599+
* @param num Number of elements in the array.
562600
*/
563601
template <typename T>
564-
const_shared_buffer(const T* buf, std::size_t sz) :
565-
const_shared_buffer(std::as_bytes(std::span<const T>{buf, sz})) { }
602+
const_shared_buffer(const T* buf, std::size_t num) :
603+
const_shared_buffer(std::as_bytes(std::span<const T>{buf, num})) { }
604+
605+
/**
606+
* @brief Construct by copying bytes from a void pointer.
607+
*
608+
* The pointer passed into this constructor is cast into a @c std::byte pointer and bytes
609+
* are then copied.
610+
*
611+
* @pre Size cannot be greater than the source buffer.
612+
*
613+
* @param buf Non-null @c void pointer to a buffer of data.
614+
*
615+
* @param sz Size of buffer, in bytes.
616+
*/
617+
const_shared_buffer(const void* buf, size_type sz) :
618+
const_shared_buffer(std::as_bytes(
619+
std::span<const std::byte>{std::bit_cast<const std::byte*>(buf), sz})) { }
566620

567621
/**
568622
* @brief Construct by copying from a @c mutable_shared_buffer object.
@@ -581,8 +635,8 @@ class const_shared_buffer {
581635
*
582636
* This constructor will move from a @c mutable_shared_buffer into a @c const_shared_buffer.
583637
* This allows efficient API boundaries, where application code can construct and fill in a
584-
* @c mutable_shared_buffer, then @c std::move it into a @c const_shared_buffer for use
585-
* with asynchronous functions.
638+
* @c mutable_shared_buffer, then use this constructor which will @c std::move it into a
639+
* @c const_shared_buffer for use with asynchronous functions.
586640
*
587641
* @param rhs @c mutable_shared_buffer to be moved from; after moving the
588642
* @c mutable_shared_buffer will be empty.

test/shared_buffer_test.cpp

+22-9
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,16 @@ bool check_sb_against_test_data(SB sb) {
4444
}
4545

4646
template <typename SB, typename PT>
47-
SB generic_pointer_construction_test() {
48-
auto ptr { std::bit_cast<const PT *>(test_data.data()) };
47+
SB generic_pointer_construction_test(const PT * ptr) {
4948
SB sb(ptr, test_data_size);
5049
REQUIRE_FALSE (sb.empty());
5150
REQUIRE (check_sb_against_test_data(sb));
5251
return sb;
5352
}
5453

5554
template <typename PT>
56-
void generic_pointer_append_test() {
57-
auto sb { generic_pointer_construction_test<chops::mutable_shared_buffer, PT>() };
55+
void generic_pointer_append_test(const PT * ptr) {
56+
auto sb { generic_pointer_construction_test<chops::mutable_shared_buffer>(ptr) };
5857
auto sav_sz { sb.size() };
5958
const PT arr[] { 5, 6, 7 };
6059
const PT* ptr_arr { arr };
@@ -149,10 +148,17 @@ void byte_vector_move_test() {
149148
TEMPLATE_TEST_CASE ( "Generic pointer construction",
150149
"[common]",
151150
char, unsigned char, signed char, std::uint8_t ) {
152-
generic_pointer_construction_test<chops::mutable_shared_buffer, TestType>();
153-
generic_pointer_construction_test<chops::const_shared_buffer, TestType>();
151+
const TestType* ptr { std::bit_cast<const TestType *>(test_data.data()) };
152+
generic_pointer_construction_test<chops::mutable_shared_buffer>(ptr);
153+
generic_pointer_construction_test<chops::const_shared_buffer>(ptr);
154154
}
155155

156+
TEST_CASE ( "Void pointer construction",
157+
"[common]" ) {
158+
auto ptr { static_cast<const void *>(test_data.data()) };
159+
generic_pointer_construction_test<chops::mutable_shared_buffer>(ptr);
160+
generic_pointer_construction_test<chops::const_shared_buffer>(ptr);
161+
}
156162

157163
TEMPLATE_TEST_CASE ( "Shared buffer common ctor methods",
158164
"[const_shared_buffer] [mutable_shared_buffer] [common]",
@@ -261,8 +267,6 @@ TEST_CASE ( "Mutable shared buffer append",
261267
REQUIRE (sb == ta);
262268
}
263269

264-
265-
266270
SECTION ( "Append mutable shared buffer" ) {
267271
sb.append(ta);
268272
REQUIRE (sb == ta);
@@ -287,12 +291,21 @@ TEST_CASE ( "Mutable shared buffer append",
287291
sb.append(sv.data(), sv.size());
288292
REQUIRE (sb == cb);
289293
}
294+
295+
SECTION ( "Append with void pointer" ) {
296+
std::string_view sv("Haha, Bro!");
297+
const void* ptr { static_cast<const void*>(sv.data()) };
298+
chops::mutable_shared_buffer cb(sv.data(), sv.size());
299+
sb.append(ptr, sv.size());
300+
REQUIRE (sb == cb);
301+
}
290302
}
291303

292304
TEMPLATE_TEST_CASE ( "Generic pointer append",
293305
"[mutable_shared_buffer] [pointer] [append]",
294306
char, unsigned char, signed char, std::uint8_t ) {
295-
generic_pointer_append_test<TestType>();
307+
const TestType* ptr { std::bit_cast<const TestType *>(test_data.data()) };
308+
generic_pointer_append_test<TestType>(ptr);
296309
}
297310

298311
TEST_CASE ( "Compare a mutable shared_buffer with a const shared buffer",

0 commit comments

Comments
 (0)