Skip to content

Commit

Permalink
Adding Integer
Browse files Browse the repository at this point in the history
  • Loading branch information
whaeck committed Apr 4, 2024
1 parent b99481b commit 1cd1073
Show file tree
Hide file tree
Showing 5 changed files with 300 additions and 13 deletions.
1 change: 1 addition & 0 deletions cmake/unit_testing.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ add_subdirectory( src/tools/Log/test )
add_subdirectory( src/tools/disco/BaseField/test )
add_subdirectory( src/tools/disco/BaseFixedWidthField/test )
add_subdirectory( src/tools/disco/Column/test )
add_subdirectory( src/tools/disco/Integer/test )
add_subdirectory( src/tools/disco/Real/test )
add_subdirectory( src/tools/disco/Scientific/test )

Expand Down
99 changes: 99 additions & 0 deletions src/tools/disco/Integer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#ifndef NJOY_TOOLS_DISCO_REAL
#define NJOY_TOOLS_DISCO_REAL

// system includes
#include <sstream>
#include <iomanip>

// other includes
#include "fast_float/fast_float.h"
#include "tools/disco/BaseFixedWidthField.hpp"

namespace njoy {
namespace tools {
namespace disco {

/**
* @brief A class for reading fixed width data fields containing integer values
*/
template < unsigned int Width >
class Integer : public BaseFixedWidthField< Width > {

/* fields */

protected:

using BaseFixedWidthField< Width >::isSpace;
using BaseFixedWidthField< Width >::isSpaceOrTabulation;
using BaseFixedWidthField< Width >::isWhiteSpace;
using BaseFixedWidthField< Width >::isNewLine;
using BaseFixedWidthField< Width >::isEndOfFile;
using BaseFixedWidthField< Width >::skipSpaces;
using BaseFixedWidthField< Width >::skipPlusSign;

public:

template < typename Representation, typename Iterator >
static Representation read( Iterator& iter, const Iterator& ) {

unsigned int position = 0;
const auto end = iter + Width;
Representation value = 0;

skipSpaces( iter, position );
if ( isNewLine( iter ) || isEndOfFile( iter ) || Width == position ) {

return value;
}

skipPlusSign( iter, position );
if ( Width == position ) {

throw std::runtime_error( "cannot parse invalid integer number 1" );
}

// we are using fast_float::from_chars instead of std::from_chars since
// not all standard c++ libraries implement the floating point version of
// std::from_chars
auto result = fast_float::from_chars( &*iter, &*end, value );
if ( result.ec == std::errc() ) {

auto advance = result.ptr - &*iter;
iter += advance;
position += advance;
}
else {

throw std::runtime_error( "cannot parse invalid integer number 2" );
}

skipSpaces( iter, position );
if ( Width != position ) {

if ( ! isNewLine( iter ) && ! isEndOfFile( iter ) ) {

throw std::runtime_error( "cannot parse invalid integer number 3" );
}
}

return value;
}

template< typename Representation, typename Iterator >
static void write( Representation value, Iterator& iter ) {

std::ostringstream buffer;
buffer << std::right << std::setw( Width ) << value;

for ( auto b : buffer.str() ) {

*iter++ = b;
}
}
};

} // disco namespace
} // tools namespace
} // njoy namespace

#endif
1 change: 1 addition & 0 deletions src/tools/disco/Integer/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_cpp_test( disco.Integer Integer.test.cpp )
199 changes: 199 additions & 0 deletions src/tools/disco/Integer/test/Integer.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// include Catch2
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
using Catch::Matchers::WithinRel;

// what we are testing
#include "tools/disco/Integer.hpp"

// other includes

// convenience typedefs
using namespace njoy::tools::disco;

SCENARIO( "Integer" ) {

GIVEN( "strings of length 10" ) {

THEN( "the strings are entirely consumed for a field width of equal length" ) {

std::string string;
auto begin = string.begin();
auto end = string.end();

string = " ";
begin = string.begin();
end = string.end();
CHECK_THAT( 0, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = " +123";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = " 123";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = " -123";
begin = string.begin();
end = string.end();
CHECK_THAT( -123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = "+123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = "123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = "-123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( -123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = " +123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = " 123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = " -123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( -123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end );

string = " +123\n";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = " +123";
string += char{ std::char_traits<char>::eof() };
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );
} // THEN
} // GIVEN

GIVEN( "strings of length 11" ) {

THEN( "the strings are not entirely consumed for a field width of smaller length" ) {

std::string string;
auto begin = string.begin();
auto end = string.end();

string = " ";
begin = string.begin();
end = string.end();
CHECK_THAT( 0, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = " +123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = " 123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = " -123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( -123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = "+123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = "123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = "-123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( -123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = " +123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = " 123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = " -123 ";
begin = string.begin();
end = string.end();
CHECK_THAT( -123, WithinRel( Integer< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );
} // THEN
} // GIVEN

GIVEN( "integer values" ) {

THEN( "they can be written" ) {

int value;
std::string buffer;
auto iter = std::back_inserter( buffer );

value = 0;
buffer = "";
iter = std::back_inserter( buffer );
Integer< 12 >::write( value, iter );
CHECK( " 0" == buffer );
CHECK( 12 == buffer.size() );

value = 2;
buffer = "";
iter = std::back_inserter( buffer );
Integer< 12 >::write( value, iter );
CHECK( " 2" == buffer );
CHECK( 12 == buffer.size() );

value = 10;
buffer = "";
iter = std::back_inserter( buffer );
Integer< 12 >::write( value, iter );
CHECK( " 10" == buffer );
CHECK( 12 == buffer.size() );
} // THEN
} // GIVEN
} // SCENARIO
13 changes: 0 additions & 13 deletions src/tools/disco/Real/test/Real.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,19 +343,6 @@ SCENARIO( "Real" ) {
end = string.end();
CHECK_THAT( 100, WithinRel( Real< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = " +123\n";
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Real< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );

string = " +123";
string += char{ std::char_traits<char>::eof() };
begin = string.begin();
end = string.end();
CHECK_THAT( 123, WithinRel( Real< 10 >::read< double >( begin, end ) ) );
CHECK( begin == end - 1 );
} // THEN
} // GIVEN
} // SCENARIO

0 comments on commit 1cd1073

Please sign in to comment.