diff --git a/.gitignore b/.gitignore index 409184b..94e460c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,11 @@ -.svn \ No newline at end of file +.svn +*.o + +# Targets +/libwebgraph.a +/tests/compress_webgraph +/tests/print_webgraph +/tests/print_webgraph_offline +/tests/print_webgraph_sequential +/tests/convert_to_text +/tests/convert_to_binary_edgelist \ No newline at end of file diff --git a/Makefile b/Makefile index 0d7e572..ae91932 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +SHELL := /bin/bash + include flags.mk files = asciigraph/offline_graph.o \ @@ -15,10 +17,20 @@ files = asciigraph/offline_graph.o \ # # default target # -all: libs +all: info libs tests + +info: + @echo "Compile WebGraph ..." + @echo "Shell: $(SHELL)" + @echo "INCLUDES: $(INCLUDES)" + @echo "LIBS: $(LIBS)" + @echo "FLAGS: $(FLAGS)" tests: libs - $(MAKE) -C tests + pushd tests && \ + $(MAKE) -C . && \ + popd + libs: @@ -34,6 +46,8 @@ clean: rm -f core* rm -f *~ rm -f *.o + rm -f *.a + rm -f *.so @$(MAKE) -C asciigraph clean @$(MAKE) -C bitstreams clean @$(MAKE) -C properties clean @@ -42,3 +56,5 @@ clean: @$(MAKE) -C log clean @$(MAKE) -C tests clean +.PHONY: all tests libs info clean + diff --git a/README.md b/README.md index be36168..d3a24d5 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,42 @@ work. You will notice a lot of TODOs and commented-out unimplemented methods. Feel free to write them :) + +## Build + +Use `BOOST_ROOT` to specify the location of your Boost installation, as below: + +```sh +make BOOST_ROOT=/path/to/boost +``` + +If your boost is installed at default system path, `BOOST_ROOT` can be omit. + +Compile success with g++ 11.4.0 and Boost 1.84.0. + +To build test programs, use: + +```sh +make BOOST_ROOT=/path/to/boost tests +``` + +## Run + +You can use `tests/print_webgraph` to print a webgraph file. + +```sh +./tests/print_webgraph /path/to/webgraph/graphname +``` + +Make sure `graphname.graph`, `graphname.properties` and `graphname.offsets` are in your `path/to/webgraph`. (i.e., the graph path is graph files path without extension.) + +To read a graph without offset file (sequential graph), use `test/print_webgraph_sequential`. + +To convert graph to binary edge list, run: + +```sh +./tests/convert_to_binary_edgelist [input_graph] [output_file] +``` + +Each edge will represent as 2 64bit integers. + diff --git a/asciigraph/deps.mk b/asciigraph/deps.mk deleted file mode 100644 index 6423cbd..0000000 --- a/asciigraph/deps.mk +++ /dev/null @@ -1 +0,0 @@ -ASCIIGRAPH_DEPS = TokenizerTest.cpp diff --git a/asciigraph/offline_vertex_iterator.cpp b/asciigraph/offline_vertex_iterator.cpp index 045bcab..62beaf5 100644 --- a/asciigraph/offline_vertex_iterator.cpp +++ b/asciigraph/offline_vertex_iterator.cpp @@ -112,7 +112,7 @@ void offline_vertex_iterator::copy( const offline_vertex_iterator& other ) { void offline_vertex_iterator::increment() { string tmp; - bool success = getline( back, tmp ); + bool success = (bool)getline( back, tmp ); if( !success ) { end_marker = true; diff --git a/asciigraph/tests/test_ascii_graph.cpp b/asciigraph/tests/test_ascii_graph.cpp index b8d1aa0..981e88f 100644 --- a/asciigraph/tests/test_ascii_graph.cpp +++ b/asciigraph/tests/test_ascii_graph.cpp @@ -1,22 +1,22 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - +/* + * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + #include "../offline_graph.hpp" #include #include diff --git a/benchmarks/compress_webgraph.cpp b/benchmarks/compress_webgraph.cpp index 62ad70b..d2b311e 100644 --- a/benchmarks/compress_webgraph.cpp +++ b/benchmarks/compress_webgraph.cpp @@ -52,6 +52,7 @@ int main( int argc, char** argv ) { quantum = 10000; bool offline = false, write_offsets = false; + (void) offline; // not used yet ostringstream help_message_oss; diff --git a/bitstreams/deps.mk b/bitstreams/deps.mk deleted file mode 100644 index 89b7d4e..0000000 --- a/bitstreams/deps.mk +++ /dev/null @@ -1 +0,0 @@ -BITSTREAM_DEPS = bitstreams.hpp bitstreams.cpp diff --git a/bitstreams/input_bitstream.cpp b/bitstreams/input_bitstream.cpp index e51b1f5..da8e919 100644 --- a/bitstreams/input_bitstream.cpp +++ b/bitstreams/input_bitstream.cpp @@ -25,7 +25,7 @@ #include "../utils/fast.hpp" -#define LOGGING +// #define LOGGING namespace webgraph { using namespace std; @@ -142,8 +142,10 @@ int ibitstream::read() { if ( avail == 0 ) { // then the buffer is empty. attempt to fill it again. if( is != NULL ) + { assert( buffer->size() == buffer->capacity() ); avail = is->readsome( (char*)&(*buffer).at(0), buffer->size() ); // used to be capacity + } #ifdef LOGGING cerr << "==================================================\n"; cerr << "BUFFER REFILLED; first 50 bytes : \n"; @@ -185,7 +187,7 @@ int ibitstream::read_from_current( unsigned int len ) { // We just empty everything. read_bits += len; fill = 0; - int retval = current & ( 1 << len ) - 1; + int retval = current & (( 1 << len ) - 1); #ifdef LOGGING cerr << "\tread_from_current(" << len << ") = " << retval << " " << "(current=" << utils::int_to_binary(current,fill) << ")\n"; @@ -222,11 +224,11 @@ void ibitstream::read( byte bits[], unsigned int len ) { if ( len <= fill ) { if ( len <= 8 ) { - bits[ 0 ] = (byte)( read_from_current( len ) << 8 - len ); + bits[ 0 ] = (byte)( read_from_current( len ) << (8 - len) ); return; } else { bits[ 0 ] = (byte)( read_from_current( 8 ) ); - bits[ 1 ] = (byte)( read_from_current( len - 8 ) << 16 - len ); + bits[ 1 ] = (byte)( read_from_current( len - 8 ) << (16 - len) ); return; } } else { @@ -239,7 +241,7 @@ void ibitstream::read( byte bits[], unsigned int len ) { const unsigned int shift = fill; - bits[ j ] = (byte)( read_from_current( shift ) << 8 - shift ); + bits[ j ] = (byte)( read_from_current( shift ) << (8 - shift) ); len -= shift; i = len >> 3; @@ -247,7 +249,7 @@ void ibitstream::read( byte bits[], unsigned int len ) { b = read(); // used to be >>> bits[ j ] |= (( b & 0xFF ) >> shift) & 0xFF; // the last & 0xFF is mine. - bits[ ++j ] = (byte)( b << 8 - shift ); + bits[ ++j ] = (byte)( b << (8 - shift) ); } read_bits += len & ~7; @@ -255,10 +257,10 @@ void ibitstream::read( byte bits[], unsigned int len ) { len &= 7; if ( len != 0 ) { if ( len <= 8 - shift ) { - bits[ j ] |= (byte)( read_from_current( len ) << 8 - shift - len ); + bits[ j ] |= (byte)( read_from_current( len ) << (8 - shift - len) ); } else { bits[ j ] |= (byte)( read_from_current( 8 - shift ) ); - bits[ j + 1 ] = (byte)( read_from_current( len + shift - 8 ) << 16 - shift - len ); + bits[ j + 1 ] = (byte)( read_from_current( len + shift - 8 ) << (16 - shift - len) ); } } } @@ -383,7 +385,7 @@ void ibitstream::set_position( unsigned long position ) { int pos = (int)this->pos; - if ( delta <= avail && delta >= - pos ) { + if ( delta <= (int)avail && delta >= - pos ) { // We can reposition just by moving into the buffer. avail -= delta; pos += delta; @@ -409,7 +411,7 @@ int ibitstream::read_unary() { if ( fill < 8 ) refill(); -#if 1 +#ifdef LOGGING cerr << "current: " << current << endl << "fill: " << fill << endl; #endif @@ -425,7 +427,7 @@ int ibitstream::read_unary() { read_bits += x + 1; fill -= x + 1; -#if 1 +#ifdef LOGGING cerr << "1. read_unary() = " << x << endl; #endif return x; @@ -437,7 +439,7 @@ int ibitstream::read_unary() { x += 7 - ( fill = BYTEMSB[ current ] ); read_bits += x + 1; -#if 1 +#ifdef LOGGING cerr << "2. read_unary() = " << x << endl; #endif return x; @@ -765,7 +767,7 @@ int ibitstream::read_zeta( int k ) { if ( pre_comp != 0 ) { read_bits += pre_comp >> 8; fill -= pre_comp >> 8; -#if 1 +#ifdef LOGGING cerr << "\t1. read_zeta returning " << (pre_comp & 0xFF) << endl; #endif return pre_comp & 0xFF; @@ -778,7 +780,7 @@ int ibitstream::read_zeta( int k ) { const int m = read_int( h * k + k - 1 ); if ( m < left ) { int retval = m + left - 1; -#if 1 +#ifdef LOGGING cerr << "\t2. read_zeta returning " << retval << endl; #endif return retval; @@ -786,7 +788,7 @@ int ibitstream::read_zeta( int k ) { int retval = ( m << 1 ) + read_bit() - 1; -#if 1 +#ifdef LOGGING cerr << "\t3. read_zeta returning " << retval << endl; #endif diff --git a/bitstreams/input_bitstream.hpp b/bitstreams/input_bitstream.hpp index 1639a3f..9571b93 100644 --- a/bitstreams/input_bitstream.hpp +++ b/bitstreams/input_bitstream.hpp @@ -452,7 +452,7 @@ class ibitstream { << utils::int_to_binary( current, fill ) << "\n"; #endif - } catch( eof_exception e ) { + } catch( eof_exception& e ) { // don't care. } } diff --git a/bitstreams/output_bitstream.cpp b/bitstreams/output_bitstream.cpp index 932e9a5..cec96be 100644 --- a/bitstreams/output_bitstream.cpp +++ b/bitstreams/output_bitstream.cpp @@ -184,7 +184,7 @@ int obitstream::write_byte_offset( const byte bits[], if ( len <= free ) { /// used to be >>> // this is okay because bits[] is unsigned, so 0's will be shifted in - return write_in_current( bits[ offset ] >> 8 - len, len ); + return write_in_current( bits[ offset ] >> (8 - len), len ); } else { const int shift = free; @@ -193,7 +193,7 @@ int obitstream::write_byte_offset( const byte bits[], // cerr << "shift = " << shift << endl; // used to be >>> - write_in_current( bits[ offset ] >> 8 - shift, shift ); + write_in_current( bits[ offset ] >> (8 - shift), shift ); len -= shift; @@ -201,7 +201,7 @@ int obitstream::write_byte_offset( const byte bits[], i = len >> 3; while( i-- != 0 ) { // used to be >>> - write( bits[ j ] << shift | ( bits[ j + 1 ] & 0xFF ) >> 8 - shift ); + write( bits[ j ] << shift | ( bits[ j + 1 ] & 0xFF ) >> (8 - shift) ); written_bits += 8; j++; } @@ -210,12 +210,12 @@ int obitstream::write_byte_offset( const byte bits[], if ( q != 0 ) { if ( q <= 8 - shift ) { /// used to be >>> - write_in_current( bits[ j ] >> 8 - shift - q, q ); + write_in_current( bits[ j ] >> (8 - shift - q), q ); } else { write_in_current( bits[ j ], 8 - shift ); /// used to be >>> - write_in_current( bits[ j + 1 ] >> 16 - q - shift, q + shift - 8 ); + write_in_current( bits[ j + 1 ] >> (16 - q - shift), q + shift - 8 ); } } diff --git a/bitstreams/output_bitstream.hpp b/bitstreams/output_bitstream.hpp index 07392a3..38d4ca1 100644 --- a/bitstreams/output_bitstream.hpp +++ b/bitstreams/output_bitstream.hpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include "../log/logger.hpp" diff --git a/bitstreams/tests/reader_writer_test.cpp b/bitstreams/tests/reader_writer_test.cpp index 70bdb22..2c4fd60 100644 --- a/bitstreams/tests/reader_writer_test.cpp +++ b/bitstreams/tests/reader_writer_test.cpp @@ -46,7 +46,7 @@ int main(int, char**) { cerr << "Done with files.. now time for arrays.\n"; - shared_ptr< vector > res = test_write_to_array( b, sizeof(somebits) ); + boost::shared_ptr< vector > res = test_write_to_array( b, sizeof(somebits) ); cerr << "We've written .. now let's see how it looks.\n"; cerr << "The bytes of res[] are " << endl; diff --git a/boost/edge_iterator.hpp b/boost/edge_iterator.hpp deleted file mode 100644 index 59ba818..0000000 --- a/boost/edge_iterator.hpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef WEBGRAPH_BOOST_EDGE_ITERATOR_HPP -#define WEBGRAPH_BOOST_EDGE_ITERATOR_HPP - -#include -#include -#include - -#include "types.hpp" -#include - -// TODO this will have to change to work with offline graphs. - -namespace webgraph { namespace bv_graph { namespace boost_integration { - - class edge_iterator : public boost::iterator_facade { - private: - // data members - webgraph::bv_graph::graph::node_iterator v, v_end; - webgraph::bv_graph::graph::successor_iterator s, s_end; - vertex_descriptor current_vertex; - bool end_marker; - - public: - // interface - edge_iterator( const webgraph::bv_graph::graph& gg ) { - - tie( v, v_end ) = gg.get_node_iterator(0); - - assert( v != v_end ); - - do { - - tie( s, s_end ) = successors( v ); - current_vertex = *v; - ++v; - } while( s == s_end && v != v_end ); - - - end_marker = s == s_end; // shouldn't happen... - } - - edge_iterator() { - end_marker = true; - } - - friend class boost::iterator_core_access; - private: - //////////////////////////////////////////////////////////////////////////////// - void increment() { - ++s; - - while( s == s_end && v != v_end ) { - tie( s, s_end ) = successors( v ); - current_vertex = *v; - ++v; - } - - end_marker = s == s_end; - } - - //////////////////////////////////////////////////////////////////////////////// - edge_descriptor dereference() const { - return make_pair( current_vertex, *s ); - } - - //////////////////////////////////////////////////////////////////////////////// - bool equal( const edge_iterator& other ) const { - if( end_marker && other.end_marker ) { - return true; - } else { - return v == other.v && s == other.s; - } - } - }; -}}} - -#endif - diff --git a/boost/integration.hpp b/boost/integration.hpp deleted file mode 100644 index e9bf08c..0000000 --- a/boost/integration.hpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef WEBGRAPH_BOOST_HPP -#define WEBGRAPH_BOOST_HPP - -#include -#include -#include -#include - -#include -#include -#include - -#include "../webgraph.hpp" -#include "../iterators/node_iterator.hpp" -#include "../types.hpp" -#include "edge_iterator.hpp" -#include "out_edge_iterator.hpp" - -namespace boost { - - // we assume in the following that we're only dealing with online graphs. - // At some point these types should be pulled apart, since online and offline graphs - // are different creatures, really. - - struct bv_graph_traversal_category : - public virtual vertex_list_graph_tag, - public virtual edge_list_graph_tag, - public virtual incidence_graph_tag, - public virtual adjacency_graph_tag - {}; - - namespace bvg_boost = webgraph::bv_graph::boost_integration; - - template<> - struct graph_traits< webgraph::bv_graph::graph > { - - //! Vertex and edge descriptors - required for all concepts - //! These are from types.hpp - typedef bvg_boost::vertex_descriptor vertex_descriptor; - typedef bvg_boost::edge_descriptor edge_descriptor; - - // Tags - typedef directed_tag directed_category; - typedef disallow_parallel_edge_tag edge_parallel_category; - typedef bv_graph_traversal_category traversal_category; - - //////////////////////////////////////////////////////////////////////////////// - /*! - * vertex_iterator - required by Vertex List Graph concept - */ - typedef webgraph::bv_graph::node_iterator vertex_iterator; - typedef unsigned int vertices_size_type; - - //////////////////////////////////////////////////////////////////////////////// - /*! - * edge_iterator - required by Edge List Graph concept. Defined in edge_iterator.hpp - */ - typedef bvg_boost::edge_iterator edge_iterator; - typedef unsigned int edges_size_type; - - //////////////////////////////////////////////////////////////////////////////// - // the following is what necessitates an online graph. - //////////////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////////////// - /*! - * out_edge_iterator - required by incidence graph concept - */ - - typedef bvg_boost::out_edge_iterator out_edge_iterator; - typedef unsigned int degree_size_type; - - //////////////////////////////////////////////////////////////////////////////// - /*! required for the adjacency graph concept - */ -// typedef boost::adjacency_iterator_generator::type adjacency_iterator; - - typedef webgraph::bv_graph::graph::successor_iterator adjacency_iterator; - - - }; // end of graph traits definition - - typedef graph_traits bvg_traits; - - //////////////////////////////////////////////////////////////////////////////// - /*! - * Support functions for Vertex List Graph concept - */ - std::pair< bvg_traits::vertex_iterator, bvg_traits::vertex_iterator > - vertices( const webgraph::bv_graph::graph& g ) { - return g.get_node_iterator(0); - } - - bvg_traits::vertices_size_type num_vertices( const webgraph::bv_graph::graph& g ) { - return static_cast(g.get_num_nodes()); - } - - //////////////////////////////////////////////////////////////////////////////// - /*! - * Support for EdgeListGraph concept (and Incidence Graph) - */ - bvg_traits::vertex_descriptor source( bvg_traits::edge_descriptor e, - const webgraph::bv_graph::graph& g ) { - return e.first; - } - - bvg_traits::vertex_descriptor target( bvg_traits::edge_descriptor e, - const webgraph::bv_graph::graph& g ) { - return e.second; - } - - std::pair< bvg_traits::edge_iterator, bvg_traits::edge_iterator > - edges( const webgraph::bv_graph::graph& g ) { - return make_pair( bvg_boost::edge_iterator( g ), - bvg_boost::edge_iterator() ); - } - - bvg_traits::edges_size_type num_edges( const webgraph::bv_graph::graph& g ) { - return g.get_num_arcs(); - } - - - //////////////////////////////////////////////////////////////////////////////// - /*! - * Required for IncidenceGraph (and requires the backing graph to be online). - */ - std::pair< bvg_traits::out_edge_iterator, - bvg_traits::out_edge_iterator> - out_edges( const bvg_traits::vertex_descriptor& v, - const webgraph::bv_graph::graph& g ) { - typedef bvg_traits::out_edge_iterator oeitor; - - oeitor beg( v, g ); - oeitor end; - - return make_pair( beg, end ); - } - - bvg_traits::degree_size_type out_degree( const bvg_traits::vertex_descriptor& v, - const webgraph::bv_graph::graph& g ) { - return g.outdegree( v ); - } - - //////////////////////////////////////////////////////////////////////////////// - /*! - * Required for AdjacencyListGraph (requires backing graph to be online). - */ - std::pair< bvg_traits::adjacency_iterator, - bvg_traits::adjacency_iterator > - adjacent_vertices( const bvg_traits::vertex_descriptor& v, - const webgraph::bv_graph::graph& g ) { - return g.get_successors( v ); - } - - - //////////////////////////////////////////////////////////////////////////////// - /*! - * This is for making property maps out of these graphs. It's pretty dumb but required - * for syntactic correctness with the Boost stuff... - */ - class vertex_index_accessor {}; // models readable property map somehow. - - vertex_index_accessor get( boost::vertex_index_t, const webgraph::bv_graph::graph& g ) { - return vertex_index_accessor(); - } - - typedef unsigned int vertex_label_t; - - vertex_label_t get( const vertex_index_accessor&, - const bvg_traits::vertex_descriptor& v ) { - return static_cast( v ); - } - - template<> - class property_traits { - public: - typedef vertex_label_t value_type; - typedef vertex_label_t reference; - typedef bvg_traits::vertex_descriptor key_type; - typedef readable_property_map_tag category; - }; -} - -#endif - diff --git a/boost/out_edge_iterator.hpp b/boost/out_edge_iterator.hpp deleted file mode 100644 index 4045a08..0000000 --- a/boost/out_edge_iterator.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef BVG_BOOST_OUT_EDGE_ITERATOR_HPP -#define BVG_BOOST_OUT_EDGE_ITERATOR_HPP - -#include -#include -#include "types.hpp" - - -namespace webgraph { namespace bv_graph { namespace boost_integration { - class out_edge_iterator : public boost::iterator_facade { - private: - vertex_descriptor v; - webgraph::bv_graph::graph::successor_iterator s, s_end; - edge_descriptor cur_edge; - - public: - out_edge_iterator( const vertex_descriptor& v, - const webgraph::bv_graph::graph& g ) { - boost::tie( s, s_end ) = g.get_successors( v ); - cur_edge = make_pair( v, *s ); - } - - out_edge_iterator() {} - - friend class boost::iterator_core_access; - private: - void increment() { - ++s; - cur_edge = make_pair( v, *s ); - } - - edge_descriptor dereference() const { - return cur_edge; - } - - bool equal( const out_edge_iterator& other ) const { - return - (s == s_end && other.s == other.s_end) || - (s == other.s && s_end == other.s_end); - } - }; -}}} - -#endif diff --git a/boost/test/Makefile b/boost/test/Makefile deleted file mode 100644 index d4225d8..0000000 --- a/boost/test/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -include ../../../flags.mk - -linklibs = -lboost_regex -lboost_filesystem -lboost_program_options -lwebgraph - -all: print_graph test_incidence_and_adjacency - -print_graph: print_graph.o - g++ $(FLAGS) -o print_graph print_graph.o $(linklibs) - -test_incidence_and_adjacency: test_incidence_and_adjacency.o - g++ $(FLAGS) -o test_incidence_and_adjacency test_incidence_and_adjacency.o $(linklibs) - -clean: - rm -f *.o - -%.o: %.cpp - g++ $(INCLUDES) $(FLAGS) -c $< diff --git a/boost/test/print_graph.cpp b/boost/test/print_graph.cpp deleted file mode 100644 index 56c4f13..0000000 --- a/boost/test/print_graph.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -/* - * usage: given a compressed graph g (consisting of g.graph, g.offsets, and - * g.properties), the following will run this program: - * - * print_graph g - * - */ - -#include -#include -#include -#include - -int main(int argc, char** argv) { - typedef webgraph::bv_graph::graph graph; - typedef boost::shared_ptr graph_ptr; - - assert( argc > 1 ); - - graph_ptr gp = webgraph::bv_graph::graph::load( argv[1] ); - - typedef boost::graph_traits< graph > bv_traits; - - cerr << "Here are the vertices ...." << endl; - - bv_traits::vertex_iterator v, v_end; - for( tie( v, v_end ) = boost::vertices( *gp ); v != v_end; ++v ) { - cerr << *v << endl; - } - - cerr << "Here are the vertices again ...." << endl; - - bv_traits::vertex_iterator v2, v2_end; - for( tie( v2, v2_end ) = boost::vertices( *gp ); v2 != v2_end; ++v2 ) { - cerr << *v2 << endl; - } - - cerr << "Now here are the edges..." << endl; - - bv_traits::edge_iterator e, e_end; - for( tie( e, e_end ) = boost::edges( *gp ); e != e_end; ++e ) { - cerr << "<" << e->first << ", " << e->second << ">" << endl; - } - - return 0; -} diff --git a/boost/types.hpp b/boost/types.hpp deleted file mode 100644 index 4db1905..0000000 --- a/boost/types.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef WEBGRAPH_BOOST_TYPES_HPP -#define WEBGRAPH_BOOST_TYPES_HPP - -// These types are used in graph_traits, but also elsewhere, thus we pull the definitions -// out to here. - -namespace webgraph { namespace bv_graph { namespace boost_integration { - - typedef int vertex_descriptor; - typedef std::pair< vertex_descriptor, vertex_descriptor > edge_descriptor; - -}}} - -#endif diff --git a/deps.mk b/deps.mk deleted file mode 100644 index ec46046..0000000 --- a/deps.mk +++ /dev/null @@ -1,2 +0,0 @@ -WEBGRAPH_DEPS = webgraph.hpp webgraph.cpp compression_flags.hpp types.hpp compression_flags.cpp - diff --git a/flags.mk b/flags.mk index f440e1e..3cfda2f 100644 --- a/flags.mk +++ b/flags.mk @@ -1,9 +1,12 @@ # Change these to match your configuration -INCLUDES = /u/jpr/old_code/webgraph -LIBS = /u/jpr/old_code/webgraph - -#LIBS = /u/jpr/workspace/cpp_webgraph +ifdef BOOST_ROOT + INCLUDES = $(BOOST_ROOT)/include + LIBS = $(BOOST_ROOT)/lib +else + INCLUDES = . + LIBS = . +endif base = -I$(INCLUDES) -L$(LIBS) -Wall @@ -14,9 +17,10 @@ else endif ifndef CONFIG_DBG - FLAGS = $(base) -DCONFIG_FAST -O3 $(prof) + CONFIG_FAST = 1 + FLAGS = $(base) -DCONFIG_FAST -std=c++11 -O3 $(prof) -DBOOST_TIMER_ENABLE_DEPRECATED else - FLAGS = $(base) -DCONFIG_FAST -g $(prof) + FLAGS = $(base) -DCONFIG_FAST -DLOGGING -std=c++11 -g $(prof) -DBOOST_TIMER_ENABLE_DEPRECATED endif #FLAGS = -I$(INCLUDES) -Wall -g diff --git a/includes.mk b/includes.mk deleted file mode 100644 index bf267a4..0000000 --- a/includes.mk +++ /dev/null @@ -1 +0,0 @@ -INCLUDES = /usr/include/boost-1_33 diff --git a/iterators/Makefile b/iterators/Makefile deleted file mode 100644 index 92a2e32..0000000 --- a/iterators/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -include ../../flags.mk - -all: all_o -ifndef CONFIG_FAST - $(MAKE) -C tests all -endif - -all_o: node_iterator.o -ifndef CONFIG_FAST - $(MAKE) -C tests all_o -endif - -%.o : %.cpp %.hpp - g++ $(FLAGS) -c $< - -clean: - rm -f *.o - rm -f *~ diff --git a/iterators/collection_wrappers.hpp b/iterators/collection_wrappers.hpp deleted file mode 100644 index 35f7bea..0000000 --- a/iterators/collection_wrappers.hpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#include "utility_iterator_base.hpp" - -namespace webgraph { namespace bv_graph { namespace utility_iterators { - - - -}}} diff --git a/iterators/empty_iterator.hpp b/iterators/empty_iterator.hpp deleted file mode 100644 index 4451661..0000000 --- a/iterators/empty_iterator.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef EMPTY_ITERATOR_HPP -#define EMPTY_ITERATOR_HPP - -#include "utility_iterator_base.hpp" -#include -#include -#include - -namespace webgraph { namespace bv_graph { namespace utility_iterators { - -class empty_iterator : public utility_iterator_base { -public: - empty_iterator() {} - - int next() { - throw std::logic_error( "Can't increment empty iterator." ); - } - - bool has_next() const { - return false; - } - - std::string as_str() const { - return "Empty iterator."; - } - - int skip( int how_many ) { - throw std::logic_error( "Can't skip on an empty iterator." ); - } - - empty_iterator* clone() const { - return new empty_iterator(); - } -}; - -}}} - -#endif diff --git a/iterators/interval_sequence_iterator.hpp b/iterators/interval_sequence_iterator.hpp deleted file mode 100644 index 014a934..0000000 --- a/iterators/interval_sequence_iterator.hpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef INTERVAL_SEQUENCE_ITERATOR_HPP_ -#define INTERVAL_SEQUENCE_ITERATOR_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include "utility_iterator_base.hpp" -#include "../../log/logger.hpp" - -//#define HARDCORE_DEBUG_INT_SEQ_ITOR - -namespace webgraph { namespace bv_graph { namespace utility_iterators { - -/** This class iterates over the integers contained in a sequence of intervals, - * which are specified by their left points and the number of integers they contain. - */ -template< class integral_type > -class interval_sequence_iterator : public utility_iterator_base { -private: - /** The left extremes. */ - std::vector left; - - /** The lengths. */ - std::vector len; - - /** The index of the current interval. */ - unsigned int curr_interval; - - /** The left point of the current interval */ - unsigned int curr_left; - - /** The current position in the current interval: the next integer to be output is - * left[cur_interval] + cur_index. */ - unsigned int curr_index; - - /** number of intervals left.. this should always be equal to left.size() - - * cur_interval */ - unsigned n; - - void init() { - /** takes care of initializing the default stuff */ - curr_interval = 0; - curr_left = 0; - curr_index = 0; - } -public: - interval_sequence_iterator( const std::vector& lf, - const std::vector& ln ) : - left( lf ), len(ln), n(lf.size()) { - init(); - advance(); - } - - /** Creates a new interval-sequence iterator by specifying arrays of left extremes and - * lengths, and the number of valid entries. Note that the two arrays are not - * copied, so they are supposed not to be changed during the iteration. - * - * @param left an array containing the left extremes of the intervals generating this - * iterator. - * - * @param len an array (of the same length as left) containing the number - * of integers in each interval. - * - * @param N the number of valid entries in left and len. - */ - - interval_sequence_iterator( const std::vector& lf, - const std::vector& ln, - const int sz ) : left(lf), len(ln), n(sz) { - init(); - advance(); - } - -public: - -// Make the next() method log debugging information if needed. -#ifdef HARDCORE_DEBUG_INT_SEQ_ITOR - integral_type next() { - integral_type result = next_internal(); - logs::logger( "iterators" ) << logs::LEVEL_MAX - << "interval sequence iterator next about to return " - << result << "\n"; - return result; - } - - integral_type next_internal(); -#else - integral_type next(); -#endif - - interval_sequence_iterator* clone() const { - return new interval_sequence_iterator( *this ); - } - - bool has_next() const { - return n != 0; - } - - int skip( int how_many ); - - //////////////////////////////////////////////////////////////////////////////// - std::string as_str() const { - using namespace std; - - ostringstream oss; - - oss << "interval_sequence_iterator:\n" - << "\tleft.size() = " << left.size() << "\n" - << "\tlen.size() = " << len.size() << "\n" - << "\tcur_interval = " << curr_interval << "\n" - << "\tcur_index = " << curr_index << "\n" - << "\tn = " << n << "\n"; - - return oss.str(); - } - -private: - void advance(); -}; - -//////////////////////////////////////////////////////////////////////////////// -template -#ifdef HARDCORE_DEBUG_INT_SEQ_ITOR -integral_type interval_sequence_iterator::next_internal() { -#else -integral_type interval_sequence_iterator::next() { -#endif - if ( ! has_next() ) - throw std::logic_error("Attempt to fetch next element of empty integral_type iterator."); - - const int next = curr_left + curr_index++; - advance(); - return next; -} - -//////////////////////////////////////////////////////////////////////////////// -template -int interval_sequence_iterator::skip( int how_many ) { - int skipped = 0; - - while( skipped < how_many && how_many != 0 ) { - if ( how_many - skipped < len[ curr_interval ] - (int)curr_index ) { - curr_index += ( how_many - skipped ); - return how_many; - } else { - skipped += len[ curr_interval ] - curr_index; - curr_index = len[ curr_interval ]; - advance(); - } - } - - return skipped; -} - -template -void interval_sequence_iterator::advance() { - while( n != 0 ) { - curr_left = left[ curr_interval ]; - if ( (int)curr_index < len[ curr_interval ] ) - break; - n--; - curr_interval++; - curr_index = 0; - } -} - -} } } - -#endif /*INTERVAL_SEQUENCE_ITERATOR_HPP_*/ diff --git a/iterators/iterator_wrappers.hpp b/iterators/iterator_wrappers.hpp deleted file mode 100644 index 5c05222..0000000 --- a/iterators/iterator_wrappers.hpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef ITERATOR_WRAPPERS_HPP -#define ITERATOR_WRAPPERS_HPP - -#include -#include -#include "utility_iterator_base.hpp" -#include -#include -#include -#include -#include -#include -#include -#include "../../log/logger.hpp" - -namespace webgraph { namespace bv_graph { namespace iterator_wrappers { - -/** - * Access a CPP wrapper through a Java idiom, and as a subclass of - * utility_iterator_base. - */ -template -class cpp_to_java : - public webgraph::bv_graph::utility_iterators::utility_iterator_base { - itor_type itor; - itor_type itor_end; -// int num_to_return; -// int num_returned; - -public: - cpp_to_java( itor_type i_begin, itor_type i_end ) : - itor( i_begin ), itor_end( i_end ) { - } - -// cpp_to_java( itor_type i_begin, itor_type i_end, unsigned begin_index, unsigned length ) : -// itor( i_begin ), itor_end( i_end ), num_to_return( length ) { -// // TODO find more elegant way to do this. -// skip( begin_index ); -// num_returned = 0; // don't count the ones that skip counted. -// } - - ~cpp_to_java() {} - - val_type next() { - if( !has_next() ) - throw std::logic_error( "Attempt to dereference empty STL iterator." ); - - val_type val = *itor; - ++itor; -// ++num_returned; - - return val; - } - - bool has_next() const { -// return (itor != itor_end) && ( num_to_return == -1 || (num_returned < num_to_return) ); - return itor != itor_end; - } - - int skip( int n ); - - std::string as_str() const { - return "not implemented yet."; - } - - cpp_to_java* clone() const { - return new cpp_to_java( *this ); - } -}; - -template -int cpp_to_java::skip( int n ) { - int num_skipped = 0; - while( itor != itor_end && num_skipped < n ) { - ++itor; - ++num_skipped; - } - -// num_returned += num_skipped; - - return num_skipped; -} - -//////////////////////////////////////////////////////////////////////////////// -/** - * Access a Java iterator through a C++ idiom, with all properties thereof - * (cheap copy construction, pass by value, etc) - */ -template -class java_to_cpp : - public boost::iterator_facade< - java_to_cpp, - val_type, - boost::forward_traversal_tag, - val_type> { -public: - typedef utility_iterators::utility_iterator_base underlying_t; - typedef boost::shared_ptr< underlying_t > underlying_ptr; - -private: - underlying_ptr underlying; - val_type curr_val; - - bool end_marker; - -public: - java_to_cpp() : curr_val(), end_marker(true) {} - ~java_to_cpp() {} - java_to_cpp( underlying_ptr u ) : underlying( u->clone() ), end_marker(false) { - if( underlying->has_next() ) - increment(); - else - end_marker = true; - } - java_to_cpp( underlying_t& u ) : underlying( u.clone() ), end_marker(false) { - if( underlying->has_next() ) - increment(); - else - end_marker = true; - } - - java_to_cpp( const java_to_cpp& other ) { - if( other.underlying != NULL ) { - underlying.reset(other.underlying->clone()); - } - - curr_val = other.curr_val; - end_marker = other.end_marker; - } - -// static java_to_cpp get_end_marker() { -// return java_to_cpp(); -// } - - java_to_cpp& operator = ( const java_to_cpp& other ) { - if( other.underlying == NULL ) { - underlying.reset(); - } else { - underlying.reset(other.underlying->clone()); - } - - curr_val = other.curr_val; - end_marker = other.end_marker; - - return *this; - } - - std::string as_str() const { - using namespace std; - ostringstream oss; - - oss << "successor_iterator_wrapper wrapping :\n"; - if( underlying == NULL ) { - oss << "\tNULL"; - } else { - oss << "\t" << underlying->as_str(); - } - - oss << ", curr_val = " << curr_val; - - return oss.str(); - } -//////////////////////////////////////////////////////////////////////////////// -// iterator facade access -private: - friend class boost::iterator_core_access; - - void increment() { - if( !underlying->has_next() ) { - end_marker = true; - } else { - curr_val = underlying->next(); - } - } - - val_type dereference() const { - return curr_val; - } - - bool equal( const java_to_cpp& other ) const { - // the only thing I'll worry about is comparisons with the end marker - if( (underlying == NULL || end_marker) && - (other.underlying == NULL || other.end_marker ) ) { - return true; - } else { - return false; - } - } -}; - -template -class itor_capture_wrapper : - public webgraph::bv_graph::utility_iterators::utility_iterator_base { -private: - std::vector backing; - unsigned cur_pos; - -public: - itor_capture_wrapper( itor_type i_begin, - unsigned begin_index, - unsigned length ) : backing(length), cur_pos(0) { - -// if( length != 0 ) { - // we need a +1 because the last one is not copied. - std::copy( i_begin, i_begin + length, backing.begin() ); -// } - } - - val_type next() { - if( !has_next() ) { - throw std::logic_error( "Trying to dereference empty container_wrapper." ); - } - - return backing[cur_pos++]; - } - - bool has_next() const { - return cur_pos < backing.size(); - } - - itor_capture_wrapper* clone() const { - return new itor_capture_wrapper( *this ); - } - - std::string as_str() const { - std::ostringstream oss; - - oss << "itor_capture_wrapper with size = " << backing.size() << " and cur_pos = " << cur_pos << "\n"; - - return oss.str(); - } - - int skip( int how_many ) { - if( cur_pos + how_many < backing.size() ) { - cur_pos += how_many; - return how_many; - } else { - // TODO might be off-by-one? - int num_skipped = backing.size() - cur_pos; - cur_pos = backing.size(); - return num_skipped; - } - } -}; - -}}} - -#endif /*WEBGRAPH_INTERNAL_SUCCESSOR_ITERATORS_HPP_*/ diff --git a/iterators/masked_iterator.hpp b/iterators/masked_iterator.hpp deleted file mode 100644 index 049b7ac..0000000 --- a/iterators/masked_iterator.hpp +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef MASKED_ITERATOR_HPP_ -#define MASKED_ITERATOR_HPP_ - -#include "utility_iterator_base.hpp" -#include "../../log/logger.hpp" -#include -#include -#include -#include -#include -#include -#include - -//#define HARDCORE_DEBUG_MI - -namespace webgraph { namespace bv_graph { namespace utility_iterators { - -/** A {@link MaskedIntIterator} is based on an array, the mask, and on an - * underlying iterator. The sum of the values contained in the mask must not - * exceed the number of elements returned by the underlying iterator. Moreover, all - * integers in the mask must be positive, except possibly for the first one, which may be - * zero. - * - *

Mask values are interpreted as specifying inclusion-exclusion blocks. Suppose that - * the underlying iterator returns N values, and that the mask is - * n0, n1, …, - * nk. Then, the first n0 values returned by - * the underlying iterator must be kept, the next n1 values must be - * ignored, the next n2 must be kept and so on. The last - * N−(n0+…+nk) must - * be kept if k is odd, and must be ignored otherwise. An instance of this - * class will returns the kept values only, in increasing order. - * - * itor_type is the iterator type - * value_type is returned by the iterator. - */ -template -class masked_iterator : public utility_iterator_base { -private: - typedef boost::shared_ptr< utility_iterator_base > underlying_ptr; - /** The underlying iterator. */ - underlying_ptr underlying; - - /** The mask. */ - std::vector mask; - - /** explicit mask length */ - unsigned mask_len; - - /** This index in mask always represents an exclusion block. */ - unsigned curr_mask; - /** How many integers are left in the current inclusion block. If - * 0 everything left must be discarded; if - * -1 all remaining values must be kept. */ - int left; - /** Whether {@link #underlying} is exhausted. This is accessed so - * frequently that it is better to cache it. */ - bool not_over; - - void init() { - curr_mask = 0; - - if ( curr_mask < mask_len ) { - left = mask[ curr_mask++ ]; - advance(); - } - else - left = -1; - not_over = underlying->has_next(); - } - - void copy( const masked_iterator& other ) { - if( other.underlying != NULL ) - underlying.reset( other.underlying->clone() ); - else - underlying.reset(); - - mask = other.mask; - mask_len = other.mask_len; - curr_mask = other.curr_mask; - left = other.left; - not_over = other.not_over; - } - - public: - masked_iterator( const masked_iterator& other ) { - copy( other ); - } - - masked_iterator( const std::vector& m, underlying_ptr ul ) : - underlying(ul), mask( m ), mask_len( m.size() ) - { - init(); - } - - - /** Creates a new masked iterator using a given mask, mask length - * and underlying iterator. - * - * @param mask a mask, or null, meaning an empty mask - * (everything is copied). - * @param maskLen an explicit mask length. - * @param underlying an underlying iterator. - */ - masked_iterator( const std::vector& m, - const int ml, - underlying_ptr ul ) : - underlying( ul ), mask( m ), mask_len( ml ) - { - init(); - } - - -#ifdef HARDCORE_DEBUG_MI - val_type next() { - val_type val = next_internal(); - logs::logger( "iterators" ) << LEVEL_DEBUG - << "masked iterator next about to return " << val - << "\n"; - return val; - } - - val_type next_internal(); -#else - val_type next(); -#endif - - bool has_next() const; - int skip( int n ); - - masked_iterator& operator = ( const masked_iterator& other ) { - copy( other ); - } - - masked_iterator* clone() const { - return new masked_iterator( *this ); - } - - std::string as_str() const { - std::ostringstream oss; - - oss << "masked_iterator masking:\n" - << "\t" << underlying->as_str(); - - return oss.str(); - } - -private: - void advance(); -}; - -template -#ifdef HARDCORE_DEBUG_MI -val_type masked_iterator::next_internal() { -#else -val_type masked_iterator::next() { -#endif - if ( ! has_next() ) - throw std::logic_error( "Trying to dereference empty masked_iterator." ); - - const int nxt = underlying->next(); - if ( left > 0 ) { - left--; - advance(); - } - not_over = underlying->has_next(); - return nxt; -} - -template -bool masked_iterator::has_next() const { - if ( left == 0 ) - return false; - if ( left < 0 ) { - if( not_over ) assert( underlying->has_next() ); - return not_over; - } - - assert( underlying->has_next() ); - return true; -} - -template -void masked_iterator::advance() { - if ( left == 0 && curr_mask < mask_len ) { - underlying->skip( mask[ curr_mask++ ] ); - if ( curr_mask < mask_len ) - left = mask[ curr_mask++ ]; - else left = -1; - } -} - -template -int masked_iterator::skip( int n ) { - int skipped = 0; - - while( skipped < n && ( left > 0 || left == -1 && not_over ) ) { - if ( left == -1 ) - skipped += underlying->skip( n - skipped ); - else { - if ( n - skipped < left ) { - underlying->skip( n - skipped ); - not_over = underlying->has_next(); - left -= ( n - skipped ); - return n; - } - else { - underlying->skip( left ); - skipped += left; - left = 0; - advance(); - not_over = underlying->has_next(); - } - } - } - - return skipped; -} - -} } } -#endif /*MASKED_ITERATOR_HPP_*/ diff --git a/iterators/merged_iterator.hpp b/iterators/merged_iterator.hpp deleted file mode 100644 index 7c31b55..0000000 --- a/iterators/merged_iterator.hpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef MERGED_ITERATOR_HPP_ -#define MERGED_ITERATOR_HPP_ - -#include "utility_iterator_base.hpp" -#include "../../log/logger.hpp" -#include -#include -#include -#include -#include -#include -#include - -//#define HARDCORE_DEBUG_MERGED_ITOR - -namespace webgraph { namespace bv_graph { namespace utility_iterators { - -/** A merged integer iterator based on two other iterators returning comparable values in - * an increasing fashion simply returns the (ordered) merge of the two iterators, without - * duplicates. - * - * itor : should be a forward traversal output iterator - * val_type : needs to have < defined on it - */ - -template -class merged_iterator : public utility_iterator_base { -public: - typedef boost::shared_ptr< utility_iterator_base > underlying_ptr; - -private: - underlying_ptr it0, it1; - bool valid0, valid1; - val_type curr0, curr1; - int n; - - void init() { - if ( valid0 = it0->has_next() ) - curr0 = it0->next(); - if ( valid1 = it1->has_next() ) - curr1 = it1->next(); - } - - void copy( const merged_iterator& other ); - -public: - merged_iterator( underlying_ptr i0, underlying_ptr i1 ) : - it0(i0), it1(i1), n(std::numeric_limits::max()) - { - init(); - } - - merged_iterator( const merged_iterator& other ) { - copy( other ); - } - - /** Creates a new merged iterator by merging two given iterators; - * the resulting iterator will not emit more than n - * integers. - * - * @param it0 the first increasing iterator. - * @param it1 the second increasing iterator. - * @param n the maximum number of integers this iterator will enumerate. - */ - merged_iterator( underlying_ptr i0, underlying_ptr i1, int sz ) : - it0( i0 ), it1( i1 ), n(sz) { - init(); - } - - merged_iterator& operator = ( const merged_iterator& other ) { - copy( other ); - return *this; - } - - bool has_next() const { - return n != 0 && ( valid0 || valid1 ); - } - -#ifdef HARDCORE_DEBUG_MERGED_ITOR - val_type next() { - val_type v = next_internal(); - - logs::logger( "iterators" ) << LEVEL_DEBUG - << "merged iterator next about to return " << v - << "\n"; - - return v; - } - - val_type next_internal(); -#else - val_type next(); -#endif - - std::string as_str() const { - std::ostringstream oss; - - oss << "merged iterator merging:\n" - << it0->as_str() << "\nand\n" - << it1->as_str() << "\n"; - - return oss.str(); - } - - int skip( int how_many ) { - int num_skipped = 0; - - while( num_skipped < how_many && has_next() ) { - next(); - ++num_skipped; - } - - return num_skipped; - } - - merged_iterator* clone() const { - return new merged_iterator( *this ); - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -template -void merged_iterator::copy( const merged_iterator& other ) { - if( other.it0 != NULL ) { - it0.reset( other.it0->clone() ); - } else { - it0.reset(); - } - - if( other.it1 != NULL ) { - it1.reset( other.it1->clone() ); - } else { - it1.reset(); - } - - valid0 = other.valid0; - valid1 = other.valid1; - curr0 = other.curr0; - curr1 = other.curr1; - n = other.n; -} - -template< class val_type > -#ifdef HARDCORE_DEBUG_MERGED_ITOR -val_type merged_iterator::next_internal() { -#else -val_type merged_iterator::next() { -#endif - if ( !has_next() ) - throw std::logic_error( "Trying to dereference empty merged_iterator." ); - n--; - - int current; - - if ( !valid0 ) { - current = curr1; - if ( valid1 = it1->has_next() ) - curr1 = it1->next(); - return current; - } - if ( !valid1 ) { - current = curr0; - if ( valid0 = it0->has_next() ) - curr0 = it0->next(); - return current; - } - if ( curr0 < curr1 ) { - current = curr0; - if ( valid0 = it0->has_next() ) - curr0 = it0->next(); - } - else if ( curr0 > curr1 ) { - current = curr1; - if ( valid1 = it1->has_next() ) - curr1 = it1->next(); - } - else { - current = curr0; - if ( valid0 = it0->has_next() ) - curr0 = it0->next(); - if ( valid1 = it1->has_next() ) - curr1 = it1->next(); - } - return current; -} - -} } } - - -#endif /*MERGED_ITERATOR_HPP_*/ diff --git a/iterators/node_iterator.cpp b/iterators/node_iterator.cpp deleted file mode 100644 index 5b60ebe..0000000 --- a/iterators/node_iterator.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#include "node_iterator.hpp" -#include "iterator_wrappers.hpp" - -#include -#include -#include -#include - -#include "../webgraph.hpp" - -using namespace std; -#ifndef CONFIG_FAST -using namespace logs; -#endif - -namespace webgraph { namespace bv_graph { - -using namespace utility_iterators; - -node_iterator::node_iterator( const graph* owner, boost::shared_ptr is, - int from, int window_size ) : - ibs(is) { - this->from = from; - this->cyclic_buffer_size = window_size + 1; - this->owner = owner; - this->n = owner->get_num_nodes(); - this->end_marker = false; - this->window.resize( cyclic_buffer_size ); - for( vector< vector >::iterator itor = window.begin(); - itor != window.end(); - itor++ ) { - itor->resize( graph::INITIAL_SUCCESSOR_LIST_LENGTH ); - - this->outd.resize( cyclic_buffer_size ); -// this->block_outdegrees = NULL; // so long as offset step = 1 TODO change this - - if ( from != 0 ) { - owner->position( *ibs, from ); - } - curr = from - 1; - } - increment(); // grab the first node. -} - -//////////////////////////////////////////////////////////////////////////////// - -void node_iterator::copy( const node_iterator& other ) { - this->n = other.n; - this->ibs = other.ibs; - this->cyclic_buffer_size = other.cyclic_buffer_size; - this->window = other.window; - this->outd = other.outd; - this->block_outdegrees = other.block_outdegrees; - this->from = other.from; - this->curr = other.curr; - this->owner = other.owner; - this->end_marker = other.end_marker; -} - - -//////////////////////////////////////////////////////////////////////////////// -void node_iterator::increment() { - if( curr == n - 1 ) { - // then this increment is about to place curr == n. Rather than trying to load - // any successor list, just invalidate this iterator and make it an end marker. - end_marker = true; - } else { - assert( curr < n - 1 ); - int cur_index = ++curr % cyclic_buffer_size; - - graph::internal_succ_itor_ptr itor; - - itor = owner->get_successors_internal( curr, ibs, window, outd, block_outdegrees ); - - if( window[cur_index].size() < (unsigned)outd[cur_index] ) - window[cur_index ].resize( outd[cur_index] ); - - vector::iterator i = window[cur_index].begin(); - - while( itor->has_next() ) { - *i = itor->next(); -#ifndef CONFIG_FAST - logs::logger( "iterators" ) << logs::LEVEL_EVERYTHING - << "node iterator - succ list so far: " << *i << "\n"; -#endif - - ++i; - } - -// logger( "iterators" ) << LEVEL_EVERYTHING -// << "itor: " << itor->as_str() << "\n"; - -// iterator_wrappers::java_to_cpp w_itor( itor ), w_end; - -// std::copy( w_itor, w_end, window[cur_index].begin() ); - -// logger( "iterators" ) << LEVEL_EVERYTHING -// << "Done copying...\n"; - } -} - -//////////////////////////////////////////////////////////////////////////////// -bool node_iterator::equal(const node_iterator& rhs ) const { - // figure out of this is supposed to be an end comparison - if( (rhs.end_marker && n == curr) || - (rhs.n == rhs.curr && end_marker) || - (rhs.end_marker && end_marker) || - (n == curr && rhs.n == rhs.curr) ) - return true; - - // otherwise, do a real comparison - - return this->n == rhs.n && - ibs == rhs.ibs && - cyclic_buffer_size == rhs.cyclic_buffer_size && - window == rhs.window && - outd == rhs.outd && - block_outdegrees == rhs.block_outdegrees && - from == rhs.from && - curr == rhs.curr && - owner == rhs.owner; -} - -graph::succ_itor_pair successors( node_iterator& itor ) { - assert( itor.curr != itor.from - 1 ); - - int cur_index = itor.curr % itor.cyclic_buffer_size; - - typedef iterator_wrappers::itor_capture_wrapper::iterator, int> itor_base; - - itor_base ib( itor.window[cur_index].begin(), 0, itor.outd[cur_index] ); - - // now wrap the iterator and return - return make_pair( iterator_wrappers::java_to_cpp( ib ), - iterator_wrappers::java_to_cpp() ); - -// return make_pair( successor_iterator_wrapper(base_pair.first), -// successor_iterator_wrapper(base_pair.second) ); -} - - -vector successor_vector( const node_iterator& itor ) { - assert( itor.curr != itor.from - 1 ); - - vector retval = itor.window[ itor.curr % itor.cyclic_buffer_size ]; - - retval.resize( itor.outd[ itor.curr % itor.cyclic_buffer_size ] ); - - return retval; -} - -int outdegree( const node_iterator& itor ) { - assert( itor.curr != itor.from - 1 ); - - return itor.outd[ itor.curr % itor.cyclic_buffer_size ]; -} - -} } diff --git a/iterators/node_iterator.hpp b/iterators/node_iterator.hpp deleted file mode 100644 index 4c9f4fc..0000000 --- a/iterators/node_iterator.hpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef NODE_ITERATOR_HPP -#define NODE_ITERATOR_HPP - -#include -#include -#include -#include -#include - -#include "iterator_wrappers.hpp" -#include "../../bitstreams/input_bitstream.hpp" -#include "../../log/logger.hpp" - -namespace webgraph { namespace bv_graph { - -class graph; - -class node_iterator : - public boost::iterator_facade< - node_iterator, - int, - boost::forward_traversal_tag, - int> { -private: - int n; // = numNodes(); - - /** Our bit stream. */ - boost::shared_ptr ibs; - /** We keep the size of the cyclic buffer (the window size + 1 ) in a local variable. */ - int cyclic_buffer_size; // = windowSize + 1; - /** At any time, window will be ready to be passed to {@link BVGraph#successors(int, - * InputBitStream, int[][], int[], int[])} */ - std::vector< std::vector > window; // = new int[ cyclicBufferSize ][ INITIAL_SUCCESSOR_LIST_LENGTH ]; - /** At any time, outd will be ready to be passed to {@link BVGraph#successors(int, - * InputBitStream, int[][], int[], int[])} */ - std::vector outd; // = new int[ cyclicBufferSize ]; - /** At any time, blockOutdegrees will be ready to be passed to {@link - * BVGraph#successors(int, InputBitStream, int[][], int[], int[])} */ - std::vector block_outdegrees; // = offsetStep > 1 ? new int[ offsetStep ] : null; - /** The index of the node from which we started iterating. */ - int from; - /** The index of the node just before the next one. */ - int curr; - /** the graph that this iterator is iterating over. */ - const graph* owner; - /** wether this is meant to stand as an end marker */ - bool end_marker; - - //////////////////////////////////////////////////////////////////////////////// - // methods -public: - node_iterator() { - this->from = 0; - this->cyclic_buffer_size = 0; - this->owner = NULL; - this->n = 0; - this->end_marker = true; - -#ifndef CONFIG_FAST - logs::register_logger( "iterators", logs::LEVEL_MAX ); -#endif - } - - //////////////////////////////////////////////////////////////////////////////// - node_iterator( const graph* owner, boost::shared_ptr is, - int from, int window_size ); - - node_iterator( const node_iterator& rhs ) { - copy( rhs ); - } - - ~node_iterator() { - // nothing needed. - } - - node_iterator& operator = ( const node_iterator& rhs ) { - copy( rhs ); - - return *this; - } - -private: - friend class boost::iterator_core_access; - - void copy( const node_iterator& other ); - - - /** At each call, we build the successor iterator (making a call to {@link - * BVGraph#successors(int, InputBitStream, int[][], int[], int[])}, and we completely - * iterate over it, filling the appropriate entry in window. - */ - void increment(); - -// int nextInt() { -// if ( ! hasNext() ) throw new NoSuchElementException(); - -// final int currIndex = ++curr % cyclicBufferSize; -// final IntIterator i = BVGraph.this.successors( curr, ibs, window, outd, blockOutdegrees ); - -// if ( window[ currIndex ].length < outd[ currIndex ] ) window[ currIndex ] = new int[ outd[ currIndex ] ]; -// IntIterators.unwrap( i, window[ currIndex ] ); - -// return curr; -// } - - int dereference() const { - return curr; - } - - bool equal( const node_iterator& rhs ) const; - -public: - typedef webgraph::bv_graph::iterator_wrappers::java_to_cpp succ_itor_wrapper; - friend std::pair successors( node_iterator& rhs ); - - friend std::vector successor_vector( const node_iterator& rhs ); - friend int outdegree( const node_iterator& rhs ); - friend class graph; -}; - -int outdegree( const node_iterator& itor ); - -} } - - -#endif diff --git a/iterators/residual_iterator.hpp b/iterators/residual_iterator.hpp deleted file mode 100644 index 9360f53..0000000 --- a/iterators/residual_iterator.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef RESIDUAL_ITERATOR_HPP_ -#define RESIDUAL_ITERATOR_HPP_ - -#include "utility_iterator_base.hpp" -#include "../../utils/fast.hpp" -#include "../../bitstreams/input_bitstream.hpp" -#include -#include -#include -#include -#include "../webgraph.hpp" -#include "../../log/logger.hpp" - -//#define HARDCORE_DEBUG_RESID_ITOR - -namespace webgraph { namespace bv_graph { - -//class graph; - -namespace utility_iterators { - -template -class residual_iterator : public utility_iterator_base { -private: - unsigned int node; - int prev; - unsigned int i; - const webgraph::bv_graph::graph* owner; - boost::shared_ptr ibs; - -public: - residual_iterator( int n, int res_left, - const webgraph::bv_graph::graph* o, boost::shared_ptr i ) : - node(n), prev(-1), i( res_left ), owner(o), ibs(i) {} - - bool has_next() const { - return i != 0; - } - -#ifdef HARDCORE_DEBUG_RESID_ITOR - val_type next() { - val_type n = next_internal(); - logs::logger( "iterators" ) << LEVEL_EVERYTHING << "residual_iterator next about to return " - << n << "\n"; - - return n; - } - - val_type next_internal(); -#else - val_type next(); -#endif - - std::string as_str() const { - std::ostringstream oss; - - oss << "residual iterator:\n" - << "node = " << node << ", prev = " << prev << ", i = " << i << "\n"; - - return oss.str(); - } - - residual_iterator* clone() const { - return new residual_iterator( *this ); - } - - int skip( int how_many ) { -// throw logic_error( "this should not happen." ); - - int num_skipped = 0; - - while( has_next() && num_skipped < how_many ) { - next(); - num_skipped++; - } - - return num_skipped; - } -}; - -template -#ifdef HARDCORE_DEBUG_RESID_ITOR -val_type residual_iterator::next_internal() { -#else -val_type residual_iterator::next() { -#endif - if ( ! has_next() ) - throw logic_error( "Trying to dereference empty residual_iterator." ); - i--; - if ( prev == -1 ) - return prev = node + utils::nat2int( owner->read_residual( *ibs ) ); - else - return prev = owner->read_residual( *ibs ) + prev + 1; -} - -} } } -#endif /*RESIDUAL_ITERATOR_HPP_*/ diff --git a/iterators/tests/Makefile b/iterators/tests/Makefile deleted file mode 100644 index 8edc39c..0000000 --- a/iterators/tests/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# Tests makefile - -include ../../../flags.mk - -all: test_merged_iterator test_masked_iterator test_interval_sequence_iterator - -all_o: test_interval_sequence_iterator.o test_masked_iterator.o test_merged_iterator.o - -test_wrapped_iterators: test_wrapped_iterators.o - g++ $(FLAGS) -o test_wrapped_iterators test_wrapped_iterators.o - -test_merged_iterator: test_merged_iterator.o - g++ $(FLAGS) -o test_merged_iterator test_merged_iterator.o - -test_masked_iterator: test_masked_iterator.o - g++ $(FLAGS) -o test_masked_iterator test_masked_iterator.o - -test_interval_sequence_iterator: test_interval_sequence_iterator.o - g++ $(FLAGS) -o test_interval_sequence_iterator test_interval_sequence_iterator.o - -test_iterator_wrappers: test_iterator_wrappers.o - g++ $(FLAGS) -o test_iterator_wrappers test_iterator_wrappers.o - -clean: - rm -f *.o - rm -f test_merged_iterator - rm -f test_masked_iterator - rm -f core.* - rm -f *~ - -%.o : %.cpp - g++ $(FLAGS) -c $< - diff --git a/iterators/tests/compare_iterators.hpp b/iterators/tests/compare_iterators.hpp deleted file mode 100644 index f2c7754..0000000 --- a/iterators/tests/compare_iterators.hpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef COMPARE_ITERATORS_HPP -#define COMPARE_ITERATORS_HPP - -#include "../utility_iterator_base.hpp" -#include "../iterator_wrappers.hpp" -#include - -//////////////////////////////////////////////////////////////////////////////// -template -void compare_iterators( my_itor mi, - exp_itor expected, - exp_itor expected_end ) { - using namespace std; - - while( mi.has_next() ) { - int cur_value = mi.next(); - - if( cur_value != *expected ) { - cerr << "Error - got " << cur_value << ", expected " << *expected << endl; - return; - } - - if( expected == expected_end && mi.has_next() ) { - cerr << "mi is still returning stuff, but expected is done" << endl; - return; - } - - if( expected == expected_end && !mi.has_next() ) { - break; - } - ++expected; - } - - if( expected != expected_end ) { - cerr << "mi ran out too soon." << endl; - return; - } - - cerr << "Everything seems to have worked.\n"; -} - -//////////////////////////////////////////////////////////////////////////////// -template -void compare_iterators_polymorphic( my_itor mi, - exp_itor expected, - exp_itor expected_end ) { - // cast mine to the base class before doing anything... - using namespace webgraph::bv_graph::utility_iterators; - using namespace std; - - utility_iterator_base* uib = &mi; - - while( uib->has_next() ) { - int cur_value = uib->next(); - - if( cur_value != *expected ) { - cerr << "Error - got " << cur_value - << ", expected " << *expected << endl; - } - - if( expected == expected_end && uib->has_next() ) { - cerr << "uib is still returning stuff, but expected is done" << endl; - return; - } - - if( expected == expected_end && !uib->has_next() ) { - break; - } - - ++expected; - } - - if( expected != expected_end ) { - cerr << "uib ran out too soon." << endl; - return; - } - - cerr << "Everything seems to have worked.\n"; -} - -//////////////////////////////////////////////////////////////////////////////// -template -void compare_iterators_wrapped( my_itor mi, - exp_itor expected, exp_itor expected_end ) { - using namespace std; - using namespace webgraph::bv_graph; - - // wrap both, and compare them backwards. - typedef iterator_wrappers::java_to_cpp jtc_t; - typedef iterator_wrappers::cpp_to_java ctj_t; - - jtc_t jtc( mi ), jtc_end; - ctj_t ctj( expected, expected_end ); - - cerr << "Comparing wrapped iterators backwards.\n"; - compare_iterators( ctj, jtc, jtc_end ); - - cerr << "Now comparing the cpp->java iterator polymorphically.\n"; - compare_iterators_polymorphic( ctj, jtc, jtc_end ); -} - -#endif diff --git a/iterators/tests/test_capture_wrapper.cpp b/iterators/tests/test_capture_wrapper.cpp deleted file mode 100644 index 4519d35..0000000 --- a/iterators/tests/test_capture_wrapper.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#include "../iterator_wrappers.hpp" -#include "../utility_iterator_base.hpp" -#include -#include -#include -#include - -int main() { - using namespace std; - using namespace webgraph::bv_graph::iterator_wrappers; - - vector test_vector (10); - int j = 0; - for( vector::iterator i = test_vector.begin(); i != test_vector.end(); ++i ) - *i = j++; - - cerr << "Here is the vector by itself: \n"; - copy( test_vector.begin(), test_vector.end(), ostream_iterator(cerr, " ") ); - - cerr << "\nHere is the vector through an itor capture wrapper: \n"; - - itor_capture_wrapper::iterator, int> cap( test_vector.begin(), 0, 10 ); - - while( cap.has_next() ) { - cerr << cap.next() << " "; - } - - cerr << endl; - - itor_capture_wrapper::iterator, int> cap2( test_vector.begin(), 0, 10 ); - java_to_cpp jv( cap2 ), j_end; - - cerr << "Here it is again through a java to cpp adapter:\n"; - - copy( jv, j_end, ostream_iterator(cerr, " ") ); - - cerr << endl; - - return 0; -} diff --git a/iterators/tests/test_interval_sequence_iterator b/iterators/tests/test_interval_sequence_iterator deleted file mode 100755 index da6ee1a..0000000 Binary files a/iterators/tests/test_interval_sequence_iterator and /dev/null differ diff --git a/iterators/tests/test_interval_sequence_iterator.cpp b/iterators/tests/test_interval_sequence_iterator.cpp deleted file mode 100644 index 3ace4e2..0000000 --- a/iterators/tests/test_interval_sequence_iterator.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#include -#include -#include -#include "../interval_sequence_iterator.hpp" -#include "compare_iterators.hpp" - -class interval_size_generator { - int avg; - -public: - interval_size_generator( int a ) { - avg = a; - } - - bool coin_is_heads() { - return rand() % 2 == 0; - } - - int sign() { - if( coin_is_heads() ) - return 1; - else - return -1; - } - - size_t operator() () { - return avg + sign() * (rand() % avg) / 2; - } -}; - -//////////////////////////////////////////////////////////////////////////////// -int main(int argc, char**argv) { - using namespace std; - using namespace webgraph::bv_graph; - - int num_intervals = atoi( argv[1] ); - int avg_size_of_interval = atoi( argv[2] ); - - vector sizes( num_intervals ); - generate( sizes.begin(), sizes.end(), interval_size_generator(avg_size_of_interval) ); - - cerr << "Here are the sizes : "; - copy( sizes.begin(), sizes.end(), - ostream_iterator< size_t >( cerr, " " ) ); - - cerr << endl; - - int start_of_last_interval = rand() % 100; - - vector left( num_intervals ); - left[0] = start_of_last_interval; - - - for( int i = 1; i < num_intervals; i++ ) { - // it's at least as long as the size, but could be twice that, - // just to spice things up - - int end_of_last_interval = start_of_last_interval + sizes[i-1]; - int start_of_this_interval = end_of_last_interval + rand() % sizes[i-1] + 1; - - left[i] = start_of_this_interval; - - // set things up for next time - start_of_last_interval = start_of_this_interval; - } - - // data is generated, print it - cerr << "We expect to see:\n"; - - vector expected; - - for( int i = 0; i < num_intervals; i++ ) { - for( int j = 0; j < sizes[i]; j++ ) { - expected.push_back( left[i] + j ); - } - } - - copy( expected.begin(), expected.end(), - ostream_iterator( cerr, " " ) ); - - cerr << endl; - - cerr << "Here's what we really see:\n"; - - using namespace utility_iterators; - - interval_sequence_iterator ist( left, sizes ); - - cerr << "Comparing the iterators normally...\n"; - compare_iterators( ist, expected.begin(), expected.end() ); - - cerr << "Comparing the iterators polymorphically...\n"; - compare_iterators_polymorphic( ist, expected.begin(), expected.end() ); - - cerr << "Comparing wrapped iterators...\n"; - compare_iterators_wrapped( ist, expected.begin(), expected.end() ); - - return 0; -} - diff --git a/iterators/tests/test_masked_iterator b/iterators/tests/test_masked_iterator deleted file mode 100755 index aed9a1c..0000000 Binary files a/iterators/tests/test_masked_iterator and /dev/null differ diff --git a/iterators/tests/test_masked_iterator.cpp b/iterators/tests/test_masked_iterator.cpp deleted file mode 100644 index f670517..0000000 --- a/iterators/tests/test_masked_iterator.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#include -#include - -#include "../masked_iterator.hpp" -#include "compare_iterators.hpp" - -using namespace std; -using namespace webgraph; -using namespace webgraph::bv_graph::utility_iterators; - -//////////////////////////////////////////////////////////////////////////////// -int main( int argc, char** argv ) { - // Reads the length and number of 0s - unsigned n = atoi( argv[ 1 ] ); - unsigned z = atoi( argv[ 2 ] ); - - vector x( n ); - - vector keep( n ); - - vector res; - vector blocks; - - unsigned i, j, p = 0; - bool dep; - - // Generate - for ( i = 0; i < n; i++ ) - p = x[ i ] = p + ( rand() % 1000 ); - - for ( i = 0; i < n-z; i++ ) - keep[ i ] = true; - - for ( i = 0; i < n; i++ ) { - j = i + (int)( rand() % ( n - i ) ); - // swap... - dep = keep[ i ]; - keep[ i ] = keep[ j ]; - keep[ j ] = dep; - } - - // Compute result - for ( i = 0; i < n; i++ ) - if ( keep[ i ] ) - res.push_back( x[ i ] ); - - // Prepare blocks - bool look_at = true; - - int curr = 0; - for ( i = 0; i < n; i++ ) { - if ( keep[ i ] == look_at ) - curr++; - else { - blocks.push_back( curr ); - look_at = !look_at; - curr = 1; - } - } - - // Output - cerr << "GENERATED:"; - for ( i = 0; i < n; i++ ) { - if ( keep[ i ] ) - cerr << "*"; - cerr << x[ i ] << " "; - } - - cerr << "\nBLOCKS:"; - - for ( i = 0; i < blocks.size(); i++ ) - cerr << blocks[ i ] << " "; - - cerr << "\nEXPECTED RESULT:"; - - for ( i = 0; i < res.size(); i++ ) - cerr << res[ i ] << " "; - - cerr << endl; - - typedef webgraph::bv_graph::iterator_wrappers::cpp_to_java::iterator, int> wrapper_t; - - typedef masked_iterator mi_t; - - boost::shared_ptr< wrapper_t > wrapped( new wrapper_t( x.begin(), x.end() ) ); - - mi_t mi( blocks, wrapped ); - - cerr << "Testing iterators normally\n"; - compare_iterators( mi, res.begin(), res.end() ); - - cerr << "Testing iterators normally\n"; - compare_iterators( mi, res.begin(), res.end() ); - - cerr << "Testing iterators polymorphically\n"; - compare_iterators_polymorphic( mi, res.begin(), res.end() ); - - cerr << "Testing iterators wrapped..\n"; - compare_iterators_wrapped( mi, res.begin(), res.end() ); - - return 0; -} diff --git a/iterators/tests/test_merged_iterator b/iterators/tests/test_merged_iterator deleted file mode 100755 index 987e31c..0000000 Binary files a/iterators/tests/test_merged_iterator and /dev/null differ diff --git a/iterators/tests/test_merged_iterator.cpp b/iterators/tests/test_merged_iterator.cpp deleted file mode 100644 index 7ac775a..0000000 --- a/iterators/tests/test_merged_iterator.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "../merged_iterator.hpp" -#include "compare_iterators.hpp" - -using namespace std; -using namespace webgraph; -using namespace webgraph::bv_graph::utility_iterators; - -int tiny_rand() { - return rand(); -} - -int main( int argc, char** argv ) { - // Reads two lengths - int n0 = atoi( argv[1] ); - int n1 = atoi( argv[2] ); - - vector x0( n0 ), x1( n1 ); - - x0.resize( n0 ); - x1.resize( n1 ); - - // fill both with random numbers - srand( time(NULL) ); - - generate( x0.begin(), x0.end(), tiny_rand ); - generate( x1.begin(), x1.end(), tiny_rand ); - - sort( x0.begin(), x0.end() ); - sort( x1.begin(), x1.end() ); - - vector expected; - - vector::iterator x0_end = unique( x0.begin(), x0.end() ); - x0.erase( x0_end, x0.end() ); - - vector::iterator x1_end = unique( x1.begin(), x1.end() ); - x1.erase( x1_end, x1.end() ); - - set_union( x0.begin(), x0.end(), - x1.begin(), x1.end(), - back_insert_iterator > (expected) ); - - cerr << "x0.size() : " << x0.size() << endl - << "x1.size() : " << x1.size() << endl - << "expected.size() : " << expected.size() << endl; - - typedef merged_iterator mi_t; - typedef webgraph::bv_graph::iterator_wrappers::cpp_to_java< vector::iterator, int > wrapper_t; - typedef boost::shared_ptr wrapper_ptr; - - wrapper_ptr x0_wrap( new wrapper_t(x0.begin(), x0.end()) ); - wrapper_ptr x1_wrap( new wrapper_t(x1.begin(), x1.end()) ); - - mi_t m( x0_wrap, x1_wrap ); - - cerr << "comparing iterators normally..\n"; - - compare_iterators( m, expected.begin(), expected.end() ); - - cerr << "Comparing iterators polymorphically..\n"; - compare_iterators_polymorphic( m, expected.begin(), expected.end() ); - - - cerr << "Comparing iterators wrapped..\n"; - compare_iterators_wrapped( m, expected.begin(), expected.end() ); - return 0; -} diff --git a/iterators/tests/test_wrapped_iterators.cpp b/iterators/tests/test_wrapped_iterators.cpp deleted file mode 100644 index 5540967..0000000 --- a/iterators/tests/test_wrapped_iterators.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#include "../iterator_wrappers.hpp" -#include "../utility_iterator_base.hpp" -#include -#include -#include -#include - -int myrand() { - return rand() % 100; -} - -int main( int ac, char** av ) { - using namespace std; - using namespace webgraph::bv_graph::iterator_wrappers; - using namespace webgraph::bv_graph::utility_iterators; - - vector blah(10); - srand( time(NULL) ); - - generate( blah.begin(), blah.end(), myrand ); - - cerr << "Printing out 10 random numbers from vector with STL iterator.\n"; - - for( vector::iterator itor = blah.begin(); - itor != blah.end(); - ++itor ) { - cerr << *itor << " "; - } - - cerr << "\nNow the same 10 using iterator wrapped with Java idiom.\n"; - - cpp_to_java::iterator, int> ctj( blah.begin(), blah.end() ); - - while( ctj.has_next() ) { - cerr << ctj.next() << " "; - } - - cpp_to_java::iterator, int> ctj2( blah.begin(), blah.end() ); - - utility_iterator_base* u = &ctj2; - - cerr << "\nPrinting polymorphically.\n"; - - while( u->has_next() ) { - cerr << u->next() << " "; - } - - cerr << "\nNow re-wrapping as a Java iterator and printing again.\n"; - - cpp_to_java< vector::iterator, int > ctj_3( blah.begin(), blah.end() ); - java_to_cpp jtc( ctj_3 ), jtc_end; - - java_to_cpp jtc2; - jtc2 = jtc; - - for( ; jtc != jtc_end; ++jtc ) - cerr << *jtc << " "; - - cerr << endl; - - for( ; jtc2 != jtc_end; ++jtc2 ) - cerr << *jtc2 << " "; - - cerr << endl; - - return 0; -} diff --git a/iterators/utility_iterator_base.hpp b/iterators/utility_iterator_base.hpp deleted file mode 100644 index 6646707..0000000 --- a/iterators/utility_iterator_base.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef UTILITY_ITERATOR_BASE_HPP -#define UTILITY_ITERATOR_BASE_HPP - -#include -#include - -namespace webgraph { namespace bv_graph { namespace utility_iterators { - // nothing here.. just serves as a polymorphic base class - template - class utility_iterator_base { - public: - utility_iterator_base() {} - virtual ~utility_iterator_base() {} - - virtual val_type next() = 0; - virtual bool has_next() const = 0; - virtual int skip( int how_many ) = 0; - - virtual std::string as_str() const = 0; - - // need this for the C++ pass-by-value idiom to work with polymorphism - virtual utility_iterator_base* clone() const = 0; - }; -} } } - -#endif diff --git a/tests/Makefile b/tests/Makefile index 7578301..177ac61 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,7 +1,30 @@ include ../flags.mk +all: compress_webgraph print_webgraph print_webgraph_offline print_webgraph_sequential convert_to_binary_edgelist convert_to_text + compress_webgraph: compress_webgraph.o - g++ -L$(LIBS) -o compress_webgraph compress_webgraph.o \ + pwd + g++ -static -L$(LIBS) -L.. -o compress_webgraph compress_webgraph.o \ + -lwebgraph -lboost_regex -lboost_program_options -lboost_filesystem + +print_webgraph: print_webgraph.o + g++ -static -L$(LIBS) -L.. -o print_webgraph print_webgraph.o \ + -lwebgraph -lboost_regex -lboost_program_options -lboost_filesystem + +print_webgraph_offline: print_webgraph_offline.o + g++ -static -L$(LIBS) -L.. -o print_webgraph_offline print_webgraph_offline.o \ + -lwebgraph -lboost_regex -lboost_program_options -lboost_filesystem + +print_webgraph_sequential: print_webgraph_sequential.o + g++ -static -L$(LIBS) -L.. -o print_webgraph_sequential print_webgraph_sequential.o \ + -lwebgraph -lboost_regex -lboost_program_options -lboost_filesystem + +convert_to_binary_edgelist: convert_to_binary_edgelist.o + g++ -static -L$(LIBS) -L.. -o convert_to_binary_edgelist convert_to_binary_edgelist.o \ + -lwebgraph -lboost_regex -lboost_program_options -lboost_filesystem + +convert_to_text: convert_to_text.o + g++ -static -L$(LIBS) -L.. -o convert_to_text convert_to_text.o \ -lwebgraph -lboost_regex -lboost_program_options -lboost_filesystem install: @@ -13,3 +36,10 @@ install: clean: rm -f *.o rm -f *~ + rm -f compress_webgraph + rm -f print_webgraph + rm -f print_webgraph_offline + rm -f print_webgraph_sequential + rm -f convert_to_binary_edgelist + rm -f convert_to_text + diff --git a/tests/PrintWebgraph.java b/tests/PrintWebgraph.java deleted file mode 100644 index 71928bb..0000000 --- a/tests/PrintWebgraph.java +++ /dev/null @@ -1,40 +0,0 @@ -import it.unimi.dsi.webgraph.*; -import it.unimi.dsi.fastutil.ints.*; - -public class PrintWebgraph { - - public static void main( String[] args ) throws Exception { - ImmutableGraph g; - - if( args.length < 1 ) { - System.err.println( "Need to supply name of graph to print." ); - System.exit( 1 ); - } - - String graphName = args[0]; - - g = ImmutableGraph.load( graphName ); - - NodeIterator itor = g.nodeIterator(); - - System.err.println( g.numNodes() ); - - while( itor.hasNext() ) { - - int nodeID = itor.nextInt(); - //System.err.println( itor.nextInt() ); - System.err.println( nodeID ); - //itor.nextInt(); - IntIterator succItor = g.successors( nodeID ); //itor.successors(); - - if( succItor.hasNext() ) - System.err.print( succItor.nextInt() ); - - while( succItor.hasNext() ) { - System.err.print( " " + succItor.nextInt() ); - } - - System.err.println(); - } - } -} diff --git a/tests/asciigraph_tests/test_ascii_graph.cpp b/tests/asciigraph_tests/test_ascii_graph.cpp index 92df676..bd2a68f 100644 --- a/tests/asciigraph_tests/test_ascii_graph.cpp +++ b/tests/asciigraph_tests/test_ascii_graph.cpp @@ -1,22 +1,22 @@ -/* - * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - +/* + * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + #include "../../asciigraph/offline_graph.hpp" #include #include @@ -73,7 +73,7 @@ void print_first_n_edges( webgraph::ascii_graph::offline_graph o, int n ) { } //////////////////////////////////////////////////////////////////////////////// -void print_all_vertices_and_edges( webgraph::ascii_graph::offline_graph oag ) { +void print_all_vertices_and_edges( webgraph::ascii_graph::offline_graph oag ) { using namespace webgraph::ascii_graph; offline_graph::vertex_iterator begin, end; diff --git a/tests/compress_webgraph.cpp b/tests/compress_webgraph.cpp index 18fdb3e..6073750 100644 --- a/tests/compress_webgraph.cpp +++ b/tests/compress_webgraph.cpp @@ -51,6 +51,7 @@ int main( int argc, char** argv ) { quantum = 10000; bool offline = false, write_offsets = false; + (void) offline; // not used yet ostringstream help_message_oss; diff --git a/tests/convert_to_binary_edgelist.cpp b/tests/convert_to_binary_edgelist.cpp new file mode 100644 index 0000000..8efed33 --- /dev/null +++ b/tests/convert_to_binary_edgelist.cpp @@ -0,0 +1,191 @@ +/* + * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cxxopts.hpp" + +#include "../webgraph/webgraph.hpp" + +int main(int argc, char **argv) +{ + using namespace std; + using namespace webgraph::bv_graph; + + cxxopts::Options options("convert_to_binary_edgelist", "Convert webgraph format to binary edgelist format"); + + options.add_options() + ("h,help", "Show help message") + ("input", "Input webgraph file path", cxxopts::value()) + ("output", "Output binary edgelist file path", cxxopts::value()) + ("do_not_remap", "Disable node ID remapping (even if .nodes file exists)", cxxopts::value()->implicit_value("true")->default_value("false")) + ("short", "Use 32-bit vertex IDs instead of 64-bit", cxxopts::value()->implicit_value("true")->default_value("false")) + ; + + options.parse_positional({"input", "output"}); + options.positional_help(" "); + + auto result = options.parse(argc, argv); + + if (result.count("help")) { + cout << options.help() << endl; + return 0; + } + + if (!result.count("input") || !result.count("output")) { + cerr << "Error: Input and output file paths are required" << endl; + cout << options.help() << endl; + return 1; + } + + string input_name = result["input"].as(); + string output_name = result["output"].as(); + bool use_short = result["short"].as(); + + if (use_short) { + cerr << "Using 32-bit vertex ID format" << endl; + } else { + cerr << "Using 64-bit vertex ID format" << endl; + } + + // 检查是否存在.nodes文件,如果存在则自动启用重映射 + string nodes_file = input_name + ".nodes"; + bool do_not_remap = result["do_not_remap"].as(); + bool remap_nodes = false; + + ifstream nodes_check(nodes_file); + if (nodes_check.good()) { + nodes_check.close(); + if (do_not_remap) { + cerr << "Detected " << nodes_file << " file, but node remapping is disabled" << endl; + remap_nodes = false; + } else { + cerr << "Detected " << nodes_file << " file, enabling node remapping" << endl; + remap_nodes = true; + } + } else { + cerr << "No " << nodes_file << " file detected, node remapping disabled" << endl; + remap_nodes = false; + } + + // 读取节点映射文件 + vector node_mapping; + if (remap_nodes) { + ifstream nodes_in(nodes_file); + if (!nodes_in.is_open()) { + cerr << "Error: Cannot open node mapping file " << nodes_file << endl; + return 1; + } + + string line; + while (getline(nodes_in, line)) { + if (!line.empty()) { + node_mapping.push_back(stoull(line)); + } + } + nodes_in.close(); + cerr << "Loaded " << node_mapping.size() << " node mappings" << endl; + } + + typedef boost::shared_ptr graph_ptr; + + graph_ptr gp = graph::load_sequential(input_name); + + // cerr << "about to try to get node iterator.\n"; + + graph::node_iterator n, n_end; + + tie(n, n_end) = gp->get_node_iterator(0); + + cerr << "num vertices:\n"; + cerr << gp->get_num_nodes() << endl; + + ofstream fout(output_name, ios::binary); + if(!fout.is_open()) { + cout << "Open output file failed." << endl; + exit(1); + } + + + size_t node_count = 0; + size_t edge_count = 0; + size_t total_node = gp->get_num_nodes(); + + while (n != n_end) + { + webgraph::bv_graph::graph::successor_iterator succ, succ_end; + + // cerr << "outdegree : " << outdegree(n) << endl; + tie(succ, succ_end) = successors(n); + + while (succ != succ_end) + { + // cerr << edge_count << "th" << endl; + uint64_t src = *n; + uint64_t dest = *succ; + + // 应用节点映射 + if (remap_nodes) { + if (src < node_mapping.size()) { + src = node_mapping[src]; + } + if (dest < node_mapping.size()) { + dest = node_mapping[dest]; + } + } + + if (use_short) { + uint32_t src32 = static_cast(src); + uint32_t dest32 = static_cast(dest); + fout.write((char *)&src32, sizeof(uint32_t)); + fout.write((char *)&dest32, sizeof(uint32_t)); + } else { + fout.write((char *)&src, sizeof(uint64_t)); + fout.write((char *)&dest, sizeof(uint64_t)); + } + + // cerr << src << " " << dest << endl; + + ++succ; + ++edge_count; + } + + // cerr << "before ++n" << endl; + + ++n; + ++node_count; + + if(node_count % 100000 == 0) + { + cerr << "progress: " << node_count << "/" << total_node << endl; + cerr << "edge count: " << edge_count << endl; + } + } + + cerr << "node count: " << node_count << endl; + cerr << "edge count: " << edge_count << endl; + + return 0; +} diff --git a/tests/convert_to_text.cpp b/tests/convert_to_text.cpp new file mode 100644 index 0000000..98a230d --- /dev/null +++ b/tests/convert_to_text.cpp @@ -0,0 +1,100 @@ +/* + * Portions copyright (c) 2003-2007, Paolo Boldi and Sebastiano Vigna. Translation copyright (c) 2007, Jacob Ratkiewicz + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../webgraph/webgraph.hpp" + +int main(int argc, char **argv) +{ + using namespace std; + using namespace webgraph::bv_graph; + + if (argc < 3) + { + cerr << "convert_to_text [webgraph_path] [output_file_path]" << endl; + return 1; + } + + string input_name = argv[1]; + string output_name = argv[2]; + + + typedef boost::shared_ptr graph_ptr; + + graph_ptr gp = graph::load_sequential(input_name); + + // cerr << "about to try to get node iterator.\n"; + + graph::node_iterator n, n_end; + + tie(n, n_end) = gp->get_node_iterator(0); + + cerr << "num vertices:\n"; + cerr << gp->get_num_nodes() << endl; + + ofstream fout(output_name); + + size_t node_count = 0; + size_t edge_count = 0; + size_t total_node = gp->get_num_nodes(); + + while (n != n_end) + { + webgraph::bv_graph::graph::successor_iterator succ, succ_end; + + // cerr << "outdegree : " << outdegree(n) << endl; + tie(succ, succ_end) = successors(n); + + while (succ != succ_end) + { + // cerr << edge_count << "th" << endl; + uint64_t src = *n; + uint64_t dest = *succ; + fout << src << " " << dest << endl; + + // cerr << src << " " << dest << endl; + + ++succ; + ++edge_count; + } + + // cerr << "before ++n" << endl; + + ++n; + ++node_count; + + if(node_count % 100000 == 0) + { + cerr << "progress: " << node_count << "/" << total_node << endl; + cerr << "edge count: " << edge_count << endl; + } + } + + cerr << "node count: " << node_count << endl; + cerr << "edge count: " << edge_count << endl; + + return 0; +} diff --git a/tests/cxxopts.hpp b/tests/cxxopts.hpp new file mode 100644 index 0000000..32c8f2c --- /dev/null +++ b/tests/cxxopts.hpp @@ -0,0 +1,2930 @@ +/* + +Copyright (c) 2014-2022 Jarryd Beck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// vim: ts=2:sw=2:expandtab + +#ifndef CXXOPTS_HPP_INCLUDED +#define CXXOPTS_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CXXOPTS_NO_EXCEPTIONS +#include +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# if (__GNUC__ * 10 + __GNUC_MINOR__) < 49 +# define CXXOPTS_NO_REGEX true +# endif +#endif +#if defined(_MSC_VER) && !defined(__clang__) +#define CXXOPTS_LINKONCE_CONST __declspec(selectany) extern +#define CXXOPTS_LINKONCE __declspec(selectany) extern +#else +#define CXXOPTS_LINKONCE_CONST +#define CXXOPTS_LINKONCE +#endif + +#ifndef CXXOPTS_NO_REGEX +# include +#endif // CXXOPTS_NO_REGEX + +// Nonstandard before C++17, which is coincidentally what we also need for +#ifdef __has_include +# if __has_include() +# include +# ifdef __cpp_lib_optional +# define CXXOPTS_HAS_OPTIONAL +# endif +# endif +# if __has_include() +# include +# ifdef __cpp_lib_filesystem +# define CXXOPTS_HAS_FILESYSTEM +# endif +# endif +#endif + +#define CXXOPTS_FALLTHROUGH +#ifdef __has_cpp_attribute + #if __has_cpp_attribute(fallthrough) + #undef CXXOPTS_FALLTHROUGH + #define CXXOPTS_FALLTHROUGH [[fallthrough]] + #endif +#endif + +#if __cplusplus >= 201603L +#define CXXOPTS_NODISCARD [[nodiscard]] +#else +#define CXXOPTS_NODISCARD +#endif + +#ifndef CXXOPTS_VECTOR_DELIMITER +#define CXXOPTS_VECTOR_DELIMITER ',' +#endif + +#define CXXOPTS__VERSION_MAJOR 3 +#define CXXOPTS__VERSION_MINOR 3 +#define CXXOPTS__VERSION_PATCH 1 + +#if (__GNUC__ < 10 || (__GNUC__ == 10 && __GNUC_MINOR__ < 1)) && __GNUC__ >= 6 + #define CXXOPTS_NULL_DEREF_IGNORE +#endif + +#if defined(__GNUC__) +#define DO_PRAGMA(x) _Pragma(#x) +#define CXXOPTS_DIAGNOSTIC_PUSH DO_PRAGMA(GCC diagnostic push) +#define CXXOPTS_DIAGNOSTIC_POP DO_PRAGMA(GCC diagnostic pop) +#define CXXOPTS_IGNORE_WARNING(x) DO_PRAGMA(GCC diagnostic ignored x) +#else +// define other compilers here if needed +#define CXXOPTS_DIAGNOSTIC_PUSH +#define CXXOPTS_DIAGNOSTIC_POP +#define CXXOPTS_IGNORE_WARNING(x) +#endif + +#ifdef CXXOPTS_NO_RTTI +#define CXXOPTS_RTTI_CAST static_cast +#else +#define CXXOPTS_RTTI_CAST dynamic_cast +#endif + +namespace cxxopts { +static constexpr struct { + uint8_t major, minor, patch; +} version = { + CXXOPTS__VERSION_MAJOR, + CXXOPTS__VERSION_MINOR, + CXXOPTS__VERSION_PATCH +}; +} // namespace cxxopts + +//when we ask cxxopts to use Unicode, help strings are processed using ICU, +//which results in the correct lengths being computed for strings when they +//are formatted for the help output +//it is necessary to make sure that can be found by the +//compiler, and that icu-uc is linked in to the binary. + +#ifdef CXXOPTS_USE_UNICODE +#include + +namespace cxxopts { + +using String = icu::UnicodeString; + +inline +String +toLocalString(std::string s) +{ + return icu::UnicodeString::fromUTF8(std::move(s)); +} + +// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: +// warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor +CXXOPTS_DIAGNOSTIC_PUSH +CXXOPTS_IGNORE_WARNING("-Wnon-virtual-dtor") +// This will be ignored under other compilers like LLVM clang. +class UnicodeStringIterator +{ + public: + + using iterator_category = std::forward_iterator_tag; + using value_type = int32_t; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) + : s(string) + , i(pos) + { + } + + value_type + operator*() const + { + return s->char32At(i); + } + + bool + operator==(const UnicodeStringIterator& rhs) const + { + return s == rhs.s && i == rhs.i; + } + + bool + operator!=(const UnicodeStringIterator& rhs) const + { + return !(*this == rhs); + } + + UnicodeStringIterator& + operator++() + { + ++i; + return *this; + } + + UnicodeStringIterator + operator+(int32_t v) + { + return UnicodeStringIterator(s, i + v); + } + + private: + const icu::UnicodeString* s; + int32_t i; +}; +CXXOPTS_DIAGNOSTIC_POP + +inline +String& +stringAppend(String&s, String a) +{ + return s.append(std::move(a)); +} + +inline +String& +stringAppend(String& s, std::size_t n, UChar32 c) +{ + for (std::size_t i = 0; i != n; ++i) + { + s.append(c); + } + + return s; +} + +template +String& +stringAppend(String& s, Iterator begin, Iterator end) +{ + while (begin != end) + { + s.append(*begin); + ++begin; + } + + return s; +} + +inline +size_t +stringLength(const String& s) +{ + return static_cast(s.length()); +} + +inline +std::string +toUTF8String(const String& s) +{ + std::string result; + s.toUTF8String(result); + + return result; +} + +inline +bool +empty(const String& s) +{ + return s.isEmpty(); +} + +} // namespace cxxopts + +namespace std { + +inline +cxxopts::UnicodeStringIterator +begin(const icu::UnicodeString& s) +{ + return cxxopts::UnicodeStringIterator(&s, 0); +} + +inline +cxxopts::UnicodeStringIterator +end(const icu::UnicodeString& s) +{ + return cxxopts::UnicodeStringIterator(&s, s.length()); +} + +} // namespace std + +//ifdef CXXOPTS_USE_UNICODE +#else + +namespace cxxopts { + +using String = std::string; + +template +T +toLocalString(T&& t) +{ + return std::forward(t); +} + +inline +std::size_t +stringLength(const String& s) +{ + return s.length(); +} + +inline +String& +stringAppend(String&s, const String& a) +{ + return s.append(a); +} + +inline +String& +stringAppend(String& s, std::size_t n, char c) +{ + return s.append(n, c); +} + +template +String& +stringAppend(String& s, Iterator begin, Iterator end) +{ + return s.append(begin, end); +} + +template +std::string +toUTF8String(T&& t) +{ + return std::forward(t); +} + +inline +bool +empty(const std::string& s) +{ + return s.empty(); +} + +} // namespace cxxopts + +//ifdef CXXOPTS_USE_UNICODE +#endif + +namespace cxxopts { + +namespace { +CXXOPTS_LINKONCE_CONST std::string LQUOTE("\'"); +CXXOPTS_LINKONCE_CONST std::string RQUOTE("\'"); +} // namespace + +// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we +// want to silence it: warning: base class 'class +// std::enable_shared_from_this' has accessible non-virtual +// destructor This will be ignored under other compilers like LLVM clang. +CXXOPTS_DIAGNOSTIC_PUSH +CXXOPTS_IGNORE_WARNING("-Wnon-virtual-dtor") + +// some older versions of GCC warn under this warning +CXXOPTS_IGNORE_WARNING("-Weffc++") +class Value : public std::enable_shared_from_this +{ + public: + + virtual ~Value() = default; + + virtual + std::shared_ptr + clone() const = 0; + + virtual void + add(const std::string& text) const = 0; + + virtual void + parse(const std::string& text) const = 0; + + virtual void + parse() const = 0; + + virtual bool + has_default() const = 0; + + virtual bool + is_container() const = 0; + + virtual bool + has_implicit() const = 0; + + virtual std::string + get_default_value() const = 0; + + virtual std::string + get_implicit_value() const = 0; + + virtual std::shared_ptr + default_value(const std::string& value) = 0; + + virtual std::shared_ptr + implicit_value(const std::string& value) = 0; + + virtual std::shared_ptr + no_implicit_value() = 0; + + virtual bool + is_boolean() const = 0; +}; + +CXXOPTS_DIAGNOSTIC_POP + +namespace exceptions { + +class exception : public std::exception +{ + public: + explicit exception(std::string message) + : m_message(std::move(message)) + { + } + + CXXOPTS_NODISCARD + const char* + what() const noexcept override + { + return m_message.c_str(); + } + + private: + std::string m_message; +}; + +class specification : public exception +{ + public: + + explicit specification(const std::string& message) + : exception(message) + { + } +}; + +class parsing : public exception +{ + public: + explicit parsing(const std::string& message) + : exception(message) + { + } +}; + +class option_already_exists : public specification +{ + public: + explicit option_already_exists(const std::string& option) + : specification("Option " + LQUOTE + option + RQUOTE + " already exists") + { + } +}; + +class invalid_option_format : public specification +{ + public: + explicit invalid_option_format(const std::string& format) + : specification("Invalid option format " + LQUOTE + format + RQUOTE) + { + } +}; + +class invalid_option_syntax : public parsing { + public: + explicit invalid_option_syntax(const std::string& text) + : parsing("Argument " + LQUOTE + text + RQUOTE + + " starts with a - but has incorrect syntax") + { + } +}; + +class no_such_option : public parsing +{ + public: + explicit no_such_option(const std::string& option) + : parsing("Option " + LQUOTE + option + RQUOTE + " does not exist") + { + } +}; + +class missing_argument : public parsing +{ + public: + explicit missing_argument(const std::string& option) + : parsing( + "Option " + LQUOTE + option + RQUOTE + " is missing an argument" + ) + { + } +}; + +class option_requires_argument : public parsing +{ + public: + explicit option_requires_argument(const std::string& option) + : parsing( + "Option " + LQUOTE + option + RQUOTE + " requires an argument" + ) + { + } +}; + +class gratuitous_argument_for_option : public parsing +{ + public: + gratuitous_argument_for_option + ( + const std::string& option, + const std::string& arg + ) + : parsing( + "Option " + LQUOTE + option + RQUOTE + + " does not take an argument, but argument " + + LQUOTE + arg + RQUOTE + " given" + ) + { + } +}; + +class requested_option_not_present : public parsing +{ + public: + explicit requested_option_not_present(const std::string& option) + : parsing("Option " + LQUOTE + option + RQUOTE + " not present") + { + } +}; + +class option_has_no_value : public exception +{ + public: + explicit option_has_no_value(const std::string& option) + : exception( + !option.empty() ? + ("Option " + LQUOTE + option + RQUOTE + " has no value") : + "Option has no value") + { + } +}; + +class incorrect_argument_type : public parsing +{ + public: + explicit incorrect_argument_type + ( + const std::string& arg + ) + : parsing( + "Argument " + LQUOTE + arg + RQUOTE + " failed to parse" + ) + { + } +}; + +} // namespace exceptions + + +template +void throw_or_mimic(const std::string& text) +{ + static_assert(std::is_base_of::value, + "throw_or_mimic only works on std::exception and " + "deriving classes"); + +#ifndef CXXOPTS_NO_EXCEPTIONS + // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw + throw T{text}; +#else + // Otherwise manually instantiate the exception, print what() to stderr, + // and exit + T exception{text}; + std::cerr << exception.what() << std::endl; + std::exit(EXIT_FAILURE); +#endif +} + +using OptionNames = std::vector; + +namespace values { + +namespace parser_tool { + +struct IntegerDesc +{ + std::string negative = ""; + std::string base = ""; + std::string value = ""; +}; +struct ArguDesc { + std::string arg_name = ""; + bool grouping = false; + bool set_value = false; + std::string value = ""; +}; + +#ifdef CXXOPTS_NO_REGEX +inline IntegerDesc SplitInteger(const std::string &text) +{ + if (text.empty()) + { + throw_or_mimic(text); + } + IntegerDesc desc; + const char *pdata = text.c_str(); + if (*pdata == '-') + { + pdata += 1; + desc.negative = "-"; + } + if (strncmp(pdata, "0x", 2) == 0) + { + pdata += 2; + desc.base = "0x"; + } + if (*pdata != '\0') + { + desc.value = std::string(pdata); + } + else + { + throw_or_mimic(text); + } + return desc; +} + +inline bool IsTrueText(const std::string &text) +{ + const char *pdata = text.c_str(); + if (*pdata == 't' || *pdata == 'T') + { + pdata += 1; + if (strncmp(pdata, "rue\0", 4) == 0) + { + return true; + } + } + else if (strncmp(pdata, "1\0", 2) == 0) + { + return true; + } + return false; +} + +inline bool IsFalseText(const std::string &text) +{ + const char *pdata = text.c_str(); + if (*pdata == 'f' || *pdata == 'F') + { + pdata += 1; + if (strncmp(pdata, "alse\0", 5) == 0) + { + return true; + } + } + else if (strncmp(pdata, "0\0", 2) == 0) + { + return true; + } + return false; +} + +inline OptionNames split_option_names(const std::string &text) +{ + OptionNames split_names; + + std::string::size_type token_start_pos = 0; + auto length = text.length(); + + if (length == 0) + { + throw_or_mimic(text); + } + + while (token_start_pos < length) { + const auto &npos = std::string::npos; + auto next_non_space_pos = text.find_first_not_of(' ', token_start_pos); + if (next_non_space_pos == npos) { + throw_or_mimic(text); + } + token_start_pos = next_non_space_pos; + auto next_delimiter_pos = text.find(',', token_start_pos); + if (next_delimiter_pos == token_start_pos) { + throw_or_mimic(text); + } + if (next_delimiter_pos == npos) { + next_delimiter_pos = length; + } + auto token_length = next_delimiter_pos - token_start_pos; + // validate the token itself matches the regex /([:alnum:][-_[:alnum:]]*/ + { + const char* option_name_valid_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "_-.?"; + + if (!std::isalnum(text[token_start_pos], std::locale::classic()) || + text.find_first_not_of(option_name_valid_chars, token_start_pos) < next_delimiter_pos) { + throw_or_mimic(text); + } + } + split_names.emplace_back(text.substr(token_start_pos, token_length)); + token_start_pos = next_delimiter_pos + 1; + } + return split_names; +} + +inline ArguDesc ParseArgument(const char *arg, bool &matched) +{ + ArguDesc argu_desc; + const char *pdata = arg; + matched = false; + if (strncmp(pdata, "--", 2) == 0) + { + pdata += 2; + if (isalnum(*pdata, std::locale::classic())) + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + while (isalnum(*pdata, std::locale::classic()) || *pdata == '-' || *pdata == '_') + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + } + if (argu_desc.arg_name.length() > 1) + { + if (*pdata == '=') + { + argu_desc.set_value = true; + pdata += 1; + if (*pdata != '\0') + { + argu_desc.value = std::string(pdata); + } + matched = true; + } + else if (*pdata == '\0') + { + matched = true; + } + } + } + } + else if (strncmp(pdata, "-", 1) == 0) + { + pdata += 1; + argu_desc.grouping = true; + while (isalnum(*pdata, std::locale::classic())) + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + } + matched = !argu_desc.arg_name.empty() && *pdata == '\0'; + } + return argu_desc; +} + +#else // CXXOPTS_NO_REGEX + +namespace { +CXXOPTS_LINKONCE +const char* const integer_pattern = + "(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"; +CXXOPTS_LINKONCE +const char* const truthy_pattern = + "(t|T)(rue)?|1"; +CXXOPTS_LINKONCE +const char* const falsy_pattern = + "(f|F)(alse)?|0"; +CXXOPTS_LINKONCE +const char* const option_pattern = + "--([[:alnum:]][-_[:alnum:]\\.]+)(=(.*))?|-([[:alnum:]].*)"; +CXXOPTS_LINKONCE +const char* const option_specifier_pattern = + "([[:alnum:]][-_[:alnum:]\\.]*)(,[ ]*[[:alnum:]][-_[:alnum:]]*)*"; +CXXOPTS_LINKONCE +const char* const option_specifier_separator_pattern = ", *"; + +} // namespace + +inline IntegerDesc SplitInteger(const std::string &text) +{ + static const std::basic_regex integer_matcher(integer_pattern); + + std::smatch match; + std::regex_match(text, match, integer_matcher); + + if (match.length() == 0) + { + throw_or_mimic(text); + } + + IntegerDesc desc; + desc.negative = match[1]; + desc.base = match[2]; + desc.value = match[3]; + + if (match.length(4) > 0) + { + desc.base = match[5]; + desc.value = "0"; + return desc; + } + + return desc; +} + +inline bool IsTrueText(const std::string &text) +{ + static const std::basic_regex truthy_matcher(truthy_pattern); + std::smatch result; + std::regex_match(text, result, truthy_matcher); + return !result.empty(); +} + +inline bool IsFalseText(const std::string &text) +{ + static const std::basic_regex falsy_matcher(falsy_pattern); + std::smatch result; + std::regex_match(text, result, falsy_matcher); + return !result.empty(); +} + +// Gets the option names specified via a single, comma-separated string, +// and returns the separate, space-discarded, non-empty names +// (without considering which or how many are single-character) +inline OptionNames split_option_names(const std::string &text) +{ + static const std::basic_regex option_specifier_matcher(option_specifier_pattern); + if (!std::regex_match(text.c_str(), option_specifier_matcher)) + { + throw_or_mimic(text); + } + + OptionNames split_names; + + static const std::basic_regex option_specifier_separator_matcher(option_specifier_separator_pattern); + constexpr int use_non_matches { -1 }; + auto token_iterator = std::sregex_token_iterator( + text.begin(), text.end(), option_specifier_separator_matcher, use_non_matches); + std::copy(token_iterator, std::sregex_token_iterator(), std::back_inserter(split_names)); + return split_names; +} + +inline ArguDesc ParseArgument(const char *arg, bool &matched) +{ + static const std::basic_regex option_matcher(option_pattern); + std::match_results result; + std::regex_match(arg, result, option_matcher); + matched = !result.empty(); + + ArguDesc argu_desc; + if (matched) { + argu_desc.arg_name = result[1].str(); + argu_desc.set_value = result[2].length() > 0; + argu_desc.value = result[3].str(); + if (result[4].length() > 0) + { + argu_desc.grouping = true; + argu_desc.arg_name = result[4].str(); + } + } + + return argu_desc; +} + +#endif // CXXOPTS_NO_REGEX +#undef CXXOPTS_NO_REGEX +} // namespace parser_tool + +namespace detail { + +template +struct SignedCheck; + +template +struct SignedCheck +{ + template + void + operator()(bool negative, U u, const std::string& text) + { + if (negative) + { + if (u > static_cast((std::numeric_limits::min)())) + { + throw_or_mimic(text); + } + } + else + { + if (u > static_cast((std::numeric_limits::max)())) + { + throw_or_mimic(text); + } + } + } +}; + +template +struct SignedCheck +{ + template + void + operator()(bool, U, const std::string&) const {} +}; + +template +void +check_signed_range(bool negative, U value, const std::string& text) +{ + SignedCheck::is_signed>()(negative, value, text); +} + +} // namespace detail + +template +void +checked_negate(R& r, T&& t, const std::string&, std::true_type) +{ + // if we got to here, then `t` is a positive number that fits into + // `R`. So to avoid MSVC C4146, we first cast it to `R`. + // See https://github.com/jarro2783/cxxopts/issues/62 for more details. + r = static_cast(-static_cast(t-1)-1); +} + +template +void +checked_negate(R&, T&&, const std::string& text, std::false_type) +{ + throw_or_mimic(text); +} + +template +void +integer_parser(const std::string& text, T& value) +{ + parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text); + + using US = typename std::make_unsigned::type; + constexpr bool is_signed = std::numeric_limits::is_signed; + + const bool negative = int_desc.negative.length() > 0; + const uint8_t base = int_desc.base.length() > 0 ? 16 : 10; + const std::string & value_match = int_desc.value; + + US result = 0; + + for (char ch : value_match) + { + US digit = 0; + + if (ch >= '0' && ch <= '9') + { + digit = static_cast(ch - '0'); + } + else if (base == 16 && ch >= 'a' && ch <= 'f') + { + digit = static_cast(ch - 'a' + 10); + } + else if (base == 16 && ch >= 'A' && ch <= 'F') + { + digit = static_cast(ch - 'A' + 10); + } + else + { + throw_or_mimic(text); + } + + US limit = 0; + if (negative) + { + limit = static_cast(std::abs(static_cast((std::numeric_limits::min)()))); + } + else + { + limit = (std::numeric_limits::max)(); + } + + if (base != 0 && result > limit / base) + { + throw_or_mimic(text); + } + if (result * base > limit - digit) + { + throw_or_mimic(text); + } + + result = static_cast(result * base + digit); + } + + detail::check_signed_range(negative, result, text); + + if (negative) + { + checked_negate(value, result, text, std::integral_constant()); + } + else + { + value = static_cast(result); + } +} + +template +void stringstream_parser(const std::string& text, T& value) +{ + std::stringstream in(text); + in >> value; + if (!in) { + throw_or_mimic(text); + } +} + +template ::value>::type* = nullptr + > +void parse_value(const std::string& text, T& value) +{ + integer_parser(text, value); +} + +inline +void +parse_value(const std::string& text, bool& value) +{ + if (parser_tool::IsTrueText(text)) + { + value = true; + return; + } + + if (parser_tool::IsFalseText(text)) + { + value = false; + return; + } + + throw_or_mimic(text); +} + +inline +void +parse_value(const std::string& text, std::string& value) +{ + value = text; +} + +// The fallback parser. It uses the stringstream parser to parse all types +// that have not been overloaded explicitly. It has to be placed in the +// source code before all other more specialized templates. +template ::value>::type* = nullptr + > +void +parse_value(const std::string& text, T& value) { + stringstream_parser(text, value); +} + +#ifdef CXXOPTS_HAS_OPTIONAL +template +void +parse_value(const std::string& text, std::optional& value) +{ + T result; + parse_value(text, result); + value = std::move(result); +} +#endif + +#ifdef CXXOPTS_HAS_FILESYSTEM +inline +void +parse_value(const std::string& text, std::filesystem::path& value) +{ + value.assign(text); +} +#endif + +inline +void parse_value(const std::string& text, char& c) +{ + if (text.length() != 1) + { + throw_or_mimic(text); + } + + c = text[0]; +} + +template +void +parse_value(const std::string& text, std::vector& value) +{ + if (text.empty()) { + T v; + parse_value(text, v); + value.emplace_back(std::move(v)); + return; + } + std::stringstream in(text); + std::string token; + while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) { + T v; + parse_value(token, v); + value.emplace_back(std::move(v)); + } +} + +template +void +add_value(const std::string& text, T& value) +{ + parse_value(text, value); +} + +template +void +add_value(const std::string& text, std::vector& value) +{ + T v; + add_value(text, v); + value.emplace_back(std::move(v)); +} + +template +struct type_is_container +{ + static constexpr bool value = false; +}; + +template +struct type_is_container> +{ + static constexpr bool value = true; +}; + +template +class abstract_value : public Value +{ + using Self = abstract_value; + + public: + abstract_value() + : m_result(std::make_shared()) + , m_store(m_result.get()) + { + } + + explicit abstract_value(T* t) + : m_store(t) + { + } + + ~abstract_value() override = default; + + abstract_value& operator=(const abstract_value&) = default; + + abstract_value(const abstract_value& rhs) + { + if (rhs.m_result) + { + m_result = std::make_shared(); + m_store = m_result.get(); + } + else + { + m_store = rhs.m_store; + } + + m_default = rhs.m_default; + m_implicit = rhs.m_implicit; + m_default_value = rhs.m_default_value; + m_implicit_value = rhs.m_implicit_value; + } + + void + add(const std::string& text) const override + { + add_value(text, *m_store); + } + + void + parse(const std::string& text) const override + { + parse_value(text, *m_store); + } + + bool + is_container() const override + { + return type_is_container::value; + } + + void + parse() const override + { + parse_value(m_default_value, *m_store); + } + + bool + has_default() const override + { + return m_default; + } + + bool + has_implicit() const override + { + return m_implicit; + } + + std::shared_ptr + default_value(const std::string& value) override + { + m_default = true; + m_default_value = value; + return shared_from_this(); + } + + std::shared_ptr + implicit_value(const std::string& value) override + { + m_implicit = true; + m_implicit_value = value; + return shared_from_this(); + } + + std::shared_ptr + no_implicit_value() override + { + m_implicit = false; + return shared_from_this(); + } + + std::string + get_default_value() const override + { + return m_default_value; + } + + std::string + get_implicit_value() const override + { + return m_implicit_value; + } + + bool + is_boolean() const override + { + return std::is_same::value; + } + + const T& + get() const + { + if (m_store == nullptr) + { + return *m_result; + } + return *m_store; + } + + protected: + std::shared_ptr m_result{}; + T* m_store{}; + + bool m_default = false; + bool m_implicit = false; + + std::string m_default_value{}; + std::string m_implicit_value{}; +}; + +template +class standard_value : public abstract_value +{ + public: + using abstract_value::abstract_value; + + CXXOPTS_NODISCARD + std::shared_ptr + clone() const override + { + return std::make_shared>(*this); + } +}; + +template <> +class standard_value : public abstract_value +{ + public: + ~standard_value() override = default; + + standard_value() + { + set_default_and_implicit(); + } + + explicit standard_value(bool* b) + : abstract_value(b) + { + m_implicit = true; + m_implicit_value = "true"; + } + + std::shared_ptr + clone() const override + { + return std::make_shared>(*this); + } + + private: + + void + set_default_and_implicit() + { + m_default = true; + m_default_value = "false"; + m_implicit = true; + m_implicit_value = "true"; + } +}; + +} // namespace values + +template +std::shared_ptr +value() +{ + return std::make_shared>(); +} + +template +std::shared_ptr +value(T& t) +{ + return std::make_shared>(&t); +} + +class OptionAdder; + +CXXOPTS_NODISCARD +inline +const std::string& +first_or_empty(const OptionNames& long_names) +{ + static const std::string empty{""}; + return long_names.empty() ? empty : long_names.front(); +} + +class OptionDetails +{ + public: + OptionDetails + ( + std::string short_, + OptionNames long_, + String desc, + std::shared_ptr val + ) + : m_short(std::move(short_)) + , m_long(std::move(long_)) + , m_desc(std::move(desc)) + , m_value(std::move(val)) + , m_count(0) + { + m_hash = std::hash{}(first_long_name() + m_short); + } + + OptionDetails(const OptionDetails& rhs) + : m_desc(rhs.m_desc) + , m_value(rhs.m_value->clone()) + , m_count(rhs.m_count) + { + } + + OptionDetails(OptionDetails&& rhs) = default; + + CXXOPTS_NODISCARD + const String& + description() const + { + return m_desc; + } + + CXXOPTS_NODISCARD + const Value& + value() const { + return *m_value; + } + + CXXOPTS_NODISCARD + std::shared_ptr + make_storage() const + { + return m_value->clone(); + } + + CXXOPTS_NODISCARD + const std::string& + short_name() const + { + return m_short; + } + + CXXOPTS_NODISCARD + const std::string& + first_long_name() const + { + return first_or_empty(m_long); + } + + CXXOPTS_NODISCARD + const std::string& + essential_name() const + { + return m_long.empty() ? m_short : m_long.front(); + } + + CXXOPTS_NODISCARD + const OptionNames & + long_names() const + { + return m_long; + } + + std::size_t + hash() const + { + return m_hash; + } + + private: + std::string m_short{}; + OptionNames m_long{}; + String m_desc{}; + std::shared_ptr m_value{}; + int m_count; + + std::size_t m_hash{}; +}; + +struct HelpOptionDetails +{ + std::string s; + OptionNames l; + String desc; + bool has_default; + std::string default_value; + bool has_implicit; + std::string implicit_value; + std::string arg_help; + bool is_container; + bool is_boolean; +}; + +struct HelpGroupDetails +{ + std::string name{}; + std::string description{}; + std::vector options{}; +}; + +class OptionValue +{ + public: + void + add + ( + const std::shared_ptr& details, + const std::string& text + ) + { + ensure_value(details); + ++m_count; + m_value->add(text); + m_long_names = &details->long_names(); + } + + void + parse + ( + const std::shared_ptr& details, + const std::string& text + ) + { + ensure_value(details); + ++m_count; + m_value->parse(text); + m_long_names = &details->long_names(); + } + + void + parse_default(const std::shared_ptr& details) + { + ensure_value(details); + m_default = true; + m_long_names = &details->long_names(); + m_value->parse(); + } + + void + parse_no_value(const std::shared_ptr& details) + { + m_long_names = &details->long_names(); + } + +#if defined(CXXOPTS_NULL_DEREF_IGNORE) +CXXOPTS_DIAGNOSTIC_PUSH +CXXOPTS_IGNORE_WARNING("-Wnull-dereference") +#endif + + CXXOPTS_NODISCARD + std::size_t + count() const noexcept + { + return m_count; + } + +#if defined(CXXOPTS_NULL_DEREF_IGNORE) +CXXOPTS_DIAGNOSTIC_POP +#endif + + // TODO: maybe default options should count towards the number of arguments + CXXOPTS_NODISCARD + bool + has_default() const noexcept + { + return m_default; + } + + template + const T& + as() const + { + if (m_value == nullptr) { + throw_or_mimic( + m_long_names == nullptr ? "" : first_or_empty(*m_long_names)); + } + + return CXXOPTS_RTTI_CAST&>(*m_value).get(); + } + +#ifdef CXXOPTS_HAS_OPTIONAL + template + std::optional + as_optional() const + { + if (m_value == nullptr) { + return std::nullopt; + } + return as(); + } +#endif + + private: + void + ensure_value(const std::shared_ptr& details) + { + if (m_value == nullptr) + { + m_value = details->make_storage(); + } + } + + + const OptionNames * m_long_names = nullptr; + // Holding this pointer is safe, since OptionValue's only exist in key-value pairs, + // where the key has the string we point to. + std::shared_ptr m_value{}; + std::size_t m_count = 0; + bool m_default = false; +}; + +class KeyValue +{ + public: + KeyValue(std::string key_, std::string value_) noexcept + : m_key(std::move(key_)) + , m_value(std::move(value_)) + { + } + + CXXOPTS_NODISCARD + const std::string& + key() const + { + return m_key; + } + + CXXOPTS_NODISCARD + const std::string& + value() const + { + return m_value; + } + + template + T + as() const + { + T result; + values::parse_value(m_value, result); + return result; + } + + private: + std::string m_key; + std::string m_value; +}; + +using ParsedHashMap = std::unordered_map; +using NameHashMap = std::unordered_map; + +class ParseResult +{ + public: + class Iterator + { + public: + using iterator_category = std::forward_iterator_tag; + using value_type = KeyValue; + using difference_type = void; + using pointer = const KeyValue*; + using reference = const KeyValue&; + + Iterator() = default; + Iterator(const Iterator&) = default; + +// GCC complains about m_iter not being initialised in the member +// initializer list +CXXOPTS_DIAGNOSTIC_PUSH +CXXOPTS_IGNORE_WARNING("-Weffc++") + Iterator(const ParseResult *pr, bool end=false) + : m_pr(pr) + { + if (end) + { + m_sequential = false; + m_iter = m_pr->m_defaults.end(); + } + else + { + m_sequential = true; + m_iter = m_pr->m_sequential.begin(); + + if (m_iter == m_pr->m_sequential.end()) + { + m_sequential = false; + m_iter = m_pr->m_defaults.begin(); + } + } + } +CXXOPTS_DIAGNOSTIC_POP + + Iterator& operator++() + { + ++m_iter; + if(m_sequential && m_iter == m_pr->m_sequential.end()) + { + m_sequential = false; + m_iter = m_pr->m_defaults.begin(); + return *this; + } + return *this; + } + + Iterator operator++(int) + { + Iterator retval = *this; + ++(*this); + return retval; + } + + bool operator==(const Iterator& other) const + { + return (m_sequential == other.m_sequential) && (m_iter == other.m_iter); + } + + bool operator!=(const Iterator& other) const + { + return !(*this == other); + } + + const KeyValue& operator*() + { + return *m_iter; + } + + const KeyValue* operator->() + { + return m_iter.operator->(); + } + + private: + const ParseResult* m_pr; + std::vector::const_iterator m_iter; + bool m_sequential = true; + }; + + ParseResult() = default; + ParseResult(const ParseResult&) = default; + + ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector sequential, + std::vector default_opts, std::vector&& unmatched_args) + : m_keys(std::move(keys)) + , m_values(std::move(values)) + , m_sequential(std::move(sequential)) + , m_defaults(std::move(default_opts)) + , m_unmatched(std::move(unmatched_args)) + { + } + + ParseResult& operator=(ParseResult&&) = default; + ParseResult& operator=(const ParseResult&) = default; + + Iterator + begin() const + { + return Iterator(this); + } + + Iterator + end() const + { + return Iterator(this, true); + } + + std::size_t + count(const std::string& o) const + { + auto iter = m_keys.find(o); + if (iter == m_keys.end()) + { + return 0; + } + + auto viter = m_values.find(iter->second); + + if (viter == m_values.end()) + { + return 0; + } + + return viter->second.count(); + } + + bool + contains(const std::string& o) const + { + return static_cast(count(o)); + } + + const OptionValue& + operator[](const std::string& option) const + { + auto iter = m_keys.find(option); + + if (iter == m_keys.end()) + { + throw_or_mimic(option); + } + + auto viter = m_values.find(iter->second); + + if (viter == m_values.end()) + { + throw_or_mimic(option); + } + + return viter->second; + } + +#ifdef CXXOPTS_HAS_OPTIONAL + template + std::optional + as_optional(const std::string& option) const + { + auto iter = m_keys.find(option); + if (iter != m_keys.end()) + { + auto viter = m_values.find(iter->second); + if (viter != m_values.end()) + { + return viter->second.as_optional(); + } + } + return std::nullopt; + } +#endif + + const std::vector& + arguments() const + { + return m_sequential; + } + + const std::vector& + unmatched() const + { + return m_unmatched; + } + + const std::vector& + defaults() const + { + return m_defaults; + } + + const std::string + arguments_string() const + { + std::string result; + for(const auto& kv: m_sequential) + { + result += kv.key() + " = " + kv.value() + "\n"; + } + for(const auto& kv: m_defaults) + { + result += kv.key() + " = " + kv.value() + " " + "(default)" + "\n"; + } + return result; + } + + private: + NameHashMap m_keys{}; + ParsedHashMap m_values{}; + std::vector m_sequential{}; + std::vector m_defaults{}; + std::vector m_unmatched{}; +}; + +struct Option +{ + Option + ( + std::string opts, + std::string desc, + std::shared_ptr value = ::cxxopts::value(), + std::string arg_help = "" + ) + : opts_(std::move(opts)) + , desc_(std::move(desc)) + , value_(std::move(value)) + , arg_help_(std::move(arg_help)) + { + } + + std::string opts_; + std::string desc_; + std::shared_ptr value_; + std::string arg_help_; +}; + +using OptionMap = std::unordered_map>; +using PositionalList = std::vector; +using PositionalListIterator = PositionalList::const_iterator; + +class OptionParser +{ + public: + OptionParser(const OptionMap& options, const PositionalList& positional, bool allow_unrecognised) + : m_options(options) + , m_positional(positional) + , m_allow_unrecognised(allow_unrecognised) + { + } + + ParseResult + parse(int argc, const char* const* argv); + + bool + consume_positional(const std::string& a, PositionalListIterator& next); + + void + checked_parse_arg + ( + int argc, + const char* const* argv, + int& current, + const std::shared_ptr& value, + const std::string& name + ); + + void + add_to_option(const std::shared_ptr& value, const std::string& arg); + + void + parse_option + ( + const std::shared_ptr& value, + const std::string& name, + const std::string& arg = "" + ); + + void + parse_default(const std::shared_ptr& details); + + void + parse_no_value(const std::shared_ptr& details); + + private: + + void finalise_aliases(); + + const OptionMap& m_options; + const PositionalList& m_positional; + + std::vector m_sequential{}; + std::vector m_defaults{}; + bool m_allow_unrecognised; + + ParsedHashMap m_parsed{}; + NameHashMap m_keys{}; +}; + +class Options +{ + public: + + explicit Options(std::string program_name, std::string help_string = "") + : m_program(std::move(program_name)) + , m_help_string(toLocalString(std::move(help_string))) + , m_custom_help("[OPTION...]") + , m_positional_help("positional parameters") + , m_show_positional(false) + , m_allow_unrecognised(false) + , m_width(76) + , m_tab_expansion(false) + , m_options(std::make_shared()) + { + } + + Options& + positional_help(std::string help_text) + { + m_positional_help = std::move(help_text); + return *this; + } + + Options& + custom_help(std::string help_text) + { + m_custom_help = std::move(help_text); + return *this; + } + + Options& + show_positional_help() + { + m_show_positional = true; + return *this; + } + + Options& + allow_unrecognised_options() + { + m_allow_unrecognised = true; + return *this; + } + + Options& + set_width(std::size_t width) + { + m_width = width; + return *this; + } + + Options& + set_tab_expansion(bool expansion=true) + { + m_tab_expansion = expansion; + return *this; + } + + ParseResult + parse(int argc, const char* const* argv); + + OptionAdder + add_options(std::string group = ""); + + void + add_options + ( + const std::string& group, + std::initializer_list