1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
#include <iostream>
#include <string>
#include <variant>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <utility>
#include <sstream>
#include <functional>
#include <random>
#include <cassert>
namespace my
{
//////////////////// item ///////////////////////////////
// std::variant http://en.cppreference.com/w/cpp/utility/variant (C++17)
// ( use boost::variant http://www.boost.org/doc/libs/1_66_0/doc/html/variant.html
// if the implementation does not support C++17 )
using item = std::variant< int, std::string, double /* , ... */ > ;
enum type_t : std::size_t { INT = 0, STR = 1, DBL = 2, /* ... */ NOTHING = std::variant_npos };
type_t type( const item& it ) { return type_t( it.index() ) ; }
item make_item( const std::string& str, type_t type )
{
if( type == INT )
{
try { return std::stoi(str) ; }
catch( const std::exception& ) { return 0 ; } // perl-like
}
else if( type == STR ) return str ;
else if( type == DBL )
{
try { return std::stod(str) ; }
catch( const std::exception& ) { return 0.0 ; } // perl-like
}
// else if ...
// etc.
return {} ; // no match: return value initialised item (int==0 in our case)
}
std::ostream& operator<< ( std::ostream& stm, const item& it )
{
// note: we could use a visitor here http://en.cppreference.com/w/cpp/utility/variant/visit
if( type(it) == INT ) return stm << std::get<int>(it) ;
else if( type(it) == DBL ) return stm << std::get<double>(it) ;
else if( type(it) == STR ) return stm << std::quoted( std::get<std::string>(it) ) ;
// else if ...
else return stm << "<uninitalised>" ;
}
// note: items are compared using the comparison operators for variants
// http://en.cppreference.com/w/cpp/utility/variant/operator_cmp
// ie. items of the same type are compared using the comparison operators of the type
// items of different types are compared by comparing their indices INT < STR etc.
// comparing uninitialised items returns an unordered result even when
// comparing with itself. (behaves like NaN for floating point values.)
////////////////////// row //////////////////////////////////
using row = std::vector<item> ;
bool operator< ( const row& a, const row& b )
{ return std::lexicographical_compare( std::begin(a), std::end(a), std::begin(b), std::end(b) ) ;}
bool operator== ( const row& a, const row& b )
{ return std::equal( std::begin(a), std::end(a), std::begin(b), std::end(b) ) ; }
using namespace std::rel_ops ; // for implicitly generating the other relational operators for row
row make_row( const std::string& line, const std::vector<type_t>& types, char delim )
{
row result ;
std::istringstream stm( line + delim ) ;
for( type_t ty : types )
{
std::string tok ;
std::getline( stm, tok, delim ) ;
result.push_back( make_item( tok, ty ) ) ;
}
return result ;
}
std::ostream& operator<< ( std::ostream& stm, const row& r )
{
for( const item& it : r ) stm << it << " | " ;
return stm ;
}
///////////////////////// table ///////////////////////////////
using table = std::vector<row> ;
table make_table( std::istream& stm, const std::vector<type_t>& types, char delim = '#' )
{
table result ;
std::string line ;
while( std::getline( stm, line ) ) result.push_back( make_row( line, types, delim ) ) ;
return result ;
}
std::ostream& operator<< ( std::ostream& stm, const table& t )
{
for( const row& r : t ) stm << r << '\n' ;
return stm ;
}
}
/////////////////////// minimal test driver /////////////////////
int main()
{
std::istringstream file
(
"some text#12345#1654#-72345#1.23\n"
"aaaa bbbb#99999#zzzz#444444#5.78\n"
"some text#23456#$$$$#128607#0.99\n"
"some text#23456#$$$$#128600#2.34\n"
"aaaa bbbb#99999#zzzz#222222#0.66.23\n"
"aaaa bbbb#99999#zzzz#444444#1.45\n"
"some text#12345#165 #000123456#4.56\n"
"aaaa bbbb#99999#zzzx#999999#9.99\n"
);
using namespace my ; // note: this also brings in std::rel_ops
auto data = make_table( file, { STR, INT, STR, INT, DBL } ) ;
std::cout << data << '\n' ;
std::sort( std::begin(data), std::end(data) ) ;
std::cout << data << '\n' ;
std::shuffle( std::begin(data), std::end(data), std::mt19937( std::random_device{}() ) ) ;
std::cout << data << '\n' ;
std::sort( std::begin(data), std::end(data), std::greater<>() ) ; // operator >
std::cout << data << '\n' ;
assert( data[0] >= data[1] && data[2] == data[2] && data[5] <= data[2] ) ; // operators >=, ==, <=
std::cout << "\nok\n" ;
}
|