forked from OctaForge/libostd
no reference/size_type for output ranges
This commit is contained in:
parent
1619dac782
commit
a743f7b755
|
@ -46,11 +46,10 @@ input range meet the requirements for an output range. These are called
|
|||
#include <ostd/range.hh>
|
||||
|
||||
struct my_range: ostd::input_range<my_range> {
|
||||
using range_category = ostd::input_range_tag;
|
||||
using value_type = T;
|
||||
using reference = T &;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using range_category = ostd::input_range_tag;
|
||||
using value_type = T;
|
||||
using reference = T &;
|
||||
using size_type = size_t;
|
||||
|
||||
my_range(my_range const &);
|
||||
my_range &operator=(my_range const &);
|
||||
|
@ -93,11 +92,10 @@ that none of the provided methods are `virtual`, so it's not safe to call
|
|||
them while expecting the overridden variants to be called.
|
||||
|
||||
~~~{.cc}
|
||||
using range_category = ostd::input_range_tag;
|
||||
using value_type = T;
|
||||
using reference = T &;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using range_category = ostd::input_range_tag;
|
||||
using value_type = T;
|
||||
using reference = T &;
|
||||
using size_type = size_t;
|
||||
~~~
|
||||
|
||||
Any input range is required to have a series of types that define its traits.
|
||||
|
@ -119,10 +117,7 @@ really is just a type that is returned by accesses to the range, as accesses
|
|||
are typically not meant to be copy the contents (but they totally can).
|
||||
|
||||
The `size_type` alias represents the type typically used for sizes of the
|
||||
range the object represents. It's typically `size_t`. Similarly, the
|
||||
`difference_type` alias is used for a distance within the range. Usually
|
||||
it's `ptrdiff_t`, but for example for I/O stream range types it can be the
|
||||
stream's offset type.
|
||||
range the object represents. It's typically `size_t`.
|
||||
|
||||
Now let's take a look at the methods.
|
||||
|
||||
|
@ -191,10 +186,7 @@ an output range:
|
|||
#include <ostd/range.hh>
|
||||
|
||||
struct my_range: ostd::output_range<my_range> {
|
||||
using value_type = T;
|
||||
using reference = T &;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = T;
|
||||
|
||||
my_range(my_range const &);
|
||||
my_range &operator=(my_range const &);
|
||||
|
@ -211,16 +203,14 @@ an output range:
|
|||
As you can see, they're much simpler than input ranges.
|
||||
|
||||
~~~{.cc}
|
||||
using value_type = T;
|
||||
using reference = T &;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = T;
|
||||
~~~
|
||||
|
||||
Why is there no `range_category` here? Well, it's already defined by the
|
||||
ostd::output\_range it derives (and has to derive) from. We already know that
|
||||
it will always be ostd::output\_range\_tag. Might as well avoid specifying it
|
||||
always.
|
||||
always. The size and reference types are not relevant for output ranges, so
|
||||
they're not here either.
|
||||
|
||||
Output ranges are always copyable, just like input ranges. There are no rules
|
||||
on state preservation.
|
||||
|
@ -581,14 +571,13 @@ It will satisfy a forward range but won't have a writable reference type.
|
|||
using reference = int;
|
||||
|
||||
// unused
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using size_type = size_t;
|
||||
|
||||
// only allow construction with specific args
|
||||
num_range() = delete;
|
||||
|
||||
// our interval constructor
|
||||
num_range(int beg, int end): p_a(beg), p_b(end) {}
|
||||
num_range(value_type beg, value_type end): p_a(beg), p_b(end) {}
|
||||
|
||||
bool empty() const {
|
||||
// we're empty once the beginning has reached the end
|
||||
|
@ -604,7 +593,7 @@ It will satisfy a forward range but won't have a writable reference type.
|
|||
}
|
||||
|
||||
private:
|
||||
int p_a, p_b;
|
||||
value_type p_a, p_b;
|
||||
};
|
||||
~~~
|
||||
|
||||
|
@ -630,12 +619,9 @@ into stdout, each on a new line.
|
|||
#include <ostd/io.hh>
|
||||
|
||||
struct strout_range: ostd::output_range<strout_range> {
|
||||
using value_type = ostd::string_range;
|
||||
using reference = ostd::string_range &;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = ostd::string_range;
|
||||
|
||||
void put(ostd::string_range v) {
|
||||
void put(value_type v) {
|
||||
ostd::writeln(v);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -278,8 +278,6 @@ namespace detail {
|
|||
/* lightweight output range for direct stdout */
|
||||
struct stdout_range: output_range<stdout_range> {
|
||||
using value_type = char;
|
||||
using reference = char &;
|
||||
using size_type = std::size_t;
|
||||
|
||||
stdout_range() {}
|
||||
void put(char c) {
|
||||
|
|
|
@ -167,7 +167,7 @@ namespace detail {
|
|||
template<typename R>
|
||||
constexpr bool test_range_category = range_category_test<R>::value;
|
||||
|
||||
template<typename R, bool>
|
||||
template<typename R, bool, bool>
|
||||
struct range_traits_base {
|
||||
template<typename>
|
||||
static constexpr bool is_element_swappable_with = false;
|
||||
|
@ -186,8 +186,8 @@ namespace detail {
|
|||
std::remove_reference_t<typename R::reference>
|
||||
>;
|
||||
|
||||
template<typename R>
|
||||
struct range_traits_base<R, true> {
|
||||
template<typename R, bool B>
|
||||
struct range_traits_base<R, true, B> {
|
||||
using range_category = typename R::range_category;
|
||||
using size_type = typename R::size_type;
|
||||
using value_type = typename R::value_type;
|
||||
|
@ -210,6 +210,19 @@ namespace detail {
|
|||
is_element_nothrow_swappable_with<R>;
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
struct range_traits_base<R, false, true> {
|
||||
using range_category = typename R::range_category;
|
||||
using value_type = typename R::value_type;
|
||||
|
||||
template<typename>
|
||||
static constexpr bool is_element_swappable_with = false;
|
||||
static constexpr bool is_element_swappable = false;
|
||||
template<typename R2>
|
||||
static constexpr bool is_element_nothrow_swappable_with = false;
|
||||
static constexpr bool is_element_nothrow_swappable = false;
|
||||
};
|
||||
|
||||
template<typename R, bool>
|
||||
struct range_traits_impl {
|
||||
template<typename>
|
||||
|
@ -223,7 +236,7 @@ namespace detail {
|
|||
template<typename R>
|
||||
struct range_traits_impl<R, true>: range_traits_base<
|
||||
R,
|
||||
std::is_convertible_v<typename R::range_category, input_range_tag> ||
|
||||
std::is_convertible_v<typename R::range_category, input_range_tag>,
|
||||
std::is_convertible_v<typename R::range_category, output_range_tag>
|
||||
> {};
|
||||
}
|
||||
|
@ -239,6 +252,10 @@ namespace detail {
|
|||
* * `value_type` - the type of the range's elements
|
||||
* * `reference` - the type returned from value accessors
|
||||
*
|
||||
* The `size_type` and `reference` types will only be available for
|
||||
* input-type ranges. Purely output ranges will only have the category
|
||||
* and value type.
|
||||
*
|
||||
* It will always contain the following members as well:
|
||||
*
|
||||
* ~~~{.cc}
|
||||
|
@ -250,8 +267,8 @@ namespace detail {
|
|||
* static constexpr bool is_element_nothrow_swappable = is_element_swappable_with<R, R2>;
|
||||
* ~~~
|
||||
*
|
||||
* These members will be false for non-range types. Otherwise, the first
|
||||
* member tests for the following:
|
||||
* These members will be false for non-range types as well as purely output
|
||||
* range types. Otherwise, the first member tests for the following:
|
||||
*
|
||||
* * Both ranges are an ostd::input_range_tag or better (not an output range).
|
||||
* * The `reference` member type of both ranges is an lvalue reference.
|
||||
|
@ -288,6 +305,8 @@ struct range_traits: detail::range_traits_impl<R, detail::test_range_category<R>
|
|||
* typename ostd::range_traits<R>::range_category
|
||||
* ~~~
|
||||
*
|
||||
* Works for all types of ranges.
|
||||
*
|
||||
* @see ostd::range_size_t, ostd::range_value_t, ostd::range_reference_t
|
||||
*/
|
||||
template<typename R>
|
||||
|
@ -301,6 +320,8 @@ using range_category_t = typename range_traits<R>::range_category;
|
|||
* typename ostd::range_traits<R>::size_type
|
||||
* ~~~
|
||||
*
|
||||
* Works only for input-type ranges.
|
||||
*
|
||||
* @see ostd::range_category_t, ostd::range_value_t, ostd::range_reference_t
|
||||
*/
|
||||
template<typename R>
|
||||
|
@ -314,6 +335,8 @@ using range_size_t = typename range_traits<R>::size_type;
|
|||
* typename ostd::range_traits<R>::value_type
|
||||
* ~~~
|
||||
*
|
||||
* Works for all types of ranges.
|
||||
*
|
||||
* @see ostd::range_category_t, ostd::range_size_t, ostd::range_reference_t
|
||||
*/
|
||||
template<typename R>
|
||||
|
@ -327,6 +350,8 @@ using range_value_t = typename range_traits<R>::value_type;
|
|||
* typename ostd::range_traits<R>::reference
|
||||
* ~~~
|
||||
*
|
||||
* Works only for input-type ranges.
|
||||
*
|
||||
* @see ostd::range_category_t, ostd::range_size_t, ostd::range_value_t
|
||||
*/
|
||||
template<typename R>
|
||||
|
@ -929,8 +954,6 @@ namespace detail {
|
|||
template<typename T>
|
||||
struct noop_output_range: output_range<noop_output_range<T>> {
|
||||
using value_type = T;
|
||||
using reference = T &;
|
||||
using size_type = std::size_t;
|
||||
|
||||
/** @brief Has no effect. */
|
||||
void put(T const &) {}
|
||||
|
@ -952,12 +975,10 @@ namespace detail {
|
|||
template<typename R>
|
||||
struct counting_output_range: output_range<counting_output_range<R>> {
|
||||
using value_type = range_value_t<R>;
|
||||
using reference = range_reference_t<R>;
|
||||
using size_type = range_size_t<R>;
|
||||
|
||||
private:
|
||||
R p_range;
|
||||
size_type p_written = 0;
|
||||
size_t p_written = 0;
|
||||
|
||||
public:
|
||||
counting_output_range() = delete;
|
||||
|
@ -974,7 +995,7 @@ namespace detail {
|
|||
++p_written;
|
||||
}
|
||||
|
||||
size_type get_written() const {
|
||||
size_t get_written() const {
|
||||
return p_written;
|
||||
}
|
||||
};
|
||||
|
@ -1529,8 +1550,6 @@ namespace detail {
|
|||
template<typename T>
|
||||
struct appender_range: output_range<appender_range<T>> {
|
||||
using value_type = typename T::value_type;
|
||||
using reference = typename T::reference;
|
||||
using size_type = typename T::size_type;
|
||||
|
||||
/** @brief Default constructs the container inside. */
|
||||
appender_range(): p_data() {}
|
||||
|
@ -1560,16 +1579,16 @@ struct appender_range: output_range<appender_range<T>> {
|
|||
bool empty() const { return p_data.empty(); }
|
||||
|
||||
/** @brief Reserves some capacity in the container. */
|
||||
void reserve(size_type cap) { p_data.reserve(cap); }
|
||||
void reserve(typename T::size_type cap) { p_data.reserve(cap); }
|
||||
|
||||
/** @brief Resizes the container. */
|
||||
void resize(size_type len) { p_data.resize(len); }
|
||||
void resize(typename T::size_type len) { p_data.resize(len); }
|
||||
|
||||
/** @brief Gets the container size. */
|
||||
size_type size() const { return p_data.size(); }
|
||||
typename T::size_type size() const { return p_data.size(); }
|
||||
|
||||
/** @brief Gets the container capacity. */
|
||||
size_type capacity() const { return p_data.capacity(); }
|
||||
typename T::size_type capacity() const { return p_data.capacity(); }
|
||||
|
||||
/** @brief Appends a copy of a value to the end of the container. */
|
||||
void put(typename T::const_reference v) {
|
||||
|
|
Loading…
Reference in a new issue