Skip to content

Commit b65415f

Browse files
committed
[libc++][test] Add lower_bound complexity validation tests prior to introducing one-sided binary search for non-random iterators.
1 parent dda46b2 commit b65415f

File tree

3 files changed

+79
-23
lines changed

3 files changed

+79
-23
lines changed

libcxx/test/std/algorithms/alg.sorting/alg.binary.search/lower.bound/lower_bound.pass.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,20 @@ template <class Iter, class T>
3939
void
4040
test(Iter first, Iter last, const T& value)
4141
{
42-
Iter i = std::lower_bound(first, last, value);
43-
for (Iter j = first; j != i; ++j)
44-
assert(*j < value);
45-
for (Iter j = i; j != last; ++j)
46-
assert(!(*j < value));
42+
std::size_t strides{};
43+
std::size_t displacement{};
44+
stride_counting_iterator f(first, &strides, &displacement);
45+
stride_counting_iterator l(last, &strides, &displacement);
46+
47+
auto i = std::lower_bound(f, l, value);
48+
for (auto j = f; j != i; ++j)
49+
assert(*j < value);
50+
for (auto j = i; j != l; ++j)
51+
assert(!(*j < value));
52+
53+
auto len = std::distance(first, last);
54+
assert(strides <= 2.5 * len + 1);
55+
assert(displacement <= 2.5 * len + 1);
4756
}
4857

4958
template <class Iter>

libcxx/test/std/algorithms/alg.sorting/alg.binary.search/lower.bound/lower_bound_comp.pass.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <vector>
1818
#include <cassert>
1919
#include <cstddef>
20+
#include <cmath>
2021

2122
#include "test_macros.h"
2223
#include "test_iterators.h"
@@ -38,11 +39,28 @@ template <class Iter, class T>
3839
void
3940
test(Iter first, Iter last, const T& value)
4041
{
41-
Iter i = std::lower_bound(first, last, value, std::greater<int>());
42-
for (Iter j = first; j != i; ++j)
43-
assert(std::greater<int>()(*j, value));
44-
for (Iter j = i; j != last; ++j)
45-
assert(!std::greater<int>()(*j, value));
42+
std::size_t strides{};
43+
std::size_t displacement{};
44+
stride_counting_iterator f(first, &strides, &displacement);
45+
stride_counting_iterator l(last, &strides, &displacement);
46+
47+
std::size_t comparisons{};
48+
auto cmp = [&comparisons](int rhs, int lhs) {
49+
++comparisons;
50+
return std::greater<int>()(rhs, lhs);
51+
};
52+
53+
auto i = std::lower_bound(f, l, value, cmp);
54+
55+
for (auto j = f; j != i; ++j)
56+
assert(std::greater<int>()(*j, value));
57+
for (auto j = i; j != l; ++j)
58+
assert(!std::greater<int>()(*j, value));
59+
60+
auto len = std::distance(first, last);
61+
assert(strides <= 2.5 * len + 1);
62+
assert(displacement <= 2.5 * len + 1);
63+
assert(comparisons <= 2 * ceil(log(len + 1) + 2));
4664
}
4765

4866
template <class Iter>

libcxx/test/support/test_iterators.h

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,9 @@ struct common_input_iterator {
730730
// * `stride_displacement`, which records the displacement of the calls. This means that both
731731
// op++/op+= will increase the displacement counter by 1, and op--/op-= will decrease the
732732
// displacement counter by 1.
733-
template <class It>
733+
template <class It,
734+
class StrideCountType = std::iter_difference_t<It>,
735+
class StrideDisplacementType = std::iter_difference_t<It>>
734736
class stride_counting_iterator {
735737
public:
736738
using value_type = typename iter_value_or_void<It>::type;
@@ -743,16 +745,40 @@ class stride_counting_iterator {
743745
std::conditional_t<std::input_iterator<It>, std::input_iterator_tag,
744746
/* else */ std::output_iterator_tag
745747
>>>>>;
748+
using iterator_category = iterator_concept;
746749

747750
stride_counting_iterator() requires std::default_initializable<It> = default;
748751

749752
constexpr explicit stride_counting_iterator(It const& it) : base_(base(it)) { }
750753

754+
constexpr explicit stride_counting_iterator(
755+
It const& it, StrideCountType* stride_count, StrideDisplacementType* stride_displacement)
756+
: base_(base(it)), stride_count_(stride_count), stride_displacement_(stride_displacement) {}
757+
758+
constexpr stride_counting_iterator(const stride_counting_iterator& o) { *this = o; }
759+
constexpr stride_counting_iterator(stride_counting_iterator&& o) { *this = o; }
760+
761+
constexpr stride_counting_iterator& operator=(const stride_counting_iterator& o) {
762+
base_ = o.base_;
763+
// if memory backing count is owned by the object, copy values
764+
if (o.stride_count_ == &o.stride_count_default_) {
765+
assert(o.stride_displacement_ == &o.stride_displacement_default_);
766+
*stride_count_ = *o.stride_count_;
767+
*stride_displacement_ = *o.stride_displacement_;
768+
return *this;
769+
}
770+
// otherwise share the same externally-owned variables
771+
stride_count_ = o.stride_count_;
772+
stride_displacement_ = o.stride_displacement_;
773+
return *this;
774+
}
775+
constexpr stride_counting_iterator& operator=(stride_counting_iterator&& o) { return *this = o; }
776+
751777
friend constexpr It base(stride_counting_iterator const& it) { return It(it.base_); }
752778

753-
constexpr difference_type stride_count() const { return stride_count_; }
779+
constexpr StrideCountType stride_count() const { return *stride_count_; }
754780

755-
constexpr difference_type stride_displacement() const { return stride_displacement_; }
781+
constexpr StrideDisplacementType stride_displacement() const { return *stride_displacement_; }
756782

757783
constexpr decltype(auto) operator*() const { return *It(base_); }
758784

@@ -761,8 +787,8 @@ class stride_counting_iterator {
761787
constexpr stride_counting_iterator& operator++() {
762788
It tmp(base_);
763789
base_ = base(++tmp);
764-
++stride_count_;
765-
++stride_displacement_;
790+
++*stride_count_;
791+
++*stride_displacement_;
766792
return *this;
767793
}
768794

@@ -781,8 +807,8 @@ class stride_counting_iterator {
781807
{
782808
It tmp(base_);
783809
base_ = base(--tmp);
784-
++stride_count_;
785-
--stride_displacement_;
810+
++*stride_count_;
811+
--*stride_displacement_;
786812
return *this;
787813
}
788814

@@ -799,8 +825,8 @@ class stride_counting_iterator {
799825
{
800826
It tmp(base_);
801827
base_ = base(tmp += n);
802-
++stride_count_;
803-
++stride_displacement_;
828+
++*stride_count_;
829+
++*stride_displacement_;
804830
return *this;
805831
}
806832

@@ -809,8 +835,8 @@ class stride_counting_iterator {
809835
{
810836
It tmp(base_);
811837
base_ = base(tmp -= n);
812-
++stride_count_;
813-
--stride_displacement_;
838+
++*stride_count_;
839+
--*stride_displacement_;
814840
return *this;
815841
}
816842

@@ -873,8 +899,11 @@ class stride_counting_iterator {
873899

874900
private:
875901
decltype(base(std::declval<It>())) base_;
876-
difference_type stride_count_ = 0;
877-
difference_type stride_displacement_ = 0;
902+
StrideCountType stride_count_default_ = 0;
903+
StrideDisplacementType stride_displacement_default_ = 0;
904+
905+
StrideCountType* stride_count_ = &stride_count_default_;
906+
StrideDisplacementType* stride_displacement_ = &stride_displacement_default_;
878907
};
879908
template <class It>
880909
stride_counting_iterator(It) -> stride_counting_iterator<It>;

0 commit comments

Comments
 (0)