summaryrefslogtreecommitdiff
path: root/src/utility
diff options
context:
space:
mode:
Diffstat (limited to 'src/utility')
-rw-r--r--src/utility/binary.cc157
-rw-r--r--src/utility/binary.h269
-rw-r--r--src/utility/pushvar.h214
-rw-r--r--src/utility/utils.h546
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