Skip to content

Commit

Permalink
Merge pull request #829 from CaseyCarter/cartesian_fixes
Browse files Browse the repository at this point in the history
Cartesian fixes
  • Loading branch information
CaseyCarter authored and ericniebler committed May 15, 2018
2 parents 77a5469 + 6bf1619 commit 5776e6e
Show file tree
Hide file tree
Showing 18 changed files with 210 additions and 138 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ The code is known to work on the following compilers:
Release Notes:
--------------

* **0.3.6** May 15, 2018
- NEW: `view::exclusive_scan` (thanks to GitHub user @mitsutaka-takeda).
- All views get non-`const` overloads of `.empty()` and `.size()` (see [ericniebler/stl2\#793](https://github.com/ericniebler/stl2/issues/793)).
- Upgrade Conan support for conan 1.0.
- `subspan` interface tweaks.
- Fix bug in `view::split` (see [this stackoverflow question](https://stackoverflow.com/questions/49015671)).
- Fix bug in `view::stride` (see [ericniebler/stl2\#805](https://github.com/ericniebler/stl2/issues/805)).
- Fix `const`-correctness problem in `view::chunk` (see [this stackoverflow question](https://stackoverflow.com/questions/49210190)).
- Replace uses of `ranges::result_of` with `ranges::invoke_result`.
- Fix potential buffer overrun of `view::drop` over RandomAccessRanges.
- Lots of `view::cartesian_product` fixes (see [ericniebler/stl2\#820](https://github.com/ericniebler/stl2/issues/820), [ericniebler/stl2\#823](https://github.com/ericniebler/stl2/issues/823)).
- Work around gcc-8 regression regarding `volatile` `std::initializer_list`s (see [ericniebler/stl2\#826](https://github.com/ericniebler/stl2/issues/826)).
- Fix `const`-correctness problem of `view::take`.
* **0.3.5** February 17, 2018
- Rvalues may satisfy `Writable` (see [ericniebler/stl2\#387](https://github.com/ericniebler/stl2/issues/387)).
- `view_interface` gets a bounds-checking `at` method.
Expand Down
2 changes: 1 addition & 1 deletion Version.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
# This makefile will generate a new version.hpp, *AMEND THE MOST RECENT COMMIT*, and git-tag the commit.
set(RANGE_V3_MAJOR 0)
set(RANGE_V3_MINOR 3)
set(RANGE_V3_PATCHLEVEL 5)
set(RANGE_V3_PATCHLEVEL 6)
44 changes: 27 additions & 17 deletions include/range/v3/detail/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ namespace ranges
#define RANGES_CXX_DEDUCTION_GUIDES_11 0L
#define RANGES_CXX_DEDUCTION_GUIDES_14 0L
#define RANGES_CXX_DEDUCTION_GUIDES_17 201606L
#define RANGES_CXX_IF_CONSTEXPR_11 0L
#define RANGES_CXX_IF_CONSTEXPR_14 0L
#define RANGES_CXX_IF_CONSTEXPR_17 201606L

#if defined(_MSC_VER) && !defined(__clang__)
#if _MSC_VER >= 1900
Expand Down Expand Up @@ -187,9 +190,9 @@ namespace ranges

#define RANGES_DIAGNOSTIC_PUSH __pragma(warning(push))
#define RANGES_DIAGNOSTIC_POP __pragma(warning(pop))
#define RANGES_DIAGNOSTIC_IGNORE(X) __pragma(warning(disable:X))
#define RANGES_DIAGNOSTIC_IGNORE_PRAGMAS __pragma(warning(disable:4068))
#define RANGES_DIAGNOSTIC_IGNORE(X) RANGES_DIAGNOSTIC_IGNORE_PRAGMAS __pragma(warning(disable:X))
#define RANGES_DIAGNOSTIC_IGNORE_SHADOWING RANGES_DIAGNOSTIC_IGNORE(4456)
#define RANGES_DIAGNOSTIC_IGNORE_PRAGMAS RANGES_DIAGNOSTIC_IGNORE(4068)
#define RANGES_DIAGNOSTIC_IGNORE_INDENTATION
#define RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_INTERNAL
#define RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS RANGES_DIAGNOSTIC_IGNORE(4099)
Expand All @@ -203,44 +206,36 @@ namespace ranges
#define RANGES_DIAGNOSTIC_IGNORE_MISSING_BRACES
#define RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_FUNC_TEMPLATE
#define RANGES_DIAGNOSTIC_IGNORE_INCONSISTENT_OVERRIDE
#define RANGES_DIAGNOSTIC_IGNORE_RANGE_LOOP_ANALYSIS

#else // ^^^ defined(_MSC_VER) ^^^ / vvv !defined(_MSC_VER) vvv
// Generic configuration using SD-6 feature test macros with fallback to __cplusplus
#if defined(__GNUC__) || defined(__clang__)
#define RANGES_PRAGMA(X) _Pragma(#X)
#define RANGES_DIAGNOSTIC_PUSH RANGES_PRAGMA(GCC diagnostic push)
#define RANGES_DIAGNOSTIC_POP RANGES_PRAGMA(GCC diagnostic pop)
#define RANGES_DIAGNOSTIC_IGNORE(X) RANGES_PRAGMA(GCC diagnostic ignored X)
#define RANGES_DIAGNOSTIC_IGNORE_PRAGMAS RANGES_PRAGMA(GCC diagnostic ignored "-Wpragmas")
#define RANGES_DIAGNOSTIC_IGNORE(X) RANGES_DIAGNOSTIC_IGNORE_PRAGMAS RANGES_PRAGMA(GCC diagnostic ignored "-Wunknown-pragmas") RANGES_PRAGMA(GCC diagnostic ignored X)
#define RANGES_DIAGNOSTIC_IGNORE_SHADOWING RANGES_DIAGNOSTIC_IGNORE("-Wshadow")
#define RANGES_DIAGNOSTIC_IGNORE_PRAGMAS RANGES_DIAGNOSTIC_IGNORE("-Wunknown-pragmas") RANGES_DIAGNOSTIC_IGNORE("-Wpragmas")
#define RANGES_DIAGNOSTIC_IGNORE_INDENTATION RANGES_DIAGNOSTIC_IGNORE("-Wmisleading-indentation")
#define RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_INTERNAL RANGES_DIAGNOSTIC_IGNORE("-Wundefined-internal")
#define RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS RANGES_DIAGNOSTIC_IGNORE("-Wmismatched-tags")
#define RANGES_DIAGNOSTIC_IGNORE_SIGN_CONVERSION RANGES_DIAGNOSTIC_IGNORE("-Wsign-conversion")
#define RANGES_DIAGNOSTIC_IGNORE_FLOAT_EQUAL RANGES_DIAGNOSTIC_IGNORE("-Wfloat-equal")
#define RANGES_DIAGNOSTIC_IGNORE_MISSING_BRACES RANGES_DIAGNOSTIC_IGNORE("-Wmissing-braces")
#ifdef __clang__
#define RANGES_DIAGNOSTIC_IGNORE_GLOBAL_CONSTRUCTORS RANGES_DIAGNOSTIC_IGNORE("-Wglobal-constructors")
#define RANGES_DIAGNOSTIC_IGNORE_UNNEEDED_INTERNAL RANGES_DIAGNOSTIC_IGNORE("-Wunneeded-internal-declaration")
#define RANGES_DIAGNOSTIC_IGNORE_UNNEEDED_MEMBER RANGES_DIAGNOSTIC_IGNORE("-Wunneeded-member-function")
#define RANGES_DIAGNOSTIC_IGNORE_ZERO_LENGTH_ARRAY RANGES_DIAGNOSTIC_IGNORE("-Wzero-length-array")
#define RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT
#define RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT RANGES_DIAGNOSTIC_IGNORE("-Wc++1z-compat")
#define RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_FUNC_TEMPLATE RANGES_DIAGNOSTIC_IGNORE("-Wundefined-func-template")
#define RANGES_DIAGNOSTIC_IGNORE_INCONSISTENT_OVERRIDE RANGES_DIAGNOSTIC_IGNORE("-Winconsistent-missing-override")
#else
#define RANGES_DIAGNOSTIC_IGNORE_GLOBAL_CONSTRUCTORS
#define RANGES_DIAGNOSTIC_IGNORE_UNNEEDED_INTERNAL
#define RANGES_DIAGNOSTIC_IGNORE_UNNEEDED_MEMBER
#define RANGES_DIAGNOSTIC_IGNORE_ZERO_LENGTH_ARRAY
#define RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT RANGES_DIAGNOSTIC_IGNORE("-Wc++1z-compat")
#define RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_FUNC_TEMPLATE
#define RANGES_DIAGNOSTIC_IGNORE_INCONSISTENT_OVERRIDE
#endif
#define RANGES_DIAGNOSTIC_IGNORE_RANGE_LOOP_ANALYSIS RANGES_DIAGNOSTIC_IGNORE("-Wrange-loop-analysis")
#else
#define RANGES_DIAGNOSTIC_PUSH
#define RANGES_DIAGNOSTIC_POP
#define RANGES_DIAGNOSTIC_IGNORE_SHADOWING
#define RANGES_DIAGNOSTIC_IGNORE_PRAGMAS
#define RANGES_DIAGNOSTIC_IGNORE_SHADOWING
#define RANGES_DIAGNOSTIC_IGNORE_INDENTATION
#define RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_INTERNAL
#define RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
Expand Down Expand Up @@ -438,7 +433,6 @@ namespace ranges
#ifdef RANGES_FEWER_WARNINGS
#define RANGES_DISABLE_WARNINGS \
RANGES_DIAGNOSTIC_PUSH \
RANGES_DIAGNOSTIC_IGNORE_PRAGMAS \
RANGES_DIAGNOSTIC_IGNORE_SHADOWING \
RANGES_DIAGNOSTIC_IGNORE_UNDEFINED_INTERNAL \
RANGES_DIAGNOSTIC_IGNORE_INDENTATION \
Expand All @@ -461,6 +455,22 @@ namespace ranges
#define RANGES_INTENDED_MODULAR_ARITHMETIC
#endif

#ifndef RANGES_CXX_IF_CONSTEXPR
#ifdef __cpp_if_constexpr
#define RANGES_CXX_IF_CONSTEXPR __cpp_if_constexpr
#else
#define RANGES_CXX_IF_CONSTEXPR RANGES_CXX_FEATURE(IF_CONSTEXPR)
#endif
#endif // RANGES_CXX_IF_CONSTEXPR

#ifndef RANGES_CONSTEXPR_IF
#if RANGES_CXX_IF_CONSTEXPR >= RANGES_CXX_IF_CONSTEXPR_17
#define RANGES_CONSTEXPR_IF constexpr
#else
#define RANGES_CONSTEXPR_IF
#endif
#endif // RANGES_CONSTEXPR_IF

namespace ranges {
inline namespace v3 {
namespace detail {
Expand Down
1 change: 0 additions & 1 deletion include/range/v3/detail/variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,6 @@ namespace ranges
}

RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_PRAGMAS
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS

namespace std
Expand Down
1 change: 0 additions & 1 deletion include/range/v3/iterator_range.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ namespace ranges

// The standard is inconsistent about whether these are classes or structs
RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_PRAGMAS
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS

/// \cond
Expand Down
1 change: 0 additions & 1 deletion include/range/v3/range_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
/// Concept-checking classes and utilities

RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_PRAGMAS
RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT

namespace ranges
Expand Down
1 change: 0 additions & 1 deletion include/range/v3/utility/common_tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,6 @@ namespace ranges
}

RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_PRAGMAS
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS

namespace std
Expand Down
1 change: 0 additions & 1 deletion include/range/v3/utility/compressed_pair.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ namespace ranges
}

RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_PRAGMAS
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS
namespace std
{
Expand Down
1 change: 0 additions & 1 deletion include/range/v3/utility/invoke.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#include <range/v3/utility/static_const.hpp>

RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_PRAGMAS
RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT

namespace ranges
Expand Down
1 change: 0 additions & 1 deletion include/range/v3/utility/random.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@
#endif

RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_PRAGMAS
RANGES_DIAGNOSTIC_IGNORE_CXX17_COMPAT

namespace ranges
Expand Down
1 change: 0 additions & 1 deletion include/range/v3/utility/tagged_pair.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ namespace ranges
/**/

RANGES_DIAGNOSTIC_PUSH
RANGES_DIAGNOSTIC_IGNORE_PRAGMAS
RANGES_DIAGNOSTIC_IGNORE_MISMATCHED_TAGS

namespace std
Expand Down
2 changes: 1 addition & 1 deletion include/range/v3/version.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#define RANGE_V3_MAJOR 0
#define RANGE_V3_MINOR 3
#define RANGE_V3_PATCHLEVEL 5
#define RANGE_V3_PATCHLEVEL 6

#define RANGE_V3_VERSION (RANGE_V3_MAJOR * 10000 \
+ RANGE_V3_MINOR * 100 \
Expand Down
110 changes: 50 additions & 60 deletions include/range/v3/view/cartesian_product.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ namespace ranges
{
template<typename T>
using constify_if = meta::const_if_c<IsConst, T>;
using pos_t = std::tuple<iterator_t<constify_if<Views>>...>;

constify_if<cartesian_product_view> *view_;
pos_t its_;
std::tuple<iterator_t<constify_if<Views>>...> its_;

void next_(meta::size_t<0>)
{
Expand Down Expand Up @@ -146,115 +146,105 @@ namespace ranges
}
--i;
}
bool equal_(cursor const &, meta::size_t<sizeof...(Views)>) const
bool equal_(cursor const &, meta::size_t<0>) const
{
return true;
}
template<std::size_t N>
bool equal_(cursor const &that, meta::size_t<N>) const
{
return std::get<N>(its_) == std::get<N>(that.its_) &&
equal_(that, meta::size_t<N + 1>{});
return std::get<N - 1>(its_) == std::get<N - 1>(that.its_) &&
equal_(that, meta::size_t<N - 1>{});
}
struct dist_info {
std::ptrdiff_t distance;
std::ptrdiff_t size_product;

dist_info(std::ptrdiff_t d = 0, std::ptrdiff_t s = 1)
: distance{d}, size_product{s}
{}
};
std::ptrdiff_t distance_(
cursor const &, meta::size_t<0>, dist_info) const
std::ptrdiff_t distance_(cursor const &, meta::size_t<0>) const
{
CONCEPT_ASSERT(sizeof...(Views) == 0);
return 0;
}
std::ptrdiff_t distance_(
cursor const &that, meta::size_t<1>, dist_info const inf) const
std::ptrdiff_t distance_(cursor const &that, meta::size_t<1>) const
{
auto const my_distance = std::get<0>(that.its_) - std::get<0>(its_);
return static_cast<std::ptrdiff_t>(my_distance * inf.size_product + inf.distance);
return static_cast<std::ptrdiff_t>(
std::get<0>(that.its_) - std::get<0>(its_));
}
template<std::size_t N>
std::ptrdiff_t distance_(
cursor const &that, meta::size_t<N>, dist_info const inf) const
std::ptrdiff_t distance_(cursor const &that, meta::size_t<N>) const
{
auto const my_size = ranges::size(std::get<N - 1>(view_->views_));
auto const my_distance = std::get<N - 1>(that.its_) - std::get<N - 1>(its_);
return distance_(that, meta::size_t<N - 1>{}, dist_info{
static_cast<std::ptrdiff_t>(my_distance * inf.size_product + inf.distance),
static_cast<std::ptrdiff_t>(my_size) * inf.size_product
});
auto d = distance_(that, meta::size_t<N - 1>{});
d *= static_cast<std::ptrdiff_t>(
ranges::distance(std::get<N - 2>(view_->views_)));
d += static_cast<std::ptrdiff_t>(
std::get<N - 1>(that.its_) - std::get<N - 1>(its_));
return d;
}
void advance_(meta::size_t<0>, dist_info const inf)
void advance_(meta::size_t<0>, std::ptrdiff_t n)
{
RANGES_EXPECT(inf.distance == 0);
RANGES_EXPECT(n == 0);
}
template<std::size_t N>
void advance_(meta::size_t<N>, dist_info const inf)
void advance_(meta::size_t<N>, std::ptrdiff_t n)
{
if(n == 0) return;

auto &i = std::get<N - 1>(its_);
auto const my_size = ranges::size(std::get<N - 1>(view_->views_));
auto const my_size = static_cast<std::ptrdiff_t>(
ranges::size(std::get<N - 1>(view_->views_)));
auto const first = ranges::begin(std::get<N - 1>(view_->views_));

auto const idx = i - first;
auto d = inf.distance;
if(static_cast<std::ptrdiff_t>(my_size) - idx < d || d < -idx)
RANGES_EXPECT(0 <= idx && idx < my_size);
RANGES_EXPECT(n < PTRDIFF_MAX - idx);
n += idx;

if RANGES_CONSTEXPR_IF(N != 1)
{
auto const new_size = inf.size_product * static_cast<std::ptrdiff_t>(my_size);
auto div = d / new_size;
d %= new_size;
if(static_cast<std::ptrdiff_t>(my_size) - idx < d)
{
i = first;
d -= static_cast<std::ptrdiff_t>(my_size) - idx;
++div;
RANGES_EXPECT(0 <= d && d < static_cast<std::ptrdiff_t>(my_size));
}
else if(d < -idx)
{
i = first + static_cast<std::ptrdiff_t>(my_size);
d += idx;
--div;
RANGES_EXPECT(0 > d && -d <= static_cast<std::ptrdiff_t>(my_size));
}
advance_(meta::size_t<N - 1>{}, { div, new_size });
auto const borrow = n < 0;
advance_(meta::size_t<N - 1>{}, n / my_size - borrow);
n %= my_size;
if(borrow)
n += my_size;
}
i += d;
RANGES_EXPECT(0 <= n);
RANGES_EXPECT(n < my_size || (N == 1 && n == my_size));
i = first + n;
}
void check_at_end_(meta::size_t<0>, bool = false)
{}
void check_at_end_(meta::size_t<1>, bool at_end = false)
{
if(at_end)
{
ranges::advance(std::get<0>(its_), ranges::end(std::get<0>(view_->views_)));
}
}
template<std::size_t N>
void check_at_end_(meta::size_t<N>, bool at_end = false)
{
return check_at_end_(meta::size_t<N - 1>{}, at_end ||
std::get<N - 1>(its_) == ranges::end(std::get<N - 1>(view_->views_)));
if(!at_end)
at_end = std::get<N - 1>(its_) == ranges::end(std::get<N - 1>(view_->views_));
return check_at_end_(meta::size_t<N - 1>{}, at_end);
}
cursor(end_tag, constify_if<cartesian_product_view> &view, std::true_type) // Bounded
: cursor(begin_tag{}, view)
{
CONCEPT_ASSERT(BoundedView<meta::at_c<meta::list<Views...>, 0>>());
std::get<0>(its_) = ranges::end(std::get<0>(view.views_));
}
cursor(end_tag, constify_if<cartesian_product_view> &view, std::false_type) // !Bounded
: cursor(begin_tag{}, view)
{
// Only called when the 0th view type is !Bounded && RandomAccess && Sized
using View0 = meta::at_c<meta::list<Views...>, 0>;
CONCEPT_ASSERT(!BoundedView<View0>() && RandomAccessRange<View0>() &&
SizedRange<View0>());
std::get<0>(its_) += ranges::distance(std::get<0>(view.views_));
}
public:
using value_type = std::tuple<range_value_type_t<Views>...>;

cursor() = default;
explicit cursor(begin_tag, constify_if<cartesian_product_view> &view)
: view_(&view)
, its_(tuple_transform(view.views_, ranges::begin))
{
// If any of the constituent views is empty, the cartesian_product is empty
// and this "begin" iterator needs to become an "end" iterator.
check_at_end_(meta::size_t<sizeof...(Views)>{});
}
explicit cursor(end_tag, constify_if<cartesian_product_view> &view)
Expand All @@ -274,7 +264,7 @@ namespace ranges
}
bool equal(cursor const &that) const
{
return equal_(that, meta::size_t<0>{});
return equal_(that, meta::size_t<sizeof...(Views)>{});
}
CONCEPT_REQUIRES(CanBidi<IsConst>())
void prev()
Expand All @@ -284,12 +274,12 @@ namespace ranges
CONCEPT_REQUIRES(CanDistance<IsConst>())
std::ptrdiff_t distance_to(cursor const &that) const
{
return distance_(that, meta::size_t<sizeof...(Views)>{}, {});
return distance_(that, meta::size_t<sizeof...(Views)>{});
}
CONCEPT_REQUIRES(CanRandom<IsConst>())
void advance(std::ptrdiff_t n)
{
return advance_(meta::size_t<sizeof...(Views)>{}, { n });
advance_(meta::size_t<sizeof...(Views)>{}, n);
}
};
CONCEPT_REQUIRES(CanConst())
Expand Down
Loading

0 comments on commit 5776e6e

Please sign in to comment.