Skip to content

Commit 860e5d9

Browse files
committed
Asio buffer compatibility is opt-in
1 parent 9451544 commit 860e5d9

File tree

10 files changed

+732
-109
lines changed

10 files changed

+732
-109
lines changed

CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,18 @@ add_subdirectory(bench)
9898

9999
#-------------------------------------------------
100100
#
101-
# Tests
101+
# Examples (before tests so Boost::asio is available)
102102
#
103103
#-------------------------------------------------
104-
if (BOOST_CAPY_BUILD_TESTS)
105-
add_subdirectory(test)
104+
if (BOOST_CAPY_BUILD_EXAMPLES)
105+
add_subdirectory(example)
106106
endif ()
107107

108108
#-------------------------------------------------
109109
#
110-
# Examples
110+
# Tests
111111
#
112112
#-------------------------------------------------
113-
if (BOOST_CAPY_BUILD_EXAMPLES)
114-
add_subdirectory(example)
113+
if (BOOST_CAPY_BUILD_TESTS)
114+
add_subdirectory(test)
115115
endif ()

example/allocation/CMakeLists.txt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
# Official repository: https://github.com/cppalliance/capy
88
#
99

10-
include(FetchContent)
11-
FetchContent_Declare(mimalloc
12-
GIT_REPOSITORY https://github.com/microsoft/mimalloc
13-
GIT_TAG v2.2.7
14-
GIT_SHALLOW TRUE)
15-
set(MI_BUILD_TESTS OFF CACHE BOOL "Disable mimalloc tests" FORCE)
16-
FetchContent_MakeAvailable(mimalloc)
10+
if(BUILD_SHARED_LIBS)
11+
include(FetchContent)
12+
FetchContent_Declare(mimalloc
13+
GIT_REPOSITORY https://github.com/microsoft/mimalloc
14+
GIT_TAG v2.2.7
15+
GIT_SHALLOW TRUE)
16+
set(MI_BUILD_TESTS OFF CACHE BOOL "Disable mimalloc tests" FORCE)
17+
FetchContent_MakeAvailable(mimalloc)
18+
endif()
1719

1820
file(GLOB_RECURSE PFILES CONFIGURE_DEPENDS *.cpp *.hpp
1921
CMakeLists.txt
@@ -26,6 +28,9 @@ add_executable(capy_example_allocation ${PFILES})
2628
set_property(TARGET capy_example_allocation
2729
PROPERTY FOLDER "examples")
2830

29-
target_link_libraries(capy_example_allocation
30-
Boost::capy
31-
mimalloc-static)
31+
target_link_libraries(capy_example_allocation Boost::capy)
32+
33+
if(BUILD_SHARED_LIBS)
34+
target_link_libraries(capy_example_allocation mimalloc-static)
35+
target_compile_definitions(capy_example_allocation PRIVATE BOOST_CAPY_HAS_MIMALLOC=1)
36+
endif()

example/allocation/allocation.cpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@
1717

1818
#include <boost/capy.hpp>
1919
#include <boost/capy/test/run_blocking.hpp>
20+
#if BOOST_CAPY_HAS_MIMALLOC
2021
#include <mimalloc.h>
22+
#endif
2123
#include <atomic>
2224
#include <chrono>
2325
#include <cmath>
2426
#include <cstddef>
2527
#include <iomanip>
2628
#include <iostream>
2729
#include <memory_resource>
30+
#include <sstream>
2831

2932
// Prevent HALO from eliding coroutine frame allocations
3033
#if defined(_MSC_VER)
@@ -39,6 +42,7 @@ using namespace boost::capy;
3942

4043
std::atomic<std::size_t> counter{0};
4144

45+
#if BOOST_CAPY_HAS_MIMALLOC
4246
// Adapts mimalloc to std::pmr::memory_resource
4347
class mi_memory_resource
4448
: public std::pmr::memory_resource
@@ -71,6 +75,7 @@ class mi_memory_resource
7175
return this == &other;
7276
}
7377
};
78+
#endif
7479

7580
// These coroutines simulate a "composed operation"
7681
// consisting of layered APIs. For example a user's
@@ -124,6 +129,7 @@ int main()
124129
}
125130
auto t1 = std::chrono::steady_clock::now();
126131

132+
#if BOOST_CAPY_HAS_MIMALLOC
127133
// With mimalloc
128134
counter.store(0);
129135
mi_memory_resource mi_mr;
@@ -137,6 +143,7 @@ int main()
137143
ctx.run();
138144
}
139145
auto t3 = std::chrono::steady_clock::now();
146+
#endif
140147

141148
// With std::allocator (no recycling)
142149
counter.store(0);
@@ -152,31 +159,37 @@ int main()
152159

153160
auto ms_recycling =
154161
std::chrono::duration<double, std::milli>(t1 - t0).count();
155-
auto ms_mimalloc =
156-
std::chrono::duration<double, std::milli>(t3 - t2).count();
157162
auto ms_standard =
158163
std::chrono::duration<double, std::milli>(t5 - t4).count();
159164

160165
auto pct_rc_std = std::round(
161166
(ms_standard / ms_recycling - 1.0) * 1000.0) / 10.0;
162-
auto pct_mi_std = std::round(
163-
(ms_standard / ms_mimalloc - 1.0) * 1000.0) / 10.0;
164-
auto pct_rc_mi = std::round(
165-
(ms_mimalloc / ms_recycling - 1.0) * 1000.0) / 10.0;
166167

167-
std::cout
168-
<< iterations << " iterations, "
168+
std::ostringstream os;
169+
os << std::fixed << std::setprecision(1);
170+
os << iterations << " iterations, "
169171
<< "4-deep coroutine chain\n\n"
170-
<< std::fixed << std::setprecision(1)
171172
<< " Recycling allocator: "
172173
<< ms_recycling << " ms (+"
173-
<< pct_rc_std << "% vs std, +"
174-
<< pct_rc_mi << "% vs mimalloc)\n"
174+
<< pct_rc_std << "% vs std";
175+
#if BOOST_CAPY_HAS_MIMALLOC
176+
auto ms_mimalloc =
177+
std::chrono::duration<double, std::milli>(t3 - t2).count();
178+
auto pct_mi_std = std::round(
179+
(ms_standard / ms_mimalloc - 1.0) * 1000.0) / 10.0;
180+
auto pct_rc_mi = std::round(
181+
(ms_mimalloc / ms_recycling - 1.0) * 1000.0) / 10.0;
182+
os << ", +" << pct_rc_mi << "% vs mimalloc)\n"
175183
<< " mimalloc: "
176184
<< ms_mimalloc << " ms (+"
177-
<< pct_mi_std << "% vs std)\n"
178-
<< " std::allocator: "
185+
<< pct_mi_std << "% vs std)\n";
186+
#else
187+
os << ")\n";
188+
#endif
189+
os << " std::allocator: "
179190
<< ms_standard << " ms\n";
180191

192+
std::cout << os.str();
193+
181194
return 0;
182195
}

example/asio/api/capy_streams.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <boost/asio/post.hpp>
1818

1919
#include <boost/capy/buffers.hpp>
20+
#include <boost/capy/buffers/asio.hpp>
2021
#include <boost/capy/buffers/buffer_array.hpp>
2122
#include <boost/capy/concept/stream.hpp>
2223
#include <coroutine>
@@ -105,7 +106,7 @@ class asio_socket
105106
cancel_ = std::make_shared<cancel_state>(env->stop_token);
106107

107108
self_->socket_.async_read_some(
108-
capy::mutable_buffer_array<8>(buffers_),
109+
capy::to_asio(capy::mutable_buffer_array<8>(buffers_)),
109110
net::bind_cancellation_slot(
110111
cancel_->signal.slot(),
111112
[this, h, ex = env->executor](
@@ -167,7 +168,7 @@ class asio_socket
167168
cancel_ = std::make_shared<cancel_state>(env->stop_token);
168169

169170
self_->socket_.async_write_some(
170-
capy::const_buffer_array<8>(buffers_),
171+
capy::to_asio(capy::const_buffer_array<8>(buffers_)),
171172
net::bind_cancellation_slot(
172173
cancel_->signal.slot(),
173174
[this, h, ex = env->executor](

example/asio/api/uni_stream.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "capy_streams.hpp"
2020

21+
#include <boost/capy/buffers/asio.hpp>
2122
#include <boost/capy/io/any_stream.hpp>
2223
#include <boost/capy/ex/run_async.hpp>
2324
#include <boost/capy/task.hpp>
@@ -121,7 +122,8 @@ class uni_stream
121122
MutableBufferSequence bufs,
122123
ReadHandler h) -> capy::task<>
123124
{
124-
auto [ec, n] = co_await stream->read_some(bufs);
125+
auto [ec, n] = co_await stream->read_some(
126+
capy::from_asio(bufs));
125127
std::move(h)(ec, n);
126128
}(&self_->stream_, buffers, std::forward<ReadHandler>(handler)));
127129
}
@@ -152,7 +154,8 @@ class uni_stream
152154
ConstBufferSequence bufs,
153155
WriteHandler h) -> capy::task<>
154156
{
155-
auto [ec, n] = co_await stream->write_some(bufs);
157+
auto [ec, n] = co_await stream->write_some(
158+
capy::from_asio(bufs));
156159
std::move(h)(ec, n);
157160
}(&self_->stream_, buffers, std::forward<WriteHandler>(handler)));
158161
}

include/boost/capy/buffers.hpp

Lines changed: 12 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -32,38 +32,6 @@ namespace capy {
3232
class const_buffer;
3333
class mutable_buffer;
3434

35-
namespace detail {
36-
37-
// satisfies Asio's buffer constructors, CANNOT be removed!
38-
template<class T, std::size_t Extent = (std::size_t)(-1)>
39-
class basic_buffer
40-
{
41-
constexpr auto data() const noexcept ->
42-
std::conditional_t<std::is_const_v<T>, void const*, void*>
43-
{
44-
return p_;
45-
}
46-
47-
constexpr std::size_t size() const noexcept
48-
{
49-
return n_;
50-
}
51-
52-
friend class capy::const_buffer;
53-
friend class capy::mutable_buffer;
54-
friend class asio::const_buffer;
55-
friend class asio::mutable_buffer;
56-
basic_buffer() = default;
57-
constexpr basic_buffer(T* p, std::size_t n) noexcept : p_(p), n_(n) {}
58-
constexpr basic_buffer<T, (std::size_t)(-1)> subspan(
59-
std::size_t, std::size_t = (std::size_t)(-1)) const noexcept;
60-
61-
T* p_ = nullptr;
62-
std::size_t n_ = 0;
63-
};
64-
65-
} // detail
66-
6735
//------------------------------------------------
6836

6937
/// Tag type for customizing `buffer_size` via `tag_invoke`.
@@ -98,8 +66,10 @@ enum class slice_how
9866
@see const_buffer, MutableBufferSequence
9967
*/
10068
class mutable_buffer
101-
: public detail::basic_buffer<unsigned char>
10269
{
70+
unsigned char* p_ = nullptr;
71+
std::size_t n_ = 0;
72+
10373
public:
10474
/// Construct an empty buffer.
10575
mutable_buffer() = default;
@@ -115,19 +85,8 @@ class mutable_buffer
11585
/// Construct from pointer and size.
11686
constexpr mutable_buffer(
11787
void* data, std::size_t size) noexcept
118-
: basic_buffer<unsigned char>(
119-
static_cast<unsigned char*>(data), size)
120-
{
121-
}
122-
123-
/// Construct from Asio mutable_buffer.
124-
template<class MutableBuffer>
125-
requires std::same_as<MutableBuffer, asio::mutable_buffer>
126-
constexpr mutable_buffer(
127-
MutableBuffer const& b) noexcept
128-
: basic_buffer<unsigned char>(
129-
static_cast<unsigned char*>(
130-
b.data()), b.size())
88+
: p_(static_cast<unsigned char*>(data))
89+
, n_(size)
13190
{
13291
}
13392

@@ -199,8 +158,10 @@ class mutable_buffer
199158
@see mutable_buffer, ConstBufferSequence
200159
*/
201160
class const_buffer
202-
: public detail::basic_buffer<unsigned char const>
203161
{
162+
unsigned char const* p_ = nullptr;
163+
std::size_t n_ = 0;
164+
204165
public:
205166
/// Construct an empty buffer.
206167
const_buffer() = default;
@@ -215,28 +176,16 @@ class const_buffer
215176
/// Construct from pointer and size.
216177
constexpr const_buffer(
217178
void const* data, std::size_t size) noexcept
218-
: basic_buffer<unsigned char const>(
219-
static_cast<unsigned char const*>(data), size)
179+
: p_(static_cast<unsigned char const*>(data))
180+
, n_(size)
220181
{
221182
}
222183

223184
/// Construct from mutable_buffer.
224185
constexpr const_buffer(
225186
mutable_buffer const& b) noexcept
226-
: basic_buffer<unsigned char const>(
227-
static_cast<unsigned char const*>(b.data()), b.size())
228-
{
229-
}
230-
231-
/// Construct from Asio buffer types.
232-
template<class ConstBuffer>
233-
requires (std::same_as<ConstBuffer, asio::const_buffer> ||
234-
std::same_as<ConstBuffer, asio::mutable_buffer>)
235-
constexpr const_buffer(
236-
ConstBuffer const& b) noexcept
237-
: basic_buffer<unsigned char const>(
238-
static_cast<unsigned char const*>(
239-
b.data()), b.size())
187+
: p_(static_cast<unsigned char const*>(b.data()))
188+
, n_(b.size())
240189
{
241190
}
242191

0 commit comments

Comments
 (0)