Update of /cvsroot/libfunutil/libfunutil/lib/toolbox/src In directory sc8-pr-cvs1:/tmp/cvs-serv26351 Added Files: any.h argv_parser.h bzstream.h children_holder.h class_name.h debuggering_macros.h eprintf.h file_util.h gzstream.h key_value_parser.h pointer_list.h property_store.h stdstring_tokenizer.h string_tokenizer.h string_util.h to_string.h type_traits.h argv_parser.cpp bzstream.cpp file_util.cpp gzstream.cpp key_value_parser.cpp property_store.cpp stdstring_tokenizer.cpp string_tokenizer.cpp string_util.cpp to_string.cpp Log Message: egg --- NEW FILE: any.h --- #ifndef TOOLBOX_ANY_H_INCLUDED #define TOOLBOX_ANY_H_INCLUDED 1 // License: Public Domain // Author: st...@wa... #include <string> #include <iostream> #include "to_string.h" // to/from_string namespace TOOLBOX_NAMESPACE { /** * Completely untested. * A generic 'any' type inspired by, but not based on, * boost::any. It is used to store arbitrary values which can * be "cast" (so to speak, though no casting is used) to * arbitrary types. It supports any types which are * i/ostreamable. * See the namespace-scope <code>make_any()</code> function for a conventient way * to create populated any's. * Sample usage: * <pre> * #include <any.h> * using TOOLBOX_NAMESPACE; * void any_test() * { * any a = "12.12"; * #define TESTANY(vaL,typE,defaulT) a = make_any( vaL ); std::cout << "any("<<a<<").get<"<<#typE<<">(err=["<<defaulT<<"]) = " << a.get<typE>(defaulT) << std::endl; * TESTANY(17.17,double,-1.0); * TESTANY(123.90,string,"error"); * TESTANY(123.90,double,-1.0); * TESTANY(123.90,int,-42); * TESTANY("",int,-1); * TESTANY("hi!",int,-1); * TESTANY("17.12732",double,-1.0); * TESTANY("this is a string",std::string,"error"); * TESTANY("this is a string",int,-1); * } * </pre> * will output: * <pre> * any(17.170000).get<double>(err=[-1]) = 17.17 * any(123.900000).get<string>(err=[error]) = 123.900000 * any(123.900000).get<double>(err=[-1]) = 123.9 * any(123.900000).get<int>(err=[-42]) = 123 * any().get<int>(err=[-1]) = -1 * any(hi!).get<int>(err=[-1]) = -1 * any(17.12732).get<double>(err=[-1]) = 17.1273 * any(this is a string).get<std::string>(err=[error]) = this is a string * any(this is a string).get<int>(err=[-1]) = -1 * </pre> */ class any { public: /** Creates an empty any. */ any(){} ~any() {} /** Creates any with a copy of a's value. */ any( const any & a ) : m_val(a.m_val) {} /** Copies value from rhs into this object. */ any & operator = ( const any & rhs ) { this->m_val = rhs.m_val; return *this; } // todo: template < typename ValueType > any(const ValueType & val ) : m_val(TOOLBOX_NAMESPACE::to_string( val )) {} template<typename ValueType> any & operator=(const ValueType & val ) { this->m_val = TOOLBOX_NAMESPACE::to_string( val ); return *this; } /** Returns this object's value, converted to type T, returning default_or_error_val if the value cannot be converted. T must be i/ostreamable. If a valid default_or_error_val is not immediately available, e.g., if any given integer is valid for a call to get<int>(), clients can still check for an error by checking twice against different error values: <pre> any a = make_any( 0 ); if( ( 0 == a.get<int>(0) ) && (-1 == a.get<int>(-1) ) ) error... </pre> This works because if the any can validly be converted to the first default_or_error_val then it <i>cannot</i> also be validly converted to the second default_or_error_val. Thus, if the default_or_error_val is returned on both calls the client knows that the any was not convertable to the templatized type. This property is the main reason that this class uses no exceptions. ***/ template <typename T> T get( const T & default_or_error_val = T() ) const { return TOOLBOX_NAMESPACE::from_string( this->m_val, default_or_error_val ); } /** Sets this object's value to an internal representation of val. T must be i/ostreamable. */ template <typename T> void set( const T & val ) { this->m_val = TOOLBOX_NAMESPACE::to_string( val ); } /** Sends the internal representation of A's value to the given ostream. */ friend std::ostream & operator<<( std::ostream & os, const any & A ); private: std::string m_val; }; /** Sends the internal representation of A to the given ostream. */ std::ostream & operator<<( std::ostream & os, const any & a ) { // declared in TOOLBOX_NAMESPACE::any return os << a.m_val; } /** A non-member convenience function to create an <code>any</code> representing the given value. Similar in usage to <code>std::make_pair()</code>. T must be i/ostreamble. This function should not really be a friend, but it is for documentation reasons. i.e., it's much easier to find this function if it is in the class' documentation. */ template <typename T> static any make_any( const T & value ) { return any( TOOLBOX_NAMESPACE::to_string( value ) ); } } // namespace #endif // TOOLBOX_ANY_H_INCLUDED --- NEW FILE: argv_parser.h --- #ifndef ARGV_PARSER_H #define ARGV_PARSER_H 1 // Author: st...@wa... // License: Public Domain #include "property_store.h" namespace TOOLBOX_NAMESPACE { /** argv_parser is an object for parsing command line options. It exists in the s11n source tree only to ease development of test apps, and should not be considered to be part of the core library. Use it like this: <pre> #include <iostream> #include "argv_parser.h" #define VERBOSE if( opts.get( "verbose", false ) ) cerr int main( int argc, char **argv ) { argv_parser & opts = argv_parser::args( argc, argv ); opts.set( "dosomething", ! opts.get_bool( "donothing", false ) ); if( ! opts.get( "dosomething", true ) ) { exit( 0 )); } int myint = opts.get( "width", 20 ); double myangle = opts.get( "angle", 0.0 ); VERBOSE << "This is a verbose message." << endl; return opts.get( "errorcode", 0 ); } </pre> (that code's just off the top of my head - it may not compile as-is.) Note that client code outside of main can then get access to the args via the static function args(): <pre> argv_parser & opts = argv_parser::args(); </pre> See the property_store object's API for a full list of accessor functions. Supported command-line formats: <pre> -foo bar [that is, -foo == "bar"] is the same as: [--foo bar] [-foo=bar] [--foo=bar] -foo -bar false [-foo == true, -bar == false] -foo -bar=false [same] --double-dashed "some string value" --double-dashed="some string value" [same as previous line] </pre> Whether you use single or double dashes is irrelevant, but you must call get() with the same key as was actually passed on the command-line, like so: int width = opts.getInt( "-width", opts.getInt( "--width", 42 ) ); will check for -width first, then --width, defaulting to 42. Alternately, if you use this form: opts.get_string( "foo" ); // WITHOUT a dash the following options are searched: <ol> <li>foo <li>-foo <li>--foo </ol> so the above call may actually result in getting the value from -foo or --foo. This is a potential logic problem if your application uses two semantically-different, like-named arguments like -force and --force. In this case a call to get( "force" ) would find -force and not --force. Use get( "-force" ) or get("--force") to avoid this ambiguity. The dashed versions of an argument are only sought after if get() is called without a dash before the key. These sample dash-searching rules apply to is_set(). A note to Qt users: call args() on this object before calling QApplication a(argc, argv ), or QApplication will steal any argument called -name (and possibly others), removing it from argv. i.e., if you do not call args() on this object first, QApplication may steal arguments so you'll never see them. Been there, done that. Known Bugs and/or gotchyas: Negative numbers: <pre> --boolflag -123=something </pre> will be parsed as: <pre> [--boolflag == true] [-123=something] </pre> Search the .cpp file for 'negative' and you'll find where this bug lives. Since numeric arguments are so rare this is not such a big deal, i think. i can think of only a few real-world examples which use args like -1: ssh, [GNU] xargs, head, tail, lpr, ... okay, maybe they aren't so uncommon :/ Along those same lines: <pre> --bool -234 --foobar </pre> will be parsed as: <pre> [--bool == -234] [--foobar == true] </pre> Which i consider to be correct for most cases. If you want to set --bool to a negative number use: --bool=-123 If you want to force a boolean value in this case: <pre> --bool=true -234 546 </pre> parses as: <pre> --bool=true -234=456 </pre> i hate the inconsistency this adds, though. :/ */ class argv_parser : public property_store { public: /** Creates a new parser using the given arguments array and arg count. */ argv_parser( int argc, char *argv[], int startAt=0 ); argv_parser(); virtual ~argv_parser(); /** args( int, char * ) should be called once from your main() if you want clients to be able to use args() to get at them. */ static argv_parser & args( int argc, char *argv[] ); /** Returns the object containing the arguments supplied to args(int,char**). */ static argv_parser & args(); /** get/set_help() text for a given key. */ virtual void set_help( const std::string &key, const std::string &text ); /** Returns the help text associated with key. */ virtual const std::string getHelp( const std::string &key ) const; /** Re-implemented to check keys -FOO and --FOO if key FOO is not found. */ virtual bool is_set( const std::string &key ) const; /** get_string() is overridden to add a special case to all get() calls made via the property_store API: if a get() function is called with a key which does not start with a dash (-) character and they key cannot be found in our list then -key and --key will be tried. This means that, assuming the above sample code is in place, the following would work: <pre> ~/ > myapp --foo=17.34 ... double d = opts.getDouble( "foo", 0.0 ); // d == 17.34 </pre> As will this: <pre> opts.set( "--mykey", "myvalue" ); ... cerr << "mykey="<< opts.get_string( "mykey" ) << endl; </pre> Note, however, that command-line arguments passed without a leading dash are not treated as arguments, and will not be inside this object if the command-line arguments are passed in via args(). Additionally, it is important to note that if key is passed in with a leading "-" then the additional "dash checking" is NOT done. That is, if you call: <pre> opts.get_string( "-d", 0.0 ); </pre> then ONLY the entry -d will match, and not --d. */ virtual std::string get_string( const std::string &key, const std::string & defaultVal = std::string() ) const; /** * Makes a half-hearted attempt to parse out any args (begining with "-"). * Any args without values passed after them are assigned the value true. * Sample valid command lines: * <pre> * foo --a --b foo --c bar --f * (--a and --f == true, --b == "foo" and --c == "bar") * foo --a eat --b this --c "you lazy bum" * (--a==eat, --b==this, --c=="you lazy bum") * foo --a=b --c d * (--a == b, --c == d) </pre> * * These are identical for purposes of get( "c" ): <pre> * [... -c=-1.0 ...] [... -c -1.0 ...] [... --c 1.0 ...] [... --c=1.0 ...] </pre> * * * To get the values, call the property_store API functions like: <pre> * int foo = parser.getInt( "--i" ); // getInt("i") now works for -i or --i :) * bool bar = parser.get_bool( "--b" ); // or get_bool( "b") for -b or --b </pre> * 'startat' says which element in argv[] to start with. * * If argpre = 0 then it uses the default argument prefix (defaults to "-"). * If it is >0 then that is used as a char * prefix * for all arguments. * * This function also stores all processed values in a way familiar to bash and perl users: * $0 = the first argument, * $1 = the second arg * etc. * Thus given: <pre> * ./foo --arg1 val1 --arg2=foo </pre> * We have: <pre> * myargs["$1"] == "--arg1" * myargs["$3"] == "--arg2=foo" (it is arguably useful to split these, but then usage would be * inconsistent with bash/perl. However, as it is now it is inconsistent * with the results of "--arg2 foo" :/) </pre> * Note that the values are added to this object (or overwrite existing entries), and the list * is not cleared by this function. */ virtual int args( int argc, char *argv[], int startAt, const char *argpre = "-" ); /** * Similar to parse( int... ) except that this one reads a whole line of options, parses that into * an array, then passes it to parse(...). Note that this _may_ (but should not, ideally) behave slightly * differently from arguments passed to the other form, which typically come in as command-line args * (parsed by your shell). This functions uses a stdstring_tokenizer to do it's parsing, so * any differences in behaviour should be resolved there. i am not aware of any differences. */ virtual int args( std::string args, std::string separators = " " ); /** Creates a "usage"-like string for this object containing all keys for which set_help() has been called. If showcurrentvals is true then the current values are also added to th string, otherwise they are left out. Note that the order of the dumped help text/keys is alphabetic (because that's how the container object stores them). TODO: maintain the order of args, using the order from set_help(). Sample: <pre> in main() do: argv_parser & args = argv_parser::args( argc, argv ); if( args.is_hel_set() ) { // triggers on --help, -help, -? or --? cerr << args.dump_help(); exit( 0 ); // some apps exit with a non-zero for help, some don't. } </pre> */ virtual const std::string dump_help( bool showcurrentvals = true ) const; /** Returns true if -help --help, -? or --? is set. */ virtual bool is_help_set(); private: property_store helpmap; }; }; // namespace TOOLBOX_NAMESPACE #endif // ARGV_PARSER_H --- NEW FILE: bzstream.h --- // ============================================================================ // bzstream, C++ iostream classes wrapping the bz2lib compression library. // Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner // Copyright (C) 2003 stephan beal <st...@s1...> // // This code is basically a copy/paste of gzstream, adapted for libbz2 // by st...@s1... (2 Oct 2003) // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ============================================================================ // // File : bzstream.h // Revision : $Revision: 1.1 $ // Revision_date : $Date: 2003/11/28 00:56:03 $ // Author(s) : Deepak Bandyopadhyay, Lutz Kettner // // Standard streambuf implementation following Nicolai Josuttis, "The // Standard C++ Library". // ============================================================================ // Changes by st...@s1...: // October, 2003: // - added zlevel() to gzstreambase and gzstreambuf. Only works for ostreams. // - replaced gzip code with bzip code. #ifndef BZSTREAM_H_INCLUDED #define BZSTREAM_H_INCLUDED 1 // standard C++ with new header file names and std:: namespace #include <iostream> #include <fstream> #include <bzlib.h> // libbz2 header #ifndef ZSTREAM_NAMESPACE #define ZSTREAM_NAMESPACE TOOLBOX_NAMESPACE #endif #ifdef ZSTREAM_NAMESPACE namespace ZSTREAM_NAMESPACE { #endif // ---------------------------------------------------------------------------- // Internal classes to implement bzstream. See below for user classes. // ---------------------------------------------------------------------------- class bzstreambuf:public std::streambuf { private: static const int bufferSize = 47 + 256; // size of data buff // totals 512 bytes under g++ for ibzstream at the end. BZFILE * file; // file handle for compressed file char buffer[bufferSize]; // data buffer char opened; // open/close state of stream int mode; // I/O mode int flush_buffer( ); public: bzstreambuf( ):opened( 0 ), m_zlevel(-1) { setp( buffer, buffer + ( bufferSize - 1 ) ); setg( buffer + 4, // beginning of putback area buffer + 4, // read position buffer + 4 ); // end position // ASSERT: both input & output capabilities will not be used together } int is_open( ) { return opened; } bzstreambuf *open( const char *name, int open_mode ); bzstreambuf *close( ); ~bzstreambuf( ) { close( ); } virtual int overflow( int c = EOF ); virtual int underflow( ); virtual int sync( ); /** Defines the compression level, 0 - 9. A value of -1 means use the system-wide zlib default (normally 3). */ void zlevel( int z ) { this->m_zlevel = ( z<0 ? -1 : (z>9?9:z) ) ; } /** Returns the compression level for this stream. */ int zlevel() const { return this->m_zlevel; } private: int m_zlevel; }; /** Base stream class inherited by obzstream/igzstream. Any given instance may not be used for both input and output. Uses gzlib compression, and is compatible with files compressed using bzip2, or any number of other tools which support bz2lib. */ class bzstreambase:virtual public std::ios { private: int m_zlevel; protected: bzstreambuf buf; public: bzstreambase( ) { init( &buf ); } bzstreambase( const char *name, int open_mode ); ~bzstreambase( ); void open( const char *name, int open_mode ); void close( ); void zlevel( int z ) { buf.zlevel(z); } int zlevel() const { return buf.zlevel(); } bzstreambuf *rdbuf( ) { return &buf; } }; /** An input stream which decompresses it's input. Used identically to a std::ifstream. <pre> igzstream ifs( "myfile.bz2" ); </pre> */ class ibzstream:public bzstreambase, public std::istream { public: ibzstream( ):std::istream( &buf ) { } ibzstream( const char *name, int open_mode = std::ios::in ):bzstreambase( name, open_mode ), std::istream( &buf ) { } bzstreambuf *rdbuf( ) { return bzstreambase::rdbuf( ); } void open( const char *name, int open_mode = std::ios::in ) { bzstreambase::open( name, open_mode ); } }; /** An output stream which compresses it's output. Used identically to a std::ofstream: <pre> ogzstream of( "myfile.bz2" ); of << "hello, world!" << std::endl; </pre> */ class obzstream:public bzstreambase, public std::ostream { public: obzstream( ):std::ostream( &buf ) { } obzstream( const char *name, int mode = std::ios::out ):bzstreambase( name, mode ), std::ostream( &buf ) { } bzstreambuf *rdbuf( ) { return bzstreambase::rdbuf( ); } void open( const char *name, int open_mode = std::ios::out ) { bzstreambase::open( name, open_mode ); } }; #ifdef ZSTREAM_NAMESPACE } // namespace ZSTREAM_NAMESPACE #endif #endif // BZSTREAM_H_INCLUDED // ============================================================================ // EOF // --- NEW FILE: children_holder.h --- // Author: stephan beal <st...@s1...> // License: Public Domain #ifndef CHILDRENHOLDER_H_INCLUDED #define CHILDRENHOLDER_H_INCLUDED 1 #include <string> #include <list> #include <map> #include <vector> //#include <deque> // causes crashes in some cases where vector does not :/ #ifndef TYPENAME #define TYPENAME typename // gcc 3.x handles typenames "properly" and gcc 2.95.3 does not, so we must do -DTYPENAME= // for gcc 2.95.3. #endif namespace TOOLBOX_NAMESPACE { /** EXPERIMENTAL! children_holder is an experimental object for creating pointer containers for arbitrary child types. The idea is that many objects i create have a heirarchical structure, and i'm looking for a generic way to code this pattern. The interface should allow any given class, including non-modifiable 3rd-party classes, to have any number of child types. This code does no automatic clean-up of children. Client code may free all child pointers by calling cleanup_parent(), and subclasses or proxies of this object should call that in their dtor. */ template < class PType, class CType > class children_holder { public: /** The type of this object's parents in parent-child relationships. */ typedef PType parent_type; /** The type of this object's children in parent-child relationships. */ typedef CType child_type; /** The container type used to store the lists of children. */ typedef std::vector < child_type * >list_type; /** A shortcut typedef to help ease the implementation code for this class. */ typedef children_holder < parent_type, child_type > ThisType; /** iterator which can be dereferenced to a (child_type *). */ typedef typename list_type::iterator iterator; /** iterator which can be dereferenced to a (const child_type *). */ typedef typename list_type::const_iterator const_iterator; /** Returns the child list for the given parent object. If creationPolicy is non-zero then this function will create the child list if it does not yet exist (in that case, this function will never return NULL except on an out-of-memory error). The caller takes ownership of the returned pointer. All children in the list can be deleted at once by calling cleanup_parent( parent ). Different calls to this function will always return the same list (or the same NULL, depending on creationPolicy ;) until either unmap_parent() or cleanup_parent() are called, in which case further calls to this function may return a different pointer the next time it is called. */ static ThisType::list_type * child_list( const ThisType::parent_type * parent, int creationPolicy = 0 ) { if ( !parent ) return NULL; static ThisType::map_type & cmap = parentChildMap(); typename map_type::const_iterator it = cmap.find( parent ); if ( cmap.end() != it ) return ( *it ).second; if ( 0 == creationPolicy ) return NULL; list_type *cl = new list_type(); cmap[parent] = cl; return cl; } /** Removes parent from this object's internal map. This only removes the pointer to the parent's child list and the mapping which binds the parent to the children, but does not delete() anything. Returns true if it unmaps the parent, else false. It will only fail if it doesn't have an entry for parent. This is more of a maintenance detail than anything else. */ static bool unmap_parent( const ThisType::parent_type * parent ) { if ( !parent ) return false; static ThisType::map_type & cmap = parentChildMap(); TYPENAME ThisType::map_type::iterator it = cmap.find( parent ); if ( it == cmap.end() ) return false; cmap.erase( parent ); return true; } /** Simlar as unmap_parent(), but also deletes the children in the list and then deletes the list. Subclasses or proxies of this class should call this function from their dtor, in order to avoid leaving any dangling pointers in this class' internal data. */ static bool cleanup_parent( const ThisType::parent_type * parent ) { if ( !parent ) return false; static ThisType::map_type & cmap = parentChildMap(); TYPENAME ThisType::map_type::iterator it = cmap.find( parent ); if ( it == cmap.end() ) { // we were probably just never registed because children() was never called. return false; } TYPENAME ThisType::list_type * li = ( *it ).second; if ( !unmap_parent( parent ) ) { return false; } TYPENAME ThisType::list_type::iterator vit; TYPENAME ThisType::child_type * child = 0; for ( vit = li->begin(); li->begin() != li->end() ) { child = ( *vit ); li->erase( vit ); delete( child ); child = 0; } delete( li ); return true; } private: typedef std::map < const ThisType::parent_type *, ThisType::list_type * > map_type; /** i hate working with static objects in template classes (for syntax reasons), and parentChildMap() is a helper to avoid that. */ static map_type & parentChildMap() { static map_type meyers; return meyers; } }; }; // namespace TOOLBOX_NAMESPACE #endif // CHILDRENHOLDER_H_INCLUDED --- NEW FILE: class_name.h --- #ifndef CLASS_NAME_H_INCLUDED #define CLASS_NAME_H_INCLUDED 1 #include <cassert> namespace { // ns is not strictly necessary: works in global-scope as well. /** A utility class to provide human-usable class names, available at runtime. It MUST be specialized to work. Call one of these macros: <pre> CLASS_NAME(Type) CLASS_NAME_ALIAS(Type,AliasForType) </pre> from a class' header file (not an impl file, for complex linking reasons). It may only be called one time per Type per compilation unit, or you will get specialization collisions at compile time. Caveats: - template types with commas in the names will break the macro and... - typedef'd names will get their typedef'd name registered, not their real name. Maybe a feature, maybe not. To get proper names for such cases you must hand-specialize this class. See the macros for a sample implementation, or the class_names shell script which should have come with this class. */ template <class T> struct class_name { /** returns the class name for class T. */ static const char * name() { assert( 0 /* this class_name<> is unspecialized! */ ); return "error::class_name<unspecialized>"; } /** returns the class name for class T. */ operator const char * () const { return name(); } }; } // namespace /** Creates a class_name<> specialization for Type, using the class name Alias. */ #define CLASS_NAME_ALIAS(Type,Alias) \ namespace { \ template <> struct class_name< Type > {\ static const char * name() {return # Alias; }\ operator const char * () const { return name(); }\ };} #define CLASS_NAME(Type) CLASS_NAME_ALIAS(Type,Type) #endif // CLASS_NAME_H_INCLUDED --- NEW FILE: debuggering_macros.h --- #ifndef DEBUGGERING_MACROS_H #define DEBUGGERING_MACROS_H 1 // CERR is a drop-in replacement for std::cerr, but slightly more // decorative. #ifndef CERR #define CERR std::cerr << __FILE__ << ":" << std::dec << __LINE__ << " : " #define CERRL(A) CERR << A << std::endl; #endif #ifndef COUT #define COUT std::cout << __FILE__ << ":" << std::dec << __LINE__ << " : " #define COUTL(A) COUT << A << std::endl; #endif #endif // DEBUGGERING_MACROS_H --- NEW FILE: eprintf.h --- #ifndef EPRINTF_H_INCLUDED #define EPRINTF_H_INCLUDED 1 // License: Public Domain // Author: st...@wa... #include <iostream> #include <sstream> namespace TOOLBOX_NAMESPACE { /** The eprintf()-related functions: (Note: these functions have an "e" prefix ONLY because gcc 2.95.x warns about incorrect number of printf args, even when TOOLBOX_NAMESPACE::printf() is specified :/. Since i needed a prefix, and 'elib' was the library this code originated from, 'e' was the choice.) These functions are auto-generated, and they all follow the pattern set here: template <typename T0> static void esprintf( std::ostream & stream, T0 v0 ); template <typename T0> static void eprintf( T0 v0 ); template <typename T0> static std::string efstring( T0 v0 ); The same functions, taking up to 20 template parameters, are included via eprintf_impl.h (which is generated by makeEPrintf). (The exact number of parameters may be different: it's set in the Makefile.) Sample usage: <pre> cout << TOOLBOX_NAMESPACE::efstring("The int is ",42,". The double is ",42.42,".") << endl; TOOLBOX_NAMESPACE::esprintf(std::cout, "The int is ",42,". The double is ",42.42,".\n"); TOOLBOX_NAMESPACE::eprintf("Simply goes to cout.\n"); </pre> (Note the addition of a \n (or endl) to the string when using the stream-accepting variants.) Design note: the auto-generated sprintf() is more code-repetative than necessary, rather than recursive, to keep down the number of template instantiations. Consider: sprintf(cout,1,2,3,4,5,6,7,8,9,10); If that was implemented recursively, we would have 10 template instantiations (one for each number of arguments, not including the stream). The current impl will only generate 1 tmpl instantiation for that call. For maintenance reasons, printf() and fstring() are implemented in terms of sprintf(), so each unique-parm-count call to printf() or fstring() will incur 2 template instantiations: one for the function and one for the sprintf() it uses. They /could/ be implemented exactly like sprintf(), sparing a function call and a template instantiation, and this may change at some point (if i need a performance scapegoat). i tend to make lots of various printf() calls, but don't call them terribly many times, so i'm not too worried about it at this point. Note that these functions provide no additional functionality whatsoever over using standard streams, except /perhaps/ a nicer-looking calling convention. But, to be frank, i was too stoned to realize that until after the code was complete. ;) (Well, i /do/ get some use out of efstring(), anyway.) */ template <typename T0> static void esprintf( std::ostream & stream, const T0 & v0 ) { stream << v0; }; template <typename T0> static void eprintf( const T0 & v0 ) { TOOLBOX_NAMESPACE::esprintf( std::cout, v0 ); }; template <typename T0> static std::string efstring( const T0 & v0 ) { std::ostringstream stream; TOOLBOX_NAMESPACE::esprintf( stream, v0 ); return stream.str(); }; #include "eprintf_impl.h" }; // namespace TOOLBOX_NAMESPACE #endif // EPRINTF_H_INCLUDED --- NEW FILE: file_util.h --- #ifndef TOOLKIT_FILE_UTIL_H_INCLUDED #define TOOLKIT_FILE_UTIL_H_INCLUDED 1 #include <string> namespace TOOLBOX_NAMESPACE { /** CompressionPolicy describes the framework-wide policy regarding compression when writing to files. (Sorry, pure stream-based compression isn't yet supported.) Setting to GZip/BZipCompression only enables compression if HAVE_ZLIB or HAVE_BZLIB ars set during library compilation, otherwise non-compressed streams are used in all cases. bzip compresses much better than gzip, but is notably slower. The speed should not make much of a difference unless you are working with very large data sets, and then you will notice that gzip is faster. Tip: you can use get_istream() on an arbitrary filename to get an appropriate input stream. Likewise, use get_ostream() to open writable a file with the policy-mandated stream type (if possible, defaulting to std::ofstream). */ enum CompressionPolicy { /** NoCompression implies just what it says - do not use compressed output streams. */ NoCompression = 1, /** GZipCompression means to use the TOOLBOX_NAMESPACE::ogzstream class for output streams. */ GZipCompression = 2, /** BZipCompression means to use the TOOLBOX_NAMESPACE::obzstream class for output streams. */ BZipCompression = 3 }; /** Sets the framework-wide CompressionPolicy preference. See the TOOLBOX_NAMESPACE::CompressionPolicy enum. */ void compression_policy( CompressionPolicy c ); /** Returns the framework-wide CompressionPolicy preference. See the TOOLBOX_NAMESPACE::CompressionPolicy enum. */ int compression_policy(); /** Looks at the given file and tries to figure out what type of decompression stream, if any, should be used. It will return one of the following types: - std::ifstream - TOOLBOX_NAMESPACE::gzstream - TOOLBOX_NAMESPACE::bzstream It will return NULL if it cannot open filename, or a std::ifstream if it cannot figure out a decompression scheme. It will only return one of the compressed stream types if this code is built with the appropriate macros: HAVE_ZLIB and HAVE_BZLIB, and then linked against -lgz and/or -lbz2. Thus, if this code is not built with compression support it is possible that it returns a std::ifstream reading from a compressed file. */ std::istream * get_istream( const std::string & filename ); /** Returns one of the following types of ostreams, depending on compression_policy() and compile-time library settings of HAVE_ZLIB and HAVE_BZLIB. - TOOLBOX_NAMESPACE::ogzstream - TOOLBOX_NAMESPACE::obzstream - std::ofstream Note that this function only uses filename to pass to the stream's constructor, and does no checking of the file. The caller is responsible for deleting the pointer. For determining the type of input stream for a file, see TOOLBOX_NAMESPACE::get_istream(). */ std::ostream * get_ostream( const std::string & filename ); /** Returns the first 'bytes' bytes from the given file, assuming the file exists and can be read. It stops at the first newline character unless read_past_nl is true. On error an empty string is returned. This function is primarily intended to be used for looking for magic cookies. It is also sometimes useful, for example, for checking the type of a file or grabbing, e.g., the CVSROOT out of CVS/Root. Results are undefined with binary files. If this library is compiled with HAVE_ZLIB/HAVE_BZLIB set to true then this function supports transparent decompression of gzipped/bzipped files. It caches requests, so subsequent lookups are fast. */ std::string bytes_from_file( const std::string & fn, unsigned int bytes = 128, bool read_past_nl = false ); }; // namespace TOOLBOX_NAMESPACE #endif // TOOLKIT_FILE_UTIL_H_INCLUDED --- NEW FILE: gzstream.h --- // ============================================================================ // gzstream, C++ iostream classes wrapping the zlib compression library. // Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ============================================================================ // // File : gzstream.h // Revision : $Revision: 1.1 $ // Revision_date : $Date: 2003/11/28 00:56:03 $ // Author(s) : Deepak Bandyopadhyay, Lutz Kettner // // Standard streambuf implementation following Nicolai Josuttis, "The // Standard C++ Library". // ============================================================================ // Changes by st...@s1...: // October, 2003: // - added zlevel() to gzstreambase and gzstreambuf. Only works for ostreams. #ifndef GZSTREAM_H_INCLUDED #define GZSTREAM_H_INCLUDED 1 // standard C++ with new header file names and std:: namespace #include <iostream> #include <fstream> #include <zlib.h> #ifndef ZSTREAM_NAMESPACE #define ZSTREAM_NAMESPACE TOOLBOX_NAMESPACE #endif #ifdef ZSTREAM_NAMESPACE namespace ZSTREAM_NAMESPACE { #endif // ---------------------------------------------------------------------------- // Internal classes to implement gzstream. See below for user classes. // ---------------------------------------------------------------------------- class gzstreambuf:public std::streambuf { private: static const int bufferSize = 47 + 256; // size of data buff // totals 512 bytes under g++ for igzstream at the end. gzFile file; // file handle for compressed file char buffer[bufferSize]; // data buffer char opened; // open/close state of stream int mode; // I/O mode int flush_buffer(); public: gzstreambuf():opened( 0 ), m_zlevel(-1) { setp( buffer, buffer + ( bufferSize - 1 ) ); setg( buffer + 4, // beginning of putback area buffer + 4, // read position buffer + 4 ); // end position // ASSERT: both input & output capabilities will not be used together } int is_open() { return opened; } gzstreambuf *open( const char *name, int open_mode ); gzstreambuf *close(); ~gzstreambuf() { close(); } virtual int overflow( int c = EOF ); virtual int underflow(); virtual int sync(); void zlevel( int z ) { this->m_zlevel = ( z<0 ? -1 : (z>9?9:z) ) ; } int zlevel() const { return this->m_zlevel; } private: int m_zlevel; }; /** Base stream class inherited by ogzstream/igzstream. Any given instance may not be used for both input and output. Uses gzlib compression, and is compatible with files compressed using gzip, or any number of other tools which support gzlib. */ class gzstreambase:virtual public std::ios { private: int m_zlevel; protected: gzstreambuf buf; public: gzstreambase() { init( &buf ); } gzstreambase( const char *name, int open_mode ); ~gzstreambase(); void open( const char *name, int open_mode ); void close(); void zlevel( int z ) { buf.zlevel(z); } int zlevel() const { return buf.zlevel(); } gzstreambuf *rdbuf() { return &buf; } }; /** An input stream which decompresses it's input. Used identically to a std::ifstream. <pre> igzstream ifs( "myfile.gz" ); </pre> */ class igzstream:public gzstreambase, public std::istream { public: igzstream():std::istream( &buf ) { } igzstream( const char *name, int open_mode = std::ios::in ):gzstreambase( name, open_mode ), std::istream( &buf ) { } gzstreambuf *rdbuf() { return gzstreambase::rdbuf(); } void open( const char *name, int open_mode = std::ios::in ) { gzstreambase::open( name, open_mode ); } }; /** An output stream which compresses it's output. Used identically to a std::ofstream: <pre> ogzstream of( "myfile.gz" ); of << "hello, world!" << std::endl; </pre> */ class ogzstream:public gzstreambase, public std::ostream { public: ogzstream():std::ostream( &buf ) { } ogzstream( const char *name, int mode = std::ios::out ):gzstreambase( name, mode ), std::ostream( &buf ) { } gzstreambuf *rdbuf() { return gzstreambase::rdbuf(); } void open( const char *name, int open_mode = std::ios::out ) { gzstreambase::open( name, open_mode ); } }; #ifdef ZSTREAM_NAMESPACE } // namespace ZSTREAM_NAMESPACE #endif #endif // GZSTREAM_H_INCLUDED // ============================================================================ // EOF // --- NEW FILE: key_value_parser.h --- // Author: stephan beal <st...@s1...> // License: Public Domain #ifndef SGB_KEYVALUEPARSER_H #define SGB_KEYVALUEPARSER_H #include <string> #include <map> #include <list> namespace TOOLBOX_NAMESPACE { using namespace std; /** key_value_parser is a class for parsing "key=value"-style lines, like those which would come from a configuration file. */ class key_value_parser { public: /** Creates a new key_value_parser and runs parse( line ). */ explicit key_value_parser( const string & line ); /** Creates an empty key_value_parser. */ key_value_parser(); virtual ~key_value_parser(){} /** Parses 'line' into a key/value pair. To be parseable the line must be in the form: key=value Extra whitespace around the '=' removed, as are leading and trailing whitespace around the key and value. This behaviour is arguable but probably desireable in most cases (it is in all of mine, and i wrote the damned thing ;). todo: add a whitespace removal policy as optional 3rd argument? delimiter is the string which separates the key and value, so a line in the format: key{alternateDelimiter}value... (minus the braces) is parseable. alternateDelimiter can be a set of possible delimiters, such as " \t". That is: parse( "one;two",";" ) results in key() == "one" and value() == "two" This function returns false if it does not consider the line to be parseable. Use key() and value() to get the parsed values. Use line() to get the whole string passed to parse (as if you'd ever need it, though subclasses might). line() /is/ guaranteed to be set to line by this call, unlike key() and value(). If this function returns false, the values returned by key() and value() cannot be considered reliable (i.e., they are undefined). This function will return false if a line contains no key (like '=value'), but empty values are not an error (i.e., they will not cause this function to return false). BUG: in some cases (when delimiter is a space) a no-value key can fail to parse. */ bool parse( const string & line, const string & delimiter = "=" ); /** Returns the parsed-out key. Only valid if parse() returned true. */ inline const string & key() const { return this->m_key; } /** Sets this object's key(). */ inline void key( const string & v ) { this->m_key = v; } /** Returns the parsed-out value (may be empty). Only valid if parse() returned true. */ inline const string & value() const { return this->m_val; } /** Sets this object's value(). */ inline void value( const string & v ) { this->m_val = v; } /** Returns the last whole line passed to parse(). */ inline const string & line() const { return this->m_line; } private: string m_key; string m_val; string m_line; string::const_iterator strIt; }; /** enters k.key()=k.value() into os. */ std::ostream & operator <<( std::ostream & os, const key_value_parser & ); }; // namespace TOOLBOX_NAMESPACE #endif // SGB_KEYVALUEPARSER_H --- NEW FILE: pointer_list.h --- // Author: stephan beal <st...@s1...> // License: Public Domain #ifndef POINTERLIST_H_INCLUDED #define POINTERLIST_H_INCLUDED #include <string> #include <list> #include <map> #define POINTERLIST_USES_VECTOR 1 // define to true if you want to use a vector instead of a list (should be a bit faster?) #if POINTERLIST_USES_VECTOR # include <vector> #else # include <list> #endif namespace TOOLBOX_NAMESPACE { using namespace std; /** pointer_list is a simple template class for a container of pointers to T, plus some memory management features. It's usage is STL-like. Parameterized on: - ChildType: the type of object to hold pointers to. pointer_lists with auto_delete(true) often make useful ad-hoc poor-man's garbage collectors. Known caveats: Inserting the same pointer into the same list multiple times is fatal if the list's auto_delete() is enabled. It will crash in the list's dtor when it deletes the pointer twice. Multiple pointers to the same object are allowed because the STL containers allow it, and i want to conform with that basic behaviour. */ template < class ChildType > class pointer_list { public: /** A typedef to make the rest of the implementation easier to write. */ typedef pointer_list < ChildType > ThisType; /** value_type defines the child type of this list. Note that it is a pointer type (because this is a /pointer list/ ;), so don't be confused by constructs like: value_type objptr = 0; (note the distinct lack of a *). This odd definition is required for compatibility with std::vector and std::list. i would prefer to define it without the *. :/ */ typedef ChildType *value_type; /** list_type is the type of underlying pointer container. */ #if POINTERLIST_USES_VECTOR typedef std::vector < value_type > list_type; #else typedef std::list < value_type > list_type; #endif /** iterator which can be dereferenced to a (value_type *). */ typedef typename list_type::iterator iterator; /** const iterator which can be dereferenced to a (value_type *). */ typedef typename list_type::const_iterator const_iterator; /** Creates a pointer_list with the given auto_delete policy. */ pointer_list( bool autodel = false ):m_autodel( autodel ) { } /** Deletes all child pointers if this->auto_delete(). */ virtual ~pointer_list() { if ( this->auto_delete() ) this->delete_all(); } /** If auto_delete() is true then all objects in this list will be deleted when this object dies or when erase() is called. Autodelete is false by default. */ bool auto_delete() const { return this->m_autodel; } /** Sets the autodelete policy. See auto_delete(). */ void auto_delete( bool autodel ) { this->m_autodel = autodel; } /** Return a const iterator for the first element in this container. */ typename ThisType::const_iterator begin() const { return this->list.begin(); } /** Return an iterator pointing to the first element in this container. */ typename ThisType::iterator begin() { return this->list.begin(); } /** Return the after-the-end iterator. */ typename ThisType::const_iterator end() const { return this->list.end(); } /** Return the after-the-end iterator. */ typename ThisType::iterator end() { return this->list.end(); } /** Returns an iterator pointing to the given pointer, or end() if this object does not contain that pointer. */ typename ThisType::iterator find( typename ThisType::value_type a ) { typename ThisType::iterator iter = list.begin(); typename ThisType::iterator enditer = list.end(); for ( ; iter != enditer; ++iter ) { if ( ( *iter ) == a ) { //LIBE_CERR << "find( " << a << " ) found " << (*iter) << endl; return iter; } } return list.end(); } /** Returns the number of child pointers in this list. */ unsigned long count() const { return ( unsigned long ) this->list.size(); // i hope that's implemented constant-time. C++ Standard doesn't define performance on ::std::list::size(). } /** Same as count(). */ unsigned long size() const { return ( unsigned long ) this->list.size(); } /** Adds the given pointer to the list. If front == true then the pointer is added to the front of the list, else the end of the list. If the pointer is NULL then this function does nothing. Returns the pointer passed to it. */ typename ThisType::value_type add( typename ThisType::value_type a, bool front = false ) { if ( !a ) return NULL; if ( !front ) list.push_back( a ); else { #if POINTERLIST_USES_VECTOR list.insert( list.begin(), a ); #else list.push_front( a ); #endif } return a; } /** For STL compatibility. Adds an entry to the back of this list. */ typename ThisType::value_type push_back( typename ThisType::value_type a ) { return this->add( a, false ); } /** For STL compatibility. Adds an entry to the front of this list. */ typename ThisType::value_type push_front( typename ThisType::value_type a ) { return this->add( a, true ); } /** Defines the deletion policies recognized by remove(). */ enum DeletionPolicy { /** Use the policy set in <code>auto_delete()</code>. */ CheckAutoDelete = -1, /** Do not delete object. */ DoNotDelete = 0, /** Delete object. */ Delete = 1 }; /** Removes the given pointer from this list, assuming it contains the pointer. If the pointer is NULL or the list does not contain the entry, it returns NULL, otherwise it returns the pointer passed to it. The passed-in pointer may or may not be deleted, depending on the value of deletionPolicy: - CheckAutoDelete (-1, default) == check auto_delete() and do whatever that says. - DoNotDelete (0) == do not delete - Delete (1) == delete, regardless of auto_delete() Obviously, if this function deletes the pointer then it will return NULL. */ typename ThisType::value_type remove( typename ThisType::value_type a, DeletionPolicy deletionPolicy = CheckAutoDelete ) { // todo: try to replace this stuff with: // std::remove_if( begin(), end(), std::equal_to<value_type>() ); if ( !a ) return NULL; typename ThisType::iterator iter = list.begin(); while ( iter != list.end() ) { if ( ( *iter ) == a ) { list.erase( iter ); if ( deletionPolicy > 0 || ( ( deletionPolicy == -1 ) && this->auto_delete() ) ) { delete( a ); return NULL; } return a; } ++iter; } return NULL; } /** For STL compatibility. if ( this->auto_delete() ) then (*it) is deleted. */ void erase( ThisType::iterator it ) { if ( this->m_autodel ) delete( *it ); this->list.erase( it ); } /** For STL compatibility. if ( this->auto_delete() ) then the pointers in (*it) are deleted. TODO: validate that the iterators are guaranteed to be valid after list_type::erase() is called! */ void erase( ThisType::iterator begin, ThisType::iterator end ) { for( ; begin != end; ++begin ) { if( this->m_autodel ) delete( *begin ); this->list.erase( begin ); } } /** For STL compatibility. Calls erase( begin(), end() ). *... [truncated message content] |