Skip to content

Commit d200f0f

Browse files
Marshall ClowGitHub Enterprise
Marshall Clow
authored and
GitHub Enterprise
committed
Add clamp/erase/erase_if algorithms to bsl (#3743)
* Add bsl::clamp for pre-c++17 systems * add bsl::erase/erase_if for the sequence containers (vector, deque, list) * fix typo & include <functional> * add 'bsl::' to uses of iterator_traits * fix another dumb SunOS typo * fix YET another dumb SunOS typo * Add missing 'inline' * add erase_if to map/unordered_map * Add 'erase_if' to all the sets * Regen 03 files * Reowrk AlgorithmUtil - change name, put it into namespace bslstl * Reformat some loops; NFCI * Add a class banner and a few 'inline's * One more inline
1 parent 1592340 commit d200f0f

37 files changed

+1534
-23
lines changed

groups/bsl/bslstl/bslstl_algorithm.h

+85-2
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,40 @@ BSLS_IDENT("$Id: $")
2525
// 'bsl_algorithm.h' directly.
2626

2727
#include <bslscm_version.h>
28+
#include <bsls_assert.h>
2829
#include <bsls_keyword.h>
2930
#include <bsls_libraryfeatures.h>
3031

3132
#include <bslstl_iterator.h> // iterator tags
3233
#include <bslstl_pair.h>
3334

3435
#include <algorithm>
36+
#include <functional> // less
3537

3638
#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
3739
#include <bsls_nativestd.h>
3840
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
3941

42+
namespace BloombergLP {
43+
namespace bslstl {
44+
45+
struct AlgorithmUtil {
46+
// Provide a namespace for implementing helper routines for algorithm
47+
// implementations.
48+
49+
// CLASS FUNCTIONS
50+
template <class CONTAINER, class PREDICATE>
51+
static
52+
typename CONTAINER::size_type
53+
containerEraseIf(CONTAINER& container, PREDICATE predicate);
54+
// Erase all the elements in the specified container 'container' that
55+
// satisfy the specified predicate 'predicate'. Return the number of
56+
// elements erased.
57+
};
58+
59+
} // close package namespace
60+
} // close enterprise namespace
61+
4062
namespace bsl {
4163

4264
// Import selected symbols into bsl namespace
@@ -243,6 +265,22 @@ namespace bsl {
243265
# endif // !BSLS_LIBRARYFEATURES_STDCPP_MSVC
244266
#endif // !BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
245267

268+
#ifndef BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY
269+
template<class TYPE, class COMPARE>
270+
BSLS_KEYWORD_CONSTEXPR_CPP14
271+
const TYPE&
272+
clamp(const TYPE& value, const TYPE& low, const TYPE& high, COMPARE comp);
273+
// Return the specified 'value' adjusted so that it is in the range
274+
// ['low', 'high'), using the specified comparison predicate 'comp'.
275+
276+
template<class TYPE>
277+
BSLS_KEYWORD_CONSTEXPR_CPP14
278+
const TYPE&
279+
clamp(const TYPE& value, const TYPE& low, const TYPE& high);
280+
// Return the specified 'value' adjusted so that it is in the range
281+
// ['low', 'high').
282+
#endif
283+
246284
#ifndef BSLS_LIBRARYFEATURES_HAS_CPP17_SEARCH_OVERLOAD
247285
template<class FORWARD_ITERATOR, class SEARCHER>
248286
BSLS_KEYWORD_CONSTEXPR_CPP14
@@ -253,19 +291,43 @@ namespace bsl {
253291
// first occurrence of the pattern sought by the specified 'searcher'
254292
// if found, and 'last' otherwise. See [alg.search].
255293
#endif // BSLS_LIBRARYFEATURES_HAS_CPP17_SEARCH_OVERLOAD
294+
256295
} // close namespace bsl
257296

258297
// ============================================================================
259298
// INLINE DEFINITIONS
260299
// ============================================================================
261300

301+
// --------------------
302+
// struct AlgorithmUtil
303+
// --------------------
304+
305+
template <class CONTAINER, class PREDICATE>
306+
inline
307+
typename CONTAINER::size_type
308+
BloombergLP::bslstl::AlgorithmUtil::containerEraseIf(CONTAINER& container,
309+
PREDICATE predicate)
310+
{
311+
typename CONTAINER::size_type oldSize = container.size();
312+
for (typename CONTAINER::iterator it = container.begin();
313+
it != container.end();) {
314+
if (predicate(*it)) {
315+
it = container.erase(it);
316+
}
317+
else {
318+
++it;
319+
}
320+
}
321+
return oldSize - container.size();
322+
}
323+
262324
#ifdef BSLSTL_ITERATOR_PROVIDE_SUN_CPP98_FIXES
263325
template <class INPUT_ITERATOR, class TYPE>
264326
inline
265327
typename bsl::iterator_traits<INPUT_ITERATOR>::difference_type
266328
bsl::count(INPUT_ITERATOR first, INPUT_ITERATOR last, const TYPE& value)
267329
{
268-
typename iterator_traits<INPUT_ITERATOR>::difference_type ret = 0;
330+
typename bsl::iterator_traits<INPUT_ITERATOR>::difference_type ret = 0;
269331
std::count(first, last, value, ret);
270332
return ret;
271333
}
@@ -275,7 +337,7 @@ inline
275337
typename bsl::iterator_traits<INPUT_ITERATOR>::difference_type
276338
bsl::count_if(INPUT_ITERATOR first, INPUT_ITERATOR last, PREDICATE pred)
277339
{
278-
typename iterator_traits<INPUT_ITERATOR>::difference_type ret = 0;
340+
typename bsl::iterator_traits<INPUT_ITERATOR>::difference_type ret = 0;
279341
std::count_if(first, last, pred, ret);
280342
return ret;
281343
}
@@ -338,6 +400,26 @@ bsl::copy_if(INPUT_ITERATOR first,
338400
#endif // BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
339401

340402

403+
#ifndef BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY
404+
template<class TYPE, class COMPARE>
405+
BSLS_KEYWORD_CONSTEXPR_CPP14
406+
inline const TYPE&
407+
bsl::clamp(const TYPE& value, const TYPE& low, const TYPE& high, COMPARE comp)
408+
{
409+
BSLS_ASSERT(!comp(high, low));
410+
return comp(value, low) ? low : comp(high, value) ? high : value;
411+
}
412+
413+
template<class TYPE>
414+
BSLS_KEYWORD_CONSTEXPR_CPP14
415+
inline const TYPE&
416+
bsl::clamp(const TYPE& value, const TYPE& low, const TYPE& high)
417+
{
418+
return bsl::clamp(value, low, high, std::less<TYPE>());
419+
}
420+
#endif // BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY
421+
422+
341423
#ifndef BSLS_LIBRARYFEATURES_HAS_CPP17_SEARCH_OVERLOAD
342424
template<class FORWARD_ITERATOR, class SEARCHER>
343425
inline
@@ -351,6 +433,7 @@ bsl::search(FORWARD_ITERATOR first,
351433
}
352434
#endif // BSLS_LIBRARYFEATURES_HAS_CPP17_SEARCH_OVERLOAD
353435

436+
354437
#endif // INCLUDED_BSLSTL_ALGORITHM
355438

356439
// ----------------------------------------------------------------------------

groups/bsl/bslstl/bslstl_algorithm.t.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
// [ 1] bool any_of (InputIter first, InputIter last, PREDICATE pred);
3333
// [ 1] bool none_of(InputIter first, InputIter last, PREDICATE pred);
3434
// [ 2] BREATHING TEST
35+
// [ 3] bsl::clamp();
3536
// ----------------------------------------------------------------------------
3637

3738
// ============================================================================
@@ -340,6 +341,32 @@ int main(int argc, char *argv[])
340341
printf("TEST " __FILE__ " CASE %d\n", test);
341342

342343
switch (test) { case 0:
344+
case 3: {
345+
// --------------------------------------------------------------------
346+
// TESTING C++17 <BSL_ALGORITHM.H> ADDITIONS
347+
//
348+
// Concerns:
349+
//: 1 The call 'bsl::clamp' exists and return expected values for
350+
//: simple cases.
351+
//
352+
// Plan:
353+
//: 1 Call each version of the algorithm with simple inputs and verify
354+
//: that the result is correct.
355+
//
356+
// Testing:
357+
// bsl::clamp();
358+
// --------------------------------------------------------------------
359+
360+
if (verbose) printf("\nTESTING C++17 <BSL_ALGORITHM.H> ADDITIONS"
361+
"\n=========================================\n");
362+
363+
#ifndef BSLS_LIBRARYFEATURES_HAS_CPP17_BASELINE_LIBRARY
364+
ASSERT(3 == bsl::clamp(3, 1, 10));
365+
ASSERT(3 == bsl::clamp(1, 3, 10));
366+
ASSERT(3 == bsl::clamp(3, 10, 1, std::greater<int>()));
367+
ASSERT(3 == bsl::clamp(1, 10, 3, std::greater<int>()));
368+
#endif
369+
} break;
343370
case 2: {
344371
// --------------------------------------------------------------------
345372
// BREATHING TEST

groups/bsl/bslstl/bslstl_deque.0.t.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@
216216
//
217217
// FREE FUNCTIONS
218218
// [20] void swap(deque& a, deque& b);
219+
// [33] size_t erase(deque<T,A>&, const U&);
220+
// [33] size_t erase_if(deque<T,A>&, PREDICATE);
219221
// ----------------------------------------------------------------------------
220222
// [22] CONCERN: 'std::length_error' is used properly.
221223
//

groups/bsl/bslstl/bslstl_deque.3.t.cpp

+101
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,26 @@ size_t numNotMovedInto(const CONTAINER& X,
169169
return numNotMoved;
170170
}
171171

172+
// ============
173+
// class EqPred
174+
// ============
175+
176+
template <class TYPE>
177+
struct EqPred
178+
// A predicate for testing 'erase_if'; it takes a value at construction
179+
// and uses it for comparisons later.
180+
{
181+
TYPE d_ch;
182+
EqPred(TYPE ch) : d_ch(ch) {}
183+
184+
bool operator() (TYPE ch) const
185+
// return 'true' if the specified 'ch' is equal to the stored value,
186+
// and 'false' otherwise.
187+
{
188+
return d_ch == ch;
189+
}
190+
};
191+
172192
// ============================================================================
173193
// TEST DRIVER TEMPLATE
174194
// ----------------------------------------------------------------------------
@@ -228,6 +248,9 @@ struct TestDriver3 : TestSupport<TYPE, ALLOC> {
228248

229249
// TEST CASES
230250

251+
static void testCase33();
252+
// test 'bsl::erase' and 'bsl::erase_if' with 'bsl::deque'.
253+
231254
static void testCase31();
232255
// Test 'noexcept' specifications
233256

@@ -339,6 +362,56 @@ class StdBslmaTestDriver3 : public StdBslmaTestDriverHelper<TestDriver3, TYPE>
339362
// TEST CASES
340363
// ----------
341364

365+
template <class TYPE, class ALLOC>
366+
void TestDriver3<TYPE, ALLOC>::testCase33()
367+
// test 'bsl::erase' and 'bsl::erase_if' with 'bsl::deque'.
368+
{
369+
static const struct {
370+
int d_line; // source line number
371+
const char *d_initial_p; // initial values
372+
char d_element; // value to remove
373+
const char *d_results_p; // expected result value
374+
} DATA[] = {
375+
//line initial element results
376+
//---- ------------------- ------- -------------------
377+
{ L_, "", 'A', "" },
378+
{ L_, "A", 'A', "" },
379+
{ L_, "A", 'B', "A" },
380+
{ L_, "B", 'A', "B" },
381+
{ L_, "AB", 'A', "B" },
382+
{ L_, "BA", 'A', "B" },
383+
{ L_, "BC", 'D', "BC" },
384+
{ L_, "ABC", 'C', "AB" },
385+
{ L_, "CBADEABCDAB", 'B', "CADEACDA" },
386+
{ L_, "CBADEABCDABCDEA", 'E', "CBADABCDABCDA" },
387+
{ L_, "ZZZZZZZZZZZZZZZZ", 'Z', "" }
388+
};
389+
enum { NUM_DATA = sizeof DATA / sizeof *DATA };
390+
391+
for (size_t i = 0; i < NUM_DATA; ++i)
392+
{
393+
int LINE = DATA[i].d_line;
394+
const char *initial = DATA[i].d_initial_p;
395+
size_t initialLen = strlen(initial);
396+
const char *results = DATA[i].d_results_p;
397+
size_t resultsLen = strlen(results);
398+
399+
Obj v1(initial, initial + initialLen);
400+
Obj v2(initial, initial + initialLen);
401+
Obj vres(results, results + resultsLen);
402+
size_t ret1 = bsl::erase (v1, DATA[i].d_element);
403+
size_t ret2 = bsl::erase_if(v2, EqPred<TYPE>(DATA[i].d_element));
404+
405+
// Are the modified containers correct?
406+
ASSERTV(LINE, v1 == vres);
407+
ASSERTV(LINE, v2 == vres);
408+
409+
// Are the return values correct?
410+
ASSERTV(LINE, ret1 == initialLen - resultsLen);
411+
ASSERTV(LINE, ret2 == initialLen - resultsLen);
412+
}
413+
}
414+
342415
template <class TYPE, class ALLOC>
343416
void TestDriver3<TYPE,ALLOC>::testCase31()
344417
{
@@ -4660,6 +4733,34 @@ int main(int argc, char *argv[])
46604733
printf("TEST " __FILE__ " CASE %d\n", test);
46614734

46624735
switch (test) { case 0: // Zero is always the leading case.
4736+
case 33: {
4737+
// --------------------------------------------------------------------
4738+
// TESTING FREE FUNCTIONS 'BSL::ERASE' AND 'BSL::ERASE_IF'
4739+
//
4740+
// Concerns:
4741+
//: 1 The free functions exist, and are callable with a deque.
4742+
//
4743+
// Plan:
4744+
//: 1 Fill a deque with known values, then attempt to erase some of
4745+
//: the values using 'bsl::erase' and 'bsl::erase_if'. Verify that
4746+
//: the resultant deque is the right size, contains the correct
4747+
//: values, and that the value returned from the functions is
4748+
//: correct.
4749+
//
4750+
// Testing:
4751+
// size_t erase(deque<T,A>&, const U&);
4752+
// size_t erase_if(deque<T,A>&, PREDICATE);
4753+
// --------------------------------------------------------------------
4754+
4755+
if (verbose)
4756+
printf(
4757+
"\nTESTING FREE FUNCTIONS 'BSL::ERASE' AND 'BSL::ERASE_IF'"
4758+
"\n=======================================================\n");
4759+
4760+
TestDriver3<char>::testCase33();
4761+
TestDriver3<int>::testCase33();
4762+
TestDriver3<long>::testCase33();
4763+
} break;
46634764
case 32: {
46644765
//---------------------------------------------------------------------
46654766
// TESTING CLASS TEMPLATE DEDUCTION GUIDES (AT COMPILE TIME)

groups/bsl/bslstl/bslstl_deque.h

+31
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ BSLS_IDENT("$Id: $")
393393

394394
#include <bslscm_version.h>
395395

396+
#include <bslstl_algorithm.h>
396397
#include <bslstl_iterator.h>
397398
#include <bslstl_iteratorutil.h>
398399
#include <bslstl_randomaccessiterator.h>
@@ -1530,6 +1531,18 @@ bool operator>=(const deque<VALUE_TYPE, ALLOCATOR>& lhs,
15301531
// 'value_type'. Note that this operator returns '!(lhs < rhs)'.
15311532

15321533
// FREE FUNCTIONS
1534+
template <class VALUE_TYPE, class ALLOCATOR, class OTHER_TYPE>
1535+
typename deque<VALUE_TYPE, ALLOCATOR>::size_type
1536+
erase(deque<VALUE_TYPE, ALLOCATOR>& deq, const OTHER_TYPE& value);
1537+
// Erase all the elements in the specified deque 'deq' that compare equal
1538+
// to the specified 'value'. Return the number of elements erased.
1539+
1540+
template <class VALUE_TYPE, class ALLOCATOR, class PREDICATE>
1541+
typename deque<VALUE_TYPE, ALLOCATOR>::size_type
1542+
erase_if(deque<VALUE_TYPE, ALLOCATOR>& deq, PREDICATE predicate);
1543+
// Erase all the elements in the specified deque 'deq' that satisfy the
1544+
// specified predicate 'predicate'. Return the number of elements erased.
1545+
15331546
template <class VALUE_TYPE, class ALLOCATOR>
15341547
void swap(deque<VALUE_TYPE, ALLOCATOR>& a, deque<VALUE_TYPE, ALLOCATOR>& b)
15351548
BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(false);
@@ -3892,6 +3905,24 @@ bool operator>=(const deque<VALUE_TYPE, ALLOCATOR>& lhs,
38923905
}
38933906

38943907
// FREE FUNCTIONS
3908+
template <class VALUE_TYPE, class ALLOCATOR, class OTHER_TYPE>
3909+
inline typename deque<VALUE_TYPE, ALLOCATOR>::size_type
3910+
erase(deque<VALUE_TYPE, ALLOCATOR>& deq, const OTHER_TYPE& value)
3911+
{
3912+
typename deque<VALUE_TYPE, ALLOCATOR>::size_type oldSize = deq.size();
3913+
deq.erase(bsl::remove(deq.begin(), deq.end(), value), deq.end());
3914+
return oldSize - deq.size();
3915+
}
3916+
3917+
template <class VALUE_TYPE, class ALLOCATOR, class PREDICATE>
3918+
inline typename deque<VALUE_TYPE, ALLOCATOR>::size_type
3919+
erase_if(deque<VALUE_TYPE, ALLOCATOR>& deq, PREDICATE predicate)
3920+
{
3921+
typename deque<VALUE_TYPE, ALLOCATOR>::size_type oldSize = deq.size();
3922+
deq.erase(bsl::remove_if(deq.begin(), deq.end(), predicate), deq.end());
3923+
return oldSize - deq.size();
3924+
}
3925+
38953926
template <class VALUE_TYPE, class ALLOCATOR>
38963927
inline
38973928
void swap(deque<VALUE_TYPE, ALLOCATOR>& a, deque<VALUE_TYPE, ALLOCATOR>& b)

0 commit comments

Comments
 (0)