forked from Alepha/Alepha
139 lines
2.8 KiB
C++
139 lines
2.8 KiB
C++
static_assert( __cplusplus > 2020'99 );
|
|
|
|
#pragma once
|
|
|
|
#include <Alepha/Alepha.h>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <string_view>
|
|
#include <algorithm>
|
|
|
|
#include "StackableStreambuf.h"
|
|
#include "StreamState.h"
|
|
|
|
namespace Alepha::Hydrogen::IOStreams ::detail:: LineTrackingStreambuf_m
|
|
{
|
|
inline namespace exports {}
|
|
|
|
struct TrackLines_params {};
|
|
|
|
namespace exports
|
|
{
|
|
struct LineTrackingStreambuf;
|
|
|
|
using TrackLines= IOStreams::PushStack< TrackLines_params >;
|
|
|
|
std::int64_t getLineNumber( std::ios_base &ios );
|
|
auto setLineNumber( std::int64_t baseLine );
|
|
}
|
|
|
|
inline StreamState< LineTrackingStreambuf * > tracker{ []{ return nullptr; } };
|
|
|
|
struct exports::LineTrackingStreambuf
|
|
: public virtual StackableStreambuf, public virtual std::streambuf
|
|
{
|
|
private:
|
|
std::int64_t baseLine= 1;
|
|
std::vector< std::int64_t > lineStarts;
|
|
char *bufBase= nullptr;
|
|
|
|
std::int64_t current() const { return gptr() - bufBase; }
|
|
|
|
std::int64_t
|
|
index() const
|
|
{
|
|
return std::lower_bound( begin( lineStarts ), end( lineStarts ), current() ) - begin( lineStarts );
|
|
}
|
|
|
|
public:
|
|
explicit
|
|
LineTrackingStreambuf( std::ios &is )
|
|
: StackableStreambuf( is )
|
|
{
|
|
tracker.get( is )= this;
|
|
}
|
|
|
|
void
|
|
setLineNumber( const std::int64_t baseLine )
|
|
{
|
|
this->baseLine= baseLine - index();
|
|
}
|
|
|
|
std::int64_t
|
|
getLineNumber() const
|
|
{
|
|
return baseLine + index();
|
|
}
|
|
|
|
void writeChar( char ch ) override { throw "Unimpl"; }
|
|
void drain() override { throw "Unimpl"; }
|
|
|
|
int
|
|
underflow() override
|
|
{
|
|
baseLine+= lineStarts.size();
|
|
lineStarts.clear();
|
|
const auto rv= forwardUnderflow();
|
|
if( rv == EOF ) return rv;
|
|
|
|
assume_underlying();
|
|
|
|
const std::string_view view{ gptr(), egptr() };
|
|
bufBase= gptr();
|
|
for( std::int64_t i= 0; i < view.size(); ++i )
|
|
{
|
|
if( view.at( i ) == '\n' ) lineStarts.push_back( i + 1 );
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
};
|
|
|
|
inline std::int64_t
|
|
exports::getLineNumber( std::ios_base &ios )
|
|
{
|
|
auto thisTracker= tracker.get( ios );
|
|
if( thisTracker == nullptr ) return -1;
|
|
return thisTracker->getLineNumber();
|
|
}
|
|
|
|
#if 0
|
|
struct Setter
|
|
{
|
|
const std::int64_t baseLine;
|
|
|
|
friend std::istream &
|
|
operator >> ( std::istream &is, const Setter &s )
|
|
{
|
|
auto thisTracker= tracker.get( is );
|
|
if( thisTracker != nullptr )
|
|
{
|
|
thisTracker->setLineNumber( s.baseLine );
|
|
}
|
|
|
|
return is;
|
|
}
|
|
};
|
|
|
|
inline auto
|
|
exports::setLineNumber( const std::int64_t baseLine )
|
|
{
|
|
return Setter{ baseLine };
|
|
}
|
|
#endif
|
|
|
|
inline void
|
|
build_streambuf( std::istream &is, TrackLines && )
|
|
{
|
|
new LineTrackingStreambuf{ is };
|
|
}
|
|
}
|
|
|
|
namespace Alepha::Hydrogen::IOStreams::inline exports::inline LineTrackingStreambuf_m
|
|
{
|
|
using namespace detail::LineTrackingStreambuf_m::exports;
|
|
}
|