Skip to content

Commit

Permalink
view::generate always std::input_range
Browse files Browse the repository at this point in the history
  • Loading branch information
OleErikPeistorpet committed Jun 14, 2024
1 parent 4463663 commit 898745b
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 97 deletions.
68 changes: 68 additions & 0 deletions auxi/detail_tight_pair.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#pragma once

// Copyright 2020 Ole Erik Peistorpet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include "core_util.h"


namespace oel::_detail
{
template< typename T, typename U,
bool = std::is_empty_v<U> >
struct TightPair
{
T first;
U _sec;

OEL_ALWAYS_INLINE constexpr const U & second() const { return _sec; }
OEL_ALWAYS_INLINE constexpr U & second() { return _sec; }
};

// MSVC needs unique names to guard against name collision due to inheritance
template< typename T_Qai6Y, typename U_Qai6Y >
struct TightPair<T_Qai6Y, U_Qai6Y, true>
: U_Qai6Y
{
T_Qai6Y first;

TightPair() = default;
constexpr TightPair(T_Qai6Y f, U_Qai6Y s)
: U_Qai6Y{s}, first{std::move(f)}
{}

OEL_ALWAYS_INLINE constexpr const U_Qai6Y & second() const { return *this; }
OEL_ALWAYS_INLINE constexpr U_Qai6Y & second() { return *this; }
};


template< typename T, typename F,
bool = std::is_empty_v<F> >
struct TightPairMutableFn
{
T first;
F mutable _fn;

OEL_ALWAYS_INLINE constexpr F & func() const { return _fn; }
};

template< typename T_Qai6Y, typename F_Qai6Y >
struct TightPairMutableFn<T_Qai6Y, F_Qai6Y, true>
: F_Qai6Y
{
T_Qai6Y first;

TightPairMutableFn() = default;
constexpr TightPairMutableFn(T_Qai6Y fir, F_Qai6Y fn)
: F_Qai6Y{fn}, first{std::move(fir)}
{}

OEL_ALWAYS_INLINE constexpr F_Qai6Y & func() const
{
return const_cast<TightPairMutableFn &>(*this);
}
};
}
21 changes: 15 additions & 6 deletions unit_test/view_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,9 @@ using StdArrInt2 = std::array<int, 2>;
constexpr auto multBy2(StdArrInt2 a)
{
StdArrInt2 res{};
struct
{ constexpr auto operator()(int i) const { return 2 * i; }
} mult2{};
auto mult2 = [j = 2](int i) { return i * j; };
auto v = view::transform(a, mult2);

size_t i{};
for (auto val : v)
res[i++] = val;
Expand Down Expand Up @@ -253,6 +252,13 @@ struct Ints

TEST(viewTest, viewGenerate)
{
{
auto v = view::generate([] { return 7; }, 1);
for (auto i : v)
EXPECT_EQ(7, i);

static_assert(sizeof v.begin() <= sizeof(ptrdiff_t));
}
auto d = view::generate(Ints{1}, 2) | oel::to_dynarray();

ASSERT_EQ(2U, d.size());
Expand All @@ -261,6 +267,12 @@ TEST(viewTest, viewGenerate)

d.assign(oel::view::generate(Ints{}, 0));
EXPECT_TRUE(d.empty());

#if OEL_STD_RANGES
using G = decltype( view::generate(Ints{}, 2) );
static_assert(std::ranges::input_range<G>);
static_assert(std::ranges::sized_range<G>);
#endif
}

TEST(viewTest, viewMoveEndDifferentType)
Expand All @@ -284,9 +296,6 @@ TEST(viewTest, viewMoveMutableEmptyAndSize)
EXPECT_EQ(1U, v.size());
}

using IntGenIter = oel::iterator_t<decltype( view::generate(Ints{}, 0) )>;
static_assert(std::input_iterator<IntGenIter>);

TEST(viewTest, chainWithStd)
{
auto f = [](int i) { return -i; };
Expand Down
28 changes: 0 additions & 28 deletions util.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,34 +153,6 @@ namespace _detail
OEL_THROW(std::out_of_range(what), what);
}
};



template< typename T, typename U,
bool = std::is_empty_v<U> >
struct TightPair
{
T first;
U _sec;

OEL_ALWAYS_INLINE constexpr const U & second() const { return _sec; }
OEL_ALWAYS_INLINE constexpr U & second() { return _sec; }
};

template< typename Type_unique_name_for_MSVC, typename Empty_type_MSVC_unique_name >
struct TightPair<Type_unique_name_for_MSVC, Empty_type_MSVC_unique_name, true>
: Empty_type_MSVC_unique_name
{
Type_unique_name_for_MSVC first;

TightPair() = default;
constexpr TightPair(Type_unique_name_for_MSVC f, Empty_type_MSVC_unique_name s)
: Empty_type_MSVC_unique_name{s}, first{std::move(f)}
{}

OEL_ALWAYS_INLINE constexpr const Empty_type_MSVC_unique_name & second() const { return *this; }
OEL_ALWAYS_INLINE constexpr Empty_type_MSVC_unique_name & second() { return *this; }
};
}

} // namespace oel
41 changes: 30 additions & 11 deletions view/generate.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include "counted.h"
#include "subrange.h"
#include "../auxi/assignable.h"

/** @file
Expand All @@ -15,37 +15,56 @@
namespace oel
{

struct _defaultSentinel {};


template< typename Generator >
class generate_iterator
class _generateIterator
{
typename _detail::AssignableWrap<Generator>::Type mutable _g;
_detail::TightPairMutableFn< ptrdiff_t, typename _detail::AssignableWrap<Generator>::Type > _m;

public:
using iterator_category = std::input_iterator_tag;
using difference_type = ptrdiff_t;
using reference = decltype( std::declval<Generator &>()() );
using pointer = void;
using value_type = std::remove_cv_t< std::remove_reference_t<reference> >;
using difference_type = ptrdiff_t;

constexpr explicit generate_iterator(Generator g) : _g{std::move(g)} {}
constexpr _generateIterator(Generator g, difference_type count) : _m{count, std::move(g)} {}

constexpr reference operator*() const
{
return static_cast<Generator &>(_g)();
Generator & g = _m.func(); return g();
}

constexpr generate_iterator & operator++() OEL_ALWAYS_INLINE { return *this; }
constexpr void operator++(int) & OEL_ALWAYS_INLINE {}
constexpr _generateIterator & operator++() OEL_ALWAYS_INLINE { --_m.first; return *this; }

constexpr void operator++(int) & OEL_ALWAYS_INLINE { --_m.first; }

friend constexpr difference_type operator -
(_defaultSentinel, const _generateIterator & right) { return right._m.first; }
friend constexpr difference_type operator -
(const _generateIterator & left, _defaultSentinel) { return -left._m.first; }

friend constexpr bool operator==(const _generateIterator & left, _defaultSentinel) { return 0 == left._m.first; }

friend constexpr bool operator==(_defaultSentinel left, const _generateIterator & right) { return right == left; }

friend constexpr bool operator!=(const _generateIterator & left, _defaultSentinel) { return 0 != left._m.first; }

friend constexpr bool operator!=(_defaultSentinel, const _generateIterator & right) { return 0 != right._m.first; }
};


namespace view
{
//! Returns a view that generates `count` elements by calling the given generator function
/**
* Like `generate_n` in the Range-v3 library, but this is only for use within OE-Lib. */
inline constexpr auto generate =
[](auto generator, ptrdiff_t count) { return counted(generate_iterator{std::move(generator)}, count); };
* Almost same as `generate_n` in the Range-v3 library. */
inline constexpr auto generate = [](auto generator, ptrdiff_t count)
{
return subrange(_generateIterator{std::move(generator), count}, _defaultSentinel{});
};
}

} // oel
3 changes: 2 additions & 1 deletion view/subrange.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include "../util.h"
#include "../util.h" // for as_unsigned
#include "../auxi/detail_tight_pair.h"

/** @file
*/
Expand Down
Loading

0 comments on commit 898745b

Please sign in to comment.