Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F386530
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Size
20 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/include/rosa/support/writer/split_tuple_writer.hpp b/include/rosa/support/writer/split_tuple_writer.hpp
index 22e3a35..d98ace2 100644
--- a/include/rosa/support/writer/split_tuple_writer.hpp
+++ b/include/rosa/support/writer/split_tuple_writer.hpp
@@ -1,554 +1,562 @@
//===-- 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 <memory>
#include <tuple>
#include <queue>
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
+ Flush, ///< flush incomplete tuples, use default value for missing elements
+#ifndef NDEBUG
+ DbgFail ///< fail with an assertion, available only in debug build
+#endif // !defined NDEBUG
};
/// 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 <typename TB, size_t I>
class SplittedElementWriter {
public:
/// Type alias for the values the writer writes.
using T = typename TB::template element_type<I>;
/// \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<TB> 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<I>();
}
/// 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<I>(V); }
private:
std::shared_ptr<TB> 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 <typename TB, size_t I>
SplittedElementWriter<TB, I> &
operator<<(SplittedElementWriter<TB, I> &W,
const typename SplittedElementWriter<TB, I>::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<Tuple>::Type
/// \endcode
template <typename T> struct TupleBufferContainer;
/// Template definition for \c std::tuple.
template <typename... Ts> struct TupleBufferContainer<std::tuple<Ts...>> {
/// The converted type.
using Type = std::tuple<std::queue<Ts>...>;
};
///@}
/// 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 <typename Tuple>
using tuple_buffer_container_t = typename TupleBufferContainer<Tuple>::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 <typename TupleWriter>
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<writer_value_type>;
/// Template type alias to get element types of \c writer_value_type by
/// index.
/// \tparam I the index of the element
template <size_t I>
using element_type =
typename std::tuple_element<I, writer_value_type>::type;
/// Type alias for index sequence for accessing elements of \c
/// writer_value_size.
using element_idx_seq_t = seq_t<writer_value_size>;
/// 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;
+#ifndef NDEBUG
+ case DbgFail:
+ ASSERT(empty(element_idx_seq_t()) && "Non-empty buffer");
+ break;
+#endif // !defined NDEBUG
}
}
}
/// 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 I> size_t buffered(void) const noexcept {
return std::get<I>(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<I>() calls has no
/// effect and the last \c buffered<I>() 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 <size_t I> void write(const element_type<I> &V) {
ASSERT(!hasCompleteTuple(element_idx_seq_t()));
if (good()) {
std::get<I>(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 <size_t... S0> bool empty(Seq<S0...>) const noexcept {
return (true && ... && std::get<S0>(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 <size_t... S0> bool hasCompleteTuple(Seq<S0...>) const noexcept {
return (true && ... && !std::get<S0>(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 <size_t... S0> void makeCompleteTuple(Seq<S0...>) noexcept {
auto addDefaultIfEmpty = [](auto &Queue) {
if (Queue.empty()) {
Queue.emplace(); // default construct a value in the empty queue.
}
};
(addDefaultIfEmpty(std::get<S0>(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 <size_t... S0> writer_value_type front(Seq<S0...>) const noexcept {
ASSERT(hasCompleteTuple(element_idx_seq_t()));
return {std::get<S0>(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 <size_t... S0> void pop(Seq<S0...>) noexcept {
ASSERT(hasCompleteTuple(element_idx_seq_t()));
(std::get<S0>(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<writer_value_type>
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 <typename TB, size_t I>
using element_writer_t = SplittedElementWriter<TB, I>;
///\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<TB, typename TB::element_idx_seq_t>::Type
/// \endcode
template <typename TB, typename S> struct ElementWriters;
/// Template definition.
template <typename TB, size_t... S0>
struct ElementWriters<TB, Seq<S0...>> {
/// The converted type.
using Type = std::tuple<element_writer_t<TB, S0>...>;
};
///@}
/// 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 <typename TB>
using element_writers_t =
typename ElementWriters<TB, typename TB::element_idx_seq_t>::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 <typename TupleWriter>
using splitted_tuple_writers_t =
element_writers_t<TupleWriterBuffer<TupleWriter>>;
/// 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 <typename TupleWriter, size_t... S0>
splitted_tuple_writers_t<TupleWriter>
splitTupleWriterImpl(TupleWriter &&Writer, const IncompleteTuplePolicy Policy,
Seq<S0...>) noexcept {
using TB = TupleWriterBuffer<TupleWriter>;
// 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<TB>(std::move(Writer), Policy);
return {element_writer_t<TB, S0>(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<T1, T2, T3> 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 <typename TupleWriter>
splitted_tuple_writers_t<TupleWriter>
splitTupleWriter(TupleWriter &&Writer,
const IncompleteTuplePolicy Policy) noexcept {
return splitTupleWriterImpl(
std::move(Writer), Policy,
seq_t<std::tuple_size_v<typename TupleWriter::value_type>>());
}
} // End namespace writer
} // End namespace rosa
#endif // ROSA_SUPPORT_WRITER_SPLIT_TUPLE_WRITER_HPP
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jul 3, 7:51 PM (6 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
157336
Default Alt Text
(20 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment