forked from Alepha/Alepha
Add line-comment filter for streambuf.
This commit is contained in:
@ -2,6 +2,7 @@ add_subdirectory( IStreamable.test )
|
||||
add_subdirectory( OStreamable.test )
|
||||
add_subdirectory( Streamable.test )
|
||||
add_subdirectory( LineTrackingStreambuf.test )
|
||||
add_subdirectory( LineComments.test )
|
||||
add_subdirectory( OutUnixFileBuf.test )
|
||||
add_subdirectory( StackableStreambuf.test )
|
||||
add_subdirectory( Filter.test )
|
||||
|
170
IOStreams/LineComments.h
Normal file
170
IOStreams/LineComments.h
Normal file
@ -0,0 +1,170 @@
|
||||
static_assert( __cplusplus > 2023'00 );
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string_view>
|
||||
#include <algorithm>
|
||||
|
||||
#include <Alepha/error.h>
|
||||
|
||||
#include "StackableStreambuf.h"
|
||||
#include "StreamState.h"
|
||||
|
||||
namespace Alepha::Hydrogen::IOStreams ::detail:: LineComments_m
|
||||
{
|
||||
namespace C
|
||||
{
|
||||
const bool debug= false;
|
||||
const bool debugUnderflow= false or C::debug;
|
||||
}
|
||||
|
||||
inline namespace exports {}
|
||||
|
||||
struct LineComments_params {};
|
||||
|
||||
namespace exports
|
||||
{
|
||||
struct LineCommentsStreambuf;
|
||||
|
||||
using DropComments= IOStreams::PushStack< LineComments_params >;
|
||||
}
|
||||
|
||||
struct exports::LineCommentsStreambuf
|
||||
: public virtual StackableStreambuf, public virtual std::streambuf
|
||||
{
|
||||
private:
|
||||
enum { Active, Commented } state= Active;
|
||||
|
||||
public:
|
||||
explicit
|
||||
LineCommentsStreambuf( std::ios &is )
|
||||
: StackableStreambuf( is )
|
||||
{}
|
||||
|
||||
void writeChar( char ch ) override { throw "Unimpl"; }
|
||||
void drain() override { throw "Unimpl"; }
|
||||
|
||||
int
|
||||
underflow() override
|
||||
{
|
||||
std::string_view view{ gptr(), egptr() };
|
||||
while( view.empty() )
|
||||
{
|
||||
if( gptr() == nullptr or gptr() >= underlying_egptr() )
|
||||
{
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Current view of buffer is empty." << std::endl;
|
||||
}
|
||||
const auto rv= forwardUnderflow();
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Underlying underflow returned `" << rv << "`" << std::endl;
|
||||
}
|
||||
if( rv == EOF )
|
||||
{
|
||||
Alepha::error() << "Returning EOF from initial-kind read." << std::endl;
|
||||
setg( nullptr, nullptr, nullptr );
|
||||
return rv;
|
||||
}
|
||||
view= { underlying_gptr(), underlying_egptr() };
|
||||
}
|
||||
|
||||
while( state == Commented )
|
||||
{
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Current state is `Commented`, underlying view peek is `" << view << "`" << std::endl;
|
||||
}
|
||||
while( not view.empty() )
|
||||
{
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Examining: `" << view.front() << "`" << std::endl;
|
||||
}
|
||||
if( view.front() == '\n' )
|
||||
{
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Found end of line." << std::endl;
|
||||
}
|
||||
state= Active;
|
||||
break;
|
||||
}
|
||||
underlying_sbumpc();
|
||||
view.remove_prefix( 1 );
|
||||
}
|
||||
if( state == Active ) break;
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Underlying view exhausted, getting more..." << std::endl;
|
||||
}
|
||||
const auto rv= forwardUnderflow();
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Underlying view underflow returned `" << rv << "`" << std::endl;
|
||||
}
|
||||
if( rv == EOF )
|
||||
{
|
||||
Alepha::error() << "Returning EOF from mid-comment read." << std::endl;
|
||||
setg( nullptr, nullptr, nullptr );
|
||||
return rv;
|
||||
}
|
||||
view= { underlying_gptr(), underlying_egptr() };
|
||||
}
|
||||
assert( state == Active );
|
||||
assert( not view.empty() );
|
||||
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Current state is `Active`, underlying view peek is `" << view << "`" << std::endl;
|
||||
}
|
||||
|
||||
for( std::size_t i= 0; i < view.size(); ++i )
|
||||
{
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Looking at `" << view.at( i ) << "`'" << std::endl;
|
||||
}
|
||||
underlying_sbumpc();
|
||||
if( view.at( i ) == '#' )
|
||||
{
|
||||
view= view.substr( 0, i );
|
||||
state= Commented;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Current state is `Active`, setting underlying view to `" << view << "`" << std::endl;
|
||||
}
|
||||
setg( (char *) view.data(), (char *) view.data(), (char *) view.data() + view.size() );
|
||||
}
|
||||
|
||||
if( C::debugUnderflow )
|
||||
{
|
||||
Alepha::error() << "Normal return with first char being `" << view.front() << "`" << std::endl;
|
||||
}
|
||||
return view.front();
|
||||
}
|
||||
};
|
||||
|
||||
inline void
|
||||
build_streambuf( std::istream &is, DropComments && )
|
||||
{
|
||||
new LineCommentsStreambuf{ is };
|
||||
}
|
||||
}
|
||||
|
||||
namespace Alepha::Hydrogen::IOStreams::inline exports::inline LineComments_m
|
||||
{
|
||||
using namespace detail::LineComments_m::exports;
|
||||
}
|
39
IOStreams/LineComments.test/0.cc
Normal file
39
IOStreams/LineComments.test/0.cc
Normal file
@ -0,0 +1,39 @@
|
||||
#include "../LineComments.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <Alepha/Testing/test.h>
|
||||
#include <Alepha/Testing/TableTest.h>
|
||||
|
||||
#include <Alepha/Utility/evaluation_helpers.h>
|
||||
|
||||
|
||||
|
||||
static auto
|
||||
stream( const std::string &text )
|
||||
{
|
||||
std::istringstream iss{ text };
|
||||
|
||||
iss >> Alepha::IOStreams::DropComments{};
|
||||
|
||||
std::string s;
|
||||
getline( iss, s, {} );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static auto init= Alepha::Utility::enroll <=[]
|
||||
{
|
||||
using namespace Alepha::Testing::exports;
|
||||
|
||||
"Do we strip comments correctly"_test <=TableTest< stream >
|
||||
::Cases
|
||||
{
|
||||
{ "Simple (no comment)", { "Hello World!" }, "Hello World!" },
|
||||
{ "Simple (One comment)", { "Hello World!# Comment" }, "Hello World!" },
|
||||
{ "Two lines (One comment at end)", { "Hello World!\nGoodbye World! # Comment" }, "Hello World!\nGoodbye World! " },
|
||||
{ "Two lines (One comment after first)", { "Hello World! #Comment\nGoodbye World!" }, "Hello World! \nGoodbye World!" },
|
||||
{ "Two lines (Two comments)", { "Hello World! #Comment\nGoodbye World! #Comment" }, "Hello World! \nGoodbye World! " },
|
||||
{ "Two lines (Two comments, extra newline)", { "Hello World! #Comment\nGoodbye World! #Comment\n" }, "Hello World! \nGoodbye World! \n" },
|
||||
};
|
||||
};
|
1
IOStreams/LineComments.test/CMakeLists.txt
Normal file
1
IOStreams/LineComments.test/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
unit_test( 0 )
|
Reference in New Issue
Block a user