|
|
@@ -7,20 +7,15 @@
|
|
|
#include <vector>
|
|
|
|
|
|
#include "detail/ifd_pointer.hpp"
|
|
|
+#include <iterator/facade.h>
|
|
|
|
|
|
namespace stream {
|
|
|
- template <typename T> class iterator {
|
|
|
- public:
|
|
|
- using value_type = typename std::remove_reference<T>::type;
|
|
|
- using reference = value_type &;
|
|
|
- using pointer = value_type *;
|
|
|
- using difference_type = std::ptrdiff_t;
|
|
|
- using iterator_category = std::forward_iterator_tag;
|
|
|
-
|
|
|
+ template <typename T>
|
|
|
+ class iterator : public ::iterator::facade<iterator<T>> {
|
|
|
private:
|
|
|
- T (*dereference)(void *){nullptr};
|
|
|
- bool (*compare)(void *, void *){nullptr};
|
|
|
- void (*advance)(void *){nullptr};
|
|
|
+ T (*dereference_)(void *){nullptr};
|
|
|
+ bool (*equal_to_)(void *, void *){nullptr};
|
|
|
+ void (*increment_)(void *){nullptr};
|
|
|
char const * type_{nullptr};
|
|
|
detail::ifd_pointer impl_{};
|
|
|
|
|
|
@@ -29,193 +24,166 @@ namespace stream {
|
|
|
|
|
|
template <typename Iter>
|
|
|
iterator(Iter impl)
|
|
|
- : dereference(&iterator::dereference_<Iter>),
|
|
|
- compare(&iterator::compare_<Iter>),
|
|
|
- advance(&iterator::advance_<Iter>), type_(typeid(Iter).name()),
|
|
|
- impl_(std::forward<Iter>(impl)) {}
|
|
|
-
|
|
|
- T operator*() const { return dereference(impl_.get()); }
|
|
|
- iterator & operator++() {
|
|
|
- advance(impl_.get());
|
|
|
- return *this;
|
|
|
+ : dereference_([](void * p) -> T { return **((Iter *)p); }),
|
|
|
+ equal_to_(
|
|
|
+ [](void * l, void * r) { return *((Iter *)l) == *((Iter *)r); }),
|
|
|
+ increment_([](void * p) { ++(*(Iter *)(p)); }),
|
|
|
+ type_(typeid(Iter).name()), impl_(std::forward<Iter>(impl)) {}
|
|
|
+
|
|
|
+ T dereference() const { return dereference_(impl_.get()); }
|
|
|
+ void increment() { increment_(impl_.get()); }
|
|
|
+ bool equal_to(iterator other) const {
|
|
|
+ return equal_to_(impl_.get(), other.impl_.get());
|
|
|
}
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+MAKE_ITERATOR_FACADE_TYPEDEFS_T(::stream::iterator);
|
|
|
+
|
|
|
+namespace stream::detail {
|
|
|
+ template <typename T, typename = void> class stream_base_pointer_impl {};
|
|
|
|
|
|
- bool operator==(iterator const & other) const {
|
|
|
- if (strcmp(type_, other.type_)) { return false; }
|
|
|
- return compare(impl_.get(), other.impl_.get());
|
|
|
+ template <typename T>
|
|
|
+ class stream_base_pointer_impl<
|
|
|
+ T, std::enable_if_t<traits::is_dereferencable_v<T>>> {
|
|
|
+ private:
|
|
|
+ using self_t = stream_base<T>;
|
|
|
+ using pointer = typename std::remove_reference<T>::type;
|
|
|
+ using element_type = typename std::pointer_traits<pointer>::element_type;
|
|
|
+
|
|
|
+ public:
|
|
|
+ auto deref() const & -> stream_base<element_type &> {
|
|
|
+ return static_cast<self_t const *>(this)->map(
|
|
|
+ [](T const & p) -> element_type & { return *p; });
|
|
|
}
|
|
|
|
|
|
- bool operator!=(iterator const & other) const {
|
|
|
- if (strcmp(type_, other.type_)) { return false; }
|
|
|
- return !compare(impl_.get(), other.impl_.get());
|
|
|
+ auto deref() && -> stream_base<element_type &> {
|
|
|
+ return static_cast<self_t &&>(*this).map(
|
|
|
+ [](T const & p) -> element_type & { return *p; });
|
|
|
}
|
|
|
+ };
|
|
|
|
|
|
+ template <typename T> class stream_base : public stream_base_pointer_impl<T> {
|
|
|
private:
|
|
|
- friend void swap(iterator & lhs, iterator & rhs) {
|
|
|
- using std::swap;
|
|
|
- swap(lhs.dereference, rhs.dereference);
|
|
|
- swap(lhs.compare, rhs.compare);
|
|
|
- swap(lhs.advance, rhs.advance);
|
|
|
- swap(lhs.type_, rhs.type_);
|
|
|
- swap(lhs.impl_, rhs.impl_);
|
|
|
+ using value_type = typename std::decay<T>::type;
|
|
|
+
|
|
|
+ public:
|
|
|
+ template <typename Stream> stream_base(std::shared_ptr<Stream> && impl) {
|
|
|
+ do_begin = [](std::shared_ptr<void> p) -> iterator<T> {
|
|
|
+ return std::static_pointer_cast<Stream>(p)->begin();
|
|
|
+ };
|
|
|
+ do_end = [](std::shared_ptr<void> p) -> iterator<T> {
|
|
|
+ return std::static_pointer_cast<Stream>(p)->end();
|
|
|
+ };
|
|
|
+ impl_ = std::static_pointer_cast<void>(impl);
|
|
|
}
|
|
|
|
|
|
- template <typename It> static T dereference_(void * p) {
|
|
|
- return **((It *)p);
|
|
|
+ ::stream::iterator<T> begin() const { return do_begin(impl_); }
|
|
|
+ ::stream::iterator<T> end() const { return do_end(impl_); }
|
|
|
+
|
|
|
+ bool empty() const { return begin() == end(); }
|
|
|
+
|
|
|
+ std::vector<value_type> collect() const {
|
|
|
+ std::vector<value_type> coll;
|
|
|
+ collect(coll);
|
|
|
+ return coll;
|
|
|
}
|
|
|
- template <typename It> static bool compare_(void * l, void * r) {
|
|
|
- return *((It *)l) == *((It *)r);
|
|
|
+
|
|
|
+ template <typename C, typename = std::enable_if_t<
|
|
|
+ !std::is_void_v<typename C::value_type>>>
|
|
|
+ C & collect(C & coll) const {
|
|
|
+ std::copy(begin(), end(), std::inserter(coll, coll.end()));
|
|
|
+ return coll;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::optional<value_type> first() const {
|
|
|
+ return begin() != end() ? std::optional(*begin()) : std::nullopt;
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F> bool none(F && pred) const {
|
|
|
+ return std::none_of(begin(), end(), pred);
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F> bool all(F && pred) const {
|
|
|
+ return std::all_of(begin(), end(), pred);
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F> bool any(F && pred) const {
|
|
|
+ return std::any_of(begin(), end(), pred);
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F>
|
|
|
+ value_type accumulate(F && fold, value_type const & accum) const {
|
|
|
+ return std::accumulate(begin(), end(), accum, fold);
|
|
|
}
|
|
|
- template <typename It> static void advance_(void * p) { ++(*(It *)(p)); }
|
|
|
- };
|
|
|
|
|
|
- namespace detail {
|
|
|
- template <typename T, typename = void> class stream_base_pointer_impl {};
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- class stream_base_pointer_impl<
|
|
|
- T, typename std::enable_if<traits::is_dereferencable<T>::value>::type> {
|
|
|
- private:
|
|
|
- using self_t = stream_base<T>;
|
|
|
- using pointer = typename std::remove_reference<T>::type;
|
|
|
- using element_type = typename std::pointer_traits<pointer>::element_type;
|
|
|
-
|
|
|
- public:
|
|
|
- auto deref() const & -> stream_base<element_type &> {
|
|
|
- return static_cast<self_t const *>(this)->map(
|
|
|
- [](T const & p) -> element_type & { return *p; });
|
|
|
- }
|
|
|
-
|
|
|
- auto deref() && -> stream_base<element_type &> {
|
|
|
- return static_cast<self_t &&>(*this).map(
|
|
|
- [](T const & p) -> element_type & { return *p; });
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- class stream_base : public stream_base_pointer_impl<T> {
|
|
|
- private:
|
|
|
- using value_type = typename std::decay<T>::type;
|
|
|
-
|
|
|
- public:
|
|
|
- template <typename Stream> stream_base(std::shared_ptr<Stream> && impl) {
|
|
|
- do_begin = [](std::shared_ptr<void> p) -> iterator<T> {
|
|
|
- return std::static_pointer_cast<Stream>(p)->begin();
|
|
|
- };
|
|
|
- do_end = [](std::shared_ptr<void> p) -> iterator<T> {
|
|
|
- return std::static_pointer_cast<Stream>(p)->end();
|
|
|
- };
|
|
|
- impl_ = std::static_pointer_cast<void>(impl);
|
|
|
- }
|
|
|
-
|
|
|
- ::stream::iterator<T> begin() const { return do_begin(impl_); }
|
|
|
- ::stream::iterator<T> end() const { return do_end(impl_); }
|
|
|
-
|
|
|
- bool empty() const { return begin() == end(); }
|
|
|
-
|
|
|
- std::vector<value_type> collect() const {
|
|
|
- std::vector<value_type> coll;
|
|
|
- collect(coll);
|
|
|
- return coll;
|
|
|
- }
|
|
|
-
|
|
|
- template <typename C, typename = std::enable_if_t<
|
|
|
- !std::is_void_v<typename C::value_type>>>
|
|
|
- C & collect(C & coll) const {
|
|
|
- std::copy(begin(), end(), std::inserter(coll, coll.end()));
|
|
|
- return coll;
|
|
|
- }
|
|
|
-
|
|
|
- std::optional<value_type> first() const {
|
|
|
- return begin() != end() ? std::optional(*begin()) : std::nullopt;
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F> bool none(F && pred) const {
|
|
|
- return std::none_of(begin(), end(), pred);
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F> bool all(F && pred) const {
|
|
|
- return std::all_of(begin(), end(), pred);
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F> bool any(F && pred) const {
|
|
|
- return std::any_of(begin(), end(), pred);
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F>
|
|
|
- value_type accumulate(F && fold, value_type const & accum) const {
|
|
|
- return std::accumulate(begin(), end(), accum, fold);
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F, typename = std::enable_if_t<
|
|
|
- std::is_invocable_v<F, value_type, value_type>>>
|
|
|
- std::optional<value_type> accumulate(F && fold) const {
|
|
|
- if (empty()) { return std::nullopt; }
|
|
|
- value_type first = *begin();
|
|
|
- return std::accumulate(++begin(), end(), first, fold);
|
|
|
- }
|
|
|
-
|
|
|
- value_type accumulate(value_type const & accum) const {
|
|
|
- return std::accumulate(begin(), end(), accum);
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F> void each(F && consumer) const {
|
|
|
- std::for_each(begin(), end(), consumer);
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F>
|
|
|
- stream_base<traits::mapped_t<T, F>> map(F && func) const &;
|
|
|
- template <typename F> stream_base<T> filter(F && func) const &;
|
|
|
- template <typename F>
|
|
|
- stream_base<traits::fmapped_t<T, F>> flatmap(F && func) const &;
|
|
|
-
|
|
|
- auto keys() const & {
|
|
|
- return map([](auto & kv) -> decltype(auto) { return kv.first; });
|
|
|
- }
|
|
|
-
|
|
|
- auto values() const & {
|
|
|
- return map([](auto & kv) -> decltype(auto) { return kv.second; });
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F>
|
|
|
- stream_base<traits::mapped_t<T, F>> map(F && func) &&;
|
|
|
- template <typename F> stream_base<T> filter(F && func) &&;
|
|
|
- template <typename F>
|
|
|
- stream_base<traits::fmapped_t<T, F>> flatmap(F && func) &&;
|
|
|
-
|
|
|
- template <typename Cast> stream_base<Cast const &> cast() const & {
|
|
|
- return map([](T const & p) -> Cast const & { return p; });
|
|
|
- }
|
|
|
-
|
|
|
- template <typename Cast> stream_base<Cast const &> cast() && {
|
|
|
- return std::move(*this).map(
|
|
|
- [](T const & p) -> Cast const & { return p; });
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F, typename = traits::is_memvar_t<F>>
|
|
|
- stream_base<traits::memvar_f<F>> map(F && memvar) const & {
|
|
|
- return map(map_member_object<F>{memvar});
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F, typename = traits::is_memfun_t<F>>
|
|
|
- stream_base<traits::memfun_f<F>> map(F && memvar) const & {
|
|
|
- return map(map_member_function<F>{memvar});
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F, typename = traits::is_memvar_t<F>>
|
|
|
- stream_base<traits::memvar_f<F>> map(F && memvar) && {
|
|
|
- return std::move(*this).map(map_member_object<F>{memvar});
|
|
|
- }
|
|
|
-
|
|
|
- template <typename F, typename = traits::is_memfun_t<F>>
|
|
|
- stream_base<traits::memfun_f<F>> map(F && memvar) && {
|
|
|
- return std::move(*this).map(map_member_function<F>{memvar});
|
|
|
- }
|
|
|
-
|
|
|
- private:
|
|
|
- iterator<T> (*do_begin)(std::shared_ptr<void>){nullptr};
|
|
|
- iterator<T> (*do_end)(std::shared_ptr<void>){nullptr};
|
|
|
- std::shared_ptr<void> impl_{nullptr};
|
|
|
- };
|
|
|
- }
|
|
|
+ template <typename F, typename = std::enable_if_t<
|
|
|
+ std::is_invocable_v<F, value_type, value_type>>>
|
|
|
+ std::optional<value_type> accumulate(F && fold) const {
|
|
|
+ if (empty()) { return std::nullopt; }
|
|
|
+ value_type first = *begin();
|
|
|
+ return std::accumulate(++begin(), end(), first, fold);
|
|
|
+ }
|
|
|
+
|
|
|
+ value_type accumulate(value_type const & accum) const {
|
|
|
+ return std::accumulate(begin(), end(), accum);
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F> void each(F && consumer) const {
|
|
|
+ std::for_each(begin(), end(), consumer);
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F>
|
|
|
+ stream_base<traits::mapped_t<T, F>> map(F && func) const &;
|
|
|
+ template <typename F> stream_base<T> filter(F && func) const &;
|
|
|
+ template <typename F>
|
|
|
+ stream_base<traits::fmapped_t<T, F>> flatmap(F && func) const &;
|
|
|
+
|
|
|
+ auto keys() const & {
|
|
|
+ return map([](auto & kv) -> decltype(auto) { return kv.first; });
|
|
|
+ }
|
|
|
+
|
|
|
+ auto values() const & {
|
|
|
+ return map([](auto & kv) -> decltype(auto) { return kv.second; });
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F> stream_base<traits::mapped_t<T, F>> map(F && func) &&;
|
|
|
+ template <typename F> stream_base<T> filter(F && func) &&;
|
|
|
+ template <typename F>
|
|
|
+ stream_base<traits::fmapped_t<T, F>> flatmap(F && func) &&;
|
|
|
+
|
|
|
+ template <typename Cast> stream_base<Cast const &> cast() const & {
|
|
|
+ return map([](T const & p) -> Cast const & { return p; });
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename Cast> stream_base<Cast const &> cast() && {
|
|
|
+ return std::move(*this).map(
|
|
|
+ [](T const & p) -> Cast const & { return p; });
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F, typename = traits::is_memvar_t<F>>
|
|
|
+ stream_base<traits::memvar_f<F>> map(F && memvar) const & {
|
|
|
+ return map(map_member_object<F>{memvar});
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F, typename = traits::is_memfun_t<F>>
|
|
|
+ stream_base<traits::memfun_f<F>> map(F && memvar) const & {
|
|
|
+ return map(map_member_function<F>{memvar});
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F, typename = traits::is_memvar_t<F>>
|
|
|
+ stream_base<traits::memvar_f<F>> map(F && memvar) && {
|
|
|
+ return std::move(*this).map(map_member_object<F>{memvar});
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename F, typename = traits::is_memfun_t<F>>
|
|
|
+ stream_base<traits::memfun_f<F>> map(F && memvar) && {
|
|
|
+ return std::move(*this).map(map_member_function<F>{memvar});
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ iterator<T> (*do_begin)(std::shared_ptr<void>){nullptr};
|
|
|
+ iterator<T> (*do_end)(std::shared_ptr<void>){nullptr};
|
|
|
+ std::shared_ptr<void> impl_{nullptr};
|
|
|
+ };
|
|
|
}
|