diff --git a/include/rosa/support/csv/CSVWriter.hpp b/include/rosa/support/csv/CSVWriter.hpp index 574806b..1c06bbb 100755 --- a/include/rosa/support/csv/CSVWriter.hpp +++ b/include/rosa/support/csv/CSVWriter.hpp @@ -1,152 +1,161 @@ //===-- rosa/support/csv/CSVWriter.hpp --------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/csv/CSVWriter.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Facitilities to write CSV files. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_CSV_CSVWRITER_HPP #define ROSA_SUPPORT_CSV_CSVWRITER_HPP #include #include #include namespace rosa { namespace csv { /// Provides facilities to write values into a CSV file. /// /// The writer emits a comma, the character `,`, between each written values. /// The resulted stream is a flat CSV file as it consists of onlyone row, no new /// line is emitted. /// /// \tparam T type of values to write template class CSVWriter { public: + /// \defgroup CSVWriterTypedefs Typedefs of rosa::csv::CSVWriter + /// + /// Useful `typedef`s for writers. + /// + ///@{ + typedef T value_type; ///< Type of values written + typedef T &reference; ///< Reference to the type written + ///@} + /// Creates a new instance. /// /// \param [in,out] S output stream to write to /// /// \note The writer operates on non-binary outputs as long as \p S is in /// good state. CSVWriter(std::ostream &S) : Str(S.good() && !(S.flags() & std::ios::binary) ? &S : nullptr), IsFirst(true) {} /// Tells if the last operation was successful. /// /// \return if the last operation was successful bool good(void) const noexcept { return Str != nullptr; } /// Writes an entry to the output stream. /// /// The implementation does anything only if the last operation was /// successful. If so, \p V is written to \c rosa::csv::CSVWriter::Str. /// The emitted value is preceded with a comma if the actual call is not the /// first one for \p this object. Success of the operation is checked at the /// end. /// /// \param V value to write void write(const T &V) { if (Str) { if (!IsFirst) { *Str << ','; } else { IsFirst = false; } *Str << V; if (!Str->good()) { Str = nullptr; } } } private: std::ostream *Str; ///< Output stream to write to. bool IsFirst; ///< Denotes if the next write would be the first one. }; /// Writes a tuple of values into a CSV file /// /// \tparam Ts tpyes of values to write template class CSVTupleWriter { public: /// Creates a new instance. /// /// \param [in,out] S output stream to write to /// /// \note The writer operates on non-binary outputs as long as \p S is in /// good state. CSVTupleWriter(std::ostream &S) : Str(S.good() && !(S.flags() & std::ios::binary) ? &S : nullptr), IsFirst(true) {} /// Tells if the last operation was successful. /// /// \return if the last operation was successful bool good(void) const noexcept { return Str != nullptr; } template void write(std::tuple values) { size_t size = 0; std::cout << "Writing tuple values into file" << std::endl; std::cout << "Tuple has "; std::cout << std::tuple_size::value; std::cout << " elements." << std::endl; size = std::tuple_size::value; std::cout << std::get(values) << std::endl; if(Str){ if constexpr(i+1 != sizeof...(Ts)){ *Str << std::get(values) << " ,"; write(values); }else if constexpr(i + 1 == sizeof...(Ts)){ *Str << std::get(values) << '\n'; } } } private: std::ostream *Str; ///< Output stream to write to. bool IsFirst; ///< Denotes if the next write would be the first one. }; /// Writes a value to a CSV file with \c rosa::csv::CSVWriter. /// /// \see rosa::csv::CSVWriter /// /// \tparam T type of value to write /// /// \param [in,out] W object to write with /// \param V value to write /// /// \return \p W after writing \p V with it template CSVWriter &operator<<(CSVWriter &W, const T& V) { W.write(V); return W; } } // End namespace csv } // End namespace rosa #endif // ROSA_SUPPORT_CSV_CSVWRITER_HPP diff --git a/include/rosa/support/iterator/split_tuple_iterator.hpp b/include/rosa/support/iterator/split_tuple_iterator.hpp index f64b346..3d1b9e9 100644 --- a/include/rosa/support/iterator/split_tuple_iterator.hpp +++ b/include/rosa/support/iterator/split_tuple_iterator.hpp @@ -1,427 +1,431 @@ //===-- 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; + /// Type alias for index sequence for accessing elements of \c + /// iterator_value_type. + using element_idx_seq_t = seq_t; + /// 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()); + push(*Iterator++, element_idx_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 +/// 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; + 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. +/// The function moves its first argument (i.e., \p Begin cannot be used +/// directly 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/include/rosa/support/writer/namespace.h b/include/rosa/support/writer/namespace.h new file mode 100644 index 0000000..3349a93 --- /dev/null +++ b/include/rosa/support/writer/namespace.h @@ -0,0 +1,25 @@ +//===-- rosa/support/writer/namespace.h --------------------------*- C++ -*-===/ +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===/ +/// +/// \file rosa/support/writer/namespace.h +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Documentation for the namespace \c rosa::writer. +/// +//===----------------------------------------------------------------------===/ + +#ifndef ROSA_SUPPORT_WRITER_NAMESPACE_H +#define ROSA_SUPPORT_WRITER_NAMESPACE_H + +namespace rosa { +/// Provides facilities to work with writers. +namespace writer {} +} // End namespace rosa + +#endif // ROSA_SUPPORT_WRITER_NAMESPACE_H diff --git a/include/rosa/support/writer/split_tuple_writer.hpp b/include/rosa/support/writer/split_tuple_writer.hpp new file mode 100644 index 0000000..22e3a35 --- /dev/null +++ b/include/rosa/support/writer/split_tuple_writer.hpp @@ -0,0 +1,554 @@ +//===-- rosa/support/writer/split_tuple_writer.hpp ---------------*- C++ -*-===/ +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===/ +/// +/// \file rosa/support/writer/split_tuple_writer.hpp +/// +/// \authors David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Facilities to split writers of \c std::tuple into writers of +/// their elements. +/// +//===----------------------------------------------------------------------===/ + +#ifndef ROSA_SUPPORT_WRITER_SPLIT_TUPLE_WRITER_HPP +#define ROSA_SUPPORT_WRITER_SPLIT_TUPLE_WRITER_HPP + +#include "rosa/support/debug.hpp" +#include "rosa/support/sequence.hpp" + +#include +#include +#include + +namespace rosa { +namespace writer { + +/// What to do when splitted element writers got destructed so that some +/// incomplete tuples remain in the buffer. +enum IncompleteTuplePolicy { + Ignore, ///< ignore incomplete tuples, data discarded + Flush ///< flush incomplete tuples, use default value for missing elements +}; + +/// Anonymous namespace providing implementation for splitting tuple writers; +/// consider it private. +namespace { + +/// Writes values into a buffer based on an index. +/// +/// The values are first buffered and flushed out later once a corresponding +/// tuple gets complete (i.e., other elementwise writers put the corresponding +/// values into the buffer). Since the underlying buffer waits for tuples to +/// become complete, the elementwise writers are expected to provide the same +/// number of values for the buffer (i.e., completing all tuples that have an +/// element). That is, however, not enforced in any ways. +/// +/// Once all elementwise writers are destructed, the underlying buffer gets +/// destructed as well. Should the buffer contain some values, which are +/// elements of incomplete tuples, the destructor of the buffer handles the +/// situation according to the \c rosa::writer::IncompleteTuplePolicy set when +/// the elementwise writers were created by \c rosa::writer::splitTupleWriter(). +/// +/// \tparam TB buffer to write into +/// \tparam I index of the values to write to \p TB +/// +/// \note \p TB is expected to implemnet an interface matching that of \c +/// TupleWriterBuffer. +/// +/// \note the +template +class SplittedElementWriter { +public: + /// Type alias for the values the writer writes. + using T = typename TB::template element_type; + + /// \defgroup SplittedElemenWriterTypedefs Typedefs of + /// \c SplittedElementWriter + /// + /// Useful `typedef`s for writers. + /// + ///@{ + typedef T value_type; ///< Type of values written. + typedef T &reference; ///< Reference to the type written + ///@} + + /// Creates a new instance. + /// + /// \param Buffer buffer \p this object writes values into + /// + /// \note \p Buffer is captured as a \c std::shared_ptr because it is shared + /// among writers for its element positions. + SplittedElementWriter(std::shared_ptr Buffer) : Buffer(Buffer) {} + + /// Tells how many values are still in the buffer. + /// + /// Values are buffered as long as all elements of their corresponding tuples + /// are written into the buffer by other elementwise writers and in turn + /// complete tuples written by the buffer itself. This function tells how many + /// values are still in the buffer waiting for their containing tuples to be + /// complete and written out from the buffer. + /// + /// \note The function simply calles the corresponding function of \p TB. + /// + /// \return how many values are still in the buffer. + size_t buffered(void) const noexcept { + return Buffer->template buffered(); + } + + /// Tells if the last write operation of the buffer was successful. + /// + /// Values are buffered until their corresponding tuples gets complete. The + /// buffer writes complete tuples by the underlying writer. This function + /// tells if the buffer successfully has written the latest complete tuple by + /// the underlying writer. + /// + /// Once this function returns \c false, further \c write() calls has no + /// effect and the last \c buffered() values will not be written to the + /// underlying writer of \c std::tuple. + /// + /// \note The function simply calles the corresponding function of \p TB. + /// + /// \return if the last write operation was successful + bool good(void) const noexcept { return Buffer->good(); } + + /// Writes an entry to the buffer. + /// + /// The function has no effect if an earlier write operation of the buffer has + /// failed, that is \c good() returns \c false. + /// + /// \note The function simply calles the corresponding function of \p TB. + /// + /// \param V value to write + void write(const T &V) { Buffer->template write(V); } + +private: + std::shared_ptr Buffer; ///< Buffer \p this object writes into +}; + +/// Writes an element of a tuple. +/// +/// \see SplittedElementWriter +/// +/// \tparam TB type of the buffer \p W writes into +/// \tparam I index of the values \p W write to \p TB +/// +/// \param [in,out] W object to write with +/// \param V value to write +/// +/// \return \p W after writing \p V with it +template +SplittedElementWriter & +operator<<(SplittedElementWriter &W, + const typename SplittedElementWriter::value_type &V) { + W.write(V); + return W; +} + +///\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 writer of \c std::tuple. +/// +/// The class can be instantiated with a writer of \c std::tuple and provides +/// an interface for writing elements into tuples one by one. +/// +/// \note The class is utilized by \c SplittedElementWriter. +/// +/// \tparam TupleWriter the writer type that handles values of \c std::tuple +/// +/// \note The elements of the written \c std::tuple need to be default +/// constructible because of \c rosa::writer::IncompleteTuplePolicy::Flush. +/// +/// \todo Consider thread safety of the class. +template +class TupleWriterBuffer { +public: + /// Type alias for the value type of \p TupleWriter. + /// \note The type is expected to be \c std::tuple. + using writer_value_type = typename TupleWriter::value_type; + + /// The number of elements of \c writer_value_type. + static constexpr size_t writer_value_size = + std::tuple_size_v; + + /// Template type alias to get element types of \c writer_value_type by + /// index. + /// \tparam I the index of the element + template + using element_type = + typename std::tuple_element::type; + + /// Type alias for index sequence for accessing elements of \c + /// writer_value_size. + using element_idx_seq_t = seq_t; + + /// Creates a new instance. + /// + /// \param Writer the writer \p this object uses to write tuples + /// \param Policy what to do with incomplete tuples when destructing \p + /// this object + TupleWriterBuffer(TupleWriter &&Writer, + const IncompleteTuplePolicy Policy) noexcept + : Writer(Writer), Policy(Policy), Buffer() {} + + /// Destructor. + /// + /// Should \p this object has some values in \c Buffer (i.e., incomplete + /// tuples), the destructor takes care of them according to \c Policy. + /// + /// \note The destructor may flush the buffered values if the last write + /// operation was successful, that is \c good() returns \c true. + ~TupleWriterBuffer(void) noexcept { + if (good()) { + switch (Policy) { + default: + ASSERT(false && "Unexpected Policy"); + case Ignore: + // Do not care about incomplete tuples in the buffer. + break; + case Flush: + // Whatever we have in the buffer, flush it out. + flush(); + break; + } + } + } + + /// Tells how many values are in the buffer for index \p I. + /// + /// \tparam I the index of the element to check + /// + /// \return the number of values in buffer for index \p I + template size_t buffered(void) const noexcept { + return std::get(Buffer).size(); + } + + /// Tells if the last write operation was successful. + /// + /// Values are buffered until their corresponding tuples gets complete. + /// Once a tuple becomes complete, it is written by \c Writer. This function + /// tells if writing the latest complete tuple was successful. + /// + /// Once this function returns \c false, further \c write() calls has no + /// effect and the last \c buffered() values will not be written to the + /// underlying writer of \c std::tuple. + /// + /// \return if the last write operation was successful + bool good(void) const noexcept { return Writer.good(); } + + /// Writes an entry to the buffer for index \p I. + /// + /// The function has no effect if an earlier write operation of the buffer has + /// failed, that is \c good() returns \c false. + /// + /// The value is buffered first and written by \p Writer once its + /// corresponding tuple becomes complete (i.e., all other elements of the + /// tuple are written into \p this object by corresponding elementwise + /// writers). + /// + /// \tparam I the index of the element to write + /// + /// \param V value to write + template void write(const element_type &V) { + ASSERT(!hasCompleteTuple(element_idx_seq_t())); + if (good()) { + std::get(Buffer).push(V); + if (hasCompleteTuple(element_idx_seq_t())) { + writeTuple(false); + } + } + ASSERT(!hasCompleteTuple(element_idx_seq_t())); + } + +private: + /// Tells whether \c Buffer is completely empty, all elements of it are empty. + /// + /// \tparam S0 indices for accessing elements of \c std::tuple + /// + /// \note The parameter provides indices as template parameter \p S0 and its + /// actual value is ignored. + /// + /// \return whether all elements of \c Buffer are empty + template bool empty(Seq) const noexcept { + return (true && ... && std::get(Buffer).empty()); + } + + /// Tells whether \c Buffer contains at least one complete tuple. + /// + /// \tparam S0 indices for accessing elements of \c std::tuple + /// + /// \note The parameter provides indices as template parameter \p S0 and its + /// actual value is ignored. + /// + /// \return whether there is at least one complete tuple in \c Buffer + template bool hasCompleteTuple(Seq) const noexcept { + return (true && ... && !std::get(Buffer).empty()); + } + + /// Makes sure \c Buffer has one complete tuple in front. + /// + /// If the tuple in front of \c Buffer is not complete, missing elements are + /// default constructed in \c Buffer to complete the tuple. + /// + /// \tparam S0 indices for accessing elements of \c std::tuple + /// + /// \note The parameter provides indices as template parameter \p S0 and its + /// actual value is ignored. + template void makeCompleteTuple(Seq) noexcept { + auto addDefaultIfEmpty = [](auto &Queue) { + if (Queue.empty()) { + Queue.emplace(); // default construct a value in the empty queue. + } + }; + (addDefaultIfEmpty(std::get(Buffer)), ...); + } + + /// Gives the first complete tuple from \c Buffer. + /// + /// \tparam S0 indices for accessing elements of \c std::tuple + /// + /// \note The parameter provides indices as template parameter \p S0 and its + /// actual value is ignored. + /// + /// \return the first complete tuple from \c Buffer + /// + /// \pre There is at least one complete tuple in \c Buffer:\code + /// hasCompleteTuple(element_idx_seq_t()) + /// \endcode + template writer_value_type front(Seq) const noexcept { + ASSERT(hasCompleteTuple(element_idx_seq_t())); + return {std::get(Buffer).front()...}; + } + + /// Removes the first complete tuple from \c Buffer. + /// + /// \tparam S0 indices for accessing elements of \c std::tuple + /// + /// \note The parameter provides indices as template parameter \p S0 and its + /// actual value is ignored. + /// + /// \pre There is at least one complete tuple in \c Buffer:\code + /// hasCompleteTuple(element_idx_seq_t()) + /// \endcode + template void pop(Seq) noexcept { + ASSERT(hasCompleteTuple(element_idx_seq_t())); + (std::get(Buffer).pop(), ...); + } + + /// Takes the first tuple from \c Buffer and writes it with \c Writer. + /// + /// \c Buffer need to contain a complete tuple to write it with \c Writer. The + /// function makes sure that the tuple in front of \c Buffer is complete if \p + /// MakeComplete is true. The tuple in fron of \c Buffer are expected to be + /// complete otherwise. + /// + /// \param MakeComplete whether to make the first tuple complete + /// + /// \pre There is at least one complete tuple in \c Buffer if not \p + /// MakeComplete: \code + /// MakeComplete || hasCompleteTuple(element_idx_seq_t()) + /// \endcode + void writeTuple(const bool MakeComplete) noexcept { + if (MakeComplete) { + makeCompleteTuple(element_idx_seq_t()); + } + ASSERT(hasCompleteTuple(element_idx_seq_t())); + Writer.write(front(element_idx_seq_t())); + pop(element_idx_seq_t()); + } + + /// Empties \c Buffer by writing out all tuples from it so that missing + /// elements of incomplete tuples are extended with default constructed + /// values. + void flush(void) noexcept { + while (!empty(element_idx_seq_t())) { + ASSERT(!hasCompleteTuple(element_idx_seq_t())); // Sanity check. + writeTuple(true); + } + } + + TupleWriter Writer; ///< The splitted writer + const IncompleteTuplePolicy Policy; ///< what to do with incomplete tuples + ///< when destructing \p this object + tuple_buffer_container_t + Buffer; ///< Container for elementwise buffering +}; + +/// Template type alias for writer of an element based on buffered writer of +/// \c std::tuple. +/// +/// The alias utilizes \c SplittedElementWriter for writing element values by +/// \p TB. +/// +/// \tparam TB buffer to write into +/// \tparam I index of the values to write to \p TB +template +using element_writer_t = SplittedElementWriter; + +///\defgroup ElementWriters Type converter turning a buffer of \c std::tuple +///into a \c std::tuple of corresponding \c element_writer_t. +/// +///@{ + +/// Template declaration. +/// +/// \tparam TB buffer to write into +/// \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 +/// TupleWriterBuffer. +/// +/// \note The template is defined only when \p S is a \c rosa::Seq. +/// +/// Usage for a proper buffer type \c TB:\code +/// typename ElementIteratorWriters::Type +/// \endcode +template struct ElementWriters; + +/// Template definition. +template +struct ElementWriters> { + /// The converted type. + using Type = std::tuple...>; +}; + +///@} + +/// Convenience template type alias for easy use of \c ElementIteratorWriters. +/// +/// Converts a buffer of \c std::tuple into a \c std::tuple of corresponding \c +/// element_writer_t. +/// +/// \tparam TB buffer to write into +/// +/// \note \p TB is expected to implement an interface matching that of \c +/// TupleWriterBuffer. +template +using element_writers_t = + typename ElementWriters::Type; + +/// Template type alias for turning a writer of \c std::tuple into +/// corresponding \c element_writers_t. +/// +/// The alias utilizes \c TupleWriterBuffer for buffering values before writing +/// them by \p TupleWriter. The elementwise writers are \c +/// SplittedElementWriter. +/// +/// \tparam TupleWriter writer of \c std::tuple +template +using splitted_tuple_writers_t = + element_writers_t>; + +/// Creates elementwise writers for a writer of \c std::tuple. +/// +/// \note Implementation for \c rosa::iterator::splitTupleWriter. +/// +/// \tparam TupleWriter writer of \c std::tuple +/// \tparam S0 indices for accessing elements of \c std::tuple +/// +/// \param Writer the writer to write tuples with +/// \param Policy how to handle incomplete tuples when destructing the +/// underlying buffer +/// +/// \note The last parameter provides indices as template parameter \p S0 and +/// its actual value is ignored. +/// +/// \return \c std::tuple of elementwise writers corresponding to \p Writer +template +splitted_tuple_writers_t +splitTupleWriterImpl(TupleWriter &&Writer, const IncompleteTuplePolicy Policy, + Seq) noexcept { + using TB = TupleWriterBuffer; + // Create a buffer in shared pointer. The buffer will be destructed once + // all corresponding element writers (created below) have been destructed. + auto Buffer = std::make_shared(std::move(Writer), Policy); + return {element_writer_t(Buffer)...}; +} + +} // End namespace + +/// Creates elementwise writers for a writer of \c std::tuple. +/// +/// \note The implementation utilizes \c splitTupleWriterImpl. +/// +/// Obtain elementwise writers for a writer \p Writer of type \c TupleWriter of +/// \c std::tuple as \code +/// auto [T1Writer, T2Writer, T3Writer] = splitTupleWriter(std::move(Writer), +/// Ignore); +/// \endcode +/// +/// The function returns a tuple of writers, which can be assigned to variables +/// using structured binding. +/// +/// The function moves its first argument (i.e., \p Writer cannot be used +/// directly after splitting it). If the first argument is a variable, it needs +/// to be moved explicitly by \c std::move() as in the example. +/// +/// While a tuple could be written with \p Writer directly as \code +/// Writer << std::make_tuple(T1(), T2(), T3()); +/// \endcode The same tuple is written with splitted writers as \code +/// T1Writer << T1(); +/// T2Writer << T2(); +/// T3Writer << T3(); +/// \endcode +/// +/// \tparam TupleWriter writer of \c std::tuple +/// +/// \note The elements of the written \c std::tuple need to be default +/// constructible because of \c rosa::writer::IncompleteTuplePolicy::Flush. +/// +/// \param Writer the writer to write tuples with +/// \param Policy what to do with incomplete tuples when destructing the +/// underlying buffer +/// +/// \return \c std::tuple of elementwise writers corresponding to \p Writer +template +splitted_tuple_writers_t +splitTupleWriter(TupleWriter &&Writer, + const IncompleteTuplePolicy Policy) noexcept { + return splitTupleWriterImpl( + std::move(Writer), Policy, + seq_t>()); +} + +} // End namespace writer +} // End namespace rosa + +#endif // ROSA_SUPPORT_WRITER_SPLIT_TUPLE_WRITER_HPP diff --git a/lib/support/CMakeLists.txt b/lib/support/CMakeLists.txt index 12a3334..318486d 100644 --- a/lib/support/CMakeLists.txt +++ b/lib/support/CMakeLists.txt @@ -1,42 +1,46 @@ 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 + ${LIB_INCLUDE_DIR}/writer/namespace.h + writer/namespace.cpp + ${LIB_INCLUDE_DIR}/writer/split_tuple_writer.hpp + writer/split_tuple_writer.cpp ) diff --git a/lib/support/writer/namespace.cpp b/lib/support/writer/namespace.cpp new file mode 100644 index 0000000..b659e2d --- /dev/null +++ b/lib/support/writer/namespace.cpp @@ -0,0 +1,20 @@ +//===-- support/writer/namespace.cpp -----------------------------*- C++ -*-===/ +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===/ +/// +/// \file support/writer/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/writer/namespace.h. +/// +//===----------------------------------------------------------------------===/ + +#include "rosa/support/writer/namespace.h" diff --git a/lib/support/writer/split_tuple_writer.cpp b/lib/support/writer/split_tuple_writer.cpp new file mode 100644 index 0000000..651e012 --- /dev/null +++ b/lib/support/writer/split_tuple_writer.cpp @@ -0,0 +1,20 @@ +//===-- support/writer/split_tuple_writer.cpp --------------------*- C++ -*-===/ +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===/ +/// +/// \file support/writer/split_tuple_writer.cpp +/// +/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Implementation for rosa/support/writer/split_tuple_writer.hpp. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/support/writer/split_tuple_writer.hpp. +/// +//===----------------------------------------------------------------------===/ + +#include "rosa/support/writer/split_tuple_writer.hpp"