about summary refs log tree commit diff
path: root/immer/algorithm.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'immer/algorithm.hpp')
-rw-r--r--immer/algorithm.hpp212
1 files changed, 212 insertions, 0 deletions
diff --git a/immer/algorithm.hpp b/immer/algorithm.hpp
new file mode 100644
index 000000000000..ecdc417e2b07
--- /dev/null
+++ b/immer/algorithm.hpp
@@ -0,0 +1,212 @@
+//
+// immer: immutable data structures for C++
+// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
+//
+// This software is distributed under the Boost Software License, Version 1.0.
+// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
+//
+
+#pragma once
+
+#include <algorithm>
+#include <numeric>
+#include <type_traits>
+
+namespace immer {
+
+/**
+ * @defgroup algorithm
+ * @{
+ */
+
+/*@{*/
+// Right now these algorithms dispatch directly to the vector
+// implementations unconditionally.  This will be changed in the
+// future to support other kinds of containers.
+
+/*!
+ * Apply operation `fn` for every contiguous *chunk* of data in the
+ * range sequentially.  Each time, `Fn` is passed two `value_type`
+ * pointers describing a range over a part of the vector.  This allows
+ * iterating over the elements in the most efficient way.
+ *
+ * @rst
+ *
+ * .. tip:: This is a low level method. Most of the time, :doc:`other
+ *    wrapper algorithms <algorithms>` should be used instead.
+ *
+ * @endrst
+ */
+template <typename Range, typename Fn>
+void for_each_chunk(const Range& r, Fn&& fn)
+{
+    r.impl().for_each_chunk(std::forward<Fn>(fn));
+}
+
+template <typename Iterator, typename Fn>
+void for_each_chunk(const Iterator& first, const Iterator& last, Fn&& fn)
+{
+    assert(&first.impl() == &last.impl());
+    first.impl().for_each_chunk(
+        first.index(), last.index(), std::forward<Fn>(fn));
+}
+
+template <typename T, typename Fn>
+void for_each_chunk(const T* first, const T* last, Fn&& fn)
+{
+    std::forward<Fn>(fn)(first, last);
+}
+
+/*!
+ * Apply operation `fn` for every contiguous *chunk* of data in the
+ * range sequentially, until `fn` returns `false`.  Each time, `Fn` is
+ * passed two `value_type` pointers describing a range over a part of
+ * the vector.  This allows iterating over the elements in the most
+ * efficient way.
+ *
+ * @rst
+ *
+ * .. tip:: This is a low level method. Most of the time, :doc:`other
+ *    wrapper algorithms <algorithms>` should be used instead.
+ *
+ * @endrst
+ */
+template <typename Range, typename Fn>
+bool for_each_chunk_p(const Range& r, Fn&& fn)
+{
+    return r.impl().for_each_chunk_p(std::forward<Fn>(fn));
+}
+
+template <typename Iterator, typename Fn>
+bool for_each_chunk_p(const Iterator& first, const Iterator& last, Fn&& fn)
+{
+    assert(&first.impl() == &last.impl());
+    return first.impl().for_each_chunk_p(
+        first.index(), last.index(), std::forward<Fn>(fn));
+}
+
+template <typename T, typename Fn>
+bool for_each_chunk_p(const T* first, const T* last, Fn&& fn)
+{
+    return std::forward<Fn>(fn)(first, last);
+}
+
+/*!
+ * Equivalent of `std::accumulate` applied to the range `r`.
+ */
+template <typename Range, typename T>
+T accumulate(Range&& r, T init)
+{
+    for_each_chunk(r, [&](auto first, auto last) {
+        init = std::accumulate(first, last, init);
+    });
+    return init;
+}
+
+template <typename Range, typename T, typename Fn>
+T accumulate(Range&& r, T init, Fn fn)
+{
+    for_each_chunk(r, [&](auto first, auto last) {
+        init = std::accumulate(first, last, init, fn);
+    });
+    return init;
+}
+
+/*!
+ * Equivalent of `std::accumulate` applied to the range @f$ [first,
+ * last) @f$.
+ */
+template <typename Iterator, typename T>
+T accumulate(Iterator first, Iterator last, T init)
+{
+    for_each_chunk(first, last, [&](auto first, auto last) {
+        init = std::accumulate(first, last, init);
+    });
+    return init;
+}
+
+template <typename Iterator, typename T, typename Fn>
+T accumulate(Iterator first, Iterator last, T init, Fn fn)
+{
+    for_each_chunk(first, last, [&](auto first, auto last) {
+        init = std::accumulate(first, last, init, fn);
+    });
+    return init;
+}
+
+/*!
+ * Equivalent of `std::for_each` applied to the range `r`.
+ */
+template <typename Range, typename Fn>
+Fn&& for_each(Range&& r, Fn&& fn)
+{
+    for_each_chunk(r, [&](auto first, auto last) {
+        for (; first != last; ++first)
+            fn(*first);
+    });
+    return std::forward<Fn>(fn);
+}
+
+/*!
+ * Equivalent of `std::for_each` applied to the range @f$ [first,
+ * last) @f$.
+ */
+template <typename Iterator, typename Fn>
+Fn&& for_each(Iterator first, Iterator last, Fn&& fn)
+{
+    for_each_chunk(first, last, [&](auto first, auto last) {
+        for (; first != last; ++first)
+            fn(*first);
+    });
+    return std::forward<Fn>(fn);
+}
+
+/*!
+ * Equivalent of `std::copy` applied to the range `r`.
+ */
+template <typename Range, typename OutIter>
+OutIter copy(Range&& r, OutIter out)
+{
+    for_each_chunk(
+        r, [&](auto first, auto last) { out = std::copy(first, last, out); });
+    return out;
+}
+
+/*!
+ * Equivalent of `std::copy` applied to the range @f$ [first,
+ * last) @f$.
+ */
+template <typename InIter, typename OutIter>
+OutIter copy(InIter first, InIter last, OutIter out)
+{
+    for_each_chunk(first, last, [&](auto first, auto last) {
+        out = std::copy(first, last, out);
+    });
+    return out;
+}
+
+/*!
+ * Equivalent of `std::all_of` applied to the range `r`.
+ */
+template <typename Range, typename Pred>
+bool all_of(Range&& r, Pred p)
+{
+    return for_each_chunk_p(
+        r, [&](auto first, auto last) { return std::all_of(first, last, p); });
+}
+
+/*!
+ * Equivalent of `std::all_of` applied to the range @f$ [first, last)
+ * @f$.
+ */
+template <typename Iter, typename Pred>
+bool all_of(Iter first, Iter last, Pred p)
+{
+    return for_each_chunk_p(first, last, [&](auto first, auto last) {
+        return std::all_of(first, last, p);
+    });
+}
+
+/** @} */ // group: algorithm
+
+} // namespace immer