diff --git a/.clang-tidy b/.clang-tidy index 477f572..c2f8408 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,2 +1,15 @@ -Checks: '-*,modernize-*,cppcoreguidelines-*,bugprone-*,-modernize-use-trailing-return-type,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-macro-usage,-cppcoreguidelines-no-malloc,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers, -cppcoreguidelines-non-private-member-variables-in-classes, -bugprone-easily-swappable-parameters' +Checks: + - -* + - modernize-* + - cppcoreguidelines-* + - bugprone-* + - -modernize-use-trailing-return-type + - -cppcoreguidelines-special-member-functions + - -cppcoreguidelines-macro-usage + - -cppcoreguidelines-no-malloc + - -cppcoreguidelines-pro-bounds-pointer-arithmetic + - -cppcoreguidelines-pro-bounds-constant-array-index + - -cppcoreguidelines-avoid-magic-numbers + - -cppcoreguidelines-non-private-member-variables-in-classes + - -bugprone-easily-swappable-parameters HeaderFilterRegex: 'itertools' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ee175ae..a4482dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,10 +26,10 @@ jobs: fail-fast: false matrix: include: - - {os: ubuntu-22.04, cc: gcc-12, cxx: g++-12} - - {os: ubuntu-22.04, cc: clang-15, cxx: clang++-15} - - {os: macos-12, cc: gcc-12, cxx: g++-12} - - {os: macos-12, cc: clang, cxx: clang++} + - {os: ubuntu-22.04, cc: gcc-12, cxx: g++-12, doc: OFF} + - {os: ubuntu-22.04, cc: clang-15, cxx: clang++-15, doc: ON} + - {os: macos-12, cc: gcc-12, cxx: g++-12, doc: OFF} + - {os: macos-12, cc: clang, cxx: clang++, doc: OFF} runs-on: ${{ matrix.os }} @@ -91,6 +91,23 @@ jobs: echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> $GITHUB_ENV echo "PATH=$PATH" >> $GITHUB_ENV + - name: Build doxygen + if: matrix.doc == 'ON' + env: + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + LIBRARY_PATH: /usr/local/opt/llvm/lib + run: | + cd $HOME + git clone https://github.com/doxygen/doxygen.git + cd doxygen + git checkout Release_1_10_0 + mkdir build + cd build + cmake .. -Duse_libclang=ON -Dstatic_libclang=ON -Duse_libc++=OFF -DLLVM_ROOT=/usr/lib/llvm-15/lib/cmake/llvm -DClang_ROOT=/usr/lib/llvm-15/lib/cmake/clang + make -j 2 VERBOSE=1 + make install + - name: add clang cxxflags if: ${{ contains(matrix.cxx, 'clang') }} run: | @@ -103,7 +120,7 @@ jobs: CXX: ${{ matrix.cxx }} LIBRARY_PATH: /usr/local/opt/llvm/lib run: | - mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/install + mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/install -DBuild_Documentation=${{ matrix.doc }} make -j2 || make -j1 VERBOSE=1 - name: Test itertools @@ -123,3 +140,11 @@ jobs: with: path: ${{ env.CCACHE_DIR }} key: ccache-${{ matrix.os }}-${{ matrix.cc }}-${{ github.run_id }} + + - name: Deploy documentation + if: matrix.doc == 'ON' && github.ref == 'refs/heads/unstable' + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: build/doc/html + branch: github.io + target-folder: docs/unstable diff --git a/c++/itertools/enumerate.hpp b/c++/itertools/enumerate.hpp new file mode 100644 index 0000000..ac77f40 --- /dev/null +++ b/c++/itertools/enumerate.hpp @@ -0,0 +1,176 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides a range adapting function for enumerating a given range/view. + */ + +#ifndef _ITERTOOLS_ENUMERATE_HPP +#define _ITERTOOLS_ENUMERATE_HPP + +#include "./iterator_facade.hpp" +#include "./sentinel.hpp" + +#include +#include +#include + +namespace itertools { + + namespace detail { + + /** + * @ingroup range_iterators + * @brief Iterator for a detail::enumerated range. + * + * @details It stores an iterator of the original range and an index. Incrementing advances the iterator + * and the index by 1. Dereferencing returns a std::pair consisting of the current index and the current + * dereferenced value of the original iterator. + * + * See itertools::enumerate(R &&) for more details. + * + * @tparam Iter Iterator type. + */ + template struct enum_iter : iterator_facade, std::pair::value_type>> { + /// Iterator of the original range. + Iter it; + + /// Index for enumerating. + long i = 0; + + /// Default constructor sets the index to zero and default constructs the original iterator. + enum_iter() = default; + + /** + * @brief Construct an enumerated iterator from a given iterator and set the index to zero. + * @param it Iterator of the original range. + */ + enum_iter(Iter it) : it(std::move(it)) {} + + /// Increment the iterator by incrementing the original iterator and the index. + void increment() { + ++it; + ++i; + } + + /** + * @brief Equal-to operator for two detail::enum_iter objects. + * + * @param other detail::enum_iter to compare with. + * @return True, if the original iterators are equal. + */ + [[nodiscard]] bool operator==(enum_iter const &other) const { return it == other.it; } + + /** + * @brief Equal-to operator for a detail::enum_iter and an itertools::sentinel_t. + * + * @tparam SentinelIter Iterator type of the sentinel. + * @param s itertools::sentinel_t to compare with. + * @return True, if the original iterator is equal to the iterator stored in the sentinel. + */ + template [[nodiscard]] bool operator==(sentinel_t const &s) const { return it == s.it; } + + /** + * @brief Dereference the iterator. + * @return Tuple consisting of the current index and the current dereferenced value of the original iterator. + */ + [[nodiscard]] decltype(auto) dereference() const { return std::tuple{i, *it}; } + }; + + /** + * @ingroup adapted_ranges + * @brief Represents an enumerated range. + * + * @details See itertools::enumerate(R &&) for more details. + * + * @tparam R Range type. + */ + template struct enumerated { + /// Original range. + R rg; + + /// Iterator type of the enumerated range. + using iterator = enum_iter; + + /// Const iterator type of the enumerated range. + using const_iterator = enum_iter; + + /// Default equal-to operator. + [[nodiscard]] bool operator==(enumerated const &) const = default; + + /** + * @brief Beginning of the enumerated range. + * @return detail::enum_iter constructed from the beginning of the original range with the index set to zero. + */ + [[nodiscard]] iterator begin() noexcept { return std::begin(rg); } + + /// Const version of begin(). + [[nodiscard]] const_iterator cbegin() const noexcept { return std::cbegin(rg); } + + /// Const overload of begin(). + [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } + + /** + * @brief End of the enumerated range. + * @return itertools::sentinel_t containing the end iterator of the original range. + */ + [[nodiscard]] auto end() noexcept { return make_sentinel(std::end(rg)); } + + /// Const version of end(). + [[nodiscard]] auto cend() const noexcept { return make_sentinel(std::cend(rg)); } + + /// Const overload of end(). + [[nodiscard]] auto end() const noexcept { return cend(); } + }; + + } // namespace detail + + /** + * @ingroup range_adapting_functions + * @brief Lazy-enumerate a given range (similar to Python's enumerate). + * + * @details Each element in the original range is assigned an index, starting from zero. This function + * returns an iterable lazy object (a detail::enumerated range), which iterates over tuples consisting of the + * index and the value of the dereferenced iterator of the original range: + * + * @code{.cpp} + * std::vector vec { 'a', 'b', 'c' }; + * + * for (auto [idx, val] : enumerate(vec)) { + * std::cout << "(" << idx << ", " << val << ")\n"; + * } + * @endcode + * + * Output: + * + * ``` + * (0, a) + * (1, b) + * (2, c) + * ``` + * + * See also std::ranges::views::enumerate. + * + * @tparam R Range type. + * @param rg Range to enumerate. + * @return A detail::enumerated range. + */ + template [[nodiscard]] detail::enumerated enumerate(R &&rg) { return {std::forward(rg)}; } + +} // namespace itertools + +#endif // _ITERTOOLS_ENUMERATE_HPP \ No newline at end of file diff --git a/c++/itertools/iterator_facade.hpp b/c++/itertools/iterator_facade.hpp new file mode 100644 index 0000000..acc894a --- /dev/null +++ b/c++/itertools/iterator_facade.hpp @@ -0,0 +1,119 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides a CRTP base class for various iterator types in itertools. + */ + +#ifndef _ITERTOOLS_ITERATOR_FACADE_HPP +#define _ITERTOOLS_ITERATOR_FACADE_HPP + +#include +#include + +namespace itertools { + + /// @cond + // Forward declaration. + template + struct iterator_facade; + /// @endcond + + /** + * @ingroup utilities + * @brief CRTP base class for various iterator types in itertools. + * + * @details All iterator types defined in itertools are derived from this class. It uses the + * forward iterator + * category. Derived classes are required to implement the following member functions: + * + * @code{.cpp} + * // used by operator++() and operator++(int) + * void increment(); + * + * // used by operator*() and operator->() + * value_type [const] [&] dereference() [const]; + * @endcode + * + * The `[..]` are optional and depend on the actual iterator type. + * + * @tparam Iter Derived iterator type. + * @tparam Value Value type of the iterator. + * @tparam Reference Reference type of the iterator. + * @tparam Difference Difference type of the iterator. + */ + template + struct iterator_facade { + private: + // Get a reference to the derived iterator. + [[nodiscard]] Iter &self() { return static_cast(*this); } + + // Get a const reference to the derived iterator. + [[nodiscard]] Iter const &self() const { return static_cast(*this); } + + public: + /// Value type of the derived iterator. + using value_type = Value; + + /// Reference type of the derived iterator. + using reference = Reference; + + /// Pointer type of the derived iterator. + using pointer = Value *; + + /// Difference type of the derived iterator. + using difference_type = Difference; + + /// Iterator category of the derived iterator. + using iterator_category = std::forward_iterator_tag; + + /** + * @brief Pre-increment operator. + * @return Reference to the derived iterator after calling the derived iterator's `increment()` function. + */ + Iter &operator++() { + self().increment(); + return self(); + } + + /** + * @brief Post-increment operator. + * @return Copy of the derived iterator before calling the derived iterator's `increment()` function. + */ + Iter operator++(int) { + Iter c = self(); + self().increment(); + return c; + } + + /** + * @brief Dereference operator. + * @return Result of the derived iterator's `dereference()` function. + */ + [[nodiscard]] decltype(auto) operator*() const { return self().dereference(); } + + /** + * @brief Member access operator. + * @return Result of the derived iterator's `dereference()` function. + */ + [[nodiscard]] decltype(auto) operator->() const { return operator*(); } + }; + +} // namespace itertools + +#endif // _ITERTOOLS_ITERATOR_FACADE_HPP \ No newline at end of file diff --git a/c++/itertools/itertools.hpp b/c++/itertools/itertools.hpp index ee21091..16dae73 100644 --- a/c++/itertools/itertools.hpp +++ b/c++/itertools/itertools.hpp @@ -14,675 +14,20 @@ // // Authors: Olivier Parcollet, Nils Wentzell, chuffa +/** + * @file + * @brief Provides a small subset of the ranges and views from [std::ranges](https://en.cppreference.com/w/cpp/ranges). + */ + #ifndef _ITERTOOLS_HPP #define _ITERTOOLS_HPP -#include -#include -#include -#include -#include -#include - -namespace itertools { - - template - struct iterator_facade; - - /* - * A helper for the implementation of forward iterators using CRTP - * - * @tparam Iter - * The Iterator Class to be implemented - * `Iter` is required to have the following member functions - * - value_type [const] [&] dereference() - * - void increment() - */ - template - struct iterator_facade { - - private: - Iter &self() { return static_cast(*this); } - [[nodiscard]] Iter const &self() const { return static_cast(*this); } - - public: - using value_type = Value; - using reference = Reference; - using pointer = Value *; - using difference_type = Difference; - using iterator_category = std::forward_iterator_tag; - - Iter &operator++() { - self().increment(); - return self(); - } - - Iter operator++(int) { - Iter c = self(); - self().increment(); - return c; - } - - decltype(auto) operator*() const { return self().dereference(); } - decltype(auto) operator->() const { return operator*(); } - }; - - template inline typename std::iterator_traits::difference_type distance(Iter first, EndIter last) { - if constexpr (std::is_same_v::iterator_category, std::random_access_iterator_tag>) { - // Difference should be defined also for the case that last is a sentinel - return last - first; - } else { - typename std::iterator_traits::difference_type r(0); - for (; first != last; ++first) ++r; - return r; - } - } - - // Sentinel_t, used to denote the end of certain ranges - template struct sentinel_t { - It it; - }; - template sentinel_t make_sentinel(It it) { return {std::move(it)}; } - - namespace detail { - - /********************* Enumerate Iterator ********************/ - - template struct enum_iter : iterator_facade, std::pair::value_type>> { - - Iter it; - long i = 0; - - enum_iter() = default; - enum_iter(Iter it) : it(std::move(it)) {} - - void increment() { - ++it; - ++i; - } - - bool operator==(enum_iter const &other) const { return it == other.it; } - - template bool operator==(sentinel_t const &other) const { return it == other.it; } - - [[nodiscard]] decltype(auto) dereference() const { return std::tuple{i, *it}; } - }; - - /********************* Transform Iterator ********************/ - - template ::value_type>> - struct transform_iter : iterator_facade, Value> { - - Iter it; - mutable std::optional lambda; - - transform_iter() = default; - transform_iter(Iter it, L lambda) : it(std::move(it)), lambda(std::move(lambda)) {} - - void increment() { ++it; } - - transform_iter(transform_iter &&) = default; - transform_iter(transform_iter const &) = default; - transform_iter &operator=(transform_iter &&other) = default; - - transform_iter &operator=(transform_iter const &other) { - it = other.it; - if (other.lambda.has_value()) - lambda.emplace(other.lambda.value()); - else - lambda.reset(); - return *this; - } - - bool operator==(transform_iter const &other) const { return it == other.it; } - - template bool operator==(sentinel_t const &other) const { return (it == other.it); } - - decltype(auto) dereference() const { return (*lambda)(*it); } - }; - - /********************* Zip Iterator ********************/ - - template struct zip_iter : iterator_facade, std::tuple::value_type...>> { - - std::tuple its; - - zip_iter() = default; - zip_iter(std::tuple its) : its(std::move(its)) {} - - private: - template [[gnu::always_inline]] void increment_all(std::index_sequence) { ((void)(++std::get(its)), ...); } - - public: - void increment() { increment_all(std::index_sequence_for{}); } - - bool operator==(zip_iter const &other) const { return its == other.its; } - - template bool operator==(sentinel_t const &other) const { - return [&](std::index_sequence) { - return ((std::get(its) == std::get(other.it)) || ...); - }(std::index_sequence_for{}); - } - - template [[nodiscard]] auto tuple_map_impl(std::index_sequence) const { - return std::tuple(its))...>(*std::get(its)...); - } - - [[nodiscard]] decltype(auto) dereference() const { return tuple_map_impl(std::index_sequence_for{}); } - }; - - /********************* Product Iterator ********************/ - - template - struct prod_iter : iterator_facade, std::tuple::value_type...>> { - - std::tuple its_begin; - TupleSentinel its_end; - std::tuple its = its_begin; - static constexpr long Rank = sizeof...(It); - - prod_iter() = default; - prod_iter(std::tuple its_begin, TupleSentinel its_end) : its_begin(std::move(its_begin)), its_end(std::move(its_end)) {} - - template void _increment() { - ++std::get(its); - if constexpr (N > 0) { - if (std::get(its) == std::get(its_end)) { - std::get(its) = std::get(its_begin); - _increment(); - } - } - } - void increment() { _increment(); } - - bool operator==(prod_iter const &other) const { return its == other.its; } - - template bool operator==(sentinel_t const &s) const { return (s.it == std::get<0>(its)); } - - private: - template [[gnu::always_inline]] [[nodiscard]] auto tuple_map_impl(std::index_sequence) const { - return std::tuple(its))...>(*std::get(its)...); - } - - public: - [[nodiscard]] decltype(auto) dereference() const { return tuple_map_impl(std::index_sequence_for{}); } - }; - - /********************* Stride Iterator ********************/ - - template struct stride_iter : iterator_facade, typename std::iterator_traits::value_type> { - - Iter it; - std::ptrdiff_t stride; - - stride_iter() = default; - stride_iter(Iter it, std::ptrdiff_t stride) : it(it), stride(stride) { - if (stride <= 0) throw std::runtime_error("strided range requires a positive stride"); - } - - void increment() { std::advance(it, stride); } - - bool operator==(stride_iter const &other) const { return it == other.it; } - - decltype(auto) dereference() const { return *it; } - }; - - /********************* The Wrapper Classes representing the adapted ranges ********************/ - - template struct transformed { - T x; - L lambda; - - using const_iterator = transform_iter; - using iterator = const_iterator; - - [[nodiscard]] const_iterator cbegin() const noexcept { return {std::cbegin(x), lambda}; } - [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } - - [[nodiscard]] auto cend() const noexcept { return make_sentinel(std::cend(x)); } - [[nodiscard]] auto end() const noexcept { return cend(); } - }; - - // --------------------------------------------- - - template struct enumerated { - T x; - - using iterator = enum_iter; - using const_iterator = enum_iter; - - bool operator==(enumerated const &) const = default; - - [[nodiscard]] iterator begin() noexcept { return std::begin(x); } - [[nodiscard]] const_iterator cbegin() const noexcept { return std::cbegin(x); } - [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } - - [[nodiscard]] auto end() noexcept { return make_sentinel(std::end(x)); } - [[nodiscard]] auto cend() const noexcept { return make_sentinel(std::cend(x)); } - [[nodiscard]] auto end() const noexcept { return cend(); } - }; - - // --------------------------------------------- - - template struct zipped { - std::tuple tu; // T can be a ref. - - using seq_t = std::index_sequence_for; - using iterator = zip_iter()))...>; - using const_iterator = zip_iter()))...>; - - template zipped(U &&...ranges) : tu{std::forward(ranges)...} {} - - bool operator==(zipped const &) const = default; - - private: - // Apply function to tuple - template [[gnu::always_inline]] auto tuple_map(F &&f, std::index_sequence) { - return std::make_tuple(f(std::get(tu))...); - } - template [[gnu::always_inline]] auto tuple_map(F &&f, std::index_sequence) const { - return std::make_tuple(f(std::get(tu))...); - } - - public: - [[nodiscard]] iterator begin() noexcept { - return tuple_map([](auto &&x) { return std::begin(x); }, seq_t{}); - } - [[nodiscard]] const_iterator cbegin() const noexcept { - return tuple_map([](auto &&x) { return std::cbegin(x); }, seq_t{}); - } - [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } - - [[nodiscard]] auto end() noexcept { - return make_sentinel(tuple_map([](auto &&x) { return std::end(x); }, seq_t{})); - } - [[nodiscard]] auto cend() const noexcept { - return make_sentinel(tuple_map([](auto &&x) { return std::cend(x); }, seq_t{})); - } - [[nodiscard]] auto end() const noexcept { return cend(); } - }; - - // --------------------------------------------- - - template struct multiplied { - std::tuple tu; // T can be a ref. - - using iterator = prod_iter()))...>, decltype(std::begin(std::declval()))...>; - using const_iterator = prod_iter()))...>, decltype(std::cbegin(std::declval()))...>; - - template multiplied(U &&...ranges) : tu{std::forward(ranges)...} {} - - bool operator==(multiplied const &) const = default; - - private: - template [[gnu::always_inline]] auto _begin(std::index_sequence) { - return iterator{std::make_tuple(std::begin(std::get(tu))...), std::make_tuple(std::end(std::get(tu))...)}; - } - - template [[gnu::always_inline]] auto _cbegin(std::index_sequence) const { - return const_iterator{std::make_tuple(std::cbegin(std::get(tu))...), std::make_tuple(std::cend(std::get(tu))...)}; - } - - public: - [[nodiscard]] iterator begin() noexcept { return _begin(std::index_sequence_for{}); } - [[nodiscard]] const_iterator cbegin() const noexcept { return _cbegin(std::index_sequence_for{}); } - [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } - - [[nodiscard]] auto end() noexcept { return make_sentinel(std::end(std::get<0>(tu))); } - [[nodiscard]] auto cend() const noexcept { return make_sentinel(std::cend(std::get<0>(tu))); } - [[nodiscard]] auto end() const noexcept { return cend(); } - }; - - template multiplied(T &&...) -> multiplied...>; - - // --------------------------------------------- - - template struct sliced { - T x; - std::ptrdiff_t start_idx, end_idx; - - using iterator = decltype(std::begin(x)); - using const_iterator = decltype(std::cbegin(x)); - - bool operator==(sliced const &) const = default; - - [[nodiscard]] std::ptrdiff_t size() const { - std::ptrdiff_t total_size = distance(std::cbegin(x), std::cend(x)); - return std::min(total_size, end_idx) - start_idx; - } - - [[nodiscard]] iterator begin() noexcept { return std::next(std::begin(x), start_idx); } - [[nodiscard]] const_iterator cbegin() const noexcept { return std::next(std::cbegin(x), start_idx); } - [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } - - [[nodiscard]] iterator end() noexcept { return std::next(begin(), size()); } - [[nodiscard]] const_iterator cend() const noexcept { return std::next(cbegin(), size()); } - [[nodiscard]] const_iterator end() const noexcept { return cend(); } - }; - - // --------------------------------------------- - - template struct strided { - T x; - std::ptrdiff_t stride; - - using iterator = stride_iter; - using const_iterator = stride_iter; - - bool operator==(strided const &) const = default; - - private: - [[nodiscard]] std::ptrdiff_t end_offset() const { - auto size = distance(std::cbegin(x), std::cend(x)); - return (size == 0) ? 0 : ((size - 1) / stride + 1) * stride; - } - - public: - [[nodiscard]] iterator begin() noexcept { return {std::begin(x), stride}; } - [[nodiscard]] const_iterator cbegin() const noexcept { return {std::cbegin(x), stride}; } - [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } - - [[nodiscard]] iterator end() noexcept { return {std::next(std::begin(x), end_offset()), stride}; } - [[nodiscard]] const_iterator cend() const noexcept { return {std::next(std::cbegin(x), end_offset()), stride}; } - [[nodiscard]] const_iterator end() const noexcept { return cend(); } - }; - - } // namespace detail - - /********************* The range adapting functions ********************/ - - /** - * Transform (lazy)applies a unary lambda function to every - * element of a range. It returns itself a range. - * - * @param range The range that the lambda is applied to - * @param range The lambda to apply to the range - */ - template auto transform(T &&range, L lambda) { - return detail::transformed{std::forward(range), std::move(lambda)}; - } - - /** - * Lazy-enumerate a range (similar to Python enumerate) - * - * The function returns a iterable lazy object. When iterated upon, - * this object yields a pair (n,x) where : - * * n is the index (starting at 0) - * * x is in the object in the range - * - * @tparam R Type of the ranges - * @param range The range to enumerate - * @example itertools/enumerate.cpp - */ - template detail::enumerated enumerate(R &&range) { return {std::forward(range)}; } - - /** - * Generate a zip of the ranges (similar to Python zip). - * - * The function returns a iterable lazy object. When iterated upon, - * this object yields a tuple of the objects in the ranges. - * - * @tparam R Type of the ranges - * @param ranges - * The ranges to zip. - * - * .. warning:: - * The ranges have to be equal lengths or behaviour is undefined. - */ - template detail::zipped zip(R &&...ranges) { return {std::forward(ranges)...}; } - - /** - * Generate a zip of the ranges (similar to Python zip). - * - * DOC TO BE WRITTEN. - * - * @param ranges - * @param lambda - * @tparam R Type of the ranges - * @tparam L Type of the Lambda - */ - template auto zip_with(T &&...ranges, L &&lambda) { - return transform(zip(std::forward(ranges)...), [lambda](std::tuple t) { return std::apply(lambda, t); }); - } - - /** - * Lazy-product of multiple ranges. This function returns itself a range of tuple. - * Iterating over it will yield all combinations of the different range values. - * Note: The ranges are incremented beginning with the leftmost range. - * Note: The length is equal to the minimum of the lengths of all ranges. - * - * @tparam T The types of the different ranges - * @param ranges The ranges to zip. - */ - template detail::multiplied product(T &&...ranges) { return {std::forward(ranges)...}; } - - /** - * Lazy-slice a range. - * This function returns itself a slice of the initial range - * - * @param range The range to slice - * @param start_idx The index to start the slice at - * @param end_idx The index one past the end of the sliced range - */ - template detail::sliced slice(T &&range, std::ptrdiff_t start_idx, std::ptrdiff_t end_idx) { - return {std::forward(range), start_idx, std::max(start_idx, end_idx)}; - } - - /** - * Lazy-stride a range. - * This function returns itself a subrange of the initial range - * by considering only every N-th element - * - * @param range The range to take the subrange of - * @param stride The numer of elements to skip - */ - template detail::strided stride(T &&range, std::ptrdiff_t stride) { return {std::forward(range), stride}; } - - /********************* Some factory functions ********************/ - - namespace detail { - template [[gnu::always_inline]] auto make_product_impl(A &arr, std::index_sequence) { - return product(arr[Is]...); - } - } // namespace detail - - template auto make_product(std::array &arr) { return detail::make_product_impl(arr, std::make_index_sequence{}); } - - template auto make_product(std::array const &arr) { - return detail::make_product_impl(arr, std::make_index_sequence{}); - } - - template auto make_vector_from_range(R const &r) { - std::vector> vec{}; // decltype returns a & - if constexpr (std::is_same_v) { - auto total_size = distance(std::cbegin(r), std::cend(r)); - vec.reserve(total_size); - } - for (auto const &x : r) vec.emplace_back(x); - return vec; - } - - /********************* Functionality related to Integer ranges ********************/ - - /** - * A range of integer indices that mimics the Python `range`. - */ - class range { - long first_ = 0, last_ = -1, step_ = 1; - - public: - // Denote the full range at compile-time by variable all of a seperate type - struct all_t {}; - static inline constexpr all_t all = {}; - - // Keep alias index_t for backward compatibility - using index_t = long; - - /** - * Default constructor - Deprecated - * - * Note: For full index range in slicing use range::all - * */ - [[deprecated("range default construction deprecated. Use range::all for full range in slicing operation")]] range() = default; - - /** - * Constructor - * - * @param first: First index of the range - * @param last: End of the range (excluded) - * - * @examples : - * - * A(range (0,3), 0) // means A(0,0), A(1,0), A(2,0) - * A(range (0,4,2), 0) // means A(0,0), A(2,0) - * */ - range(long first, long last) noexcept : first_(first), last_(last) {} - - /** - * Constructor - * - * @param first: First index of the range - * @param last: End of the range (excluded) - * @param step: Step-size between two indices - * - * @examples : - * - * A(range (0,3), 0) // means A(0,0), A(1,0), A(2,0) - * A(range (0,4,2), 0) // means A(0,0), A(2,0) - * */ - range(long first, long last, long step) : first_(first), last_(last), step_(step) { - if (step_ == 0) throw std::runtime_error("Step-size cannot be zero in construction of integer range"); - } - - /** - * Constructor - * - * @param last: End of the range (excluded) - * - * Equivalent to range(0,last,1) - */ - explicit range(long last) : range(0, last, 1) {} - - bool operator==(range const &) const = default; - - /// First index of the range - [[nodiscard]] long first() const { return first_; } - - /// End of the range (excluded) - [[nodiscard]] long last() const { return last_; } - - /// Step-size between two indices - [[nodiscard]] long step() const { return step_; } - - /// Number of indices in the range - [[nodiscard]] long size() const { return std::max(0l, (last_ + step_ - (step_ > 0 ? 1 : -1) - first_) / step_); } - - range operator+(long shift) const { return {first_ + shift, last_ + shift, step_}; } - - friend inline std::ostream &operator<<(std::ostream &os, const range &r) { - os << "range(" << r.first() << "," << r.last() << "," << r.step() << ")"; - return os; - } - - // Iterator on the range (for for loop e.g.) - class const_iterator { - - public: - long pos, last, step; - - using value_type = long; - using iterator_category = std::forward_iterator_tag; - using pointer = value_type *; - using difference_type = std::ptrdiff_t; - using reference = value_type const &; - - const_iterator &operator++() noexcept { - pos += step; - return *this; - } - - const_iterator operator++(int) noexcept { - const_iterator c = *this; - pos += step; - return c; - } - - [[nodiscard]] bool atEnd() const noexcept { return step > 0 ? pos >= last : pos <= last; } - - bool operator==(const_iterator const &other) const noexcept { - // EXPECTS(other.last == this->last); - // EXPECTS(other.step == this->step); - return (other.pos == this->pos) || (other.atEnd() && this->atEnd()); - } - bool operator!=(const_iterator const &other) const noexcept { return (!operator==(other)); } - - long operator*() const noexcept { return pos; } - long operator->() const noexcept { return operator*(); } - }; - - [[nodiscard]] const_iterator begin() const noexcept { return {first_, last_, step_}; } - [[nodiscard]] const_iterator cbegin() const noexcept { return {first_, last_, step_}; } - - [[nodiscard]] const_iterator end() const noexcept { return {last_, last_, step_}; } - [[nodiscard]] const_iterator cend() const noexcept { return {last_, last_, step_}; } - }; - - /** - * A product of an arbitrary number of integer ranges - * given a set of integers or an integer tuple - * - * @tparam Integers The integer types - */ - template and ...), int>> - auto product_range(Integers... Is) { - return product(range(Is)...); - } - - namespace detail { - template [[gnu::always_inline]] auto product_range_impl(Tuple const &idx_tpl, std::index_sequence) { - return product_range(std::get(idx_tpl)...); - } - } // namespace detail - - template and ...), int>> - auto product_range(std::tuple const &idx_tpl) { - return detail::product_range_impl(idx_tpl, std::make_index_sequence{}); - } - - template , int>> - auto product_range(std::array const &idx_arr) { - return detail::product_range_impl(idx_arr, std::make_index_sequence{}); - } - - /** - * Given an integer range [start, end), chunk it as equally as possible into n_chunks. - * If the range is not dividable in n_chunks equal parts, the first chunks have - * one more element than the last ones. - */ - inline std::pair chunk_range(std::ptrdiff_t start, std::ptrdiff_t end, long n_chunks, long rank) { - auto total_size = end - start; - auto chunk_size = total_size / n_chunks; - auto n_large_nodes = total_size - n_chunks * chunk_size; - if (rank < n_large_nodes) // larger nodes have size chunk_size + 1 - return {start + rank * (chunk_size + 1), start + (rank + 1) * (chunk_size + 1)}; - else // smaller nodes have size chunk_size - return {start + n_large_nodes + rank * chunk_size, start + n_large_nodes + (rank + 1) * chunk_size}; - } - - /** - * Apply a function f to every element of an integer range - * - * @param r - * The range to apply the function to - * - * @param f - * The function to apply - */ - template void foreach (range const &r, F && f) { - auto i = r.first(), last = r.last(), step = r.step(); - for (; i < last; i += step) f(i); - } - -} // namespace itertools +#include "./enumerate.hpp" +#include "./product.hpp" +#include "./range.hpp" +#include "./slice.hpp" +#include "./stride.hpp" +#include "./transform.hpp" +#include "./zip.hpp" -#endif +#endif // _ITERTOOLS_HPP_ diff --git a/c++/itertools/omp_chunk.hpp b/c++/itertools/omp_chunk.hpp index 91cd39c..d01b94f 100644 --- a/c++/itertools/omp_chunk.hpp +++ b/c++/itertools/omp_chunk.hpp @@ -14,26 +14,33 @@ // // Authors: Olivier Parcollet, Nils Wentzell +/** + * @file + * @brief Provides utilities to distribute a range across OMP threads. + */ + #pragma once -#include +#include "./itertools.hpp" -#include +#include namespace itertools { /** - * Function to chunk a range, distributing it uniformly over all OMP threads. - * - * This range-adapting function should be used inside an omp parallel region - * - * @tparam T The type of the range - * - * @param range The range to chunk - */ - template auto omp_chunk(T &&range) { - auto total_size = itertools::distance(std::cbegin(range), std::cend(range)); + * @ingroup utilities + * @brief Distribute a range as evenly as possible across all OMP threads. + * + * @details See chunk_range(std::ptrdiff_t, std::ptrdiff_t, long, long) and slice(R &&, std::ptrdiff_t, std::ptrdiff_t) for more details. + * + * @tparam R Range type. + * @param rg Range to chunk. + * @return A detail::sliced range, containing the chunk of the original range that belongs to the current thread. + */ + template auto omp_chunk(R &&rg) { + auto total_size = itertools::distance(std::cbegin(rg), std::cend(rg)); auto [start_idx, end_idx] = chunk_range(0, total_size, omp_get_num_threads(), omp_get_thread_num()); - return itertools::slice(std::forward(range), start_idx, end_idx); + return itertools::slice(std::forward(rg), start_idx, end_idx); } + } // namespace itertools diff --git a/c++/itertools/product.hpp b/c++/itertools/product.hpp new file mode 100644 index 0000000..ef9e9c6 --- /dev/null +++ b/c++/itertools/product.hpp @@ -0,0 +1,281 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides a range adapting function for multiplying a given number of ranges/views (cartesian product). + */ + +#ifndef _ITERTOOLS_PRODUCT_HPP +#define _ITERTOOLS_PRODUCT_HPP + +#include "./iterator_facade.hpp" +#include "./sentinel.hpp" + +#include +#include +#include +#include + +namespace itertools { + + /// @cond + // Forward declarations. + namespace detail { + template struct multiplied; + } + template detail::multiplied product(Rs &&...); + /// @endcond + + namespace detail { + + /** + * @ingroup range_iterators + * @brief Iterator for a detail::multiplied (cartesian product) range. + * + * @details It stores three tuples of iterators of the original ranges: + * - `its_begin` contains the begin iterators of all ranges + * - `its_end` contains the end iterators of all ranges + * - `its` contains the current iterators of all ranges + * + * Incrementing is done from right to left, i.e. the iterator of the last range is incremented first. + * Once an iterator reaches the end of its range, it is reset to the beginning and the iterator of the + * previous range is incremented once. + * Dereferencing returns a tuple containing the results of dereferencing each iterator. + * + * See itertools::product(Rs &&...rgs) for more details. + * + * @tparam EndIters Tuple type containing the end iterators of all ranges. + * @tparam Iters Iterator types. + */ + template + struct prod_iter : iterator_facade, std::tuple::value_type...>> { + /// Tuple containing the begin iterators of the original ranges. + std::tuple its_begin; + + /// Tuple containing the end iterators of the original ranges. + EndIters its_end; + + /// Tuple containing the current iterators of the original ranges. + std::tuple its = its_begin; + + /// Number of original ranges. + static constexpr long Rank = sizeof...(Iters); + + /// Default constructor. + prod_iter() = default; + + /** + * @brief Construct a product iterator from given begin iterators and end iterators. + * + * @param its_begin Tuple containing begin iterators of the original ranges. + * @param its_end Tuple containing end iterators of the original ranges. + */ + prod_iter(std::tuple its_begin, EndIters its_end) : its_begin(std::move(its_begin)), its_end(std::move(its_end)) {} + + private: + // Helper function to recursively increment the current iterators. + template void _increment() { + // increment Nth iterator + ++std::get(its); + // recursively increment previous iterators if necessary + if constexpr (N > 0) { + // if Nth iterator is at its end, reset it to its begin iterator and increment N-1st iterator + if (std::get(its) == std::get(its_end)) { + std::get(its) = std::get(its_begin); + _increment(); + } + } + } + + public: + /// Increment the iterator by incrementing the current iterators starting with the iterator of the last range. + void increment() { _increment(); } + + /** + * @brief Equal-to operator for two detail::prod_iter objects. + * + * @param other detail::prod_iter to compare with. + * @return True, if all original iterators are equal. + */ + [[nodiscard]] bool operator==(prod_iter const &other) const { return its == other.its; } + + /** + * @brief Equal-to operator for a detail::prod_iter and an itertools::sentinel_t. + * + * @details We reach the end of the product range, when the first iterator, i.e. `std::get<0>(its)`, is at its end. + * + * @tparam SentinelIter Iterator type of the sentinel. + * @param s itertools::sentinel_t to compare with. + * @return True, if the first iterator, i.e. `std::get<0>(its)`, is equal to the iterator of the sentinel. + */ + template [[nodiscard]] bool operator==(sentinel_t const &s) const { return (s.it == std::get<0>(its)); } + + private: + // Helper function to dereference all original iterators. + template [[gnu::always_inline]] [[nodiscard]] auto tuple_map_impl(std::index_sequence) const { + return std::tuple(its))...>(*std::get(its)...); + } + + public: + /** + * @brief Dereference the iterator. + * @return Tuple containing the dereferenced values of all original iterators. + */ + [[nodiscard]] decltype(auto) dereference() const { return tuple_map_impl(std::index_sequence_for{}); } + }; + + /** + * @ingroup adapted_ranges + * @brief Represents a cartesian product of ranges. + * + * @details See itertools::product(Rs &&...rgs) for more details. + * + * @tparam Rs Range types. + */ + template struct multiplied { + /// Tuple containing the original ranges. + std::tuple tu; + + /// Iterator type of the product range. + using iterator = prod_iter()))...>, decltype(std::begin(std::declval()))...>; + + /// Const iterator type the product range. + using const_iterator = prod_iter()))...>, decltype(std::cbegin(std::declval()))...>; + + /** + * @brief Constructs a cartesian product (multiplied) range from the given ranges. + * + * @tparam Us Range types. + * @param rgs Ranges to be multiplied. + */ + template multiplied(Us &&...rgs) : tu{std::forward(rgs)...} {} + + /// Default equal-to operator. + [[nodiscard]] bool operator==(multiplied const &) const = default; + + private: + // Helper function to create a detail::prod_iter representing the beginning of the product range. + template [[gnu::always_inline]] auto _begin(std::index_sequence) { + return iterator{std::make_tuple(std::begin(std::get(tu))...), std::make_tuple(std::end(std::get(tu))...)}; + } + + // Const version of _begin(std::index_sequence). + template [[gnu::always_inline]] auto _cbegin(std::index_sequence) const { + return const_iterator{std::make_tuple(std::cbegin(std::get(tu))...), std::make_tuple(std::cend(std::get(tu))...)}; + } + + public: + /** + * @brief Beginning of the product range. + * @return detail::prod_iter representing the beginning of the product range. + */ + [[nodiscard]] iterator begin() noexcept { return _begin(std::index_sequence_for{}); } + + /// Const version of begin(). + [[nodiscard]] const_iterator cbegin() const noexcept { return _cbegin(std::index_sequence_for{}); } + + /// Const overload of begin(). + [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } + + /** + * @brief End of the product range. + * @return itertools::sentinel_t containing the end iterator of the first original range, i.e. `std::end(std::get<0>(tu))`. + */ + [[nodiscard]] auto end() noexcept { return make_sentinel(std::end(std::get<0>(tu))); } + + /// Const version of end(). + [[nodiscard]] auto cend() const noexcept { return make_sentinel(std::cend(std::get<0>(tu))); } + + /// Const overload of end(). + [[nodiscard]] auto end() const noexcept { return cend(); } + }; + + /// @cond + // Class template argument deduction guide. + template multiplied(Rs &&...) -> multiplied...>; + + // Helper function to create a product range from a container of ranges. + template [[gnu::always_inline]] [[nodiscard]] auto make_product_impl(C &cont, std::index_sequence) { + return product(cont[Is]...); + } + /// @endcond + + } // namespace detail + + /** + * @addtogroup range_adapting_functions + * @{ + */ + + /** + * @brief Lazy-multiply a given number of ranges by forming their cartesian product. + * + * @details An arbitrary number of ranges are multiplied together into a cartesian product range. + * They are traversed such that the last range is traversed the fastest (see the example below). + * The number of elements in a product range is equal to the product of the sizes of the given ranges. + * This function returns an iterable lazy object, which can be used in range-based for loops: + * + * @code{.cpp} + * std::vector v1 { 1, 2, 3 }; + * std::vector v2 { 'a', 'b' }; + * + * for (auto [i, c] : product(v1, v2)) { + * std::cout << "(" << i << ", " << c << ")\n"; + * } + * @endcode + * + * Output: + * + * ``` + * (1, a) + * (1, b) + * (2, a) + * (2, b) + * (3, a) + * (3, b) + * ``` + * + * See also std::ranges::views::cartesian_product. + * + * @tparam Rs Range types. + * @param rgs Ranges to be used. + * @return A product (detail::multiplied) range. + */ + template [[nodiscard]] detail::multiplied product(Rs &&...rgs) { return {std::forward(rgs)...}; } + + /** + * @brief Create a cartesian product range from an array of ranges. + * + * @tparam R Range type. + * @tparam N Number of ranges. + * @param arr Array of ranges. + * @return A product (detail::multiplied) range from the ranges in the array. + */ + template [[nodiscard]] auto make_product(std::array &arr) { + return detail::make_product_impl(arr, std::make_index_sequence{}); + } + + /// Const overload of make_product(std::array &). + template [[nodiscard]] auto make_product(std::array const &arr) { + return detail::make_product_impl(arr, std::make_index_sequence{}); + } + + /** @} */ + +} // namespace itertools + +#endif // _ITERTOOLS_PRODUCT_HPP \ No newline at end of file diff --git a/c++/itertools/range.hpp b/c++/itertools/range.hpp new file mode 100644 index 0000000..d3ad4f4 --- /dev/null +++ b/c++/itertools/range.hpp @@ -0,0 +1,412 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides an integer range similar to Python's range. + */ + +#ifndef _ITERTOOLS_RANGE_HPP +#define _ITERTOOLS_RANGE_HPP + +#include "./product.hpp" + +#include +#include +#include +#include +#include +#include + +namespace itertools { + + /** + * @addtogroup integer_range + * @{ + */ + + /** + * @brief A lazy range of integers that mimics a Python range. + * + * @details It stores the first value, the last value (excluded) and the step size between two indices. + * By default, the step size is set to 1. This function returns an iterable lazy object, which can be + * used in range-based for loops: + * + * @code{.cpp} + * for (auto i : range(5)) { + * std::cout << i << " "; + * } + * std::cout << "\n"; + + * for (auto i : range(-2, 1)) { + * std::cout << i << " "; + * } + * std::cout << "\n"; + + * for (auto i : range(10, 3, -2)) { + * std::cout << i << " "; + * } + * std::cout << "\n"; + + * for (auto i : range(0, 10, -1)) { + * std::cout << i << " "; // empty + * } + * @endcode + * + * Output: + * + * ``` + * 0 1 2 3 4 + * -2 -1 0 + * 10 8 6 4 + * ``` + * + * See also std::ranges::views::iota. + */ + class range { + // First value of the range. + long first_ = 0; + + // Last value of the range (excluded). + long last_ = -1; + + // Number of integers between two elements of the range. + long step_ = 1; + + public: + /** + * @ingroup integer_range + * @brief Denote a full range at compile-time. + * @details Can be used for accessing slices of multi-dimensional arrays. + */ + struct all_t {}; + + /// See range::all_t. + static inline constexpr all_t all = {}; + + /// Integer type for backward compatibility. + using index_t = long; + + /** + * @brief Default constructor. + * @deprecated Use range::range(long, long) or range::range(long, long, long) instead. + */ + [[deprecated("range default construction deprecated. Use range::all for full range in slicing operation")]] range() = default; + + /** + * @brief Construct a range with a step size of 1 and a given first and last (excluded) value. + * + * @param first First value of the range. + * @param last Last value of the range (excluded). + */ + range(long first, long last) noexcept : first_(first), last_(last) {} + + /** + * @brief Construct a range with a given step size and a given first and last (excluded) value. + * + * @details Throws an exception if the step size is zero. + * + * @param first First value of the range. + * @param last Last value of the range (excluded). + * @param step Number of integers between two elements of the range. + */ + range(long first, long last, long step) : first_(first), last_(last), step_(step) { + if (step_ == 0) throw std::runtime_error("Step-size cannot be zero in construction of integer range"); + } + + /** + * @brief Construct a range with a step size of 1, a first value set to 0 and a given last value (excluded). + * @param last Last value of the range (excluded). + */ + explicit range(long last) : range(0, last, 1) {} + + /// Default equal-to operator. + [[nodiscard]] bool operator==(range const &) const = default; + + /// Get first value of the range. + [[nodiscard]] long first() const { return first_; } + + /// Get last value of the range (excluded). + [[nodiscard]] long last() const { return last_; } + + /// Get step size between two elements of the range. + [[nodiscard]] long step() const { return step_; } + + /// Get number of elements in the range. + [[nodiscard]] long size() const { return std::max(0l, (last_ + step_ - (step_ > 0 ? 1 : -1) - first_) / step_); } + + /** + * @brief Shift the whole range by a given amount. + * + * @details Simply adds the given shift to the first and last value of the range, while keeping + * the same step size. + * + * @param shift Amount to shift the range by. + * @return Shifted range. + */ + [[nodiscard]] range operator+(long shift) const { return {first_ + shift, last_ + shift, step_}; } + + /** + * @brief Write the range details to std::ostream. + * + * @param os std::ostream object. + * @param rg range object. + * @return Reference to os. + */ + friend inline std::ostream &operator<<(std::ostream &os, const range &rg) { + os << "range(" << rg.first() << "," << rg.last() << "," << rg.step() << ")"; + return os; + } + + /// Const iterator type for itertools::range. + struct const_iterator { + /// Current value. + long pos; + + /// Last value of the range (excluded). + long last; + + /// Step size. + long step; + + /// Value type. + using value_type = long; + + /// Iterator category. + using iterator_category = std::forward_iterator_tag; + + /// Pointer type. + using pointer = value_type *; + + /// Difference type. + using difference_type = std::ptrdiff_t; + + /// Reference type. + using reference = value_type const &; + + /** + * @brief Pre-increment operator increments the current value by the step size. + * @return Reference to the incremented iterator. + */ + const_iterator &operator++() noexcept { + pos += step; + return *this; + } + + /** + * @brief Post-increment operator increments the current value by the step size. + * @return Copy of the iterator before incrementing. + */ + const_iterator operator++(int) noexcept { + const_iterator c = *this; + pos += step; + return c; + } + + /** + * @brief Has the iterator reached the end of the range? + * @return True, if the current value of the iterator is >= the last value of the range for positive step size or + * if the current value of the iterator is <= the last value of the range for negative step size. + */ + [[nodiscard]] bool atEnd() const noexcept { return step > 0 ? pos >= last : pos <= last; } + + /** + * @brief Equal-to operator for two iterators. + * + * @param other Iterator to compare with. + * @return True, if the current values of both iterators are equal or both iterators are at the end of the range. + */ + [[nodiscard]] bool operator==(const_iterator const &other) const noexcept { + return (other.pos == this->pos) || (other.atEnd() && this->atEnd()); + } + + /** + * @brief Not-equal-to operator for two iterators. + * + * @param other Iterator to compare with. + * @return True, if the iterators are not equal. + */ + [[nodiscard]] bool operator!=(const_iterator const &other) const noexcept { return (!operator==(other)); } + + /** + * @brief Dereference operator. + * @return Current value of the iterator. + */ + [[nodiscard]] long operator*() const noexcept { return pos; } + + /** + * @brief Member access operator. + * @return Current value of the iterator. + */ + [[nodiscard]] long operator->() const noexcept { return operator*(); } + }; + + /** + * @brief Beginning of the integer range. + * @return Iterator with its current value set to the first value of the range. + */ + [[nodiscard]] const_iterator cbegin() const noexcept { return {first_, last_, step_}; } + + /// The same as cbegin(). + [[nodiscard]] const_iterator begin() const noexcept { return {first_, last_, step_}; } + + /** + * @brief End of the range. + * @return Iterator with its current value set to the excluded last value of the range. + */ + [[nodiscard]] const_iterator cend() const noexcept { return {last_, last_, step_}; } + + /// The same as cend(). + [[nodiscard]] const_iterator end() const noexcept { return {last_, last_, step_}; } + }; + + /** + * @brief Create a cartesian product range of integer ranges from given integers. + * + * @details The given integers specify the excluded last values of the individual itertools::range objects. + * Each range starts at 0 and has a step size of 1. + * + * @code{.cpp} + * for (auto [i1, i2] : product_range(2, 3)) { + * std::cout << "(" << i1 << ", " << i2 << ")\n"; + * } + * @endcode + * + * Output: + * + * ``` + * (0, 0) + * (0, 1) + * (0, 2) + * (1, 0) + * (1, 1) + * (1, 2) + * ``` + * + * @tparam Is Integer types. + * @param is Last values of the integer ranges (excluded). + * @return Product (detail::multiplied) range of integer ranges. See itertools::product and itertools::range. + */ + template and ...), int>> [[nodiscard]] auto product_range(Is... is) { + return product(range(is)...); + } + + /// @cond + namespace detail { + + // Helper function to create a product range of integer ranges from a tuple or an array. + template [[gnu::always_inline]] auto product_range_impl(T const &idxs, std::index_sequence) { + return product_range(std::get(idxs)...); + } + + } // namespace detail + /// @endcond + + /** + * @brief Create a cartesian product range of integer ranges from a tuple of integers. + * + * @details The integers in the given tuple specify the excluded last values of the individual itertools::range objects. + * Each range starts at 0 and has a step size of 1. + * + * @code{.cpp} + * for (auto [i1, i2] : product_range(std::make_tuple(2, 3))) { + * std::cout << "(" << i1 << ", " << i2 << ")\n"; + * } + * @endcode + * + * Output: + * + * ``` + * (0, 0) + * (0, 1) + * (0, 2) + * (1, 0) + * (1, 1) + * (1, 2) + * ``` + * + * @tparam Is Integer types. + * @param idx_tpl Tuple containing the excluded last values of the integer ranges. + * @return Product (detail::multiplied) range of integer ranges. See itertools::product and itertools::range. + */ + template and ...), int>> + [[nodiscard]] auto product_range(std::tuple const &idx_tpl) { + return detail::product_range_impl(idx_tpl, std::make_index_sequence{}); + } + + /** + * @brief Create a cartesian product range of integer ranges from an array of integers. + * + * @details The integers in the given array specify the excluded last values of the individual itertools::range objects. + * Each range starts at 0 and has a step size of 1. + * + * @code{.cpp} + * for (auto [i1, i2] : product_range(std::array{2, 3})) { + * std::cout << "(" << i1 << ", " << i2 << ")\n"; + * } + * @endcode + * + * Output: + * + * ``` + * (0, 0) + * (0, 1) + * (0, 2) + * (1, 0) + * (1, 1) + * (1, 2) + * ``` + * + * @tparam I Integer type. + * @tparam N Number of elements in the array. + * @param idx_arr Array containing the excluded last values of the integer ranges. + * @return Product (detail::multiplied) range of integer ranges. See itertools::product and itertools::range. + */ + template , int>> + [[nodiscard]] auto product_range(std::array const &idx_arr) { + return detail::product_range_impl(idx_arr, std::make_index_sequence{}); + } + + /** + * @brief Apply a function to every element of an integer itertools::range. + * + * @code{.cpp} + * // print out the first 10 squares + * itertools::foreach(itertools::range(1, 11), [](int i) { + * std::cout << i * i << " "; + * }); + * @endcode + * + * Output: + * + * ``` + * 1 4 9 16 25 36 49 64 81 100 + * ``` + * + * @tparam F Callable type. + * @param rg itertools::range object. + * @param f Callable object to be applied to each element. + */ + template void foreach (range const &rg, F && f) { + auto i = rg.first(), last = rg.last(), step = rg.step(); + for (; i < last; i += step) std::forward(f)(i); + } + + /** @} */ + +} // namespace itertools + +#endif // _ITERTOOLS_RANGE_HPP \ No newline at end of file diff --git a/c++/itertools/sentinel.hpp b/c++/itertools/sentinel.hpp new file mode 100644 index 0000000..aad194a --- /dev/null +++ b/c++/itertools/sentinel.hpp @@ -0,0 +1,56 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides a generic sentinel type for various iterator types in itertools. + */ + +#ifndef _ITERTOOLS_SENTINEL_HPP +#define _ITERTOOLS_SENTINEL_HPP + +#include + +namespace itertools { + + /** + * @addtogroup utilities + * @{ + */ + + /** + * @brief Generic sentinel type that can be used to mark the end of a range. + * @tparam Iter Iterator type. + */ + template struct sentinel_t { + /// End iterator of some range. + Iter it; + }; + + /** + * @brief Create an itertools::sentinel_t from an iterator using template type deduction. + * + * @tparam Iter Iterator type. + * @param it Iterator to be turned into an itertools::sentinel_t. + * @return Sentinel object. + */ + template [[nodiscard]] sentinel_t make_sentinel(Iter it) { return {std::move(it)}; } + + /** @} */ + +} // namespace itertools + +#endif // _ITERTOOLS_SENTINEL_HPP \ No newline at end of file diff --git a/c++/itertools/slice.hpp b/c++/itertools/slice.hpp new file mode 100644 index 0000000..7d50bba --- /dev/null +++ b/c++/itertools/slice.hpp @@ -0,0 +1,146 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides a range adapting function for slicing a given range/view. + */ + +#ifndef _ITERTOOLS_SLICE_HPP +#define _ITERTOOLS_SLICE_HPP + +#include "./utils.hpp" + +#include +#include +#include +#include + +namespace itertools { + + namespace detail { + + /** + * @ingroup adapted_ranges + * @brief Represents a sliced range. + * + * @details See itertools::slice(R &&, std::ptrdiff_t, std::ptrdiff_t) for more details. + * + * @tparam R Range type. + */ + template struct sliced { + /// Original range. + R rg; + + /// Index at which the sliced range starts. + std::ptrdiff_t start_idx; + + /// Index at which the sliced range ends. + std::ptrdiff_t end_idx; + + /// Iterator type of the sliced range. + using iterator = decltype(std::begin(rg)); + + /// Const iterator type of the sliced range. + using const_iterator = decltype(std::cbegin(rg)); + + /// Default equal-to operator. + [[nodiscard]] bool operator==(sliced const &) const = default; + + /** + * @brief Helper function to calculate the size of the sliced range. + * @return Number of elements in the slice. + */ + [[nodiscard]] std::ptrdiff_t size() const { + std::ptrdiff_t total_size = distance(std::cbegin(rg), std::cend(rg)); + return std::min(total_size, end_idx) - start_idx; + } + + /** + * @brief Beginning of the sliced range. + * @return Iterator to the beginning of the sliced range. + */ + [[nodiscard]] iterator begin() noexcept { return std::next(std::begin(rg), start_idx); } + + /// Const version of begin(). + [[nodiscard]] const_iterator cbegin() const noexcept { return std::next(std::cbegin(rg), start_idx); } + + /// Const overload of begin(). + [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } + + /** + * @brief End of the sliced range. + * @return Iterator to the end of the sliced range. + */ + [[nodiscard]] iterator end() noexcept { return std::next(begin(), size()); } + + /// Const version of end(). + [[nodiscard]] const_iterator cend() const noexcept { return std::next(cbegin(), size()); } + + /// Const overload of end(). + [[nodiscard]] const_iterator end() const noexcept { return cend(); } + }; + + } // namespace detail + + /** + * @ingroup range_adapting_functions + * @brief Lazy-slice a given range. + * + * @details Only the part of the given range between the `start_idx` and the `end_idx` is taken into account. + * If `end_idx` is bigger than the size of the original range, the slice ends at the end of the original range. + * If `end_idx` is smaller than `start_idx`, the slice is empty. Note that the behaviour is undefined if + * `start_idx` is smaller than zero. This function returns an iterable lazy object, which can be used in + * range-based for loops: + * + * @code{.cpp} + * std::array arr { 1, 2, 3, 4, 5 }; + * + * for (auto i : slice(arr, 1, 3)) { + * std::cout << i << " "; + * } + * std::cout << "\n"; + * + * for (auto i : slice(arr, 3, 7)) { + * std::cout << i << " "; + * } + * std::cout << "\n"; + * + * for (auto i : slice(arr, 4, 3)) { + * std::cout << i << " "; // empty slice + * } + * @endcode + * + * Output: + * + * ``` + * 2 3 + * 4 5 + * ``` + * + * @tparam R Range type. + * @param rg Range to be sliced. + * @param start_idx Index where the slice starts. + * @param end_idx Index of the first element past the end of the sliced range (excluded). + * @return A detail::sliced range. + */ + template [[nodiscard]] detail::sliced slice(R &&rg, std::ptrdiff_t start_idx, std::ptrdiff_t end_idx) { + return {std::forward(rg), start_idx, std::max(start_idx, end_idx)}; + } + +} // namespace itertools + +#endif // _ITERTOOLS_SLICE_HPP \ No newline at end of file diff --git a/c++/itertools/stride.hpp b/c++/itertools/stride.hpp new file mode 100644 index 0000000..aacfbd4 --- /dev/null +++ b/c++/itertools/stride.hpp @@ -0,0 +1,184 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides a range adapting function for striding through a given range/view. + */ + +#ifndef _ITERTOOLS_STRIDE_HPP +#define _ITERTOOLS_STRIDE_HPP + +#include "./iterator_facade.hpp" +#include "./utils.hpp" + +#include +#include +#include +#include + +namespace itertools { + + namespace detail { + + /** + * @ingroup range_iterators + * @brief Iterator for a detail::strided range. + * + * @details It stores an iterator of the original range as well as a stride. Incrementing advances the original + * iterator by the given stride. Dereferencing simply returns the dereferenced original iterator. + * + * See itertools::stride(R &&, std::ptrdiff_t) for more details. + * + * @tparam Iter Iterator type. + */ + template struct stride_iter : iterator_facade, typename std::iterator_traits::value_type> { + /// Iterator of the original range. + Iter it; + + /// Number of elements in the original range to skip when incrementing the iterator. + std::ptrdiff_t stride{1}; + + /// Default constructor. + stride_iter() = default; + + /** + * @brief Construct a strided iterator from a given iterator and a given stride. + * + * @param it Iterator of the original range. + * @param stride Stride for advancing the iterator (has to be > 0). + */ + stride_iter(Iter it, std::ptrdiff_t stride) : it(it), stride(stride) { + if (stride <= 0) throw std::runtime_error("The itertools::detail::strided range requires a positive stride"); + } + + /// Increment the iterator by advancing the original iterator by the stride. + void increment() { std::advance(it, stride); } + + /** + * @brief Equal-to operator for two detail::stride_iter objects. + * + * @param other detail::stride_iter to compare with. + * @return True, if the original iterators are equal. + */ + [[nodiscard]] bool operator==(stride_iter const &other) const { return it == other.it; } + + /** + * @brief Dereference the iterator. + * @return Dereferenced value of the original iterator. + */ + [[nodiscard]] decltype(auto) dereference() const { return *it; } + }; + + /** + * @ingroup adapted_ranges + * @brief Represents a strided range. + * + * @details See itertools::stride(R &&, std::ptrdiff_t) for more details. + * + * @tparam R Range type. + */ + template struct strided { + /// Original range. + R rg; + + /// Number of elements in the original range to skip when incrementing the iterator. + std::ptrdiff_t stride; + + /// Iterator type of the strided range. + using iterator = stride_iter; + + /// Const iterator type of the strided range. + using const_iterator = stride_iter; + + /// Default equal-to operator. + [[nodiscard]] bool operator==(strided const &) const = default; + + private: + // Helper function to calculate the index of the end iterator. + [[nodiscard]] std::ptrdiff_t end_offset() const { + auto size = distance(std::cbegin(rg), std::cend(rg)); + return (size == 0) ? 0 : ((size - 1) / stride + 1) * stride; + } + + public: + /** + * @brief Beginning of the strided range. + * @return detail::stride_iter containing the begin iterator of the original range and the stride. + */ + [[nodiscard]] iterator begin() noexcept { return {std::begin(rg), stride}; } + + /// Const version of begin(). + [[nodiscard]] const_iterator cbegin() const noexcept { return {std::cbegin(rg), stride}; } + + /// Const overload of begin(). + [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } + + /** + * @brief End of the strided range. + * @return detail::stride_iter containing an iterator of the original range end_offset() elements beyond the + * beginning and the stride. + */ + [[nodiscard]] iterator end() noexcept { return {std::next(std::begin(rg), end_offset()), stride}; } + + /// Const version of end(). + [[nodiscard]] const_iterator cend() const noexcept { return {std::next(std::cbegin(rg), end_offset()), stride}; } + + /// Const overload of end(). + [[nodiscard]] const_iterator end() const noexcept { return cend(); } + }; + + } // namespace detail + + /** + * @ingroup range_adapting_functions + * @brief Lazy-stride through a given range. + * + * @details Only every Nth element of the original range is taken into account. If the given stride (N) is <= 0, an + * exception is thrown. This function returns an iterable lazy object, which can be used in range-based for loops: + * + * @code{.cpp} + * std::vector vec { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + * + * for (auto i : stride(vec, 3)) { + * std::cout << i << " "; + * } + * std::cout << "\n"; + * + * for (auto i : stride(vec, 10)) { + * std::cout << i << " "; + * } + * @endcode + * + * Output: + * + * ``` + * 1 4 7 10 + * 1 + * ``` + * + * See also See also std::ranges::views::stride. + * + * @tparam R Range type. + * @param rg Original range. + * @param stride Number of elements to skip when incrementing. + * @return A detail::strided range. + */ + template [[nodiscard]] detail::strided stride(R &&rg, std::ptrdiff_t stride) { return {std::forward(rg), stride}; } + +} // namespace itertools + +#endif // _ITERTOOLS_STRIDE_HPP \ No newline at end of file diff --git a/c++/itertools/transform.hpp b/c++/itertools/transform.hpp new file mode 100644 index 0000000..fbdb44a --- /dev/null +++ b/c++/itertools/transform.hpp @@ -0,0 +1,197 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides a range adapting function for transforming a given range/view. + */ + +#ifndef _ITERTOOLS_TRANSFORM_HPP +#define _ITERTOOLS_TRANSFORM_HPP + +#include "./iterator_facade.hpp" +#include "./sentinel.hpp" + +#include +#include +#include +#include + +namespace itertools { + + namespace detail { + + /** + * @ingroup range_iterators + * @brief Iterator for a detail::transformed range. + * + * @details It stores an iterator of the original range and a callable object that is used to transform the + * elements of the original range. Incrementing simply increments the iterator. Dereferencing returns the + * result of the callable object applied to the dereferenced iterator, i.e. the transformed element. + * + * See itertools::transform(R &&, F) for more details. + * + * @tparam Iter Iterator type. + * @tparam F Callable type. + * @tparam Value Return type of the callable. + */ + template ::value_type>> + struct transform_iter : iterator_facade, Value> { + /// Iterator of the original range. + Iter it; + + /// Callable doing the transformation. + mutable std::optional lambda; + + /// Default constructor. + transform_iter() = default; + + /** + * @brief Construct a transformed iterator from a given iterator and callable. + * + * @param it Iterator of the original range. + * @param lambda Callable doing the transformation. + */ + transform_iter(Iter it, F lambda) : it(std::move(it)), lambda(std::move(lambda)) {} + + /// Increment the iterator by incrementing the original iterator. + void increment() { ++it; } + + /// Default move constructor. + transform_iter(transform_iter &&) = default; + + /// Default copy constructor. + transform_iter(transform_iter const &) = default; + + /// Default move assignment operator. + transform_iter &operator=(transform_iter &&) = default; + + /** + * @brief Custom copy assignment operator makes sure that the optional callable is correctly copied. + * @param other detail::transform_iter to copy from. + */ + transform_iter &operator=(transform_iter const &other) { + it = other.it; + if (other.lambda.has_value()) + lambda.emplace(other.lambda.value()); + else + lambda.reset(); + return *this; + } + + /** + * @brief Equal-to operator for two detail::transform_iter objects. + * + * @param other detail::transform_iter to compare with. + * @return True, if the original iterators are equal. + */ + [[nodiscard]] bool operator==(transform_iter const &other) const { return it == other.it; } + + /** + * @brief Equal-to operator for a detail::transform_iter and an itertools::sentinel_t. + * + * @tparam SentinelIter Iterator type of the sentinel. + * @param s itertools::sentinel_t to compare with. + * @return True, if the original iterator is equal to the iterator stored in the sentinel. + */ + template [[nodiscard]] bool operator==(sentinel_t const &s) const { return (it == s.it); } + + /** + * @brief Dereference the iterator. + * @return Result of the callable applied to the dereferenced iterator, i.e. the transformed value. + */ + [[nodiscard]] decltype(auto) dereference() const { return (*lambda)(*it); } + }; + + /** + * @ingroup adapted_ranges + * @brief Represents a transformed range. + * + * @details See itertools::transform(R &&, F) for more details. + * + * @tparam R Range type. + * @tparam F Callable type. + */ + template struct transformed { + /// Original range. + R rg; + + /// Callable doing the transformation. + F lambda; + + /// Const iterator type of the transformed range. + using const_iterator = transform_iter; + + /// Iterator type of the transformed range. + using iterator = const_iterator; + + /** + * @brief Beginning of the transformed range. + * @return detail::transform_iter constructed from the beginning of the original range and the callable. + */ + [[nodiscard]] const_iterator cbegin() const noexcept { return {std::cbegin(rg), lambda}; } + + /// The same as cbegin(). + [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } + + /** + * @brief End of the transformed range. + * @return itertools::sentinel_t containing the end iterator of the original range. + */ + [[nodiscard]] auto cend() const noexcept { return make_sentinel(std::cend(rg)); } + + /// The same as cend(). + [[nodiscard]] auto end() const noexcept { return cend(); } + }; + + } // namespace detail + + /** + * @ingroup range_adapting_functions + * @brief Lazy-transform a given range by applying a unary callable object to every element of the original range. + * + * @details The value type of the transformed range depends on the return type of the callable. + * This function returns an iterable lazy object (a detail::transformed range), which can be used in range-based for loops: + * + * @code{.cpp} + * std::list list { 1, 2, 3, 4, 5 }; + * + * for (auto i : itertools::transform(list, [](int i) { return i * i; })) { + * std::cout << i << " "; + * } + * @endcode + * + * Output: + * + * ``` + * 1 4 9 16 25 + * ``` + * + * See also std::ranges::views::transform. + * + * @tparam R Range type. + * @tparam F Callable type. + * @param rg Range to transform. + * @param lambda Callable to be applied to the given range. + * @return A detail::transformed range. + */ + template [[nodiscard]] auto transform(R &&rg, F lambda) { + return detail::transformed{std::forward(rg), std::move(lambda)}; + } + +} // namespace itertools + +#endif // _ITERTOOLS_TRANSFORM_HPP \ No newline at end of file diff --git a/c++/itertools/utils.hpp b/c++/itertools/utils.hpp new file mode 100644 index 0000000..67984b1 --- /dev/null +++ b/c++/itertools/utils.hpp @@ -0,0 +1,106 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides some utility functions for itertools. + */ + +#ifndef _ITERTOOLS_UTILS_HPP +#define _ITERTOOLS_UTILS_HPP + +#include +#include +#include +#include +#include + +namespace itertools { + + /** + * @addtogroup utilities + * @{ + */ + + /** + * @brief Calculate the distance between two iterators. + * + * @details It is similar to std::distance, + * except that it can be used for two different iterator types, e.g. in case one of them is a const iterator. + * + * @tparam Iter1 Iterator type #1. + * @tparam Iter2 Iterator type #2. + * @param first Iterator #1. + * @param last Iterator #2. + * @return Number of elements between the two iterators. + */ + template + [[nodiscard]] inline typename std::iterator_traits::difference_type distance(Iter1 first, Iter2 last) { + // O(1) for random access iterators + if constexpr (std::is_same_v::iterator_category, std::random_access_iterator_tag>) { + return last - first; + } else { // O(n) for other iterators + typename std::iterator_traits::difference_type r(0); + for (; first != last; ++first) ++r; + return r; + } + } + + /** + * @brief Create a vector from a range. + * + * @tparam R Range type. + * @param rg Range. + * @return std::vector containing the elements of the range, where T denotes the value type of the range. + */ + template [[nodiscard]] auto make_vector_from_range(R const &rg) { + std::vector> vec{}; + // do we really want to reserve memory here? maybe only for random access ranges? + if constexpr (std::is_same_v) { + auto total_size = distance(std::cbegin(rg), std::cend(rg)); + vec.reserve(total_size); + } + for (auto const &x : rg) vec.emplace_back(x); + return vec; + } + + /** + * @brief Given an integer range `[first, last)`, divide it as equally as possible into N chunks. + * + * @details It is intended to divide a range among different processes. If the size of the range is not + * divisible by N without a remainder, i.e. `r = (last - first) % N`, then the first `r` chunks have one more element. + * + * @param first First value of the range. + * @param last Last value of the range (excluded). + * @param n_chunks Number of chunks to divide the range into. + * @param rank Rank of the calling process. + * @return Pair of indices specifying the first and last (excluded) value of the chunk assigned to the calling process. + */ + [[nodiscard]] inline std::pair chunk_range(std::ptrdiff_t first, std::ptrdiff_t last, long n_chunks, long rank) { + auto total_size = last - first; + auto chunk_size = total_size / n_chunks; + auto n_large_nodes = total_size - n_chunks * chunk_size; + if (rank < n_large_nodes) + return {first + rank * (chunk_size + 1), first + (rank + 1) * (chunk_size + 1)}; + else + return {first + n_large_nodes + rank * chunk_size, first + n_large_nodes + (rank + 1) * chunk_size}; + } + + /** @} */ + +} // namespace itertools + +#endif // _ITERTOOLS_UTILS_HPP \ No newline at end of file diff --git a/c++/itertools/zip.hpp b/c++/itertools/zip.hpp new file mode 100644 index 0000000..45ec6ba --- /dev/null +++ b/c++/itertools/zip.hpp @@ -0,0 +1,225 @@ +// Copyright (c) 2019-2022 Simons Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Authors: Olivier Parcollet, Nils Wentzell, chuffa + +/** + * @file + * @brief Provides a range adapting function for zipping a given number of ranges/views. + */ + +#ifndef _ITERTOOLS_ZIP_HPP +#define _ITERTOOLS_ZIP_HPP + +#include "./iterator_facade.hpp" +#include "./sentinel.hpp" + +#include +#include +#include +#include + +namespace itertools { + + namespace detail { + + /** + * @ingroup range_iterators + * @brief Iterator for a detail::zipped range. + * + * @details It stores iterators of the original ranges in a tuple. Incrementing simply increments each iterator + * individually. Dereferencing returns a tuple containing the results of dereferencing each iterator. + * + * See itertools::zip(Rs &&...rgs) for more details. + * + * @tparam Iters Iterator types. + */ + template + struct zip_iter : iterator_facade, std::tuple::value_type...>> { + /// Tuple containing iterators of the original ranges. + std::tuple its; + + /// Default constructor. + zip_iter() = default; + + /** + * @brief Constructs a zipped iterator from given iterators. + * @param its Tuple containing iterators of the original ranges. + */ + zip_iter(std::tuple its) : its(std::move(its)) {} + + private: + // Helper function which increments all original iterators. + template [[gnu::always_inline]] void increment_all(std::index_sequence) { ((void)(++std::get(its)), ...); } + + public: + /// Increment the iterator by incrementing all original iterators stored in the tuple. + void increment() { increment_all(std::index_sequence_for{}); } + + /** + * @brief Equal-to operator for two detail::zip_iter objects. + * + * @param other detail::zip_iter to compare with. + * @return True, if all original iterators are equal. + */ + [[nodiscard]] bool operator==(zip_iter const &other) const { return its == other.its; } + + /** + * @brief Equal-to operator for a detail::zip_iter and an itertools::sentinel_t. + * + * @details Only one of the iterators has to be equal to the corresponding iterator of the sentinel. In case + * the original ranges have different lengths, the detail::zipped range should have the length of the shortest range. + * + * @tparam SentinelIter Iterator type of the sentinel. + * @param s itertools::sentinel_t to compare with. + * @return True, if one of the original iterators is equal to the corresponding iterator of the sentinel. + */ + template [[nodiscard]] bool operator==(sentinel_t const &s) const { + return [&](std::index_sequence) { + return ((std::get(its) == std::get(s.it)) || ...); + }(std::index_sequence_for{}); + } + + private: + // Helper function to dereference all original iterators. + template [[nodiscard]] auto tuple_map_impl(std::index_sequence) const { + return std::tuple(its))...>(*std::get(its)...); + } + + public: + /** + * @brief Dereference the iterator. + * @return Tuple containing the dereferenced values of all original iterators. + */ + [[nodiscard]] decltype(auto) dereference() const { return tuple_map_impl(std::index_sequence_for{}); } + }; + + /** + * @ingroup adapted_ranges + * @brief Represents a zipped range. + * + * @details See itertools::zip(Rs &&...rgs) for more details. + * + * @tparam Rs Range types. + */ + template struct zipped { + /// Tuple containing the original ranges. + std::tuple tu; + + /// Convenience typedef for an std::index_sequence. + using seq_t = std::index_sequence_for; + + /// Iterator type of the zipped range. + using iterator = zip_iter()))...>; + + /// Const iterator type of the zipped range. + using const_iterator = zip_iter()))...>; + + /** + * @brief Construct a zipped range from the given ranges. + * + * @tparam Us Range types. + * @param rgs Ranges to zip. + */ + template zipped(Us &&...rgs) : tu{std::forward(rgs)...} {} + + /// Default equal-to operator. + [[nodiscard]] bool operator==(zipped const &) const = default; + + private: + // Helper function that applies a given callable to each range in the stored tuple and returns a new tuple with the results. + template [[gnu::always_inline]] auto tuple_map(F &&f, std::index_sequence) { + return std::make_tuple(std::forward(f)(std::get(tu))...); + } + + // Const overload of tuple_map(F &&, std::index_sequence). + template [[gnu::always_inline]] auto tuple_map(F &&f, std::index_sequence) const { + return std::make_tuple(std::forward(f)(std::get(tu))...); + } + + public: + /** + * @brief Beginning of the zipped range. + * @return detail::zip_iter constructed from the begin iterators of the original ranges. + */ + [[nodiscard]] iterator begin() noexcept { + return tuple_map([](auto &&rg) { return std::begin(rg); }, seq_t{}); + } + + /// Const version of begin(). + [[nodiscard]] const_iterator cbegin() const noexcept { + return tuple_map([](auto &&rg) { return std::cbegin(rg); }, seq_t{}); + } + + /// Const overload of begin(). + [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } + + /** + * @brief End of the zipped range. + * @return itertools::sentinel_t containing a tuple of end iterators of the original ranges. + */ + [[nodiscard]] auto end() noexcept { + return make_sentinel(tuple_map([](auto &&rg) { return std::end(rg); }, seq_t{})); + } + + /// Const version of end(). + [[nodiscard]] auto cend() const noexcept { + return make_sentinel(tuple_map([](auto &&rg) { return std::cend(rg); }, seq_t{})); + } + + /// Const overload of end(). + [[nodiscard]] auto end() const noexcept { return cend(); } + }; + + } // namespace detail + + /** + * @ingroup range_adapting_functions + * @brief Lazy-zip ranges together (similar to Python's zip). + * + * @details An arbitrary number of ranges are zipped together into a tuple. The zipped range will have as many + * elements as the shortest given range. This function returns an iterable lazy object, which can be used in + * range-based for loops: + * + * @code{.cpp} + * std::vector v1 { 1, 2, 3 }; + * std::vector v2 { 'a', 'b', 'c', 'd', 'e' }; + * + * for (auto [i1, i2] : zip(v1, v1)) { + * std::cout << "(" << i1 << ", " << i2 << ") "; + * } + * + * for (auto [i1, i2, c3] : zip(v1, v1, v2)) { + * std::cout << "(" << i1 << ", " << i2 << ", " << c3 << ") "; + * } + * @endcode + * + * Output: + * + * ``` + * (1, 1) (2, 2) (3, 3) + * (1, 1, a) (2, 2, b) (3, 3, c) + * ``` + * + * See also std::ranges::views::zip. + * + * @tparam Rs Range types. + * @param rgs Ranges to zip. + * @return A detail::zipped range. + */ + template [[nodiscard]] detail::zipped zip(Rs &&...rgs) { return {std::forward(rgs)...}; } + +} // namespace itertools + +#endif // _ITERTOOLS_ZIP_HPP \ No newline at end of file diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index ae34bcf..65090ca 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -47,16 +47,6 @@ else() endif() endif() -# -- Cpp2Py -- -if(PythonSupport OR (NOT IS_SUBPROJECT AND Build_Documentation)) - external_dependency(Cpp2Py - GIT_REPO https://github.com/TRIQS/cpp2py - VERSION 2.0 - GIT_TAG unstable - BUILD_ALWAYS - ) -endif() - # -- GTest -- external_dependency(GTest GIT_REPO https://github.com/google/googletest diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index ce967a3..790f6fb 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,74 +1,34 @@ -# Generate the sphinx config file -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py @ONLY) - -# ----------------------------------------------------------------------------- -# Create an optional target that allows us to regenerate the C++ doc with c++2rst -# ----------------------------------------------------------------------------- -add_custom_target(${PROJECT_NAME}_docs_cpp2rst) -include(${PROJECT_SOURCE_DIR}/share/cmake/extract_flags.cmake) -extract_flags(${PROJECT_NAME}_c BUILD_INTERFACE) -separate_arguments(${PROJECT_NAME}_c_CXXFLAGS) -macro(generate_docs header_file) - add_custom_command( - TARGET ${PROJECT_NAME}_docs_cpp2rst - COMMAND rm -rf ${CMAKE_CURRENT_SOURCE_DIR}/cpp2rst_generated - COMMAND - PYTHONPATH=${CPP2PY_BINARY_DIR}:$ENV{PYTHONPATH} - PATH=${CPP2PY_BINARY_DIR}/bin:${CPP2PY_ROOT}/bin:$ENV{PATH} - c++2rst - ${header_file} - -N ${PROJECT_NAME} - --output_directory ${CMAKE_CURRENT_SOURCE_DIR}/cpp2rst_generated - -I${PROJECT_SOURCE_DIR}/c++ - --cxxflags="${${PROJECT_NAME}_c_CXXFLAGS}" - ) -endmacro(generate_docs) - -generate_docs(${PROJECT_SOURCE_DIR}/c++/${PROJECT_NAME}/${PROJECT_NAME}.hpp) - -# -------------------------------------------------------- -# Build & Run the C++ doc examples and capture the output -# -------------------------------------------------------- - -add_custom_target(${PROJECT_NAME}_docs_example_output) -file(GLOB_RECURSE ExampleList RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) -foreach(example ${ExampleList}) - get_filename_component(f ${example} NAME_WE) - get_filename_component(d ${example} DIRECTORY) - add_executable(${PROJECT_NAME}_doc_${f} EXCLUDE_FROM_ALL ${example}) - set_property(TARGET ${PROJECT_NAME}_doc_${f} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${d}) - add_custom_command(TARGET ${PROJECT_NAME}_doc_${f} - COMMAND ${PROJECT_NAME}_doc_${f} > ${CMAKE_CURRENT_SOURCE_DIR}/${d}/${f}.output 2>/dev/null - WORKING_DIRECTORY ${d} - ) - add_dependencies(${PROJECT_NAME}_docs_example_output ${PROJECT_NAME}_doc_${f}) -endforeach() - -# --------------------------------- -# Top Sphinx target -# --------------------------------- -if(NOT DEFINED SPHINXBUILD_EXECUTABLE) - find_package(Sphinx) -endif() - -# Sphinx has internal caching, always run it -add_custom_target(${PROJECT_NAME}_docs_sphinx ALL) -add_custom_command( - TARGET ${PROJECT_NAME}_docs_sphinx - COMMAND ${SPHINXBUILD_EXECUTABLE} -c . -j auto -b html ${CMAKE_CURRENT_SOURCE_DIR} html +# ############ +# Doxygen +find_package(Doxygen REQUIRED) + +# Configure Doxyfile +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) + +# Configure markdown files +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/overview.md.in ${CMAKE_CURRENT_BINARY_DIR}/overview.md @ONLY) + +# Fetch doxygen-awesome-css +include(FetchContent) +FetchContent_Declare(doxyawesome + GIT_REPOSITORY https://github.com/jothepro/doxygen-awesome-css.git + GIT_TAG v2.3.2) +FetchContent_MakeAvailable(doxyawesome) +file(COPY ${doxyawesome_SOURCE_DIR}/doxygen-awesome.css DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +file(COPY ${doxyawesome_SOURCE_DIR}/doxygen-awesome-sidebar-only.css DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +# Add custom target for Doxygen +add_custom_target(doxygen ALL + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating Doxygen documentation" + VERBATIM ) -option(Sphinx_Only "When building the documentation, skip the Python Modules and the generation of C++ Api and example outputs" OFF) -if(NOT Sphinx_Only) - # Generation of C++ Api and Example Outputs - add_dependencies(${PROJECT_NAME}_docs_sphinx ${PROJECT_NAME}_docs_cpp2rst ${PROJECT_NAME}_docs_example_output) -endif() - -# --------------------------------- +# ############ # Install -# --------------------------------- install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ COMPONENT documentation DESTINATION share/doc/${PROJECT_NAME} FILES_MATCHING REGEX "\\.(html|pdf|png|gif|jpg|svg|ico|js|xsl|css|py|txt|inv|bib|ttf|woff2|eot|sh)$" PATTERN "_*" -) +) \ No newline at end of file diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index fc599b5..a3b4f91 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -1,6 +1,4 @@ -(changelog)= - -# Changelog +@page changelog Changelog ## Version 1.2.0 diff --git a/doc/Doxyfile b/doc/Doxyfile.in similarity index 83% rename from doc/Doxyfile rename to doc/Doxyfile.in index d6f6f94..b8b901b 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.9.3 +# Doxyfile 1.11.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -32,19 +42,19 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = TRIQS/itertools +PROJECT_NAME = "TRIQS/@PROJECT_NAME@" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.1.0 +PROJECT_NUMBER = @PROJECT_VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "A single-header C++ library with range-adaptors similar to Python's itertools" +PROJECT_BRIEF = "C++ range library" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 @@ -53,23 +63,41 @@ PROJECT_BRIEF = "A single-header C++ library with range-adaptors simila PROJECT_LOGO = +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = +OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@ -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,14 +109,14 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English @@ -152,7 +180,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@/c++ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -161,7 +189,7 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = @CMAKE_SOURCE_DIR@/c++ # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -331,6 +359,17 @@ MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 5 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -343,8 +382,8 @@ AUTOLINK_SUPPORT = YES # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO @@ -356,9 +395,9 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. +# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse +# them like normal C++ but will assume all classes use public instead of private +# inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO @@ -386,7 +425,7 @@ DISTRIBUTE_GROUP_DOC = NO # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. -GROUP_NESTED_COMPOUNDS = NO +GROUP_NESTED_COMPOUNDS = YES # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that @@ -442,7 +481,7 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing @@ -455,6 +494,14 @@ LOOKUP_CACHE_SIZE = 0 NUM_PROC_THREADS = 1 +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -467,7 +514,7 @@ NUM_PROC_THREADS = 1 # normally produced when WARNINGS is set to YES. # The default value is: NO. -EXTRACT_ALL = YES +EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. @@ -491,7 +538,7 @@ EXTRACT_PACKAGE = NO # included in the documentation. # The default value is: NO. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, @@ -499,7 +546,7 @@ EXTRACT_STATIC = NO # for Java sources. # The default value is: YES. -EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are @@ -536,7 +583,8 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO @@ -567,30 +615,31 @@ INTERNAL_DOCS = NO # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with +# are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. -# The default value is: system dependent. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. -CASE_SENSE_NAMES = YES +CASE_SENSE_NAMES = SYSTEM # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. -HIDE_SCOPE_NAMES = NO +HIDE_SCOPE_NAMES = YES # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. -HIDE_COMPOUND_REFERENCE= NO +HIDE_COMPOUND_REFERENCE = YES # If the SHOW_HEADERFILE tag is set to YES then the documentation for a class # will show which file needs to be included to use the class. @@ -609,7 +658,7 @@ SHOW_INCLUDE_FILES = YES # which file to include in order to use the member. # The default value is: NO. -SHOW_GROUPED_MEMB_INC = NO +SHOW_GROUPED_MEMB_INC = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. @@ -636,7 +685,7 @@ SORT_MEMBER_DOCS = YES # this will also influence the order of the classes in the class list. # The default value is: NO. -SORT_BRIEF_DOCS = NO +SORT_BRIEF_DOCS = YES # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and @@ -648,14 +697,14 @@ SORT_BRIEF_DOCS = NO # detailed member documentation. # The default value is: NO. -SORT_MEMBERS_CTORS_1ST = NO +SORT_MEMBERS_CTORS_1ST = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. -SORT_GROUP_NAMES = NO +SORT_GROUP_NAMES = YES # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will @@ -665,7 +714,7 @@ SORT_GROUP_NAMES = NO # list. # The default value is: NO. -SORT_BY_SCOPE_NAME = NO +SORT_BY_SCOPE_NAME = YES # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between @@ -700,7 +749,7 @@ GENERATE_BUGLIST = YES # the documentation. # The default value is: YES. -GENERATE_DEPRECATEDLIST= YES +GENERATE_DEPRECATEDLIST = YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond @@ -762,7 +811,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = @CMAKE_CURRENT_SOURCE_DIR@/DoxygenLayout.xml # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -826,11 +875,26 @@ WARN_IF_INCOMPLETE_DOC = YES WARN_NO_PARAMDOC = NO +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO @@ -841,10 +905,21 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). In case the file specified cannot be opened for writing the @@ -864,17 +939,30 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ../c++ +INPUT = @CMAKE_CURRENT_SOURCE_DIR@ \ + @CMAKE_CURRENT_BINARY_DIR@ \ + @CMAKE_CURRENT_SOURCE_DIR@/../c++ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). +# See also: INPUT_ENCODING for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -886,14 +974,64 @@ INPUT_ENCODING = UTF-8 # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, -# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C -# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, -# *.vhdl, *.ucf, *.qsf and *.ice. - -FILE_PATTERNS = +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cxxm \ + *.cpp \ + *.cppm \ + *.ccm \ + *.c++ \ + *.c++m \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.ixx \ + *.l \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -931,11 +1069,8 @@ EXCLUDE_PATTERNS = # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # ANamespace::AClass, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = detail +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include @@ -948,7 +1083,7 @@ EXAMPLE_PATH = # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands @@ -978,6 +1113,11 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -1019,6 +1159,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -1030,10 +1179,11 @@ USE_MDFILE_AS_MAINPAGE = # also VERBATIM_HEADERS is set to NO. # The default value is: NO. -SOURCE_BROWSER = NO +SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO @@ -1105,6 +1255,46 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = @CMAKE_CURRENT_BINARY_DIR@/.. + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -1116,10 +1306,11 @@ VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = YES -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1198,10 +1389,16 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = @CMAKE_CURRENT_BINARY_DIR@/doxygen-awesome.css \ + @CMAKE_CURRENT_BINARY_DIR@/doxygen-awesome-sidebar-only.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1213,6 +1410,19 @@ HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generates light mode output, DARK always +# generates dark mode output, AUTO_LIGHT automatically sets the mode according +# to the user preference, uses light mode if no preference is set (the default), +# AUTO_DARK automatically sets the mode according to the user preference, uses +# dark mode if no preference is set and TOGGLE allows a user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see @@ -1243,15 +1453,6 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will @@ -1271,6 +1472,33 @@ HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1401,6 +1629,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1511,7 +1749,7 @@ DISABLE_INDEX = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES # When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the # FULL_SIDEBAR option determines if the side bar is limited to only the treeview @@ -1576,17 +1814,6 @@ HTML_FORMULA_FORMAT = png FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. @@ -1602,7 +1829,7 @@ FORMULA_MACROFILE = # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -USE_MATHJAX = NO +USE_MATHJAX = YES # With MATHJAX_VERSION it is possible to specify the MathJax version to be used. # Note that the different versions of MathJax have different requirements with @@ -1613,7 +1840,7 @@ USE_MATHJAX = NO # The default value is: MathJax_2. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_VERSION = MathJax_2 +MATHJAX_VERSION = MathJax_3 # When MathJax is enabled you can set the default output format to be used for # the MathJax output. For more details about the output format see MathJax @@ -1624,7 +1851,7 @@ MATHJAX_VERSION = MathJax_2 # Possible values are: HTML-CSS (which is slower, but has the best # compatibility. This is the name for Mathjax version 2, for MathJax version 3 # this will be translated into chtml), NativeMML (i.e. MathML. Only supported -# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This # is the name for Mathjax version 3, for MathJax version 2 this will be # translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. @@ -1644,12 +1871,12 @@ MATHJAX_FORMAT = HTML-CSS # - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example -# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html -# #tex-and-latex-extensions): +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # For example for MathJax version 3 (see # http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): @@ -1782,7 +2009,7 @@ LATEX_OUTPUT = latex # the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_CMD_NAME = latex +LATEX_CMD_NAME = # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. @@ -1900,9 +2127,16 @@ PDF_HYPERLINKS = YES USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1923,14 +2157,6 @@ LATEX_HIDE_INDICES = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -2096,13 +2322,39 @@ DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- + +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2177,7 +2429,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2244,15 +2497,15 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2266,16 +2519,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2284,7 +2530,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -2301,37 +2547,55 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" + +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = Helvetica +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a -# graph for each documented class showing the direct and indirect inheritance -# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, -# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set -# to TEXT the direct and indirect inheritance relations will be shown as texts / -# links. -# Possible values are: NO, YES, TEXT and GRAPH. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. CLASS_GRAPH = YES @@ -2339,14 +2603,21 @@ CLASS_GRAPH = YES # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2388,8 +2659,8 @@ DOT_UML_DETAILS = NO # The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters # to display on a single line. If the actual line length exceeds this threshold -# significantly it will wrapped across multiple lines. Some heuristics are apply -# to avoid ugly line breaks. +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. # Minimum value: 0, maximum value: 1000, default value: 17. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2406,7 +2677,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2415,7 +2688,10 @@ INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2455,7 +2731,10 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2471,7 +2750,7 @@ DIR_GRAPH_MAX_DEPTH = 1 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). @@ -2508,11 +2787,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2541,7 +2821,7 @@ PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes # larger than this value, doxygen will truncate the graph, which is visualized -# by representing a node as a red box. Note that doxygen if the number of direct +# by representing a node as a red box. Note that if the number of direct # children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that # the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. @@ -2562,18 +2842,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2601,3 +2869,19 @@ GENERATE_LEGEND = YES # The default value is: YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/doc/DoxygenLayout.xml b/doc/DoxygenLayout.xml new file mode 100644 index 0000000..919cbeb --- /dev/null +++ b/doc/DoxygenLayout.xml @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/_static/css/custom.css b/doc/_static/css/custom.css deleted file mode 100644 index a8c2f1b..0000000 --- a/doc/_static/css/custom.css +++ /dev/null @@ -1,5 +0,0 @@ -@import url("theme.css"); - -.wy-nav-content { - max-width: 70em; -} diff --git a/doc/_static/logo_cea.png b/doc/_static/logo_cea.png deleted file mode 100644 index 1a28b43..0000000 Binary files a/doc/_static/logo_cea.png and /dev/null differ diff --git a/doc/_static/logo_cnrs.png b/doc/_static/logo_cnrs.png deleted file mode 100644 index 53c7af0..0000000 Binary files a/doc/_static/logo_cnrs.png and /dev/null differ diff --git a/doc/_static/logo_erc.jpg b/doc/_static/logo_erc.jpg deleted file mode 100644 index b7181ee..0000000 Binary files a/doc/_static/logo_erc.jpg and /dev/null differ diff --git a/doc/_static/logo_flatiron.png b/doc/_static/logo_flatiron.png deleted file mode 100644 index 9c97b4b..0000000 Binary files a/doc/_static/logo_flatiron.png and /dev/null differ diff --git a/doc/_static/logo_github.png b/doc/_static/logo_github.png deleted file mode 100644 index 54bca71..0000000 Binary files a/doc/_static/logo_github.png and /dev/null differ diff --git a/doc/_static/logo_simons.jpg b/doc/_static/logo_simons.jpg deleted file mode 100644 index 8843123..0000000 Binary files a/doc/_static/logo_simons.jpg and /dev/null differ diff --git a/doc/_static/logo_x.png b/doc/_static/logo_x.png deleted file mode 100644 index 18aba0b..0000000 Binary files a/doc/_static/logo_x.png and /dev/null differ diff --git a/doc/_templates/autosummary_class_template.rst b/doc/_templates/autosummary_class_template.rst deleted file mode 100644 index 49fc678..0000000 --- a/doc/_templates/autosummary_class_template.rst +++ /dev/null @@ -1,29 +0,0 @@ -{{ fullname | escape | underline }} - -.. currentmodule:: {{ module }} - -.. autoclass:: {{ objname }} - -{% block methods %} -{% if methods %} -.. rubric:: {{ _('Methods') }} - -.. autosummary:: - :toctree: - {% for item in methods %} - ~{{ name }}.{{ item }} - {%- endfor %} -{% endif %} -{% endblock %} - -{% block attributes %} -{% if attributes %} -.. rubric:: {{ _('Attributes') }} - -.. autosummary:: - :toctree: - {% for item in attributes %} - ~{{ name }}.{{ item }} - {%- endfor %} -{% endif %} -{% endblock %} diff --git a/doc/_templates/autosummary_module_template.rst b/doc/_templates/autosummary_module_template.rst deleted file mode 100644 index 737206f..0000000 --- a/doc/_templates/autosummary_module_template.rst +++ /dev/null @@ -1,68 +0,0 @@ -{{ fullname | escape | underline}} - -.. automodule:: {{ fullname }} - -{% block functions %} -{% if functions %} -.. rubric:: Functions - -.. autosummary:: - :toctree: - {% for item in functions %} - {{ item }} - {%- endfor %} -{% endif %} -{% endblock %} - -{% block attributes %} -{% if attributes %} -.. rubric:: Module Attributes - -.. autosummary:: - :toctree: - {% for item in attributes %} - {{ item }} - {%- endfor %} -{% endif %} -{% endblock %} - -{% block classes %} -{% if classes %} -.. rubric:: {{ _('Classes') }} - -.. autosummary:: - :toctree: - :template: autosummary_class_template.rst - {% for item in classes %} - {{ item }} - {%- endfor %} -{% endif %} -{% endblock %} - -{% block exceptions %} -{% if exceptions %} -.. rubric:: {{ _('Exceptions') }} - -.. autosummary:: - :toctree: - {% for item in exceptions %} - {{ item }} - {%- endfor %} -{% endif %} -{% endblock %} - -{% block modules %} -{% if modules %} -.. rubric:: Modules - -.. autosummary:: - :toctree: - :template: autosummary_module_template.rst - :recursive: - - {% for item in modules %} - {{ item }} - {%- endfor %} -{% endif %} -{% endblock %} - diff --git a/doc/_templates/sideb.html b/doc/_templates/sideb.html deleted file mode 100644 index 1b7d4f1..0000000 --- a/doc/_templates/sideb.html +++ /dev/null @@ -1,14 +0,0 @@ -

- CEA - Ecole Polytechnique -
- CNRS -ERC - Flatiron Institute -
- Simons Foundation -

-
-

- Visit the project on GitHub -

diff --git a/doc/about.rst b/doc/about.rst deleted file mode 100644 index 7210f03..0000000 --- a/doc/about.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _about: - -About itertools -*************** - -itertools is a single-header C++ library that allows, with a simple interface, for the writing of -various types of range-based for loops. diff --git a/doc/conf.py.in b/doc/conf.py.in deleted file mode 100644 index 205066b..0000000 --- a/doc/conf.py.in +++ /dev/null @@ -1,142 +0,0 @@ -# -*- coding: utf-8 -*- -# -# documentation build configuration file - -import sys -sys.path.insert(0, "@CMAKE_CURRENT_SOURCE_DIR@/sphinxext") -sys.path.insert(0, "@CMAKE_CURRENT_SOURCE_DIR@/sphinxext/numpydoc") - -# exclude these folders from scanning by sphinx -exclude_patterns = ['_templates'] - -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.mathjax', - 'sphinx.ext.intersphinx', - 'sphinx.ext.doctest', - 'sphinx.ext.todo', - 'sphinx.ext.viewcode', - 'sphinx.ext.autosummary', - 'sphinx.ext.githubpages', - 'sphinx_autorun', - 'nbsphinx', - 'myst_parser', - 'matplotlib.sphinxext.plot_directive', - 'numpydoc'] - -myst_enable_extensions = [ - "amsmath", - "colon_fence", - "deflist", - "dollarmath", - "html_admonition", - "html_image", - "linkify", - "replacements", - "smartquotes", - "substitution", - "tasklist", -] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -source_suffix = '.rst' - -# Turn on sphinx.ext.autosummary -autosummary_generate = True -autosummary_imported_members=False - -project = '@PROJECT_NAME@ - A lightweight C++ library to alter C++ ranges' -version = '@PROJECT_VERSION@' - -# this makes the current project version available as var in every rst file -rst_epilog = """ -.. |PROJECT_VERSION| replace:: {version} -""".format( -version = version, -) - -copyright = '2018-2021 The Simons Foundation, authors: A. Hampel, O. Parcollet, D. Simons, H. Strand, N. Wentzell' - -mathjax_path = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=default" -templates_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_templates'] - -# this requires the sphinx_rtd_theme to be installed via pip -html_theme = 'sphinx_rtd_theme' -# this loads the custom css file to change the page width -html_style = 'css/custom.css' - -# options for the the rtd theme -html_theme_options = { - 'logo_only': False, - 'display_version': True, - 'prev_next_buttons_location': 'bottom', - 'style_external_links': False, - 'vcs_pageview_mode': '', - 'style_nav_header_background': '#7E588A', - # Toc options - 'collapse_navigation': False, - 'sticky_navigation': True, - 'navigation_depth': 5, - 'includehidden': True, - 'titles_only': False -} - -html_show_sphinx = False - -html_context = {'header_title': '@PROJECT_NAME@'} - -html_static_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_static'] -html_sidebars = {'index': ['sideb.html', 'searchbox.html']} - -htmlhelp_basename = '@PROJECT_NAME@doc' - -# Plot options -plot_include_source = True -plot_html_show_source_link = False -plot_html_show_formats = False - -intersphinx_mapping = {'python': ('https://docs.python.org/3.11', None)} - -# open links in new tab instead of same window -from sphinx.writers.html import HTMLTranslator -from docutils import nodes -from docutils.nodes import Element - -class PatchedHTMLTranslator(HTMLTranslator): - - def visit_reference(self, node: Element) -> None: - atts = {'class': 'reference'} - if node.get('internal') or 'refuri' not in node: - atts['class'] += ' internal' - else: - atts['class'] += ' external' - # --------------------------------------------------------- - # Customize behavior (open in new tab, secure linking site) - atts['target'] = '_blank' - atts['rel'] = 'noopener noreferrer' - # --------------------------------------------------------- - if 'refuri' in node: - atts['href'] = node['refuri'] or '#' - if self.settings.cloak_email_addresses and atts['href'].startswith('mailto:'): - atts['href'] = self.cloak_mailto(atts['href']) - self.in_mailto = True - else: - assert 'refid' in node, \ - 'References must have "refuri" or "refid" attribute.' - atts['href'] = '#' + node['refid'] - if not isinstance(node.parent, nodes.TextElement): - assert len(node) == 1 and isinstance(node[0], nodes.image) - atts['class'] += ' image-reference' - if 'reftitle' in node: - atts['title'] = node['reftitle'] - if 'target' in node: - atts['target'] = node['target'] - self.body.append(self.starttag(node, 'a', '', **atts)) - - if node.get('secnumber'): - self.body.append(('%s' + self.secnumber_suffix) % - '.'.join(map(str, node['secnumber']))) - -def setup(app): - app.set_translator('html', PatchedHTMLTranslator) diff --git a/doc/documentation.md b/doc/documentation.md new file mode 100644 index 0000000..15f7010 --- /dev/null +++ b/doc/documentation.md @@ -0,0 +1,97 @@ +@page documentation API Documentation + +[TOC] + +The following provides a detailed reference documentation grouped into logical units. + +For most users of the library it should be sufficient to either use one of the @ref range_adapting_functions or +an @ref integer_range. + +If you are looking for a specific function, class, etc., try using the search bar in the top left corner. + +## Range adapting functions + +@ref range_adapting_functions take one or more existing ranges and return lazy @ref adapted_ranges that +can be iterated over. +Lazy means that new elements are produced on the fly whenever they are needed instead of being precomputed +when the range is created. + +The following range adpating functions are available in **itertools**: + +* @ref itertools::enumerate "enumerate" +* @ref itertools::make_product "make_product" +* @ref itertools::product "product" +* @ref itertools::slice "slice" +* @ref itertools::stride "stride" +* @ref itertools::transform "transform" +* @ref itertools::zip "zip" + +## Adapted ranges + +@ref adapted_ranges are returned by the range adapting functions and can be iterated over using one of the +@ref range_iterators. +In most cases, the user will never have to create or modify an adapted range directly. +Instead, it is recommended to simply use the provided @ref range_adapting_functions. + +The following adapted ranges are defined in **itertools**: + +* @ref itertools::detail::enumerated "enumerated" +* @ref itertools::detail::multiplied "multiplied" +* @ref itertools::detail::sliced "sliced" +* @ref itertools::detail::strided "strided" +* @ref itertools::detail::transformed "transformed" +* @ref itertools::detail::zipped "zipped" + +## Range iterators + +@ref range_iterators are internally used by the library to iterate over @ref adapted_ranges. +In general, there should be no need for users to deal with range iterators directly. +Instead, it is recommended to use range-based for loops, e.g. +```cpp +for (auto [idx, val] : itertools::enumerate(some_range)) { + // do something with the index and the value of the range +} +``` +vs. the traditional for loops, e.g. +```cpp +auto enum_range = itertools::enumerate(some_range); +for (auto it = enum_range.begin(); it != enum_range.end(); ++it) { + // do something with the iterator +} +``` + +The following range iterators are defined in **itertools**: + +* @ref itertools::detail::enum_iter "enum_iter" +* @ref itertools::detail::prod_iter "prod_iter" +* @ref itertools::detail::stride_iter "stride_iter" +* @ref itertools::detail::transform_iter "transform_iter" +* @ref itertools::detail::zip_iter "zip_iter" + +## Integer range + +An @ref integer_range is similar to a Python `range`. +It is defined by a start value, an end value and a step size such that the i-th value of the range is given by +`start + i * step`. + +The following classes and functions related to integer ranges are defined in **itertools**: + +* @ref itertools::range "range" +* @ref itertools::foreach "foreach" +* @ref itertools::product_range "product_range" + +## Utilities + +@ref utilities are mostly internal implementation details and should not concern everyday users. +The only functions the might be intersting to some users are: @ref itertools::chunk_range "chunk_range", +@ref itertools::make_vector_from_range "make_vector_from_range" and @ref itertools::omp_chunk "omp_chunk". + +The following utilities are defined in **itertools**: + +* @ref itertools::chunk_range "chunk_range" +* @ref itertools::distance "distance" +* @ref itertools::iterator_facade "iterator_facade" +* @ref itertools::make_sentinel "make_sentinel" +* @ref itertools::make_vector_from_range "make_vector_from_range" +* @ref itertools::omp_chunk "omp_chunk" +* @ref itertools::sentinel_t "sentinel_t" \ No newline at end of file diff --git a/doc/documentation.rst b/doc/documentation.rst deleted file mode 100644 index a196de6..0000000 --- a/doc/documentation.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _documentation: - -Documentation -************* - - -.. math:: - - (a + b)^2 &= (a + b)(a + b) \\ - &= a^2 + 2ab + b^2 - - -C++ reference manual -==================== - -.. toctree:: - :maxdepth: 5 - - cpp2rst_generated/contents diff --git a/doc/ex1.md b/doc/ex1.md new file mode 100644 index 0000000..3ca9190 --- /dev/null +++ b/doc/ex1.md @@ -0,0 +1,68 @@ +@page ex1 Example 1: Comparison with std::ranges + +[TOC] + +In this example, we compare **itertools**'s adapted ranges with their counterparts from `std::ranges`. + +```cpp +#include "./print.hpp" + +#include +#include +#include +#include + +int main() { + // we use the following vector and array as our base ranges for the examples + std::vector vec {1, 2, 3, 4, 5, 6}; + std::array arr {'a', 'b'}; + + // compare itertools::enumerate with std::views::enumerate (only available in c++23 with gcc>=13) + print_tuple_range(itertools::enumerate(arr)); + print_tuple_range(std::views::enumerate(arr)); + + // compare itertools::transform with std::views::transform + auto square = [](int i) { return i * i; }; + print_simple_range(itertools::transform(vec, square)); + print_simple_range(std::views::transform(vec, square)); + + // compare itertools::zip with std::views::zip + print_tuple_range(itertools::zip(vec, arr)); + print_tuple_range(std::views::zip(vec, arr)); + + // compare itertools::product with std::views::cartesian_product (only available in c++23 with gcc>=13) + print_tuple_range(itertools::product(vec, arr)); + print_tuple_range(std::views::cartesian_product(vec, arr)); + + // compare itertools::stride with std::views::stride (only available in c++23 with gcc>=13) + print_simple_range(itertools::stride(vec, 2)); + print_simple_range(std::views::stride(vec, 2)); + + // compare itertools::slice with std::views::counted + print_simple_range(itertools::slice(vec, 1, 5)); + print_simple_range(std::views::counted(vec.begin() + 1, 4)); + + // compare itertools::range with std::views::iota (only available in c++23 with gcc>=13) + print_simple_range(itertools::range(10, 20, 2)); + print_simple_range(std::views::iota(10, 20) | std::views::stride(2)); +} +``` + +Output: + +``` +(0, a) (1, b) +(0, a) (1, b) +1 4 9 16 25 36 +1 4 9 16 25 36 +(1, a) (2, b) +(1, a) (2, b) +(1, a) (1, b) (2, a) (2, b) (3, a) (3, b) (4, a) (4, b) (5, a) (5, b) (6, a) (6, b) +(1, a) (1, b) (2, a) (2, b) (3, a) (3, b) (4, a) (4, b) (5, a) (5, b) (6, a) (6, b) +1 3 5 +1 3 5 +2 3 4 5 +2 3 4 5 +10 12 14 16 18 +10 12 14 16 18 +``` \ No newline at end of file diff --git a/doc/examples.md b/doc/examples.md new file mode 100644 index 0000000..99f95cd --- /dev/null +++ b/doc/examples.md @@ -0,0 +1,80 @@ +@page examples Examples + +[TOC] + +- @ref ex1 "Example 1: Comparison with std::ranges" + +@section compiling Compiling the examples + +All examples have been compiled on a MacBook Pro with an Apple M2 Max chip. +At the point of writing this documentation only gcc-13 has implemented the required `std::ranges` for some of the examples. +We therefore used gcc 13.2.0 together with cmake 3.27.2. + +Assuming that the actual example code is in a file `main.cpp` and that the `print.hpp` (see below) is in the same directory, the following generic `CMakeLists.txt` should work for all examples: + +```cmake +cmake_minimum_required(VERSION 3.20) +project(example CXX) + +# set required standard (needed for some std::ranges) +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# fetch itertools from github +set(Build_Tests OFF CACHE BOOL "" FORCE) +include (FetchContent) +FetchContent_Declare( + itertools + GIT_REPOSITORY https://github.com/TRIQS/itertools.git + GIT_TAG 1.2.x +) +FetchContent_MakeAvailable(itertools) + +# build the example +add_executable(ex main.cpp) +target_link_libraries(ex itertools::itertools_c) +``` + +@subsection print_header print.hpp + +To print the elements of a range to `stdout`, we used the following header: + +```cpp +#include +#include +#include + +// helper function to pretty-print a tuple/array +template +void print_impl(const T& tup, std::index_sequence) { + std::cout << "("; + (..., (std::cout << (I == 0? "" : ", ") << std::get(tup))); + std::cout << ")"; +} + +// print a tuple/array to std::cout +template +void print_tuple(const T& tup) { + print_impl(tup, std::make_index_sequence>()); +} + +// print a range of tuple elements to std::cout +template +void print_tuple_range(R&& rg) { + for (auto&& x : rg) { + print_tuple(x); + std::cout << " "; + } + std::cout << std::endl; +} + +// print a range of simple elements to std::cout +template +void print_simple_range(R&& rg) { + for (auto&& x : rg) { + std::cout << x << " "; + } + std::cout << std::endl; +} +``` \ No newline at end of file diff --git a/doc/groups.dox b/doc/groups.dox new file mode 100644 index 0000000..00ede52 --- /dev/null +++ b/doc/groups.dox @@ -0,0 +1,53 @@ +/** + * @defgroup range_adapting_functions Range adapting functions + * @brief Range adapting functions take one or more existing ranges and return lazy @ref adapted_ranges that + * can be iterated over. + * + * @details Lazy means that new elements are produced on the fly whenever they are needed instead of being precomputed + * when the range is created. + */ + +/** + * @defgroup adapted_ranges Adapted ranges + * @brief Adapted ranges are returned by the range adapting functions and can be iterated over using one of the + * @ref range_iterators. + * + * @details In most cases, the user will never have to create or modify an adapted range directly. + * Instead, it is recommended to simply use the provided @ref range_adapting_functions. + */ + +/** + * @defgroup range_iterators Range iterators + * @brief Range iterators are internally used by the library to iterate over @ref adapted_ranges. + * + * @details In general, there should be no need for users to deal with range iterators directly. + * Instead, it is recommended to use range-based for loops, e.g. + * ```cpp + * for (auto [idx, val] : itertools::enumerate(some_range)) { + * // do something with the index and the value of the range + * } + * ``` + * vs. the traditional for loops, e.g. + * ```cpp + * auto enum_range = itertools::enumerate(some_range); + * for (auto it = enum_range.begin(); it != enum_range.end(); ++it) { + * // do something with the iterator + * } + * ``` + */ + +/** + * @defgroup integer_range Integer range + * @brief An integer range is similar to a Python `range`. + * + * @details It is defined by a start value, an end value and a step size such that the i-th value of the range is given by + * `start + i * step`. + */ + +/** + * @defgroup utilities Utilities + * @brief Utilities are mostly internal implementation details and should not concern everyday users. + * + * @details The only functions the might be intersting to some users are: @ref itertools::chunk_range "chunk_range", + * @ref itertools::make_vector_from_range "make_vector_from_range" and @ref itertools::omp_chunk "omp_chunk". + */ \ No newline at end of file diff --git a/doc/index.rst b/doc/index.rst deleted file mode 100644 index dc20d4c..0000000 --- a/doc/index.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. _welcome: - -itertools -********* - -.. sidebar:: itertools |PROJECT_VERSION| - - This is the homepage of itertools |PROJECT_VERSION|. - For changes see the :ref:`changelog page `. - - .. image:: _static/logo_github.png - :width: 75% - :align: center - :target: https://github.com/triqs/itertools - -itertools is a single-header C++ library that allows, with a simple interface, for the writing of -various types of range-based for loops. - -This documentation is generated based on `rst `_ files -and the comments in the sources and headers. - -Learn how to use itertools in the :ref:`documentation`. - - -.. toctree:: - :maxdepth: 2 - :hidden: - - install - documentation - issues - ChangeLog.md - about diff --git a/doc/install.rst b/doc/install.rst deleted file mode 100644 index 275b8dc..0000000 --- a/doc/install.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. highlight:: bash - -.. _install: - -Install itertools -***************** - -Compiling itertools from source -=============================== - -.. note:: To guarantee reproducibility in scientific calculations we strongly recommend the use of a stable `release `_ of itertools. - -Installation steps ------------------- - -#. Download the source code of the latest stable version by cloning the ``TRIQS/itertools`` repository from GitHub:: - - $ git clone https://github.com/TRIQS/itertools itertools.src - -#. Create and move to a new directory where you will compile the code:: - - $ mkdir itertools.build && cd itertools.build - -#. In the build directory call cmake, including any additional custom CMake options, see below:: - - $ cmake -DCMAKE_INSTALL_PREFIX=path_to_install_dir ../itertools.src - -#. Compile the code, run the tests and install the application:: - - $ make - $ make test - $ make install - -Versions --------- - -To use a particular version, go into the directory with the sources, and look at all available versions:: - - $ cd itertools.src && git tag - -Checkout the version of the code that you want:: - - $ git checkout 2.1.0 - -and follow steps 2 to 4 above to compile the code. - -Custom CMake options --------------------- - -The compilation of ``itertools`` can be configured using CMake-options:: - - cmake ../itertools.src -DOPTION1=value1 -DOPTION2=value2 ... - -+-----------------------------------------+-----------------------------------------------+ -| Options | Syntax | -+=========================================+===============================================+ -| Specify an installation path | -DCMAKE_INSTALL_PREFIX=path_to_itertools | -+-----------------------------------------+-----------------------------------------------+ -| Build in Debugging Mode | -DCMAKE_BUILD_TYPE=Debug | -+-----------------------------------------+-----------------------------------------------+ -| Disable testing (not recommended) | -DBuild_Tests=OFF | -+-----------------------------------------+-----------------------------------------------+ -| Build the documentation | -DBuild_Documentation=ON | -+-----------------------------------------+-----------------------------------------------+ diff --git a/doc/installation.md b/doc/installation.md new file mode 100644 index 0000000..6ae2f0c --- /dev/null +++ b/doc/installation.md @@ -0,0 +1,85 @@ +@page installation Installation + +[TOC] + +**itertools** is a header only library and installation is not necessary. +However, it still supports the usual installation procedure using CMake. + +If you want to skip the installation step, you can go directly to @ref integration to see how you can integrate +**itertools** into your own C++ project. + +> **Note:** To guarantee reproducibility in scientific calculations, we strongly recommend the use of a stable +> [release version](https://github.com/TRIQS/itertools/releases). + +@section dependencies Dependencies + +The dependencies of **itertools** are as follows: + +* gcc version 12 or later OR clang version 15 or later OR IntelLLVM (icx) 2023.1.0 or later +* CMake version 3.20 or later (for installation or integration into an existing project via CMake) + +@section install_steps Installation steps + +1. Download the source code of the latest stable version by cloning the [TRIQS/itertools](https://github.com/triqs/itertools) +repository from GitHub: + + ```console + $ git clone https://github.com/TRIQS/itertools itertools.src + ``` + +2. Create and move to a new directory where you will compile the code: + + ```console + $ mkdir itertools.build && cd itertools.build + ``` + +3. In the build directory call cmake, including any additional custom CMake options (see below): + + ```console + $ cmake -DCMAKE_INSTALL_PREFIX=path_to_install_dir ../itertools.src + ``` + + Note that it is required to specify ``CMAKE_INSTALL_PREFIX``, otherwise CMake will stop with an error. + +4. Compile the code, run the tests and install the application: + + ```console + $ make -j N + $ make test + $ make install + ``` + + Replace `N` with the number of cores you want to use to build the library. + +@section versions Versions + +To use a particular version, go into the directory with the sources, and look at all available versions: + +```console +$ cd itertools.src && git tag +``` + +Checkout the version of the code that you want: + +```console +$ git checkout 1.2.0 +``` + +and follow steps 2 to 4 to compile the code. + +@section cmake_options Custom CMake options + +The compilation of **itertools** can be configured using CMake options + +```console +$ cmake ../itertools.src -DOPTION1=value1 -DOPTION2=value2 ... +``` + + +| Options | Syntax | +|-----------------------------------------|---------------------------------------------------| +| Specify an installation path | ``-DCMAKE_INSTALL_PREFIX=path_to_install_dir`` | +| Build in Debugging Mode | ``-DCMAKE_BUILD_TYPE=Debug`` | +| Disable testing (not recommended) | ``-DBuild_Tests=OFF`` | +| Build the documentation | ``-DBuild_Documentation=ON`` | +| Build benchmarks | ``-DBuild_Benchs=ON`` | diff --git a/doc/integration.md b/doc/integration.md new file mode 100644 index 0000000..4c9bc35 --- /dev/null +++ b/doc/integration.md @@ -0,0 +1,96 @@ +@page integration Integration in C++ projects + +[TOC] + +**itertools** is a header only library. +To use it in your own `C++` code, you simply have to include the following header + +```cpp +#include + +// use itertools +``` + +and tell your compiler/build system where it can find the necessary files. +In the following, we describe some common ways to achieve this (with special focus on CMake). + +@section cmake CMake + +@subsection fetch FetchContent + +If you use [CMake](https://cmake.org/) to build your source code, it is recommended to fetch the source code directly from the +[Github repository](https://github.com/TRIQS/itertools) using CMake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) +module: + +```cmake +cmake_minimum_required(VERSION 3.20) +project(my_project CXX) + +# fetch from github +include (FetchContent) +FetchContent_Declare( + itertools + GIT_REPOSITORY https://github.com/TRIQS/itertools.git + GIT_TAG 1.2.x +) +FetchContent_MakeAvailable(itertools) + +# declare a target and link to itertools +add_executable(my_executable main.cpp) +target_link_libraries(my_executable itertools::itertools_c) +``` + +Note that the above will also build [goolgetest](https://github.com/google/googletest) and the unit tests for **itertools**. +To disable this, you can put `set(Build_Tests OFF CACHE BOOL "" FORCE)` before fetching the content. + +@subsection find_package find_package + +If you have already installed **itertools** on your system by following the instructions from the @ref installation page, you can also make +use of CMake's [find_package](https://cmake.org/cmake/help/latest/command/find_package.html) command. +This has the advantage that you don't need to download anything, i.e. no internet connection is required. + +Let's assume that **itertools** has been installed to `path_to_install_dir`. +Then linking your project to **itertools** with CMake is as easy as + +```cmake +cmake_minimum_required(VERSION 3.20) +project(my_project CXX) + +# find itertools +find_package(itertools REQUIRED) + +# declare a target and link to itertools +add_executable(my_executable main.cpp) +target_link_libraries(my_executable itertools::itertools_c) +``` + +In case, CMake cannot find the package, you might have to tell it where to look for the `itertools-config.cmake` file by setting the variable +`itertools_DIR` to `path_to_install_dir/lib/cmake/itertools` or by sourcing the provided `itertoolsvars.sh` before running CMake: + +```console +$ source path_to_install_dir/share/itertools/itertoolsvars.sh +``` + +@subsection add_sub add_subdirectory + +You can also integrate **itertools** into our CMake project by placing the entire source tree in a subdirectory and call `add_subdirectory()`: + +```cmake +cmake_minimum_required(VERSION 3.20) +project(my_project CXX) + +# add itertools subdirectory +add_subdirectory(deps/itertools) + +# declare a target and link to itertools +add_executable(my_executable main.cpp) +target_link_libraries(my_executable itertools::itertools_c) +``` + +Here, it is assumed that the **itertools** source tree is in a subdirectory `deps/itertools` relative to your `CMakeLists.txt` file. + +@section other Other + +Since **itertools** is header-only, you can also simply copy the relevant files directly into our project. +For example, you could place the `c++/itertools` directory from the **itertools** source tree into the include path of your project. +You can then build or compile it with any available method. diff --git a/doc/issues.md b/doc/issues.md new file mode 100644 index 0000000..062876f --- /dev/null +++ b/doc/issues.md @@ -0,0 +1,21 @@ +@page issues Issues + +[TOC] + +Please report all problems and bugs directly at the [GitHub issues page](https://github.com/TRIQS/itertools/issues). +In order to make it easier for us to solve the issue please follow these guidelines: + +1. In all cases specify which version of the application you are using. You can + find the version number in the file `CMakeLists.txt` at the root of the + application sources. + +2. If you have a problem during the installation, give us information about + your operating system and the compiler you are using. Include the outputs of + the `cmake` and `make` commands as well as the `CMakeCache.txt` file + which is in the build directory. Please include these outputs in a + [gist](http://gist.github.com/>) file referenced in the issue. + +3. If you are experiencing a problem during the execution of the application, provide + a script which allows to quickly reproduce the problem. + +Thanks! \ No newline at end of file diff --git a/doc/issues.rst b/doc/issues.rst deleted file mode 100644 index 57f8807..0000000 --- a/doc/issues.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. _issues: - -Reporting issues -**************** - -Please report all problems and bugs directly at the github issue page -``_. In order to make it easier for us -to solve the issue please follow these guidelines: - -#. In all cases specify which version of the application you are using. You can - find the version number in the file :file:`CMakeLists.txt` at the root of the - application sources. - -#. If you have a problem during the installation, give us information about - your operating system and the compiler you are using. Include the outputs of - the ``cmake`` and ``make`` commands as well as the ``CMakeCache.txt`` file - which is in the build directory. Please include these outputs in a - `gist `_ file referenced in the issue. - -#. If you are experiencing a problem during the execution of the application, provide - a script which allows to quickly reproduce the problem. - -Thanks! diff --git a/doc/overview.md.in b/doc/overview.md.in new file mode 100644 index 0000000..7ad5ed4 --- /dev/null +++ b/doc/overview.md.in @@ -0,0 +1,90 @@ +@mainpage Overview + +[TOC] + +[![build](https://github.com/TRIQS/itertools/workflows/build/badge.svg?branch=unstable)](https://github.com/TRIQS/itertools/actions?query=workflow%3Abuild) + +> This is the homepage of **TRIQS/itertools @PROJECT_VERSION@**. The source code can be found on [GitHub](https://github.com/TRIQS/itertools). + + +```cpp +#include +#include + +using namespace itertools; + +int main() { + + // ===== Integer ranges ===== + + for(int i: range(10)) { /* 0, 1, .., 9 */ } + + for(int i: range(2, 10, 2)) { /* 2, 4, 6, 8 */ } + + for (auto [i, j] : product_range(5, 5)) { + /* (0, 0), (0, 1), .. (0, 4), + (1, 0), (1, 2), .. (1, 4), + ... + (4, 0), (4, 2), .. (4, 4) */ + } + + // ===== Adapted ranges ===== + + std::vector Vc{'a', 'b', 'c'}; + + for (auto [i, c] : enumerate(Vc)) { + /* (0, 'a'), (1, 'b'), (2, 'c') */ + } + + std::vector Vd{2.0, 4.0, 1.0}; + + for (auto [c, d] : zip(Vc, Vd)) { + /* ('a', 2.0), ('b', 4.0), ('c', 1.0) */ + } + + for (auto [c, d] : product(Vc, Vd)) { + /* ('a', 2.0), ('a', 4.0), ('a', 1.0), + ('b', 2.0), ('b', 4.0), ('b', 1.0), + ('c', 2.0), ('c', 4.0), ('c', 1.0) */ + } + + for (auto x : transform(Vd, [](auto d){ return d * d; })) { + /* 4.0, 16.0, 1.0 */ + } + +} +``` + +**itertools** defines a small subset of the ranges and views from [std::ranges](https://en.cppreference.com/w/cpp/ranges). +The main purpose of the library is to provide lazy ranges +* that can be iterated over in range-based for loops (see example above) and +* that can be used to make lazy views of multidimensional arrays + ```cpp + #include + + int main() { + // create a 10 x 10 matrix + auto A = nda::matrix::rand(10, 10); + + // create a view on the 5 x 10 submatrix consisting of every other row + auto sub_A = A(nda::range(0, 10, 2), nda::range::all); + } + ``` + Visit [TRIQS/nda](https://github.com/TRIQS/nda) for more details. + +Note that nearly all of the functionality (and much more) of **itertools** is also provided by [std::ranges](https://en.cppreference.com/w/cpp/ranges) +or Eric Niebler's [range-v3](https://github.com/ericniebler/range-v3) library. +We therefore recommend to use one of those, if you have a choice. + +@section start Where to start? + +The @ref installation section tells you how to get the library and make it available on your system. + +@ref integration explains how to integrate **itertools** in your own C++ code. + +Then, you can start with the @ref examples section to get an overview of the library's features and how +it compares with `std::ranges`. + +Furthermore, we provide a detailed reference @ref documentation to answer your questions. + +If you experience any problem with the library, you can post an @ref issues "Issue" on GitHub. diff --git a/doc/sphinxext/sphinx_autorun/__init__.py b/doc/sphinxext/sphinx_autorun/__init__.py deleted file mode 100644 index 1afa037..0000000 --- a/doc/sphinxext/sphinx_autorun/__init__.py +++ /dev/null @@ -1,93 +0,0 @@ -# -*- coding: utf-8 -*- -""" -sphinxcontirb.autorun -~~~~~~~~~~~~~~~~~~~~~~ - -Run the code and insert stdout after the code block. -""" -import os -from subprocess import PIPE, Popen - -from docutils import nodes -from docutils.parsers.rst import Directive, directives -from sphinx.errors import SphinxError - -from sphinx_autorun import version - -__version__ = version.version - - -class RunBlockError(SphinxError): - category = 'runblock error' - - -class AutoRun(object): - here = os.path.abspath(__file__) - pycon = os.path.join(os.path.dirname(here), 'pycon.py') - config = { - 'pycon': 'python ' + pycon, - 'pycon_prefix_chars': 4, - 'pycon_show_source': False, - 'console': 'bash', - 'console_prefix_chars': 1, - } - - @classmethod - def builder_init(cls, app): - cls.config.update(app.builder.config.autorun_languages) - - -class RunBlock(Directive): - has_content = True - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = False - option_spec = { - 'linenos': directives.flag, - } - - def run(self): - config = AutoRun.config - language = self.arguments[0] - - if language not in config: - raise RunBlockError('Unknown language %s' % language) - - # Get configuration values for the language - args = config[language].split() - input_encoding = config.get(language+'_input_encoding', 'utf8') - output_encoding = config.get(language+'_output_encoding', 'utf8') - prefix_chars = config.get(language+'_prefix_chars', 0) - show_source = config.get(language+'_show_source', True) - - # Build the code text - proc = Popen(args, bufsize=1, stdin=PIPE, stdout=PIPE, stderr=PIPE) - codelines = (line[prefix_chars:] for line in self.content) - code = u'\n'.join(codelines).encode(input_encoding) - - # Run the code - stdout, stderr = proc.communicate(code) - - # Process output - if stdout: - out = stdout.decode(output_encoding) - if stderr: - out = stderr.decode(output_encoding) - - # Get the original code with prefixes - if show_source: - code = u'\n'.join(self.content) - code_out = u'\n'.join((code, out)) - else: - code_out = out - - literal = nodes.literal_block(code_out, code_out) - literal['language'] = language - literal['linenos'] = 'linenos' in self.options - return [literal] - - -def setup(app): - app.add_directive('runblock', RunBlock) - app.connect('builder-inited', AutoRun.builder_init) - app.add_config_value('autorun_languages', AutoRun.config, 'env') diff --git a/doc/sphinxext/sphinx_autorun/pycon.py b/doc/sphinxext/sphinx_autorun/pycon.py deleted file mode 100644 index c0edf86..0000000 --- a/doc/sphinxext/sphinx_autorun/pycon.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys -from code import InteractiveInterpreter - - -def main(): - """ - Print lines of input along with output. - """ - source_lines = (line.rstrip() for line in sys.stdin) - console = InteractiveInterpreter() - source = '' - try: - while True: - source = next(source_lines) - # Allow the user to ignore specific lines of output. - if not source.endswith('# ignore'): - print('>>>', source) - more = console.runsource(source) - while more: - next_line = next(source_lines) - print('...', next_line) - source += '\n' + next_line - more = console.runsource(source) - except StopIteration: - if more: - print('... ') - more = console.runsource(source + '\n') - - -if __name__ == '__main__': - main() diff --git a/doc/sphinxext/sphinx_autorun/version.py b/doc/sphinxext/sphinx_autorun/version.py deleted file mode 100644 index 433d173..0000000 --- a/doc/sphinxext/sphinx_autorun/version.py +++ /dev/null @@ -1,4 +0,0 @@ -# coding: utf-8 -# file generated by setuptools_scm -# don't change, don't track in version control -version = '1.1.1' diff --git a/doc/sphinxext/triqs_example/triqs_example.py b/doc/sphinxext/triqs_example/triqs_example.py deleted file mode 100644 index 2c90ac4..0000000 --- a/doc/sphinxext/triqs_example/triqs_example.py +++ /dev/null @@ -1,123 +0,0 @@ -import tempfile -# -*- coding: utf-8 -*- -# seems to be executed at the level of the conf.py -# so we need to link the lib at that place... -""" -""" -import os -import codecs -from os import path -from subprocess import Popen,PIPE -from docutils import nodes -from docutils.parsers.rst import Directive -from docutils.parsers.rst import directives -from sphinx.errors import SphinxError - -class TriqsExampleError(SphinxError): - category = 'triqs_example error' - -class TriqsExampleRun: - #here = os.path.abspath(__file__) - #pycon = os.path.join(os.path.dirname(here),'pycon.py') - config = dict( - ) - @classmethod - def builder_init(cls,app): - #cls.config.update(app.builder.config.autorun_languages) - #cls.config.update(app.builder.config.autocompile_opts) - pass - -class TriqsExample(Directive): - has_content = True - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = False - option_spec = { - 'linenos': directives.flag, - } - - def run(self): - document = self.state.document - filename = self.arguments[0] - if not document.settings.file_insertion_enabled: - return [document.reporter.warning('File insertion disabled', - line=self.lineno)] - env = document.settings.env - if filename.startswith('/') or filename.startswith(os.sep): - rel_fn = filename[1:] - else: - docdir = path.dirname(env.doc2path(env.docname, base=None)) - rel_fn = path.normpath(path.join(docdir, filename)) - try: - fn = path.join(env.srcdir, rel_fn) - except UnicodeDecodeError: - # the source directory is a bytestring with non-ASCII characters; - # let's try to encode the rel_fn in the file system encoding - rel_fn = rel_fn.encode(sys.getfilesystemencoding()) - fn = path.join(env.srcdir, rel_fn) - - encoding = self.options.get('encoding', env.config.source_encoding) - try: - f = codecs.open(fn, 'rU', encoding) - lines = f.readlines() - f.close() - except (IOError, OSError): - return [document.reporter.warning( - 'Include file %r not found or reading it failed' % filename, - line=self.lineno)] - except UnicodeError: - return [document.reporter.warning( - 'Encoding %r used for reading included file %r seems to ' - 'be wrong, try giving an :encoding: option' % - (encoding, filename))] - - config = TriqsExampleRun.config - - # Get configuration values for the language - input_encoding = 'utf8' #config.get(language+'_input_encoding','ascii') - output_encoding = 'utf8' #config.get(language+'_output_encoding','ascii') - show_source = True - - # Build the code text - code = ''.join(lines).strip() - filename_clean = filename.rsplit('.',1)[0] - if filename_clean.startswith('./') : filename_clean = filename_clean[2:] - #print "Running the example ....",filename_clean - #print "Root ?", env.doc2path(env.docname, base=None) - - import subprocess as S - error = True - try : - stdout ='' - #resout = S.check_output("./example_bin/doc_%s"%(filename_clean) ,stderr=S.STDOUT,shell=True) - resout = S.check_output("./%s/doc_%s"%(docdir,filename_clean) ,stderr=S.STDOUT,shell=True) - if resout : - stdout = '---------- Result is -------\n' + resout.strip() - error = False - except S.CalledProcessError as E : - stdout ='---------- RunTime error -------\n' - stdout += E.output - - # Process output - if stdout: - stdout = stdout.decode(output_encoding,'ignore') - out = ''.join(stdout).decode(output_encoding) - else: - out = '' #.join(stderr).decode(output_encoding) - - # Get the original code with prefixes - code_out = '\n'.join((code,out)) - - if error : # report on console - print(" Error in processing ") - print(code_out) - - literal = nodes.literal_block(code_out,code_out) - literal['language'] = 'c' - literal['linenos'] = 'linenos' in self.options - return [literal] - -def setup(app): - app.add_directive('triqs_example', TriqsExample) - app.connect('builder-inited',TriqsExampleRun.builder_init) - diff --git a/doc/themes/triqs/layout.html b/doc/themes/triqs/layout.html deleted file mode 100644 index 0275e11..0000000 --- a/doc/themes/triqs/layout.html +++ /dev/null @@ -1,52 +0,0 @@ -{# - layout.html - ~~~~~~~~~~~ - - TRIQS layout template heavily based on the sphinxdoc theme. - - :copyright: Copyright 2013 by the TRIQS team. - :copyright: Copyright 2007-2013 by the Sphinx team. - :license: BSD, see LICENSE for details. -#} -{%- extends "basic/layout.html" %} - -{# put the sidebar before the body #} -{% block sidebar1 %}{{ sidebar() }}{% endblock %} -{% block sidebar2 %}{% endblock %} - -{% block extrahead %} - - - - -{{ super() }} -{%- if not embedded %} - -{%- endif %} -{% endblock %} - -{% block rootrellink %} -
  • Home »
  • -{% endblock %} - -{% block header %} - -{% endblock %} diff --git a/doc/themes/triqs/static/bodybg.png b/doc/themes/triqs/static/bodybg.png deleted file mode 100644 index 506b6f9..0000000 Binary files a/doc/themes/triqs/static/bodybg.png and /dev/null differ diff --git a/doc/themes/triqs/static/cufon-yui.js b/doc/themes/triqs/static/cufon-yui.js deleted file mode 100644 index 935614e..0000000 --- a/doc/themes/triqs/static/cufon-yui.js +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright (c) 2009 Simo Kinnunen. - * Licensed under the MIT license. - * - * @version 1.09i - */ -var Cufon=(function(){var m=function(){return m.replace.apply(null,arguments)};var x=m.DOM={ready:(function(){var C=false,E={loaded:1,complete:1};var B=[],D=function(){if(C){return}C=true;for(var F;F=B.shift();F()){}};if(document.addEventListener){document.addEventListener("DOMContentLoaded",D,false);window.addEventListener("pageshow",D,false)}if(!window.opera&&document.readyState){(function(){E[document.readyState]?D():setTimeout(arguments.callee,10)})()}if(document.readyState&&document.createStyleSheet){(function(){try{document.body.doScroll("left");D()}catch(F){setTimeout(arguments.callee,1)}})()}q(window,"load",D);return function(F){if(!arguments.length){D()}else{C?F():B.push(F)}}})(),root:function(){return document.documentElement||document.body}};var n=m.CSS={Size:function(C,B){this.value=parseFloat(C);this.unit=String(C).match(/[a-z%]*$/)[0]||"px";this.convert=function(D){return D/B*this.value};this.convertFrom=function(D){return D/this.value*B};this.toString=function(){return this.value+this.unit}},addClass:function(C,B){var D=C.className;C.className=D+(D&&" ")+B;return C},color:j(function(C){var B={};B.color=C.replace(/^rgba\((.*?),\s*([\d.]+)\)/,function(E,D,F){B.opacity=parseFloat(F);return"rgb("+D+")"});return B}),fontStretch:j(function(B){if(typeof B=="number"){return B}if(/%$/.test(B)){return parseFloat(B)/100}return{"ultra-condensed":0.5,"extra-condensed":0.625,condensed:0.75,"semi-condensed":0.875,"semi-expanded":1.125,expanded:1.25,"extra-expanded":1.5,"ultra-expanded":2}[B]||1}),getStyle:function(C){var B=document.defaultView;if(B&&B.getComputedStyle){return new a(B.getComputedStyle(C,null))}if(C.currentStyle){return new a(C.currentStyle)}return new a(C.style)},gradient:j(function(F){var G={id:F,type:F.match(/^-([a-z]+)-gradient\(/)[1],stops:[]},C=F.substr(F.indexOf("(")).match(/([\d.]+=)?(#[a-f0-9]+|[a-z]+\(.*?\)|[a-z]+)/ig);for(var E=0,B=C.length,D;E0){E=" "+E}}else{if(B400}if(I==500){I=400}for(var J in G){if(!k(G,J)){continue}J=parseInt(J,10);if(!F||JD){D=J}K.push(J)}if(ID){I=D}K.sort(function(M,L){return(E?(M>=I&&L>=I)?ML:(M<=I&&L<=I)?M>L:Mcufoncanvas{text-indent:0;}@media screen{cvml\\:shape,cvml\\:rect,cvml\\:fill,cvml\\:shadow{behavior:url(#default#VML);display:block;antialias:true;position:absolute;}cufoncanvas{position:absolute;text-align:left;}cufon{display:inline-block;position:relative;vertical-align:'+(h?"middle":"text-bottom")+";}cufon cufontext{position:absolute;left:-10000in;font-size:1px;}a cufon{cursor:pointer}}@media print{cufon cufoncanvas{display:none;}}").replace(/;/g,"!important;"));function c(i,j){return a(i,/(?:em|ex|%)$|^[a-z-]+$/i.test(j)?"1em":j)}function a(l,m){if(m==="0"){return 0}if(/px$/i.test(m)){return parseFloat(m)}var k=l.style.left,j=l.runtimeStyle.left;l.runtimeStyle.left=l.currentStyle.left;l.style.left=m.replace("%","em");var i=l.style.pixelLeft;l.style.left=k;l.runtimeStyle.left=j;return i}function f(l,k,j,n){var i="computed"+n,m=k[i];if(isNaN(m)){m=k.get(n);k[i]=m=(m=="normal")?0:~~j.convertFrom(a(l,m))}return m}var g={};function d(p){var q=p.id;if(!g[q]){var n=p.stops,o=document.createElement("cvml:fill"),i=[];o.type="gradient";o.angle=180;o.focus="0";o.method="sigma";o.color=n[0][1];for(var m=1,l=n.length-1;mO){O=K}if(I>N){N=I}if(K":{"w":232},"?":{"d":"413,-133r0,133r-192,0r0,-133r192,0xm221,-188v-13,-173,78,-281,237,-282r341,0v53,0,80,-24,80,-71v0,-47,-27,-71,-80,-71r-799,0r0,-166r817,-1v141,-1,227,93,227,236v0,149,-87,234,-227,234r-315,0v-67,-1,-99,45,-89,121r-192,0","w":1218},"@":{"d":"305,-388v0,55,25,70,85,70r436,0r0,-146r-439,0v-55,0,-82,25,-82,76xm339,-62v-218,3,-334,-116,-339,-327v-4,-168,93,-282,227,-315v106,-26,574,-16,605,-3v56,23,105,70,105,151r0,316r-579,0v-98,2,-164,-54,-164,-148v0,-106,69,-154,188,-154r444,0v-2,-97,-62,-97,-185,-100v-135,-3,-342,-4,-427,22v-86,26,-136,115,-136,231v0,166,96,250,261,250r483,0r0,77r-483,0","w":1060},"A":{"d":"754,-341v0,-61,-24,-84,-89,-84r-626,0r0,-131r667,0v135,5,215,66,215,217r0,339r-745,0v-108,1,-176,-63,-176,-171v0,-107,69,-171,176,-170r578,0xm754,-131r0,-85r-534,0v-35,0,-53,14,-53,43v0,28,18,42,53,42r534,0","w":1096},"B":{"d":"969,-278v0,176,-93,278,-267,278r-702,0r0,-778r167,0r0,222r535,0v170,-2,267,101,267,278xm794,-278v0,-81,-38,-139,-114,-139r-513,0r0,278r513,0v76,0,114,-58,114,-139","w":1097},"C":{"d":"0,-278v0,-173,94,-278,267,-278r595,0r0,139r-573,0v-76,0,-114,58,-114,139v0,81,38,139,114,139r573,0r0,139r-595,0v-173,1,-267,-105,-267,-278","w":1022},"D":{"d":"0,-278v-1,-176,93,-278,267,-278r521,0r0,-222r167,0r0,778r-688,0v-171,2,-266,-102,-267,-278xm175,-278v0,81,38,139,114,139r499,0r0,-278r-499,0v-76,0,-114,58,-114,139","w":1130},"E":{"d":"176,-216v24,58,48,85,113,85r581,0r0,131r-603,0v-173,1,-267,-105,-267,-278v0,-173,94,-278,267,-278r603,0r0,131r-581,0v-65,4,-87,27,-113,84r694,0r0,125r-694,0","w":1022},"F":{"d":"105,-341v-10,-142,29,-222,167,-222r501,1r0,130r-423,0v-60,-4,-81,31,-78,91r501,-2r0,131r-501,2r0,425r-167,0r0,-425r-105,0r0,-131r105,0","w":906},"G":{"d":"0,-278v0,-173,94,-278,267,-278r770,1r0,571v3,126,-82,208,-203,208r-773,-2r0,-130r743,1v55,0,68,-33,66,-93r-603,0v-173,1,-267,-105,-267,-278xm175,-278v0,81,37,139,114,139r581,-2r0,-275r-581,-1v-76,0,-114,58,-114,139","w":1204},"H":{"d":"735,-359v1,-35,-25,-58,-58,-58r-510,0r0,417r-167,0r0,-778r167,0r0,222r537,0v116,-4,198,68,198,170r0,386r-167,0r0,-359"},"I":{"d":"167,0r-167,0r0,-556r167,0r0,556xm167,-612r-167,0r0,-133r167,0r0,133","w":334},"J":{"d":"743,-612r-167,0r0,-133r167,0r0,133xm743,40v-5,114,-100,182,-221,182r-522,0r0,-139r510,0v44,0,66,-24,66,-73r0,-566r167,0r0,596","w":916},"K":{"d":"767,-481r146,0r0,-77r-146,0r0,77xm1040,-2v25,-199,-69,-334,-263,-334r-610,1r0,-442r-167,0r0,775r167,0r0,-195r588,0v95,-4,128,100,107,195r178,0xm914,-481v0,97,-49,145,-146,145r0,-145r146,0xm767,-481v4,77,-98,149,-175,146r175,0r0,-146","w":1195},"L":{"d":"183,-299v0,80,47,132,132,132r523,0r0,167r-569,0v-174,4,-268,-107,-268,-282r0,-276r182,0r0,259","w":996},"M":{"d":"961,-556v116,-4,197,66,197,170r0,386r-167,0r0,-359v0,-39,-19,-58,-58,-58r-273,0r0,417r-167,0r0,-417r-326,0r0,417r-167,0r0,-556r961,0","w":1312},"N":{"d":"688,-556v116,-4,198,68,198,170r0,386r-167,0r0,-359v0,-39,-19,-58,-58,-58r-494,0r0,417r-167,0r0,-556r688,0","w":1057},"O":{"d":"7,-368v-3,-111,96,-207,207,-207r536,0v112,-3,207,95,207,207r0,162v3,111,-96,207,-207,207r-536,0v-110,3,-207,-97,-207,-207r0,-162xm264,-445v-45,-1,-85,40,-85,85r0,138v-1,45,40,85,85,85r428,0v45,1,85,-40,85,-85r0,-138v1,-45,-40,-85,-85,-85r-428,0","w":1104},"P":{"d":"986,-278v1,176,-93,278,-267,278r-552,0r0,222r-167,0r0,-778r719,0v171,-2,266,102,267,278xm811,-278v0,-81,-38,-139,-114,-139r-530,0r0,278r530,0v76,0,114,-58,114,-139","w":1141},"Q":{"d":"0,-278v-1,-176,93,-278,267,-278r777,2r0,776r-167,0r0,-223r-610,1v-171,2,-266,-102,-267,-278xm175,-278v0,81,38,139,114,139r588,-1r0,-275r-588,-2v-77,0,-114,58,-114,139","w":1211},"R":{"d":"610,-558v134,0,213,83,197,228r-167,0v4,-51,-8,-86,-58,-86r-415,-1r0,417r-167,0r0,-556","w":950},"S":{"d":"913,-170v0,103,-65,170,-175,170r-738,0r0,-131r705,1v37,0,55,-14,55,-43v0,-28,-18,-42,-55,-42r-530,-1v-102,1,-175,-66,-175,-169v0,-101,66,-171,175,-171r708,0r0,131r-675,0v-37,0,-55,14,-55,42v0,28,18,42,55,42r530,1v102,-1,175,67,175,170","w":1039},"T":{"d":"267,-208v1,58,20,77,78,77r425,0r0,131r-504,0v-116,-3,-166,-47,-166,-167r0,-258r-100,0r0,-131r100,0r0,-222r167,0r0,222r503,0r0,131r-503,0r0,217","w":917},"U":{"d":"198,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,358v0,39,19,59,58,59r506,0r0,-417r167,0r0,556r-700,0"},"V":{"d":"167,-139r564,0r0,-417r167,0r0,556r-898,0r0,-556r167,0r0,417"},"W":{"d":"197,0v-115,4,-197,-68,-197,-170r0,-386r167,0r0,358v0,39,19,59,58,59r273,0r0,-417r167,0r0,417r326,0r0,-417r167,0r0,556r-961,0","w":1323},"X":{"d":"132,-208r646,0r0,-131r-646,0r0,131xm1,-138v-2,-70,61,-133,131,-131r0,131r-131,0xm0,-138r132,0r0,138r-132,0r0,-138xm1,-396v-2,71,61,133,131,131r0,-131r-131,0xm0,-396r132,0r0,-158r-132,0r0,158xm909,-138v2,-70,-61,-133,-131,-131r0,131r131,0xm910,-138r-132,0r0,138r132,0r0,-138xm909,-396v2,71,-61,133,-131,131r0,-131r131,0xm910,-396r-132,0r0,-158r132,0r0,158xm133,-454v-2,62,53,117,115,115r-115,0r0,-115xm133,-94v-2,-62,53,-117,115,-115r-115,0r0,115xm777,-454v2,62,-53,117,-115,115r115,0r0,-115xm778,-93v2,-62,-54,-117,-115,-115r115,0r0,115","w":1017},"Y":{"d":"754,92v53,-1,68,-31,66,-92r-622,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,336v-1,49,32,82,81,81r572,0r0,-417r167,0r0,576v3,124,-85,207,-204,207r-769,0r0,-135r740,0","w":1169},"Z":{"d":"0,-170v0,101,66,170,175,170r738,0r0,-131r-704,1v-37,0,-56,-14,-56,-43v0,-28,19,-42,56,-42r529,-1v102,1,175,-66,175,-169v0,-102,-66,-171,-175,-171r-707,-2r0,131r674,2v37,0,55,14,55,42v0,28,-18,42,-55,42r-530,1v-102,-1,-175,67,-175,170","w":1039},"[":{"d":"0,-931r306,0r0,153r-153,0r0,778r153,0r0,153r-306,0r0,-1084","w":361},"\\":{"d":"877,0r-692,-778r-185,0r681,778r196,0","w":942},"]":{"w":366},"^":{"w":406},"_":{"d":"0,61r1001,0r0,161r-1001,0r0,-161","w":1172},"`":{"d":"0,-806r94,0r112,111r-95,0","w":261},"a":{"d":"754,-341v0,-61,-24,-84,-89,-84r-626,0r0,-131r667,0v135,5,215,66,215,217r0,339r-745,0v-108,1,-176,-63,-176,-171v0,-107,69,-171,176,-170r578,0xm754,-131r0,-85r-534,0v-35,0,-53,14,-53,43v0,28,18,42,53,42r534,0","w":1096},"b":{"d":"969,-278v0,176,-93,278,-267,278r-702,0r0,-778r167,0r0,222r535,0v170,-2,267,101,267,278xm794,-278v0,-81,-38,-139,-114,-139r-513,0r0,278r513,0v76,0,114,-58,114,-139","w":1097},"c":{"d":"0,-278v0,-173,94,-278,267,-278r595,0r0,139r-573,0v-76,0,-114,58,-114,139v0,81,38,139,114,139r573,0r0,139r-595,0v-173,1,-267,-105,-267,-278","w":1022},"d":{"d":"0,-278v-1,-176,93,-278,267,-278r521,0r0,-222r167,0r0,778r-688,0v-171,2,-266,-102,-267,-278xm175,-278v0,81,38,139,114,139r499,0r0,-278r-499,0v-76,0,-114,58,-114,139","w":1130},"e":{"d":"176,-216v24,58,48,85,113,85r581,0r0,131r-603,0v-173,1,-267,-105,-267,-278v0,-173,94,-278,267,-278r603,0r0,131r-581,0v-65,4,-87,27,-113,84r694,0r0,125r-694,0","w":1022},"f":{"d":"105,-341v-10,-142,29,-222,167,-222r501,1r0,130r-423,0v-60,-4,-81,31,-78,91r501,-2r0,131r-501,2r0,425r-167,0r0,-425r-105,0r0,-131r105,0","w":906},"g":{"d":"0,-278v0,-173,94,-278,267,-278r770,1r0,571v3,126,-82,208,-203,208r-773,-2r0,-130r743,1v55,0,68,-33,66,-93r-603,0v-173,1,-267,-105,-267,-278xm175,-278v0,81,37,139,114,139r581,-2r0,-275r-581,-1v-76,0,-114,58,-114,139","w":1204},"h":{"d":"735,-359v1,-35,-25,-58,-58,-58r-510,0r0,417r-167,0r0,-778r167,0r0,222r537,0v116,-4,198,68,198,170r0,386r-167,0r0,-359"},"i":{"d":"167,0r-167,0r0,-556r167,0r0,556xm167,-612r-167,0r0,-133r167,0r0,133","w":334},"j":{"d":"743,-612r-167,0r0,-133r167,0r0,133xm743,40v-5,114,-100,182,-221,182r-522,0r0,-139r510,0v44,0,66,-24,66,-73r0,-566r167,0r0,596","w":916},"k":{"d":"767,-481r146,0r0,-77r-146,0r0,77xm1040,-2v25,-199,-69,-334,-263,-334r-610,1r0,-442r-167,0r0,775r167,0r0,-195r588,0v95,-4,128,100,107,195r178,0xm914,-481v0,97,-49,145,-146,145r0,-145r146,0xm767,-481v4,77,-98,149,-175,146r175,0r0,-146","w":1195},"l":{"d":"183,-299v0,80,47,132,132,132r523,0r0,167r-569,0v-174,4,-268,-107,-268,-282r0,-276r182,0r0,259","w":996},"m":{"d":"961,-556v116,-4,197,66,197,170r0,386r-167,0r0,-359v0,-39,-19,-58,-58,-58r-273,0r0,417r-167,0r0,-417r-326,0r0,417r-167,0r0,-556r961,0","w":1312},"n":{"d":"688,-556v116,-4,198,68,198,170r0,386r-167,0r0,-359v0,-39,-19,-58,-58,-58r-494,0r0,417r-167,0r0,-556r688,0","w":1057},"o":{"d":"7,-368v-3,-111,96,-207,207,-207r536,0v112,-3,207,95,207,207r0,162v3,111,-96,207,-207,207r-536,0v-110,3,-207,-97,-207,-207r0,-162xm264,-445v-45,-1,-85,40,-85,85r0,138v-1,45,40,85,85,85r428,0v45,1,85,-40,85,-85r0,-138v1,-45,-40,-85,-85,-85r-428,0","w":1104},"p":{"d":"986,-278v1,176,-93,278,-267,278r-552,0r0,222r-167,0r0,-778r719,0v171,-2,266,102,267,278xm811,-278v0,-81,-38,-139,-114,-139r-530,0r0,278r530,0v76,0,114,-58,114,-139","w":1141},"q":{"d":"0,-278v-1,-176,93,-278,267,-278r777,2r0,776r-167,0r0,-223r-610,1v-171,2,-266,-102,-267,-278xm175,-278v0,81,38,139,114,139r588,-1r0,-275r-588,-2v-77,0,-114,58,-114,139","w":1211},"r":{"d":"610,-558v134,0,213,83,197,228r-167,0v4,-51,-8,-86,-58,-86r-415,-1r0,417r-167,0r0,-556","w":950},"s":{"d":"913,-170v0,103,-65,170,-175,170r-738,0r0,-131r705,1v37,0,55,-14,55,-43v0,-28,-18,-42,-55,-42r-530,-1v-102,1,-175,-66,-175,-169v0,-101,66,-171,175,-171r708,0r0,131r-675,0v-37,0,-55,14,-55,42v0,28,18,42,55,42r530,1v102,-1,175,67,175,170","w":1039},"t":{"d":"267,-208v1,58,20,77,78,77r425,0r0,131r-504,0v-116,-3,-166,-47,-166,-167r0,-258r-100,0r0,-131r100,0r0,-222r167,0r0,222r503,0r0,131r-503,0r0,217","w":917},"u":{"d":"198,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,358v0,39,19,59,58,59r506,0r0,-417r167,0r0,556r-700,0"},"v":{"d":"167,-139r564,0r0,-417r167,0r0,556r-898,0r0,-556r167,0r0,417"},"w":{"d":"197,0v-115,4,-197,-68,-197,-170r0,-386r167,0r0,358v0,39,19,59,58,59r273,0r0,-417r167,0r0,417r326,0r0,-417r167,0r0,556r-961,0","w":1323},"x":{"d":"132,-208r646,0r0,-131r-646,0r0,131xm1,-138v-2,-70,61,-133,131,-131r0,131r-131,0xm0,-138r132,0r0,138r-132,0r0,-138xm1,-396v-2,71,61,133,131,131r0,-131r-131,0xm0,-396r132,0r0,-158r-132,0r0,158xm909,-138v2,-70,-61,-133,-131,-131r0,131r131,0xm910,-138r-132,0r0,138r132,0r0,-138xm909,-396v2,71,-61,133,-131,131r0,-131r131,0xm910,-396r-132,0r0,-158r132,0r0,158xm133,-454v-2,62,53,117,115,115r-115,0r0,-115xm133,-94v-2,-62,53,-117,115,-115r-115,0r0,115xm777,-454v2,62,-53,117,-115,115r115,0r0,-115xm778,-93v2,-62,-54,-117,-115,-115r115,0r0,115","w":1017},"y":{"d":"754,92v53,-1,68,-31,66,-92r-622,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,336v-1,49,32,82,81,81r572,0r0,-417r167,0r0,576v3,124,-85,207,-204,207r-769,0r0,-135r740,0","w":1169},"z":{"d":"0,-170v0,101,66,170,175,170r738,0r0,-131r-704,1v-37,0,-56,-14,-56,-43v0,-28,19,-42,56,-42r529,-1v102,1,175,-66,175,-169v0,-102,-66,-171,-175,-171r-707,-2r0,131r674,2v37,0,55,14,55,42v0,28,-18,42,-55,42r-530,1v-102,-1,-175,67,-175,170","w":1039},"{":{"d":"0,-466v58,7,98,-17,100,-66v3,-102,-10,-222,10,-308v23,-50,68,-91,143,-91r196,0r0,153r-163,0v-22,0,-33,11,-33,33r0,289v1,35,-29,68,-64,67v36,0,65,30,64,66r0,290v0,22,11,33,33,33r163,0r0,153r-196,0v-87,1,-153,-65,-153,-153r0,-246v-1,-49,-42,-75,-100,-67r0,-153","w":515},"|":{"w":211},"}":{"d":"349,-778v0,-93,-61,-152,-153,-153r-196,0r0,153r163,0v22,0,33,11,33,33r0,289v-1,35,29,68,64,67v-36,0,-65,30,-64,66r0,290v0,22,-11,33,-33,33r-163,0r0,153r196,0v91,0,153,-64,153,-153r0,-246v1,-49,42,-75,100,-67r0,-153v-58,7,-99,-17,-100,-66r0,-246","w":515},"~":{"w":342},"\u0131":{"w":256},"\u00c7":{"w":729},"\u00d6":{"w":1084},"\u00dc":{"w":761},"\u00e7":{"w":578},"\u00f6":{"d":"7,-368v-3,-111,96,-207,207,-207r536,0v112,-3,207,95,207,207r0,162v3,111,-96,207,-207,207r-536,0v-110,3,-207,-97,-207,-207r0,-162xm264,-445v-45,-1,-85,40,-85,85r0,138v-1,45,40,85,85,85r428,0v45,1,85,-40,85,-85r0,-138v1,-45,-40,-85,-85,-85r-428,0xm289,-650r0,-128r379,0r0,128r-379,0","w":1084},"\u00fc":{"d":"198,0v-119,6,-198,-71,-198,-170r0,-386r167,0r0,358v0,39,19,59,58,59r506,0r0,-417r167,0r0,556r-700,0xm284,-650r0,-128r379,0r0,128r-379,0","w":1032},"\u00a0":{"w":668}}}); diff --git a/doc/themes/triqs/static/triqs.css b/doc/themes/triqs/static/triqs.css deleted file mode 100644 index e183cb2..0000000 --- a/doc/themes/triqs/static/triqs.css +++ /dev/null @@ -1,449 +0,0 @@ -/* - * sphinx13.css - * ~~~~~~~~~~~~ - * - * Sphinx stylesheet -- sphinx13 theme. - * - * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; - font-size: 14px; - text-align: center; - background-image: url(bodybg.png); - color: black; - padding: 0; - border-right: 1px solid #0a507a; - border-left: 1px solid #0a507a; - - margin: 0 auto; - min-width: 780px; - max-width: 1080px; -} - - -.red{ - color: red -} -.blue{ - color: blue -} -.green{ - color: green -} - -.param{ - color: blue -} - -a.triqs { - color: #073958; - text-decoration: none; -} - -a.triqs:hover { - color: #0a527f; - text-decoration: none; -} - -.pageheader { - background-color: #dcdcdc; - text-align: left; - padding: 10px 15px; - color: #073958; - border: none; -} - -.pageheader ul { - float: right; - color: #073958; - list-style-type: none; - padding-left: 0; - margin-top: 22px; - margin-right: 10px; -} - -.pageheader li { - float: left; - margin: 0 0 0 10px; -} - -.pageheader li a { - padding: 8px 12px; - color: #073958; - text-shadow: none; -} - -.pageheader li a:hover { - background-color: #f9f9f0; - color: #0a507a; - text-shadow: none; -} - -div.document { - background-color: white; - text-align: left; -} - -div.bodywrapper { - margin: 0 240px 0 0; - border-right: 1px solid #0a507a; -} - -div.body { - margin: 0; - padding: 0.5em 20px 20px 20px; -} - -div.related { - font-size: 1em; - color: white; -} - -div.related ul { - background-image: url(relbg.png); - height: 1.9em; - border-top: 1px solid #002e50; - border-bottom: 1px solid #002e50; -} - -div.related ul li { - margin: 0 5px 0 0; - padding: 0; - float: left; -} - -div.related ul li.right { - float: right; - margin-right: 5px; -} - -div.related ul li a { - margin: 0; - padding: 0 5px 0 5px; - line-height: 1.75em; - color: #f9f9f0; - text-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5); -} - -div.related ul li a:hover { - color: white; - /*text-decoration: underline;*/ - text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.5); -} - -div.sphinxsidebarwrapper { - position: relative; - top: 0px; - padding: 0; -} - -div.sphinxsidebar { - margin: 0; - padding: 0 15px 15px 0; - width: 210px; - float: right; - font-size: 1em; - text-align: left; -} - -div.sphinxsidebar .logo { - font-size: 1.8em; - color: #0A507A; - font-weight: 300; - text-align: center; -} - -div.sphinxsidebar .logo img { - vertical-align: middle; -} - -div.sphinxsidebar input { - border: 1px solid #aaa; - font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; - font-size: 1em; -} - -div.sphinxsidebar h3 { - font-size: 1.5em; - border-top: 1px solid #0a507a; - margin-top: 1em; - margin-bottom: 0.5em; - padding-top: 0.5em; -} - -div.sphinxsidebar h4 { - font-size: 1.2em; - margin-bottom: 0; -} - -div.sphinxsidebar h3, div.sphinxsidebar h4 { - margin-right: -15px; - margin-left: -15px; - padding-right: 14px; - padding-left: 14px; - color: #333; - font-weight: 300; - /*text-shadow: 0px 0px 0.5px rgba(0, 0, 0, 0.4);*/ -} - -div.sphinxsidebarwrapper > h3:first-child { - margin-top: 0.5em; - border: none; -} - -div.sphinxsidebar h3 a { - color: #333; -} - -div.sphinxsidebar ul { - color: #444; - margin-top: 7px; - padding: 0; - line-height: 130%; -} - -div.sphinxsidebar ul ul { - margin-left: 20px; - list-style-image: url(listitem.png); -} - -div.footer { - background-image: url(footerbg.png); - color: #ccc; - text-shadow: 0 0 .2px rgba(255, 255, 255, 0.8); - padding: 3px 8px 3px 0; - clear: both; - font-size: 0.8em; - text-align: right; -} - -/* no need to make a visible link to Sphinx on the Sphinx page */ -div.footer a { - color: #ccc; -} - -/* -- body styles ----------------------------------------------------------- */ - -p { - margin: 0.8em 0 0.5em 0; -} - -a { - color: #A2881D; - text-decoration: none; -} - -a:hover { - color: #E1C13F; -} - -div.body a { - text-decoration: underline; -} - -h1 { - margin: 10px 0 0 0; - font-size: 2.4em; - color: #0A507A; - font-weight: 300; -} - -h2 { - margin: 1.em 0 0.2em 0; - font-size: 1.5em; - font-weight: 300; - padding: 0; - color: #174967; -} - -h3 { - margin: 1em 0 -0.3em 0; - font-size: 1.3em; - font-weight: 300; -} - -div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { - text-decoration: none; -} - -div.body h1 a tt, div.body h2 a tt, div.body h3 a tt, div.body h4 a tt, div.body h5 a tt, div.body h6 a tt { - color: #0A507A !important; - font-size: inherit !important; -} - -a.headerlink { - color: #0A507A !important; - font-size: 12px; - margin-left: 6px; - padding: 0 4px 0 4px; - text-decoration: none !important; - float: right; -} - -a.headerlink:hover { - background-color: #ccc; - color: white!important; -} - -cite, code, tt { - font-family: 'Consolas', 'DejaVu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; - font-size: 14px; - letter-spacing: -0.02em; -} - -tt { - background-color: #f2f2f2; - border: 1px solid #ddd; - border-radius: 2px; - color: #333; - padding: 1px; -} - -tt.descname, tt.descclassname, tt.xref { - border: 0; -} - -hr { - border: 1px solid #abc; - margin: 2em; -} - -a tt { - border: 0; - color: #a2881d; -} - -a tt:hover { - color: #e1c13f; -} - -pre { - font-family: 'Consolas', 'DejaVu Sans Mono', - 'Bitstream Vera Sans Mono', monospace; - font-size: 13px; - letter-spacing: 0.015em; - line-height: 120%; - padding: 0.5em; - border: 1px solid #ccc; - border-radius: 2px; - background-color: #f8f8f8; -} - -pre a { - color: inherit; - text-decoration: underline; -} - -td.linenos pre { - padding: 0.5em 0; -} - -div.quotebar { - background-color: #f8f8f8; - max-width: 250px; - float: right; - padding: 0px 7px; - border: 1px solid #ccc; - margin-left: 1em; -} - -div.topic { - background-color: #f8f8f8; -} - -table { - border-collapse: collapse; - margin: 0 -0.5em 0 -0.5em; -} - -table td, table th { - padding: 0.2em 0.5em 0.2em 0.5em; -} - -div.admonition, div.warning { - font-size: 0.9em; - margin: 1em 0 1em 0; - border: 1px solid #86989B; - border-radius: 2px; - background-color: #f7f7f7; - padding: 0; -} - -div.admonition p, div.warning p { - margin: 0.5em 1em 0.5em 1em; - padding: 0; -} - -div.admonition pre, div.warning pre { - margin: 0.4em 1em 0.4em 1em; -} - -div.admonition p.admonition-title, -div.warning p.admonition-title { - margin-top: 1em; - padding-top: 0.5em; - font-weight: bold; -} - -div.warning { - border: 1px solid #940000; -/* background-color: #FFCCCF;*/ -} - -div.warning p.admonition-title { -} - -div.admonition ul, div.admonition ol, -div.warning ul, div.warning ol { - margin: 0.1em 0.5em 0.5em 3em; - padding: 0; -} - -div.admonition .highlight, div.warning .highlight { - background-color: #f7f7f7; -} - -.viewcode-back { - font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', - 'Verdana', sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} - - -.my-code-block.std-ref { - color : red; -} - -.cppbrief { - color: #C6792C; - font-style: oblique; -} - -.cppsynopsis { - background-color: #E7EDF9; - /*font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif;*/ - /*font-family: monospace; */ - font-family: Verdana, Arial, Lucida Console; - font-size=80%; - /*font-style: oblique;*/ - /* white-space: pre;*/ -} - - - diff --git a/doc/themes/triqs/theme.conf b/doc/themes/triqs/theme.conf deleted file mode 100644 index 96ca439..0000000 --- a/doc/themes/triqs/theme.conf +++ /dev/null @@ -1,4 +0,0 @@ -[theme] -inherit = basic -stylesheet = triqs.css -pygments_style = sphinx diff --git a/test/c++/itertools.cpp b/test/c++/itertools.cpp index 5f53e52..8b1518b 100644 --- a/test/c++/itertools.cpp +++ b/test/c++/itertools.cpp @@ -17,173 +17,210 @@ #include #include +#include #include -#include +#include +#include #include +#include +#include using namespace itertools; -// An uncopyable int -struct _int { +// A non-copyable integer. +struct non_copyable_int { int i; - _int(int u) : i(u){}; - _int(_int const &) = delete; - _int(_int &&) = default; + non_copyable_int(int u) : i(u){}; + non_copyable_int(non_copyable_int const &) = delete; + non_copyable_int(non_copyable_int &&) = default; operator int() const { return i; } - friend std::ostream &operator<<(std::ostream &out, _int const &x) { return out << x.i; } + friend std::ostream &operator<<(std::ostream &out, non_copyable_int const &x) { return out << x.i; } }; -TEST(Itertools, Zip) { - - std::array<_int, 6> V1{6, 5, 4, 3, 2, 1}; - std::vector V2{1, 2, 3, 4, 5, 6}; +TEST(Itertools, Distance) { + // check that itertools::distance implementation agrees with std::distance + std::vector vec{1, 2, 3, 4, 5, 6, 8, 9, 10}; + std::list list{1, 2, 3, 4, 5, 6, 8, 9, 10}; + auto it1 = vec.begin() + 2; + auto it2 = vec.end() - 2; + auto it3 = std::next(list.begin(), 1); + auto it4 = std::prev(list.end(), 1); + EXPECT_EQ(itertools::distance(it1, it2), std::distance(it1, it2)); + EXPECT_EQ(itertools::distance(it3, it4), std::distance(it3, it4)); +} - // Zip both vectors and sum - for (auto [x, y] : zip(V1, V2)) { EXPECT_TRUE(7 - y == x); } +TEST(Itertools, MakeVectorFromRange) { + // check that we can create a vector from a range + std::vector vec1{1, 2, 3, 4, 5}; + auto vec2 = make_vector_from_range(range(1, 6)); + EXPECT_EQ(vec1, vec2); +} - // Change the values of the second vector to the first - for (auto [x, y] : zip(V1, V2)) { y = x.i; } - EXPECT_TRUE(std::equal(V2.begin(), V2.end(), V1.begin())); +TEST(Itertools, ChunkRange) { + // check the correctness of some chunked ranges + EXPECT_EQ(chunk_range(0, 10, 1, 0), std::make_pair(0l, 10l)); + EXPECT_EQ(chunk_range(0, 10, 2, 0), std::make_pair(0l, 5l)); + EXPECT_EQ(chunk_range(0, 10, 2, 1), std::make_pair(5l, 10l)); + EXPECT_EQ(chunk_range(0, 10, 3, 0), std::make_pair(0l, 4l)); + EXPECT_EQ(chunk_range(0, 10, 3, 1), std::make_pair(4l, 7l)); + EXPECT_EQ(chunk_range(0, 10, 3, 2), std::make_pair(7l, 10l)); + EXPECT_EQ(chunk_range(0, 10, 4, 0), std::make_pair(0l, 3l)); + EXPECT_EQ(chunk_range(0, 10, 4, 1), std::make_pair(3l, 6l)); + EXPECT_EQ(chunk_range(0, 10, 4, 2), std::make_pair(6l, 8l)); + EXPECT_EQ(chunk_range(0, 10, 4, 3), std::make_pair(8l, 10l)); + EXPECT_EQ(chunk_range(0, 10, 11, 0), std::make_pair(0l, 1l)); + EXPECT_EQ(chunk_range(0, 10, 11, 10), std::make_pair(10l, 10l)); } TEST(Itertools, Enumerate) { + std::vector vec{6, 5, 4, 3, 2, 1}; - std::vector V{6, 5, 4, 3, 2, 1}; - - // Enumerate the elements of the vector - for (auto [j, x] : enumerate(V)) { + // enumerate elements of a range + for (auto [j, x] : enumerate(vec)) { EXPECT_TRUE(j + x == 6); - EXPECT_TRUE(x == V[j]); + EXPECT_TRUE(x == vec[j]); } - // Enumerate and change values - std::vector V_compare{0, 1, 2, 3, 4, 5}; - for (auto [j, x] : enumerate(V)) { x = j; } - EXPECT_TRUE(std::equal(V.begin(), V.end(), V_compare.begin())); - - std::array<_int, 6> W{6, 5, 4, 3, 2, 1}; + // enumerate and change elements of the underlying range + std::vector vec_compare{0, 1, 2, 3, 4, 5}; + for (auto [j, x] : enumerate(vec)) { x = static_cast(j); } + EXPECT_TRUE(std::equal(vec.begin(), vec.end(), vec_compare.begin())); - // Enumerate the elements of the array - for (auto [j, x] : enumerate(W)) { + // enumerate non-copyable elements of a range + std::array arr{6, 5, 4, 3, 2, 1}; + for (auto [j, x] : enumerate(arr)) { EXPECT_TRUE(6 - j == x); - EXPECT_TRUE(W[j] == x); + EXPECT_TRUE(arr[j] == x); } } TEST(Itertools, Transform) { + std::vector vec{1, 2, 3, 4, 5, 6}; + auto square = [](int i) { return i * i; }; - std::vector V{1, 2, 3, 4, 5, 6}; - - // Square the elements of the vector - auto l = [](int i) { return i * i; }; - + // square elements of an integer range int i = 0; - for (auto x : transform(V, l)) { + for (auto x : transform(vec, square)) { ++i; EXPECT_TRUE(i * i == x); } - std::array<_int, 6> W{1, 2, 3, 4, 5, 6}; - - // Square the elements of the array + // square non-copyable elements of an integer range + std::array arr{1, 2, 3, 4, 5, 6}; i = 0; - for (auto x : transform(W, l)) { + for (auto x : transform(arr, square)) { ++i; EXPECT_TRUE(i * i == x); } } +TEST(Itertools, Zip) { + std::array arr{6, 5, 4, 3, 2, 1}; + std::vector vec1{1, 2, 3, 4, 5, 6}; + + // zip two ranges + for (auto [x, y] : zip(arr, vec1)) { EXPECT_TRUE(7 - y == x); } + + // change the elements of the second range to be equal to the first + for (auto [x, y] : zip(arr, vec1)) { y = x.i; } + EXPECT_TRUE(std::equal(vec1.begin(), vec1.end(), arr.begin())); + + // check that the size of a zipped range is correct + std::vector vec2{1, 2, 3}; + int count = 0; + for ([[maybe_unused]] auto [x, y] : zip(arr, vec2)) { ++count; } + EXPECT_EQ(count, vec2.size()); +} + TEST(Itertools, Product) { + // multiply two ranges and iterate over them + std::vector vec1{0, 1, 2, 3, 4}; + std::array arr{0, 1, 2, 3, 4}; + int i = 0, j = 0; + for (auto [x, y] : product(vec1, arr)) { + EXPECT_EQ(x, i); + EXPECT_EQ(y, j); + ++j; + if (j > arr.back()) { + ++i; + j = 0; + } + std::cout << "[" << x << "," << y << "]\n"; + } - std::vector V1{0, 1, 2, 3, 4}; - std::array<_int, 5> V2{0, 1, 2, 3, 4}; - for (auto [x, y] : product(V1, V2)) { std::cout << "[" << x << "," << y << "]\n"; } + // multiply two ranges and change the elements of the second range + std::vector vec2{1, 2, 3, 4}; + std::vector vec3{1, 1, 1, 1}; + for (auto [x, y] : product(vec2, vec3)) { y *= x; } + EXPECT_EQ(vec3, std::vector(4, 1 * 2 * 3 * 4)); - // Check that we can alter the values - std::vector V3{1, 2, 3, 4}; - std::vector V4{1, 1, 1, 1}; - for (auto [x, y] : product(V3, V4)) { y *= x; } - EXPECT_EQ(V4, std::vector(4, 1 * 2 * 3 * 4)); + // make a product range from an array of ranges + constexpr int N = 4; + std::array range_arr{range(1), range(2), range(3), range(4)}; + int count = 0; + for ([[maybe_unused]] auto [u, v, w, x] : make_product(range_arr)) ++count; + EXPECT_EQ(count, 1 * 2 * 3 * 4); } TEST(Itertools, Slice) { - + // slice an integer range in various ways for (long N : range(1, 6)) { for (auto start_idx : range(N)) { for (auto M : range(1, 6)) { auto sliced = slice(range(N), start_idx, M); - long sum = std::accumulate(sliced.cbegin(), sliced.cend(), 0); + long sum = std::accumulate(sliced.cbegin(), sliced.cend(), 0l); long end_idx = std::max(std::min(M, N), start_idx); EXPECT_EQ(sum, end_idx * (end_idx - 1) / 2 - start_idx * (start_idx - 1) / 2); } } } -} - -TEST(Itertools, Make_Product) { - - constexpr int N = 4; - - std::array range_arr{range(1), range(2), range(3), range(4)}; - - int count = 0; - for ([[maybe_unused]] auto [i, j, k, l] : make_product(range_arr)) ++count; - EXPECT_EQ(count, 1 * 2 * 3 * 4); + // change the elements of a sliced range + std::vector vec1{0, 1, 2, 3, 4}; + std::vector vec2{0, 0, 0, 3, 4}; + for (auto &x : slice(vec1, 1, 3)) { x = 0; } + EXPECT_EQ(vec1, vec2); } -TEST(Itertools, Multi) { - - std::vector V{1, 2, 3, 4, 5, 6}; - - // Build enumerate from transform and compare - auto l = [n = 0](auto x) mutable { return std::make_tuple(n++, x); }; - - for (auto [x1, x2] : zip(transform(V, l), enumerate(V))) { EXPECT_TRUE(x1 == x2); } - - // Chain enumerate and transform - for (auto [i, x] : enumerate(transform(V, l))) { std::cout << i << " [" << std::get<0>(x) << ", " << std::get<1>(x) << "]\n"; } - - // Combine transform and product - auto add = [](auto &&p) { - auto [v, w] = p; - return v + w; - }; - int total = 0; - for (auto sum : transform(product(V, V), add)) total += sum; - EXPECT_EQ(total, 252); - - // slice and zip - for (auto [x1, x2] : slice(zip(V, V), 0, 4)) { EXPECT_EQ(x1, x2); } +TEST(Itertools, Stride) { + // check correctness of different strides + std::vector vec1{0, 1, 2, 3, 4}; + for (int s = 1; s < 6; ++s) { + int i = 0; + int size = 0; + for (auto x : stride(vec1, s)) { + EXPECT_EQ(i, x); + i += s; + ++size; + } + EXPECT_EQ(size, (vec1.size() - 1) / s + 1); + } - // product and transform - // Sum up numbers from 0 to 99 in a complicated way.. - auto times_ten = [](auto i) { return 10 * i; }; - total = 0; - for (auto [a, b] : product(transform(range(10), times_ten), range(10))) { total += a + b; } - EXPECT_EQ(total, 99 * 100 / 2); + // check an empty strided range + std::vector vec2; + int empty_size = 0; + for ([[maybe_unused]] auto x : stride(vec2, 2)) { ++empty_size; } + EXPECT_EQ(empty_size, 0); } TEST(Itertools, Range) { - + // check different integer ranges int L = 5; for (int a = -L; a <= L; a++) for (int b = -L; b <= L; b++) for (int s = 1; s <= 3; s++) { - int sum_with_range = 0; - for (auto i : range(a, b, (a <= b) ? s : -s)) { sum_with_range += i; } - + for (auto i : range(a, b, (a <= b) ? s : -s)) { sum_with_range += static_cast(i); } int sum_exact = 0; if (a <= b) for (int i = a; i < b; i += s) { sum_exact += i; } else for (int i = a; i > b; i -= s) { sum_exact += i; } - EXPECT_EQ(sum_with_range, sum_exact); } + // check the size of various valid integer ranges EXPECT_EQ(range(1).size(), 1); EXPECT_EQ(range(-10, 10, 2).size(), 10); EXPECT_EQ(range(10, -10, -2).size(), 10); @@ -192,52 +229,60 @@ TEST(Itertools, Range) { EXPECT_EQ(range(-1, 0, -3).size(), 0); EXPECT_EQ(range(10, -10, 2).size(), 0); EXPECT_EQ(range(-10, 10, -2).size(), 0); -} - -TEST(Itertools, Product_Range) { + // product of integer ranges long res = 0; for (auto [i, j, k] : product_range(5, 5, 5)) res += i * j * k; EXPECT_EQ(res, 1000); } -TEST(Itertools, Stride) { - std::vector V1{0, 1, 2, 3, 4}; +TEST(Itertools, CombinationOfRangeAdaptingFunctions) { + std::vector vec1{1, 2, 3, 4, 5, 6}; + std::vector vec2{0, 1, 2, 3, 4}; - // simple stride - for (int s = 1; s < 6; ++s) { - int i = 0; - int size = 0; - for (auto x : stride(V1, s)) { - EXPECT_EQ(i, x); - i += s; - ++size; - } - EXPECT_EQ(size, (V1.size() - 1) / s + 1); - } + // imitate enumerate with transform + auto enum_imitation = [n = 0](auto x) mutable { return std::make_tuple(n++, x); }; - // empty range - std::vector V2; - int empty_size = 0; - for ([[maybe_unused]] auto x : stride(V2, 2)) { ++empty_size; } - EXPECT_EQ(empty_size, 0); + // zip a transformed and an enumerated range + for (auto [x1, x2] : zip(transform(vec1, enum_imitation), enumerate(vec1))) { EXPECT_TRUE(x1 == x2); } + + // enumerate a transformed range + for (auto [i, x] : enumerate(transform(vec1, enum_imitation))) { std::cout << i << " [" << std::get<0>(x) << ", " << std::get<1>(x) << "]\n"; } + + // transform a product range + auto add = [](auto const &p) { + auto [v, w] = p; + return v + w; + }; + int total = 0; + for (auto sum : transform(product(vec1, vec1), add)) total += sum; + EXPECT_EQ(total, 252); + + // slice a zipped range + for (auto [x1, x2] : slice(zip(vec1, vec1), 0, 4)) { EXPECT_EQ(x1, x2); } + + // take the product of an integer range and a transformed range (sum up number from 0 to 99) + auto times_ten = [](auto i) { return 10 * i; }; + total = 0; + for (auto [a, b] : product(transform(range(10), times_ten), range(10))) { total += static_cast(a + b); } + EXPECT_EQ(total, 99 * 100 / 2); - // stride and product + // stride through a product range for (int s = 1; s < 6; ++s) { int idx = 0; - for (auto [x1, x2] : stride(product(V1, V1), s)) { - auto i = idx / static_cast(V1.size()); - auto j = idx - i * static_cast(V1.size()); + for (auto [x1, x2] : stride(product(vec2, vec2), s)) { + auto i = idx / static_cast(vec2.size()); + auto j = idx - i * static_cast(vec2.size()); EXPECT_EQ(x1, i); EXPECT_EQ(x2, j); idx += s; } } - // zip and stride + // zip two strided ranges for (int s = 1; s < 6; ++s) { int i = 0; - for (auto [x1, x2] : zip(stride(V1, s), stride(V1, s))) { + for (auto [x1, x2] : zip(stride(vec2, s), stride(vec2, s))) { EXPECT_EQ(x1, i); EXPECT_EQ(x2, i); i += s;