diff --git a/include/rosa/support/iterator/namespace.h b/include/rosa/support/iterator/namespace.h new file mode 100644 index 0000000..027978d --- /dev/null +++ b/include/rosa/support/iterator/namespace.h @@ -0,0 +1,25 @@ +//===-- rosa/support/iterator/namespace.h -----------------------*- C++ -*-===/ +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===/ +/// +/// \file rosa/support/iterator/namespace.h +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Documentation for the namespace \c rosa::iterator. +/// +//===----------------------------------------------------------------------===/ + +#ifndef ROSA_SUPPORT_ITERATOR_NAMESPACE_H +#define ROSA_SUPPORT_ITERATOR_NAMESPACE_H + +namespace rosa { +/// Provides facilities to work with iterators. +namespace iterator {} +} // End namespace rosa + +#endif // ROSA_SUPPORT_ITERATOR_NAMESPACE_H diff --git a/include/rosa/support/iterator/split_tuple_iterator.hpp b/include/rosa/support/iterator/split_tuple_iterator.hpp new file mode 100644 index 0000000..f64b346 --- /dev/null +++ b/include/rosa/support/iterator/split_tuple_iterator.hpp @@ -0,0 +1,427 @@ +//===-- rosa/support/iterator/split_tuple_iterator.hpp ----------*- C++ -*-===/ +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===/ +/// +/// \file rosa/support/iterator/split_tuple_iterator.hpp +/// +/// \authors David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Facilities to split iterators of \c std::tuple into iterators of +/// their elements. +/// +//===----------------------------------------------------------------------===/ + +#ifndef ROSA_SUPPORT_ITERATOR_SPLIT_TUPLE_ITERATOR_HPP +#define ROSA_SUPPORT_ITERATOR_SPLIT_TUPLE_ITERATOR_HPP + +#include "rosa/support/debug.hpp" +#include "rosa/support/sequence.hpp" + +#include +#include +#include +#include + +namespace rosa { +namespace iterator { + +/// Anonymous namespace providing implementation for splitting tuple iterators; +/// consider it private. +namespace { + +/// Iterator of values provided by a buffer based on an index +/// +/// \tparam TB buffer providing values to iterate +/// \tparam I index of the values to iterator from \p TB +/// +/// \note \p TB is expected to implemnet an interface matching that of \c +/// TupleIteratorBuffer. +template +class SplittedElementIterator { +public: + /// Type alias for the values the iterator iterates. + using T = typename TB::template element_type; + + /// \defgroup SplittedElementIteratorTypedefs Typedefs of + /// \c SplittedElementIterator + /// + /// Standard `typedef`s for iterators. + /// + ///@{ + typedef std::input_iterator_tag + iterator_category; ///< Category of the iterator. + typedef T value_type; ///< Type of values iterated over. + typedef std::size_t difference_type; ///< Type to identify distance. + typedef T *pointer; ///< Pointer to the type iterated over. + typedef T &reference; ///< Reference to the type iterated ver. + ///@} + + /// Creates a new instance. + /// + /// \param Buffer buffer providing values for \p this object + /// + /// \note \p Buffer is captured as a \c std::shared_ptr because it is shared + /// among iterators for its element positions. + SplittedElementIterator(std::shared_ptr Buffer) + : Buffer(Buffer), Value() { + // \c Value is initialized empty so the first incrementation here will read + // the first value. + ++(*this); + } + + /// Creates an empty new instance. + SplittedElementIterator(void) noexcept : Buffer(), Value() {} + + /// Pre-increment operator. + /// + /// The implementation reads the next value from \c Buffer. If no more values + /// can be provided by \c Buffer, \p this object becomes empty and the + /// operator has no further effect. + /// + /// \return \p this object after incrementing it. + SplittedElementIterator &operator++() { + if (Buffer->template hasMore()) { + Value = Buffer->template next(); + } else { + // Reached end of range, remove reference of \c Buffer. + Buffer.reset(); + } + return *this; + } + + /// Post-increment operator. + /// + /// The implementation uses the pre-increment operator and returns a copy of + /// the original state of \p this object. + /// + /// \return \p this object before incrementing it. + SplittedElementIterator operator++(int) { + SplittedElementIterator Tmp(*this); + ++(*this); + return Tmp; + } + + /// Returns a constant reference to the current value. + /// + /// \note Should not dereference the iterator when it is empty. + /// + /// \return constant reference to the current value. + const T &operator*(void)const noexcept { return Value; } + + /// Returns a constant pointer to the current value. + /// + /// \note Should not dereference the iterator when it is empty. + /// + /// \return constant pointer to the current value. + const T *operator->(void)const noexcept { return &Value; } + + /// Tells if \p this object is equal to another one. + /// + /// Two \c SplittedElementIterator instances are equal if and only if they are + /// the same or both are empty. + /// + /// \param RHS other object to compare to + /// + /// \return whether \p this object is equal with \p RHS + bool operator==(const SplittedElementIterator &RHS) const noexcept { + return ((this == &RHS) || (!Buffer && !RHS.Buffer)); + } + + /// Tells if \p this object is not equal to another one. + /// + /// \see SplittedElementIterator::operator== + /// + /// \param RHS other object to compare to + /// + /// \return whether \p this object is not equal with \p RHS. + bool operator!=(const SplittedElementIterator &RHS) const noexcept { + return !((*this) == RHS); + } + +private: + std::shared_ptr Buffer; ///< Buffer providing values for \p this object + T Value; ///< The current value of the iterator +}; + +///\defgroup TupleBufferContainer Type converter turning a \c std::tuple of +///types into a \c std::tuple of container of those types. +/// +/// The new type is used for buffering elements of tuples separately. +/// +///@{ + +/// Template declaration. +/// +/// \tparam T type to convert +/// +/// \note The template is defined only when \p T is a \c std::tuple. +/// +/// Usage for a type \c Tuple as:\code +/// typename TupleBufferContainer::Type +/// \endcode +template struct TupleBufferContainer; + +/// Template definition for \c std::tuple. +template struct TupleBufferContainer> { + /// The converted type. + using Type = std::tuple...>; +}; + +///@} + +/// Convenience template type alias for easy use of \c TupleBufferContainer. +/// +/// Converts a \c std::tuple of types into a \c std::tuple of container of those +/// types. +/// +/// \tparam Tuple type to convert +template +using tuple_buffer_container_t = typename TupleBufferContainer::Type; + +/// Buffer for element values for iterator of \c std::tuple. +/// +/// The class can be instantiated with a range of iterator of \c std::tuple and +/// provides an interface for accessing elements of the iterated tuples one by +/// one. +/// +/// \note The class is utilized by \c SplittedElementIterator. +/// +/// \tparam TupleIterator the iterator type that provides values of \c +/// std::tuple +/// +/// \todo Consider thread safety of the class. +template +class TupleIteratorBuffer { +public: + /// Type alias for the value type of \p TupleIterator. + /// \note The type is expected to be \c std::tuple. + using iterator_value_type = typename TupleIterator::value_type; + + /// The number of elements of \c iterator_value_type. + static constexpr size_t iterator_value_size = + std::tuple_size_v; + + /// Template type alias to get element types of \c iterator_value_type by + /// index. + /// \tparam I the index of the element + template + using element_type = + typename std::tuple_element::type; + + /// Creates a new instance. + /// + /// \param Begin the beginning of the iterator range to buffer + /// \param End the end of the iterator range to buffer + TupleIteratorBuffer(TupleIterator &&Begin, const TupleIterator &End) noexcept + : Iterator(Begin), End(End), Buffer() {} + + /// Tells whether there is any more value in the handled range for index \p I. + /// + /// \tparam I the index of the element to check + /// + /// \return whether there is more value for index \p I + template bool hasMore(void) const noexcept { + const auto &ElementBuffer = std::get(Buffer); + // There is more value if some has already been buffered or the end of the + // handled range is not reached yet. + return !ElementBuffer.empty() || Iterator != End; + } + + /// Gives the next value from the handled range for index \p I. + /// + /// \note The function should not be called if there is no more value for + /// index \p I (i.e., \c hasMore() returns \c false). If it is called in + /// that situation, it returns the default value of \c element_type. + /// + /// \tparam I the index of the element to fetch next value for + /// + /// \return the next value for index \p I + template element_type next(void) noexcept { + auto &ElementBuffer = std::get(Buffer); + if (ElementBuffer.empty()) { + // This position needs a new value from Iterator if there is more. + if (Iterator != End) { + // Push next value for all elements. + push(*Iterator++, seq_t()); + } else { + // No more values; called when hasMore() is false. + // Return default value. + return element_type(); + } + } + // Buffer is not empty here, return the next value. + ASSERT(!ElementBuffer.empty() && "Unexpected condition"); + // Get the next value and also pop it from the buffer. + const element_type Elem = ElementBuffer.front(); + ElementBuffer.pop(); + return Elem; + } + +private: + /// Buffers next tuple value elementwise into element containers. + /// + /// \tparam S0 indices for accessing elements of \c std::tuple + /// + /// \param Tuple the values to buffer + /// + /// \note The second parameter provides indices as template parameter \p S0 + /// and its actual value is ignored. + template + void push(const iterator_value_type &Tuple, Seq) noexcept { + (std::get(Buffer).push(std::get(Tuple)), ...); + } + + TupleIterator Iterator; ///< Current input iterator + const TupleIterator End; ///< End of iterator range to handle + tuple_buffer_container_t + Buffer; ///< Container for elementwise buffering +}; + +/// Template type alias for iterator of an element based on buffered iterator of +/// \c std::tuple. +/// +/// The alias utilizes \c SplittedElementIterator for iterating over the values +/// provided by \p TB. +/// +/// \tparam TB buffer providing values to iterate +/// \tparam I index of the values to iterator from \p TB +template +using element_iterator_t = SplittedElementIterator; + +/// Template type alias for iterator-range of an element based on buffered +/// iterator of \c std::tuple. +/// +/// \tparam TB buffer providing values to iterate +/// \tparam I index of the values to iterator from \p TB +template +using element_iterator_range_t = + std::pair, element_iterator_t>; + +///\defgroup ElementIteratorRanges Type converter turning a buffer of \c +/// std::tuple into a \c std::tuple of corresponding \c +/// element_iterator_range_t. +/// +///@{ + +/// Template declaration. +/// +/// \tparam TB buffer providing values +/// \tparam S type providing indices for accessing elements of \c std::tuple +/// +/// \note \p TB is expected to implement an interface matching that of \c +/// TupleIteratorBuffer. +/// +/// \note The template is defined only when \p S is a \c rosa::Seq. +/// +/// Usage for a proper buffer type \c TB:\code +/// typename ElementIteratorRanges>::Type +/// \endcode +template struct ElementIteratorRanges; + +/// Template definition. +template +struct ElementIteratorRanges> { + /// The converted type. + using Type = std::tuple...>; +}; + +///@} + +/// Convenience template type alias for easy use of \c ElementIteratorRanges. +/// +/// Converts a buffer of \c std::tuple into a \c std::tuple of corresponding \c +/// element_iterator_range_t. +/// +/// \tparam TB buffer providing values +/// +/// \note \p TB is expected to implement an interface matching that of \c +/// TupleIteratorBuffer. +template +using element_iterator_ranges_t = + typename ElementIteratorRanges>::Type; + +/// Template type alias for turning an iterator of \c std::tuple into +/// corresponding \c element_iterator_ranges_t. +/// +/// The alias utilizes \c TupleIteratorBuffer for buffering the values provided +/// by \p TupleIterator. The elementwise iterators are \c +/// SplittedElementIterator. +/// +/// \tparam TupleIterator iterator of \c std::tuple +template +using splitted_tuple_iterator_ranges_t = + element_iterator_ranges_t>; + +/// Creates elementwise iterator ranges for an iterator range of \c std::tuple. +/// +/// \note Implementation for \c rosa::iterator::splitTupleIterator. +/// +/// \tparam TupleIterator iterator of \c std::tuple +/// \tparam S0 indices for accessing elements of \c std::tuple +/// +/// \param Begin the beginning of the iterator range to handle +/// \param End the end of the iterator range to handle +/// +/// \note The last parameter provides indices as template parameter \p S0 and +/// its actual value is ignored. +/// +/// \return \c std::tuple of elementwise iterator ranges corresponding to \p +/// Begin and \p End +template +splitted_tuple_iterator_ranges_t +splitTupleIteratorImpl(TupleIterator &&Begin, const TupleIterator &End, + Seq) noexcept { + using TB = TupleIteratorBuffer; + // Create a buffer in shared pointer. The buffer will be destructed once + // all corresponding element iterators (created below) have reached the end of + // the handled range or have been destructed. + auto Buffer = std::make_shared(std::move(Begin), End); + return {std::make_pair(element_iterator_t(Buffer), + element_iterator_t())...}; +} + +} // End namespace + +/// Creates elementwise iterator ranges for an iterator range of \c std::tuple. +/// +/// \note The implementation utilizes \c splitTupleIteratorImpl. +/// +/// Obtain element iterator ranges for an iterator range \c Begin and \c End of +/// iterator type \c TupleIterator of \c std::tuple as \code +/// auto [T1Range, T2Range, T3Range] = splitTupleIterator(std::move(Begin), End); +/// auto [T1Begin, T1End] = T1Range; +/// auto [T2Begin, T2End] = T2Range; +/// auto [T3Begin, T3End] = T3Range; +/// \endcode +/// +/// The function returns a tuple of ranges (i.e., \c std::pair of iterators), +/// which can be assigned to variables using structured binding. The ranges can +/// be dissected into begin and end iterators by separate structured bindings. +/// +/// The function moves its first argument (i.e., \p Begin cannot be used after +/// splitting it). If the first argument is a variable, it needs to be moved +/// explicitly by \c std::move() as in the example. +/// +/// \tparam TupleIterator iterator of \c std::tuple +/// +/// \param Begin the beginning of the iterator range to handle +/// \param End the end of the iterator range to handle +/// +/// \return \c std::tuple of elementwise iterator ranges corresponding to \p +/// Begin and \p End +template +splitted_tuple_iterator_ranges_t +splitTupleIterator(TupleIterator &&Begin, const TupleIterator &End) noexcept { + return splitTupleIteratorImpl( + std::move(Begin), End, + seq_t>()); +} + +} // End namespace iterator +} // End namespace rosa + +#endif // ROSA_SUPPORT_ITERATOR_SPLIT_TUPLE_ITERATOR_HPP diff --git a/lib/support/CMakeLists.txt b/lib/support/CMakeLists.txt index 6e191ef..12a3334 100644 --- a/lib/support/CMakeLists.txt +++ b/lib/support/CMakeLists.txt @@ -1,38 +1,42 @@ set(LIB_INCLUDE_DIR ${ROSA_MAIN_INCLUDE_DIR}/rosa/support) add_library(ROSASupport ${LIB_INCLUDE_DIR}/debug.hpp debug.cpp ${LIB_INCLUDE_DIR}/terminal_colors.h terminal_colors.cpp ${LIB_INCLUDE_DIR}/log.h log.cpp ${LIB_INCLUDE_DIR}/math.hpp math.cpp ${LIB_INCLUDE_DIR}/type_helper.hpp type_helper.cpp ${LIB_INCLUDE_DIR}/types.hpp types.cpp ${LIB_INCLUDE_DIR}/atom.hpp atom.cpp ${LIB_INCLUDE_DIR}/type_pair.hpp type_pair.cpp ${LIB_INCLUDE_DIR}/type_list.hpp type_list.cpp ${LIB_INCLUDE_DIR}/squashed_int.hpp squashed_int.cpp ${LIB_INCLUDE_DIR}/type_numbers.hpp type_numbers.cpp ${LIB_INCLUDE_DIR}/type_token.hpp type_token.cpp ${LIB_INCLUDE_DIR}/tokenized_storages.hpp tokenized_storages.cpp ${LIB_INCLUDE_DIR}/sequence.hpp sequence.cpp ${LIB_INCLUDE_DIR}/csv/namespace.h csv/namespace.cpp ${LIB_INCLUDE_DIR}/csv/CSVReader.hpp csv/CSVReader.cpp ${LIB_INCLUDE_DIR}/csv/CSVWriter.hpp csv/CSVWriter.cpp + ${LIB_INCLUDE_DIR}/iterator/namespace.h + iterator/namespace.cpp + ${LIB_INCLUDE_DIR}/iterator/split_tuple_iterator.hpp + iterator/split_tuple_iterator.cpp ) diff --git a/lib/support/iterator/namespace.cpp b/lib/support/iterator/namespace.cpp new file mode 100644 index 0000000..57fe49f --- /dev/null +++ b/lib/support/iterator/namespace.cpp @@ -0,0 +1,20 @@ +//===-- support/iterator/namespace.cpp --------------------------*- C++ -*-===/ +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===/ +/// +/// \file support/iterator/namespace.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Placeholder for rosa/support/iterator/namespace.h. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/support/iterator/namespace.h. +/// +//===----------------------------------------------------------------------===/ + +#include "rosa/support/iterator/namespace.h" diff --git a/lib/support/iterator/split_tuple_iterator.cpp b/lib/support/iterator/split_tuple_iterator.cpp new file mode 100644 index 0000000..72f4f1f --- /dev/null +++ b/lib/support/iterator/split_tuple_iterator.cpp @@ -0,0 +1,20 @@ +//===-- support/iterator/split_tuple_iterator.cpp ---------------*- C++ -*-===/ +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===/ +/// +/// \file support/iterator/split_tuple_iterator.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Implementation for rosa/support/iterator/split_tuple_iterator.hpp. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/support/iterator/split_tuple_iterator.hpp. +/// +//===----------------------------------------------------------------------===/ + +#include "rosa/support/iterator/split_tuple_iterator.hpp"