diff options
Diffstat (limited to 'src/utility')
-rw-r--r-- | src/utility/binary.cc | 157 | ||||
-rw-r--r-- | src/utility/binary.h | 269 | ||||
-rw-r--r-- | src/utility/pushvar.h | 214 | ||||
-rw-r--r-- | src/utility/utils.h | 546 |
4 files changed, 1186 insertions, 0 deletions
diff --git a/src/utility/binary.cc b/src/utility/binary.cc new file mode 100644 index 00000000..5802c3bd --- /dev/null +++ b/src/utility/binary.cc @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2003-2007, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "utils.h" + +namespace ledger { +namespace binary { + +void read_bool(std::istream& in, bool& num) +{ + read_guard(in, 0x2005); + unsigned char val; + in.read((char *)&val, sizeof(val)); + num = val == 1; + read_guard(in, 0x2006); +} + +void read_bool(const char *& data, bool& num) +{ + read_guard(data, 0x2005); + unsigned char val = *((unsigned char *) data); + data += sizeof(unsigned char); + num = val == 1; + read_guard(data, 0x2006); +} + +void read_string(std::istream& in, string& str) +{ + read_guard(in, 0x3001); + + unsigned char len; + read_number_nocheck(in, len); + if (len == 0xff) { + unsigned short slen; + read_number_nocheck(in, slen); + char * buf = new char[slen + 1]; + in.read(buf, slen); + buf[slen] = '\0'; + str = buf; + checked_array_delete(buf); + } + else if (len) { + char buf[256]; + in.read(buf, len); + buf[len] = '\0'; + str = buf; + } else { + str = ""; + } + + read_guard(in, 0x3002); +} + +void read_string(const char *& data, string& str) +{ + read_guard(data, 0x3001); + + unsigned char len; + read_number_nocheck(data, len); + if (len == 0xff) { + unsigned short slen; + read_number_nocheck(data, slen); + str = string(data, slen); + data += slen; + } + else if (len) { + str = string(data, len); + data += len; + } + else { + str = ""; + } + + read_guard(data, 0x3002); +} + +void read_string(const char *& data, string * str) +{ + read_guard(data, 0x3001); + + unsigned char len; + read_number_nocheck(data, len); + if (len == 0xff) { + unsigned short slen; + read_number_nocheck(data, slen); + new(str) string(data, slen); + data += slen; + } + else if (len) { + new(str) string(data, len); + data += len; + } + else { + new(str) string(""); + } + + read_guard(data, 0x3002); +} + + +void write_bool(std::ostream& out, bool num) +{ + write_guard(out, 0x2005); + unsigned char val = num ? 1 : 0; + out.write((char *)&val, sizeof(val)); + write_guard(out, 0x2006); +} + +void write_string(std::ostream& out, const string& str) +{ + write_guard(out, 0x3001); + + unsigned long len = str.length(); + if (len > 255) { + assert(len < 65536); + write_number_nocheck<unsigned char>(out, 0xff); + write_number_nocheck<unsigned short>(out, len); + } else { + write_number_nocheck<unsigned char>(out, len); + } + + if (len) + out.write(str.c_str(), len); + + write_guard(out, 0x3002); +} + +} // namespace binary +} // namespace ledger diff --git a/src/utility/binary.h b/src/utility/binary.h new file mode 100644 index 00000000..74199c89 --- /dev/null +++ b/src/utility/binary.h @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2003-2007, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BINARY_H +#define BINARY_H + +namespace ledger { +namespace binary { + +template <typename T> +inline void read_number_nocheck(std::istream& in, T& num) { + in.read((char *)&num, sizeof(num)); +} + +template <typename T> +inline void read_number_nocheck(const char *& data, T& num) { + num = *((T *) data); + data += sizeof(T); +} + +template <typename T> +inline T read_number_nocheck(std::istream& in) { + T num; + read_number_nocheck(in, num); + return num; +} + +template <typename T> +inline T read_number_nocheck(const char *& data) { + T num; + read_number_nocheck(data, num); + return num; +} + +#if DEBUG_LEVEL >= ALPHA +#define read_guard(in, id) \ + if (read_number_nocheck<unsigned short>(in) != id) \ + assert(false); +#else +#define read_guard(in, id) +#endif + +template <typename T> +inline void read_number(std::istream& in, T& num) { + read_guard(in, 0x2003); + in.read((char *)&num, sizeof(num)); + read_guard(in, 0x2004); +} + +template <typename T> +inline void read_number(const char *& data, T& num) { + read_guard(data, 0x2003); + num = *((T *) data); + data += sizeof(T); + read_guard(data, 0x2004); +} + +template <typename T> +inline T read_number(std::istream& in) { + T num; + read_number(in, num); + return num; +} + +template <typename T> +inline T read_number(const char *& data) { + T num; + read_number(data, num); + return num; +} + +void read_bool(std::istream& in, bool& num); +void read_bool(const char *& data, bool& num); + +inline bool read_bool(std::istream& in) { + bool num; + read_bool(in, num); + return num; +} + +inline bool read_bool(const char *& data) { + bool num; + read_bool(data, num); + return num; +} + +template <typename T> +void read_long(std::istream& in, T& num) +{ + read_guard(in, 0x2001); + + unsigned char len; + read_number_nocheck(in, len); + + num = 0; + unsigned char temp; + if (len > 3) { + read_number_nocheck(in, temp); + num |= ((unsigned long)temp) << 24; + } + if (len > 2) { + read_number_nocheck(in, temp); + num |= ((unsigned long)temp) << 16; + } + if (len > 1) { + read_number_nocheck(in, temp); + num |= ((unsigned long)temp) << 8; + } + + read_number_nocheck(in, temp); + num |= ((unsigned long)temp); + + read_guard(in, 0x2002); +} + +template <typename T> +void read_long(const char *& data, T& num) +{ + read_guard(data, 0x2001); + + unsigned char len; + read_number_nocheck(data, len); + + num = 0; + unsigned char temp; + if (len > 3) { + read_number_nocheck(data, temp); + num |= ((unsigned long)temp) << 24; + } + if (len > 2) { + read_number_nocheck(data, temp); + num |= ((unsigned long)temp) << 16; + } + if (len > 1) { + read_number_nocheck(data, temp); + num |= ((unsigned long)temp) << 8; + } + + read_number_nocheck(data, temp); + num |= ((unsigned long)temp); + + read_guard(data, 0x2002); +} + +template <typename T> +inline T read_long(std::istream& in) { + T num; + read_long(in, num); + return num; +} + +template <typename T> +inline T read_long(const char *& data) { + T num; + read_long(data, num); + return num; +} + +void read_string(std::istream& in, string& str); +void read_string(const char *& data, string& str); +void read_string(const char *& data, string * str); + +inline string read_string(std::istream& in) { + string temp; + read_string(in, temp); + return temp; +} + +inline string read_string(const char *& data) { + string temp; + read_string(data, temp); + return temp; +} + + +template <typename T> +inline void write_number_nocheck(std::ostream& out, T num) { + out.write((char *)&num, sizeof(num)); +} + +#if DEBUG_LEVEL >= ALPHA +#define write_guard(out, id) \ + write_number_nocheck<unsigned short>(out, id) +#else +#define write_guard(in, id) +#endif + +template <typename T> +inline void write_number(std::ostream& out, T num) { + write_guard(out, 0x2003); + out.write((char *)&num, sizeof(num)); + write_guard(out, 0x2004); +} + +void write_bool(std::ostream& out, bool num); + +template <typename T> +void write_long(std::ostream& out, T num) +{ + write_guard(out, 0x2001); + + unsigned char len = 4; + if (((unsigned long)num) < 0x00000100UL) + len = 1; + else if (((unsigned long)num) < 0x00010000UL) + len = 2; + else if (((unsigned long)num) < 0x01000000UL) + len = 3; + write_number_nocheck<unsigned char>(out, len); + + unsigned char temp; + if (len > 3) { + temp = (((unsigned long)num) & 0xFF000000UL) >> 24; + write_number_nocheck(out, temp); + } + if (len > 2) { + temp = (((unsigned long)num) & 0x00FF0000UL) >> 16; + write_number_nocheck(out, temp); + } + if (len > 1) { + temp = (((unsigned long)num) & 0x0000FF00UL) >> 8; + write_number_nocheck(out, temp); + } + + temp = (((unsigned long)num) & 0x000000FFUL); + write_number_nocheck(out, temp); + + write_guard(out, 0x2002); +} + +void write_string(std::ostream& out, const string& str); + +template <typename T> +inline void write_object(std::ostream& out, const T& journal) { + assert(false); +} + +} // namespace binary +} // namespace ledger + +#endif // BINARY_H diff --git a/src/utility/pushvar.h b/src/utility/pushvar.h new file mode 100644 index 00000000..793c0ca6 --- /dev/null +++ b/src/utility/pushvar.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2003-2007, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file scopevar.h + * @author John Wiegley + * @date Sun May 6 20:10:52 2007 + * + * @brief Adds a facility to C++ for handling "scoped executions". + * + * There are sometimes cases where you would like to guarantee that + * something happens at the end of a scope, such as calling a function + * to close a resource for you. + * + * The common idiom for this has become to write a helper class whose + * destructor will call that function. Of course, it must then be + * passed information from the calling scope to hold onto as state + * information, since the code within the class itself has no access + * to its points of use. + * + * This type of solution is cumbersome enough that it's sometimes + * avoided. Take calling pthread_mutex_unlock(pthread_mutex_t *) for + * example. A typical snippet of safe C++ code might look like this: + * + * @code + * void foo(pthread_mutex_t * mutex) { + * if (pthread_mutex_lock(mutex) == 0) { + * try { + * // Do work that requires the mutex to be locked; then... + * pthread_mutex_unlock(mutex); + * } + * catch (std::logic_error& exc) { + * // This is an exception we actually handle, and then exit + * pthread_mutex_unlock(mutex); + * } + * catch (...) { + * // These are exceptions we do not handle, but still the + * // mutex must be unlocked + * pthread_mutex_unlock(mutex); + * throw; + * } + * } + * } + * @endcode + * + * The alternative to this, as mentioned above, is to create a helper + * class named pthread_scoped_lock, which might look like this: + * + * @code + * class pthread_scoped_lock : public boost::noncopyable { + * pthread_mutex_t * mutex; + * public: + * explicit pthread_scoped_lock(pthread_mutex_t * locked_mutex) + * : mutex(locked_mutex) {} + * ~pthread_scoped_lock() { + * pthread_mutex_unlock(mutex); + * } + * }; + * @endcode + * + * Although this helper class is just as much work as writing the code + * above, it only needs to be written once. Now the access code can + * look like this: + * + * @code + * void foo(pthread_mutex_t * mutex) { + * if (pthread_mutex_lock(mutex) == 0) { + * pthread_scoped_lock(mutex); + * try { + * // Do work that requires the mutex to be locked + * } + * catch (std::logic_error& exc) { + * // This is an exception we actually handle, and then exit + * } + * } + * } + * @endcode + * + * But what if it could be even easier? That is what this file is + * for, to provide a scopevar<> class which guarantees execution + * of arbtirary code after a scope has terminated, without having to + * resort to custom utility classes. It relies on boost::bind to + * declare pending function calls. Here it what the above would look + * like: + * + * @code + * void foo(pthread_mutex_t * mutex) { + * if (pthread_mutex_lock(mutex) == 0) { + * scopevar<void> unlock_mutex + * (boost::bind(pthread_mutex_unlock, mutex)); + * try { + * // Do work that requires the mutex to be locked + * } + * catch (std::logic_error& exc) { + * // This is an exception we actually handle, and then exit + * } + * } + * } + * @endcode + * + * The advantage here is that no helper class ever needs to created, + * and hence no bugs from such helper classes can creep into the code. + * The single call to boost::bind creates a closure binding that will + * be invoked once the containing scope has terminated. + * + * Another kind of scopevar is useful for setting the values of + * variables to a predetermined value upon completion of a scope. + * Consider this example: + * + * @code + * bool foo_was_run; + * + * void foo() { + * scopevar<bool&> set_success((_1 = true), foo_was_run); + * // do some code, and make sure foo_was_run is set to true + * // once the scope is exited -- however this happens. + * } + * @endcode + * + * In this case, the Boost.Lambda library is used to create an + * anonymous functor whose job is to set the global variable + * `foo_was_run' to a predetermined value. + * + * Lastly, there is another helper class, `scoped_variable' whose job + * is solely to return variables to the value they had at the moment + * the scoped_variable class was instantiated. For example, let's say + * you have a `bar' variable that you want to work on, but you want to + * guarantee that its value is restored upon exiting the scope. This + * can be useful in recursion, for "pushing" and "popping" variable + * values during execution, for example: + * + * @code + * std::string bar = "Hello"; + * void foo() { + * scoped_variable<std::string> restore_bar(bar); + * bar = "Goodbye"; + * // do work with the changed bar; it gets restored upon exit + * } + * @endcode + * + * As a shortcut, you can specify the new value for the pushed + * variable as a second constructor argument: + * + * @code + * std::string bar = "Hello"; + * void foo() { + * scoped_variable<std::string> restore_bar(bar, "Goodbye"); + * // do work with the changed bar; it gets restored upon exit + * } + * @endcode + * + * Finally, you can stop a scopevar or scoped_variable from + * invoking its completion code by calling the `clear' method on the + * object instance. Once `clear' is called, the scoped execution + * becomes inert and will do nothing when the enclosing scope is + * exited. + */ + +#ifndef _SCOPEVAR_H +#define _SCOPEVAR_H + +template <typename T> +class push_variable : public boost::noncopyable +{ + T& var; + T prev; + bool enabled; + +public: + explicit push_variable(T& _var) + : var(_var), prev(var), enabled(true) {} + explicit push_variable(T& _var, const T& value) + : var(_var), prev(var), enabled(true) { + var = value; + } + ~push_variable() { + if (enabled) + var = prev; + } + + void clear() { + enabled = false; + } +}; + +#endif // _SCOPEVAR_H diff --git a/src/utility/utils.h b/src/utility/utils.h new file mode 100644 index 00000000..9ddedb0e --- /dev/null +++ b/src/utility/utils.h @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2003-2007, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file utils.h + * @author John Wiegley + * @date Sun May 6 21:20:00 2007 + * + * @brief This file contains general utility facilities used by Ledger. + * + * Ledger has need of the following utility code, which this file + * provides or includes in: + * + * - system headers + * - asserts + * - verification (basically, "heavy asserts") + * - tracing code + * - debug logging code + * - timing code + * - current error context + * - exception framework + * - date/time type + * - supports_flags<> for objects that use flags + * - push_variable<> for restoring variable values + */ + +#ifndef _UTILS_H +#define _UTILS_H + +#if defined(DEBUG_MODE) +#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE 1 +#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING 1 +#endif + +#include <system.hh> + +/********************************************************************** + * + * Default values + */ + +#if defined(DEBUG_MODE) +#define VERIFY_ON 1 +#define TRACING_ON 1 +#define DEBUG_ON 1 +#define TIMERS_ON 1 +#elif defined(NDEBUG) +#define NO_ASSERTS 1 +#define NO_LOGGING 1 +#else +#define VERIFY_ON 1 // compiled in, use --verify to enable +#define TRACING_ON 1 // use --trace X to enable +#define TIMERS_ON 1 +#endif + +/********************************************************************** + * + * Forward declarations + */ + +namespace ledger { + using namespace boost; + +#if defined(VERIFY_ON) + class string; +#else + typedef std::string string; +#endif + + typedef posix_time::ptime ptime; + typedef ptime::time_duration_type time_duration; + typedef gregorian::date date; + typedef gregorian::date_duration date_duration; + typedef posix_time::seconds seconds; + + typedef boost::filesystem::path path; + typedef boost::filesystem::ifstream ifstream; + typedef boost::filesystem::ofstream ofstream; + typedef boost::filesystem::filesystem_error filesystem_error; +} + +/********************************************************************** + * + * Assertions + */ + +#ifdef assert +#undef assert +#endif + +#if ! defined(NO_ASSERTS) +#define ASSERTS_ON 1 +#endif +#if defined(ASSERTS_ON) + +namespace ledger { + void debug_assert(const string& reason, const string& func, + const string& file, unsigned long line); +} + +#define assert(x) \ + ((x) ? ((void)0) : debug_assert(#x, BOOST_CURRENT_FUNCTION, \ + __FILE__, __LINE__)) + +#else // ! ASSERTS_ON + +#define assert(x) + +#endif // ASSERTS_ON + +/********************************************************************** + * + * Verification (basically, very slow asserts) + */ + +#if defined(VERIFY_ON) + +namespace ledger { + +extern bool verify_enabled; + +#define VERIFY(x) (ledger::verify_enabled ? assert(x) : ((void)0)) +#define DO_VERIFY() ledger::verify_enabled + +void initialize_memory_tracing(); +void shutdown_memory_tracing(); + +std::size_t current_memory_size(); +std::size_t current_objects_size(); + +void trace_ctor_func(void * ptr, const char * cls_name, const char * args, + std::size_t cls_size); +void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size); + +#define TRACE_CTOR(cls, args) \ + (DO_VERIFY() ? trace_ctor_func(this, #cls, args, sizeof(cls)) : ((void)0)) +#define TRACE_DTOR(cls) \ + (DO_VERIFY() ? trace_dtor_func(this, #cls, sizeof(cls)) : ((void)0)) + +void report_memory(std::ostream& out, bool report_all = false); + +/** + * This string type is a wrapper around std::string that allows us to + * trace constructor and destructor calls. + */ +class string : public std::string +{ +public: + string(); + string(const string& str); + string(const std::string& str); + string(const int len, char x); + string(const char * str); + string(const char * str, const char * end); + string(const string& str, int x); + string(const string& str, int x, int y); + string(const char * str, int x); + string(const char * str, int x, int y); + ~string(); +}; + +inline string operator+(const string& __lhs, const string& __rhs) +{ + string __str(__lhs); + __str.append(__rhs); + return __str; +} + +string operator+(const char* __lhs, const string& __rhs); +string operator+(char __lhs, const string& __rhs); + +inline string operator+(const string& __lhs, const char* __rhs) +{ + string __str(__lhs); + __str.append(__rhs); + return __str; +} + +inline string operator+(const string& __lhs, char __rhs) +{ + typedef string __string_type; + typedef string::size_type __size_type; + __string_type __str(__lhs); + __str.append(__size_type(1), __rhs); + return __str; +} + +inline bool operator==(const string& __lhs, const string& __rhs) +{ return __lhs.compare(__rhs) == 0; } + +inline bool operator==(const char* __lhs, const string& __rhs) +{ return __rhs.compare(__lhs) == 0; } + +inline bool operator==(const string& __lhs, const char* __rhs) +{ return __lhs.compare(__rhs) == 0; } + +inline bool operator!=(const string& __lhs, const string& __rhs) +{ return __rhs.compare(__lhs) != 0; } + +inline bool operator!=(const char* __lhs, const string& __rhs) +{ return __rhs.compare(__lhs) != 0; } + +inline bool operator!=(const string& __lhs, const char* __rhs) +{ return __lhs.compare(__rhs) != 0; } + +} // namespace ledger + +#else // ! VERIFY_ON + +#define VERIFY(x) +#define DO_VERIFY() true +#define TRACE_CTOR(cls, args) +#define TRACE_DTOR(cls) + +#endif // VERIFY_ON + +#define IF_VERIFY() if (DO_VERIFY()) + +/********************************************************************** + * + * Logging + */ + +#if ! defined(NO_LOGGING) +#define LOGGING_ON 1 +#endif +#if defined(LOGGING_ON) + +namespace ledger { + +enum log_level_t { + LOG_OFF = 0, + LOG_CRIT, + LOG_FATAL, + LOG_ASSERT, + LOG_ERROR, + LOG_VERIFY, + LOG_WARN, + LOG_INFO, + LOG_EXCEPT, + LOG_DEBUG, + LOG_TRACE, + LOG_ALL +}; + +extern log_level_t _log_level; +extern std::ostream * _log_stream; +extern std::ostringstream _log_buffer; + +bool logger_func(log_level_t level); + +#define LOGGER(cat) \ + static const char * const _this_category = cat + +#if defined(TRACING_ON) + +extern unsigned int _trace_level; + +#define SHOW_TRACE(lvl) \ + (ledger::_log_level >= ledger::LOG_TRACE && lvl <= ledger::_trace_level) +#define TRACE(lvl, msg) \ + (SHOW_TRACE(lvl) ? \ + ((ledger::_log_buffer << msg), \ + ledger::logger_func(ledger::LOG_TRACE)) : false) + +#else // TRACING_ON + +#define SHOW_TRACE(lvl) false +#define TRACE(lvl, msg) + +#endif // TRACING_ON + +#if defined(DEBUG_ON) + +extern optional<std::string> _log_category; + +inline bool category_matches(const char * cat) { + return _log_category && starts_with(cat, *_log_category); +} + +#define SHOW_DEBUG(cat) \ + (ledger::_log_level >= ledger::LOG_DEBUG && ledger::category_matches(cat)) +#define SHOW_DEBUG_() SHOW_DEBUG(_this_category) + +#define DEBUG(cat, msg) \ + (SHOW_DEBUG(cat) ? \ + ((ledger::_log_buffer << msg), \ + ledger::logger_func(ledger::LOG_DEBUG)) : false) +#define DEBUG_(msg) DEBUG(_this_category, msg) + +#else // DEBUG_ON + +#define SHOW_DEBUG(cat) false +#define SHOW_DEBUG_() false +#define DEBUG(cat, msg) +#define DEBUG_(msg) + +#endif // DEBUG_ON + +#define LOG_MACRO(level, msg) \ + (ledger::_log_level >= level ? \ + ((ledger::_log_buffer << msg), ledger::logger_func(level)) : false) + +#define SHOW_INFO() (ledger::_log_level >= ledger::LOG_INFO) +#define SHOW_WARN() (ledger::_log_level >= ledger::LOG_WARN) +#define SHOW_ERROR() (ledger::_log_level >= ledger::LOG_ERROR) +#define SHOW_FATAL() (ledger::_log_level >= ledger::LOG_FATAL) +#define SHOW_CRITICAL() (ledger::_log_level >= ledger::LOG_CRIT) + +#define INFO(msg) LOG_MACRO(ledger::LOG_INFO, msg) +#define WARN(msg) LOG_MACRO(ledger::LOG_WARN, msg) +#define ERROR(msg) LOG_MACRO(ledger::LOG_ERROR, msg) +#define FATAL(msg) LOG_MACRO(ledger::LOG_FATAL, msg) +#define CRITICAL(msg) LOG_MACRO(ledger::LOG_CRIT, msg) +#define EXCEPTION(msg) LOG_MACRO(ledger::LOG_EXCEPT, msg) + +} // namespace ledger + +#else // ! LOGGING_ON + +#define LOGGER(cat) + +#define SHOW_TRACE(lvl) false +#define SHOW_DEBUG(cat) false +#define SHOW_DEBUG_() false +#define SHOW_INFO() false +#define SHOW_WARN() false +#define SHOW_ERROR() false +#define SHOW_FATAL() false +#define SHOW_CRITICAL() false + +#define TRACE(lvl, msg) +#define DEBUG(cat, msg) +#define DEBUG_(msg) +#define INFO(msg) +#define WARN(msg) +#define ERROR(msg) +#define FATAL(msg) +#define CRITICAL(msg) + +#endif // LOGGING_ON + +#define IF_TRACE(lvl) if (SHOW_TRACE(lvl)) +#define IF_DEBUG(cat) if (SHOW_DEBUG(cat)) +#define IF_DEBUG_() if (SHOW_DEBUG_()) +#define IF_INFO() if (SHOW_INFO()) +#define IF_WARN() if (SHOW_WARN()) +#define IF_ERROR() if (SHOW_ERROR()) +#define IF_FATAL() if (SHOW_FATAL()) +#define IF_CRITICAL() if (SHOW_CRITICAL()) + +/********************************************************************** + * + * Timers (allows log entries to specify cumulative time spent) + */ + +#if defined(LOGGING_ON) && defined(TIMERS_ON) + +namespace ledger { + +void start_timer(const char * name, log_level_t lvl); +void stop_timer(const char * name); +void finish_timer(const char * name); + +#if defined(TRACING_ON) +#define TRACE_START(name, lvl, msg) \ + (SHOW_TRACE(lvl) ? \ + ((ledger::_log_buffer << msg), \ + ledger::start_timer(#name, ledger::LOG_TRACE)) : ((void)0)) +#define TRACE_STOP(name, lvl) \ + (SHOW_TRACE(lvl) ? ledger::stop_timer(#name) : ((void)0)) +#define TRACE_FINISH(name, lvl) \ + (SHOW_TRACE(lvl) ? ledger::finish_timer(#name) : ((void)0)) +#else +#define TRACE_START(name, lvl, msg) +#define TRACE_STOP(name) +#define TRACE_FINISH(name) +#endif + +#if defined(DEBUG_ON) +#define DEBUG_START(name, cat, msg) \ + (SHOW_DEBUG(cat) ? \ + ((ledger::_log_buffer << msg), \ + ledger::start_timer(#name, ledger::LOG_DEBUG)) : ((void)0)) +#define DEBUG_START_(name, msg) \ + DEBUG_START_(name, _this_category, msg) +#define DEBUG_STOP(name, cat) \ + (SHOW_DEBUG(cat) ? ledger::stop_timer(#name) : ((void)0)) +#define DEBUG_STOP_(name) \ + DEBUG_STOP_(name, _this_category) +#define DEBUG_FINISH(name, cat) \ + (SHOW_DEBUG(cat) ? ledger::finish_timer(#name) : ((void)0)) +#define DEBUG_FINISH_(name) \ + DEBUG_FINISH_(name, _this_category) +#else +#define DEBUG_START(name, cat, msg) +#define DEBUG_START_(name, msg) +#define DEBUG_STOP(name) +#define DEBUG_FINISH(name) +#endif + +#define INFO_START(name, msg) \ + (SHOW_INFO() ? \ + ((ledger::_log_buffer << msg), \ + ledger::start_timer(#name, ledger::LOG_INFO)) : ((void)0)) +#define INFO_STOP(name) \ + (SHOW_INFO() ? stop_timer(#name) : ((void)0)) +#define INFO_FINISH(name) \ + (SHOW_INFO() ? finish_timer(#name) : ((void)0)) + +} // namespace ledger + +#else // ! (LOGGING_ON && TIMERS_ON) + +#define TRACE_START(lvl, msg, name) +#define TRACE_STOP(name) +#define TRACE_FINISH(name) + +#define DEBUG_START(name, msg) +#define DEBUG_START_(name, cat, msg) +#define DEBUG_STOP(name) +#define DEBUG_FINISH(name) + +#define INFO_START(name, msg) +#define INFO_STOP(name) +#define INFO_FINISH(name) + +#endif // TIMERS_ON + +/********************************************************************** + * + * Exception handling + */ + +#include "context.h" + +namespace ledger { + +#define DECLARE_EXCEPTION(name) \ + class name : public std::logic_error { \ + public: \ + name(const string& why) throw() : std::logic_error(why) {} \ + } + +extern std::ostringstream _exc_buffer; + +template <typename T> +inline void throw_func(const std::string& message) { + _exc_buffer.str(""); + throw T(message); +} + +#define throw_(cls, msg) \ + ((_exc_buffer << msg), throw_func<cls>(_exc_buffer.str())) + +#if 0 +inline void throw_unexpected_error(char c, char wanted) { + if (c == -1) { + if (wanted) + throw new error(string("Missing '") + wanted + "'"); + else + throw new error("Unexpected end of input"); + } else { + if (wanted) + throw new error(string("Invalid char '") + c + + "' (wanted '" + wanted + "')"); + else + throw new error(string("Invalid char '") + c + "'"); + } +} +#else +inline void throw_unexpected_error(char, char) { +} +#endif + +} // namespace ledger + +/********************************************************************** + * + * Date/time support classes + * General support for objects with "flags" + * Support for object serialization (binary read/write) + * Support for scoped execution and variable restoration + */ + +#include "times.h" +#include "flags.h" +#include "binary.h" +#include "pushvar.h" + +/********************************************************************** + * + * General utility functions + */ + +#define foreach BOOST_FOREACH + +namespace ledger { + +template <typename T, typename U> +inline T& downcast(U& object) { + return *polymorphic_downcast<T *>(&object); +} + +path resolve_path(const path& pathname); + +#ifdef HAVE_REALPATH +extern "C" char * realpath(const char *, char resolved_path[]); +#endif + +inline const string& either_or(const string& first, + const string& second) { + return first.empty() ? second : first; +} + +} // namespace ledger + +#endif // _UTILS_H |