File indexing completed on 2024-06-16 05:06:54

0001 /*
0002     SPDX-FileCopyrightText: 2018 Ivan Čukić <ivan.cukic(at)kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #ifndef VOY_OPERATIONS_SLICE_H
0008 #define VOY_OPERATIONS_SLICE_H
0009 
0010 // STL
0011 #include <functional>
0012 
0013 // Self
0014 #include "../utils.h"
0015 #include "../traits.h"
0016 #include "../dsl/node_tags.h"
0017 
0018 namespace voy {
0019 
0020 using voy::utils::non_copyable;
0021 
0022 using voy::dsl::continuator_base,
0023       voy::dsl::transformation_node_tag;
0024 
0025 template <typename = void>
0026 class slice_impl {
0027 public:
0028     using node_category = transformation_node_tag;
0029 
0030     explicit slice_impl(size_t drop, size_t take)
0031         : m_drop{drop}
0032         , m_take{take}
0033     {
0034     }
0035 
0036     template <typename Cont>
0037     class node: public continuator_base<Cont>, non_copyable {
0038         using base = continuator_base<Cont>;
0039 
0040     public:
0041         node(size_t drop, size_t take, Cont&& continuation)
0042             : base(std::move(continuation))
0043             , m_drop(drop)
0044             , m_take(take)
0045         {
0046         }
0047 
0048         template <typename T>
0049         void operator() (T&& value) const
0050         {
0051             //  0 1 2 3 4 5 6 7 8 9    drop 3 take 5
0052             //        [         )
0053             //        3        3+5
0054             utils::on_scope_exit increment_count = [&] {
0055                 if (m_current_count < m_drop + m_take) {
0056                     m_current_count++;
0057                 }
0058             };
0059 
0060             if (m_current_count < m_drop) return;
0061             if (m_take != 0 && m_current_count >= m_drop + m_take) return;
0062 
0063             base::emit(voy_fwd(value));
0064 
0065             if (m_current_count == m_drop + m_take - 1) {
0066                 this->m_continuation.notify_ended();
0067             }
0068         }
0069 
0070     private:
0071         size_t m_drop;
0072         size_t m_take;
0073 
0074         // no need for locking, nodes are not shared across threads
0075         mutable size_t m_current_count = 0;
0076     };
0077 
0078     template <typename Cont>
0079     auto with_continuation(Cont&& cont) &&
0080     {
0081         return node<Cont>(m_drop, m_take, voy_fwd(cont));
0082     }
0083 
0084 private:
0085     size_t m_drop;
0086     size_t m_take;
0087 };
0088 
0089 inline
0090 auto drop(size_t drop_count)
0091 {
0092     return slice_impl(drop_count, 0);
0093 }
0094 
0095 inline
0096 auto take(size_t take_count)
0097 {
0098     return slice_impl(0, take_count);
0099 }
0100 
0101 inline
0102 auto slice(size_t drop_count, size_t take_count)
0103 {
0104     return slice_impl(drop_count, take_count);
0105 }
0106 
0107 
0108 } // namespace voy
0109 
0110 #endif // include guard
0111