diff options
author | John Wiegley <johnw@newartisans.com> | 2008-08-09 19:48:23 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2008-08-09 19:48:23 -0400 |
commit | 6fe833bb9b8486404b34fb8b5e2f730cdfb50a06 (patch) | |
tree | 569eb87ca21a74b756cda1739bce3a45a62722b6 /lib | |
parent | 5419e74378134d34894c8f25d54e8a28482ff5a8 (diff) | |
download | fork-ledger-6fe833bb9b8486404b34fb8b5e2f730cdfb50a06.tar.gz fork-ledger-6fe833bb9b8486404b34fb8b5e2f730cdfb50a06.tar.bz2 fork-ledger-6fe833bb9b8486404b34fb8b5e2f730cdfb50a06.zip |
Moved sources which I did not write from src/ into lib/.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/fdstream.h | 184 | ||||
-rw-r--r-- | lib/tuples.h | 250 |
2 files changed, 434 insertions, 0 deletions
diff --git a/lib/fdstream.h b/lib/fdstream.h new file mode 100644 index 00000000..a74a5781 --- /dev/null +++ b/lib/fdstream.h @@ -0,0 +1,184 @@ +/* The following code declares classes to read from and write to + * file descriptore or file handles. + * + * See + * http://www.josuttis.com/cppcode + * for details and the latest version. + * + * - open: + * - integrating BUFSIZ on some systems? + * - optimized reading of multiple characters + * - stream for reading AND writing + * - i18n + * + * (C) Copyright Nicolai M. Josuttis 2001. + * Permission to copy, use, modify, sell and distribute this software + * is granted provided this copyright notice appears in all copies. + * This software is provided "as is" without express or implied + * warranty, and with no claim as to its suitability for any purpose. + * + * Version: Jul 28, 2002 + * History: + * Jul 28, 2002: bugfix memcpy() => memmove() + * fdinbuf::underflow(): cast for return statements + * Aug 05, 2001: first public version + */ +#ifndef BOOST_FDSTREAM_HPP +#define BOOST_FDSTREAM_HPP + +#include <istream> +#include <ostream> +#include <streambuf> +// for EOF: +#include <cstdio> +// for memmove(): +#include <cstring> + + +// low-level read and write functions +#ifdef _MSC_VER +# include <io.h> +#else +# include <unistd.h> +//extern "C" { +// int write (int fd, const char* buf, int num); +// int read (int fd, char* buf, int num); +//} +#endif + + +// BEGIN namespace BOOST +namespace boost { + + +/************************************************************ + * fdostream + * - a stream that writes on a file descriptor + ************************************************************/ + + +class fdoutbuf : public std::streambuf { + protected: + int fd; // file descriptor + public: + // constructor + fdoutbuf (int _fd) : fd(_fd) { + } + protected: + // write one character + virtual int_type overflow (int_type c) { + if (c != EOF) { + char z = c; + if (write (fd, &z, 1) != 1) { + return EOF; + } + } + return c; + } + // write multiple characters + virtual + std::streamsize xsputn (const char* s, + std::streamsize num) { + return write(fd,s,num); + } +}; + +class fdostream : public std::ostream { + protected: + fdoutbuf buf; + public: + fdostream (int fd) : std::ostream(0), buf(fd) { + rdbuf(&buf); + } +}; + + +/************************************************************ + * fdistream + * - a stream that reads on a file descriptor + ************************************************************/ + +class fdinbuf : public std::streambuf { + protected: + int fd; // file descriptor + protected: + /* data buffer: + * - at most, pbSize characters in putback area plus + * - at most, bufSize characters in ordinary read buffer + */ + static const int pbSize = 4; // size of putback area + static const int bufSize = 1024; // size of the data buffer + char buffer[bufSize+pbSize]; // data buffer + + public: + /* constructor + * - initialize file descriptor + * - initialize empty data buffer + * - no putback area + * => force underflow() + */ + fdinbuf (int _fd) : fd(_fd) { + setg (buffer+pbSize, // beginning of putback area + buffer+pbSize, // read position + buffer+pbSize); // end position + } + + protected: + // insert new characters into the buffer + virtual int_type underflow () { +#ifndef _MSC_VER + using std::memmove; +#endif + + // is read position before end of buffer? + if (gptr() < egptr()) { + return traits_type::to_int_type(*gptr()); + } + + /* process size of putback area + * - use number of characters read + * - but at most size of putback area + */ + int numPutback; + numPutback = gptr() - eback(); + if (numPutback > pbSize) { + numPutback = pbSize; + } + + /* copy up to pbSize characters previously read into + * the putback area + */ + memmove (buffer+(pbSize-numPutback), gptr()-numPutback, + numPutback); + + // read at most bufSize new characters + int num; + num = read (fd, buffer+pbSize, bufSize); + if (num <= 0) { + // ERROR or EOF + return EOF; + } + + // reset buffer pointers + setg (buffer+(pbSize-numPutback), // beginning of putback area + buffer+pbSize, // read position + buffer+pbSize+num); // end of buffer + + // return next character + return traits_type::to_int_type(*gptr()); + } +}; + +class fdistream : public std::istream { + protected: + fdinbuf buf; + public: + fdistream (int fd) : std::istream(0), buf(fd) { + rdbuf(&buf); + } +}; + + +} // END namespace boost + +#endif /*BOOST_FDSTREAM_HPP*/ diff --git a/lib/tuples.h b/lib/tuples.h new file mode 100644 index 00000000..07bcccc9 --- /dev/null +++ b/lib/tuples.h @@ -0,0 +1,250 @@ +// Copyright 2004-2007 Roman Yakovenko. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef TUPLES_HPP_16_JAN_2007 +#define TUPLES_HPP_16_JAN_2007 + +#include "boost/python.hpp" +#include "boost/tuple/tuple.hpp" +#include "boost/python/object.hpp" //len function +#include <boost/mpl/int.hpp> +#include <boost/mpl/next.hpp> + +/** + * Converts boost::tuples::tuple<...> to\from Python tuple + * + * The conversion is done "on-the-fly", you should only register the conversion + * with your tuple classes. + * For example: + * + * typedef boost::tuples::tuple< int, double, std::string > triplet; + * boost::python::register_tuple< triplet >(); + * + * That's all. After this point conversion to\from next types will be handled + * by Boost.Python library: + * + * triplet + * triplet& ( return type only ) + * const triplet + * const triplet& + * + * Implementation description. + * The conversion uses Boost.Python custom r-value converters. r-value converters + * is very powerful and undocumented feature of the library. The only documentation + * we have is http://boost.org/libs/python/doc/v2/faq.html#custom_string . + * + * The conversion consists from two parts: "to" and "from". + * + * "To" conversion + * The "to" part is pretty easy and well documented ( http://docs.python.org/api/api.html ). + * You should use Python C API to create an instance of a class and than you + * initialize the relevant members of the instance. + * + * "From" conversion + * Lets start from analyzing one of the use case Boost.Python library have to + * deal with: + * + * void do_smth( const triplet& arg ){...} + * + * In order to allow calling this function from Python, the library should keep + * parameter "arg" alive until the function returns. In other words, the library + * should provide instances life-time management. The provided interface is not + * ideal and could be improved. You have to implement two functions: + * + * void* convertible( PyObject* obj ) + * Checks whether the "obj" could be converted to an instance of the desired + * class. If true, the function should return "obj", otherwise NULL + * + * void construct( PyObject* obj, converter::rvalue_from_python_stage1_data* data) + * Constructs the instance of the desired class. This function will be called + * if and only if "convertible" function returned true. The first argument + * is Python object, which was passed as parameter to "convertible" function. + * The second object is some kind of memory allocator for one object. Basically + * it keeps a memory chunk. You will use the memory for object allocation. + * + * For some unclear for me reason, the library implements "C style Inheritance" + * ( http://www.embedded.com/97/fe29712.htm ). So, in order to create new + * object in the storage you have to cast to the "right" class: + * + * typedef converter::rvalue_from_python_storage<your_type_t> storage_t; + * storage_t* the_storage = reinterpret_cast<storage_t*>( data ); + * void* memory_chunk = the_storage->storage.bytes; + * + * "memory_chunk" points to the memory, where the instance will be allocated. + * + * In order to create object at specific location, you should use placement new + * operator: + * + * your_type_t* instance = new (memory_chunk) your_type_t(); + * + * Now, you can continue to initialize the instance. + * + * instance->set_xyz = read xyz from obj + * + * If "your_type_t" constructor requires some arguments, "read" the Python + * object before you call the constructor: + * + * xyz_type xyz = read xyz from obj + * your_type_t* instance = new (memory_chunk) your_type_t(xyz); + * + * Hint: + * In most case you don't really need\have to work with C Python API. Let + * Boost.Python library to do some work for you! + * + **/ + +namespace boost{ namespace python{ + +namespace details{ + +//Small helper function, introduced to allow short syntax for index incrementing +template< int index> +typename mpl::next< mpl::int_< index > >::type increment_index(){ + typedef typename mpl::next< mpl::int_< index > >::type next_index_type; + return next_index_type(); +} + +} + +template< class TTuple > +struct to_py_tuple{ + + typedef mpl::int_< tuples::length< TTuple >::value > length_type; + + static PyObject* convert(const TTuple& c_tuple){ + list values; + //add all c_tuple items to "values" list + convert_impl( c_tuple, values, mpl::int_< 0 >(), length_type() ); + //create Python tuple from the list + return incref( python::tuple( values ).ptr() ); + } + +private: + + template< int index, int length > + static void + convert_impl( const TTuple &c_tuple, list& values, mpl::int_< index >, mpl::int_< length > ) { + values.append( c_tuple.template get< index >() ); + convert_impl( c_tuple, values, details::increment_index<index>(), length_type() ); + } + + template< int length > + static void + convert_impl( const TTuple&, list& values, mpl::int_< length >, mpl::int_< length >) + {} + +}; + + +template< class TTuple> +struct from_py_sequence{ + + typedef TTuple tuple_type; + + typedef mpl::int_< tuples::length< TTuple >::value > length_type; + + static void* + convertible(PyObject* py_obj){ + + if( !PySequence_Check( py_obj ) ){ + return 0; + } + + if( !PyObject_HasAttrString( py_obj, "__len__" ) ){ + return 0; + } + + python::object py_sequence( handle<>( borrowed( py_obj ) ) ); + + if( tuples::length< TTuple >::value != len( py_sequence ) ){ + return 0; + } + + if( convertible_impl( py_sequence, mpl::int_< 0 >(), length_type() ) ){ + return py_obj; + } + else{ + return 0; + } + } + + static void + construct( PyObject* py_obj, converter::rvalue_from_python_stage1_data* data){ + typedef converter::rvalue_from_python_storage<TTuple> storage_t; + storage_t* the_storage = reinterpret_cast<storage_t*>( data ); + void* memory_chunk = the_storage->storage.bytes; + TTuple* c_tuple = new (memory_chunk) TTuple(); + data->convertible = memory_chunk; + + python::object py_sequence( handle<>( borrowed( py_obj ) ) ); + construct_impl( py_sequence, *c_tuple, mpl::int_< 0 >(), length_type() ); + } + + static TTuple to_c_tuple( PyObject* py_obj ){ + if( !convertible( py_obj ) ){ + throw std::runtime_error( "Unable to construct boost::tuples::tuple from Python object!" ); + } + TTuple c_tuple; + python::object py_sequence( handle<>( borrowed( py_obj ) ) ); + construct_impl( py_sequence, c_tuple, mpl::int_< 0 >(), length_type() ); + return c_tuple; + } + +private: + + template< int index, int length > + static bool + convertible_impl( const python::object& py_sequence, mpl::int_< index >, mpl::int_< length > ){ + + typedef typename tuples::element< index, TTuple>::type element_type; + + object element = py_sequence[index]; + extract<element_type> type_checker( element ); + if( !type_checker.check() ){ + return false; + } + else{ + return convertible_impl( py_sequence, details::increment_index<index>(), length_type() ); + } + } + + template< int length > + static bool + convertible_impl( const python::object& py_sequence, mpl::int_< length >, mpl::int_< length > ){ + return true; + } + + template< int index, int length > + static void + construct_impl( const python::object& py_sequence, TTuple& c_tuple, mpl::int_< index >, mpl::int_< length > ){ + + typedef typename tuples::element< index, TTuple>::type element_type; + + object element = py_sequence[index]; + c_tuple.template get< index >() = extract<element_type>( element ); + + construct_impl( py_sequence, c_tuple, details::increment_index<index>(), length_type() ); + } + + template< int length > + static void + construct_impl( const python::object& py_sequence, TTuple& c_tuple, mpl::int_< length >, mpl::int_< length > ) + {} + +}; + +template< class TTuple> +void register_tuple(){ + + to_python_converter< TTuple, to_py_tuple<TTuple> >(); + + converter::registry::push_back( &from_py_sequence<TTuple>::convertible + , &from_py_sequence<TTuple>::construct + , type_id<TTuple>() ); +}; + +} } //boost::python + +#endif//TUPLES_HPP_16_JAN_2007 |