1
0
forked from Alepha/Alepha

Add IStreamable helper.

This commit is contained in:
2023-10-22 04:43:25 -04:00
parent b4438d46d6
commit 08971abb06
5 changed files with 116 additions and 0 deletions

1
IOStreams/CMakeLists.txt Normal file
View File

@ -0,0 +1 @@
add_subdirectory( IStreamable.test )

60
IOStreams/IStreamable.h Normal file
View File

@ -0,0 +1,60 @@
static_assert( __cplusplus > 2020'00 );
#pragma once
#include <Alepha/Alepha.h>
#include <istream>
#include <Alepha/Capabilities.h>
#include <Alepha/template_for_each.h>
#include <Alepha/string_algorithms.h>
#include <Alepha/Concepts.h>
#include <Alepha/Reflection/tuplizeAggregate.h>
namespace Alepha::Hydrogen::IOStreams ::detail:: istreamable_module
{
inline namespace exports
{
struct IStreamable {};
}
template< typename T >
concept IStreamableAggregate= Aggregate< T > and Capability< T, IStreamable >;
std::istream &
operator >> ( std::istream &is, IStreamableAggregate auto &istreamable )
{
std::string line;
std::getline( is, line );
const auto commentChar= line.find( "#" );
if( commentChar != std::string::npos ) line= line.substr( line.find( "#" ) );
const auto tokens= split( line, '\t' );
auto decomposed= Alepha::Reflection::tuplizeAggregate( istreamable );
if( tokens.size() != std::tuple_size_v< std::decay_t< decltype( decomposed ) > > )
{
throw 0;
}
int index= 0;
// TODO: Consider the lens system here... but the basic use case seems to be for
// aggregates, so we'll go with this simple case for now...
tuple_for_each( decomposed ) <=[&]( auto &element )
{
std::istringstream iss{ tokens.at( index++ ) };
iss >> element;
};
return is;
}
}
namespace Alepha::Hydrogen::IOStreams::inline exports::inline istreamable_module
{
using namespace detail::istreamable_module::exports;
}

View File

@ -0,0 +1,52 @@
static_assert( __cplusplus > 2020'00 );
#include "../IStreamable.h"
#include <Alepha/Testing/TableTest.h>
#include <Alepha/Testing/test.h>
#include <sstream>
namespace
{
template< typename= Alepha::Capabilities< Alepha::IOStreams::IStreamable > >
struct Agg_core
{
int x;
int y;
int z;
friend bool operator == ( const Agg_core &lhs, const Agg_core &rhs )= default;
friend std::ostream &
operator << ( std::ostream &os, const Agg_core &agg )
{
return os << "{ " << agg.x << ", " << agg.y << ", " << agg.z << " }";
}
};
using Agg= Agg_core<>;
static_assert( Alepha::Aggregate< Agg > );
static_assert( Alepha::Capability< Agg, Alepha::IOStreams::IStreamable > );
}
auto
buildFromString( const std::string text )
{
Agg rv;
std::istringstream iss{ text };
iss >> rv;
return rv;
}
static auto init= Alepha::Utility::enroll <=[]
{
using namespace Alepha::Testing::exports;
using namespace Alepha::Testing::literals::test_literals;
"Simple IStream"_test <=TableTest< buildFromString >
::Cases
{
{ "smoke test", { "1\t2\t3" }, { 1, 2, 3 } },
};
};

View File

@ -0,0 +1,2 @@
link_libraries( unit-test )
unit_test( 0 )