forked from OctaForge/libostd
clean up join/zip ranges with c++17 fold expressions
This commit is contained in:
parent
d06637eac6
commit
2e773b3849
14
README.md
14
README.md
|
@ -8,10 +8,6 @@ make the language easier and more convenient to use.
|
||||||
|
|
||||||
Documentation for OctaSTD can be found at https://wiki.octaforge.org/docs/octastd.
|
Documentation for OctaSTD can be found at https://wiki.octaforge.org/docs/octastd.
|
||||||
|
|
||||||
It's not necessary that your compiler fully supports C++17, only C++14
|
|
||||||
language is used, but new C++17 containers have to be present, such as
|
|
||||||
`string_view` and `optional`.
|
|
||||||
|
|
||||||
## Supported compilers
|
## Supported compilers
|
||||||
|
|
||||||
Compiler | Version
|
Compiler | Version
|
||||||
|
@ -35,12 +31,10 @@ use GCC/Clang, if you need Visual Studio, LLVM integration exists.
|
||||||
Sadly, it's not possible to properly integrate `std::string` and `std::hash`
|
Sadly, it's not possible to properly integrate `std::string` and `std::hash`
|
||||||
with OctaSTD ranges without utilizing `std::string_view`. Also, C++17 provides
|
with OctaSTD ranges without utilizing `std::string_view`. Also, C++17 provides
|
||||||
library features that OctaSTD would have to implement otherwise, which would
|
library features that OctaSTD would have to implement otherwise, which would
|
||||||
lead to potentially incompatible APIs. However, OctaSTD does not make wide
|
lead to potentially incompatible APIs. C++17 also provides some nice language
|
||||||
use of C++17 language features, limiting itself mostly to library features
|
features (such as `if constexpr` and fold epxressions) which allow a lot of
|
||||||
which have been present for more or less a pretty long time (in experimental
|
code to be written in a cleaner way. However, it is made sure that no features
|
||||||
namespace for example) which should avoid buggy behavior. There is still the
|
beyond the minimum supported compiler are necessary to use the library.
|
||||||
problem of requiring a very recent toolchain, but this situation should solve
|
|
||||||
itself in near future.
|
|
||||||
|
|
||||||
## Supported operating systems
|
## Supported operating systems
|
||||||
|
|
||||||
|
|
122
ostd/range.hh
122
ostd/range.hh
|
@ -1485,44 +1485,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<size_t I, size_t N>
|
|
||||||
struct JoinRangeEmpty {
|
|
||||||
template<typename T>
|
|
||||||
static bool empty(T const &tup) {
|
|
||||||
if (!std::get<I>(tup).empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return JoinRangeEmpty<I + 1, N>::empty(tup);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<size_t N>
|
|
||||||
struct JoinRangeEmpty<N, N> {
|
|
||||||
template<typename T>
|
|
||||||
static bool empty(T const &) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<size_t I, size_t N>
|
|
||||||
struct TupleRangeEqual {
|
|
||||||
template<typename T>
|
|
||||||
static bool equal(T const &tup1, T const &tup2) {
|
|
||||||
if (!std::get<I>(tup1).equals_front(std::get<I>(tup2))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return TupleRangeEqual<I + 1, N>::equal(tup1, tup2);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<size_t N>
|
|
||||||
struct TupleRangeEqual<N, N> {
|
|
||||||
template<typename T>
|
|
||||||
static bool equal(T const &, T const &) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<size_t I, size_t N>
|
template<size_t I, size_t N>
|
||||||
struct JoinRangePop {
|
struct JoinRangePop {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -1587,13 +1549,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
return detail::JoinRangeEmpty<0, sizeof...(R)>::empty(p_ranges);
|
return std::apply([](auto const &...args) {
|
||||||
|
return (... && args.empty());
|
||||||
|
}, p_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool equals_front(JoinRange const &r) const {
|
bool equals_front(JoinRange const &r) const {
|
||||||
return detail::TupleRangeEqual<0, sizeof...(R)>::equal(
|
return std::apply([&r](auto const &...r1) {
|
||||||
p_ranges, r.p_ranges
|
return std::apply([&](auto const &...r2) {
|
||||||
);
|
return (... && r1.equals_front(r2));
|
||||||
|
}, r);
|
||||||
|
}, p_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() {
|
bool pop_front() {
|
||||||
|
@ -1620,58 +1586,6 @@ namespace detail {
|
||||||
|
|
||||||
template<typename ...T>
|
template<typename ...T>
|
||||||
using ZipValue = typename detail::ZipValueType<T...>::Type;
|
using ZipValue = typename detail::ZipValueType<T...>::Type;
|
||||||
|
|
||||||
template<size_t I, size_t N>
|
|
||||||
struct ZipRangeEmpty {
|
|
||||||
template<typename T>
|
|
||||||
static bool empty(T const &tup) {
|
|
||||||
if (std::get<I>(tup).empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return ZipRangeEmpty<I + 1, N>::empty(tup);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<size_t N>
|
|
||||||
struct ZipRangeEmpty<N, N> {
|
|
||||||
template<typename T>
|
|
||||||
static bool empty(T const &) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<size_t I, size_t N>
|
|
||||||
struct ZipRangePop {
|
|
||||||
template<typename T>
|
|
||||||
static bool pop(T &tup) {
|
|
||||||
return (
|
|
||||||
std::get<I>(tup).pop_front() && ZipRangePop<I + 1, N>::pop(tup)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<size_t N>
|
|
||||||
struct ZipRangePop<N, N> {
|
|
||||||
template<typename T>
|
|
||||||
static bool pop(T &) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ...T>
|
|
||||||
struct ZipRangeFront {
|
|
||||||
template<typename U, size_t ...I>
|
|
||||||
static ZipValue<T...> tup_get(U const &tup, std::index_sequence<I...>) {
|
|
||||||
return ZipValue<T...>(std::get<I>(tup).front()...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
static ZipValue<T...> front(U const &tup) {
|
|
||||||
return ZipRangeFront<T...>::tup_get(
|
|
||||||
tup, std::make_index_sequence<sizeof...(T)>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...R>
|
template<typename ...R>
|
||||||
|
@ -1701,21 +1615,29 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
return detail::ZipRangeEmpty<0, sizeof...(R)>::empty(p_ranges);
|
return std::apply([](auto const &...args) {
|
||||||
|
return (... || args.empty());
|
||||||
|
}, p_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool equals_front(ZipRange const &r) const {
|
bool equals_front(ZipRange const &r) const {
|
||||||
return detail::TupleRangeEqual<0, sizeof...(R)>::equal(
|
return std::apply([&r](auto const &...r1) {
|
||||||
p_ranges, r.p_ranges
|
return std::apply([&](auto const &...r2) {
|
||||||
);
|
return (... && r1.equals_front(r2));
|
||||||
|
}, r);
|
||||||
|
}, p_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() {
|
bool pop_front() {
|
||||||
return detail::ZipRangePop<0, sizeof...(R)>::pop(p_ranges);
|
return std::apply([](auto &...args) {
|
||||||
|
return (... && args.pop_front());
|
||||||
|
}, p_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::ZipValue<RangeReference<R>...> front() const {
|
detail::ZipValue<RangeReference<R>...> front() const {
|
||||||
return detail::ZipRangeFront<RangeReference<R>...>::front(p_ranges);
|
return std::apply([](auto &&...args) {
|
||||||
|
return detail::ZipValue<RangeReference<R>...>{args.front()...};
|
||||||
|
}, p_ranges);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue