Skip to content

Commit 21c680f

Browse files
committed
Reapply reverted iterator invalidation fix and improve buffers test performance
1 parent cf782bd commit 21c680f

File tree

4 files changed

+134
-39
lines changed

4 files changed

+134
-39
lines changed

include/boost/buffers/slice.hpp

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,12 @@ class slice_of
6464
using iter_type = decltype(
6565
std::declval<BufferSequence const&>().begin());
6666

67+
using difference_type =
68+
typename std::iterator_traits<iter_type>::difference_type;
69+
6770
BufferSequence bs_;
68-
iter_type begin_;
69-
iter_type end_;
71+
difference_type begin_ = 0; // index of first buffer in sequence
72+
difference_type end_ = 0; // 1 + index of last buffer in sequence
7073
std::size_t len_ = 0; // length of bs_
7174
std::size_t size_ = 0; // total bytes
7275
std::size_t prefix_ = 0; // used prefix bytes
@@ -92,11 +95,12 @@ class slice_of
9295
slice_of(
9396
BufferSequence const& bs)
9497
: bs_(bs)
95-
, begin_(buffers::begin(bs_))
96-
, end_(buffers::end(bs_))
9798
{
98-
auto it = begin_;
99-
while(it != end_)
99+
iter_type it = buffers::begin(bs_);
100+
iter_type eit = buffers::end(bs_);
101+
begin_ = 0;
102+
end_ = std::distance(it, eit);
103+
while(it != eit)
100104
{
101105
value_type b(*it);
102106
size_ += b.size();
@@ -127,18 +131,39 @@ class slice_of
127131
}
128132

129133
private:
134+
iter_type
135+
begin_iter_impl() const noexcept
136+
{
137+
iter_type it = buffers::begin(bs_);
138+
std::advance(it, begin_);
139+
return it;
140+
}
141+
142+
iter_type
143+
end_iter_impl() const noexcept
144+
{
145+
iter_type it = buffers::begin(bs_);
146+
std::advance(it, end_);
147+
return it;
148+
}
149+
130150
void
131151
remove_prefix_impl(
132152
std::size_t n)
133153
{
154+
if(n > size_)
155+
n = size_;
156+
134157
// nice hack to simplify the loop (M. Nejati)
135158
n += prefix_;
136159
size_ += prefix_;
137160
prefix_ = 0;
138161

162+
iter_type it = begin_iter_impl();
163+
139164
while(n > 0 && begin_ != end_)
140165
{
141-
value_type b = *begin_;
166+
value_type b = *it;
142167
if(n < b.size())
143168
{
144169
prefix_ = n;
@@ -148,6 +173,7 @@ class slice_of
148173
n -= b.size();
149174
size_ -= b.size();
150175
++begin_;
176+
++it;
151177
--len_;
152178
}
153179
}
@@ -162,12 +188,19 @@ class slice_of
162188
return;
163189
}
164190
BOOST_ASSERT(begin_ != end_);
191+
192+
if(n > size_)
193+
n = size_;
194+
165195
n += suffix_;
166196
size_ += suffix_;
167197
suffix_ = 0;
168-
iter_type it = end_;
169-
--it;
170-
while(it != begin_)
198+
199+
iter_type bit = begin_iter_impl();
200+
iter_type it = end_iter_impl();
201+
it--;
202+
203+
while(it != bit)
171204
{
172205
value_type b = *it;
173206
if(n < b.size())
@@ -192,6 +225,7 @@ class slice_of
192225
}
193226
end_ = begin_;
194227
len_ = 0;
228+
size_ = 0;
195229
}
196230

197231
void
@@ -376,7 +410,7 @@ begin() const noexcept ->
376410
const_iterator
377411
{
378412
return const_iterator(
379-
this->begin_, prefix_, suffix_, 0, len_);
413+
begin_iter_impl(), prefix_, suffix_, 0, len_);
380414
}
381415

382416
template<class BufferSequence>
@@ -386,7 +420,7 @@ end() const noexcept ->
386420
const_iterator
387421
{
388422
return const_iterator(
389-
this->end_, prefix_, suffix_, len_, len_);
423+
end_iter_impl(), prefix_, suffix_, len_, len_);
390424
}
391425

392426
//------------------------------------------------

test/unit/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
# Official repository: https://github.com/cppalliance/buffers
88
#
99

10-
add_subdirectory(../../../url/extra/test_suite test_suite)
10+
if (NOT TARGET boost_url_test_suite)
11+
add_subdirectory(../../../url/extra/test_suite test_suite)
12+
endif()
1113

1214
file(GLOB_RECURSE PFILES CONFIGURE_DEPENDS *.cpp *.hpp)
1315
list(APPEND PFILES

test/unit/slice.cpp

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

1919
#include <array>
20+
#include <vector>
2021

2122
#include "test_buffers.hpp"
2223
#include "test_suite.hpp"
@@ -116,10 +117,13 @@ struct slice_test
116117
return;
117118
if(! BOOST_TEST_EQ(core::string_view(buf, n), s))
118119
return;
119-
test::check_iterators(b, s);
120+
121+
std::string tmp;
122+
test::check_iterators(b, s, tmp);
120123
}
121124

122-
using seq_type = std::array<const_buffer, 3>;
125+
// Use a vector so that iterator invalidation is observable during testing.
126+
using seq_type = std::vector<const_buffer>;
123127

124128
void
125129
grind_back(
@@ -176,9 +180,9 @@ struct slice_test
176180
run()
177181
{
178182
std::string s;
179-
seq_type bs = make_buffers(s,
180-
"boost.", "buffers.", "slice_" );
181-
test::check_sequence(bs, s);
183+
auto a = make_buffers(s, "boost.", "buffers.", "slice_");
184+
seq_type bs(a.begin(), a.end());
185+
test::check_sequence(bs, s, true);
182186
//check(bs, s);
183187
//grind(bs, s);
184188
}

test/unit/test_buffers.hpp

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,21 @@ template<class ConstBufferSequence>
9999
void
100100
check_iterators(
101101
ConstBufferSequence bs,
102-
core::string_view pat)
102+
core::string_view pat,
103+
std::string& s)
103104
{
104105
BOOST_ASSERT(is_const_buffer_sequence<ConstBufferSequence>::value);
105106
BOOST_TEST_EQ(size(bs), pat.size());
106107

107108
auto const& ct = bs;
108109

110+
//std::string s;
111+
s.reserve(pat.size() + 1);
112+
109113
// operator++()
110114
{
111-
std::string s;
115+
s.clear();
116+
s.reserve(pat.size() + 1);
112117
auto it = begin(bs);
113118
auto const end_ = end(bs);
114119
while(it != end_)
@@ -124,7 +129,8 @@ check_iterators(
124129

125130
// operator++(int)
126131
{
127-
std::string s;
132+
s.clear();
133+
s.reserve(pat.size() + 1);
128134
auto it = begin(bs);
129135
auto const end_ = end(bs);
130136
while(it != end_)
@@ -140,7 +146,8 @@ check_iterators(
140146

141147
// operator++() const
142148
{
143-
std::string s;
149+
s.clear();
150+
s.reserve(pat.size() + 1);
144151
auto it = begin(ct);
145152
auto const end_ = end(ct);
146153
while(it != end_)
@@ -156,7 +163,8 @@ check_iterators(
156163

157164
// operator++(int) const
158165
{
159-
std::string s;
166+
s.clear();
167+
s.reserve(pat.size() + 1);
160168
auto it = begin(ct);
161169
auto const end_ = end(ct);
162170
while(it != end_)
@@ -172,7 +180,8 @@ check_iterators(
172180

173181
// operator--()
174182
{
175-
std::string s;
183+
s.clear();
184+
s.reserve(pat.size() + 1);
176185
auto it = end(bs);
177186
auto const begin_ = begin(bs);
178187
while(it != begin_)
@@ -188,7 +197,8 @@ check_iterators(
188197

189198
// operator--(int)
190199
{
191-
std::string s;
200+
s.clear();
201+
s.reserve(pat.size() + 1);
192202
auto it = end(bs);
193203
auto const begin_ = begin(bs);
194204
while(it != begin_)
@@ -204,7 +214,8 @@ check_iterators(
204214

205215
// operator--() const
206216
{
207-
std::string s;
217+
s.clear();
218+
s.reserve(pat.size() + 1);
208219
auto it = end(ct);
209220
auto const begin_ = begin(ct);
210221
while(it != begin_)
@@ -220,7 +231,8 @@ check_iterators(
220231

221232
// operator--(int) const
222233
{
223-
std::string s;
234+
s.clear();
235+
s.reserve(pat.size() + 1);
224236
auto it = end(ct);
225237
auto const begin_ = begin(ct);
226238
while(it != begin_)
@@ -255,23 +267,44 @@ template<class ConstBufferSequence>
255267
void
256268
grind_front(
257269
ConstBufferSequence const& bs0,
258-
core::string_view pat0)
270+
core::string_view pat0,
271+
bool deep)
259272
{
273+
std::string tmp;
274+
260275
for(std::size_t n = 0; n <= pat0.size() + 1; ++n)
261276
{
262277
{
263278
auto pat = trimmed_front(pat0, n);
264279
slice_type<ConstBufferSequence> bs(bs0);
265280
remove_prefix(bs, n);
266281
check_eq(bs, pat);
267-
check_iterators(bs, pat);
282+
check_iterators(bs, pat, tmp);
283+
284+
if(deep)
285+
{
286+
// Take a copy, blank out the original to invalidate any
287+
// iterators, and redo the test
288+
slice_type<ConstBufferSequence> bsc(bs);
289+
{
290+
slice_type<ConstBufferSequence> dummy{};
291+
std::swap(bs, dummy);
292+
}
293+
for(std::size_t m = 0; m <= pat.size() + 1; ++m)
294+
{
295+
auto pat2 = trimmed_front(pat, m);
296+
slice_type<ConstBufferSequence> bs2(bsc);
297+
remove_prefix(bs2, m);
298+
check_eq(bs2, pat2);
299+
}
300+
}
268301
}
269302
{
270303
auto pat = kept_front(pat0, n);
271304
slice_type<ConstBufferSequence> bs(bs0);
272305
keep_prefix(bs, n);
273306
check_eq(bs, pat);
274-
check_iterators(bs, pat);
307+
check_iterators(bs, pat, tmp);
275308
}
276309
}
277310
}
@@ -280,23 +313,43 @@ template<class ConstBufferSequence>
280313
void
281314
grind_back(
282315
ConstBufferSequence const& bs0,
283-
core::string_view pat0)
316+
core::string_view pat0,
317+
bool deep)
284318
{
319+
std::string tmp;
320+
285321
for(std::size_t n = 0; n <= pat0.size() + 1; ++n)
286322
{
287323
{
288324
auto pat = trimmed_back(pat0, n);
289325
slice_type<ConstBufferSequence> bs(bs0);
290326
remove_suffix(bs, n);
291327
check_eq(bs, pat);
292-
check_iterators(bs, pat);
328+
check_iterators(bs, pat, tmp);
329+
if(deep)
330+
{
331+
// Take a copy, blank out the original to invalidate any
332+
// iterators, and redo the test
333+
slice_type<ConstBufferSequence> bsc(bs);
334+
{
335+
slice_type<ConstBufferSequence> dummy{};
336+
std::swap(bs, dummy);
337+
}
338+
for(std::size_t m = 0; m <= pat.size() + 1; ++m)
339+
{
340+
auto pat2 = trimmed_back(pat, m);
341+
slice_type<ConstBufferSequence> bs2(bsc);
342+
remove_suffix(bs2, m);
343+
check_eq(bs2, pat2);
344+
}
345+
}
293346
}
294347
{
295348
auto pat = kept_back(pat0, n);
296349
slice_type<ConstBufferSequence> bs(bs0);
297350
keep_suffix(bs, n);
298351
check_eq(bs, pat);
299-
check_iterators(bs, pat);
352+
check_iterators(bs, pat, tmp);
300353
}
301354
}
302355
}
@@ -305,22 +358,24 @@ template<class ConstBufferSequence>
305358
void
306359
check_slice(
307360
ConstBufferSequence const& bs,
308-
core::string_view pat)
361+
core::string_view pat,
362+
bool deep)
309363
{
310-
grind_front(bs, pat);
311-
grind_back(bs, pat);
364+
grind_front(bs, pat, deep);
365+
grind_back(bs, pat, deep);
312366
}
313367

314368
// Test API and behavior of a BufferSequence
315369
template<class T>
316370
void
317371
check_sequence(
318-
T const& t, core::string_view pat)
372+
T const& t, core::string_view pat, bool deep = false)
319373
{
320374
BOOST_STATIC_ASSERT(is_const_buffer_sequence<T>::value);
321375

322-
check_iterators(t, pat);
323-
check_slice(t, pat);
376+
std::string tmp;
377+
check_iterators(t, pat, tmp);
378+
check_slice(t, pat, deep);
324379
}
325380

326381
} // test

0 commit comments

Comments
 (0)