From 66e8acfd5b6d65770bfdb1ccb26a4cd08f14136a Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Wed, 3 Apr 2024 15:53:43 -0400 Subject: [PATCH] List delimiting primitive for output streams. --- CMakeLists.txt | 2 + delimited_list.cc | 79 ++++++++++++++++++++++++++++++ delimited_list.h | 42 ++++++++++++++++ delimited_list.test/0.cc | 35 +++++++++++++ delimited_list.test/CMakeLists.txt | 1 + 5 files changed, 159 insertions(+) create mode 100644 delimited_list.cc create mode 100644 delimited_list.h create mode 100644 delimited_list.test/0.cc create mode 100644 delimited_list.test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 77b9477..83127ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ add_library( alepha SHARED string_algorithms.cc word_wrap.cc Thread.cc + delimited_list.cc ) # Everything else depends upon it link_libraries( alepha ) @@ -40,6 +41,7 @@ add_subdirectory( assertion.test ) add_subdirectory( Constness.test ) add_subdirectory( Blob.test ) add_subdirectory( Capabilities.test ) +add_subdirectory( delimited_list.test ) # Sample applications add_executable( example example.cc ) diff --git a/delimited_list.cc b/delimited_list.cc new file mode 100644 index 0000000..a4ebf9b --- /dev/null +++ b/delimited_list.cc @@ -0,0 +1,79 @@ +static_assert( __cplusplus > 2020'99 ); + +#include "delimited_list.h" + +#include + +#include + +namespace Alepha::Hydrogen ::detail:: delimited_list_m +{ + + namespace + { + namespace C + { + const bool debug= false; + } + + namespace impl_cc + { + struct DelimitedListStreambuf; + } + + IOStreams::StreamState< impl_cc::DelimitedListStreambuf * > tracker{ [] { return nullptr; } }; + } + + struct impl_cc::DelimitedListStreambuf + : virtual public IOStreams::StackableStreambuf, virtual public std::streambuf + { + private: + std::string delim; + bool first= true; + + public: + explicit + DelimitedListStreambuf( std::ios &is, const std::string delim ) + : StackableStreambuf( is ), delim( delim ) + { + tracker.get( is )= this; + if( C::debug ) error() << "Streambuf adapted." << std::endl; + } + + void + doNext() + { + if( C::debug ) error() << "Do Next called" << std::endl; + if( not first ) out() << delim; + first= false; + } + + private: + void writeChar( char ) override { throw "Unimpl"; } + void drain() override { throw "Unimpl"; } + + int + overflow( const int ch ) override + { + if( C::debug ) error() << "Overflow called" << std::endl; + return forwardOverflow( ch ); + } + }; + + + std::ostream & + impl::operator << ( std::ostream &os, MarkItem_t ) + { + if( C::debug ) error() << "Marker called" << std::endl; + auto thisTracker= tracker.get( os ); + if( thisTracker != nullptr ) thisTracker->doNext(); + + return os; + } + + void + impl::build_streambuf( std::ostream &os, StartDelimitedList &¶ms ) + { + new impl_cc::DelimitedListStreambuf( os, params.delimiter ); + } +} diff --git a/delimited_list.h b/delimited_list.h new file mode 100644 index 0000000..27239f9 --- /dev/null +++ b/delimited_list.h @@ -0,0 +1,42 @@ +static_assert( __cplusplus > 2020'99 ); + +#pragma once + +#include + +#include + +#include + +namespace Alepha::Hydrogen ::detail:: delimited_list_m +{ + inline namespace exports {} + + struct DelimitedList_params + { + const std::string delimiter; + + explicit DelimitedList_params( const std::string delimiter ) : delimiter( delimiter ) {} + }; + + struct MarkItem_t {}; + + namespace exports + { + constexpr MarkItem_t NextItem;; + + using StartDelimitedList= IOStreams::PushStack< DelimitedList_params >; + constexpr IOStreams::PopStack EndDelimitedList; + } + + inline namespace impl + { + void build_streambuf( std::ostream &, StartDelimitedList && ); + std::ostream &operator << ( std::ostream &os, MarkItem_t ); + } +} + +namespace Alepha::Hydrogen::inline exports::inline delimited_list_m +{ + using namespace detail::delimited_list_m::exports; +} diff --git a/delimited_list.test/0.cc b/delimited_list.test/0.cc new file mode 100644 index 0000000..a671af8 --- /dev/null +++ b/delimited_list.test/0.cc @@ -0,0 +1,35 @@ +static_assert( __cplusplus > 2020'99 ); + +#include "../delimited_list.h" + +#include +#include + +#include + +static auto init= Alepha::Utility::enroll <=[] +{ + using namespace Alepha::Testing::literals; + using namespace std::literals::string_literals; + + using namespace Alepha::Testing::exports; + + "Simple Comma Testing"_test <=TableTest + < + []( std::vector< std::string > names ) + { + std::ostringstream oss; + oss << Alepha::StartDelimitedList{ ", "s }; + for( const auto &name: names ) + { + oss << Alepha::NextItem << name; + } + + return oss.str(); + } + > + ::Cases + { + { "Simple", { { "Alpha", "Bravo", "Charlie", "Delta", "Echo" } }, "Alpha, Bravo, Charlie, Delta, Echo" }, + }; +}; diff --git a/delimited_list.test/CMakeLists.txt b/delimited_list.test/CMakeLists.txt new file mode 100644 index 0000000..b099603 --- /dev/null +++ b/delimited_list.test/CMakeLists.txt @@ -0,0 +1 @@ +unit_test( 0 )