gta: update base modules and sync FFmpeg code with Bino.
authorMartin Lambers <marlam@marlam.de>
Fri, 9 Jan 2015 18:45:33 +0000 (19:45 +0100)
committerMartin Lambers <marlam@marlam.de>
Sat, 10 Jan 2015 08:40:13 +0000 (09:40 +0100)
23 files changed:
gtatool/configure.ac
gtatool/src/Makefile.am
gtatool/src/base/dbg.cpp
gtatool/src/base/exc.cpp
gtatool/src/base/fio.cpp
gtatool/src/base/fio.h
gtatool/src/base/opt.cpp
gtatool/src/base/str.cpp
gtatool/src/conv-ffmpeg/base/pth.cpp [new file with mode: 0644]
gtatool/src/conv-ffmpeg/base/pth.h [new file with mode: 0644]
gtatool/src/conv-ffmpeg/base/ser.cpp [new file with mode: 0644]
gtatool/src/conv-ffmpeg/base/ser.h [new file with mode: 0644]
gtatool/src/conv-ffmpeg/media_data.cpp
gtatool/src/conv-ffmpeg/media_data.h
gtatool/src/conv-ffmpeg/media_object.cpp
gtatool/src/conv-ffmpeg/s11n.cpp [deleted file]
gtatool/src/conv-ffmpeg/s11n.h [deleted file]
gtatool/src/conv-ffmpeg/thread.cpp [deleted file]
gtatool/src/conv-ffmpeg/thread.h [deleted file]
gtatool/src/view/base/ser.cpp
gtatool/src/view/base/sys.cpp
gtatool/src/view/base/tmr.cpp
gtatool/src/view/xgl/glvm.hpp

index 8da54b9..dfddf22 100644 (file)
@@ -71,8 +71,8 @@ if test "$w32" = "yes"; then
     CPPFLAGS="$CPPFLAGS -D_BSD_SOURCE"
     dnl For PathMatchSpec() in base module fio:
     LIBS="$LIBS -lshlwapi"
-    dnl To allow us to use more than 2 GiB of memory:
-    LDFLAGS="$LDFLAGS -Wl,--large-address-aware"
+    dnl To allow us to use more than 2 GiB of memory on 32 bit Windows:
+    case "${target}" in i*86-*-mingw32*) LDFLAGS="$LDFLAGS -Wl,--large-address-aware" ;; esac
 else
     MAKENSIS=":"
 fi
index 81ab929..5314b5b 100644 (file)
@@ -279,18 +279,19 @@ endif
 endif
 
 if WITH_FFMPEG
+AM_CPPFLAGS += -I$(top_srcdir)/src/conv-ffmpeg
 if DYNAMIC_MODULES
 pkglib_LTLIBRARIES += conv-ffmpeg.la
 conv_ffmpeg_la_SOURCES = conv-ffmpeg/from-ffmpeg.cpp \
-       conv-ffmpeg/s11n.h conv-ffmpeg/s11n.cpp \
-       conv-ffmpeg/thread.h conv-ffmpeg/thread.cpp \
+       conv-ffmpeg/base/ser.h conv-ffmpeg/base/ser.cpp \
+       conv-ffmpeg/base/pth.h conv-ffmpeg/base/pth.cpp \
        conv-ffmpeg/media_data.h conv-ffmpeg/media_data.cpp \
        conv-ffmpeg/media_object.h conv-ffmpeg/media_object.cpp
 conv_ffmpeg_la_LIBADD = $(libffmpeg_LIBS)
 else
 libbuiltin_la_SOURCES += conv-ffmpeg/from-ffmpeg.cpp \
-       conv-ffmpeg/s11n.h conv-ffmpeg/s11n.cpp \
-       conv-ffmpeg/thread.h conv-ffmpeg/thread.cpp \
+       conv-ffmpeg/base/ser.h conv-ffmpeg/base/ser.cpp \
+       conv-ffmpeg/base/pth.h conv-ffmpeg/base/pth.cpp \
        conv-ffmpeg/media_data.h conv-ffmpeg/media_data.cpp \
        conv-ffmpeg/media_object.h conv-ffmpeg/media_object.cpp
 libbuiltin_la_LIBADD += $(libffmpeg_LIBS)
index e2ca2da..6c6234f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
 # include <signal.h>
 #endif
 
-#include "base/gettext.h"
-#define _(string) gettext(string)
-
 #include "base/msg.h"
 #include "base/dbg.h"
 
+#include "base/gettext.h"
+#define _(string) gettext(string)
+
 
 namespace dbg
 {
index 084358e..b2133ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
 #include <cstring>
 #include <cerrno>
 
-#include "base/gettext.h"
-#define _(string) gettext(string)
-
 #include "base/msg.h"
 #include "base/exc.h"
 
+#include "base/gettext.h"
+#define _(string) gettext(string)
+
 
 const char *exc::_fallback_str = strerror(ENOMEM);
 
index 11c0a6d..59b75ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -711,6 +711,32 @@ error_exit:
         return lock(1, f, filename);
     }
 
+    void unlock(FILE *f, const std::string &filename)
+    {
+        int fd = fileno(f);     // Do not use ::fileno(f); fileno might be a macro
+        bool success;
+#if !W32
+        struct flock lock;
+        lock.l_type = F_UNLCK;
+        lock.l_whence = SEEK_SET;
+        lock.l_start = 0;
+        lock.l_len = 0;
+#endif /* !W32 */
+
+        errno = 0;
+#if W32
+        success = (::_locking(fd, _LK_UNLCK, LONG_MAX) == 0);
+#else /* POSIX */
+        success = (::fcntl(fd, F_SETLK, &lock) == 0);
+#endif
+        if (!success)
+        {
+            throw exc(std::string("Cannot unlock ")
+                    + (!filename.empty() ? to_sys(filename) : "temporary file")
+                    + ": " + std::strerror(errno), errno);
+        }
+    }
+
     void read(void *dest, size_t s, size_t n, FILE *f, const std::string &filename)
     {
         size_t r;
index e7edf62..3e0f4f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,8 @@
  * C-style IO for C++, with exception handling.
  */
 
-#ifndef CIO_H
-#define CIO_H
+#ifndef FIO_H
+#define FIO_H
 
 #include <cstdio>
 #include <string>
@@ -103,6 +103,7 @@ namespace fio
     // advisory locks (for the whole file)
     bool readlock(FILE *f, const std::string &filename = std::string(""));
     bool writelock(FILE *f, const std::string &filename = std::string(""));
+    void unlock(FILE *f, const std::string &filename = std::string(""));
 
     // fread and fwrite replacements
     void read(void *dest, size_t s, size_t n, FILE *f, const std::string &filename = std::string(""));
index 7586e3f..fd09cff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012, 2013
+ * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2015
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,9 +25,6 @@
 # include <set>
 #endif
 
-#include "gettext.h"
-#define _(string) gettext(string)
-
 #include <getopt.h>
 #undef no_argument
 #undef required_argument
@@ -37,6 +34,9 @@
 #include "base/msg.h"
 #include "base/opt.h"
 
+#include "base/gettext.h"
+#define _(string) gettext(string)
+
 
 namespace opt
 {
index 383b2f4..f9c83fe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014
+ * Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
 # include <quadmath.h>
 #endif
 
-#include "base/gettext.h"
-#define _(string) gettext(string)
-
 #include "base/dbg.h"
 #include "base/exc.h"
 #include "base/msg.h"
 
+#include "base/gettext.h"
+#define _(string) gettext(string)
+
 #include "base/str.h"
 
 
diff --git a/gtatool/src/conv-ffmpeg/base/pth.cpp b/gtatool/src/conv-ffmpeg/base/pth.cpp
new file mode 100644 (file)
index 0000000..24fed2d
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2011, 2012, 2013, 2015
+ * Martin Lambers <marlam@marlam.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <cerrno>
+#include <cstring>
+#include <pthread.h>
+#include <sched.h>
+
+#include "base/pth.h"
+
+#include "base/gettext.h"
+#define _(string) gettext(string)
+
+
+const pthread_mutex_t mutex::_mutex_initializer = PTHREAD_MUTEX_INITIALIZER;
+
+mutex::mutex() : _mutex(_mutex_initializer)
+{
+    int e = pthread_mutex_init(&_mutex, NULL);
+    if (e != 0)
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_mutex_init(): " + std::strerror(e), e);
+}
+
+mutex::mutex(const mutex&) : _mutex(_mutex_initializer)
+{
+    // You cannot have multiple copies of the same mutex.
+    // Instead, we create a new one. This allows easier use of mutexes in STL containers.
+    int e = pthread_mutex_init(&_mutex, NULL);
+    if (e != 0)
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_mutex_init(): " + std::strerror(e), e);
+}
+
+mutex::~mutex()
+{
+    (void)pthread_mutex_destroy(&_mutex);
+}
+
+void mutex::lock()
+{
+    int e = pthread_mutex_lock(&_mutex);
+    if (e != 0)
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_mutex_lock(): " + std::strerror(e), e);
+}
+
+bool mutex::trylock()
+{
+    return (pthread_mutex_trylock(&_mutex) == 0);
+}
+
+void mutex::unlock()
+{
+    int e = pthread_mutex_unlock(&_mutex);
+    if (e != 0)
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_mutex_unlock(): " + std::strerror(e), e);
+}
+
+
+const pthread_cond_t condition::_cond_initializer = PTHREAD_COND_INITIALIZER;
+
+condition::condition() : _cond(_cond_initializer)
+{
+    int e = pthread_cond_init(&_cond, NULL);
+    if (e != 0)
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_cond_init(): " + std::strerror(e), e);
+}
+
+condition::condition(const condition&) : _cond(_cond_initializer)
+{
+    // You cannot have multiple copies of the same condition.
+    // Instead, we create a new one. This allows easier use of conditions in STL containers.
+    int e = pthread_cond_init(&_cond, NULL);
+    if (e != 0)
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_cond_init(): " + std::strerror(e), e);
+}
+
+condition::~condition()
+{
+    (void)pthread_cond_destroy(&_cond);
+}
+
+void condition::wait(mutex& m)
+{
+    int e = pthread_cond_wait(&_cond, &m._mutex);
+    if (e != 0)
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_cond_wait(): " + std::strerror(e), e);
+}
+
+void condition::wake_one()
+{
+    int e = pthread_cond_signal(&_cond);
+    if (e != 0)
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_cond_signal(): " + std::strerror(e), e);
+}
+
+void condition::wake_all()
+{
+    int e = pthread_cond_broadcast(&_cond);
+    if (e != 0)
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_cond_broadcast(): " + std::strerror(e), e);
+}
+
+
+const int thread::priority_default;
+const int thread::priority_min;
+
+thread::thread() :
+    __thread_id(pthread_self()),
+    __joinable(false),
+    __running(false),
+    __wait_mutex(),
+    __exception()
+{
+}
+
+thread::thread(const thread&) :
+    __thread_id(pthread_self()),
+    __joinable(false),
+    __running(false),
+    __wait_mutex(),
+    __exception()
+{
+    // The thread state cannot be copied; a new state is created instead.
+}
+
+thread::~thread()
+{
+    if (__joinable)
+        (void)pthread_detach(__thread_id);
+}
+
+void* thread::__run(void* p)
+{
+    thread* t = static_cast<thread*>(p);
+    try {
+        t->run();
+    }
+    catch (exc& e) {
+        t->__exception = e;
+    }
+    catch (std::exception& e) {
+        t->__exception = e;
+    }
+    catch (...) {
+        // We must assume this means thread cancellation. In this
+        // case, we *must* rethrow the exception.
+        t->__running = false;
+        throw;
+    }
+    t->__running = false;
+    return NULL;
+}
+
+void thread::start(int priority)
+{
+    if (atomic::bool_compare_and_swap(&__running, false, true)) {
+        wait();
+        int e;
+        pthread_attr_t priority_thread_attr;
+        pthread_attr_t* thread_attr = NULL;
+        if (priority != priority_default)
+        {
+            // Currently this means priority_min
+            int policy, min_priority;
+            struct sched_param param;
+            e = pthread_attr_init(&priority_thread_attr);
+            e = e || pthread_attr_getschedpolicy(&priority_thread_attr, &policy);
+            if (e == 0) {
+                min_priority = sched_get_priority_min(policy);
+                if (min_priority == -1)
+                    e = errno;
+            }
+            e = e || pthread_attr_getschedparam(&priority_thread_attr, &param);
+            if (e == 0) {
+                param.sched_priority = min_priority;
+            }
+            e = e || pthread_attr_setschedparam(&priority_thread_attr, &param);
+            if (e != 0) {
+                throw exc(std::string(_("System function failed: "))
+                        + "pthread_attr_*(): " + std::strerror(e), e);
+            }
+            thread_attr = &priority_thread_attr;
+        }
+        e = pthread_create(&__thread_id, thread_attr, __run, this);
+        if (e != 0) {
+            throw exc(std::string(_("System function failed: "))
+                    + "pthread_create(): " + std::strerror(e), e);
+        }
+        __joinable = true;
+    }
+}
+
+void thread::wait()
+{
+    __wait_mutex.lock();
+    if (atomic::bool_compare_and_swap(&__joinable, true, false)) {
+        int e = pthread_join(__thread_id, NULL);
+        if (e != 0) {
+            __wait_mutex.unlock();
+            throw exc(std::string(_("System function failed: "))
+                    + "pthread_join(): " + std::strerror(e), e);
+        }
+    }
+    __wait_mutex.unlock();
+}
+
+void thread::finish()
+{
+    wait();
+    if (!exception().empty())
+        throw exception();
+}
+
+void thread::cancel()
+{
+    __wait_mutex.lock();
+    int e = pthread_cancel(__thread_id);
+    if (e != 0) {
+        __wait_mutex.unlock();
+        throw exc(std::string(_("System function failed: "))
+                + "pthread_cancel(): " + std::strerror(e), e);
+    }
+    __wait_mutex.unlock();
+}
+
+
+thread_group::thread_group(unsigned char size) : __max_size(size)
+{
+    __active_threads.reserve(__max_size);
+    __finished_threads.reserve(__max_size);
+}
+
+thread_group::~thread_group()
+{
+    try {
+        for (size_t i = 0; i < __active_threads.size(); i++) {
+            __active_threads[i]->cancel();
+        }
+    }
+    catch (...) {
+    }
+}
+
+bool thread_group::start(thread* t, int priority)
+{
+    if (__active_threads.size() < __max_size) {
+        t->start(priority);
+        __active_threads.push_back(t);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+thread* thread_group::get_next_finished_thread()
+{
+    if (__finished_threads.size() == 0) {
+        std::vector<thread*>::iterator it = __active_threads.begin();
+        while (it != __active_threads.end()) {
+            if (!(*it)->running()) {
+                __finished_threads.push_back(*it);
+                it = __active_threads.erase(it);
+            } else {
+                it++;
+            }
+        }
+    }
+    if (__finished_threads.size() > 0) {
+        thread* ret = __finished_threads.back();
+        __finished_threads.pop_back();
+        return ret;
+    } else {
+        return NULL;
+    }
+}
diff --git a/gtatool/src/conv-ffmpeg/base/pth.h b/gtatool/src/conv-ffmpeg/base/pth.h
new file mode 100644 (file)
index 0000000..1c5d1e6
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2011, 2012, 2013, 2015
+ * Martin Lambers <marlam@marlam.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PTH_H
+#define PTH_H
+
+#include <vector>
+#include <pthread.h>
+
+#include "base/exc.h"
+
+
+/*
+ * Atomic operations
+ */
+
+namespace atomic
+{
+    // TODO
+    //
+    // Currently this is just an interface to the GCC atomic builtin functions; see
+    // http://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Atomic-Builtins.html#Atomic-Builtins
+    //
+    // This must be extended when (if) other compilers are used some day.
+    //
+    // The functions obviously only work for basic data types.
+    // The comments were copied from the GCC manual referenced above.
+
+    /* The following functions perform the operation suggested by the name,
+     * and return the value that had previously been in memory. */
+    template<typename T> T fetch_and_add(T* ptr, T value) { return __sync_fetch_and_add(ptr, value); }
+    template<typename T> T fetch_and_sub(T* ptr, T value) { return __sync_fetch_and_sub(ptr, value); }
+    template<typename T> T fetch_and_or(T* ptr, T value) { return __sync_fetch_and_or(ptr, value); }
+    template<typename T> T fetch_and_and(T* ptr, T value) { return __sync_fetch_and_and(ptr, value); }
+    template<typename T> T fetch_and_xor(T* ptr, T value) { return __sync_fetch_and_xor(ptr, value); }
+    template<typename T> T fetch_and_nand(T* ptr, T value) { return __sync_fetch_and_nand(ptr, value); }
+
+    /* The following functions perform the operation suggested by the name,
+     * and return the new value. */
+    template<typename T> T add_and_fetch(T* ptr, T value) { return __sync_add_and_fetch(ptr, value); }
+    template<typename T> T sub_and_fetch(T* ptr, T value) { return __sync_sub_and_fetch(ptr, value); }
+    template<typename T> T or_and_fetch(T* ptr, T value) { return __sync_or_and_fetch(ptr, value); }
+    template<typename T> T and_and_fetch(T* ptr, T value) { return __sync_and_and_fetch(ptr, value); }
+    template<typename T> T xor_and_fetch(T* ptr, T value) { return __sync_xor_and_fetch(ptr, value); }
+    template<typename T> T nand_and_fetch(T* ptr, T value) { return __sync_nand_and_fetch(ptr, value); }
+
+    /* The following functions perform an atomic compare and swap.
+     * That is, if the current value of *ptr is oldval, then write newval into *ptr.
+     * The "bool" version returns true if the comparison is successful and newval was written.
+     * The "val" version returns the contents of *ptr before the operation. */
+    template<typename T> bool bool_compare_and_swap(T* ptr, T oldval, T newval) { return __sync_bool_compare_and_swap(ptr, oldval, newval); }
+    template<typename T> T val_compare_and_swap(T* ptr, T oldval, T newval) { return __sync_val_compare_and_swap(ptr, oldval, newval); }
+
+    /* The following are convenience functions implemented on top of the above
+     * basic atomic operations. */
+    template<typename T> T fetch_and_inc(T* ptr) { return fetch_and_add(ptr, static_cast<T>(1)); }
+    template<typename T> T inc_and_fetch(T* ptr) { return add_and_fetch(ptr, static_cast<T>(1)); }
+    template<typename T> T fetch_and_dec(T* ptr) { return fetch_and_sub(ptr, static_cast<T>(1)); }
+    template<typename T> T dec_and_fetch(T* ptr) { return sub_and_fetch(ptr, static_cast<T>(1)); }
+}
+
+
+/*
+ * Mutex
+ */
+
+class mutex
+{
+private:
+    static const pthread_mutex_t _mutex_initializer;
+    pthread_mutex_t _mutex;
+
+public:
+    // Constructor / Destructor
+    mutex();
+    mutex(const mutex& m);
+    ~mutex();
+
+    // Lock the mutex.
+    void lock();
+    // Try to lock the mutex. Return true on success, false otherwise.
+    bool trylock();
+    // Unlock the mutex
+    void unlock();
+
+    friend class condition;
+};
+
+
+/*
+ * Wait condition
+ */
+
+class condition
+{
+private:
+    static const pthread_cond_t _cond_initializer;
+    pthread_cond_t _cond;
+
+public:
+    // Constructor / Destructor
+    condition();
+    condition(const condition& c);
+    ~condition();
+
+    // Wait for the condition. The calling thread must have the mutex locked.
+    void wait(mutex& m);
+    // Wake one thread that waits on the condition.
+    void wake_one();
+    // Wake all threads that wait on the condition.
+    void wake_all();
+};
+
+
+/*
+ * Thread
+ *
+ * Implement the run() function in a subclass.
+ */
+
+class thread
+{
+private:
+    pthread_t __thread_id;
+    bool __joinable;
+    bool __running;
+    mutex __wait_mutex;
+    exc __exception;
+
+    static void* __run(void* p);
+
+public:
+    // Priorities
+    static const int priority_default = 0;
+    static const int priority_min = 1;
+
+    // Constructor / Destructor
+    thread();
+    thread(const thread& t);
+    virtual ~thread();
+
+    // Implement this in a subclass; it will be executed from the thread via start()
+    virtual void run() = 0;
+
+    // Start a new thread that executes the run() function. If the thread is already
+    // running, this function does nothing.
+    void start(int priority = thread::priority_default);
+
+    // Returns whether this thread is currently running.
+    bool running()
+    {
+        return __running;
+    }
+
+    // Wait for the thread to finish. If the thread is not running, this function
+    // returns immediately.
+    void wait();
+
+    // Wait for the thread to finish, like wait(), and rethrow an exception that the
+    // run() function might have thrown during its execution.
+    void finish();
+
+    // Cancel a thread. This is dangerous and should not be used.
+    void cancel();
+
+    // Get an exception that the run() function might have thrown.
+    const exc& exception() const
+    {
+        return __exception;
+    }
+    // Modify the stored exception
+    exc& exception()
+    {
+        return __exception;
+    }
+};
+
+
+/*
+ * Thread group.
+ *
+ * This manages a group of threads that has a fixed maximum size. New threads
+ * can only be started if there are still free slots in the group. A finished
+ * thread makes its slot available for future threads.
+ *
+ * A thread group must be managed from a single thread. When the thread group
+ * object is destroyed, all remaining threads are cancelled.
+ */
+
+class thread_group
+{
+private:
+    unsigned char __max_size;
+    std::vector<thread*> __active_threads;
+    std::vector<thread*> __finished_threads;
+
+public:
+    thread_group(unsigned char size);
+    virtual ~thread_group();
+
+    // Start a new thread and return its slot number. If there are no free
+    // slots, the thread is not started and false is returned.
+    bool start(thread* t, int priority = thread::priority_default);
+
+    // Return a finished thread object from the group and free its slot so
+    // that future threads can use it. If there is no finished thread, NULL
+    // is returned.
+    thread* get_next_finished_thread();
+};
+
+#endif
diff --git a/gtatool/src/conv-ffmpeg/base/ser.cpp b/gtatool/src/conv-ffmpeg/base/ser.cpp
new file mode 100644 (file)
index 0000000..681f5ed
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2015
+ * Martin Lambers <marlam@marlam.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <cstring>
+
+#include "base/str.h"
+
+#include "base/ser.h"
+
+
+static const char* low_char_encodings[] = {
+    "\\(NUL)", // 0
+    "\\(SOH)", // 1
+    "\\(STX)", // 2
+    "\\(ETX)", // 3
+    "\\(EOT)", // 4
+    "\\(ENQ)", // 5
+    "\\(ACK)", // 6
+    "\\(BEL)", // 7
+    "\\(_BS)", // 8
+    "\\(_HT)", // 9
+    "\\(_LF)", // 10
+    "\\(_VT)", // 11
+    "\\(_FF)", // 12
+    "\\(_CR)", // 13
+    "\\(_SO)", // 14
+    "\\(_SI)", // 15
+    "\\(DLE)", // 16
+    "\\(DC1)", // 17
+    "\\(DC2)", // 18
+    "\\(DC3)", // 19
+    "\\(DC4)", // 20
+    "\\(NAK)", // 21
+    "\\(SYN)", // 22
+    "\\(ETB)", // 23
+    "\\(CAN)", // 24
+    "\\(_EM)", // 25
+    "\\(SUB)", // 26
+    "\\(ESC)", // 27
+    "\\(_FS)", // 28
+    "\\(_GS)", // 29
+    "\\(_RS)", // 30
+    "\\(_US)", // 31
+};
+
+
+void s11n::startgroup(std::ostream& os, const char* name)
+{
+    os << ' ' << name << "={";
+}
+
+void s11n::endgroup(std::ostream& os)
+{
+    os << " }";
+}
+
+void s11n::load(std::istream& is, std::string& name, std::string& value)
+{
+    char c;
+    // skip leading spaces
+    while (is.good() && (c = is.get()) == ' ');
+    // read name
+    name.clear();
+    while (is.good() && c != '=') {
+        name.push_back(c);
+        c = is.get();
+    }
+    c = is.get();
+    // read value
+    value.clear();
+    bool value_is_valid = false;
+    int group_depth = 0;
+    char enc_char[] = "\\(...)";
+    for (;;) {
+        bool c_is_valid = false;
+        if (c == '\\') {
+            c = is.get();
+            if (c == '\\' || c == ' ' || c == '{' || c == '}') {
+                c_is_valid = true;
+            } else {
+                enc_char[1] = c;
+                enc_char[2] = is.get();
+                enc_char[3] = is.get();
+                enc_char[4] = is.get();
+                enc_char[5] = is.get();
+                if (std::memcmp(enc_char, "\\(DEL)", 6) == 0) {
+                    c = 127;
+                    c_is_valid = true;
+                } else {
+                    for (int j = 0; j <= 31; j++) {
+                        if (std::memcmp(enc_char, low_char_encodings[j], 6) == 0) {
+                            c = j;
+                            c_is_valid = true;
+                            break;
+                        }
+                    }
+                }
+            }
+        } else {
+            if (c == '{') {
+                group_depth++;
+            } else if (c == '}') {
+                group_depth--;
+                if (group_depth < 0)
+                    break;
+            }
+            c_is_valid = true;
+        }
+        if (!c_is_valid || !is.good())
+            break;
+        value.append(1, c);
+        if (group_depth == 0 && (is.peek() == ' ' || is.eof())) {
+            value_is_valid = true;
+            break;
+        }
+        c = is.get();
+    }
+    if (!value_is_valid)
+        value = "";
+    else if (value.length() >= 2 && value[0] == '{' && value[value.length() - 1] == '}')
+        value = value.substr(1, value.length() - 2);
+}
+
+void serializable::save(std::ostream& os, const char* name) const
+{
+    // Default implementation: use binary save and store binary blob
+    std::ostringstream oss;
+    this->save(oss);
+    s11n::startgroup(os, name);
+    s11n::save(os, "size", oss.str().length());
+    s11n::save(os, "", oss.str().data(), oss.str().length());
+    s11n::endgroup(os);
+}
+
+void serializable::load(const std::string& s)
+{
+    // Default implementation: read and restore binary blob
+    std::istringstream iss(s);
+    std::string name, value;
+    s11n::load(iss, name, value);
+    size_t size = 0;
+    if (name == "size")
+        s11n::load(value, size);
+    s11n::load(iss, name, value);
+    std::string str;
+    char* buf = new char[size];
+    s11n::load(value, buf, size);
+    str.assign(buf, size);
+    delete[] buf;
+    std::istringstream iss2(str);
+    this->load(iss2);
+}
+
+// Return value NULL means the character can be written as is.
+static const char* enc_char(char x)
+{
+    return (x >= 0 && x <= 31 ? low_char_encodings[static_cast<int>(x)]
+            : x == 127 ? "\\(DEL)"
+            : x == '{' ? "\\{"
+            : x == '}' ? "\\}"
+            : x == ' ' ? "\\ "
+            : x == '\\' ? "\\\\"
+            : NULL);
+}
+
+// Decode a character. The index i is incremented according to the characters consumed from s.
+static char dec_char(const char* s, size_t& i)
+{
+    if (s[i] == '\\') {
+        if (s[i + 1] == '\\' || s[i + 1] == ' ' || s[i + 1] == '{' || s[i + 1] == '}') {
+            i++;
+            return s[i++];
+        } else if (s[i + 1] != '\0' && s[i + 2] != '\0' && s[i + 3] != '\0' && s[i + 4] != '\0' && s[i + 5] != '\0') {
+            if (std::memcmp(s, "\\(DEL)", 6) == 0) {
+                i += 6;
+                return 127;
+            } else {
+                for (int j = 0; j <= 31; j++) {
+                    if (std::memcmp(s, low_char_encodings[j], 6) == 0) {
+                        i += 6;
+                        return j;
+                    }
+                }
+                // invalid string!
+                return '\0';
+            }
+        } else {
+            // invalid string!
+            return '\0';
+        }
+    } else {
+        return s[i++];
+    }
+}
+
+/*
+ * Save a value to a stream
+ */
+
+// Fundamental arithmetic data types
+
+void s11n::save(std::ostream& os, bool x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, bool x)
+{
+    os << ' ' << name << '=' << (x ? '1' : '0');
+}
+
+void s11n::save(std::ostream& os, char x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, char x)
+{
+    const char* e = enc_char(x);
+    os << ' ' << name << '=';
+    if (e)
+        os << e;
+    else
+        os << x;
+}
+
+void s11n::save(std::ostream& os, signed char x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, signed char x)
+{
+    os << ' ' << name << '=' << static_cast<int>(x);
+}
+
+void s11n::save(std::ostream& os, unsigned char x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, unsigned char x)
+{
+    os << ' ' << name << '=' << static_cast<int>(x);
+}
+
+void s11n::save(std::ostream& os, short x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, short x)
+{
+    os << ' ' << name << '=' << x;
+}
+
+void s11n::save(std::ostream& os, unsigned short x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, unsigned short x)
+{
+    os << ' ' << name << '=' << x;
+}
+
+void s11n::save(std::ostream& os, int x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, int x)
+{
+    os << ' ' << name << '=' << x;
+}
+
+void s11n::save(std::ostream& os, unsigned int x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, unsigned int x)
+{
+    os << ' ' << name << '=' << x;
+}
+
+void s11n::save(std::ostream& os, long x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, long x)
+{
+    os << ' ' << name << '=' << x;
+}
+
+void s11n::save(std::ostream& os, unsigned long x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, unsigned long x)
+{
+    os << ' ' << name << '=' << x;
+}
+
+void s11n::save(std::ostream& os, long long x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, long long x)
+{
+    os << ' ' << name << '=' << x;
+}
+
+void s11n::save(std::ostream& os, unsigned long long x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, unsigned long long x)
+{
+    os << ' ' << name << '=' << x;
+}
+
+void s11n::save(std::ostream& os, float x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, float x)
+{
+    os << ' ' << name << '=' << str::from(x).c_str();
+}
+
+void s11n::save(std::ostream& os, double x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, double x)
+{
+    os << ' ' << name << '=' << str::from(x).c_str();
+}
+
+void s11n::save(std::ostream& os, long double x)
+{
+    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
+}
+
+void s11n::save(std::ostream& os, const char* name, long double x)
+{
+    os << ' ' << name << '=' << str::from(x).c_str();
+}
+
+// Binary blobs
+
+void s11n::save(std::ostream& os, const void* x, const size_t n)
+{
+    os.write(reinterpret_cast<const char*>(x), n);
+}
+
+void s11n::save(std::ostream& os, const char* name, const void* x, const size_t n)
+{
+    static const char hex[] = "0123456789abcdef";
+    startgroup(os, name);
+    for (size_t i = 0; i < n; i++) {
+        unsigned char val = static_cast<const unsigned char*>(x)[i];
+        os << hex[(val >> 4) & 0xf] << hex[val & 0xf];
+        if (i < n - 1)
+            os << ' ';
+    }
+    endgroup(os);
+}
+
+// Serializable classes
+
+void s11n::save(std::ostream& os, const serializable& x)
+{
+    x.save(os);
+}
+
+void s11n::save(std::ostream& os, const char* name, const serializable& x)
+{
+    x.save(os, name);
+}
+
+// Basic STL types
+
+void s11n::save(std::ostream& os, const std::string& x)
+{
+    size_t s = x.length();
+    os.write(reinterpret_cast<const char*>(&s), sizeof(s));
+    os.write(reinterpret_cast<const char*>(x.data()), s);
+}
+
+void s11n::save(std::ostream& os, const char* name, const std::string& x)
+{
+    os << ' ' << name << '=';
+    for (size_t i = 0; i < x.length(); i++) {
+        char c = x[i];
+        const char* e = enc_char(c);
+        if (e)
+            os << e;
+        else
+            os << c;
+    }
+}
+
+
+/*
+ * Load a value from a stream
+ */
+
+// Fundamental arithmetic data types
+
+void s11n::load(std::istream& is, bool& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, bool& x)
+{
+    x = str::to<bool>(s);
+}
+
+void s11n::load(std::istream& is, char& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, char& x)
+{
+    size_t i = 0;
+    x = dec_char(s.c_str(), i);
+}
+
+void s11n::load(std::istream& is, signed char& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, signed char& x)
+{
+    x = str::to<int>(s);
+}
+
+void s11n::load(std::istream& is, unsigned char& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, unsigned char& x)
+{
+    x = str::to<unsigned int>(s);
+}
+
+void s11n::load(std::istream& is, short& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, short& x)
+{
+    x = str::to<short>(s);
+}
+
+void s11n::load(std::istream& is, unsigned short& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, unsigned short& x)
+{
+    x = str::to<unsigned short>(s);
+}
+
+void s11n::load(std::istream& is, int& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, int& x)
+{
+    x = str::to<int>(s);
+}
+
+void s11n::load(std::istream& is, unsigned int& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, unsigned int& x)
+{
+    x = str::to<unsigned int>(s);
+}
+
+void s11n::load(std::istream& is, long& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, long& x)
+{
+    x = str::to<long>(s);
+}
+
+void s11n::load(std::istream& is, unsigned long& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, unsigned long& x)
+{
+    x = str::to<unsigned long>(s);
+}
+
+void s11n::load(std::istream& is, long long& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, long long& x)
+{
+    x = str::to<long long>(s);
+}
+
+void s11n::load(std::istream& is, unsigned long long& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, unsigned long long& x)
+{
+    x = str::to<unsigned long long>(s);
+}
+
+void s11n::load(std::istream& is, float& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, float& x)
+{
+    x = str::to<float>(s);
+}
+
+void s11n::load(std::istream& is, double& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, double& x)
+{
+    x = str::to<double>(s);
+}
+
+void s11n::load(std::istream& is, long double& x)
+{
+    is.read(reinterpret_cast<char*>(&x), sizeof(x));
+}
+
+void s11n::load(const std::string& s, long double& x)
+{
+    x = str::to<long double>(s);
+}
+
+// Binary blobs
+
+void s11n::load(std::istream& is, void* x, const size_t n)
+{
+    is.read(reinterpret_cast<char*>(x), n);
+}
+
+void s11n::load(const std::string& s, void* x, const size_t n)
+{
+    std::memset(x, 0, n);
+    size_t i = 0;
+    while (i < n && i + 3 < s.length()) {
+        unsigned char val = 0;
+        if (s[i] == ' ') {
+            i++;
+            if (s[i] >= '0' && s[i] <= '9')
+                val |= (s[i] - '0') << 4;
+            else if (s[i] >= 'a' && s[i] <= 'z')
+                val |= (s[i] - 'a' + 10) << 4;
+            i++;
+            if (s[i] >= '0' && s[i] <= '9')
+                val |= (s[i] - '0');
+            else if (s[i] >= 'a' && s[i] <= 'z')
+                val |= (s[i] - 'a' + 10);
+        }
+        static_cast<unsigned char*>(x)[i] = val;
+    }
+}
+
+// Serializable classes
+
+void s11n::load(std::istream& is, serializable& x)
+{
+    x.load(is);
+}
+
+void s11n::load(const std::string& s, serializable& x)
+{
+    x.load(s);
+}
+
+// Basic STL types
+
+void s11n::load(std::istream& is, std::string& x)
+{
+    size_t s;
+    is.read(reinterpret_cast<char*>(&s), sizeof(s));
+    char* buf = new char[s];
+    is.read(buf, s);
+    x.assign(buf, s);
+    delete[] buf;
+}
+
+void s11n::load(const std::string& s, std::string& x)
+{
+    x.clear();
+    if (s.length() == 0)
+        return;
+    const char *sc = s.c_str();
+    size_t i = 0;
+    while (i < s.length()) {
+        x.append(1, dec_char(sc, i));
+    }
+}
diff --git a/gtatool/src/conv-ffmpeg/base/ser.h b/gtatool/src/conv-ffmpeg/base/ser.h
new file mode 100644 (file)
index 0000000..68fb833
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014
+ * Martin Lambers <marlam@marlam.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef S11N_H
+#define S11N_H
+
+/*
+ * This module provides functions s11n::save() and s11n::load() that serialize
+ * types and objects.
+ * This works for all basic data types, STL types such as std::string, and
+ * classes that implement the s11n interface.
+ * Additionally, STL containers of serializable types can also be serialized,
+ * e.g. std::vector<std::string>.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+
+class serializable
+{
+public:
+    /*
+     * Interface for serializable classes
+     */
+
+    // Save binary. Efficient. Needs compatible architectures and application versions on the writing and reading end.
+    virtual void save(std::ostream& os) const = 0;
+    virtual void load(std::istream& is) = 0;
+
+    // Save in human-readable and editable text format. Can be used for machine- and application version independent
+    // saving of data. The default implementation falls back on the above binary functions and stores the binary data in
+    // strings.
+    virtual void save(std::ostream& os, const char* name) const;
+    virtual void load(const std::string& s);
+};
+
+namespace s11n
+{
+    // Functions needed for human-readable save/load:
+    // - When saving a group of values contained in a serializable class, use startgroup()/endgroup()
+    // - When loading back, get the next name/value pair and interpret it
+    void startgroup(std::ostream& os, const char* name);
+    void endgroup(std::ostream& os);
+    void load(std::istream& is, std::string& name, std::string& value);
+
+    /*
+     * Save a value to a stream
+     */
+
+    // Fundamental arithmetic data types
+
+    void save(std::ostream& os, bool x);
+    void save(std::ostream& os, const char* name, bool x);
+    void save(std::ostream& os, char x);
+    void save(std::ostream& os, const char* name, char x);
+    void save(std::ostream& os, signed char x);
+    void save(std::ostream& os, const char* name, signed char x);
+    void save(std::ostream& os, unsigned char x);
+    void save(std::ostream& os, const char* name, unsigned char x);
+    void save(std::ostream& os, short x);
+    void save(std::ostream& os, const char* name, short x);
+    void save(std::ostream& os, unsigned short x);
+    void save(std::ostream& os, const char* name, unsigned short x);
+    void save(std::ostream& os, int x);
+    void save(std::ostream& os, const char* name, int x);
+    void save(std::ostream& os, unsigned int x);
+    void save(std::ostream& os, const char* name, unsigned int x);
+    void save(std::ostream& os, long x);
+    void save(std::ostream& os, const char* name, long x);
+    void save(std::ostream& os, unsigned long x);
+    void save(std::ostream& os, const char* name, unsigned long x);
+    void save(std::ostream& os, long long x);
+    void save(std::ostream& os, const char* name, long long x);
+    void save(std::ostream& os, unsigned long long x);
+    void save(std::ostream& os, const char* name, unsigned long long x);
+    void save(std::ostream& os, float x);
+    void save(std::ostream& os, const char* name, float x);
+    void save(std::ostream& os, double x);
+    void save(std::ostream& os, const char* name, double x);
+    void save(std::ostream& os, long double x);
+    void save(std::ostream& os, const char* name, long double x);
+
+    // Binary blobs
+
+    void save(std::ostream& os, const void* x, const size_t n);
+    void save(std::ostream& os, const char* name, const void* x, const size_t n);
+
+    // Serializable classes
+
+    void save(std::ostream& os, const serializable& x);
+    void save(std::ostream& os, const char* name, const serializable& x);
+
+    // Basic STL types
+
+    void save(std::ostream& os, const std::string& x);
+    void save(std::ostream& os, const char* name, const std::string& x);
+
+    // STL containters
+
+    template<typename T>
+    void save(std::ostream& os, const std::vector<T>& x)
+    {
+        size_t s = x.size();
+        save(os, s);
+        for (size_t i = 0; i < s; i++) {
+            save(os, x[i]);
+        }
+    }
+
+    template<typename T>
+    void save(std::ostream& os, const char* name, const std::vector<T>& x)
+    {
+        size_t s = x.size();
+        startgroup(os, name);
+        save(os, "size", s);
+        for (size_t i = 0; i < s; i++) {
+            save(os, "", x[i]);
+        }
+        endgroup(os);
+    }
+
+    // TODO: add more STL containers as needed
+
+    /*
+     * Load a value from a stream
+     */
+
+    // Fundamental arithmetic data types
+
+    void load(std::istream& is, bool& x);
+    void load(const std::string& s, bool& x);
+    void load(std::istream& is, char& x);
+    void load(const std::string& s, char& x);
+    void load(std::istream& is, signed char& x);
+    void load(const std::string& s, signed char& x);
+    void load(std::istream& is, unsigned char& x);
+    void load(const std::string& s, unsigned char& x);
+    void load(std::istream& is, short& x);
+    void load(const std::string& s, short& x);
+    void load(std::istream& is, unsigned short& x);
+    void load(const std::string& s, unsigned short& x);
+    void load(std::istream& is, int& x);
+    void load(const std::string& s, int& x);
+    void load(std::istream& is, unsigned int& x);
+    void load(const std::string& s, unsigned int& x);
+    void load(std::istream& is, long& x);
+    void load(const std::string& s, long& x);
+    void load(std::istream& is, unsigned long& x);
+    void load(const std::string& s, unsigned long& x);
+    void load(std::istream& is, long long& x);
+    void load(const std::string& s, long long& x);
+    void load(std::istream& is, unsigned long long& x);
+    void load(const std::string& s, unsigned long long& x);
+    void load(std::istream& is, float& x);
+    void load(const std::string& s, float& x);
+    void load(std::istream& is, double& x);
+    void load(const std::string& s, double& x);
+    void load(std::istream& is, long double& x);
+    void load(const std::string& s, long double& x);
+
+    // Binary blobs
+
+    void load(std::istream& is, void* x, const size_t n);
+    void load(const std::string& s, void* x, const size_t n);
+
+    // Serializable classes
+
+    void load(std::istream& is, serializable& x);
+    void load(const std::string& s, serializable& x);
+
+    // Basic STL types
+
+    void load(std::istream& is, std::string& x);
+    void load(const std::string& s, std::string& x);
+
+    // STL containers
+
+    template<typename T>
+    void load(std::istream& is, std::vector<T>& x)
+    {
+        size_t s;
+        load(is, s);
+        x.resize(s);
+        for (size_t i = 0; i < s; i++) {
+            load(is, x[i]);
+        }
+    }
+
+    template<typename T>
+    void load(const std::string& s, std::vector<T>& x)
+    {
+        std::stringstream ss(s);
+        std::string name, value;
+        size_t z = 0;
+        load(ss, name, value);
+        if (name == "size")
+            load(value, z);
+        x.resize(z);
+        size_t i = 0;
+        while (ss.good() && i < z) {
+            load(ss, name, value);
+            load(value, x[i]);
+            i++;
+        }
+    }
+
+    // TODO: add more STL containers as needed
+
+    // Convenience wrappers: directly return a loaded value
+
+    template<typename T>
+    T load(std::istream& is)
+    {
+        T x;
+        load(is, x);
+        return x;
+    }
+
+    template<typename T>
+    T load(const std::string& s)
+    {
+        T x;
+        load(s, x);
+        return x;
+    }
+};
+
+#endif
index 57fb374..ac3a229 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of bino, a 3D video player.
  *
- * Copyright (C) 2010, 2011, 2012, 2013
+ * Copyright (C) 2010, 2011, 2012, 2013, 2015
  * Martin Lambers <marlam@marlam.de>
  * Joe <joe@wpj.cz>
  * D. Matz <bandregent@yahoo.de>
 #include <cstring>
 #include <cmath>
 
-#include "base/gettext.h"
-#define _(string) gettext(string)
-
 #include "media_data.h"
 
 #include "base/str.h"
 #include "base/msg.h"
 #include "base/dbg.h"
 
+#include "base/gettext.h"
+#define _(string) gettext(string)
+
 #if HAVE_LIBXNVCTRL
 #include "NVCtrl.h"
 #endif // HAVE_LIBXNVCTRL
index b081cf0..30c7bec 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of bino, a 3D video player.
  *
- * Copyright (C) 2010, 2011, 2012, 2013
+ * Copyright (C) 2010, 2011, 2012, 2013, 2015
  * Martin Lambers <marlam@marlam.de>
  * Joe <joe@wpj.cz>
  * D. Matz <bandregent@yahoo.de>
@@ -28,7 +28,7 @@
 #include <string>
 #include <stdint.h>
 
-#include "s11n.h"
+#include "base/ser.h"
 #include "base/msg.h"
 
 
index 491e159..9dde4cc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of bino, a 3D video player.
  *
- * Copyright (C) 2010, 2011, 2012, 2013, 2014
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015
  * Martin Lambers <marlam@marlam.de>
  * Frédéric Devernay <frederic.devernay@inrialpes.fr>
  * Joe <cuchac@email.cz>
@@ -45,15 +45,15 @@ extern "C"
 #  include <windows.h>
 #endif
 
-#include "base/gettext.h"
-#define _(string) gettext(string)
-
 #include "base/dbg.h"
 #include "base/blb.h"
 #include "base/exc.h"
 #include "base/msg.h"
 #include "base/str.h"
-#include "thread.h"
+#include "base/pth.h"
+
+#include "base/gettext.h"
+#define _(string) gettext(string)
 
 #include "media_object.h"
 
diff --git a/gtatool/src/conv-ffmpeg/s11n.cpp b/gtatool/src/conv-ffmpeg/s11n.cpp
deleted file mode 100644 (file)
index 19d7c4c..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * Copyright (C) 2008, 2009, 2010, 2011, 2012
- * Martin Lambers <marlam@marlam.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <cstring>
-
-#include "base/str.h"
-
-#include "s11n.h"
-
-
-static const char* low_char_encodings[] = {
-    "\\(NUL)", // 0
-    "\\(SOH)", // 1
-    "\\(STX)", // 2
-    "\\(ETX)", // 3
-    "\\(EOT)", // 4
-    "\\(ENQ)", // 5
-    "\\(ACK)", // 6
-    "\\(BEL)", // 7
-    "\\(_BS)", // 8
-    "\\(_HT)", // 9
-    "\\(_LF)", // 10
-    "\\(_VT)", // 11
-    "\\(_FF)", // 12
-    "\\(_CR)", // 13
-    "\\(_SO)", // 14
-    "\\(_SI)", // 15
-    "\\(DLE)", // 16
-    "\\(DC1)", // 17
-    "\\(DC2)", // 18
-    "\\(DC3)", // 19
-    "\\(DC4)", // 20
-    "\\(NAK)", // 21
-    "\\(SYN)", // 22
-    "\\(ETB)", // 23
-    "\\(CAN)", // 24
-    "\\(_EM)", // 25
-    "\\(SUB)", // 26
-    "\\(ESC)", // 27
-    "\\(_FS)", // 28
-    "\\(_GS)", // 29
-    "\\(_RS)", // 30
-    "\\(_US)", // 31
-};
-
-
-void s11n::startgroup(std::ostream& os, const char* name)
-{
-    os << ' ' << name << "={";
-}
-
-void s11n::endgroup(std::ostream& os)
-{
-    os << " }";
-}
-
-void s11n::load(std::istream& is, std::string& name, std::string& value)
-{
-    char c;
-    // skip leading spaces
-    while (is.good() && (c = is.get()) == ' ');
-    // read name
-    name.clear();
-    while (is.good() && c != '=') {
-        name.push_back(c);
-        c = is.get();
-    }
-    c = is.get();
-    // read value
-    value.clear();
-    bool value_is_valid = false;
-    int group_depth = 0;
-    char enc_char[] = "\\(...)";
-    for (;;) {
-        bool c_is_valid = false;
-        if (c == '\\') {
-            c = is.get();
-            if (c == '\\' || c == ' ' || c == '{' || c == '}') {
-                c_is_valid = true;
-            } else {
-                enc_char[1] = c;
-                enc_char[2] = is.get();
-                enc_char[3] = is.get();
-                enc_char[4] = is.get();
-                enc_char[5] = is.get();
-                if (std::memcmp(enc_char, "\\(DEL)", 6) == 0) {
-                    c = 127;
-                    c_is_valid = true;
-                } else {
-                    for (int j = 0; j <= 31; j++) {
-                        if (std::memcmp(enc_char, low_char_encodings[j], 6) == 0) {
-                            c = j;
-                            c_is_valid = true;
-                            break;
-                        }
-                    }
-                }
-            }
-        } else {
-            if (c == '{') {
-                group_depth++;
-            } else if (c == '}') {
-                group_depth--;
-                if (group_depth < 0)
-                    break;
-            }
-            c_is_valid = true;
-        }
-        if (!c_is_valid || !is.good())
-            break;
-        value.append(1, c);
-        if (group_depth == 0 && (is.peek() == ' ' || is.eof())) {
-            value_is_valid = true;
-            break;
-        }
-        c = is.get();
-    }
-    if (!value_is_valid)
-        value = "";
-    else if (value.length() >= 2 && value[0] == '{' && value[value.length() - 1] == '}')
-        value = value.substr(1, value.length() - 2);
-}
-
-void serializable::save(std::ostream& os, const char* name) const
-{
-    // Default implementation: use binary save and store binary blob
-    std::ostringstream oss;
-    this->save(oss);
-    s11n::startgroup(os, name);
-    s11n::save(os, "size", oss.str().length());
-    s11n::save(os, "", oss.str().data(), oss.str().length());
-    s11n::endgroup(os);
-}
-
-void serializable::load(const std::string& s)
-{
-    // Default implementation: read and restore binary blob
-    std::istringstream iss(s);
-    std::string name, value;
-    s11n::load(iss, name, value);
-    size_t size = 0;
-    if (name == "size")
-        s11n::load(value, size);
-    s11n::load(iss, name, value);
-    std::string str;
-    char* buf = new char[size];
-    s11n::load(value, buf, size);
-    str.assign(buf, size);
-    delete[] buf;
-    std::istringstream iss2(str);
-    this->load(iss2);
-}
-
-// Return value NULL means the character can be written as is.
-static const char* enc_char(char x)
-{
-    return (x >= 0 && x <= 31 ? low_char_encodings[static_cast<int>(x)]
-            : x == 127 ? "\\(DEL)"
-            : x == '{' ? "\\{"
-            : x == '}' ? "\\}"
-            : x == ' ' ? "\\ "
-            : x == '\\' ? "\\\\"
-            : NULL);
-}
-
-// Decode a character. The index i is incremented according to the characters consumed from s.
-static char dec_char(const char* s, size_t& i)
-{
-    if (s[i] == '\\') {
-        if (s[i + 1] == '\\' || s[i + 1] == ' ' || s[i + 1] == '{' || s[i + 1] == '}') {
-            i++;
-            return s[i++];
-        } else if (s[i + 1] != '\0' && s[i + 2] != '\0' && s[i + 3] != '\0' && s[i + 4] != '\0' && s[i + 5] != '\0') {
-            if (std::memcmp(s, "\\(DEL)", 6) == 0) {
-                i += 6;
-                return 127;
-            } else {
-                for (int j = 0; j <= 31; j++) {
-                    if (std::memcmp(s, low_char_encodings[j], 6) == 0) {
-                        i += 6;
-                        return j;
-                    }
-                }
-                // invalid string!
-                return '\0';
-            }
-        } else {
-            // invalid string!
-            return '\0';
-        }
-    } else {
-        return s[i++];
-    }
-}
-
-/*
- * Save a value to a stream
- */
-
-// Fundamental arithmetic data types
-
-void s11n::save(std::ostream& os, bool x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, bool x)
-{
-    os << ' ' << name << '=' << (x ? '1' : '0');
-}
-
-void s11n::save(std::ostream& os, char x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, char x)
-{
-    const char* e = enc_char(x);
-    os << ' ' << name << '=';
-    if (e)
-        os << e;
-    else
-        os << x;
-}
-
-void s11n::save(std::ostream& os, signed char x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, signed char x)
-{
-    os << ' ' << name << '=' << static_cast<int>(x);
-}
-
-void s11n::save(std::ostream& os, unsigned char x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, unsigned char x)
-{
-    os << ' ' << name << '=' << static_cast<int>(x);
-}
-
-void s11n::save(std::ostream& os, short x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, short x)
-{
-    os << ' ' << name << '=' << x;
-}
-
-void s11n::save(std::ostream& os, unsigned short x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, unsigned short x)
-{
-    os << ' ' << name << '=' << x;
-}
-
-void s11n::save(std::ostream& os, int x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, int x)
-{
-    os << ' ' << name << '=' << x;
-}
-
-void s11n::save(std::ostream& os, unsigned int x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, unsigned int x)
-{
-    os << ' ' << name << '=' << x;
-}
-
-void s11n::save(std::ostream& os, long x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, long x)
-{
-    os << ' ' << name << '=' << x;
-}
-
-void s11n::save(std::ostream& os, unsigned long x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, unsigned long x)
-{
-    os << ' ' << name << '=' << x;
-}
-
-void s11n::save(std::ostream& os, long long x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, long long x)
-{
-    os << ' ' << name << '=' << x;
-}
-
-void s11n::save(std::ostream& os, unsigned long long x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, unsigned long long x)
-{
-    os << ' ' << name << '=' << x;
-}
-
-void s11n::save(std::ostream& os, float x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, float x)
-{
-    os << ' ' << name << '=' << str::from(x).c_str();
-}
-
-void s11n::save(std::ostream& os, double x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, double x)
-{
-    os << ' ' << name << '=' << str::from(x).c_str();
-}
-
-void s11n::save(std::ostream& os, long double x)
-{
-    os.write(reinterpret_cast<const char*>(&x), sizeof(x));
-}
-
-void s11n::save(std::ostream& os, const char* name, long double x)
-{
-    os << ' ' << name << '=' << str::from(x).c_str();
-}
-
-// Binary blobs
-
-void s11n::save(std::ostream& os, const void* x, const size_t n)
-{
-    os.write(reinterpret_cast<const char*>(x), n);
-}
-
-void s11n::save(std::ostream& os, const char* name, const void* x, const size_t n)
-{
-    static const char hex[] = "0123456789abcdef";
-    startgroup(os, name);
-    for (size_t i = 0; i < n; i++) {
-        unsigned char val = static_cast<const unsigned char*>(x)[i];
-        os << hex[(val >> 4) & 0xf] << hex[val & 0xf];
-        if (i < n - 1)
-            os << ' ';
-    }
-    endgroup(os);
-}
-
-// Serializable classes
-
-void s11n::save(std::ostream& os, const serializable& x)
-{
-    x.save(os);
-}
-
-void s11n::save(std::ostream& os, const char* name, const serializable& x)
-{
-    x.save(os, name);
-}
-
-// Basic STL types
-
-void s11n::save(std::ostream& os, const std::string& x)
-{
-    size_t s = x.length();
-    os.write(reinterpret_cast<const char*>(&s), sizeof(s));
-    os.write(reinterpret_cast<const char*>(x.data()), s);
-}
-
-void s11n::save(std::ostream& os, const char* name, const std::string& x)
-{
-    os << ' ' << name << '=';
-    for (size_t i = 0; i < x.length(); i++) {
-        char c = x[i];
-        const char* e = enc_char(c);
-        if (e)
-            os << e;
-        else
-            os << c;
-    }
-}
-
-
-/*
- * Load a value from a stream
- */
-
-// Fundamental arithmetic data types
-
-void s11n::load(std::istream& is, bool& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, bool& x)
-{
-    x = str::to<bool>(s);
-}
-
-void s11n::load(std::istream& is, char& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, char& x)
-{
-    size_t i = 0;
-    x = dec_char(s.c_str(), i);
-}
-
-void s11n::load(std::istream& is, signed char& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, signed char& x)
-{
-    x = str::to<int>(s);
-}
-
-void s11n::load(std::istream& is, unsigned char& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, unsigned char& x)
-{
-    x = str::to<unsigned int>(s);
-}
-
-void s11n::load(std::istream& is, short& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, short& x)
-{
-    x = str::to<short>(s);
-}
-
-void s11n::load(std::istream& is, unsigned short& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, unsigned short& x)
-{
-    x = str::to<unsigned short>(s);
-}
-
-void s11n::load(std::istream& is, int& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, int& x)
-{
-    x = str::to<int>(s);
-}
-
-void s11n::load(std::istream& is, unsigned int& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, unsigned int& x)
-{
-    x = str::to<unsigned int>(s);
-}
-
-void s11n::load(std::istream& is, long& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, long& x)
-{
-    x = str::to<long>(s);
-}
-
-void s11n::load(std::istream& is, unsigned long& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, unsigned long& x)
-{
-    x = str::to<unsigned long>(s);
-}
-
-void s11n::load(std::istream& is, long long& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, long long& x)
-{
-    x = str::to<long long>(s);
-}
-
-void s11n::load(std::istream& is, unsigned long long& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, unsigned long long& x)
-{
-    x = str::to<unsigned long long>(s);
-}
-
-void s11n::load(std::istream& is, float& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, float& x)
-{
-    x = str::to<float>(s);
-}
-
-void s11n::load(std::istream& is, double& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, double& x)
-{
-    x = str::to<double>(s);
-}
-
-void s11n::load(std::istream& is, long double& x)
-{
-    is.read(reinterpret_cast<char*>(&x), sizeof(x));
-}
-
-void s11n::load(const std::string& s, long double& x)
-{
-    x = str::to<long double>(s);
-}
-
-// Binary blobs
-
-void s11n::load(std::istream& is, void* x, const size_t n)
-{
-    is.read(reinterpret_cast<char*>(x), n);
-}
-
-void s11n::load(const std::string& s, void* x, const size_t n)
-{
-    std::memset(x, 0, n);
-    size_t i = 0;
-    while (i < n && i + 3 < s.length()) {
-        unsigned char val = 0;
-        if (s[i] == ' ') {
-            i++;
-            if (s[i] >= '0' && s[i] <= '9')
-                val |= (s[i] - '0') << 4;
-            else if (s[i] >= 'a' && s[i] <= 'z')
-                val |= (s[i] - 'a' + 10) << 4;
-            i++;
-            if (s[i] >= '0' && s[i] <= '9')
-                val |= (s[i] - '0');
-            else if (s[i] >= 'a' && s[i] <= 'z')
-                val |= (s[i] - 'a' + 10);
-        }
-        static_cast<unsigned char*>(x)[i] = val;
-    }
-}
-
-// Serializable classes
-
-void s11n::load(std::istream& is, serializable& x)
-{
-    x.load(is);
-}
-
-void s11n::load(const std::string& s, serializable& x)
-{
-    x.load(s);
-}
-
-// Basic STL types
-
-void s11n::load(std::istream& is, std::string& x)
-{
-    size_t s;
-    is.read(reinterpret_cast<char*>(&s), sizeof(s));
-    char* buf = new char[s];
-    is.read(buf, s);
-    x.assign(buf, s);
-    delete[] buf;
-}
-
-void s11n::load(const std::string& s, std::string& x)
-{
-    x.clear();
-    if (s.length() == 0)
-        return;
-    const char *sc = s.c_str();
-    size_t i = 0;
-    while (i < s.length()) {
-        x.append(1, dec_char(sc, i));
-    }
-}
diff --git a/gtatool/src/conv-ffmpeg/s11n.h b/gtatool/src/conv-ffmpeg/s11n.h
deleted file mode 100644 (file)
index 6f39915..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2008, 2009, 2010, 2011, 2012
- * Martin Lambers <marlam@marlam.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef S11N_H
-#define S11N_H
-
-/*
- * This module provides functions s11n::save() and s11n::load() that serialize
- * types and objects.
- * This works for all basic data types, STL types such as std::string, and
- * classes that implement the s11n interface.
- * Additionally, STL containers of serializable types can also be serialized,
- * e.g. std::vector<std::string>.
- */
-
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <vector>
-
-
-class serializable
-{
-public:
-    /*
-     * Interface for serializable classes
-     */
-
-    // Save binary. Efficient. Needs compatible architectures and application versions on the writing and reading end.
-    virtual void save(std::ostream& os) const = 0;
-    virtual void load(std::istream& is) = 0;
-
-    // Save in human-readable and editable text format. Can be used for machine- and application version independent
-    // saving of data. The default implementation falls back on the above binary functions and stores the binary data in
-    // strings.
-    virtual void save(std::ostream& os, const char* name) const;
-    virtual void load(const std::string& s);
-};
-
-namespace s11n
-{
-    // Functions needed to human-readable save/load:
-    // - When saving a group of values contained in a serializable class, use startgroup()/endgroup()
-    // - When loading back, get the next name/value pair and interpret it
-    void startgroup(std::ostream& os, const char* name);
-    void endgroup(std::ostream& os);
-    void load(std::istream& is, std::string& name, std::string& value);
-
-    /*
-     * Save a value to a stream
-     */
-
-    // Fundamental arithmetic data types
-
-    void save(std::ostream& os, bool x);
-    void save(std::ostream& os, const char* name, bool x);
-    void save(std::ostream& os, char x);
-    void save(std::ostream& os, const char* name, char x);
-    void save(std::ostream& os, signed char x);
-    void save(std::ostream& os, const char* name, signed char x);
-    void save(std::ostream& os, unsigned char x);
-    void save(std::ostream& os, const char* name, unsigned char x);
-    void save(std::ostream& os, short x);
-    void save(std::ostream& os, const char* name, short x);
-    void save(std::ostream& os, unsigned short x);
-    void save(std::ostream& os, const char* name, unsigned short x);
-    void save(std::ostream& os, int x);
-    void save(std::ostream& os, const char* name, int x);
-    void save(std::ostream& os, unsigned int x);
-    void save(std::ostream& os, const char* name, unsigned int x);
-    void save(std::ostream& os, long x);
-    void save(std::ostream& os, const char* name, long x);
-    void save(std::ostream& os, unsigned long x);
-    void save(std::ostream& os, const char* name, unsigned long x);
-    void save(std::ostream& os, long long x);
-    void save(std::ostream& os, const char* name, long long x);
-    void save(std::ostream& os, unsigned long long x);
-    void save(std::ostream& os, const char* name, unsigned long long x);
-    void save(std::ostream& os, float x);
-    void save(std::ostream& os, const char* name, float x);
-    void save(std::ostream& os, double x);
-    void save(std::ostream& os, const char* name, double x);
-    void save(std::ostream& os, long double x);
-    void save(std::ostream& os, const char* name, long double x);
-
-    // Binary blobs
-
-    void save(std::ostream& os, const void* x, const size_t n);
-    void save(std::ostream& os, const char* name, const void* x, const size_t n);
-
-    // Serializable classes
-
-    void save(std::ostream& os, const serializable& x);
-    void save(std::ostream& os, const char* name, const serializable& x);
-
-    // Basic STL types
-
-    void save(std::ostream& os, const std::string& x);
-    void save(std::ostream& os, const char* name, const std::string& x);
-
-    // STL containters
-
-    template<typename T>
-    void save(std::ostream& os, const std::vector<T>& x)
-    {
-        size_t s = x.size();
-        save(os, s);
-        for (size_t i = 0; i < s; i++) {
-            save(os, x[i]);
-        }
-    }
-
-    template<typename T>
-    void save(std::ostream& os, const char* name, const std::vector<T>& x)
-    {
-        size_t s = x.size();
-        startgroup(os, name);
-        save(os, "size", s);
-        for (size_t i = 0; i < s; i++) {
-            save(os, "", x[i]);
-        }
-        endgroup(os);
-    }
-
-    // TODO: add more STL containers as needed
-
-    /*
-     * Load a value from a stream
-     */
-
-    // Fundamental arithmetic data types
-
-    void load(std::istream& is, bool& x);
-    void load(const std::string& s, bool& x);
-    void load(std::istream& is, char& x);
-    void load(const std::string& s, char& x);
-    void load(std::istream& is, signed char& x);
-    void load(const std::string& s, signed char& x);
-    void load(std::istream& is, unsigned char& x);
-    void load(const std::string& s, unsigned char& x);
-    void load(std::istream& is, short& x);
-    void load(const std::string& s, short& x);
-    void load(std::istream& is, unsigned short& x);
-    void load(const std::string& s, unsigned short& x);
-    void load(std::istream& is, int& x);
-    void load(const std::string& s, int& x);
-    void load(std::istream& is, unsigned int& x);
-    void load(const std::string& s, unsigned int& x);
-    void load(std::istream& is, long& x);
-    void load(const std::string& s, long& x);
-    void load(std::istream& is, unsigned long& x);
-    void load(const std::string& s, unsigned long& x);
-    void load(std::istream& is, long long& x);
-    void load(const std::string& s, long long& x);
-    void load(std::istream& is, unsigned long long& x);
-    void load(const std::string& s, unsigned long long& x);
-    void load(std::istream& is, float& x);
-    void load(const std::string& s, float& x);
-    void load(std::istream& is, double& x);
-    void load(const std::string& s, double& x);
-    void load(std::istream& is, long double& x);
-    void load(const std::string& s, long double& x);
-
-    // Binary blobs
-
-    void load(std::istream& is, void* x, const size_t n);
-    void load(const std::string& s, void* x, const size_t n);
-
-    // Serializable classes
-
-    void load(std::istream& is, serializable& x);
-    void load(const std::string& s, serializable& x);
-
-    // Basic STL types
-
-    void load(std::istream& is, std::string& x);
-    void load(const std::string& s, std::string& x);
-
-    // STL containers
-
-    template<typename T>
-    void load(std::istream& is, std::vector<T>& x)
-    {
-        x.clear();
-        size_t s;
-        load(is, s);
-        for (size_t i = 0; i < s; i++) {
-            T v;
-            load(is, v);
-            x.push_back(v);
-        }
-    }
-
-    template<typename T>
-    void load(const std::string& s, std::vector<T>& x)
-    {
-        std::stringstream ss(s);
-        std::string name, value;
-        size_t z = 0;
-        load(ss, name, value);
-        if (name == "size")
-            load(value, z);
-        size_t i = 0;
-        while (ss.good() && i < z) {
-            load(ss, name, value);
-            T v;
-            load(value, v);
-            x.push_back(v);
-            i++;
-        }
-        x.resize(z);
-    }
-
-    // TODO: add more STL containers as needed
-
-    // Convenience wrappers: directly return a loaded value
-
-    template<typename T>
-    T load(std::istream& is)
-    {
-        T x;
-        load(is, x);
-        return x;
-    }
-
-    template<typename T>
-    T load(const std::string& s)
-    {
-        T x;
-        load(s, x);
-        return x;
-    }
-};
-
-#endif
diff --git a/gtatool/src/conv-ffmpeg/thread.cpp b/gtatool/src/conv-ffmpeg/thread.cpp
deleted file mode 100644 (file)
index da1f2bf..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2011, 2012
- * Martin Lambers <marlam@marlam.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <cerrno>
-#include <cstring>
-#include <pthread.h>
-#include <sched.h>
-
-#include "base/gettext.h"
-#define _(string) gettext(string)
-
-#include "thread.h"
-
-
-const pthread_mutex_t mutex::_mutex_initializer = PTHREAD_MUTEX_INITIALIZER;
-
-mutex::mutex() : _mutex(_mutex_initializer)
-{
-    int e = pthread_mutex_init(&_mutex, NULL);
-    if (e != 0)
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_mutex_init(): " + std::strerror(e), e);
-}
-
-mutex::mutex(const mutex&) : _mutex(_mutex_initializer)
-{
-    // You cannot have multiple copies of the same mutex.
-    // Instead, we create a new one. This allows easier use of mutexes in STL containers.
-    int e = pthread_mutex_init(&_mutex, NULL);
-    if (e != 0)
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_mutex_init(): " + std::strerror(e), e);
-}
-
-mutex::~mutex()
-{
-    (void)pthread_mutex_destroy(&_mutex);
-}
-
-void mutex::lock()
-{
-    int e = pthread_mutex_lock(&_mutex);
-    if (e != 0)
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_mutex_lock(): " + std::strerror(e), e);
-}
-
-bool mutex::trylock()
-{
-    return (pthread_mutex_trylock(&_mutex) == 0);
-}
-
-void mutex::unlock()
-{
-    int e = pthread_mutex_unlock(&_mutex);
-    if (e != 0)
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_mutex_unlock(): " + std::strerror(e), e);
-}
-
-
-const pthread_cond_t condition::_cond_initializer = PTHREAD_COND_INITIALIZER;
-
-condition::condition() : _cond(_cond_initializer)
-{
-    int e = pthread_cond_init(&_cond, NULL);
-    if (e != 0)
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_cond_init(): " + std::strerror(e), e);
-}
-
-condition::condition(const condition&) : _cond(_cond_initializer)
-{
-    // You cannot have multiple copies of the same condition.
-    // Instead, we create a new one. This allows easier use of conditions in STL containers.
-    int e = pthread_cond_init(&_cond, NULL);
-    if (e != 0)
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_cond_init(): " + std::strerror(e), e);
-}
-
-condition::~condition()
-{
-    (void)pthread_cond_destroy(&_cond);
-}
-
-void condition::wait(mutex& m)
-{
-    int e = pthread_cond_wait(&_cond, &m._mutex);
-    if (e != 0)
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_cond_wait(): " + std::strerror(e), e);
-}
-
-void condition::wake_one()
-{
-    int e = pthread_cond_signal(&_cond);
-    if (e != 0)
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_cond_signal(): " + std::strerror(e), e);
-}
-
-void condition::wake_all()
-{
-    int e = pthread_cond_broadcast(&_cond);
-    if (e != 0)
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_cond_broadcast(): " + std::strerror(e), e);
-}
-
-
-const int thread::priority_default;
-const int thread::priority_min;
-
-thread::thread() :
-    __thread_id(pthread_self()),
-    __joinable(false),
-    __running(false),
-    __wait_mutex(),
-    __exception()
-{
-}
-
-thread::thread(const thread&) :
-    __thread_id(pthread_self()),
-    __joinable(false),
-    __running(false),
-    __wait_mutex(),
-    __exception()
-{
-    // The thread state cannot be copied; a new state is created instead.
-}
-
-thread::~thread()
-{
-    if (__joinable)
-        (void)pthread_detach(__thread_id);
-}
-
-void* thread::__run(void* p)
-{
-    thread* t = static_cast<thread*>(p);
-    try {
-        t->run();
-    }
-    catch (exc& e) {
-        t->__exception = e;
-    }
-    catch (std::exception& e) {
-        t->__exception = e;
-    }
-    catch (...) {
-        // We must assume this means thread cancellation. In this
-        // case, we *must* rethrow the exception.
-        t->__running = false;
-        throw;
-    }
-    t->__running = false;
-    return NULL;
-}
-
-void thread::start(int priority)
-{
-    if (atomic::bool_compare_and_swap(&__running, false, true)) {
-        wait();
-        int e;
-        pthread_attr_t priority_thread_attr;
-        pthread_attr_t* thread_attr = NULL;
-        if (priority != priority_default)
-        {
-            // Currently this means priority_min
-            int policy, min_priority;
-            struct sched_param param;
-            e = pthread_attr_init(&priority_thread_attr);
-            e = e || pthread_attr_getschedpolicy(&priority_thread_attr, &policy);
-            if (e == 0) {
-                min_priority = sched_get_priority_min(policy);
-                if (min_priority == -1)
-                    e = errno;
-            }
-            e = e || pthread_attr_getschedparam(&priority_thread_attr, &param);
-            if (e == 0) {
-                param.sched_priority = min_priority;
-            }
-            e = e || pthread_attr_setschedparam(&priority_thread_attr, &param);
-            if (e != 0) {
-                throw exc(std::string(_("System function failed: "))
-                        + "pthread_attr_*(): " + std::strerror(e), e);
-            }
-            thread_attr = &priority_thread_attr;
-        }
-        e = pthread_create(&__thread_id, thread_attr, __run, this);
-        if (e != 0) {
-            throw exc(std::string(_("System function failed: "))
-                    + "pthread_create(): " + std::strerror(e), e);
-        }
-        __joinable = true;
-    }
-}
-
-void thread::wait()
-{
-    __wait_mutex.lock();
-    if (atomic::bool_compare_and_swap(&__joinable, true, false)) {
-        int e = pthread_join(__thread_id, NULL);
-        if (e != 0) {
-            __wait_mutex.unlock();
-            throw exc(std::string(_("System function failed: "))
-                    + "pthread_join(): " + std::strerror(e), e);
-        }
-    }
-    __wait_mutex.unlock();
-}
-
-void thread::finish()
-{
-    wait();
-    if (!exception().empty())
-        throw exception();
-}
-
-void thread::cancel()
-{
-    __wait_mutex.lock();
-    int e = pthread_cancel(__thread_id);
-    if (e != 0) {
-        __wait_mutex.unlock();
-        throw exc(std::string(_("System function failed: "))
-                + "pthread_cancel(): " + std::strerror(e), e);
-    }
-    __wait_mutex.unlock();
-}
-
-
-thread_group::thread_group(unsigned char size) : __max_size(size)
-{
-    __active_threads.reserve(__max_size);
-    __finished_threads.reserve(__max_size);
-}
-
-thread_group::~thread_group()
-{
-    try {
-        for (size_t i = 0; i < __active_threads.size(); i++) {
-            __active_threads[i]->cancel();
-        }
-    }
-    catch (...) {
-    }
-}
-
-bool thread_group::start(thread* t, int priority)
-{
-    if (__active_threads.size() < __max_size) {
-        t->start(priority);
-        __active_threads.push_back(t);
-        return true;
-    } else {
-        return false;
-    }
-}
-
-thread* thread_group::get_next_finished_thread()
-{
-    if (__finished_threads.size() == 0) {
-        std::vector<thread*>::iterator it = __active_threads.begin();
-        while (it != __active_threads.end()) {
-            if (!(*it)->is_running()) {
-                __finished_threads.push_back(*it);
-                it = __active_threads.erase(it);
-            } else {
-                it++;
-            }
-        }
-    }
-    if (__finished_threads.size() > 0) {
-        thread* ret = __finished_threads.back();
-        __finished_threads.pop_back();
-        return ret;
-    } else {
-        return NULL;
-    }
-}
diff --git a/gtatool/src/conv-ffmpeg/thread.h b/gtatool/src/conv-ffmpeg/thread.h
deleted file mode 100644 (file)
index fc0678c..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2011, 2012
- * Martin Lambers <marlam@marlam.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef THREADS_H
-#define THREADS_H
-
-#include <vector>
-#include <pthread.h>
-
-#include "base/exc.h"
-
-
-/*
- * Atomic operations
- */
-
-namespace atomic
-{
-    // TODO
-    //
-    // Currently this is just an interface to the GCC atomic builtin functions; see
-    // http://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Atomic-Builtins.html#Atomic-Builtins
-    //
-    // This must be extended when (if) other compilers are used some day.
-    //
-    // The functions obviously only work for basic data types.
-    // The comments were copied from the GCC manual referenced above.
-
-    /* The following functions perform the operation suggested by the name,
-     * and return the value that had previously been in memory. */
-    template<typename T> T fetch_and_add(T* ptr, T value) { return __sync_fetch_and_add(ptr, value); }
-    template<typename T> T fetch_and_sub(T* ptr, T value) { return __sync_fetch_and_sub(ptr, value); }
-    template<typename T> T fetch_and_or(T* ptr, T value) { return __sync_fetch_and_or(ptr, value); }
-    template<typename T> T fetch_and_and(T* ptr, T value) { return __sync_fetch_and_and(ptr, value); }
-    template<typename T> T fetch_and_xor(T* ptr, T value) { return __sync_fetch_and_xor(ptr, value); }
-    template<typename T> T fetch_and_nand(T* ptr, T value) { return __sync_fetch_and_nand(ptr, value); }
-
-    /* The following functions perform the operation suggested by the name,
-     * and return the new value. */
-    template<typename T> T add_and_fetch(T* ptr, T value) { return __sync_add_and_fetch(ptr, value); }
-    template<typename T> T sub_and_fetch(T* ptr, T value) { return __sync_sub_and_fetch(ptr, value); }
-    template<typename T> T or_and_fetch(T* ptr, T value) { return __sync_or_and_fetch(ptr, value); }
-    template<typename T> T and_and_fetch(T* ptr, T value) { return __sync_and_and_fetch(ptr, value); }
-    template<typename T> T xor_and_fetch(T* ptr, T value) { return __sync_xor_and_fetch(ptr, value); }
-    template<typename T> T nand_and_fetch(T* ptr, T value) { return __sync_nand_and_fetch(ptr, value); }
-
-    /* The following functions perform an atomic compare and swap.
-     * That is, if the current value of *ptr is oldval, then write newval into *ptr.
-     * The "bool" version returns true if the comparison is successful and newval was written.
-     * The "val" version returns the contents of *ptr before the operation. */
-    template<typename T> bool bool_compare_and_swap(T* ptr, T oldval, T newval) { return __sync_bool_compare_and_swap(ptr, oldval, newval); }
-    template<typename T> T val_compare_and_swap(T* ptr, T oldval, T newval) { return __sync_val_compare_and_swap(ptr, oldval, newval); }
-
-    /* The following are convenience functions implemented on top of the above
-     * basic atomic operations. */
-    template<typename T> T fetch_and_inc(T* ptr) { return fetch_and_add(ptr, static_cast<T>(1)); }
-    template<typename T> T inc_and_fetch(T* ptr) { return add_and_fetch(ptr, static_cast<T>(1)); }
-    template<typename T> T fetch_and_dec(T* ptr) { return fetch_and_sub(ptr, static_cast<T>(1)); }
-    template<typename T> T dec_and_fetch(T* ptr) { return sub_and_fetch(ptr, static_cast<T>(1)); }
-}
-
-
-/*
- * Mutex
- */
-
-class mutex
-{
-private:
-    static const pthread_mutex_t _mutex_initializer;
-    pthread_mutex_t _mutex;
-
-public:
-    // Constructor / Destructor
-    mutex();
-    mutex(const mutex& m);
-    ~mutex();
-
-    // Lock the mutex.
-    void lock();
-    // Try to lock the mutex. Return true on success, false otherwise.
-    bool trylock();
-    // Unlock the mutex
-    void unlock();
-
-    friend class condition;
-};
-
-
-/*
- * Wait condition
- */
-
-class condition
-{
-private:
-    static const pthread_cond_t _cond_initializer;
-    pthread_cond_t _cond;
-
-public:
-    // Constructor / Destructor
-    condition();
-    condition(const condition& c);
-    ~condition();
-
-    // Wait for the condition. The calling thread must have the mutex locked.
-    void wait(mutex& m);
-    // Wake one thread that waits on the condition.
-    void wake_one();
-    // Wake all threads that wait on the condition.
-    void wake_all();
-};
-
-
-/*
- * Thread
- *
- * Implement the run() function in a subclass.
- */
-
-class thread
-{
-private:
-    pthread_t __thread_id;
-    bool __joinable;
-    bool __running;
-    mutex __wait_mutex;
-    exc __exception;
-
-    static void* __run(void* p);
-
-public:
-    // Priorities
-    static const int priority_default = 0;
-    static const int priority_min = 1;
-
-    // Constructor / Destructor
-    thread();
-    thread(const thread& t);
-    virtual ~thread();
-
-    // Implement this in a subclass; it will be executed from the thread via start()
-    virtual void run() = 0;
-
-    // Start a new thread that executes the run() function. If the thread is already
-    // running, this function does nothing.
-    void start(int priority = thread::priority_default);
-
-    // Returns whether this thread is currently running.
-    bool is_running()
-    {
-        return __running;
-    }
-
-    // Wait for the thread to finish. If the thread is not running, this function
-    // returns immediately.
-    void wait();
-
-    // Wait for the thread to finish, like wait(), and rethrow an exception that the
-    // run() function might have thrown during its execution.
-    void finish();
-
-    // Cancel a thread. This is dangerous and should not be used.
-    void cancel();
-
-    // Get an exception that the run() function might have thrown.
-    const exc& exception() const
-    {
-        return __exception;
-    }
-    // Modify the stored exception
-    exc& exception()
-    {
-        return __exception;
-    }
-};
-
-
-/*
- * Thread group.
- *
- * This manages a group of threads that has a fixed maximum size. New threads
- * can only be started if there are still free slots in the group. A finished
- * thread makes its slot available for future threads.
- *
- * A thread group must be managed from a single thread. When the thread group
- * object is destroyed, all remaining threads are cancelled.
- */
-
-class thread_group
-{
-private:
-    unsigned char __max_size;
-    std::vector<thread*> __active_threads;
-    std::vector<thread*> __finished_threads;
-
-public:
-    thread_group(unsigned char size);
-    virtual ~thread_group();
-
-    // Start a new thread and return its slot number. If there are no free
-    // slots, the thread is not started and false is returned.
-    bool start(thread* t, int priority = thread::priority_default);
-
-    // Return a finished thread object from the group and free its slot so
-    // that future threads can use it. If there is no finished thread, NULL
-    // is returned.
-    thread* get_next_finished_thread();
-};
-
-#endif
index 81940b5..681f5ed 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013
+ * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2015
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
index 86693d9..21a265b 100644 (file)
@@ -35,7 +35,7 @@
 # include <windows.h>
 #endif
 
-#include "sys.h"
+#include "base/sys.h"
 
 
 uintmax_t sys::total_ram()
index ceeea23..7dc8ab5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2011, 2012, 2013
+ * Copyright (C) 2010, 2011, 2012, 2013, 2015
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
 # include <sys/time.h>
 #endif
 
-#include "base/gettext.h"
-#define _(string) gettext(string)
-
 #include "base/exc.h"
 #include "base/tmr.h"
 
+#include "base/gettext.h"
+#define _(string) gettext(string)
+
 
 long long timer::get(timer::type t)
 {
index faed302..f374c75 100644 (file)
 namespace glvm
 {
     /* Basic numeric constants. Values copied from /usr/include/math.h on a recent GNU/Linux system. */
-    template<typename T> inline T const_e();       /* e */
-    template<> inline long double const_e<long double>() { return 2.7182818284590452353602874713526625L; }
-    template<> inline double const_e<double>() { return static_cast<double>(const_e<long double>()); }
-    template<> inline float const_e<float>() { return static_cast<float>(const_e<long double>()); }
-    template<typename T> inline T const_log2e();   /* log_2 e */
-    template<> inline long double const_log2e<long double>() { return 1.4426950408889634073599246810018921L; }
-    template<> inline double const_log2e<double>() { return const_log2e<long double>(); }
-    template<> inline float const_log2e<float>() { return const_log2e<long double>(); }
-    template<typename T> inline T const_log10e();  /* log_10 e */
-    template<> inline long double const_log10e<long double>() { return 0.4342944819032518276511289189166051L; }
-    template<> inline double const_log10e<double>() { return const_log10e<long double>(); }
-    template<> inline float const_log10e<float>() { return const_log10e<long double>(); }
-    template<typename T> inline T const_ln2();     /* log_e 2 */
-    template<> inline long double const_ln2<long double>() { return 0.6931471805599453094172321214581766L; }
-    template<> inline double const_ln2<double>() { return const_ln2<long double>(); }
-    template<> inline float const_ln2<float>() { return const_ln2<long double>(); }
-    template<typename T> inline T const_ln10();    /* log_e 10 */
-    template<> inline long double const_ln10<long double>() { return 2.3025850929940456840179914546843642L; }
-    template<> inline double const_ln10<double>() { return const_ln10<long double>(); }
-    template<> inline float const_ln10<float>() { return const_ln10<long double>(); }
-    template<typename T> inline T const_pi();      /* pi */
-    template<> inline long double const_pi<long double>() { return 3.1415926535897932384626433832795029L; }
-    template<> inline double const_pi<double>() { return const_pi<long double>(); }
-    template<> inline float const_pi<float>() { return const_pi<long double>(); }
-    template<typename T> inline T const_pi_2();    /* pi / 2 */
-    template<> inline long double const_pi_2<long double>() { return 1.5707963267948966192313216916397514L; }
-    template<> inline double const_pi_2<double>() { return const_pi_2<long double>(); }
-    template<> inline float const_pi_2<float>() { return const_pi_2<long double>(); }
-    template<typename T> inline T const_pi_4();    /* pi / 4 */
-    template<> inline long double const_pi_4<long double>() { return 0.7853981633974483096156608458198757L; }
-    template<> inline double const_pi_4<double>() { return const_pi_4<long double>(); }
-    template<> inline float const_pi_4<float>() { return const_pi_4<long double>(); }
-    template<typename T> inline T const_1_pi();    /* 1 / pi */
-    template<> inline long double const_1_pi<long double>() { return 0.3183098861837906715377675267450287L; }
-    template<> inline double const_1_pi<double>() { return const_1_pi<long double>(); }
-    template<> inline float const_1_pi<float>() { return const_1_pi<long double>(); }
-    template<typename T> inline T const_2_pi();    /* 2 / pi */
-    template<> inline long double const_2_pi<long double>() { return 0.6366197723675813430755350534900574L; }
-    template<> inline double const_2_pi<double>() { return const_2_pi<long double>(); }
-    template<> inline float const_2_pi<float>() { return const_2_pi<long double>(); }
-    template<typename T> inline T const_2_sqrtpi(); /* 2 / sqrt(pi) */
-    template<> inline long double const_2_sqrtpi<long double>() { return 1.1283791670955125738961589031215452L; }
-    template<> inline double const_2_sqrtpi<double>() { return const_2_sqrtpi<long double>(); }
-    template<> inline float const_2_sqrtpi<float>() { return const_2_sqrtpi<long double>(); }
-    template<typename T> inline T const_sqrt2();    /* sqrt(2) */
-    template<> inline long double const_sqrt2<long double>() { return 1.4142135623730950488016887242096981L; }
-    template<> inline double const_sqrt2<double>() { return const_sqrt2<long double>(); }
-    template<> inline float const_sqrt2<float>() { return const_sqrt2<long double>(); }
-    template<typename T> inline T const_sqrt1_2();  /* 1 / sqrt(2) */
-    template<> inline long double const_sqrt1_2<long double>() { return 0.7071067811865475244008443621048490L; }
-    template<> inline double const_sqrt1_2<double>() { return const_sqrt1_2<long double>(); }
-    template<> inline float const_sqrt1_2<float>() { return const_sqrt1_2<long double>(); }
+    namespace constants
+    {
+        template<typename T> constexpr T e();       /* e */
+        template<> constexpr long double e<long double>() { return 2.7182818284590452353602874713526625L; }
+        template<> constexpr double e<double>() { return static_cast<double>(e<long double>()); }
+        template<> constexpr float e<float>() { return static_cast<float>(e<long double>()); }
+        template<typename T> constexpr T log2e();   /* log_2 e */
+        template<> constexpr long double log2e<long double>() { return 1.4426950408889634073599246810018921L; }
+        template<> constexpr double log2e<double>() { return static_cast<double>(log2e<long double>()); }
+        template<> constexpr float log2e<float>() { return static_cast<float>(log2e<long double>()); }
+        template<typename T> constexpr T log10e();  /* log_10 e */
+        template<> constexpr long double log10e<long double>() { return 0.4342944819032518276511289189166051L; }
+        template<> constexpr double log10e<double>() { return static_cast<double>(log10e<long double>()); }
+        template<> constexpr float log10e<float>() { return static_cast<float>(log10e<long double>()); }
+        template<typename T> constexpr T ln2();     /* log_e 2 */
+        template<> constexpr long double ln2<long double>() { return 0.6931471805599453094172321214581766L; }
+        template<> constexpr double ln2<double>() { return static_cast<double>(ln2<long double>()); }
+        template<> constexpr float ln2<float>() { return static_cast<float>(ln2<long double>()); }
+        template<typename T> constexpr T ln10();    /* log_e 10 */
+        template<> constexpr long double ln10<long double>() { return 2.3025850929940456840179914546843642L; }
+        template<> constexpr double ln10<double>() { return static_cast<double>(ln10<long double>()); }
+        template<> constexpr float ln10<float>() { return static_cast<float>(ln10<long double>()); }
+        template<typename T> constexpr T pi();      /* pi */
+        template<> constexpr long double pi<long double>() { return 3.1415926535897932384626433832795029L; }
+        template<> constexpr double pi<double>() { return static_cast<double>(pi<long double>()); }
+        template<> constexpr float pi<float>() { return static_cast<float>(pi<long double>()); }
+        template<typename T> constexpr T pi_div_2();    /* pi / 2 */
+        template<> constexpr long double pi_div_2<long double>() { return 1.5707963267948966192313216916397514L; }
+        template<> constexpr double pi_div_2<double>() { return static_cast<double>(pi_div_2<long double>()); }
+        template<> constexpr float pi_div_2<float>() { return static_cast<float>(pi_div_2<long double>()); }
+        template<typename T> constexpr T pi_div_4();    /* pi / 4 */
+        template<> constexpr long double pi_div_4<long double>() { return 0.7853981633974483096156608458198757L; }
+        template<> constexpr double pi_div_4<double>() { return static_cast<double>(pi_div_4<long double>()); }
+        template<> constexpr float pi_div_4<float>() { return static_cast<float>(pi_div_4<long double>()); }
+        template<typename T> constexpr T one_div_pi();    /* 1 / pi */
+        template<> constexpr long double one_div_pi<long double>() { return 0.3183098861837906715377675267450287L; }
+        template<> constexpr double one_div_pi<double>() { return static_cast<double>(one_div_pi<long double>()); }
+        template<> constexpr float one_div_pi<float>() { return static_cast<float>(one_div_pi<long double>()); }
+        template<typename T> constexpr T two_div_pi();    /* 2 / pi */
+        template<> constexpr long double two_div_pi<long double>() { return 0.6366197723675813430755350534900574L; }
+        template<> constexpr double two_div_pi<double>() { return static_cast<double>(two_div_pi<long double>()); }
+        template<> constexpr float two_div_pi<float>() { return static_cast<float>(two_div_pi<long double>()); }
+        template<typename T> constexpr T two_div_sqrtpi(); /* 2 / sqrt(pi) */
+        template<> constexpr long double two_div_sqrtpi<long double>() { return 1.1283791670955125738961589031215452L; }
+        template<> constexpr double two_div_sqrtpi<double>() { return static_cast<double>(two_div_sqrtpi<long double>()); }
+        template<> constexpr float two_div_sqrtpi<float>() { return static_cast<float>(two_div_sqrtpi<long double>()); }
+        template<typename T> constexpr T sqrt2();    /* sqrt(2) */
+        template<> constexpr long double sqrt2<long double>() { return 1.4142135623730950488016887242096981L; }
+        template<> constexpr double sqrt2<double>() { return static_cast<double>(sqrt2<long double>()); }
+        template<> constexpr float sqrt2<float>() { return static_cast<float>(sqrt2<long double>()); }
+        template<typename T> constexpr T one_div_sqrt2();  /* 1 / sqrt(2) */
+        template<> constexpr long double one_div_sqrt2<long double>() { return 0.7071067811865475244008443621048490L; }
+        template<> constexpr double one_div_sqrt2<double>() { return static_cast<double>(one_div_sqrt2<long double>()); }
+        template<> constexpr float one_div_sqrt2<float>() { return static_cast<float>(one_div_sqrt2<long double>()); }
+    }
 
     /* Define the GLSL functions for the subset of the base data types
      * for which the function makes sense. The base data types are:
@@ -119,474 +122,474 @@ namespace glvm
      * float, double, long double
      */
 
-    inline signed char min(signed char x, signed char y)
+    constexpr signed char min(signed char x, signed char y)
     {
         return (x < y ? x : y);
     }
 
-    inline unsigned char min(unsigned char x, unsigned char y)
+    constexpr unsigned char min(unsigned char x, unsigned char y)
     {
         return (x < y ? x : y);
     }
 
-    inline short min(short x, short y)
+    constexpr short min(short x, short y)
     {
         return (x < y ? x : y);
     }
 
-    inline unsigned short min(unsigned short x, unsigned short y)
+    constexpr unsigned short min(unsigned short x, unsigned short y)
     {
         return (x < y ? x : y);
     }
 
-    inline int min(int x, int y)
+    constexpr int min(int x, int y)
     {
         return (x < y ? x : y);
     }
 
-    inline unsigned int min(unsigned int x, unsigned int y)
+    constexpr unsigned int min(unsigned int x, unsigned int y)
     {
         return (x < y ? x : y);
     }
 
-    inline long min(long x, long y)
+    constexpr long min(long x, long y)
     {
         return (x < y ? x : y);
     }
 
-    inline unsigned long min(unsigned long x, unsigned long y)
+    constexpr unsigned long min(unsigned long x, unsigned long y)
     {
         return (x < y ? x : y);
     }
 
-    inline long long min(long long x, long long y)
+    constexpr long long min(long long x, long long y)
     {
         return (x < y ? x : y);
     }
 
-    inline unsigned long long min(unsigned long long x, unsigned long long y)
+    constexpr unsigned long long min(unsigned long long x, unsigned long long y)
     {
         return (x < y ? x : y);
     }
 
-    inline float min(float x, float y)
+    constexpr float min(float x, float y)
     {
         return (x < y ? x : y);
     }
 
-    inline double min(double x, double y)
+    constexpr double min(double x, double y)
     {
         return (x < y ? x : y);
     }
 
-    inline long double min(long double x, long double y)
+    constexpr long double min(long double x, long double y)
     {
         return (x < y ? x : y);
     }
 
     // Bonus: min() for 3 and 4 arguments
-    template<typename T> inline T min(T x, T y, T z) { return min(min(x, y), z); }
-    template<typename T> inline T min(T x, T y, T z, T w) { return min(min(min(x, y), z), w); }
+    template<typename T> constexpr T min(T x, T y, T z) { return min(min(x, y), z); }
+    template<typename T> constexpr T min(T x, T y, T z, T w) { return min(min(min(x, y), z), w); }
 
-    inline signed char max(signed char x, signed char y)
+    constexpr signed char max(signed char x, signed char y)
     {
         return (x > y ? x : y);
     }
 
-    inline unsigned char max(unsigned char x, unsigned char y)
+    constexpr unsigned char max(unsigned char x, unsigned char y)
     {
         return (x > y ? x : y);
     }
 
-    inline short max(short x, short y)
+    constexpr short max(short x, short y)
     {
         return (x > y ? x : y);
     }
 
-    inline unsigned short max(unsigned short x, unsigned short y)
+    constexpr unsigned short max(unsigned short x, unsigned short y)
     {
         return (x > y ? x : y);
     }
 
-    inline int max(int x, int y)
+    constexpr int max(int x, int y)
     {
         return (x > y ? x : y);
     }
 
-    inline unsigned int max(unsigned int x, unsigned int y)
+    constexpr unsigned int max(unsigned int x, unsigned int y)
     {
         return (x > y ? x : y);
     }
 
-    inline long max(long x, long y)
+    constexpr long max(long x, long y)
     {
         return (x > y ? x : y);
     }
 
-    inline unsigned long max(unsigned long x, unsigned long y)
+    constexpr unsigned long max(unsigned long x, unsigned long y)
     {
         return (x > y ? x : y);
     }
 
-    inline long long max(long long x, long long y)
+    constexpr long long max(long long x, long long y)
     {
         return (x > y ? x : y);
     }
 
-    inline unsigned long long max(unsigned long long x, unsigned long long y)
+    constexpr unsigned long long max(unsigned long long x, unsigned long long y)
     {
         return (x > y ? x : y);
     }
 
-    inline float max(float x, float y)
+    constexpr float max(float x, float y)
     {
         return (x > y ? x : y);
     }
 
-    inline double max(double x, double y)
+    constexpr double max(double x, double y)
     {
         return (x > y ? x : y);
     }
 
-    inline long double max(long double x, long double y)
+    constexpr long double max(long double x, long double y)
     {
         return (x > y ? x : y);
     }
 
     // Bonus: max() for 3 and 4 arguments
-    template<typename T> inline T max(T x, T y, T z) { return max(max(x, y), z); }
-    template<typename T> inline T max(T x, T y, T z, T w) { return max(max(max(x, y), z), w); }
+    template<typename T> constexpr T max(T x, T y, T z) { return max(max(x, y), z); }
+    template<typename T> constexpr T max(T x, T y, T z, T w) { return max(max(max(x, y), z), w); }
 
-    inline signed char clamp(signed char x, signed char minval, signed char maxval)
+    constexpr signed char clamp(signed char x, signed char minval, signed char maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline unsigned char clamp(unsigned char x, unsigned char minval, unsigned char maxval)
+    constexpr unsigned char clamp(unsigned char x, unsigned char minval, unsigned char maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline short clamp(short x, short minval, short maxval)
+    constexpr short clamp(short x, short minval, short maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline unsigned short clamp(unsigned short x, unsigned short minval, unsigned short maxval)
+    constexpr unsigned short clamp(unsigned short x, unsigned short minval, unsigned short maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline int clamp(int x, int minval, int maxval)
+    constexpr int clamp(int x, int minval, int maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline unsigned int clamp(unsigned int x, unsigned int minval, unsigned int maxval)
+    constexpr unsigned int clamp(unsigned int x, unsigned int minval, unsigned int maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline long clamp(long x, long minval, long maxval)
+    constexpr long clamp(long x, long minval, long maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline unsigned long clamp(unsigned long x, unsigned long minval, unsigned long maxval)
+    constexpr unsigned long clamp(unsigned long x, unsigned long minval, unsigned long maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline long long clamp(long long x, long long minval, long long maxval)
+    constexpr long long clamp(long long x, long long minval, long long maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline unsigned long long clamp(unsigned long long x, unsigned long long minval, unsigned long long maxval)
+    constexpr unsigned long long clamp(unsigned long long x, unsigned long long minval, unsigned long long maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline float clamp(float x, float minval, float maxval)
+    constexpr float clamp(float x, float minval, float maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline double clamp(double x, double minval, double maxval)
+    constexpr double clamp(double x, double minval, double maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline long double clamp(long double x, long double minval, long double maxval)
+    constexpr long double clamp(long double x, long double minval, long double maxval)
     {
         return min(maxval, max(minval, x));
     }
 
-    inline signed char step(signed char x, signed char edge)
+    constexpr signed char step(signed char x, signed char edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline unsigned char step(unsigned char x, unsigned char edge)
+    constexpr unsigned char step(unsigned char x, unsigned char edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline short step(short x, short edge)
+    constexpr short step(short x, short edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline unsigned short step(unsigned short x, unsigned short edge)
+    constexpr unsigned short step(unsigned short x, unsigned short edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline int step(int x, int edge)
+    constexpr int step(int x, int edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline unsigned int step(unsigned int x, unsigned int edge)
+    constexpr unsigned int step(unsigned int x, unsigned int edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline long step(long x, long edge)
+    constexpr long step(long x, long edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline unsigned long step(unsigned long x, unsigned long edge)
+    constexpr unsigned long step(unsigned long x, unsigned long edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline long long step(long long x, long long edge)
+    constexpr long long step(long long x, long long edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline unsigned long long step(unsigned long long x, unsigned long long edge)
+    constexpr unsigned long long step(unsigned long long x, unsigned long long edge)
     {
         return (x < edge ? 0 : 1);
     }
 
-    inline float step(float x, float edge)
+    constexpr float step(float x, float edge)
     {
         return (x < edge ? 0.0f : 1.0f);
     }
 
-    inline double step(double x, double edge)
+    constexpr double step(double x, double edge)
     {
         return (x < edge ? 0.0 : 1.0);
     }
 
-    inline long double step(long double x, long double edge)
+    constexpr long double step(long double x, long double edge)
     {
         return (x < edge ? 0.0L : 1.0L);
     }
 
-    inline signed char mod(signed char x, signed char y)
+    constexpr signed char mod(signed char x, signed char y)
     {
         return x - (x / y) * y;
     }
 
-    inline unsigned char mod(unsigned char x, unsigned char y)
+    constexpr unsigned char mod(unsigned char x, unsigned char y)
     {
         return x - (x / y) * y;
     }
 
-    inline short mod(short x, short y)
+    constexpr short mod(short x, short y)
     {
         return x - (x / y) * y;
     }
 
-    inline unsigned short mod(unsigned short x, unsigned short y)
+    constexpr unsigned short mod(unsigned short x, unsigned short y)
     {
         return x - (x / y) * y;
     }
 
-    inline int mod(int x, int y)
+    constexpr int mod(int x, int y)
     {
         return x - (x / y) * y;
     }
 
-    inline unsigned int mod(unsigned int x, unsigned int y)
+    constexpr unsigned int mod(unsigned int x, unsigned int y)
     {
         return x - (x / y) * y;
     }
 
-    inline long mod(long x, long y)
+    constexpr long mod(long x, long y)
     {
         return x - (x / y) * y;
     }
 
-    inline unsigned long mod(unsigned long x, unsigned long y)
+    constexpr unsigned long mod(unsigned long x, unsigned long y)
     {
         return x - (x / y) * y;
     }
 
-    inline long long mod(long long x, long long y)
+    constexpr long long mod(long long x, long long y)
     {
         return x - (x / y) * y;
     }
 
-    inline unsigned long long mod(unsigned long long x, unsigned long long y)
+    constexpr unsigned long long mod(unsigned long long x, unsigned long long y)
     {
         return x - (x / y) * y;
     }
 
-    inline float mod(float x, float y)
+    constexpr float mod(float x, float y)
     {
         return x - std::floor(x / y) * y;
     }
 
-    inline double mod(double x, double y)
+    constexpr double mod(double x, double y)
     {
         return x - std::floor(x / y) * y;
     }
 
-    inline long double mod(long double x, long double y)
+    constexpr long double mod(long double x, long double y)
     {
         return x - std::floor(x / y) * y;
     }
 
-    inline signed char sign(signed char x)
+    constexpr signed char sign(signed char x)
     {
         return (x < 0 ? -1 : x > 0 ? +1 : 0);
     }
 
-    inline unsigned char sign(unsigned char x)
+    constexpr unsigned char sign(unsigned char x)
     {
         return (x > 0 ? +1 : 0);
     }
 
-    inline short sign(short x)
+    constexpr short sign(short x)
     {
         return (x < 0 ? -1 : x > 0 ? +1 : 0);
     }
 
-    inline unsigned short sign(unsigned short x)
+    constexpr unsigned short sign(unsigned short x)
     {
         return (x > 0 ? +1 : 0);
     }
 
-    inline int sign(int x)
+    constexpr int sign(int x)
     {
         return (x < 0 ? -1 : x > 0 ? +1 : 0);
     }
 
-    inline unsigned int sign(unsigned int x)
+    constexpr unsigned int sign(unsigned int x)
     {
         return (x > 0 ? +1 : 0);
     }
 
-    inline long sign(long x)
+    constexpr long sign(long x)
     {
         return (x < 0 ? -1 : x > 0 ? +1 : 0);
     }
 
-    inline unsigned long sign(unsigned long x)
+    constexpr unsigned long sign(unsigned long x)
     {
         return (x > 0 ? +1 : 0);
     }
 
-    inline long long sign(long long x)
+    constexpr long long sign(long long x)
     {
         return (x < 0 ? -1 : x > 0 ? +1 : 0);
     }
 
-    inline unsigned long long sign(unsigned long long x)
+    constexpr unsigned long long sign(unsigned long long x)
     {
         return (x > 0 ? +1 : 0);
     }
 
-    inline float sign(float x)
+    constexpr float sign(float x)
     {
         return (x < 0.0f ? -1.0f : x > 0.0f ? +1.0f : 0.0f);
     }
 
-    inline double sign(double x)
+    constexpr double sign(double x)
     {
         return (x < 0.0 ? -1.0 : x > 0.0 ? +1.0 : 0.0);
     }
 
-    inline long double sign(long double x)
+    constexpr long double sign(long double x)
     {
         return (x < 0.0L ? -1.0L : x > 0.0L ? +1.0L : 0.0L);
     }
 
     using std::abs;
 
-    inline bool abs(bool x)
+    constexpr bool abs(bool x)
     {
         return x;
     }
 
-    inline signed char abs(signed char x)
+    constexpr signed char abs(signed char x)
     {
         return (x < 0 ? -x : x);
     }
 
-    inline unsigned char abs(unsigned char x)
+    constexpr unsigned char abs(unsigned char x)
     {
         return x;
     }
 
-    inline short abs(short x)
+    constexpr short abs(short x)
     {
         return (x < 0 ? -x : x);
     }
 
-    inline unsigned short abs(unsigned short x)
+    constexpr unsigned short abs(unsigned short x)
     {
         return x;
     }
 
-    inline unsigned int abs(unsigned int x)
+    constexpr unsigned int abs(unsigned int x)
     {
         return x;
     }
 
-    inline unsigned long abs(unsigned long x)
+    constexpr unsigned long abs(unsigned long x)
     {
         return x;
     }
 
-    inline unsigned long long abs(unsigned long long x)
+    constexpr unsigned long long abs(unsigned long long x)
     {
         return x;
     }
 
-    inline float radians(float x)
+    constexpr float radians(float x)
     {
-        return x * (const_pi<float>() / 180.0f);
+        return x * (constants::pi<float>() / 180.0f);
     }
 
-    inline double radians(double x)
+    constexpr double radians(double x)
     {
-        return x * (const_pi<double>() / 180.0);
+        return x * (constants::pi<double>() / 180.0);
     }
 
-    inline long double radians(long double x)
+    constexpr long double radians(long double x)
     {
-        return x * (const_pi<long double>() / 180.0L);
+        return x * (constants::pi<long double>() / 180.0L);
     }
 
-    inline float degrees(float x)
+    constexpr float degrees(float x)
     {
-        return x * (180.0f / const_pi<float>());
+        return x * (180.0f / constants::pi<float>());
     }
 
-    inline double degrees(double x)
+    constexpr double degrees(double x)
     {
-        return x * (180.0 / const_pi<double>());
+        return x * (180.0 / constants::pi<double>());
     }
 
-    inline long double degrees(long double x)
+    constexpr long double degrees(long double x)
     {
-        return x * (180.0L / const_pi<long double>());
+        return x * (180.0L / constants::pi<long double>());
     }
 
     using std::sin;
@@ -601,17 +604,17 @@ namespace glvm
 
     using std::atan;
 
-    inline float atan(float x, float y)
+    constexpr float atan(float x, float y)
     {
         return std::atan2(x, y);
     }
 
-    inline double atan(double x, double y)
+    constexpr double atan(double x, double y)
     {
         return std::atan2(x, y);
     }
 
-    inline long double atan(long double x, long double y)
+    constexpr long double atan(long double x, long double y)
     {
         return std::atan2(x, y);
     }
@@ -630,17 +633,17 @@ namespace glvm
 
     using std::sqrt;
 
-    inline float inversesqrt(float x)
+    constexpr float inversesqrt(float x)
     {
         return 1.0f / std::sqrt(x);
     }
 
-    inline double inversesqrt(double x)
+    constexpr double inversesqrt(double x)
     {
         return 1.0 / std::sqrt(x);
     }
 
-    inline long double inversesqrt(long double x)
+    constexpr long double inversesqrt(long double x)
     {
         return 1.0L / std::sqrt(x);
     }
@@ -653,17 +656,17 @@ namespace glvm
 
     using std::ceil;
 
-    inline float fract(float x)
+    constexpr float fract(float x)
     {
         return x - std::floor(x);
     }
 
-    inline double fract(double x)
+    constexpr double fract(double x)
     {
         return x - std::floor(x);
     }
 
-    inline long double fract(long double x)
+    constexpr long double fract(long double x)
     {
         return x - std::floor(x);
     }
@@ -676,574 +679,567 @@ namespace glvm
 
     using std::isnormal;
 
-    inline float mix(float x, float y, float alpha)
+    constexpr float mix(float x, float y, float alpha)
     {
         return x * (1.0f - alpha) + y * alpha;
     }
 
-    inline double mix(double x, double y, double alpha)
+    constexpr double mix(double x, double y, double alpha)
     {
         return x * (1.0 - alpha) + y * alpha;
     }
 
-    inline long double mix(long double x, long double y, long double alpha)
+    constexpr long double mix(long double x, long double y, long double alpha)
     {
         return x * (1.0L - alpha) + y * alpha;
     }
 
-    inline float smoothstep(float x, float edge0, float edge1)
+    template<typename T> constexpr T _smoothstep_helper(T x, T edge0, T edge1)
+    {
+        return clamp((x - edge0) / (edge1 - edge0), static_cast<T>(0), static_cast<T>(1));
+    }
+
+    constexpr float smoothstep(float x, float edge0, float edge1)
     {
-        float t = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
-        return t * t * (3.0f - t * 2.0f);
+        return _smoothstep_helper(x, edge0, edge1) * _smoothstep_helper(x, edge0, edge1)
+            * (3.0f - _smoothstep_helper(x, edge0, edge1) * 2.0f);
     }
 
-    inline double smoothstep(double x, double edge0, double edge1)
+    constexpr double smoothstep(double x, double edge0, double edge1)
     {
-        double t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
-        return t * t * (3.0 - t * 2.0);
+        return _smoothstep_helper(x, edge0, edge1) * _smoothstep_helper(x, edge0, edge1)
+            * (3.0 - _smoothstep_helper(x, edge0, edge1) * 2.0);
     }
 
-    inline long double smoothstep(long double x, long double edge0, long double edge1)
+    constexpr long double smoothstep(long double x, long double edge0, long double edge1)
     {
-        long double t = clamp((x - edge0) / (edge1 - edge0), 0.0L, 1.0L);
-        return t * t * (3.0L - t * 2.0L);
+        return _smoothstep_helper(x, edge0, edge1) * _smoothstep_helper(x, edge0, edge1)
+            * (3.0L - _smoothstep_helper(x, edge0, edge1) * 2.0L);
     }
 
-    inline bool greaterThan(bool a, bool b)
+    constexpr bool greaterThan(bool a, bool b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(signed char a, signed char b)
+    constexpr bool greaterThan(signed char a, signed char b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(unsigned char a, unsigned char b)
+    constexpr bool greaterThan(unsigned char a, unsigned char b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(short a, short b)
+    constexpr bool greaterThan(short a, short b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(unsigned short a, unsigned short b)
+    constexpr bool greaterThan(unsigned short a, unsigned short b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(int a, int b)
+    constexpr bool greaterThan(int a, int b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(unsigned int a, unsigned int b)
+    constexpr bool greaterThan(unsigned int a, unsigned int b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(long a, long b)
+    constexpr bool greaterThan(long a, long b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(unsigned long a, unsigned long b)
+    constexpr bool greaterThan(unsigned long a, unsigned long b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(long long a, long long b)
+    constexpr bool greaterThan(long long a, long long b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(unsigned long long a, unsigned long long b)
+    constexpr bool greaterThan(unsigned long long a, unsigned long long b)
     {
         return a > b;
     }
 
-    inline bool greaterThan(float a, float b)
+    constexpr bool greaterThan(float a, float b)
     {
         return std::isgreater(a, b);
     }
 
-    inline bool greaterThan(double a, double b)
+    constexpr bool greaterThan(double a, double b)
     {
         return std::isgreater(a, b);
     }
 
-    inline bool greaterThan(long double a, long double b)
+    constexpr bool greaterThan(long double a, long double b)
     {
         return std::isgreater(a, b);
     }
 
-    inline bool greaterThanEqual(bool a, bool b)
+    constexpr bool greaterThanEqual(bool a, bool b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(signed char a, signed char b)
+    constexpr bool greaterThanEqual(signed char a, signed char b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(unsigned char a, unsigned char b)
+    constexpr bool greaterThanEqual(unsigned char a, unsigned char b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(short a, short b)
+    constexpr bool greaterThanEqual(short a, short b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(unsigned short a, unsigned short b)
+    constexpr bool greaterThanEqual(unsigned short a, unsigned short b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(int a, int b)
+    constexpr bool greaterThanEqual(int a, int b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(unsigned int a, unsigned int b)
+    constexpr bool greaterThanEqual(unsigned int a, unsigned int b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(long a, long b)
+    constexpr bool greaterThanEqual(long a, long b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(unsigned long a, unsigned long b)
+    constexpr bool greaterThanEqual(unsigned long a, unsigned long b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(long long a, long long b)
+    constexpr bool greaterThanEqual(long long a, long long b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(unsigned long long a, unsigned long long b)
+    constexpr bool greaterThanEqual(unsigned long long a, unsigned long long b)
     {
         return a >= b;
     }
 
-    inline bool greaterThanEqual(float a, float b)
+    constexpr bool greaterThanEqual(float a, float b)
     {
         return std::isgreaterequal(a, b);
     }
 
-    inline bool greaterThanEqual(double a, double b)
+    constexpr bool greaterThanEqual(double a, double b)
     {
         return std::isgreaterequal(a, b);
     }
 
-    inline bool greaterThanEqual(long double a, long double b)
+    constexpr bool greaterThanEqual(long double a, long double b)
     {
         return std::isgreaterequal(a, b);
     }
 
-    inline bool lessThan(bool a, bool b)
+    constexpr bool lessThan(bool a, bool b)
     {
         return a < b;
     }
 
-    inline bool lessThan(signed char a, signed char b)
+    constexpr bool lessThan(signed char a, signed char b)
     {
         return a < b;
     }
 
-    inline bool lessThan(unsigned char a, unsigned char b)
+    constexpr bool lessThan(unsigned char a, unsigned char b)
     {
         return a < b;
     }
 
-    inline bool lessThan(short a, short b)
+    constexpr bool lessThan(short a, short b)
     {
         return a < b;
     }
 
-    inline bool lessThan(unsigned short a, unsigned short b)
+    constexpr bool lessThan(unsigned short a, unsigned short b)
     {
         return a < b;
     }
 
-    inline bool lessThan(int a, int b)
+    constexpr bool lessThan(int a, int b)
     {
         return a < b;
     }
 
-    inline bool lessThan(unsigned int a, unsigned int b)
+    constexpr bool lessThan(unsigned int a, unsigned int b)
     {
         return a < b;
     }
 
-    inline bool lessThan(long a, long b)
+    constexpr bool lessThan(long a, long b)
     {
         return a < b;
     }
 
-    inline bool lessThan(unsigned long a, unsigned long b)
+    constexpr bool lessThan(unsigned long a, unsigned long b)
     {
         return a < b;
     }
 
-    inline bool lessThan(long long a, long long b)
+    constexpr bool lessThan(long long a, long long b)
     {
         return a < b;
     }
 
-    inline bool lessThan(unsigned long long a, unsigned long long b)
+    constexpr bool lessThan(unsigned long long a, unsigned long long b)
     {
         return a < b;
     }
 
-    inline bool lessThan(float a, float b)
+    constexpr bool lessThan(float a, float b)
     {
         return std::isless(a, b);
     }
 
-    inline bool lessThan(double a, double b)
+    constexpr bool lessThan(double a, double b)
     {
         return std::isless(a, b);
     }
 
-    inline bool lessThan(long double a, long double b)
+    constexpr bool lessThan(long double a, long double b)
     {
         return std::isless(a, b);
     }
 
-    inline bool lessThanEqual(bool a, bool b)
+    constexpr bool lessThanEqual(bool a, bool b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(signed char a, signed char b)
+    constexpr bool lessThanEqual(signed char a, signed char b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(unsigned char a, unsigned char b)
+    constexpr bool lessThanEqual(unsigned char a, unsigned char b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(short a, short b)
+    constexpr bool lessThanEqual(short a, short b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(unsigned short a, unsigned short b)
+    constexpr bool lessThanEqual(unsigned short a, unsigned short b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(int a, int b)
+    constexpr bool lessThanEqual(int a, int b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(unsigned int a, unsigned int b)
+    constexpr bool lessThanEqual(unsigned int a, unsigned int b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(long a, long b)
+    constexpr bool lessThanEqual(long a, long b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(unsigned long a, unsigned long b)
+    constexpr bool lessThanEqual(unsigned long a, unsigned long b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(long long a, long long b)
+    constexpr bool lessThanEqual(long long a, long long b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(unsigned long long a, unsigned long long b)
+    constexpr bool lessThanEqual(unsigned long long a, unsigned long long b)
     {
         return a <= b;
     }
 
-    inline bool lessThanEqual(float a, float b)
+    constexpr bool lessThanEqual(float a, float b)
     {
         return std::islessequal(a, b);
     }
 
-    inline bool lessThanEqual(double a, double b)
+    constexpr bool lessThanEqual(double a, double b)
     {
         return std::islessequal(a, b);
     }
 
-    inline bool lessThanEqual(long double a, long double b)
+    constexpr bool lessThanEqual(long double a, long double b)
     {
         return std::islessequal(a, b);
     }
 
-    inline bool equal(bool a, bool b)
+    constexpr bool equal(bool a, bool b)
     {
         return a == b;
     }
 
-    inline bool equal(signed char a, signed char b)
+    constexpr bool equal(signed char a, signed char b)
     {
         return a == b;
     }
 
-    inline bool equal(unsigned char a, unsigned char b)
+    constexpr bool equal(unsigned char a, unsigned char b)
     {
         return a == b;
     }
 
-    inline bool equal(short a, short b)
+    constexpr bool equal(short a, short b)
     {
         return a == b;
     }
 
-    inline bool equal(unsigned short a, unsigned short b)
+    constexpr bool equal(unsigned short a, unsigned short b)
     {
         return a == b;
     }
 
-    inline bool equal(int a, int b)
+    constexpr bool equal(int a, int b)
     {
         return a == b;
     }
 
-    inline bool equal(unsigned int a, unsigned int b)
+    constexpr bool equal(unsigned int a, unsigned int b)
     {
         return a == b;
     }
 
-    inline bool equal(long a, long b)
+    constexpr bool equal(long a, long b)
     {
         return a == b;
     }
 
-    inline bool equal(unsigned long a, unsigned long b)
+    constexpr bool equal(unsigned long a, unsigned long b)
     {
         return a == b;
     }
 
-    inline bool equal(long long a, long long b)
+    constexpr bool equal(long long a, long long b)
     {
         return a == b;
     }
 
-    inline bool equal(unsigned long long a, unsigned long long b)
+    constexpr bool equal(unsigned long long a, unsigned long long b)
     {
         return a == b;
     }
 
-    inline bool equal(float a, float b)
+    constexpr bool equal(float a, float b)
     {
         return greaterThanEqual(a, b) && lessThanEqual(a, b);
     }
 
-    inline bool equal(double a, double b)
+    constexpr bool equal(double a, double b)
     {
         return greaterThanEqual(a, b) && lessThanEqual(a, b);
     }
 
-    inline bool equal(long double a, long double b)
+    constexpr bool equal(long double a, long double b)
     {
         return greaterThanEqual(a, b) && lessThanEqual(a, b);
     }
 
-    inline bool notEqual(bool a, bool b)
+    constexpr bool notEqual(bool a, bool b)
     {
         return a != b;
     }
 
-    inline bool notEqual(signed char a, signed char b)
+    constexpr bool notEqual(signed char a, signed char b)
     {
         return a != b;
     }
 
-    inline bool notEqual(unsigned char a, unsigned char b)
+    constexpr bool notEqual(unsigned char a, unsigned char b)
     {
         return a != b;
     }
 
-    inline bool notEqual(short a, short b)
+    constexpr bool notEqual(short a, short b)
     {
         return a != b;
     }
 
-    inline bool notEqual(unsigned short a, unsigned short b)
+    constexpr bool notEqual(unsigned short a, unsigned short b)
     {
         return a != b;
     }
 
-    inline bool notEqual(int a, int b)
+    constexpr bool notEqual(int a, int b)
     {
         return a != b;
     }
 
-    inline bool notEqual(unsigned int a, unsigned int b)
+    constexpr bool notEqual(unsigned int a, unsigned int b)
     {
         return a != b;
     }
 
-    inline bool notEqual(long a, long b)
+    constexpr bool notEqual(long a, long b)
     {
         return a != b;
     }
 
-    inline bool notEqual(unsigned long a, unsigned long b)
+    constexpr bool notEqual(unsigned long a, unsigned long b)
     {
         return a != b;
     }
 
-    inline bool notEqual(long long a, long long b)
+    constexpr bool notEqual(long long a, long long b)
     {
         return a != b;
     }
 
-    inline bool notEqual(unsigned long long a, unsigned long long b)
+    constexpr bool notEqual(unsigned long long a, unsigned long long b)
     {
         return a != b;
     }
 
-    inline bool notEqual(float a, float b)
+    constexpr bool notEqual(float a, float b)
     {
         return !equal(a, b);
     }
 
-    inline bool notEqual(double a, double b)
+    constexpr bool notEqual(double a, double b)
     {
         return !equal(a, b);
     }
 
-    inline bool notEqual(long double a, long double b)
+    constexpr bool notEqual(long double a, long double b)
     {
         return !equal(a, b);
     }
 
-    inline bool any(bool a)
+    constexpr bool any(bool a)
     {
         return a;
     }
 
-    inline bool all(bool a)
+    constexpr bool all(bool a)
     {
         return a;
     }
 
-    inline bool negate(bool a)
+    constexpr bool negate(bool a)
     {
         return !a;
     }
 
     // Bonus: log2 for positive integers
-    template<typename T> inline T _log2(T x)
+    template<typename T> constexpr T _log2(T x)
     {
-        const T zero = static_cast<T>(0);
-        const T one = static_cast<T>(1);
 #ifdef __GNUC__
-        return x < one ? zero : (std::numeric_limits<unsigned int>::digits - 1 - __builtin_clz(x));
+        return x < static_cast<T>(1) ? static_cast<T>(0) : (std::numeric_limits<unsigned int>::digits - 1 - __builtin_clz(x));
 #else
-        T r = zero;
-        while (x > one) {
-            x >>= one;
+        T r = static_cast<T>(0);
+        while (x > static_cast<T>(1)) {
+            x >>= static_cast<T>(1);
             r++;
         }
         return r;
 #endif
     }
-    template<typename T> inline T _log2l(T x)
+    template<typename T> constexpr T _log2l(T x)
     {
 #ifdef __GNUC__
-        const T zero = static_cast<T>(0);
-        const T one = static_cast<T>(1);
-        return x < one ? zero : (std::numeric_limits<unsigned long>::digits - 1 - __builtin_clzl(x));
+        return x < static_cast<T>(1) ? static_cast<T>(0) : (std::numeric_limits<unsigned long>::digits - 1 - __builtin_clzl(x));
 #else
         return _log2(x);
 #endif
     }
-    template<typename T> inline T _log2ll(T x)
+    template<typename T> constexpr T _log2ll(T x)
     {
 #ifdef __GNUC__
-        const T zero = static_cast<T>(0);
-        const T one = static_cast<T>(1);
-        return x < one ? zero : (std::numeric_limits<unsigned long long>::digits - 1 - __builtin_clzll(x));
+        return x < static_cast<T>(1) ? static_cast<T>(0) : (std::numeric_limits<unsigned long long>::digits - 1 - __builtin_clzll(x));
 #else
         return _log2(x);
 #endif
     }
-    inline signed char log2(signed char x) { return _log2(x); }
-    inline unsigned char log2(unsigned char x) { return _log2(x); }
-    inline short log2(short x) { return _log2(x); }
-    inline unsigned short log2(unsigned short x) { return _log2(x); }
-    inline int log2(int x) { return _log2(x); }
-    inline unsigned int log2(unsigned int x) { return _log2(x); }
-    inline long log2(long x) { return _log2l(x); }
-    inline unsigned long log2(unsigned long x) { return _log2l(x); }
-    inline long long log2(long long x) { return _log2ll(x); }
-    inline unsigned long long log2(unsigned long long x) { return _log2ll(x); }
+    constexpr signed char log2(signed char x) { return _log2(x); }
+    constexpr unsigned char log2(unsigned char x) { return _log2(x); }
+    constexpr short log2(short x) { return _log2(x); }
+    constexpr unsigned short log2(unsigned short x) { return _log2(x); }
+    constexpr int log2(int x) { return _log2(x); }
+    constexpr unsigned int log2(unsigned int x) { return _log2(x); }
+    constexpr long log2(long x) { return _log2l(x); }
+    constexpr unsigned long log2(unsigned long x) { return _log2l(x); }
+    constexpr long long log2(long long x) { return _log2ll(x); }
+    constexpr unsigned long long log2(unsigned long long x) { return _log2ll(x); }
 
     // Bonus: power-of-two check for positive integers
-    template<typename T> inline bool _is_pow2(T x)
-    {
-        const T zero = static_cast<T>(0);
-        const T one = static_cast<T>(1);
-        return (x > zero && (x & (x - one)) == zero);
-    }
-    inline bool is_pow2(signed char x) { return _is_pow2(x); }
-    inline bool is_pow2(unsigned char x) { return _is_pow2(x); }
-    inline bool is_pow2(short x) { return _is_pow2(x); }
-    inline bool is_pow2(unsigned short x) { return _is_pow2(x); }
-    inline bool is_pow2(int x) { return _is_pow2(x); }
-    inline bool is_pow2(unsigned int x) { return _is_pow2(x); }
-    inline bool is_pow2(long x) { return _is_pow2(x); }
-    inline bool is_pow2(unsigned long x) { return _is_pow2(x); }
-    inline bool is_pow2(long long x) { return _is_pow2(x); }
-    inline bool is_pow2(unsigned long long x) { return _is_pow2(x); }
+    template<typename T> constexpr bool _is_pow2(T x)
+    {
+        return (x > static_cast<T>(0) && (x & (x - static_cast<T>(1))) == static_cast<T>(0));
+    }
+    constexpr bool is_pow2(signed char x) { return _is_pow2(x); }
+    constexpr bool is_pow2(unsigned char x) { return _is_pow2(x); }
+    constexpr bool is_pow2(short x) { return _is_pow2(x); }
+    constexpr bool is_pow2(unsigned short x) { return _is_pow2(x); }
+    constexpr bool is_pow2(int x) { return _is_pow2(x); }
+    constexpr bool is_pow2(unsigned int x) { return _is_pow2(x); }
+    constexpr bool is_pow2(long x) { return _is_pow2(x); }
+    constexpr bool is_pow2(unsigned long x) { return _is_pow2(x); }
+    constexpr bool is_pow2(long long x) { return _is_pow2(x); }
+    constexpr bool is_pow2(unsigned long long x) { return _is_pow2(x); }
 
     // Bonus: return the next power of two, or x itself if it already is a power of two
-    template<typename T> inline T _next_pow2(T x)
-    {
-        const T zero = static_cast<T>(0);
-        const T one = static_cast<T>(1);
-        return (x < one ? one : (x & (x - one)) == zero ? x : one << (log2(x) + one));
-    }
-    inline signed char next_pow2(signed char x) { return _next_pow2(x); }
-    inline unsigned char next_pow2(unsigned char x) { return _next_pow2(x); }
-    inline short next_pow2(short x) { return _next_pow2(x); }
-    inline unsigned short next_pow2(unsigned short x) { return _next_pow2(x); }
-    inline int next_pow2(int x) { return _next_pow2(x); }
-    inline unsigned int next_pow2(unsigned int x) { return _next_pow2(x); }
-    inline long next_pow2(long x) { return _next_pow2(x); }
-    inline unsigned long next_pow2(unsigned long x) { return _next_pow2(x); }
-    inline long long next_pow2(long long x) { return _next_pow2(x); }
-    inline unsigned long long next_pow2(unsigned long long x) { return _next_pow2(x); }
+    template<typename T> constexpr T _next_pow2(T x)
+    {
+        return (x < static_cast<T>(1) ? static_cast<T>(1) : (x & (x - static_cast<T>(1))) == static_cast<T>(0) ? x : static_cast<T>(1) << (log2(x) + static_cast<T>(1)));
+    }
+    constexpr signed char next_pow2(signed char x) { return _next_pow2(x); }
+    constexpr unsigned char next_pow2(unsigned char x) { return _next_pow2(x); }
+    constexpr short next_pow2(short x) { return _next_pow2(x); }
+    constexpr unsigned short next_pow2(unsigned short x) { return _next_pow2(x); }
+    constexpr int next_pow2(int x) { return _next_pow2(x); }
+    constexpr unsigned int next_pow2(unsigned int x) { return _next_pow2(x); }
+    constexpr long next_pow2(long x) { return _next_pow2(x); }
+    constexpr unsigned long next_pow2(unsigned long x) { return _next_pow2(x); }
+    constexpr long long next_pow2(long long x) { return _next_pow2(x); }
+    constexpr unsigned long long next_pow2(unsigned long long x) { return _next_pow2(x); }
 
     // Bonus: return the next multiple of b (> 0) that is greater than or equal to a (>= 0).
-    template<typename T> inline T _next_multiple(T a, T b)
+    template<typename T> constexpr T _next_multiple(T a, T b)
     {
-        const T zero = static_cast<T>(0);
-        const T one = static_cast<T>(1);
-        return ((a / b) + (a % b == zero ? zero : one)) * b;
+        return ((a / b) + (a % b == static_cast<T>(0) ? static_cast<T>(0) : static_cast<T>(1))) * b;
     }
-    inline signed char next_multiple(signed char a, signed char b) { return _next_multiple(a, b); }
-    inline unsigned char next_multiple(unsigned char a, unsigned char b) { return _next_multiple(a, b); }
-    inline short next_multiple(short a, short b) { return _next_multiple(a, b); }
-    inline unsigned short next_multiple(unsigned short a, unsigned short b) { return _next_multiple(a, b); }
-    inline int next_multiple(int a, int b) { return _next_multiple(a, b); }
-    inline unsigned int next_multiple(unsigned int a, unsigned int b) { return _next_multiple(a, b); }
-    inline long next_multiple(long a, long b) { return _next_multiple(a, b); }
-    inline unsigned long next_multiple(unsigned long a, unsigned long b) { return _next_multiple(a, b); }
-    inline long long next_multiple(long long a, long long b) { return _next_multiple(a, b); }
-    inline unsigned long long next_multiple(unsigned long long a, unsigned long long b) { return _next_multiple(a, b); }
+    constexpr signed char next_multiple(signed char a, signed char b) { return _next_multiple(a, b); }
+    constexpr unsigned char next_multiple(unsigned char a, unsigned char b) { return _next_multiple(a, b); }
+    constexpr short next_multiple(short a, short b) { return _next_multiple(a, b); }
+    constexpr unsigned short next_multiple(unsigned short a, unsigned short b) { return _next_multiple(a, b); }
+    constexpr int next_multiple(int a, int b) { return _next_multiple(a, b); }
+    constexpr unsigned int next_multiple(unsigned int a, unsigned int b) { return _next_multiple(a, b); }
+    constexpr long next_multiple(long a, long b) { return _next_multiple(a, b); }
+    constexpr unsigned long next_multiple(unsigned long a, unsigned long b) { return _next_multiple(a, b); }
+    constexpr long long next_multiple(long long a, long long b) { return _next_multiple(a, b); }
+    constexpr unsigned long long next_multiple(unsigned long long a, unsigned long long b) { return _next_multiple(a, b); }
 
 
 
@@ -1253,19 +1249,11 @@ namespace glvm
     {
     public:
         T data[S];
+        T& operator[](std::ptrdiff_t i) { return data[i]; }
+        T operator[](std::ptrdiff_t i) const { return data[i]; }
 
         /* Operators */
 
-        T& operator[](unsigned int i)
-        {
-            return data[i];
-        }
-
-        T operator[](unsigned int i) const
-        {
-            return data[i];
-        }
-
         const Data& _op_assign(const Data& a)
         {
             for (int i = 0; i < S; i++)
@@ -2006,9 +1994,9 @@ namespace glvm
         vector(const swizzler<T, 2, S, I, J, K, L>& s)
         : vector(s.data[I], s.data[J]) {}
 
-        operator const T*() const { return data; }
-        T& operator[](unsigned int i) { return data[i]; }
-        T operator[](unsigned int i) const { return data[i]; }
+        operator const T*() const { return data.data; }
+        T& operator[](std::ptrdiff_t i) { return data.data[i]; }
+        T operator[](std::ptrdiff_t i) const { return data.data[i]; }
     };
 
     template<typename T> class vector<T, 3>
@@ -2167,9 +2155,9 @@ namespace glvm
         vector(const swizzler<T, 3, S, I, J, K, L>& s)
         : vector(s.data[I], s.data[J], s.data[K]) {}
 
-        operator const T*() const { return data; }
-        T& operator[](unsigned int i) { return data[i]; }
-        T operator[](unsigned int i) const { return data[i]; }
+        operator const T*() const { return data.data; }
+        T& operator[](std::ptrdiff_t i) { return data.data[i]; }
+        T operator[](std::ptrdiff_t i) const { return data.data[i]; }
     };
 
     template<typename T> class vector<T, 4>
@@ -2555,9 +2543,9 @@ namespace glvm
         vector(const swizzler<T, 4, S, I, J, K, L>& s)
         : vector(s.data[I], s.data[J], s.data[K], s.data[L]) {}
 
-        operator const T*() const { return data; }
-        T& operator[](unsigned int i) { return data[i]; }
-        T operator[](unsigned int i) const { return data[i]; }
+        operator const T*() const { return data.data; }
+        T& operator[](std::ptrdiff_t i) { return data.data[i]; }
+        T operator[](std::ptrdiff_t i) const { return data.data[i]; }
     };
 
     template<typename T, int S> vector<T, S>& operator+=(vector<T, S>& a, const vector<T, S>& b) { a.data._op_plus_assign(b.data); return a; }
@@ -2821,12 +2809,12 @@ namespace glvm
 
         operator const T*() const { return data.data; }
 
-        vector<T, R>& operator[](unsigned int i)
+        vector<T, R>& operator[](std::ptrdiff_t i)
         {
             return columns[i];
         }
 
-        vector<T, R> operator[](unsigned int i) const
+        vector<T, R> operator[](std::ptrdiff_t i) const
         {
             return columns[i];
         }
@@ -3285,8 +3273,6 @@ namespace glvm
             quaternion<T> t = *this * quaternion<T>(v.x, v.y, v.z, static_cast<T>(0)) * conjugate(*this);
             return vector<T, 4>(t.x, t.y, t.z, t.w);
         }
-
-        operator const T*() const { return &x; }
     };
 
     template<typename T> T magnitude(const quaternion<T>& q) { return q.data._length(); }
@@ -3294,6 +3280,39 @@ namespace glvm
     template<typename T> quaternion<T> inverse(const quaternion<T>& q) { return quaternion<T>(conjugate(q).data._op_scal_div(magnitude(q))); }
     template<typename T> quaternion<T> normalize(const quaternion<T>& q) { return quaternion<T>(q.data._op_scal_div(magnitude(q))); }
 
+    template<typename T> quaternion<T> slerp(const quaternion<T>& q, const quaternion<T>& r, T alpha)
+    {
+        quaternion<T> w = r;
+        T cos_half_angle = q.data._dot(r.data);
+        if (cos_half_angle < static_cast<T>(0)) {
+            // quat(x, y, z, w) and quat(-x, -y, -z, -w) represent the same rotation
+            w.x = -w.x; w.y = -w.y; w.z = -w.z; w.w = -w.w;
+            cos_half_angle = -cos_half_angle;
+        }
+        T tmp_q, tmp_w;
+        if (abs(cos_half_angle) >= static_cast<T>(1)) {
+            // angle is zero => rotations are identical
+            tmp_q = static_cast<T>(1);
+            tmp_w = static_cast<T>(0);
+        } else {
+            T half_angle = acos(cos_half_angle);
+            T sin_half_angle = sqrt(static_cast<T>(1) - cos_half_angle * cos_half_angle);
+            if (abs(sin_half_angle) < static_cast<T>(0.001)){
+                // angle is 180 degrees => result is not clear
+                tmp_q = static_cast<T>(0.5);
+                tmp_w = static_cast<T>(0.5);
+            } else {
+                tmp_q = sin((static_cast<T>(1) - alpha) * half_angle) / sin_half_angle;
+                tmp_w = sin(alpha * half_angle) / sin_half_angle;
+            }
+        }
+        return quaternion<T>(
+                q.x * tmp_q + w.x * tmp_w,
+                q.y * tmp_q + w.y * tmp_w,
+                q.z * tmp_q + w.z * tmp_w,
+                q.w * tmp_q + w.w * tmp_w);
+    }
+
     typedef quaternion<float> quat;
     typedef quaternion<double> dquat;
 
@@ -3334,8 +3353,6 @@ namespace glvm
             t *= q;
             n = new_near;
         }
-
-        operator const T*() const { return &l; }
     };
 
     template<typename T> matrix<T, 4, 4> toMat4(const frustum<T>& f)
@@ -3590,7 +3607,7 @@ namespace glvm
             // north pole
             result = vector<T, 3>(
                     static_cast<T>(2) * glvm::atan(q.x, q.w),
-                    const_pi_2<T>(),
+                    constants::pi_div_2<T>(),
                     static_cast<T>(0));
         }
         else if (singularity_test < static_cast<T>(-0.4999))
@@ -3598,7 +3615,7 @@ namespace glvm
             // south pole
             result = vector<T, 3>(
                     -static_cast<T>(2) * glvm::atan(q.x, q.w),
-                    -const_pi_2<T>(),
+                    -constants::pi_div_2<T>(),
                     static_cast<T>(0));
         }
         else
@@ -3615,7 +3632,7 @@ namespace glvm
 
     /* Replacements for some useful old GLU functions */
 
-    // gluPerspective()
+    // gluPerspective(), but fovy is radians not degrees
     template<typename T> frustum<T> perspective(T fovy, T aspect, T zNear, T zFar)
     {
         T t = tan(fovy / static_cast<T>(2));