aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Winget <tewinget@gmail.com>2014-10-13 18:52:45 -0400
committerwarptangent <warptangent@inbox.com>2015-01-04 18:41:44 -0800
commit90d6f8bf62bca97dc911b30505252becd8ef7520 (patch)
treeb87d425251db5171dd66f7a83e8f009ead72b176
parentupdate new blockchain to build with new changes (diff)
downloadmonero-90d6f8bf62bca97dc911b30505252becd8ef7520.tar.xz
Adding libglim as an external library
libglim is an Apache-licensed C++ wrapper for lmdb, and rather than rolling our own it seems prudent to use it. Note: lmdb is not included in it, and unless something happens as did with libunbound, should be installed via each OS' package manager or equivalent.
-rw-r--r--external/glim/ChangeLog.darcs.txt62
-rwxr-xr-xexternal/glim/LICENSE13
-rw-r--r--external/glim/NsecTimer.hpp51
-rw-r--r--external/glim/SerializablePool.hpp236
-rw-r--r--external/glim/TscTimer.hpp32
-rw-r--r--external/glim/cbcoro.hpp203
-rw-r--r--external/glim/channel.hpp40
-rw-r--r--external/glim/curl.hpp304
-rw-r--r--external/glim/doxyconf237
-rw-r--r--external/glim/exception.hpp259
-rw-r--r--external/glim/gstring.hpp578
-rw-r--r--external/glim/hget.hpp255
-rw-r--r--external/glim/ldb.hpp384
-rw-r--r--external/glim/makefile93
-rw-r--r--external/glim/mdb.hpp499
-rw-r--r--external/glim/ql2.pb.cc3741
-rw-r--r--external/glim/ql2.pb.h2532
-rw-r--r--external/glim/raii.hpp34
-rw-r--r--external/glim/runner.hpp402
-rw-r--r--external/glim/sqlite.hpp538
-rw-r--r--external/glim/test_cbcoro.cc89
-rw-r--r--external/glim/test_exception.cc73
-rw-r--r--external/glim/test_gstring.cc131
-rw-r--r--external/glim/test_ldb.cc165
-rw-r--r--external/glim/test_runner.cc74
-rw-r--r--external/glim/test_sqlite.cc18
26 files changed, 11043 insertions, 0 deletions
diff --git a/external/glim/ChangeLog.darcs.txt b/external/glim/ChangeLog.darcs.txt
new file mode 100644
index 000000000..61340d551
--- /dev/null
+++ b/external/glim/ChangeLog.darcs.txt
@@ -0,0 +1,62 @@
+Wed Dec 6 23:50:10 Russian Standard Time 2006 ArtemGr <artem@bizlink.ru>
+ * Fixes discovered under FreeBSD.
+
+Wed Dec 6 04:43:04 Russian Standard Time 2006 ArtemGr <artem@bizlink.ru>
+ * Ported to Gentoo gcc 4.1.1
+
+Fri Nov 24 14:17:08 Russian Standard Time 2006 ArtemGr <artem@bizlink.ru>
+ * Documentation improvements for the release.
+
+Fri Nov 24 13:13:50 Russian Standard Time 2006 ArtemGr <artem@bizlink.ru>
+ * A few fixes.
+
+Fri Nov 24 13:13:20 Russian Standard Time 2006 ArtemGr <artem@bizlink.ru>
+ * Do not remove the "html" directory when cleaning.
+
+Wed Nov 22 15:30:56 Russian Standard Time 2006 ArtemGr <artem@bizlink.ru>
+ * Added a compatibility #pair method to bufstr_t.
+
+Tue Nov 21 21:54:40 Russian Standard Time 2006 ArtemGr <artem@bizlink.ru>
+ * Implemented the sugared way to querying.
+
+Mon Oct 9 23:19:11 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Fixed incorrect statement = NULL in #step. Implemented parameter bindings.
+
+Mon Oct 9 20:09:17 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * SqliteQuery and SqliteParQuery classes (no binding support as of yet).
+
+Fri Oct 6 12:11:43 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * typo
+
+Thu Oct 5 23:26:21 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Basic mutex operations in SqliteSession.
+
+Sun Oct 1 23:19:36 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Compatibility with std::string.
+
+Fri Sep 29 11:42:09 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Invented SqliteSession.
+
+Fri Sep 29 01:23:31 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * SQLite wrapper: initial documentation; opening, closing.
+
+Thu Sep 28 23:15:37 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Apache version 2 license.
+
+Thu Sep 28 23:12:41 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Multiple source files for tests.
+
+Thu Sep 28 01:05:21 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Append from another bufstr_t and from a pair.
+
+Thu Sep 28 01:04:46 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Macro to construct pair from C character array.
+
+Tue Sep 26 23:23:40 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * char const* instead of const char*
+
+Tue Sep 26 20:56:07 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Everything seems to work. The library is now headers-only.
+
+Mon Sep 25 22:52:34 Russian Daylight Time 2006 ArtemGr <artem@bizlink.ru>
+ * Initial revision, containing bufstr_t; compiles, but does not work.
diff --git a/external/glim/LICENSE b/external/glim/LICENSE
new file mode 100755
index 000000000..255eeeb16
--- /dev/null
+++ b/external/glim/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2006-2012 Kozarezov Artem Aleksandrovich <artemciy@gmail.com>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/external/glim/NsecTimer.hpp b/external/glim/NsecTimer.hpp
new file mode 100644
index 000000000..e66126410
--- /dev/null
+++ b/external/glim/NsecTimer.hpp
@@ -0,0 +1,51 @@
+#ifndef _NSEC_TIMER_H
+#define _NSEC_TIMER_H
+
+#include <time.h> // clock_gettime, CLOCK_MONOTONIC
+#include <stdint.h>
+#include <string>
+#include <sstream>
+
+namespace glim {
+
+//! Safe nanoseconds timer.
+struct NsecTimer {
+ timespec start;
+ NsecTimer () {restart();}
+ //! Nanoseconds since the creation or restart of the timer.
+ int64_t operator()() const {
+ timespec nsecStop; clock_gettime (CLOCK_MONOTONIC, &nsecStop);
+ return (int64_t) (nsecStop.tv_sec - start.tv_sec) * 1000000000LL + (int64_t) (nsecStop.tv_nsec - start.tv_nsec);
+ }
+ /** Seconds since the creation or restart of the timer. */
+ double sec() const {
+ timespec nsecStop; clock_gettime (CLOCK_MONOTONIC, &nsecStop);
+ double seconds = nsecStop.tv_sec - start.tv_sec;
+ seconds += (double)(nsecStop.tv_nsec - start.tv_nsec) / 1000000000.0;
+ return seconds;
+ }
+ //! Seconds since the creation or restart of the timer.
+ std::string seconds (int precision = 9) const {
+ // The trick is to avoid the scientific notation by printing integers.
+ double sec = this->sec();
+ std::ostringstream buf;
+ int isec = (int) sec;
+ buf << isec;
+
+ sec -= isec;
+ for (int pc = precision; pc; --pc) sec *= 10.0;
+ int ifrac = (int) sec;
+ if (ifrac > 0) {
+ buf << '.';
+ buf.fill ('0'); buf.width (precision);
+ buf << ifrac;
+ }
+ return buf.str();
+ }
+ void restart() {clock_gettime (CLOCK_MONOTONIC, &start);}
+ int64_t getAndRestart() {int64_t tmp = operator()(); restart(); return tmp;}
+};
+
+}
+
+#endif // _NSEC_TIMER_H
diff --git a/external/glim/SerializablePool.hpp b/external/glim/SerializablePool.hpp
new file mode 100644
index 000000000..016e06649
--- /dev/null
+++ b/external/glim/SerializablePool.hpp
@@ -0,0 +1,236 @@
+#ifndef _GLIM_SERIALIZABLEPOOL_HPP_INCLUDED
+#define _GLIM_SERIALIZABLEPOOL_HPP_INCLUDED
+
+#include "gstring.hpp"
+#ifndef _SERIALIZABLEPOOL_NOLDB
+# include "ldb.hpp" // Reuse `ldbSerialize` and `ldbDeserialize` in the `with` method.
+#endif
+namespace glim {
+
+namespace SerializablePoolHelpers {
+ struct Impl {
+ /**
+ * Pool format: \code
+ * uint32_t valuesStart; // Network byte order.
+ * uint32_t value0Offset, value1Offset, ... valueNOffset; // Network byte order.
+ * char value0[]; char zero; char value1[]; char zero; ... char valueN[]; char zero;
+ * \endcode
+ */
+ gstring _pool;
+ std::vector<gstring> _changes;
+ std::vector<bool> _changed;
+ bool _readOnly = false;
+ Impl() = default;
+ Impl (const gstring& poolBytes): _pool (poolBytes), _readOnly (false) {}
+ };
+
+ /// Can be used to avoid a deep copy of the pool and change vectors (pImpl idiom).
+ /// Example: \code glim::SerializablePool pool; \endcode
+ struct SharedPtr {
+ std::shared_ptr<Impl> _impl;
+ SharedPtr() = default;
+ SharedPtr (const gstring& poolBytes): _impl (std::make_shared<Impl> (poolBytes)) {}
+ Impl* get() const {return _impl.get();}
+ Impl* operator->() const {return _impl.get();}
+ Impl& operator*() const {return *_impl;}
+ Impl* instance() {if (!_impl) _impl = std::make_shared<Impl>(); return _impl.get();}
+ };
+
+ /// Can be used instead of SharedPtr to avoid the shared_ptr indirection when the SerializablePoolTpl isn't going to be copied.
+ /// Example: \code glim::InlineSerializablePool temporaryPool (bytes); \endcode
+ struct InlinePtr {
+ Impl _impl;
+ InlinePtr() = default;
+ InlinePtr (const gstring& poolBytes): _impl (poolBytes) {}
+ Impl* get() const {return const_cast<Impl*> (&_impl);}
+ Impl* operator->() const {return const_cast<Impl*> (&_impl);}
+ Impl& operator*() const {return const_cast<Impl&> (_impl);}
+ Impl* instance() {return &_impl;}
+ };
+}
+
+/** Serialization with lazy parsing: fields are accessed without "unpacking" the byte array.
+ * Changes are stored separately, allowing the user to know exactly what fields has been changed and compare the old values to the new ones. */
+template <typename PI>
+class SerializablePoolTpl {
+protected:
+ using Impl = SerializablePoolHelpers::Impl;
+ PI _impl;
+ /** @param ref Return a zero-copy view. The view should not be used outside of the pool buffer's lifetime. */
+ static gstring original (const gstring& pool, uint32_t num, bool ref = false) {
+ uint32_t poolLength = pool.length(); if (poolLength < 4) return gstring();
+ uint32_t valuesStart = ntohl (*(uint32_t*) pool.data());
+ assert (valuesStart <= poolLength);
+ uint32_t valueOffsetOffset = 4 + num * 4;
+ if ((int) valuesStart - (int) valueOffsetOffset < 4) return gstring(); // num > size
+ uint32_t valueOffset = ntohl (*(uint32_t*) (pool.data() + valueOffsetOffset));
+ valueOffsetOffset += 4;
+ uint32_t nextValueOffset = ((int) valuesStart - (int) valueOffsetOffset < 4)
+ ? poolLength
+ : ntohl (*(uint32_t*) (pool.data() + valueOffsetOffset));
+ return gstring (0, (void*) (pool.data() + valueOffset), false, nextValueOffset - 1 - valueOffset, ref);
+ }
+ /** How many elements are in the pool. */
+ static uint32_t poolSize (const gstring& pool) {
+ if (pool.length() < 4) return 0;
+ uint32_t valuesStart = ntohl (*(uint32_t*) pool.data());
+ return (valuesStart - 4) / 4;
+ }
+ void toBytes (gstring& newPool, uint32_t size, const gstring* oldPool) const {
+ newPool.clear();
+ const Impl* impl = _impl.get();
+ const std::vector<bool>& changed = impl->_changed;
+ const std::vector<gstring>& changes = impl->_changes;
+ if (changed.empty()) return;
+ uint32_t valuesStart = 4 + size * 4;
+ uint32_t networkOrder = 0;
+ newPool.append ((char*) &(networkOrder = htonl (valuesStart)), 4);
+ for (uint32_t num = 0; num < size; ++num) newPool.append ((char*) &(networkOrder = 0), 4);
+ for (uint32_t num = 0; num < size; ++num) {
+ uint32_t start = newPool.length();
+ if (num < changed.size() && changed[num]) newPool << changes[num];
+ else newPool << original (oldPool ? *oldPool : impl->_pool, num);
+ newPool << '\0';
+ uint32_t valuesOffsetOffset = 4 + num * 4; assert (valuesOffsetOffset < valuesStart);
+ *(uint32_t*)(newPool.data() + valuesOffsetOffset) = htonl (start);
+ }
+ }
+public:
+ /** Field, old value, new value. Might be used to maintain indexes. */
+ typedef std::function<void(uint32_t, const gstring&, const gstring&)> ChangeVisitor;
+
+ SerializablePoolTpl() = default;
+ /** Copy the given pool bytes from the outside source (e.g. from the database). */
+ SerializablePoolTpl (const gstring& poolBytes): _impl (poolBytes) {}
+ /** Returns a view into the original serialized field (ignores the current changes).\n
+ * Returns an empty string if the field is not in the pool (num > size).
+ * @param ref Return a zero-copy view. The view becomes invalid after the value has been changed or when the pool's `Impl` is destroyed. */
+ const gstring original (uint32_t num, bool ref = false) const {return original (_impl->_pool, num, ref);}
+ /** Returns the original serialized field (ignores the current changes).\n
+ * Returns an empty string if the field is not in the pool (num > size). */
+ const char* cstringOriginal (uint32_t num) const {
+ gstring gs (original (_impl->_pool, num));
+ return gs.empty() ? "" : gs.data(); // All fields in the _pool are 0-terminated.
+ }
+ /** Returns the field.
+ * @param ref Return a zero-copy view. The view becomes invalid after the value has been changed or when the pool's `Impl` is destroyed. */
+ const gstring current (uint32_t num, bool ref = false) const {
+ const Impl* impl = _impl.get(); if (!impl) return gstring();
+ if (num < impl->_changed.size() && impl->_changed[num]) {
+ const gstring& value = impl->_changes[num]; return ref ? value.ref() : value;}
+ return original (impl->_pool, num);
+ }
+ /** Set the new value of the field. */
+ void set (uint32_t num, const gstring& value) {
+ Impl* impl = _impl.instance();
+ if (__builtin_expect (impl->_readOnly, 0)) throw std::runtime_error ("Attempt to modify a read-only SerializablePool");
+ if (num >= impl->_changed.size()) {impl->_changed.resize (num + 1); impl->_changes.resize (num + 1);}
+ impl->_changed[num] = true;
+ impl->_changes[num] = value;
+ }
+ void reserve (uint32_t fields) {
+ Impl* impl = _impl.instance();
+ if (__builtin_expect (impl->_readOnly, 0)) throw std::runtime_error ("Attempt to modify a read-only SerializablePool");
+ impl->_changed.reserve (fields);
+ impl->_changes.reserve (fields);
+ }
+ /** Peek into the pool.\n
+ * Returned reference should not be used after the SerializablePool goes out of scope (and destroyed). */
+ const gstring& originalPool() {return _impl->_pool;}
+ /** Serialize the pool.
+ * @param changeVisitor is called for every field that was really changed (e.g. the bytes differ). */
+ void toBytes (gstring& newPool, ChangeVisitor changeVisitor = ChangeVisitor()) const {
+ if (changeVisitor) {
+ const Impl* impl = _impl.get();
+ const std::vector<bool>& changed = impl->_changed;
+ const std::vector<gstring>& changes = impl->_changes;
+ for (uint32_t num = 0, size = changed.size(); num < size; ++num) if (changed[num]) {
+ const gstring& from = original (impl->_pool, num); const gstring& to = changes[num];
+ if (from != to) changeVisitor (num, from, to);
+ }
+ }
+ toBytes (newPool, (uint32_t) _impl->_changed.size(), nullptr);
+ }
+ /**
+ * Performs "delta" serialization of the pool: creates a new pool where values which has not changed are copied from the `oldPool`.\n
+ * \code Use case: 1) pools X and Y are loaded from a database by users A and B;
+ * 2) user A changes field 0 in pool X; 3) user B changes field 1 in pool Y;
+ * 4) user A loads `oldPool` from the database, does `toBytesDelta` from pool X and saves to the database;
+ * 5) user B loads `oldPool` from the database, does `toBytesDelta` from pool Y and saves to the database;
+ * result: database contains both changes (field 0 from user A and field 1 from user B). \endcode
+ * @param changeVisitor is called for every field that was changed between the oldPool and the current one.
+ * Returns `false` and leaves `newPool` *empty* if there are no changes found against the `oldPool`.
+ */
+ bool toBytesDelta (gstring& newPool, const gstring& oldPool, ChangeVisitor changeVisitor = ChangeVisitor()) const {
+ newPool.clear();
+ const Impl* impl = _impl.get();
+ const std::vector<bool>& changed = impl->_changed;
+ const std::vector<gstring>& changes = impl->_changes;
+ bool verifiedChanges = false;
+ for (uint32_t num = 0, size = changed.size(); num < size; ++num) if (changed[num]) {
+ const gstring& from = original (oldPool, num); const gstring& to = changes[num];
+ if (from != to) {
+ verifiedChanges = true;
+ if (changeVisitor) changeVisitor (num, from, to); else break;
+ }
+ }
+ if (!verifiedChanges) return false;
+
+ toBytes (newPool, std::max ((uint32_t) changed.size(), poolSize (oldPool)), &oldPool);
+ return true;
+ }
+ /** True if the field has been `set` in this pool instance.\n
+ * NB: Does *not* check if the `set` value is equal to the `original` value or not. */
+ bool changed (uint32_t num) const {const auto& changed = _impl->_changed; return num < changed.size() ? changed[num] : false;}
+ /** True if a field has been `set` in this pool instance. */
+ bool changed() const {return !_impl->_changed.empty();}
+
+ bool operator == (const SerializablePoolTpl<PI>& rhs) const {return _impl.get() == rhs._impl.get();}
+ /** Useful for storing SerializablePool in a map. */
+ intptr_t implId() const {return (intptr_t) _impl.get();}
+
+ /** If set to `true` then modifying the pool will throw an exception.\n
+ * Useful for freezing the pool before sharing it with other threads. */
+ void readOnly (bool ro) {if (_impl) _impl->_readOnly = true;}
+ bool readOnly() const {return (_impl ? _impl->_readOnly : false);}
+
+ /** Number of elements in the pool. Equals to max(num)-1. */
+ uint32_t size() const {
+ Impl* impl = _impl.get(); if (__builtin_expect (!impl, 0)) return 0;
+ return std::max (poolSize (impl->_pool), (uint32_t) impl->_changed.size());
+ }
+
+#ifndef _SERIALIZABLEPOOL_NOLDB
+ /** Serialize the `value` with `ldbSerialize` and `set` it to `num`.
+ * @param stackSize is the amount of space to preallocate on stack for the temporary buffer. */
+ template<typename T> void serialize (uint32_t num, const T& value, uint32_t stackSize = 256) {
+ GSTRING_ON_STACK (bytes, stackSize);
+ ldbSerialize (bytes, value);
+ set (num, bytes);
+ }
+ /** If the field is not empty then `ldbDeserialize` it into `value`. */
+ template<typename T> void deserialize (uint32_t num, T& value) const {
+ const gstring& bytes = current (num);
+ if (bytes.length()) ldbDeserialize (current (num), value);
+ }
+ /** Deserialize the `num` field with `ldbDeserialize`, run `visitor` on it, then optionally serialize the field back using `ldbSerialize`.
+ * Example: \code
+ * typedef std::map<std::string, std::string> MyMap;
+ * pool.with<MyMap> (_myMap, [](MyMap& myMap) {myMap["foo"] = "bar"; return true;});
+ * \endcode
+ * @param visitor must return `true` to serialize the field back to the pool.
+ */
+ template<typename T> void with (uint32_t num, std::function<bool(T&)> visitor) {
+ const gstring& fromBytes = current (num, true);
+ T value; if (fromBytes.length()) ldbDeserialize (fromBytes, value);
+ if (visitor (value)) serialize (num, value, 16 + fromBytes.length() * 2);
+ }
+#endif
+};
+
+using SerializablePool = SerializablePoolTpl<SerializablePoolHelpers::SharedPtr>;
+using InlineSerializablePool = SerializablePoolTpl<SerializablePoolHelpers::InlinePtr>;
+
+}
+
+#endif // _GLIM_SERIALIZABLEPOOL_HPP_INCLUDED
diff --git a/external/glim/TscTimer.hpp b/external/glim/TscTimer.hpp
new file mode 100644
index 000000000..ce22c7cb1
--- /dev/null
+++ b/external/glim/TscTimer.hpp
@@ -0,0 +1,32 @@
+#ifndef _TSC_TIMER_H
+#define _TSC_TIMER_H
+
+namespace glim {
+
+extern "C" { // http://en.wikipedia.org/wiki/Rdtsc
+#if (defined(__GNUC__) || defined(__ICC)) && defined(__i386__)
+ static __inline__ unsigned long long rdTsc(void) {
+ unsigned long long ret;
+ __asm__ __volatile__("rdtsc": "=A" (ret));
+ return ret;
+ }
+#elif (defined(__GNUC__) || defined(__ICC) || defined(__SUNPRO_C)) && defined(__x86_64__)
+ static __inline__ unsigned long long rdTsc(void) {
+ unsigned a, d;
+ asm volatile("rdtsc" : "=a" (a), "=d" (d));
+ return ((unsigned long long)a) | (((unsigned long long)d) << 32);
+ }
+#endif
+}
+
+//! CPU cycles timer. Fast, not safe.
+//! cf. http://en.wikipedia.org/wiki/Rdtsc
+struct TscTimer {
+ int64_t start;
+ TscTimer (): start (rdTsc()) {}
+ int64_t operator()() const {return rdTsc() - start;}
+};
+
+}
+
+#endif // _TSC_TIMER_H
diff --git a/external/glim/cbcoro.hpp b/external/glim/cbcoro.hpp
new file mode 100644
index 000000000..f788a5bf0
--- /dev/null
+++ b/external/glim/cbcoro.hpp
@@ -0,0 +1,203 @@
+/** \file
+ * ucontext-based coroutine library designed to emulate a normal control flow around callbacks. */
+
+// http://en.wikipedia.org/wiki/Setcontext; man 3 makecontext; man 2 getcontext
+// http://www.boost.org/doc/libs/1_53_0/libs/context/doc/html/index.html
+// g++ -std=c++11 -O1 -Wall -g test_cbcoro.cc -pthread && ./a.out
+
+// NB: There is now a coroutine support in Boost ASIO which can be used to make asynchronous APIs look synchronous in a similar way:
+// https://svn.boost.org/trac/boost/changeset/84311
+
+#include <ucontext.h>
+#include <sys/mman.h> // mmap
+#include <string.h> // strerror
+#include <mutex>
+#include <atomic>
+#include <valgrind/valgrind.h>
+#include <glim/exception.hpp>
+#include <boost/container/flat_map.hpp>
+#include <boost/container/slist.hpp>
+
+namespace glim {
+
+/// Simplifies turning callback control flows into normal imperative control flows.
+class CBCoro {
+ public:
+ /// "Holds" the CBCoro and will delete it when it is no longer used.
+ struct CBCoroPtr {
+ CBCoro* _coro;
+ CBCoroPtr (CBCoro* coro): _coro (coro) {
+ _coro->_users++;
+ }
+ ~CBCoroPtr() {
+ if (--_coro->_users <= 0 && _coro->_delete) delete _coro;
+ }
+ CBCoro* operator ->() const {return _coro;}
+ };
+
+ static constexpr size_t defaultStackSize() {return 512 * 1024;}
+ static constexpr uint8_t defaultCacheSize() {return 2;}
+ protected:
+ typedef boost::container::flat_map<size_t, boost::container::slist<void*> > cache_t;
+ /// The cached stacks; stackSize -> free list.
+ static cache_t& cache() {static cache_t CACHE; return CACHE;}
+ static std::mutex& cacheMutex() {static std::mutex CACHE_MUTEX; return CACHE_MUTEX;}
+
+ ucontext_t _context;
+ ucontext_t* _returnTo;
+ std::recursive_mutex _mutex; ///< This one is locked most of the time.
+ std::atomic_int_fast32_t _users; ///< Counter used by `CBCoroPtr`.
+ bool _delete; ///< Whether the `CBCoroPtr` should `delete` this instance when it is no longer used (default is `true`).
+ bool _invokeFromYield; ///< True if `invokeFromCallback()` was called directly from `yieldForCallback()`.
+ bool _yieldFromInvoke; ///< True if `yieldForCallback()` now runs from `invokeFromCallback()`.
+ uint8_t const _cacheStack; ///< Tells `freeStack()` to cache the stack if the number of cached `#_stackSize` stacks is less than it.
+ void* _stack;
+ size_t const _stackSize; ///< Keeps the size of the stack.
+
+ /// Peek a stack from the cache or allocate one with `mmap` (and register with Valgrind).
+ virtual void allocateStack() {
+ if (_cacheStack) {
+ std::lock_guard<std::mutex> lock (cacheMutex());
+ auto& freeList = cache()[_stackSize];
+ if (!freeList.empty()) {_stack = freeList.front(); freeList.pop_front(); return;}
+ }
+ _stack = mmap (nullptr, _stackSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_NORESERVE, -1, 0);
+ if (_stack == MAP_FAILED) GTHROW (std::string ("mmap allocation failed: ") + ::strerror (errno));
+ #pragma GCC diagnostic ignored "-Wunused-value"
+ VALGRIND_STACK_REGISTER (_stack, (char*) _stack + _stackSize);
+ }
+ /// Release a stack into the cache or free it with `munmap` (and deregister with Valgrind).
+ virtual void freeStack() {
+ if (_cacheStack) {
+ std::lock_guard<std::mutex> lock (cacheMutex());
+ auto& freeList = cache()[_stackSize];
+ if (freeList.size() < _cacheStack) {freeList.push_front (_stack); _stack = nullptr; return;}
+ }
+ VALGRIND_STACK_DEREGISTER (_stack);
+ if (munmap (_stack, _stackSize)) GTHROW (std::string ("!munmap: ") + ::strerror (errno));;
+ _stack = nullptr;
+ }
+
+ /// Prepare the coroutine (initialize context, allocate stack and register it with Valgrind).
+ CBCoro (uint8_t cacheStack = defaultCacheSize(), size_t stackSize = defaultStackSize()):
+ _returnTo (nullptr), _users (0), _delete (true), _invokeFromYield (false), _yieldFromInvoke (false),
+ _cacheStack (cacheStack), _stack (nullptr), _stackSize (stackSize) {
+ if (getcontext (&_context)) GTHROW ("!getcontext");
+ allocateStack();
+ _context.uc_stack.ss_sp = _stack;
+ _context.uc_stack.ss_size = stackSize;
+ }
+ virtual ~CBCoro() {
+ freeStack();
+ }
+ public:
+ /// Starts the coroutine on the `_stack` (makecontext, swapcontext), calling the `CBCoro::run`.
+ CBCoroPtr start() {
+ CBCoroPtr ptr (this);
+ ucontext_t back; _context.uc_link = &back;
+ makecontext (&_context, (void(*)()) cbcRun, 1, (intptr_t) this);
+ // Since we have to "return" from inside the `yieldForCallback`,
+ // we're not actually using the `_context.uc_link` and `return`, we use `setcontext (_returnTo)` instead.
+ _returnTo = &back;
+ _mutex.lock();
+ swapcontext (&back, &_context); // Now our stack lives and the caller stack is no longer in control.
+ _mutex.unlock();
+ return ptr;
+ }
+ protected:
+ /// Logs exception thrown from `CBCoro::run`.
+ virtual void log (const std::exception& ex) {
+ std::cerr << "glim::CBCoro, exception: " << ex.what() << std::endl;
+ }
+ static void cbcRun (CBCoro* cbCoro) {
+ try {
+ cbCoro->run();
+ } catch (const std::exception& ex) {
+ cbCoro->log (ex);
+ }
+ cbCoro->cbcReturn(); // Return the control to the rightful owner, e.g. to a last callback who ran `invokeFromCallback`, or otherwise to `cbcStart`.
+ }
+ /// Relinquish the control to the original owner of the thread, restoring its stack.
+ void cbcReturn() {
+ ucontext_t* returnTo = _returnTo;
+ if (returnTo != nullptr) {_returnTo = nullptr; setcontext (returnTo);}
+ }
+ /// This method is performed on the CBCoro stack, allowing it to be suspended and then reanimated from callbacks.
+ virtual void run() = 0;
+ public:
+ /** Use this method to wrap a return-via-callback code.
+ * For example, the callback code \code
+ * startSomeWork ([=]() {
+ * continueWhenWorkIsFinished();
+ * });
+ * \endcode should be turned into \code
+ * yieldForCallback ([&]() {
+ * startSomeWork ([&]() {
+ * invokeFromCallback();
+ * });
+ * });
+ * continueWhenWorkIsFinished();
+ * \endcode
+ *
+ * Captures the stack, runs the `fun` and relinquish the control to `_returnTo`.\n
+ * This method will never "return" by itself, in order for it to "return" the
+ * `fun` MUST call `invokeFromCallback`, maybe later and from a different stack. */
+ template <typename F> CBCoroPtr yieldForCallback (F fun) {
+ CBCoroPtr ptr (this);
+ _yieldFromInvoke = false;
+ if (getcontext (&_context)) GTHROW ("!getcontext"); // Capture.
+ if (_yieldFromInvoke) {
+ // We're now in the future, revived by the `invokeFromCallback`.
+ // All we do now is "return" to the caller whose stack we captured earlier.
+ } else {
+ // We're still in the present, still have some work to do.
+ fun(); // The `fun` is supposed to do something resulting in the `invokeFromCallback` being called later.
+ if (_invokeFromYield) {
+ // The `fun` used the `invokeFromCallback` directly, not resorting to callbacks, meaning we don't have to do our magick.
+ _invokeFromYield = false;
+ } else {
+ // So, the `fun` took measures to revive us later, it's time for us to go into torpor and return the control to whoever we've borrowed it from.
+ cbcReturn();
+ }
+ }
+ return ptr;
+ }
+
+ /// To be called from a callback in order to lend the control to CBCoro, continuing it from where it called `yieldForCallback`.
+ CBCoroPtr invokeFromCallback() {
+ CBCoroPtr ptr (this);
+ _mutex.lock(); // Wait for an other-thready `yieldForCallback` to finish.
+ if (_returnTo != nullptr) {
+ // We have not yet "returned" from the `yieldForCallback`,
+ // meaning that the `invokeFromCallback` was executed immediately from inside the `yieldForCallback`.
+ // In that case we must DO NOTHING, we must simply continue running on the current stack.
+ _invokeFromYield = true; // Tells `yieldForCallback` to do nothing.
+ } else {
+ // Revive the CBCoro, letting it continue from where it was suspended in `yieldForCallback`.
+ ucontext_t cbContext; _returnTo = &cbContext; _yieldFromInvoke = true;
+ if (swapcontext (&cbContext, &_context)) GTHROW ("!swapcontext");
+ // NB: When the CBCoro is suspended or exits, the control returns back there and then back to the callback from which we borrowed it.
+ if (_returnTo == &cbContext) _returnTo = nullptr;
+ }
+ _mutex.unlock(); // Other-thready `yieldForCallback` has finished and `cbcReturn`ed here.
+ return ptr;
+ }
+};
+
+/** CBCoro running a given functor.
+ * The functor's first argument must be a CBCoro pointer, like this: \code (new CBCoroForFunctor ([](CBCoro* cbcoro) {}))->start(); \endcode */
+template <typename FUN> struct CBCoroForFunctor: public CBCoro {
+ FUN _fun;
+ template <typename CFUN> CBCoroForFunctor (CFUN&& fun, uint8_t cacheStack, size_t stackSize): CBCoro (cacheStack, stackSize), _fun (std::forward<CFUN> (fun)) {}
+ virtual void run() {_fun (this);}
+ virtual ~CBCoroForFunctor() {}
+};
+
+/** Syntactic sugar: Runs a given functor in a CBCoro instance.
+ * Example: \code glim::cbCoro ([](glim::CBCoro* cbcoro) {}); \endcode
+ * Returns a `CBCoroPtr` to the CBCoro instance holding the `fun` which might be held somewhere in order to delay the deletion of `fun`. */
+template <typename FUN> inline CBCoro::CBCoroPtr cbCoro (FUN&& fun, uint8_t cacheStack = CBCoro::defaultCacheSize(), size_t stackSize = CBCoro::defaultStackSize()) {
+ return (new CBCoroForFunctor<FUN> (std::forward<FUN> (fun), cacheStack, stackSize))->start();
+}
+
+}
diff --git a/external/glim/channel.hpp b/external/glim/channel.hpp
new file mode 100644
index 000000000..e5ca23bdf
--- /dev/null
+++ b/external/glim/channel.hpp
@@ -0,0 +1,40 @@
+#ifndef _GLIM_CHANNEL_INCLUDED
+#define _GLIM_CHANNEL_INCLUDED
+
+#include <atomic>
+#include <mutex>
+#include <thread>
+
+namespace glim {
+
+/// Unbuffered channel.
+/// Optimized for a single value (busy-waits on a second one).
+template <typename V>
+struct Channel {
+ V _v;
+ std::mutex _mutex; // Locked when there is no value.
+ std::atomic_int_fast8_t _state; enum State {EMPTY = 0, WRITING = 1, FULL = 2};
+ Channel(): _state (EMPTY) {_mutex.lock();}
+ // Waits until the Channel is empty then stores the value.
+ template <typename VA> void send (VA&& v) {
+ for (;;) {
+ int_fast8_t expectEmpty = EMPTY; if (_state.compare_exchange_weak (expectEmpty, WRITING)) break;
+ std::this_thread::sleep_for (std::chrono::milliseconds (20));
+ }
+ try {_v = std::forward<V> (v);} catch (...) {_state = EMPTY; throw;}
+ _state = FULL;
+ _mutex.unlock(); // Allows the reader to proceed.
+ }
+ // Waits untill there is a value to receive.
+ V receive() {
+ _mutex.lock(); // Wait.
+ V tmp = std::move (_v);
+ assert (_state == FULL);
+ _state = EMPTY;
+ return tmp;
+ }
+};
+
+} // namespace glim
+
+#endif
diff --git a/external/glim/curl.hpp b/external/glim/curl.hpp
new file mode 100644
index 000000000..ff2ba9ac1
--- /dev/null
+++ b/external/glim/curl.hpp
@@ -0,0 +1,304 @@
+/** \file
+ * Very simple header-only wrapper around libcurl.\n
+ * See also: https://github.com/venam/Browser\n
+ * See also: https://github.com/mologie/curl-asio\n
+ * See also: http://thread.gmane.org/gmane.comp.web.curl.library/1322 (this one uses a temporary file). */
+
+#ifndef _GLIM_CURL_INCLUDED
+#define _GLIM_CURL_INCLUDED
+
+#include "gstring.hpp"
+#include "exception.hpp"
+#include <curl/curl.h>
+#include <algorithm>
+#include <functional>
+#include <string.h>
+#include <stdint.h>
+
+namespace glim {
+
+inline size_t curlWriteToString (void *buffer, size_t size, size_t nmemb, void *userp) {
+ ((std::string*) userp)->append ((const char*) buffer, size * nmemb);
+ return size * nmemb;};
+
+inline size_t curlReadFromString (void *ptr, size_t size, size_t nmemb, void *userdata);
+inline size_t curlReadFromGString (void *ptr, size_t size, size_t nmemb, void *userdata);
+inline size_t curlWriteHeader (void *ptr, size_t size, size_t nmemb, void *curlPtr);
+inline int curlDebugCB (CURL* curl, curl_infotype type, char* bytes, size_t size, void* curlPtr);
+
+/**
+ Simple HTTP requests using cURL.
+ Example: \code
+ std::string w3 = glim::Curl() .http ("http://www.w3.org/") .go().str();
+ \endcode
+ */
+class Curl {
+ protected:
+ Curl (const Curl&): _curl (NULL), _headers (NULL), _sent (0), _needs_cleanup (true) {} // No copying.
+ public:
+ struct PerformError: public glim::Exception {
+ PerformError (const char* message, const char* file, int32_t line):
+ glim::Exception (message, file, line) {}
+ };
+ struct GetinfoError: public glim::Exception {
+ CURLcode _code; std::string _error;
+ GetinfoError (CURLcode code, const std::string& error, const char* file, int32_t line):
+ glim::Exception (error, file, line),
+ _code (code), _error (error) {}
+ };
+ public:
+ CURL* _curl;
+ struct curl_slist *_headers;
+ std::function<void (const char* header, int len)> _headerListener;
+ std::function<void (curl_infotype type, char* bytes, size_t size)> _debugListener;
+ std::string _sendStr; ///< We're using `std::string` instead of `gstring` in order to support payloads larger than 16 MiB.
+ glim::gstring _sendGStr; ///< `gstring::view` and `gstring::ref` allow us to zero-copy.
+ uint32_t _sent;
+ std::string _got;
+ bool _needs_cleanup:1; ///< ~Curl will do `curl_easy_cleanup` if `true`.
+ char _errorBuf[CURL_ERROR_SIZE];
+
+ Curl (Curl&&) = default;
+
+ /// @param cleanup can be turned off if the cURL is freed elsewhere.
+ Curl (bool cleanup = true): _curl (curl_easy_init()), _headers (NULL), _sent (0), _needs_cleanup (cleanup) {
+ curl_easy_setopt (_curl, CURLOPT_NOSIGNAL, 1L); // required per http://curl.haxx.se/libcurl/c/libcurl-tutorial.html#Multi-threading
+ *_errorBuf = 0;}
+ /// Wraps an existing handle (will invoke `curl_easy_cleanup` nevertheless).
+ /// @param cleanup can be turned off if the cURL is freed elsewhere.
+ Curl (CURL* curl, bool cleanup = true): _curl (curl), _headers (NULL), _sent (0), _needs_cleanup (cleanup) {
+ curl_easy_setopt (_curl, CURLOPT_NOSIGNAL, 1L); // required per http://curl.haxx.se/libcurl/c/libcurl-tutorial.html#Multi-threading
+ *_errorBuf = 0;}
+ ~Curl(){
+ if (_headers) {curl_slist_free_all (_headers); _headers = NULL;}
+ if (_curl) {if (_needs_cleanup) curl_easy_cleanup (_curl); _curl = NULL;}
+ }
+
+ /** Stores the content to be sent into an `std::string` inside `Curl`.
+ * NB: In order to have an effect this method should be used *before* the `http()` and `smtp()` methods. */
+ template<typename STR> Curl& send (STR&& text) {
+ _sendStr = std::forward<STR> (text);
+ _sendGStr.clear();
+ _sent = 0;
+ return *this;}
+
+ /// Adds "Content-Type" header into `_headers`.
+ Curl& contentType (const char* ct) {
+ char ctb[64]; gstring cth (sizeof (ctb), ctb, false, 0);
+ cth << "Content-Type: " << ct << "\r\n";
+ _headers = curl_slist_append (_headers, cth.c_str());
+ return *this;
+ }
+
+ /// @param fullHeader is a full HTTP header and a newline, e.g. "User-Agent: Me\r\n".
+ Curl& header (const char* fullHeader) {
+ _headers = curl_slist_append (_headers, fullHeader);
+ return *this;
+ }
+
+ /**
+ Sets the majority of options for the http request.
+ NB: If `send` was used with a non-empty string then `http` will use `CURLOPT_UPLOAD`, setting http method to `PUT` (use the `method()` to override).
+ \n
+ Example: \code
+ glim::Curl curl;
+ curl.http (url.c_str()) .go();
+ std::cout << curl.status() << std::endl << curl.str() << std::endl;
+ \endcode
+ */
+ Curl& http (const char* url, int timeoutSec = 20) {
+ curl_easy_setopt (_curl, CURLOPT_NOSIGNAL, 1L); // required per http://curl.haxx.se/libcurl/c/libcurl-tutorial.html#Multi-threading
+ curl_easy_setopt (_curl, CURLOPT_URL, url);
+ curl_easy_setopt (_curl, CURLOPT_WRITEFUNCTION, curlWriteToString);
+ curl_easy_setopt (_curl, CURLOPT_WRITEDATA, &_got);
+ curl_easy_setopt (_curl, CURLOPT_TIMEOUT, timeoutSec);
+ curl_easy_setopt (_curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP);
+ curl_easy_setopt (_curl, CURLOPT_ERRORBUFFER, _errorBuf);
+ if (_sendStr.size() || _sendGStr.size()) {
+ curl_easy_setopt (_curl, CURLOPT_UPLOAD, 1L); // http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTUPLOAD
+ if (_sendStr.size()) {
+ curl_easy_setopt (_curl, CURLOPT_INFILESIZE, (long) _sendStr.size());
+ curl_easy_setopt (_curl, CURLOPT_READFUNCTION, curlReadFromString);
+ } else {
+ curl_easy_setopt (_curl, CURLOPT_INFILESIZE, (long) _sendGStr.size());
+ curl_easy_setopt (_curl, CURLOPT_READFUNCTION, curlReadFromGString);}
+ curl_easy_setopt (_curl, CURLOPT_READDATA, this);}
+ if (_headers)
+ curl_easy_setopt (_curl, CURLOPT_HTTPHEADER, _headers); // http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTHTTPHEADER
+ return *this;
+ }
+
+ /**
+ Set options for smtp request.
+ Example: \code
+ long rc = glim::Curl().send ("Subject: subject\r\n\r\n" "text\r\n") .smtp ("from", "to") .go().status();
+ if (rc != 250) std::cerr << "Error sending email: " << rc << std::endl;
+ \endcode */
+ Curl& smtp (const char* from, const char* to) {
+ curl_easy_setopt (_curl, CURLOPT_NOSIGNAL, 1L); // required per http://curl.haxx.se/libcurl/c/libcurl-tutorial.html#Multi-threading
+ curl_easy_setopt (_curl, CURLOPT_URL, "smtp://127.0.0.1");
+ if (from) curl_easy_setopt (_curl, CURLOPT_MAIL_FROM, from);
+ bcc (to);
+ if (_headers) curl_easy_setopt (_curl, CURLOPT_MAIL_RCPT, _headers);
+ curl_easy_setopt (_curl, CURLOPT_WRITEFUNCTION, curlWriteToString);
+ curl_easy_setopt (_curl, CURLOPT_WRITEDATA, &_got);
+ if (_sendStr.size()) {
+ curl_easy_setopt (_curl, CURLOPT_INFILESIZE, (long) _sendStr.size());
+ curl_easy_setopt (_curl, CURLOPT_READFUNCTION, curlReadFromString);
+ curl_easy_setopt (_curl, CURLOPT_READDATA, this);
+ } else if (_sendGStr.size()) {
+ curl_easy_setopt (_curl, CURLOPT_INFILESIZE, (long) _sendGStr.size());
+ curl_easy_setopt (_curl, CURLOPT_READFUNCTION, curlReadFromGString);
+ curl_easy_setopt (_curl, CURLOPT_READDATA, this);
+ }
+ curl_easy_setopt (_curl, CURLOPT_UPLOAD, 1L); // cURL now needs this to actually send the email, cf. "http://curl.haxx.se/mail/lib-2013-12/0152.html".
+ return *this;
+ }
+
+ /** Add SMTP recipient to the `_headers` (which are then set into `CURLOPT_MAIL_RCPT` by the `Curl::smtp`).
+ * NB: Should be used *before* the `Curl::smtp`! */
+ Curl& bcc (const char* to) {
+ if (to) _headers = curl_slist_append (_headers, to);
+ return *this;
+ }
+
+ /**
+ Uses `CURLOPT_CUSTOMREQUEST` to set the http method.
+ Can be used both before and after the `http` method.\n
+ Example sending a POST request to ElasticSearch: \code
+ glim::Curl curl;
+ curl.send (C2GSTRING (R"({"query":{"match_all":{}},"facets":{"tags":{"terms":{"field":"tags","size":1000}}}})"));
+ curl.method ("POST") .http ("http://127.0.0.1:9200/froples/frople/_search", 120);
+ if (curl.verbose().go().status() != 200) GTHROW ("Error fetching tags: " + std::to_string (curl.status()) + ", " + curl.str());
+ cout << curl.gstr() << endl;
+ \endcode */
+ Curl& method (const char* method) {
+ curl_easy_setopt (_curl, CURLOPT_CUSTOMREQUEST, method);
+ return *this;
+ }
+
+ /** Setup a handler to process the headers cURL gets from the response.
+ * "The header callback will be called once for each header and only complete header lines are passed on to the callback".\n
+ * See http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTHEADERFUNCTION */
+ Curl& headerListener (std::function<void (const char* header, int len)> listener) {
+ curl_easy_setopt (_curl, CURLOPT_HEADERFUNCTION, curlWriteHeader);
+ curl_easy_setopt (_curl, CURLOPT_WRITEHEADER, this);
+ _headerListener = listener;
+ return *this;
+ }
+
+ /** Setup a handler to get the debug messages generated by cURL.
+ * See http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTDEBUGFUNCTION */
+ Curl& debugListener (std::function<void (curl_infotype type, char* bytes, size_t size)> listener) {
+ curl_easy_setopt (_curl, CURLOPT_DEBUGFUNCTION, curlDebugCB);
+ curl_easy_setopt (_curl, CURLOPT_DEBUGDATA, this);
+ _debugListener = listener;
+ return verbose (true);
+ }
+
+ /**
+ Setup a handler to get some of the debug messages generated by cURL.
+ Listener gets a formatted text: outbound data is prepended with "> " and inbound with "< ".\n
+ Usage example: \code
+ auto curlDebug = std::make_shared<std::string>();
+ curl->debugListenerF ([curlDebug](const char* bytes, size_t size) {curlDebug->append (bytes, size);});
+ ...
+ if (curl->status() != 200) std::cerr << "cURL status != 200; debug follows: " << *curlDebug << std::endl;
+ \endcode
+ See http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTDEBUGFUNCTION
+ @param listener The receiver of the debug information.
+ @param data Whether to pass the data (`CURLINFO_DATA_IN`, `CURLINFO_DATA_OUT`) to the `listener`.
+ */
+ Curl& debugListenerF (std::function<void (const char* bytes, size_t size)> listener, bool data = false) {
+ return debugListener ([listener/* = std::move (listener)*/,data] (curl_infotype type, char* bytes, size_t size) {
+ GSTRING_ON_STACK (buf, 256);
+ auto prepend = [&](const char* prefix) {
+ buf << prefix; for (char *p = bytes, *end = bytes + size; p < end; ++p) {buf << *p; if (*p == '\n' && p + 2 < end) buf << prefix;}};
+ if (type == CURLINFO_HEADER_IN || (type == CURLINFO_DATA_IN && data)) prepend ("< ");
+ else if (type == CURLINFO_HEADER_OUT || (type == CURLINFO_DATA_OUT && data)) prepend ("> ");
+ listener (buf.c_str(), buf.size());
+ });
+ }
+
+ /// Whether to print debug information to `CURLOPT_STDERR`.
+ /// Note that when `debugListener` is used, verbose output will go to the listener and not to `CURLOPT_STDERR`.
+ Curl& verbose (bool on = true) {
+ curl_easy_setopt (_curl, CURLOPT_VERBOSE, on ? 1L : 0L);
+ return *this;
+ }
+
+ /// Reset the buffers and perform the cURL request.
+ Curl& go() {
+ _got.clear();
+ *_errorBuf = 0;
+ if (curl_easy_perform (_curl)) throw PerformError (_errorBuf, __FILE__, __LINE__);
+ return *this;
+ }
+
+ /// The contents of the response.
+ const std::string& str() const {return _got;}
+ /// CString of `str`.
+ const char* c_str() const {return _got.c_str();}
+ /// Returns a gstring "view" into `str`.
+ gstring gstr() const {return gstring (0, (void*) _got.data(), false, _got.size());}
+
+ /// The status of the response (For HTTP it's 200 ok, 404 not found, 500 error, etc).
+ long status() const {
+ long status; CURLcode err = curl_easy_getinfo (_curl, CURLINFO_RESPONSE_CODE, &status);
+ if (err) {
+ GSTRING_ON_STACK (message, 128) << "CURL error " << (int) err << ": " << curl_easy_strerror (err);
+ throw GetinfoError (err, message.str(), __FILE__, __LINE__);
+ }
+ return status;}
+};
+
+/** Moves the content to be sent into a `glim::gstring` inside `Curl`.
+ * NB: In order to have an effect this method should be used *before* the `http()` and `smtp()` methods. */
+template<> inline Curl& Curl::send<gstring> (gstring&& text) {
+ _sendStr.clear();
+ _sendGStr = std::move (text);
+ _sent = 0;
+ return *this;}
+
+inline size_t curlReadFromString (void *ptr, size_t size, size_t nmemb, void *userdata) {
+ Curl* curl = (Curl*) userdata;
+ size_t len = std::min (curl->_sendStr.size() - curl->_sent, size * nmemb);
+ if (len) memcpy (ptr, curl->_sendStr.data() + curl->_sent, len);
+ curl->_sent += len;
+ return len;}
+
+inline size_t curlReadFromGString (void *ptr, size_t size, size_t nmemb, void *userdata) {
+ Curl* curl = (Curl*) userdata;
+ size_t len = std::min (curl->_sendGStr.size() - curl->_sent, size * nmemb);
+ if (len) memcpy (ptr, curl->_sendGStr.data() + curl->_sent, len);
+ curl->_sent += len;
+ return len;}
+
+// http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTHEADERFUNCTION
+inline size_t curlWriteHeader (void *ptr, size_t size, size_t nmemb, void *curlPtr) {
+ Curl* curl = (Curl*) curlPtr;
+ std::function<void (const char* header, int len)>& listener = curl->_headerListener;
+ int len = size * nmemb;
+ if (listener) listener ((const char*) ptr, len);
+ return (size_t) len;
+}
+
+// http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTDEBUGFUNCTION
+inline int curlDebugCB (CURL*, curl_infotype type, char* bytes, size_t size, void* curlPtr) {
+ Curl* curl = (Curl*) curlPtr;
+ auto& listener = curl->_debugListener;
+ if (listener) listener (type, bytes, size);
+ return 0;
+}
+
+/// Example: std::string w3 = glim::curl2str ("http://www.w3.org/");
+inline std::string curl2str (const char* url, int timeoutSec = 20) {
+ try {
+ return glim::Curl().http (url, timeoutSec) .go().str();
+ } catch (const std::exception&) {}
+ return std::string();
+}
+
+}
+
+#endif
diff --git a/external/glim/doxyconf b/external/glim/doxyconf
new file mode 100644
index 000000000..592d04603
--- /dev/null
+++ b/external/glim/doxyconf
@@ -0,0 +1,237 @@
+# Doxyfile 1.8.4; http://www.stack.nl/~dimitri/doxygen/manual/config.html
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = "libglim"
+PROJECT_NUMBER = 0.7
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 2
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+# http://daringfireball.net/projects/markdown/
+MARKDOWN_SUPPORT = YES
+AUTOLINK_SUPPORT = YES
+BUILTIN_STL_SUPPORT = YES
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = NO
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+INLINE_GROUPED_CLASSES = NO
+INLINE_SIMPLE_STRUCTS = YES
+TYPEDEF_HIDES_STRUCT = NO
+LOOKUP_CACHE_SIZE = 0
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_PACKAGE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+FORCE_LOCAL_INCLUDES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = YES
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+STRICT_PROTO_MATCHING = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = NO
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+
+INPUT = ./
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.hpp
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = test_*.cc
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+FILTER_SOURCE_FILES = NO
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = NO
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = YES
+CLANG_ASSISTED_PARSING = NO
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 5
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
+HTML_EXTRA_FILES =
+HTML_COLORSTYLE_HUE = 220
+HTML_COLORSTYLE_SAT = 100
+HTML_COLORSTYLE_GAMMA = 80
+HTML_TIMESTAMP = YES
+HTML_DYNAMIC_SECTIONS = NO
+HTML_INDEX_NUM_ENTRIES = 100
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+DOCSET_PUBLISHER_NAME = Publisher
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE = org.doxygen.Project
+QHP_VIRTUAL_FOLDER = doc
+QHP_CUST_FILTER_NAME =
+QHP_CUST_FILTER_ATTRS =
+QHP_SECT_FILTER_ATTRS =
+QHG_LOCATION =
+GENERATE_ECLIPSEHELP = NO
+ECLIPSE_DOC_ID = org.doxygen.Project
+DISABLE_INDEX = NO
+GENERATE_TREEVIEW = NO
+ENUM_VALUES_PER_LINE = 4
+TREEVIEW_WIDTH = 250
+EXT_LINKS_IN_WINDOW = NO
+FORMULA_FONTSIZE = 10
+FORMULA_TRANSPARENT = YES
+USE_MATHJAX = NO
+MATHJAX_FORMAT = HTML-CSS
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+MATHJAX_EXTENSIONS =
+MATHJAX_CODEFILE =
+SEARCHENGINE = YES
+SERVER_BASED_SEARCH = NO
+EXTERNAL_SEARCH = NO
+SEARCHENGINE_URL =
+SEARCHDATA_FILE = searchdata.xml
+EXTERNAL_SEARCH_ID =
+EXTRA_SEARCH_MAPPINGS =
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4
+EXTRA_PACKAGES =
+LATEX_HEADER =
+LATEX_FOOTER =
+LATEX_EXTRA_FILES =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+LATEX_SOURCE_CODE = NO
+LATEX_BIB_STYLE = plain
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+GENERATE_DOCBOOK = NO
+DOCBOOK_OUTPUT = docbook
+GENERATE_AUTOGEN_DEF = NO
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+EXTERNAL_PAGES = YES
+PERL_PATH = /usr/bin/perl
+CLASS_DIAGRAMS = YES
+MSCGEN_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+DOT_NUM_THREADS = 0
+DOT_FONTNAME = Helvetica
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+UML_LIMIT_NUM_FIELDS = 10
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+INTERACTIVE_SVG = NO
+DOT_PATH =
+DOTFILE_DIRS =
+MSCFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 0
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
diff --git a/external/glim/exception.hpp b/external/glim/exception.hpp
new file mode 100644
index 000000000..5fbfc5aa1
--- /dev/null
+++ b/external/glim/exception.hpp
@@ -0,0 +1,259 @@
+#ifndef _GLIM_EXCEPTION_HPP_INCLUDED
+#define _GLIM_EXCEPTION_HPP_INCLUDED
+
+/// \file
+/// Exceptions with configurable behaviour.
+/// Requires `thread_local` support introduced in [gcc-4.8](http://gcc.gnu.org/gcc-4.8/changes.html)
+/// (`__thread` is not reliable with GCC 4.7.2 across shared libraries).
+
+#include <stdexcept>
+#include <string>
+#include <sstream>
+#include <stdint.h>
+#include <stdlib.h> // free
+#include <unistd.h> // write
+
+/// Throws `::glim::Exception` passing the current file and line into constructor.
+#define GTHROW(message) throw ::glim::Exception (message, __FILE__, __LINE__)
+/// Throws a `::glim::Exception` derived exception `name` passing the current file and line into constructor.
+#define GNTHROW(name, message) throw name (message, __FILE__, __LINE__)
+/// Helps defining new `::glim::Exception`-based exceptions.
+/// Named exceptions might be useful in a debugger.
+#define G_DEFINE_EXCEPTION(name) \
+ struct name: public ::glim::Exception { \
+ name (const ::std::string& message, const char* file, int line): ::glim::Exception (message, file, line) {} \
+ }
+
+// Workaround to compile under GCC 4.7.
+#if defined (__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 7 && !defined (thread_local)
+# define thread_local __thread
+#endif
+
+namespace glim {
+
+// Ideas:
+// RAII control via thread-local integer (with bits): option to capture stack trace (printed on "what()")
+// see http://stacktrace.svn.sourceforge.net/viewvc/stacktrace/stacktrace/call_stack_gcc.cpp?revision=40&view=markup
+// A handler to log exception with VALGRIND (with optional trace)
+// A handler to log thread id and *pause* the thread in exception constructor (user can attach GDB and investigate)
+// (or we might call an empty function: "I once used something similar,
+// but with an empty function debug_breakpoint. When debugging, I simply entered "bre debug_breakpoint"
+// at the gdb prompt - no asembler needed (compile debug_breakpoint in a separate compilation unit to avoid having the call optimized away)."
+// - http://stackoverflow.com/a/4720403/257568)
+// A handler to call a debugger? (see: http://stackoverflow.com/a/4732119/257568)
+
+// todo: Try a helper which uses cairo's backtrace-symbols.c
+// http://code.ohloh.net/file?fid=zUOUdEl-Id-ijyPOmCkVnBJt2d8&cid=zGpizbyIjEw&s=addr2line&browser=Default#L7
+
+// todo: Try a helper which uses cairo's lookup-symbol.c
+// http://code.ohloh.net/file?fid=Je2jZqsOxge_SvWVrvywn2I0TIs&cid=zGpizbyIjEw&s=addr2line&browser=Default#L0
+
+// todo: A helper converting backtrace to addr2line invocation, e.g.
+// bin/test_exception() [0x4020cc];bin/test_exception(__cxa_throw+0x47) [0x402277];bin/test_exception() [0x401c06];/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) [0x57f0ead];bin/test_exception() [0x401fd1];
+// should be converted to
+// addr2line -pifCa -e bin/test_exception 0x4020cc 0x402277 0x401c06 0x57f0ead 0x401fd1
+//
+// The helper should read the shared library addresses from /proc/.../map and generate separate addr2line invocations
+// for groups of addresses inside the same shared library.
+// => dladdr instead of /proc/../map; http://stackoverflow.com/a/2606152/257568
+//
+// Shared libraries (http://stackoverflow.com/a/7557756/257568).
+// Example, backtrace: /usr/local/lib/libfrople.so(_ZN5mongo14BSONObjBuilder8appendAsERKNS_11BSONElementERKNS_10StringDataE+0x1ca) [0x2aef5b45eb8a]
+// cat /proc/23630/maps | grep libfrople
+// -> 2aef5b363000-2aef5b53e000
+// 0x2aef5b45eb8a - 2aef5b363000 = FBB8A
+// addr2line -pifCa -e /usr/local/lib/libfrople.so 0xFBB8A
+//
+// cat /proc/`pidof FropleAndImg2`/maps | grep libfrople
+// addr2line -pifCa -e /usr/local/lib/libfrople.so `perl -e 'printf ("%x", 0x2aef5b45eb8a - 0x2aef5b363000)'`
+
+inline void captureBacktrace (void* stdStringPtr);
+
+typedef void (*exception_handler_fn)(void*);
+
+/// Exception with file and line information and optional stack trace capture.
+/// Requires `thread_local` support ([gcc-4.8](http://gcc.gnu.org/gcc-4.8/changes.html)).
+class Exception: public std::runtime_error {
+ protected:
+ const char* _file; int32_t _line;
+ std::string _what;
+ uint32_t _options;
+
+ /// Append [{file}:{line}] into `buf`.
+ void appendLine (std::string& buf) const {
+ if (_file || _line > 0) {
+ std::ostringstream oss;
+ oss << '[';
+ if (_file) oss << _file;
+ if (_line >= 0) oss << ':' << _line;
+ oss << "] ";
+ buf.append (oss.str());
+ }
+ }
+
+ /// Append a stack trace to `_what`.
+ void capture() {
+ if (_options & RENDEZVOUS) rendezvous();
+ if (_options & CAPTURE_TRACE) {
+ appendLine (_what);
+ _what += "[at ";
+ captureBacktrace (&_what);
+ _what.append ("] ");
+ _what += std::runtime_error::what();
+ }
+ }
+
+ public:
+ /** The reference to the thread-local options. */
+ inline static uint32_t& options() {
+ static thread_local uint32_t EXCEPTION_OPTIONS = 0;
+ return EXCEPTION_OPTIONS;
+ }
+ enum Options: uint32_t {
+ PLAIN_WHAT = 1, ///< Pass `what` as is, do not add any information to it.
+ HANDLE_ALL = 1 << 1, ///< Run the custom handler from `__cxa_throw`.
+ CAPTURE_TRACE = 1 << 2, ///< Append a stack trace into the `Exception::_what` (with the help of the `captureBacktrace`).
+ RENDEZVOUS = 1 << 3 ///< Call the rendezvous function in `throw` and in `what`, so that the GDB can catch it (break glim::Exception::rendezvous).
+ };
+
+ /** The pointer to the thread-local exception handler. */
+ inline static exception_handler_fn* handler() {
+ static thread_local exception_handler_fn EXCEPTION_HANDLER = nullptr;
+ return &EXCEPTION_HANDLER;
+ }
+ /** The pointer to the thread-local argument for the exception handler. */
+ inline static void** handlerArg() {
+ static thread_local void* EXCEPTION_HANDLER_ARG = nullptr;
+ return &EXCEPTION_HANDLER_ARG;
+ }
+
+ /// Invoked when the `RENDEZVOUS` option is set in order to help the debugger catch the exception (break glim::Exception::rendezvous).
+ static void rendezvous() __attribute__((noinline)) {
+ asm (""); // Prevents the function from being optimized away.
+ }
+
+ Exception (const std::string& message):
+ std::runtime_error (message), _file (0), _line (-1), _options (options()) {
+ capture();}
+ Exception (const std::string& message, const char* file, int32_t line):
+ std::runtime_error (message), _file (file), _line (line), _options (options()) {
+ capture();}
+ ~Exception() throw() {}
+ virtual const char* what() const throw() {
+ if (_options & RENDEZVOUS) rendezvous();
+ if (_options & PLAIN_WHAT) return std::runtime_error::what();
+ std::string& buf = const_cast<std::string&> (_what);
+ if (buf.empty()) {
+ appendLine (buf);
+ buf.append (std::runtime_error::what());
+ }
+ return buf.c_str();
+ }
+};
+
+/// RAII control of thrown `Exception`s.
+/// Example: \code
+/// glim::ExceptionControl trace (glim::Exception::Options::CAPTURE_TRACE);
+/// \endcode
+/// Modifies the `Exception` options via a thread-local variable and restores them back upon destruction.\n
+/// Currently uses http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Thread_002dLocal.html
+/// (might use C++11 `thread_local` in the future).
+class ExceptionControl {
+ protected:
+ uint32_t _savedOptions;
+ public:
+ ExceptionControl (uint32_t newOptions) {
+ uint32_t& options = Exception::options();
+ _savedOptions = options;
+ options = newOptions;
+ }
+ ~ExceptionControl() {
+ Exception::options() = _savedOptions;
+ }
+};
+
+class ExceptionHandler {
+protected:
+ uint32_t _savedOptions;
+ exception_handler_fn _savedHandler;
+ void* _savedHandlerArg;
+public:
+ ExceptionHandler (uint32_t newOptions, exception_handler_fn handler, void* handlerArg) {
+ uint32_t& options = Exception::options(); _savedOptions = options; options = newOptions;
+ exception_handler_fn* handler_ = Exception::handler(); _savedHandler = *handler_; *handler_ = handler;
+ void** handlerArg_ = Exception::handlerArg(); _savedHandlerArg = *handlerArg_; *handlerArg_ = handlerArg;
+ }
+ ~ExceptionHandler() {
+ Exception::options() = _savedOptions;
+ *Exception::handler() = _savedHandler;
+ *Exception::handlerArg() = _savedHandlerArg;
+ }
+};
+
+} // namespace glim
+
+#if defined(__GNUC__) && (defined (__linux__) || defined (_SYSTYPE_BSD))
+# include <execinfo.h> // backtrace; http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
+# define _GLIM_USE_EXECINFO
+#endif
+
+namespace glim {
+
+/** If `stdStringPtr` is not null then backtrace is saved there (must point to an std::string instance),
+ * otherwise printed to write(2). */
+void captureBacktrace (void* stdStringPtr) {
+#ifdef _GLIM_USE_EXECINFO
+ const int arraySize = 10; void *array[arraySize];
+ int got = ::backtrace (array, arraySize);
+ if (stdStringPtr) {
+ std::string* out = (std::string*) stdStringPtr;
+ char **strings = ::backtrace_symbols (array, got);
+ for (int tn = 0; tn < got; ++tn) {out->append (strings[tn]); out->append (1, ';');}
+ ::free (strings);
+ } else ::backtrace_symbols_fd (array, got, 2);
+#else
+# warning captureBacktrace: I do not know how to capture backtrace there. Patches welcome.
+#endif
+}
+
+} // namespace glim
+
+#endif // _GLIM_EXCEPTION_HPP_INCLUDED
+
+/**
+ * Special handler for ALL exceptions. Usage:
+ * 1) In the `main` module inject this code with:
+ * #define _GLIM_ALL_EXCEPTIONS_CODE
+ * #include <glim/exception.hpp>
+ * 2) Link with "-ldl" (for `dlsym`).
+ * 3) Use the ExceptionHandler to enable special behaviour in the current thread:
+ * glim::ExceptionHandler traceExceptions (glim::Exception::Options::HANDLE_ALL, glim::captureBacktrace, nullptr);
+ *
+ * About handing all exceptions see:
+ * http://stackoverflow.com/a/11674810/257568
+ * http://blog.sjinks.pro/c-cpp/969-track-uncaught-exceptions/
+ */
+#ifdef _GLIM_ALL_EXCEPTIONS_CODE
+
+#include <dlfcn.h> // dlsym
+
+typedef void(*cxa_throw_type)(void*, void*, void(*)(void*)); // Tested with GCC 4.7.
+static cxa_throw_type NATIVE_CXA_THROW = 0;
+
+extern "C" void __cxa_throw (void* thrown_exception, void* tinfo, void (*dest)(void*)) {
+ if (!NATIVE_CXA_THROW) NATIVE_CXA_THROW = reinterpret_cast<cxa_throw_type> (::dlsym (RTLD_NEXT, "__cxa_throw"));
+ if (!NATIVE_CXA_THROW) ::std::terminate();
+
+ using namespace glim;
+ uint32_t options = Exception::options();
+ if (options & Exception::RENDEZVOUS) Exception::rendezvous();
+ if (options & Exception::HANDLE_ALL) {
+ exception_handler_fn handler = *Exception::handler();
+ if (handler) handler (*Exception::handlerArg());
+ }
+
+ NATIVE_CXA_THROW (thrown_exception, tinfo, dest);
+}
+
+#undef _GLIM_ALL_EXCEPTIONS_CODE
+#endif // _GLIM_ALL_EXCEPTIONS_CODE
diff --git a/external/glim/gstring.hpp b/external/glim/gstring.hpp
new file mode 100644
index 000000000..eb0ea2cb7
--- /dev/null
+++ b/external/glim/gstring.hpp
@@ -0,0 +1,578 @@
+#ifndef _GSTRING_INCLUDED
+#define _GSTRING_INCLUDED
+
+/**
+ * A C++ char string.\n
+ * Can reuse (stack-allocated) buffers.\n
+ * Can create zero-copy views.
+ * @code
+Copyright 2012 Kozarezov Artem Aleksandrovich
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * @endcode
+ * @file
+ */
+
+#include <assert.h>
+#include <stdlib.h> // malloc, realloc, free
+#include <stdint.h>
+#include <string.h> // memcpy, memmem
+#include <stdio.h> // snprintf
+#include <stdexcept>
+#include <iostream>
+#include <iterator>
+
+#include "exception.hpp"
+
+/// Make a read-only gstring from a C string: `const gstring foo = C2GSTRING("foo")`.
+#define C2GSTRING(CSTR) ::glim::gstring (::glim::gstring::ReferenceConstructor(), CSTR, sizeof (CSTR) - 1, true)
+/// Usage: GSTRING_ON_STACK (buf, 64) << "foo" << "bar";
+#define GSTRING_ON_STACK(NAME, SIZE) char NAME##Buf[SIZE]; ::glim::gstring NAME (SIZE, NAME##Buf, false, 0); NAME.self()
+
+namespace glim {
+
+/**
+ * Based on: C++ version 0.4 char* style "itoa": Written by Lukás Chmela, http://www.strudel.org.uk/itoa/ (GPLv3).
+ * Returns a pointer to the end of the string.
+ * NB about `inline`: http://stackoverflow.com/a/1759575/257568
+ * @param base Maximum is 36 (see http://en.wikipedia.org/wiki/Base_36).
+ */
+inline char* itoa (char* ptr, int64_t value, const int base = 10) {
+ // check that the base is valid
+ if (base < 2 || base > 36) {*ptr = '\0'; return ptr;}
+
+ char *ptr1 = ptr;
+ int64_t tmp_value;
+
+ do {
+ tmp_value = value;
+ value /= base;
+ *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
+ } while (value);
+
+ // Apply negative sign
+ if (tmp_value < 0) *ptr++ = '-';
+ char* end = ptr;
+ *ptr-- = '\0';
+ char tmp_char;
+ while (ptr1 < ptr) {
+ tmp_char = *ptr;
+ *ptr--= *ptr1;
+ *ptr1++ = tmp_char;
+ }
+ return end;
+}
+
+class gstring_stream;
+
+class gstring {
+ enum Flags {
+ FREE_FLAG = 0x80000000, // 1st bit; `_buf` needs `free`ing
+ FREE_OFFSET = 31,
+ REF_FLAG = 0x40000000, // 2nd bit; `_buf` has an extended life-time (such as C string literals) and can be shared (passed by reference)
+ REF_OFFSET = 30,
+ CAPACITY_MASK = 0x3F000000, // 3..8 bits; `_buf` size is 2^this
+ CAPACITY_OFFSET = 24,
+ LENGTH_MASK = 0x00FFFFFF, // 9th bit; allocated capacity
+ };
+ uint32_t _meta;
+public:
+ void* _buf;
+public:
+ constexpr gstring() noexcept: _meta (0), _buf (nullptr) {}
+ /**
+ * Reuse `buf` of size `bufSize`.
+ * To fully use `buf` the `bufSize` should be the power of two.
+ * @param bufSize The size of the memory allocated to `buf`.
+ * @param buf The memory region to be reused.
+ * @param free Whether the `buf` should be `free`d on resize or gstring destruction.
+ * @param length String length inside the `buf`.
+ * @param ref If true then the `buf` isn't copied by gstring's copy constructors.
+ * This is useful for wrapping C string literals.
+ */
+ explicit gstring (uint32_t bufSize, void* buf, bool free, uint32_t length, bool ref = false) noexcept {
+ uint32_t power = 0; while (((uint32_t) 1 << (power + 1)) <= bufSize) ++power;
+ _meta = ((uint32_t) free << FREE_OFFSET) |
+ ((uint32_t) ref << REF_OFFSET) |
+ (power << CAPACITY_OFFSET) |
+ (length & LENGTH_MASK);
+ _buf = buf;
+ }
+
+ struct ReferenceConstructor {};
+ /// Make a view to the given cstring.
+ /// @param buf The memory region to be reused.
+ /// @param length String length inside the `buf`.
+ /// @param ref If true then the `buf` isn't copied by gstring's copy constructors.
+ /// This is useful for wrapping C string literals.
+ explicit constexpr gstring (ReferenceConstructor, const char* buf, uint32_t length, bool ref = false) noexcept:
+ _meta (((uint32_t) ref << REF_OFFSET) | (length & LENGTH_MASK)), _buf ((void*) buf) {}
+
+ /// Copy the characters into `gstring`.
+ gstring (const char* chars): _meta (0), _buf (nullptr) {
+ if (chars && *chars) {
+ size_t length = ::strlen (chars);
+ _buf = ::malloc (length);
+ ::memcpy (_buf, chars, length);
+ _meta = (uint32_t) FREE_FLAG |
+ (length & LENGTH_MASK);
+ }
+ }
+
+ /// Copy the characters into `gstring`.
+ gstring (const char* chars, size_t length) {
+ if (length != 0) {
+ _buf = ::malloc (length);
+ ::memcpy (_buf, chars, length);
+ } else _buf = nullptr;
+ _meta = (uint32_t) FREE_FLAG |
+ (length & LENGTH_MASK);
+ }
+
+ /// Copy into `gstring`.
+ gstring (const std::string& str): _meta (0), _buf (nullptr) {
+ if (!str.empty()) {
+ _buf = ::malloc (str.length());
+ ::memcpy (_buf, str.data(), str.length());
+ _meta = (uint32_t) FREE_FLAG |
+ (str.length() & LENGTH_MASK);
+ }
+ }
+
+ /// If `gstr` is `copiedByReference` then make a shallow copy of it,
+ /// otherwise copy `gstr` contents into a `malloc`ed buffer.
+ gstring (const gstring& gstr) {
+ uint32_t glen = gstr.length();
+ if (glen != 0) {
+ if (gstr.copiedByReference()) {
+ _meta = gstr._meta; _buf = gstr._buf;
+ } else {
+ _buf = ::malloc (glen);
+ if (!_buf) GTHROW ("!malloc");
+ ::memcpy (_buf, gstr._buf, glen);
+ _meta = (uint32_t) FREE_FLAG |
+ (glen & LENGTH_MASK);
+ }
+ } else {
+ _meta = 0; _buf = nullptr;
+ }
+ }
+ gstring (gstring&& gstr) noexcept: _meta (gstr._meta), _buf (gstr._buf) {
+ gstr._meta = 0; gstr._buf = nullptr;
+ }
+ gstring& operator = (const gstring& gstr) {
+ // cf. http://stackoverflow.com/questions/9322174/move-assignment-operator-and-if-this-rhs
+ if (this != &gstr) {
+ uint32_t glen = gstr.length();
+ uint32_t power = 0;
+ uint32_t capacity = this->capacity();
+ if (glen <= capacity && capacity > 1) { // `capacity <= 1` means there is no _buf.
+ // We reuse existing buffer. Keep capacity info.
+ power = (_meta & CAPACITY_MASK) >> CAPACITY_OFFSET;
+ } else {
+ if (_buf != nullptr && needsFreeing()) ::free (_buf);
+ if (gstr.copiedByReference()) {
+ _meta = gstr._meta; _buf = gstr._buf;
+ return *this;
+ }
+ _buf = ::malloc (glen);
+ if (_buf == nullptr) GTHROW ("malloc failed");
+ }
+ ::memcpy (_buf, gstr._buf, glen);
+ _meta = (uint32_t) FREE_FLAG |
+ (power << CAPACITY_OFFSET) |
+ (glen & LENGTH_MASK);
+ }
+ return *this;
+ }
+ gstring& operator = (gstring&& gstr) noexcept {
+ assert (this != &gstr);
+ if (_buf != nullptr && needsFreeing()) free (_buf);
+ _meta = gstr._meta; _buf = gstr._buf;
+ gstr._meta = 0; gstr._buf = nullptr;
+ return *this;
+ }
+
+ /// Return a copy of the string.
+ gstring clone() const {return gstring (data(), length());}
+ /// If the gstring's buffer is not owned then copy the bytes into the owned one.
+ /// Useful for turning a stack-allocated gstring into a heap-allocated gstring.
+ gstring& owned() {if (!needsFreeing()) *this = gstring (data(), length()); return *this;}
+ /** Returns a reference to the gstring: when the reference is copied the internal buffer is not copied but referenced (shallow copy).\n
+ * This method should only be used if it is know that the life-time of the reference and its copies is less than the life-time of the buffer. */
+ gstring ref() const noexcept {return gstring (0, _buf, false, length(), true);}
+
+ bool needsFreeing() const noexcept {return _meta & FREE_FLAG;}
+ bool copiedByReference() const noexcept {return _meta & REF_FLAG;}
+ /// Current buffer capacity (memory allocated to the string). Returns 1 if no memory allocated.
+ uint32_t capacity() const noexcept {return 1 << ((_meta & CAPACITY_MASK) >> CAPACITY_OFFSET);}
+ uint32_t length() const noexcept {return _meta & LENGTH_MASK;}
+ size_t size() const noexcept {return _meta & LENGTH_MASK;}
+ bool empty() const noexcept {return (_meta & LENGTH_MASK) == 0;}
+ std::string str() const {size_t len = size(); return len ? std::string ((const char*) _buf, len) : std::string();}
+ /// NB: might move the string to a new buffer.
+ const char* c_str() const {
+ uint32_t len = length(); if (len == 0) return "";
+ uint32_t cap = capacity();
+ // c_str should work even for const gstring's, otherwise it's too much of a pain.
+ if (cap < len + 1) const_cast<gstring*> (this) ->reserve (len + 1);
+ char* buf = (char*) _buf; buf[len] = 0; return buf;
+ }
+ bool equals (const char* cstr) const noexcept {
+ const char* cstr_; uint32_t clen_;
+ if (cstr != nullptr) {cstr_ = cstr; clen_ = strlen (cstr);} else {cstr_ = ""; clen_ = 0;}
+ const uint32_t len = length();
+ if (len != clen_) return false;
+ const char* gstr_ = _buf != nullptr ? (const char*) _buf : "";
+ return memcmp (gstr_, cstr_, len) == 0;
+ }
+ bool equals (const gstring& gs) const noexcept {
+ uint32_t llen = length(), olen = gs.length();
+ if (llen != olen) return false;
+ return memcmp ((const char*) _buf, (const char*) gs._buf, llen) == 0;
+ }
+
+ char& operator[] (unsigned index) noexcept {return ((char*)_buf)[index];}
+ const char& operator[] (unsigned index) const noexcept {return ((const char*)_buf)[index];}
+
+ /// Access `_buf` as `char*`. `_buf` might be nullptr.
+ char* data() noexcept {return (char*)_buf;}
+ const char* data() const noexcept {return (const char*)_buf;}
+
+ char* endp() noexcept {return (char*)_buf + length();}
+ const char* endp() const noexcept {return (const char*)_buf + length();}
+
+ gstring view (uint32_t pos, int32_t count = -1) noexcept {
+ return gstring (0, data() + pos, false, count >= 0 ? count : length() - pos, copiedByReference());}
+ const gstring view (uint32_t pos, int32_t count = -1) const noexcept {
+ return gstring (0, (void*)(data() + pos), false, count >= 0 ? count : length() - pos, copiedByReference());}
+
+ // http://en.cppreference.com/w/cpp/concept/Iterator
+ template<typename CT> struct iterator_t: public std::iterator<std::random_access_iterator_tag, CT, int32_t> {
+ CT* _ptr;
+ iterator_t () noexcept: _ptr (nullptr) {}
+ iterator_t (CT* ptr) noexcept: _ptr (ptr) {}
+ iterator_t (const iterator_t<CT>& it) noexcept: _ptr (it._ptr) {}
+
+ CT& operator*() const noexcept {return *_ptr;}
+ CT* operator->() const noexcept {return _ptr;}
+ CT& operator[](int32_t ofs) const noexcept {return _ptr[ofs];}
+
+ iterator_t<CT>& operator++() noexcept {++_ptr; return *this;}
+ iterator_t<CT> operator++(int) noexcept {return iterator_t<CT> (_ptr++);};
+ iterator_t<CT>& operator--() noexcept {--_ptr; return *this;}
+ iterator_t<CT> operator--(int) noexcept {return iterator_t<CT> (_ptr--);};
+ bool operator == (const iterator_t<CT>& i2) const noexcept {return _ptr == i2._ptr;}
+ bool operator != (const iterator_t<CT>& i2) const noexcept {return _ptr != i2._ptr;}
+ bool operator < (const iterator_t<CT>& i2) const noexcept {return _ptr < i2._ptr;}
+ bool operator > (const iterator_t<CT>& i2) const noexcept {return _ptr > i2._ptr;}
+ bool operator <= (const iterator_t<CT>& i2) const noexcept {return _ptr <= i2._ptr;}
+ bool operator >= (const iterator_t<CT>& i2) const noexcept {return _ptr >= i2._ptr;}
+ iterator_t<CT> operator + (int32_t ofs) const noexcept {return iterator (_ptr + ofs);}
+ iterator_t<CT>& operator += (int32_t ofs) noexcept {_ptr += ofs; return *this;}
+ iterator_t<CT> operator - (int32_t ofs) const noexcept {return iterator (_ptr - ofs);}
+ iterator_t<CT>& operator -= (int32_t ofs) noexcept {_ptr -= ofs; return *this;}
+ };
+ // http://en.cppreference.com/w/cpp/concept/Container
+ typedef char value_type;
+ typedef char& reference;
+ typedef const char& const_reference;
+ typedef uint32_t size_type;
+ typedef int32_t difference_type;
+ typedef iterator_t<char> iterator;
+ typedef iterator_t<const char> const_iterator;
+ iterator begin() noexcept {return iterator ((char*) _buf);}
+ const_iterator begin() const noexcept {return const_iterator ((char*) _buf);}
+ iterator end() noexcept {return iterator ((char*) _buf + size());}
+ const_iterator end() const noexcept {return const_iterator ((char*) _buf + size());}
+ const_iterator cbegin() const noexcept {return const_iterator ((char*) _buf);}
+ const_iterator cend() const noexcept {return const_iterator ((char*) _buf + size());}
+
+ /** Returns -1 if not found. */
+ int32_t find (const char* str, int32_t pos, int32_t count) const noexcept {
+ const int32_t hlen = (int32_t) length() - pos;
+ if (hlen <= 0) return -1;
+ char* haystack = (char*) _buf + pos;
+ void* mret = memmem (haystack, hlen, str, count);
+ if (mret == 0) return -1;
+ return (char*) mret - (char*) _buf;
+ }
+ int32_t find (const char* str, int32_t pos = 0) const noexcept {return find (str, pos, strlen (str));}
+
+ /** Index of `ch` inside the string or -1 if not found. */
+ int32_t indexOf (char ch) const noexcept {
+ void* ret = memchr (_buf, ch, size());
+ return ret == nullptr ? -1 : (char*) ret - (char*) _buf;
+ }
+
+ // Helps to workaround the "statement has no effect" warning in `GSTRING_ON_STACK`.
+ gstring& self() noexcept {return *this;}
+
+ /** Grow buffer to be at least `to` characters long. */
+ void reserve (uint32_t to) {
+ uint32_t power = (_meta & CAPACITY_MASK) >> CAPACITY_OFFSET;
+ if (((uint32_t) 1 << power) < to) {
+ ++power;
+ while (((uint32_t) 1 << power) < to) ++power;
+ if (power > 24) {GSTRING_ON_STACK (error, 64) << "gstring too large: " << (int) to; GTHROW (error.str());}
+ } else if (power) {
+ // No need to grow.
+ return;
+ }
+ _meta = (_meta & ~CAPACITY_MASK) | (power << CAPACITY_OFFSET);
+ if (needsFreeing() && _buf != nullptr) {
+ _buf = ::realloc (_buf, capacity());
+ if (_buf == nullptr) GTHROW ("realloc failed");
+ } else {
+ const char* oldBuf = (const char*) _buf;
+ _buf = ::malloc (capacity());
+ if (_buf == nullptr) GTHROW ("malloc failed");
+ if (oldBuf != nullptr) ::memcpy (_buf, oldBuf, length());
+ _meta |= FREE_FLAG;
+ }
+ }
+
+ /** Length setter. Useful when you manually write into the buffer or to cut the string. */
+ void length (uint32_t len) noexcept {
+ _meta = (_meta & ~LENGTH_MASK) | (len & LENGTH_MASK);
+ }
+
+protected:
+ friend class gstring_stream;
+public:
+ /** Appends an integer to the string.
+ * @param base Radix, from 1 to 36 (default 10).
+ * @param bytes How many bytes to reserve (24 by default). */
+ void append64 (int64_t iv, int base = 10, uint_fast8_t bytes = 24) {
+ uint32_t pos = length();
+ if (capacity() < pos + bytes) reserve (pos + bytes);
+ length (itoa ((char*) _buf + pos, iv, base) - (char*) _buf);
+ }
+ void append (char ch) {
+ uint32_t pos = length();
+ const uint32_t cap = capacity();
+ if (pos >= cap || cap <= 1) reserve (pos + 1);
+ ((char*)_buf)[pos] = ch;
+ length (++pos);
+ }
+ void append (const char* cstr, uint32_t clen) {
+ uint32_t len = length();
+ uint32_t need = len + clen;
+ const uint32_t cap = capacity();
+ if (need > cap || cap <= 1) reserve (need);
+ ::memcpy ((char*) _buf + len, cstr, clen);
+ length (need);
+ }
+ /** This one is for http://code.google.com/p/re2/; `clear` then `append`. */
+ bool ParseFrom (const char* cstr, int clen) {
+ if (clen < 0 || clen > (int) LENGTH_MASK) return false;
+ length (0); append (cstr, (uint32_t) clen); return true;}
+ gstring& operator << (const gstring& gs) {append (gs.data(), gs.length()); return *this;}
+ gstring& operator << (const std::string& str) {append (str.data(), str.length()); return *this;}
+ gstring& operator << (const char* cstr) {if (cstr) append (cstr, ::strlen (cstr)); return *this;}
+ gstring& operator << (char ch) {append (ch); return *this;}
+ gstring& operator << (int iv) {append64 (iv, 10, sizeof (int) * 3); return *this;}
+ gstring& operator << (long iv) {append64 (iv, 10, sizeof (long) * 3); return *this;}
+ gstring& operator << (long long iv) {append64 (iv, 10, sizeof (long long) * 3); return *this;}
+ gstring& operator << (double dv) {
+ uint32_t len = length();
+ reserve (len + 32);
+ int rc = snprintf (endp(), 31, "%f", dv);
+ if (rc > 0) {length (len + std::min (rc, 31));}
+ return *this;
+ }
+
+ bool operator < (const gstring &gs) const noexcept {
+ uint32_t len1 = length(); uint32_t len2 = gs.length();
+ if (len1 == len2) return ::strncmp (data(), gs.data(), len1) < 0;
+ int cmp = ::strncmp (data(), gs.data(), std::min (len1, len2));
+ if (cmp) return cmp < 0;
+ return len1 < len2;
+ }
+
+ /// Asks `strftime` to generate a time string. Capacity is increased if necessary (up to a limit of +1024 bytes).
+ gstring& appendTime (const char* format, struct tm* tmv) {
+ int32_t pos = length(), cap = capacity(), left = cap - pos;
+ if (left < 8) {reserve (pos + 8); return appendTime (format, tmv);}
+ size_t got = strftime ((char*) _buf + pos, left, format, tmv);
+ if (got == 0) {
+ if (left > 1024) return *this; // Guard against perpetual growth.
+ reserve (pos + left * 2); return appendTime (format, tmv);
+ }
+ length (pos + got);
+ return *this;
+ }
+
+ /// Append the characters to this `gstring` wrapping them in the netstring format.
+ gstring& appendNetstring (const char* cstr, uint32_t clen) {
+ *this << (int) clen; append (':'); append (cstr, clen); append (','); return *this;}
+ /// Append the `gstr` wrapping it in the netstring format.
+ gstring& appendNetstring (const gstring& gstr) {return appendNetstring (gstr.data(), gstr.length());}
+
+ std::ostream& writeAsNetstring (std::ostream& stream) const;
+
+ /// Parse netstring at `pos` and return a `gstring` *pointing* at the parsed netstring.\n
+ /// No heap space allocated.\n
+ /// Throws std::runtime_error if netstring parsing fails.\n
+ /// If parsing was successfull, then `after` is set to point after the parsed netstring.
+ gstring netstringAt (uint32_t pos, uint32_t* after = nullptr) const {
+ const uint32_t len = length(); char* buf = (char*) _buf;
+ if (buf == nullptr) GTHROW ("gstring: netstringAt: nullptr");
+ uint32_t next = pos;
+ while (next < len && buf[next] >= '0' && buf[next] <= '9') ++next;
+ if (next >= len || buf[next] != ':' || next - pos > 10) GTHROW ("gstring: netstringAt: no header");
+ char* endptr = 0;
+ long nlen = ::strtol (buf + pos, &endptr, 10);
+ if (endptr != buf + next) GTHROW ("gstring: netstringAt: unexpected header end");
+ pos = next + 1; next = pos + nlen;
+ if (next >= len || buf[next] != ',') GTHROW ("gstring: netstringAt: no body");
+ if (after) *after = next + 1;
+ return gstring (0, buf + pos, false, next - pos);
+ }
+
+ /// Wrapper around strtol, not entirely safe (make sure the string is terminated with a non-digit, by calling c_str, for example).
+ long intAt (uint32_t pos, uint32_t* after = nullptr, int base = 10) const {
+ // BTW: http://www.kumobius.com/2013/08/c-string-to-int/
+ const uint32_t len = length(); char* buf = (char*) _buf;
+ if (pos >= len || buf == nullptr) GTHROW ("gstring: intAt: pos >= len");
+ char* endptr = 0;
+ long lv = ::strtol (buf + pos, &endptr, base);
+ uint32_t next = endptr - buf;
+ if (next > len) GTHROW ("gstring: intAt: endptr > len");
+ if (after) *after = next;
+ return lv;
+ }
+
+ /// Wrapper around strtol. Copies the string into a temporary buffer in order to pass it to strtol. Empty string returns 0.
+ long toInt (int base = 10) const noexcept {
+ const uint32_t len = length(); if (len == 0) return 0;
+ char buf[len + 1]; memcpy (buf, _buf, len); buf[len] = 0;
+ return ::strtol (buf, nullptr, base);
+ }
+
+ /// Get a single netstring from the `stream` and append it to the end of `gstring`.
+ /// Throws an exception if the input is not a well-formed netstring.
+ gstring& readNetstring (std::istream& stream) {
+ int32_t nlen; stream >> nlen;
+ if (!stream.good() || nlen < 0) GTHROW ("!netstring");
+ int ch = stream.get();
+ if (!stream.good() || ch != ':') GTHROW ("!netstring");
+ uint32_t glen = length();
+ const uint32_t cap = capacity();
+ if (cap < glen + nlen || cap <= 1) reserve (glen + nlen);
+ stream.read ((char*) _buf + glen, nlen);
+ if (!stream.good()) GTHROW ("!netstring");
+ ch = stream.get();
+ if (ch != ',') GTHROW ("!netstring");
+ length (glen + nlen);
+ return *this;
+ }
+
+ /// Set length to 0. `_buf` not changed.
+ gstring& clear() noexcept {length (0); return *this;}
+
+ /// Removes `count` characters starting at `pos`.
+ gstring& erase (uint32_t pos, uint32_t count = 1) noexcept {
+ const char* buf = (const char*) _buf;
+ const char* pt1 = buf + pos;
+ const char* pt2 = pt1 + count;
+ uint32_t len = length();
+ const char* end = buf + len;
+ if (pt2 <= end) {
+ length (len - count);
+ ::memmove ((void*) pt1, (void*) pt2, end - pt2);
+ }
+ return *this;
+ }
+ /// Remove characters [from,till) and return `from`.\n
+ /// Compatible with "boost/algorithm/string/trim.hpp".
+ iterator_t<char> erase (iterator_t<char> from, iterator_t<char> till) noexcept {
+ intptr_t ipos = from._ptr - (char*) _buf;
+ intptr_t count = till._ptr - from._ptr;
+ if (ipos >= 0 && count > 0) erase (ipos, count);
+ return from;
+ }
+
+ ~gstring() noexcept {
+ if (_buf != nullptr && needsFreeing()) {::free (_buf); _buf = nullptr;}
+ }
+};
+
+inline bool operator == (const gstring& gs1, const gstring& gs2) noexcept {return gs1.equals (gs2);}
+inline bool operator == (const char* cstr, const gstring& gstr) noexcept {return gstr.equals (cstr);}
+inline bool operator == (const gstring& gstr, const char* cstr) noexcept {return gstr.equals (cstr);}
+inline bool operator != (const gstring& gs1, const gstring& gs2) noexcept {return !gs1.equals (gs2);}
+inline bool operator != (const char* cstr, const gstring& gstr) noexcept {return !gstr.equals (cstr);}
+inline bool operator != (const gstring& gstr, const char* cstr) noexcept {return !gstr.equals (cstr);}
+
+inline bool operator == (const gstring& gstr, const std::string& str) noexcept {
+ return gstr.equals (gstring (gstring::ReferenceConstructor(), str.data(), str.size()));}
+inline bool operator != (const gstring& gstr, const std::string& str) noexcept {return !(gstr == str);}
+inline bool operator == (const std::string& str, const gstring& gstr) noexcept {return gstr == str;}
+inline bool operator != (const std::string& str, const gstring& gstr) noexcept {return !(gstr == str);}
+inline std::string operator += (std::string& str, const gstring& gstr) {return str.append (gstr.data(), gstr.size());}
+inline std::string operator + (const std::string& str, const gstring& gstr) {return std::string (str) .append (gstr.data(), gstr.size());}
+
+inline std::ostream& operator << (std::ostream& os, const gstring& gstr) {
+ if (gstr._buf != nullptr) os.write ((const char*) gstr._buf, gstr.length());
+ return os;
+}
+
+/// Encode this `gstring` into `stream` as a netstring.
+inline std::ostream& gstring::writeAsNetstring (std::ostream& stream) const {
+ stream << length() << ':' << *this << ',';
+ return stream;
+}
+
+// http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
+// http://www.dreamincode.net/code/snippet2499.htm
+// http://spec.winprog.org/streams/
+class gstring_stream: public std::basic_streambuf<char, std::char_traits<char> > {
+ gstring& _gstr;
+public:
+ gstring_stream (gstring& gstr) noexcept: _gstr (gstr) {
+ char* buf = (char*) gstr._buf;
+ if (buf != nullptr) setg (buf, buf, buf + gstr.length());
+ }
+protected:
+ virtual int_type overflow (int_type ch) {
+ if (__builtin_expect (ch != traits_type::eof(), 1)) _gstr.append ((char) ch);
+ return 0;
+ }
+ // no copying
+ gstring_stream (const gstring_stream &);
+ gstring_stream& operator = (const gstring_stream &);
+};
+
+} // namespace glim
+
+// hash specialization
+// cf. http://stackoverflow.com/questions/8157937/how-to-specialize-stdhashkeyoperator-for-user-defined-type-in-unordered
+namespace std {
+ template <> struct hash<glim::gstring> {
+ size_t operator()(const glim::gstring& gs) const noexcept {
+ // cf. http://stackoverflow.com/questions/7666509/hash-function-for-string
+ // Would be nice to use https://131002.net/siphash/ here.
+ uint32_t hash = 5381;
+ uint32_t len = gs.length();
+ if (len) {
+ const char* str = (const char*) gs._buf;
+ const char* end = str + len;
+ while (str < end) hash = ((hash << 5) + hash) + *str++; /* hash * 33 + c */
+ }
+ return hash;
+ }
+ };
+}
+
+#endif // _GSTRING_INCLUDED
diff --git a/external/glim/hget.hpp b/external/glim/hget.hpp
new file mode 100644
index 000000000..cebbe416f
--- /dev/null
+++ b/external/glim/hget.hpp
@@ -0,0 +1,255 @@
+// Simple header-only wrapper around libevent's evhttp client.
+// See also: https://github.com/cpp-netlib/cpp-netlib/issues/160
+
+#ifndef _GLIM_HGET_INCLUDED
+#define _GLIM_HGET_INCLUDED
+
+#include <event2/event.h>
+#include <event2/dns.h>
+#include <evhttp.h> // http://stackoverflow.com/a/5237994; http://archives.seul.org/libevent/users/Sep-2010/msg00050.html
+
+#include <memory>
+#include <functional>
+#include <stdexcept>
+#include <iostream>
+#include <vector>
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include "exception.hpp"
+#include "gstring.hpp"
+
+namespace glim {
+
+/// HTTP results
+struct hgot {
+ int32_t status = 0;
+ /// Uses errno codes.
+ int32_t error = 0;
+ struct evbuffer* body = 0;
+ struct evhttp_request* req = 0;
+ size_t bodyLength() const {return body ? evbuffer_get_length (body) : 0;}
+ /// Warning: the string is NOT zero-terminated.
+ const char* bodyData() {return body ? (const char*) evbuffer_pullup (body, -1) : "";}
+ /// Returns a zero-terminated string. Warning: modifies the `body` every time in order to add the terminator.
+ const char* cbody() {if (!body) return ""; evbuffer_add (body, "", 1); return (const char*) evbuffer_pullup (body, -1);}
+ /// A gstring *view* into the `body`.
+ glim::gstring gbody() {
+ if (!body) return glim::gstring();
+ return glim::gstring (glim::gstring::ReferenceConstructor(), (const char*) evbuffer_pullup (body, -1), evbuffer_get_length (body));}
+};
+
+/// Used internally to pass both connection and handler into callback.
+struct hgetContext {
+ struct evhttp_connection* conn;
+ std::function<void(hgot&)> handler;
+ hgetContext (struct evhttp_connection* conn, std::function<void(hgot&)> handler): conn (conn), handler (handler) {}
+};
+
+/// Invoked when evhttp finishes a request.
+inline void hgetCB (struct evhttp_request* req, void* ctx_){
+ hgetContext* ctx = (hgetContext*) ctx_;
+
+ hgot gt;
+ if (req == NULL) gt.error = ETIMEDOUT;
+ else if (req->response_code == 0) gt.error = ECONNREFUSED;
+ else {
+ gt.status = req->response_code;
+ gt.body = req->input_buffer;
+ gt.req = req;
+ }
+
+ try {
+ ctx->handler (gt);
+ } catch (const std::runtime_error& ex) { // Shouldn't normally happen:
+ std::cerr << "glim::hget, handler exception: " << ex.what() << std::endl;
+ }
+
+ evhttp_connection_free ((struct evhttp_connection*) ctx->conn);
+ //freed by libevent//if (req != NULL) evhttp_request_free (req);
+ delete ctx;
+}
+
+/**
+ C++ wrapper around libevent's http client.
+ Example: \code
+ hget (evbase, dnsbase) .setRequestBuilder ([](struct evhttp_request* req){
+ evbuffer_add (req->output_buffer, "foo", 3);
+ evhttp_add_header (req->output_headers, "Content-Length", "3");
+ }) .go ("http://127.0.0.1:8080/test", [](hgot& got){
+ if (got.error) log_warn ("127.0.0.1:8080 " << strerror (got.error));
+ else if (got.status != 200) log_warn ("127.0.0.1:8080 != 200");
+ else log_info ("got " << evbuffer_get_length (got.body) << " bytes from /test: " << evbuffer_pullup (got.body, -1));
+ }); \endcode
+ */
+class hget {
+ public:
+ std::shared_ptr<struct event_base> _evbase;
+ std::shared_ptr<struct evdns_base> _dnsbase;
+ std::function<void(struct evhttp_request*)> _requestBuilder;
+ enum evhttp_cmd_type _method;
+ public:
+ typedef std::shared_ptr<struct evhttp_uri> uri_t;
+ /// The third parameter is the request number, starting from 1.
+ typedef std::function<float(hgot&,uri_t,int32_t)> until_handler_t;
+ public:
+ hget (std::shared_ptr<struct event_base> evbase, std::shared_ptr<struct evdns_base> dnsbase):
+ _evbase (evbase), _dnsbase (dnsbase), _method (EVHTTP_REQ_GET) {}
+
+ /// Modifies the request before its execution.
+ hget& setRequestBuilder (std::function<void(struct evhttp_request*)> rb) {
+ _requestBuilder = rb;
+ return *this;
+ }
+
+ /** Uses a simple request builder to send the `str`.
+ * `str` is a `char` string class with methods `data` and `size`. */
+ template<typename STR> hget& payload (STR str, const char* contentType = nullptr, enum evhttp_cmd_type method = EVHTTP_REQ_POST) {
+ _method = method;
+ return setRequestBuilder ([str,contentType](struct evhttp_request* req) {
+ if (contentType) evhttp_add_header (req->output_headers, "Content-Type", contentType);
+ char buf[64];
+ *glim::itoa (buf, (int) str.size()) = 0;
+ evhttp_add_header (req->output_headers, "Content-Length", buf);
+ evbuffer_add (req->output_buffer, (const void*) str.data(), (size_t) str.size());
+ });
+ }
+
+ struct evhttp_request* go (uri_t uri, int32_t timeoutSec, std::function<void(hgot&)> handler) {
+ int port = evhttp_uri_get_port (uri.get());
+ if (port == -1) port = 80;
+ struct evhttp_connection* conn = evhttp_connection_base_new (_evbase.get(), _dnsbase.get(),
+ evhttp_uri_get_host (uri.get()), port);
+ evhttp_connection_set_timeout (conn, timeoutSec);
+ struct evhttp_request *req = evhttp_request_new (hgetCB, new hgetContext(conn, handler));
+ int ret = evhttp_add_header (req->output_headers, "Host", evhttp_uri_get_host (uri.get()));
+ if (ret) throw std::runtime_error ("hget: evhttp_add_header(Host) != 0");
+ if (_requestBuilder) _requestBuilder (req);
+ const char* get = evhttp_uri_get_path (uri.get());
+ const char* qs = evhttp_uri_get_query (uri.get());
+ if (qs == NULL) {
+ ret = evhttp_make_request (conn, req, _method, get);
+ } else {
+ size_t getLen = strlen (get);
+ size_t qsLen = strlen (qs);
+ char buf[getLen + 1 + qsLen + 1];
+ char* caret = stpcpy (buf, get);
+ *caret++ = '?';
+ caret = stpcpy (caret, qs);
+ assert (caret - buf < sizeof (buf));
+ ret = evhttp_make_request (conn, req, _method, buf);
+ }
+ if (ret) throw std::runtime_error ("hget: evhttp_make_request != 0");
+ return req;
+ }
+ struct evhttp_request* go (const char* url, int32_t timeoutSec, std::function<void(hgot&)> handler) {
+ return go (std::shared_ptr<struct evhttp_uri> (evhttp_uri_parse (url), evhttp_uri_free), timeoutSec, handler);
+ }
+
+ void goUntil (std::vector<uri_t> urls, until_handler_t handler, int32_t timeoutSec = 20);
+ /**
+ Parse urls and call `goUntil`.
+ Example (trying ten times to reach the servers): \code
+ std::string path ("/path");
+ hget.goUntilS (boost::assign::list_of ("http://server1" + path) ("http://server2" + path),
+ [](hgot& got, hget::uri_t uri, int32_t num)->float {
+ std::cout << "server: " << evhttp_uri_get_host (uri.get()) << "; request number: " << num << std::endl;
+ if (got.status != 200 && num < 10) return 1.f; // Retry in a second.
+ return -1.f; // No need to retry the request.
+ });
+ \endcode
+ @param urls is a for-compatible container of strings (where string has methods `data` and `size`).
+ */
+ template<typename URLS> void goUntilS (URLS&& urls, until_handler_t handler, int32_t timeoutSec = 20) {
+ std::vector<uri_t> parsedUrls;
+ for (auto&& url: urls) {
+ // Copying to stack might be cheaper than malloc in c_str.
+ int len = url.size(); char buf[len + 1]; memcpy (buf, url.data(), len); buf[len] = 0;
+ struct evhttp_uri* uri = evhttp_uri_parse (buf);
+ if (!uri) GTHROW (std::string ("!evhttp_uri_parse: ") + buf);
+ parsedUrls.push_back (uri_t (uri, evhttp_uri_free));
+ }
+ goUntil (parsedUrls, handler, timeoutSec);
+ }
+ /**
+ Parse urls and call `goUntil`.
+ Example (trying ten times to reach the servers): \code
+ hget.goUntilC (boost::assign::list_of ("http://server1/") ("http://server2/"),
+ [](hgot& got, hget::uri_t uri, int32_t num)->float {
+ std::cout << "server: " << evhttp_uri_get_host (uri.get()) << "; request number: " << num << std::endl;
+ if (got.status != 200 && num < 10) return 1.f; // Retry in a second.
+ return -1.f; // No need to retry the request.
+ });
+ \endcode
+ Or with `std::array` instead of `boost::assign::list_of`: \code
+ std::array<const char*, 2> urls {{"http://server1/", "http://server2/"}};
+ hget.goUntilC (urls, [](hgot& got, hget::uri_t uri, int32_t num)->float {
+ return got.status != 200 && num < 10 ? 0.f : -1.f;});
+ \endcode
+ @param urls is a for-compatible container of C strings (const char*).
+ */
+ template<typename URLS> void goUntilC (URLS&& urls, until_handler_t handler, int32_t timeoutSec = 20) {
+ std::vector<uri_t> parsedUrls;
+ for (auto url: urls) {
+ struct evhttp_uri* uri = evhttp_uri_parse (url);
+ if (!uri) GTHROW (std::string ("Can't parse url: ") + url);
+ parsedUrls.push_back (uri_t (uri, evhttp_uri_free));
+ }
+ goUntil (parsedUrls, handler, timeoutSec);
+ }
+};
+
+inline void hgetUntilRetryCB (evutil_socket_t, short, void* utilHandlerPtr); // event_callback_fn
+
+/** `hget::goUntil` implementation.
+ * This function object is passed to `hget::go` as a handler and calls `hget::go` again if necessary. */
+struct HgetUntilHandler {
+ hget _hget;
+ hget::until_handler_t _handler;
+ std::vector<hget::uri_t> _urls;
+ int32_t _timeoutSec;
+ int32_t _requestNum;
+ uint8_t _nextUrl; ///< A round-robin pointer to the next url in `_urls`.
+ HgetUntilHandler (hget& hg, hget::until_handler_t handler, std::vector<hget::uri_t> urls, int32_t timeoutSec):
+ _hget (hg), _handler (handler), _urls (urls), _timeoutSec (timeoutSec), _requestNum (0), _nextUrl (0) {}
+ void operator() (hgot& got) {
+ uint8_t urlNum = _nextUrl ? _nextUrl - 1 : _urls.size() - 1;
+ float retryAfterSec = _handler (got, _urls[urlNum], _requestNum);
+ if (retryAfterSec == 0.f) retry();
+ else if (retryAfterSec > 0.f) {
+ struct timeval wait;
+ wait.tv_sec = (int) retryAfterSec;
+ retryAfterSec -= wait.tv_sec;
+ wait.tv_usec = (int) (retryAfterSec * 1000000.f);
+ int rc = event_base_once (_hget._evbase.get(), -1, EV_TIMEOUT, hgetUntilRetryCB, new HgetUntilHandler (*this), &wait);
+ if (rc) throw std::runtime_error ("HgetUntilHandler: event_base_once != 0");
+ }
+ }
+ void start() {retry();}
+ void retry() {
+ uint8_t nextUrl = _nextUrl++;
+ if (_nextUrl >= _urls.size()) _nextUrl = 0;
+ ++_requestNum;
+ _hget.go (_urls[nextUrl], _timeoutSec, *this);
+ }
+};
+
+/// Used in `hget::goUntil` to wait in `evtimer_new` before repeating the request.
+inline void hgetUntilRetryCB (evutil_socket_t, short, void* utilHandlerPtr) { // event_callback_fn
+ std::unique_ptr<HgetUntilHandler> untilHandler ((HgetUntilHandler*) utilHandlerPtr);
+ untilHandler->retry();
+}
+
+/**
+ * Allows to retry the request using multiple URLs in a round-robin fashion.
+ * The `handler` returns the number of seconds to wait before retrying the request or -1 if no retry is necessary.
+ */
+inline void hget::goUntil (std::vector<uri_t> urls, until_handler_t handler, int32_t timeoutSec) {
+ HgetUntilHandler (*this, handler, urls, timeoutSec) .start();
+}
+
+}
+
+#endif // _GLIM_HGET_INCLUDED
diff --git a/external/glim/ldb.hpp b/external/glim/ldb.hpp
new file mode 100644
index 000000000..efc82d7da
--- /dev/null
+++ b/external/glim/ldb.hpp
@@ -0,0 +1,384 @@
+#ifndef _GLIM_LDB_HPP_INCLUDED
+#define _GLIM_LDB_HPP_INCLUDED
+
+/**
+ * Leveldb (http://code.google.com/p/leveldb/) wrapper.
+ * @code
+Copyright 2012 Kozarezov Artem Aleksandrovich
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * @endcode
+ * @file
+ */
+
+#include <string>
+//#include <unordered_map> // having SIGFPE as in http://stackoverflow.com/q/13580823/257568
+#include <map>
+#include <climits> // CHAR_MAX
+
+#include <leveldb/db.h>
+#include <leveldb/write_batch.h>
+#include <leveldb/filter_policy.h>
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/serialization/serialization.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/range/iterator_range.hpp> // http://www.boost.org/doc/libs/1_52_0/libs/range/doc/html/range/reference/utilities/iterator_range.html
+
+#include <arpa/inet.h> // htonl, ntohl
+#include <sys/stat.h> // mkdir
+#include <sys/types.h> // mkdir
+#include <string.h> // strerror
+#include <errno.h>
+#include <sstream>
+
+#include "gstring.hpp"
+#include "exception.hpp"
+
+namespace glim {
+
+G_DEFINE_EXCEPTION (LdbEx);
+
+template <typename T> inline void ldbSerialize (gstring& bytes, const T& data) {
+ gstring_stream stream (bytes);
+ boost::archive::binary_oarchive oa (stream, boost::archive::no_header);
+ oa << data;
+}
+template <typename V> inline void ldbDeserialize (const gstring& bytes, V& data) {
+ gstring_stream stream (const_cast<gstring&> (bytes));
+ boost::archive::binary_iarchive ia (stream, boost::archive::no_header);
+ ia >> data;
+}
+
+/** uint32_t keys are stored big-endian (network byte order) in order to be compatible with lexicographic ordering. */
+template <> inline void ldbSerialize<uint32_t> (gstring& bytes, const uint32_t& ui) {
+ uint32_t nui = htonl (ui); bytes.append ((const char*) &nui, sizeof (uint32_t));}
+/** Deserialize uint32_t from big-endian (network byte order). */
+template <> inline void ldbDeserialize<uint32_t> (const gstring& bytes, uint32_t& ui) {
+ if (bytes.size() != sizeof (uint32_t)) GNTHROW (LdbEx, "Not uint32_t, wrong number of bytes");
+ uint32_t nui = * (uint32_t*) bytes.data(); ui = ntohl (nui);}
+
+/** If the data is `gstring` then use the data's buffer directly, no copy. */
+template <> inline void ldbSerialize<gstring> (gstring& bytes, const gstring& data) {
+ bytes = gstring (0, (void*) data.data(), false, data.length());}
+/** Deserializing into `gstring` copies the bytes into it, reusing its buffer. */
+template <> inline void ldbDeserialize<gstring> (const gstring& bytes, gstring& data) {
+ data.clear() << bytes;}
+
+/** If the data is `std::string` then use the data's buffer directly, no copy. */
+template <> inline void ldbSerialize<std::string> (gstring& bytes, const std::string& data) {
+ bytes = gstring (0, (void*) data.data(), false, data.length());}
+/** Deserializing into `std::string` copies the bytes into it, reusing its buffer. */
+template <> inline void ldbDeserialize<std::string> (const gstring& bytes, std::string& data) {
+ data.clear(); data.append (bytes.data(), bytes.size());}
+
+/**
+ * Header-only Leveldb wrapper.\n
+ * Uses Boost Serialization to pack keys and values (glim::gstring can be used for raw bytes).\n
+ * Allows semi-automatic indexing with triggers.
+ */
+struct Ldb {
+ std::shared_ptr<leveldb::DB> _db;
+ std::shared_ptr<const leveldb::FilterPolicy> _filter;
+
+ struct IteratorEntry { ///< Something to be `dereference`d from the Iterator. Also a pImpl allowing to keep the `_valid` and the `_lit` in sync.
+ leveldb::Iterator* _lit;
+ bool _valid:1;
+
+ IteratorEntry (const IteratorEntry&) = delete; // Owns `leveldb::Iterator`, should not be copied.
+ IteratorEntry (IteratorEntry&&) = default;
+
+ IteratorEntry (leveldb::Iterator* lit, bool valid = false): _lit (lit), _valid (valid) {}
+ ~IteratorEntry() {delete _lit;}
+
+ /** Zero-copy view of the current key bytes. Should *not* be used after the Iterator is changed or destroyed.
+ * @param ref If true then the *copies* of the returned gstring will keep pointing to LevelDB memory which is valid only until the iterator changes. */
+ const gstring keyView (bool ref = false) const {
+ if (!_valid) return gstring();
+ const leveldb::Slice& key = _lit->key();
+ return gstring (0, (void*) key.data(), false, key.size(), ref);} // Zero copy.
+ /** Zero-copy view of the current value bytes. Should *not* be used after the Iterator is changed or destroyed.
+ * @param ref If true then the *copies* of the returned gstring will keep pointing to LevelDB memory which is valid only until the iterator changes. */
+ const gstring valueView (bool ref = false) const {
+ if (!_valid) return gstring();
+ const leveldb::Slice& val = _lit->value();
+ return gstring (0, (void*) val.data(), false, val.size(), ref);} // Zero copy.
+ /** Deserialize into `key`. */
+ template <typename T> void getKey (T& key) const {ldbDeserialize (keyView (true), key);}
+ /** Deserialize the key into a temporary and return it. */
+ template <typename T> T getKey() const {T key; getKey (key); return key;}
+ /** Deserialize into `value`. */
+ template <typename T> void getValue (T& value) const {ldbDeserialize (valueView (true), value);}
+ /** Deserialize the value into a temporary and return it. */
+ template <typename T> T getValue() const {T value; getValue (value); return value;}
+ };
+ struct NoSeekFlag {}; ///< Tells the `Iterator` constructor not to seek to the beginning of the database.
+ /** Wraps Leveldb iterator.
+ * Note: "In fact the iterator is a light-weight snapshot. It will see exactly the version of the DB that existed when the iterator was created
+ * (i.e., any insert/delete done after the iterator is created, regardless of which thread does them) will be invisible to the iterator"
+ * (https://groups.google.com/d/msg/leveldb/nX8S5KKiSn4/PI92Yf1Hf6UJ). */
+ struct Iterator: public boost::iterator_facade<Iterator, IteratorEntry, boost::bidirectional_traversal_tag> {
+ std::shared_ptr<IteratorEntry> _entry; ///< The Iterator might be copied around, therefore we keep the real iterator and the state in the shared_ptr.
+
+ Iterator (const Iterator&) = default;
+ Iterator (Iterator&&) = default;
+ Iterator& operator= (const Iterator&) = default;
+ Iterator& operator= (Iterator&&) = default;
+ /** Iterate from the beginning or the end of the database.
+ * @param position can be MDB_FIRST or MDB_LAST */
+ Iterator (Ldb* ldb, leveldb::ReadOptions options = leveldb::ReadOptions()):
+ _entry (std::make_shared<IteratorEntry> (ldb->_db->NewIterator (options))) {
+ IteratorEntry* entry = _entry.get();
+ entry->_lit->SeekToFirst();
+ entry->_valid = entry->_lit->Valid();
+ }
+
+ Iterator (Ldb* ldb, NoSeekFlag, leveldb::ReadOptions options = leveldb::ReadOptions()):
+ _entry (std::make_shared<IteratorEntry> (ldb->_db->NewIterator (options))) {}
+ /** True if the iterator isn't pointing anywhere. */
+ bool end() const {return !_entry->_valid;}
+
+ bool equal (const Iterator& other) const {
+ bool weAreValid = _entry->_valid, theyAreValid = other._entry->_valid;
+ if (!weAreValid) return !theyAreValid;
+ if (!theyAreValid) return false;
+ auto&& ourKey = _entry->_lit->key(), theirKey = other._entry->_lit->key();
+ if (ourKey.size() != theirKey.size()) return false;
+ return memcmp (ourKey.data(), theirKey.data(), ourKey.size()) == 0;
+ }
+ IteratorEntry& dereference() const {
+ // NB: Boost iterator_facade expects the `dereference` to be a `const` method.
+ // I guess Iterator is not modified, so the `dereference` is `const`, even though the Entry can be modified.
+ return *_entry;
+ }
+ virtual void increment() {
+ IteratorEntry* entry = _entry.get();
+ if (entry->_valid) entry->_lit->Next();
+ else entry->_lit->SeekToFirst();
+ entry->_valid = entry->_lit->Valid();
+ }
+ virtual void decrement() {
+ IteratorEntry* entry = _entry.get();
+ if (entry->_valid) entry->_lit->Prev();
+ else entry->_lit->SeekToLast();
+ entry->_valid = entry->_lit->Valid();
+ }
+
+ Iterator& seek (const gstring& key) {
+ IteratorEntry* entry = _entry.get();
+ entry->_lit->Seek (leveldb::Slice (key.data(), key.size()));
+ entry->_valid = entry->_lit->Valid();
+ return *this;
+ }
+ };
+ Iterator begin() {return Iterator (this);}
+ Iterator end() {return Iterator (this, NoSeekFlag());}
+
+ /** Range from `from` (inclusive) to `till` (exclusive). */
+ template <typename K>
+ boost::iterator_range<Iterator> range (const K& from, const K& till, leveldb::ReadOptions options = leveldb::ReadOptions()) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ ldbSerialize (kbytes, from);
+ Iterator fit (this, NoSeekFlag(), options); fit.seek (kbytes);
+
+ ldbSerialize (kbytes.clear(), till);
+ Iterator tit (this, NoSeekFlag(), options); tit.seek (kbytes);
+
+ return boost::iterator_range<Iterator> (fit, tit);
+ }
+
+ struct StartsWithIterator: public Iterator {
+ gstring _starts;
+ StartsWithIterator (const StartsWithIterator&) = default;
+ StartsWithIterator (StartsWithIterator&&) = default;
+ StartsWithIterator& operator= (const StartsWithIterator&) = default;
+ StartsWithIterator& operator= (StartsWithIterator&&) = default;
+
+ StartsWithIterator (Ldb* ldb, const char* data, uint32_t length, leveldb::ReadOptions options = leveldb::ReadOptions()):
+ Iterator (ldb, NoSeekFlag(), options), _starts (data, length) {
+ IteratorEntry* entry = _entry.get();
+ entry->_lit->Seek (leveldb::Slice (data, length));
+ entry->_valid = checkValidity();
+ }
+ /** End iterator, pointing nowhere. */
+ StartsWithIterator (Ldb* ldb, const char* data, uint32_t length, NoSeekFlag, leveldb::ReadOptions options = leveldb::ReadOptions()):
+ Iterator (ldb, NoSeekFlag(), options), _starts (data, length) {}
+
+ bool checkValidity() const {
+ IteratorEntry* entry = _entry.get();
+ return entry->_lit->Valid() && entry->_lit->key().starts_with (leveldb::Slice (_starts.data(), _starts.length()));
+ }
+ virtual void increment() override {
+ IteratorEntry* entry = _entry.get();
+ if (entry->_valid) entry->_lit->Next();
+ else entry->_lit->Seek (leveldb::Slice (_starts.data(), _starts.length()));
+ entry->_valid = checkValidity();
+ }
+ virtual void decrement() override {
+ IteratorEntry* entry = _entry.get();
+ if (entry->_valid) entry->_lit->Prev(); else seekLast();
+ entry->_valid = checkValidity();
+ }
+ void seekLast() {
+ leveldb::Iterator* lit = _entry->_lit;
+ // Go somewhere *below* the `_starts` prefix.
+ char after[_starts.length()]; if (sizeof (after)) {
+ memcpy (after, _starts.data(), sizeof (after));
+ uint32_t pos = sizeof (after); while (--pos >= 0) if (after[pos] < CHAR_MAX) {++after[pos]; break;}
+ if (pos >= 0) {lit->Seek (leveldb::Slice (after, sizeof (after))); if (!lit->Valid()) lit->SeekToLast();} else lit->SeekToLast();
+ } else lit->SeekToLast();
+ // Seek back until we are in the `_starts` prefix.
+ for (leveldb::Slice prefix (_starts.data(), _starts.length()); lit->Valid(); lit->Prev()) {
+ leveldb::Slice key (lit->key());
+ if (key.starts_with (prefix)) break; // We're "back" in the `_starts` prefix.
+ if (key.compare (prefix) < 0) break; // Gone too far (no prefix entries in the db).
+ }
+ }
+ };
+
+ /** Range over entries starting with `key`. */
+ template <typename K>
+ boost::iterator_range<StartsWithIterator> startsWith (const K& key) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ ldbSerialize (kbytes, key);
+ return boost::iterator_range<StartsWithIterator> (
+ StartsWithIterator (this, kbytes.data(), kbytes.length()),
+ StartsWithIterator (this, kbytes.data(), kbytes.length(), NoSeekFlag()));
+ }
+
+ struct Trigger {
+ virtual gstring triggerName() const {return C2GSTRING ("defaultTriggerName");};
+ virtual void put (Ldb& ldb, void* key, gstring& kbytes, void* value, gstring& vbytes, leveldb::WriteBatch& batch) = 0;
+ virtual void del (Ldb& ldb, void* key, gstring& kbytes, leveldb::WriteBatch& batch) = 0;
+ };
+ std::map<gstring, std::shared_ptr<Trigger>> _triggers;
+
+ /** Register the trigger (by its `triggerName`). */
+ void putTrigger (std::shared_ptr<Trigger> trigger) {
+ _triggers[trigger->triggerName()] = trigger;
+ }
+
+ public:
+
+ Ldb() {}
+
+ /** Opens Leveldb database. */
+ Ldb (const char* path, leveldb::Options* options = nullptr, mode_t mode = 0770) {
+ int rc = ::mkdir (path, mode);
+ if (rc && errno != EEXIST) GNTHROW (LdbEx, std::string ("Can't create ") + path + ": " + ::strerror (errno));
+ leveldb::DB* db;
+ leveldb::Status status;
+ if (options) {
+ status = leveldb::DB::Open (*options, path, &db);
+ } else {
+ leveldb::Options localOptions;
+ localOptions.create_if_missing = true;
+ _filter.reset (leveldb::NewBloomFilterPolicy (8));
+ localOptions.filter_policy = _filter.get();
+ status = leveldb::DB::Open (localOptions, path, &db);
+ }
+ if (!status.ok()) GNTHROW (LdbEx, std::string ("Ldb: Can't open ") + path + ": " + status.ToString());
+ _db.reset (db);
+ }
+
+ /** Wraps an existing Leveldb handler. */
+ Ldb (std::shared_ptr<leveldb::DB> db): _db (db) {}
+
+ template <typename K, typename V> void put (const K& key, const V& value, leveldb::WriteBatch& batch) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ ldbSerialize (kbytes, key);
+
+ char vbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring vbytes (sizeof (vbuf), vbuf, false, 0);
+ ldbSerialize (vbytes, value);
+
+ for (auto& trigger: _triggers) trigger.second->put (*this, (void*) &key, kbytes, (void*) &value, vbytes, batch);
+
+ batch.Put (leveldb::Slice (kbytes.data(), kbytes.size()), leveldb::Slice (vbytes.data(), vbytes.size()));
+ }
+ template <typename K, typename V> void put (const K& key, const V& value) {
+ leveldb::WriteBatch batch;
+ put (key, value, batch);
+ leveldb::Status status (_db->Write (leveldb::WriteOptions(), &batch));
+ if (!status.ok()) GNTHROW (LdbEx, "Ldb: add: " + status.ToString());
+ }
+
+ /** Returns `true` if the key exists. Throws on error. */
+ template <typename K> bool have (const K& key, leveldb::ReadOptions options = leveldb::ReadOptions()) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ ldbSerialize (kbytes, key);
+ leveldb::Slice keySlice (kbytes.data(), kbytes.size());
+
+ // NB: "BloomFilter only helps for Get() calls" - https://groups.google.com/d/msg/leveldb/oEiDztqHiHc/LMY3tHxzRGAJ
+ // "Apart from the lack of Bloom filter functionality, creating an iterator is really quite slow" - qpu2jSA8mCEJ
+ std::string str;
+ leveldb::Status status (_db->Get (options, keySlice, &str));
+ if (status.ok()) return true;
+ else if (status.IsNotFound()) return false;
+ else GTHROW ("Ldb.have: " + status.ToString());
+ }
+
+ /** Returns `true` and modifies `value` if `key` is found. */
+ template <typename K, typename V> bool get (const K& key, V& value, leveldb::ReadOptions options = leveldb::ReadOptions()) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ ldbSerialize (kbytes, key);
+ leveldb::Slice keySlice (kbytes.data(), kbytes.size());
+
+ // NB: "BloomFilter only helps for Get() calls" - https://groups.google.com/d/msg/leveldb/oEiDztqHiHc/LMY3tHxzRGAJ
+ // "Apart from the lack of Bloom filter functionality, creating an iterator is really quite slow" - qpu2jSA8mCEJ
+ std::string str;
+ leveldb::Status status (_db->Get (options, keySlice, &str));
+ if (status.ok()) {
+ ldbDeserialize (gstring (0, (void*) str.data(), false, str.size()), value);
+ return true;
+ } else if (status.IsNotFound()) return false;
+ else GTHROW ("Ldb.get: " + status.ToString());
+ }
+
+ template <typename K> void del (const K& key, leveldb::WriteBatch& batch) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ ldbSerialize (kbytes, key);
+ if (kbytes.empty()) GNTHROW (LdbEx, "del: key is empty");
+
+ for (auto& trigger: _triggers) trigger.second->del (*this, (void*) &key, kbytes, batch);
+
+ batch.Delete (leveldb::Slice (kbytes.data(), kbytes.size()));
+ }
+ template <typename K> void del (const K& key) {
+ leveldb::WriteBatch batch;
+ del (key, batch);
+ leveldb::Status status (_db->Write (leveldb::WriteOptions(), &batch));
+ if (!status.ok()) GNTHROW (LdbEx, "Ldb: del: " + status.ToString());
+ }
+
+ /** Writes the batch. Throws LdbEx if not successfull. */
+ void write (leveldb::WriteBatch& batch, leveldb::WriteOptions options = leveldb::WriteOptions()) {
+ leveldb::Status status (_db->Write (options, &batch));
+ if (!status.ok()) GNTHROW (LdbEx, status.ToString());
+ }
+
+ virtual ~Ldb() {
+ _triggers.clear(); // Destroy triggers before closing the database.
+ }
+};
+
+} // namespace glim
+
+#endif // _GLIM_LDB_HPP_INCLUDED
diff --git a/external/glim/makefile b/external/glim/makefile
new file mode 100644
index 000000000..88e240ac1
--- /dev/null
+++ b/external/glim/makefile
@@ -0,0 +1,93 @@
+
+PREFIX = /usr/local
+INSTALL2 = ${PREFIX}/include/glim
+CXXFLAGS = -std=c++1y -Wall -O2 -ggdb -DBOOST_ALL_DYN_LINK
+
+all: test
+
+help:
+ @echo "make test\nmake install\nmake uninstall\nmake clean"
+
+doc: doxyconf *.hpp
+ mkdir -p doc
+ doxygen doxyconf
+
+test: test_sqlite test_gstring test_runner test_exception test_ldb
+
+test_sqlite: bin/test_sqlite
+ cp bin/test_sqlite /tmp/libglim_test_sqlite && chmod +x /tmp/libglim_test_sqlite && /tmp/libglim_test_sqlite && rm -f /tmp/libglim_test_sqlite
+
+bin/test_sqlite: test_sqlite.cc
+ mkdir -p bin
+ g++ $(CXXFLAGS) test_sqlite.cc -o bin/test_sqlite -lsqlite3
+
+test_memcache: bin/test_memcache
+ cp bin/test_memcache /tmp/libglim_test_memcache && chmod +x /tmp/libglim_test_memcache && /tmp/libglim_test_memcache && rm -f /tmp/libglim_test_memcache
+
+bin/test_memcache: test_memcache.cc memcache.hpp
+ mkdir -p bin
+ g++ $(CXXFLAGS) test_memcache.cc -o bin/test_memcache -lmemcache
+
+bin/test_gstring: test_gstring.cc gstring.hpp
+ mkdir -p bin
+ g++ $(CXXFLAGS) test_gstring.cc -o bin/test_gstring
+
+test_gstring: bin/test_gstring
+ cp bin/test_gstring /tmp/libglim_test_gstring
+ chmod +x /tmp/libglim_test_gstring
+ /tmp/libglim_test_gstring
+ rm -f /tmp/libglim_test_gstring
+
+bin/test_runner: test_runner.cc runner.hpp curl.hpp
+ mkdir -p bin
+ g++ $(CXXFLAGS) test_runner.cc -o bin/test_runner -pthread -lboost_log -levent -levent_pthreads -lcurl
+
+test_runner: bin/test_runner
+ valgrind -q bin/test_runner
+
+bin/test_exception: test_exception.cc exception.hpp
+ mkdir -p bin
+ g++ $(CXXFLAGS) test_exception.cc -o bin/test_exception -ldl -rdynamic
+
+test_exception: bin/test_exception
+ valgrind -q bin/test_exception
+
+test_ldb: test_ldb.cc ldb.hpp
+ mkdir -p bin
+ g++ $(CXXFLAGS) test_ldb.cc -o bin/test_ldb \
+ -lleveldb -lboost_serialization -lboost_filesystem -lboost_system
+ valgrind -q bin/test_ldb
+
+bin/test_cbcoro: test_cbcoro.cc
+ mkdir -p bin
+ g++ $(CXXFLAGS) test_cbcoro.cc -o bin/test_cbcoro -pthread
+
+test_cbcoro: bin/test_cbcoro
+ bin/test_cbcoro
+
+install:
+ mkdir -p ${INSTALL2}/
+ cp sqlite.hpp ${INSTALL2}/
+ cp NsecTimer.hpp ${INSTALL2}/
+ cp TscTimer.hpp ${INSTALL2}/
+ cp memcache.hpp ${INSTALL2}/
+ cp gstring.hpp ${INSTALL2}/
+ cp runner.hpp ${INSTALL2}/
+ cp hget.hpp ${INSTALL2}/
+ cp curl.hpp ${INSTALL2}/
+ cp mdb.hpp ${INSTALL2}/
+ cp ldb.hpp ${INSTALL2}/
+ cp exception.hpp ${INSTALL2}/
+ cp SerializablePool.hpp ${INSTALL2}/
+ cp cbcoro.hpp ${INSTALL2}/
+ cp raii.hpp ${INSTALL2}/
+ cp channel.hpp ${INSTALL2}/
+
+uninstall:
+ rm -rf ${INSTALL2}
+
+clean:
+ rm -rf bin/*
+ rm -rf doc
+ rm -f /tmp/libglim_test_*
+ rm -f *.exe.stackdump
diff --git a/external/glim/mdb.hpp b/external/glim/mdb.hpp
new file mode 100644
index 000000000..eca66f37d
--- /dev/null
+++ b/external/glim/mdb.hpp
@@ -0,0 +1,499 @@
+#ifndef _GLIM_MDB_HPP_INCLUDED
+#define _GLIM_MDB_HPP_INCLUDED
+
+/**
+ * A C++ wrapper around MDB (http://www.symas.com/mdb/).
+ * @code
+Copyright 2012 Kozarezov Artem Aleksandrovich
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * @endcode
+ * @file
+ */
+
+#include <mdb.h>
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/serialization/serialization.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/range/iterator_range.hpp>
+
+#include <arpa/inet.h> // htonl, ntohl
+
+#include "gstring.hpp"
+
+namespace glim {
+
+struct MdbEx: public std::runtime_error {MdbEx (std::string message): std::runtime_error (message) {}};
+
+template <typename T> inline void mdbSerialize (gstring& bytes, const T& data) {
+ gstring_stream stream (bytes);
+ boost::archive::binary_oarchive oa (stream, boost::archive::no_header);
+ oa << data;
+}
+template <typename V> inline void mdbDeserialize (const gstring& bytes, V& data) {
+ gstring_stream stream (const_cast<gstring&> (bytes));
+ boost::archive::binary_iarchive ia (stream, boost::archive::no_header);
+ ia >> data;
+}
+
+/** uint32_t keys are stored big-endian (network byte order) in order to be compatible with lexicographic ordering. */
+template <> inline void mdbSerialize<uint32_t> (gstring& bytes, const uint32_t& ui) {
+ uint32_t nui = htonl (ui); bytes.append ((const char*) &nui, sizeof (uint32_t));}
+/** Deserialize uint32_t from big-endian (network byte order). */
+template <> inline void mdbDeserialize<uint32_t> (const gstring& bytes, uint32_t& ui) {
+ if (bytes.size() != sizeof (uint32_t)) throw MdbEx ("Not uint32_t, wrong number of bytes");
+ uint32_t nui = * (uint32_t*) bytes.data(); ui = ntohl (nui);}
+
+/** If the data is `gstring` then use the data's buffer directly, no copy. */
+template <> inline void mdbSerialize<gstring> (gstring& bytes, const gstring& data) {
+ bytes = gstring (0, (void*) data.data(), false, data.length());}
+/** Deserializing into `gstring` copies the bytes into it, reusing its buffer. */
+template <> inline void mdbDeserialize<gstring> (const gstring& bytes, gstring& data) {
+ data.clear() << bytes;}
+
+/**
+ * Header-only C++ wrapper around OpenLDAP-MDB.\n
+ * Uses Boost Serialization to pack keys and values (glim::gstring can be used for raw bytes).\n
+ * Allows semi-automatic indexing with triggers.\n
+ * Known issues: http://www.openldap.org/its/index.cgi?findid=7448
+ */
+struct Mdb {
+ std::shared_ptr<MDB_env> _env;
+ MDB_dbi _dbi = 0;
+
+ typedef std::unique_ptr<MDB_txn, void(*)(MDB_txn*)> Transaction;
+
+ /** Holds the current key and value of the Iterator. */
+ struct IteratorEntry {
+ MDB_val _key = {0, 0}, _val = {0, 0};
+ /** Zero-copy view of the current key bytes. Should *not* be used after the Iterator is changed or destroyed. */
+ const gstring keyView() const {return gstring (0, _key.mv_data, false, _key.mv_size, true);} // Zero copy.
+ /** Zero-copy view of the current value bytes. Should *not* be used after the Iterator is changed or destroyed. */
+ const gstring valueView() const {return gstring (0, _val.mv_data, false, _val.mv_size, true);} // Zero copy.
+ /** Deserialize into `key`. */
+ template <typename T> void getKey (T& key) const {mdbDeserialize (keyView(), key);}
+ /** Deserialize the key into a temporary and return it. */
+ template <typename T> T getKey() const {T key; getKey (key); return key;}
+ /** Deserialize into `value`. */
+ template <typename T> void getValue (T& value) const {mdbDeserialize (valueView(), value);}
+ /** Deserialize the value into a temporary and return it. */
+ template <typename T> T getValue() const {T value; getValue (value); return value;}
+ };
+ /** Holds the Iterator's unique transaction and cursor, allowing the Iterator to be copied. */
+ struct IteratorImpl: boost::noncopyable {
+ Mdb* _mdb;
+ Transaction _txn;
+ MDB_cursor* _cur;
+ IteratorImpl (Mdb* mdb, Transaction&& txn, MDB_cursor* cur): _mdb (mdb), _txn (std::move (txn)), _cur (cur) {}
+ ~IteratorImpl() {
+ if (_cur) {::mdb_cursor_close (_cur); _cur = nullptr;}
+ if (_mdb && _txn) {_mdb->commitTransaction (_txn); _mdb = nullptr;}
+ }
+ };
+ /** Wraps MDB cursor and cursor's transaction. */
+ struct Iterator: public boost::iterator_facade<Iterator, IteratorEntry, boost::bidirectional_traversal_tag> {
+ std::shared_ptr<IteratorImpl> _impl; // Iterator might be copied around, thus we keep the unique things in IteratorImpl.
+ IteratorEntry _entry;
+ bool _stayInKey = false;
+
+ Iterator (const Iterator&) = default;
+ Iterator (Iterator&&) = default;
+ /** Iterate from the beginning or the end of the database.
+ * @param position can be MDB_FIRST or MDB_LAST */
+ Iterator (Mdb* mdb, int position = 0): _stayInKey (false) {
+ Transaction txn (mdb->beginTransaction());
+ MDB_cursor* cur = nullptr; int rc = ::mdb_cursor_open (txn.get(), mdb->_dbi, &cur);
+ if (rc) throw MdbEx ("mdb_cursor_open");
+ _impl = std::make_shared<IteratorImpl> (mdb, std::move (txn), cur);
+ if (position == ::MDB_FIRST || position == ::MDB_LAST) {
+ rc = ::mdb_cursor_get (cur, &_entry._key, &_entry._val, (MDB_cursor_op) position);
+ if (rc) throw MdbEx ("mdb_cursor_get");
+ }
+ }
+ /** Iterate over `key` values.
+ * @param stayInKey if `false` then iterator can go farther than the `key`. */
+ Iterator (Mdb* mdb, const gstring& key, bool stayInKey = true): _stayInKey (stayInKey) {
+ Transaction txn (mdb->beginTransaction());
+ MDB_cursor* cur = nullptr; int rc = ::mdb_cursor_open (txn.get(), mdb->_dbi, &cur);
+ if (rc) throw MdbEx ("mdb_cursor_open");
+ _impl = std::make_shared<IteratorImpl> (mdb, std::move (txn), cur);
+ _entry._key = {key.size(), (void*) key.data()};
+ rc = ::mdb_cursor_get (cur, &_entry._key, &_entry._val, ::MDB_SET_KEY);
+ if (rc == MDB_NOTFOUND) {_entry._key = {0, 0}; _entry._val = {0, 0};}
+ else if (rc) throw MdbEx ("mdb_cursor_get");
+ }
+
+ struct EndIteratorFlag {};
+ /** The "end" iterator does not open an MDB transaction (this is essential for having a pair of iterators without a deadlock). */
+ Iterator (EndIteratorFlag): _stayInKey (false) {}
+ /** True if the iterator isn't pointing anywhere. */
+ bool end() const {return _entry._key.mv_size == 0;}
+
+ bool equal (const Iterator& other) const {
+ IteratorImpl* impl = _impl.get();
+ if (mdb_cmp (impl->_txn.get(), impl->_mdb->_dbi, &_entry._key, &other._entry._key)) return false;
+ if (mdb_dcmp (impl->_txn.get(), impl->_mdb->_dbi, &_entry._val, &other._entry._val)) return false;
+ return true;
+ }
+ IteratorEntry& dereference() const {
+ // NB: Boost iterator_facade expects the `dereference` to be a `const` method.
+ // I guess Iterator is not modified, so the `dereference` is `const`, even though the Entry can be modified.
+ return const_cast<IteratorEntry&> (_entry);}
+ void increment() {
+ int rc = ::mdb_cursor_get (_impl->_cur, &_entry._key, &_entry._val, _stayInKey ? ::MDB_NEXT_DUP : ::MDB_NEXT);
+ if (rc) {_entry._key = {0,0}; _entry._val = {0,0};}
+ }
+ void decrement() {
+ int rc = ::mdb_cursor_get (_impl->_cur, &_entry._key, &_entry._val, _stayInKey ? ::MDB_PREV_DUP : ::MDB_PREV);
+ if (rc) {_entry._key = {0,0}; _entry._val = {0,0};}
+ }
+ };
+ Iterator begin() {return Iterator (this, ::MDB_FIRST);}
+ const Iterator end() {return Iterator (Iterator::EndIteratorFlag());}
+ /** Position the cursor at the first `key` record.\n
+ * The iterator increment will use `MDB_NEXT_DUP`, staying withing the `key`.\n
+ * See also the `all` method. */
+ template <typename K> Iterator values (const K& key) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ mdbSerialize (kbytes, key);
+ return Iterator (this, kbytes);
+ }
+ /** Range over the `key` values.\n
+ * See also the `all` method. */
+ template <typename K> boost::iterator_range<Iterator> valuesRange (const K& key) {return boost::iterator_range<Iterator> (values (key), end());}
+
+ struct Trigger {
+ virtual gstring getTriggerName() const {return C2GSTRING ("defaultTriggerName");};
+ virtual void add (Mdb& mdb, void* key, gstring& kbytes, void* value, gstring& vbytes, Transaction& txn) = 0;
+ virtual void erase (Mdb& mdb, void* key, gstring& kbytes, Transaction& txn) = 0;
+ virtual void eraseKV (Mdb& mdb, void* key, gstring& kbytes, void* value, gstring& vbytes, Transaction& txn) = 0;
+ };
+ std::map<gstring, std::shared_ptr<Trigger>> _triggers;
+
+ void setTrigger (std::shared_ptr<Trigger> trigger) {
+ _triggers[trigger->getTriggerName()] = trigger;
+ }
+
+ /** `flags` can be `MDB_RDONLY` */
+ Transaction beginTransaction (unsigned flags = 0) {
+ MDB_txn* txn = 0; int rc = ::mdb_txn_begin (_env.get(), nullptr, flags, &txn);
+ if (rc) throw MdbEx (std::string ("mdb_txn_begin: ") + ::strerror (rc));
+ return Transaction (txn, ::mdb_txn_abort);
+ }
+ void commitTransaction (Transaction& txn) {
+ int rc = ::mdb_txn_commit (txn.get());
+ txn.release(); // Must prevent `mdb_txn_abort` from happening (even if rc != 0).
+ if (rc) throw MdbEx (std::string ("mdb_txn_commit: ") + ::strerror (rc));
+ }
+
+ virtual unsigned envFlags (uint8_t sync) {
+ unsigned flags = MDB_NOSUBDIR;
+ if (sync < 1) flags |= MDB_NOSYNC; else if (sync < 2) flags |= MDB_NOMETASYNC;
+ return flags;
+ }
+ /** Used before `mdb_env_open`. By default sets the number of database to 32. */
+ virtual void envConf (MDB_env* env) {
+ int rc = ::mdb_env_set_maxdbs (env, 32);
+ if (rc) throw MdbEx (std::string ("envConf: ") + ::strerror (rc));
+ }
+ virtual void dbFlags (unsigned& flags) {}
+
+ protected:
+ void open (const char* dbName, bool dup) {
+ auto txn = beginTransaction();
+ unsigned flags = MDB_CREATE;
+ if (dup) flags |= MDB_DUPSORT;
+ dbFlags (flags);
+ int rc = ::mdb_open (txn.get(), dbName, flags, &_dbi);
+ if (rc) throw MdbEx (std::string ("mdb_open (") + dbName + "): " + ::strerror (rc));
+ commitTransaction (txn);
+ }
+ public:
+
+ /** Opens MDB environment and MDB database. */
+ Mdb (const char* path, size_t maxSizeMb = 1024, const char* dbName = "main", uint8_t sync = 0, bool dup = true, mode_t mode = 0660) {
+ MDB_env* env = 0; int rc = ::mdb_env_create (&env);
+ if (rc) throw MdbEx (std::string ("mdb_env_create: ") + ::strerror (rc));
+ _env.reset (env, ::mdb_env_close);
+ rc = ::mdb_env_set_mapsize (env, maxSizeMb * 1024 * 1024);
+ if (rc) throw MdbEx (std::string ("mdb_env_set_mapsize: ") + ::strerror (rc));
+ envConf (env);
+ rc = ::mdb_env_open (env, path, envFlags (sync), mode);
+ _dbi = 0; open (dbName, dup);
+ }
+
+ /** Opens MDB database in the provided environment. */
+ Mdb (std::shared_ptr<MDB_env> env, const char* dbName, bool dup = true): _env (env), _dbi (0) {
+ open (dbName, dup);
+ }
+
+ template <typename K, typename V> void add (const K& key, const V& value, Transaction& txn) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ mdbSerialize (kbytes, key);
+ MDB_val mkey = {kbytes.size(), (void*) kbytes.data()};
+
+ char vbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring vbytes (sizeof (vbuf), vbuf, false, 0);
+ mdbSerialize (vbytes, value);
+ MDB_val mvalue = {vbytes.size(), (void*) vbytes.data()};
+
+ for (auto& trigger: _triggers) trigger.second->add (*this, (void*) &key, kbytes, (void*) &value, vbytes, txn);
+
+ int rc = ::mdb_put (txn.get(), _dbi, &mkey, &mvalue, 0);
+ if (rc) throw MdbEx (std::string ("mdb_put: ") + ::strerror (rc));
+ }
+ template <typename K, typename V> void add (const K& key, const V& value) {
+ Transaction txn (beginTransaction());
+ add (key, value, txn);
+ commitTransaction (txn);
+ }
+
+ template <typename K, typename V> bool first (const K& key, V& value, Transaction& txn) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ mdbSerialize (kbytes, key);
+ MDB_val mkey = {kbytes.size(), (void*) kbytes.data()};
+ MDB_val mvalue;
+ int rc = ::mdb_get (txn.get(), _dbi, &mkey, &mvalue);
+ if (rc == MDB_NOTFOUND) return false;
+ if (rc) throw MdbEx (std::string ("mdb_get: ") + ::strerror (rc));
+ gstring vstr (0, mvalue.mv_data, false, mvalue.mv_size);
+ mdbDeserialize (vstr, value);
+ return true;
+ }
+ template <typename K, typename V> bool first (const K& key, V& value) {
+ Transaction txn (beginTransaction (MDB_RDONLY));
+ bool rb = first (key, value, txn);
+ commitTransaction (txn);
+ return rb;
+ }
+
+ /** Iterate over `key` values until `visitor` returns `false`. Return the number of values visited. */
+ template <typename K, typename V> int32_t all (const K& key, std::function<bool(const V&)> visitor, Transaction& txn) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ mdbSerialize (kbytes, key);
+ MDB_val mkey = {kbytes.size(), (void*) kbytes.data()};
+
+ MDB_cursor* cur = 0; int rc = ::mdb_cursor_open (txn.get(), _dbi, &cur);
+ if (rc) throw MdbEx (std::string ("mdb_cursor_open: ") + ::strerror (rc));
+ std::unique_ptr<MDB_cursor, void(*)(MDB_cursor*)> curHolder (cur, ::mdb_cursor_close);
+ MDB_val mval = {0, 0};
+ rc = ::mdb_cursor_get (cur, &mkey, &mval, ::MDB_SET_KEY); if (rc == MDB_NOTFOUND) return 0;
+ if (rc) throw MdbEx (std::string ("mdb_cursor_get: ") + ::strerror (rc));
+
+ V value;
+ gstring vstr (0, mval.mv_data, false, mval.mv_size);
+ mdbDeserialize (vstr, value);
+ bool goOn = visitor (value);
+ int32_t count = 1;
+
+ while (goOn) {
+ rc = ::mdb_cursor_get (cur, &mkey, &mval, ::MDB_NEXT_DUP); if (rc == MDB_NOTFOUND) return count;
+ if (rc) throw MdbEx (std::string ("mdb_cursor_get: ") + ::strerror (rc));
+ gstring vstr (0, mval.mv_data, false, mval.mv_size);
+ mdbDeserialize (vstr, value);
+ goOn = visitor (value);
+ ++count;
+ }
+ return count;
+ }
+ /** Iterate over `key` values until `visitor` returns `false`. Return the number of values visited. */
+ template <typename K, typename V> int32_t all (const K& key, std::function<bool(const V&)> visitor) {
+ Transaction txn (beginTransaction (MDB_RDONLY));
+ int32_t count = all (key, visitor, txn);
+ commitTransaction (txn);
+ return count;
+ }
+
+ template <typename K, typename V> bool eraseKV (const K& key, const V& value, Transaction& txn) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ mdbSerialize (kbytes, key);
+ if (kbytes.empty()) throw MdbEx ("eraseKV: key is empty");
+ MDB_val mkey = {kbytes.size(), (void*) kbytes.data()};
+
+ char vbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring vbytes (sizeof (vbuf), vbuf, false, 0);
+ mdbSerialize (vbytes, value);
+ MDB_val mvalue = {vbytes.size(), (void*) vbytes.data()};
+
+ for (auto& trigger: _triggers) trigger.second->eraseKV (*this, (void*) &key, kbytes, (void*) &value, vbytes, txn);
+
+ int rc = ::mdb_del (txn.get(), _dbi, &mkey, &mvalue);
+ if (rc == MDB_NOTFOUND) return false;
+ if (rc) throw MdbEx (std::string ("mdb_del: ") + ::strerror (rc));
+ return true;
+ }
+ template <typename K, typename V> bool eraseKV (const K& key, const V& value) {
+ Transaction txn (beginTransaction());
+ bool rb = eraseKV (key, value, txn);
+ commitTransaction (txn);
+ return rb;
+ }
+
+ /** Erase all values of the `key`. */
+ template <typename K> bool erase (const K& key, Transaction& txn) {
+ char kbuf[64]; // Allow up to 64 bytes to be serialized without heap allocations.
+ gstring kbytes (sizeof (kbuf), kbuf, false, 0);
+ mdbSerialize (kbytes, key);
+ if (kbytes.empty()) throw MdbEx ("erase: key is empty");
+ MDB_val mkey = {kbytes.size(), (void*) kbytes.data()};
+
+ for (auto& trigger: _triggers) trigger.second->erase (*this, (void*) &key, kbytes, txn);
+
+ int rc = ::mdb_del (txn.get(), _dbi, &mkey, nullptr);
+ if (rc == MDB_NOTFOUND) return false;
+ if (rc) throw MdbEx (std::string ("mdb_del: ") + ::strerror (rc));
+ return true;
+ }
+ /** Erase all values of the `key`. */
+ template <typename K> bool erase (const K& key) {
+ Transaction txn (beginTransaction());
+ bool rb = erase (key, txn);
+ commitTransaction (txn);
+ return rb;
+ }
+
+ static void test (Mdb& mdb) {
+ mdb.add (std::string ("foo"), std::string ("bar"));
+ // NB: "MDB_DUPSORT doesn't allow duplicate duplicates" (Howard Chu)
+ mdb.add (std::string ("foo"), std::string ("bar"));
+ mdb.add ((uint32_t) 123, 1);
+ mdb.add ((uint32_t) 123, 2);
+ mdb.add (C2GSTRING ("foo"), 3);
+ mdb.add (C2GSTRING ("foo"), 4);
+ mdb.add (C2GSTRING ("gsk"), C2GSTRING ("gsv"));
+ string ts; int ti; gstring tgs;
+ auto fail = [](string msg) {throw std::runtime_error ("assertion failed: " + msg);};
+ if (!mdb.first (std::string ("foo"), ts) || ts != "bar") fail ("!foo=bar");
+ if (!mdb.first ((uint32_t) 123, ti) || ti < 1 || ti > 2) fail ("!123");
+ if (!mdb.first (C2GSTRING ("foo"), ti) || ti < 3 || ti > 4) fail ("!foo=3,4");
+ if (!mdb.first (C2GSTRING ("gsk"), tgs) || tgs != "gsv") fail ("!gsk=gsv");
+
+ // Test range-based for.
+ int count = 0; bool haveGskGsv = false;
+ for (auto&& entry: mdb) {
+ if (!entry._key.mv_size || !entry._val.mv_size) fail ("!entry");
+ if (entry.keyView() == "gsk") {
+ if (entry.getKey<gstring>() != "gsk") fail ("getKey(gsk)!=gsk");
+ if (entry.getValue<gstring>() != "gsv") fail ("getValue(gsk)!=gsv");
+ haveGskGsv = true;
+ }
+ ++count;}
+ if (count != 6) fail ("count!=6"); // foo=bar, 123=1, 123=2, foo=3, foo=4, gsk=gsv
+ if (!haveGskGsv) fail ("!haveGskGsv");
+
+ // Test `values`.
+ count = 0; int sum = 0;
+ for (auto&& entry: mdb.valuesRange ((uint32_t) 123)) {
+ if (entry.getKey<uint32_t>() != (uint32_t) 123) fail("values(123).key!=123");
+ ++count; sum += entry.getValue<int>();
+ }
+ if (count != 2) fail ("count(123)!=2");
+ if (sum != 3) fail ("sum(123)!=3");
+
+ if (!mdb.eraseKV ((uint32_t) 123, 1)) fail ("!eraseKV(123,1)");
+ if (!mdb.first ((uint32_t) 123, ti) || ti != 2) fail ("!123=2");
+ if (!mdb.eraseKV ((uint32_t) 123, 2)) fail ("!eraseKV(123,2)");
+ if (mdb.first ((uint32_t) 123, ti)) fail ("123");
+
+ if (!mdb.erase (C2GSTRING ("foo"))) fail ("!erase(g(foo))");
+ if (mdb.first (C2GSTRING ("foo"), ti)) fail ("foo");
+ if (!mdb.erase (std::string ("foo"))) fail ("!erase(str(foo))");
+
+ { // We've erased "123" and "foo", the only key left is "gsk" (gsk=gsv), let's test the iterator boundaries on this small dataset.
+ auto&& it = mdb.begin();
+ if (it->getKey<gstring>() != "gsk") fail ("first key !gsk " + it->keyView().str());
+ if (!(++it).end()) fail ("++it != end");
+ if ((--it)->getKey<gstring>() != "gsk") fail ("can't go back to gsk");
+ if (!(--it).end()) fail ("--it != end");
+ if ((++it)->getKey<gstring>() != "gsk") fail ("can't go forward to gsk");
+ }
+
+ struct SimpleIndexTrigger: public Trigger {
+ const char* _name; Mdb _indexDb;
+ SimpleIndexTrigger (Mdb& mdb, const char* name = "index"): _name (name), _indexDb (mdb._env, name) {}
+ gstring getTriggerName() {return gstring (0, (void*) _name, false, strlen (_name), true);}
+ void add (Mdb& mdb, void* key, gstring& kbytes, void* value, gstring& vbytes, Transaction& txn) {
+ MDB_val mkey = {vbytes.size(), (void*) vbytes.data()};
+ MDB_val mvalue = {kbytes.size(), (void*) kbytes.data()};
+ int rc = ::mdb_put (txn.get(), _indexDb._dbi, &mkey, &mvalue, 0);
+ if (rc) throw MdbEx (std::string ("index, mdb_put: ") + ::strerror (rc));
+ }
+ void erase (Mdb& mdb, void* ekey, gstring& kbytes, Transaction& txn) {
+ // Get all the values and remove them from the index.
+ MDB_cursor* cur = 0; int rc = ::mdb_cursor_open (txn.get(), mdb._dbi, &cur);
+ if (rc) throw MdbEx (std::string ("index, erase, mdb_cursor_open: ") + ::strerror (rc));
+ std::unique_ptr<MDB_cursor, void(*)(MDB_cursor*)> curHolder (cur, ::mdb_cursor_close);
+ MDB_val mkey = {kbytes.size(), (void*) kbytes.data()}, val = {0, 0};
+ rc = ::mdb_cursor_get (cur, &mkey, &val, ::MDB_SET_KEY); if (rc == MDB_NOTFOUND) return;
+ if (rc) throw MdbEx (std::string ("index, erase, mdb_cursor_get: ") + ::strerror (rc));
+ rc = ::mdb_del (txn.get(), _indexDb._dbi, &val, &mkey);
+ if (rc && rc != MDB_NOTFOUND) throw MdbEx (std::string ("index, erase, mdb_del: ") + ::strerror (rc));
+ for (;;) {
+ rc = ::mdb_cursor_get (cur, &mkey, &val, ::MDB_NEXT_DUP); if (rc == MDB_NOTFOUND) return;
+ if (rc) throw MdbEx (std::string ("index, erase, mdb_cursor_get: ") + ::strerror (rc));
+ rc = ::mdb_del (txn.get(), _indexDb._dbi, &val, &mkey);
+ if (rc && rc != MDB_NOTFOUND) throw MdbEx (std::string ("index, erase, mdb_del: ") + ::strerror (rc));
+ }
+ }
+ void eraseKV (Mdb& mdb, void* key, gstring& kbytes, void* value, gstring& vbytes, Transaction& txn) {
+ MDB_val mkey = {vbytes.size(), (void*) vbytes.data()};
+ MDB_val mvalue = {kbytes.size(), (void*) kbytes.data()};
+ int rc = ::mdb_del (txn.get(), _indexDb._dbi, &mkey, &mvalue);
+ if (rc && rc != MDB_NOTFOUND) throw MdbEx (std::string ("index, mdb_del: ") + ::strerror (rc));
+ }
+ };
+ auto indexTrigger = std::make_shared<SimpleIndexTrigger> (mdb); mdb.setTrigger (indexTrigger); auto& indexDb = indexTrigger->_indexDb;
+ mdb.erase (C2GSTRING ("gsk")); // NB: "gsk" wasn't indexed here. `IndexTrigger.erase` should handle this gracefully.
+
+ // Add indexed.
+ mdb.add (C2GSTRING ("ik"), C2GSTRING ("iv1"));
+ mdb.add (C2GSTRING ("ik"), string ("iv2"));
+ mdb.add (C2GSTRING ("ik"), 3);
+ // Check the index.
+ gstring ik;
+ if (!indexDb.first (C2GSTRING ("iv1"), ik) || ik != "ik") fail ("!iv1=ik");
+ if (!indexDb.first (string ("iv2"), ik) || ik != "ik") fail ("!iv2=ik");
+ if (!indexDb.first (3, ik) || ik != "ik") fail ("!iv3=ik");
+
+ // Remove indexed.
+ mdb.eraseKV (C2GSTRING ("ik"), string ("iv2"));
+ // Check the index.
+ if (!indexDb.first (C2GSTRING ("iv1"), ik) || ik != "ik") fail ("!iv1=ik");
+ if (indexDb.first (string ("iv2"), ik)) fail ("iv2=ik");
+ if (!indexDb.first (3, ik) || ik != "ik") fail ("!iv3=ik");
+
+ // Remove indexed.
+ mdb.erase (C2GSTRING ("ik"));
+ // Check the index.
+ if (indexDb.first (C2GSTRING ("iv1"), ik)) fail ("iv1");
+ if (indexDb.first (3, ik)) fail ("iv3");
+ // Check the data.
+ if (mdb.first (C2GSTRING ("ik"), ik)) fail ("ik");
+ }
+
+ virtual ~Mdb() {
+ _triggers.clear(); // Destroy triggers before closing the database.
+ if (_dbi) {::mdb_close (_env.get(), _dbi); _dbi = 0;}
+ }
+};
+
+} // namespace glim
+
+#endif // _GLIM_MDB_HPP_INCLUDED
diff --git a/external/glim/ql2.pb.cc b/external/glim/ql2.pb.cc
new file mode 100644
index 000000000..42e6e4667
--- /dev/null
+++ b/external/glim/ql2.pb.cc
@@ -0,0 +1,3741 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "ql2.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace {
+
+const ::google::protobuf::Descriptor* VersionDummy_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ VersionDummy_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* VersionDummy_Version_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* Query_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Query_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Query_AssocPair_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Query_AssocPair_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* Query_QueryType_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* Frame_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Frame_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* Frame_FrameType_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* Backtrace_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Backtrace_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Response_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Response_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* Response_ResponseType_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* Datum_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Datum_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Datum_AssocPair_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Datum_AssocPair_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* Datum_DatumType_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* Term_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Term_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Term_AssocPair_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ Term_AssocPair_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* Term_TermType_descriptor_ = NULL;
+
+} // namespace
+
+
+void protobuf_AssignDesc_ql2_2eproto() {
+ protobuf_AddDesc_ql2_2eproto();
+ const ::google::protobuf::FileDescriptor* file =
+ ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+ "ql2.proto");
+ GOOGLE_CHECK(file != NULL);
+ VersionDummy_descriptor_ = file->message_type(0);
+ static const int VersionDummy_offsets_[1] = {
+ };
+ VersionDummy_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ VersionDummy_descriptor_,
+ VersionDummy::default_instance_,
+ VersionDummy_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(VersionDummy, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(VersionDummy, _unknown_fields_),
+ -1,
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(VersionDummy));
+ VersionDummy_Version_descriptor_ = VersionDummy_descriptor_->enum_type(0);
+ Query_descriptor_ = file->message_type(1);
+ static const int Query_offsets_[5] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query, type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query, query_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query, token_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query, obsolete_noreply_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query, global_optargs_),
+ };
+ Query_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Query_descriptor_,
+ Query::default_instance_,
+ Query_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query, _unknown_fields_),
+ -1,
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Query));
+ Query_AssocPair_descriptor_ = Query_descriptor_->nested_type(0);
+ static const int Query_AssocPair_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query_AssocPair, key_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query_AssocPair, val_),
+ };
+ Query_AssocPair_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Query_AssocPair_descriptor_,
+ Query_AssocPair::default_instance_,
+ Query_AssocPair_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query_AssocPair, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Query_AssocPair, _unknown_fields_),
+ -1,
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Query_AssocPair));
+ Query_QueryType_descriptor_ = Query_descriptor_->enum_type(0);
+ Frame_descriptor_ = file->message_type(2);
+ static const int Frame_offsets_[3] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Frame, type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Frame, pos_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Frame, opt_),
+ };
+ Frame_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Frame_descriptor_,
+ Frame::default_instance_,
+ Frame_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Frame, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Frame, _unknown_fields_),
+ -1,
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Frame));
+ Frame_FrameType_descriptor_ = Frame_descriptor_->enum_type(0);
+ Backtrace_descriptor_ = file->message_type(3);
+ static const int Backtrace_offsets_[1] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Backtrace, frames_),
+ };
+ Backtrace_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Backtrace_descriptor_,
+ Backtrace::default_instance_,
+ Backtrace_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Backtrace, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Backtrace, _unknown_fields_),
+ -1,
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Backtrace));
+ Response_descriptor_ = file->message_type(4);
+ static const int Response_offsets_[4] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Response, type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Response, token_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Response, response_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Response, backtrace_),
+ };
+ Response_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Response_descriptor_,
+ Response::default_instance_,
+ Response_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Response, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Response, _unknown_fields_),
+ -1,
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Response));
+ Response_ResponseType_descriptor_ = Response_descriptor_->enum_type(0);
+ Datum_descriptor_ = file->message_type(5);
+ static const int Datum_offsets_[6] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, r_bool_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, r_num_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, r_str_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, r_array_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, r_object_),
+ };
+ Datum_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Datum_descriptor_,
+ Datum::default_instance_,
+ Datum_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, _unknown_fields_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, _extensions_),
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Datum));
+ Datum_AssocPair_descriptor_ = Datum_descriptor_->nested_type(0);
+ static const int Datum_AssocPair_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum_AssocPair, key_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum_AssocPair, val_),
+ };
+ Datum_AssocPair_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Datum_AssocPair_descriptor_,
+ Datum_AssocPair::default_instance_,
+ Datum_AssocPair_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum_AssocPair, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum_AssocPair, _unknown_fields_),
+ -1,
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Datum_AssocPair));
+ Datum_DatumType_descriptor_ = Datum_descriptor_->enum_type(0);
+ Term_descriptor_ = file->message_type(6);
+ static const int Term_offsets_[4] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term, type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term, datum_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term, args_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term, optargs_),
+ };
+ Term_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Term_descriptor_,
+ Term::default_instance_,
+ Term_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term, _unknown_fields_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term, _extensions_),
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Term));
+ Term_AssocPair_descriptor_ = Term_descriptor_->nested_type(0);
+ static const int Term_AssocPair_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term_AssocPair, key_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term_AssocPair, val_),
+ };
+ Term_AssocPair_reflection_ =
+ new ::google::protobuf::internal::GeneratedMessageReflection(
+ Term_AssocPair_descriptor_,
+ Term_AssocPair::default_instance_,
+ Term_AssocPair_offsets_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term_AssocPair, _has_bits_[0]),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Term_AssocPair, _unknown_fields_),
+ -1,
+ ::google::protobuf::DescriptorPool::generated_pool(),
+ ::google::protobuf::MessageFactory::generated_factory(),
+ sizeof(Term_AssocPair));
+ Term_TermType_descriptor_ = Term_descriptor_->enum_type(0);
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+ ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+ &protobuf_AssignDesc_ql2_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ VersionDummy_descriptor_, &VersionDummy::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Query_descriptor_, &Query::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Query_AssocPair_descriptor_, &Query_AssocPair::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Frame_descriptor_, &Frame::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Backtrace_descriptor_, &Backtrace::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Response_descriptor_, &Response::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Datum_descriptor_, &Datum::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Datum_AssocPair_descriptor_, &Datum_AssocPair::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Term_descriptor_, &Term::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ Term_AssocPair_descriptor_, &Term_AssocPair::default_instance());
+}
+
+} // namespace
+
+void protobuf_ShutdownFile_ql2_2eproto() {
+ delete VersionDummy::default_instance_;
+ delete VersionDummy_reflection_;
+ delete Query::default_instance_;
+ delete Query_reflection_;
+ delete Query_AssocPair::default_instance_;
+ delete Query_AssocPair_reflection_;
+ delete Frame::default_instance_;
+ delete Frame_reflection_;
+ delete Backtrace::default_instance_;
+ delete Backtrace_reflection_;
+ delete Response::default_instance_;
+ delete Response_reflection_;
+ delete Datum::default_instance_;
+ delete Datum_reflection_;
+ delete Datum_AssocPair::default_instance_;
+ delete Datum_AssocPair_reflection_;
+ delete Term::default_instance_;
+ delete Term_reflection_;
+ delete Term_AssocPair::default_instance_;
+ delete Term_AssocPair_reflection_;
+}
+
+void protobuf_AddDesc_ql2_2eproto() {
+ static bool already_here = false;
+ if (already_here) return;
+ already_here = true;
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+ "\n\tql2.proto\"5\n\014VersionDummy\"%\n\007Version\022\014"
+ "\n\004V0_1\020\266\364\206\373\003\022\014\n\004V0_2\020\341\203\302\221\007\"\365\001\n\005Query\022\036\n\004"
+ "type\030\001 \001(\0162\020.Query.QueryType\022\024\n\005query\030\002 "
+ "\001(\0132\005.Term\022\r\n\005token\030\003 \001(\003\022\037\n\020OBSOLETE_no"
+ "reply\030\004 \001(\010:\005false\022(\n\016global_optargs\030\006 \003"
+ "(\0132\020.Query.AssocPair\032,\n\tAssocPair\022\013\n\003key"
+ "\030\001 \001(\t\022\022\n\003val\030\002 \001(\0132\005.Term\".\n\tQueryType\022"
+ "\t\n\005START\020\001\022\014\n\010CONTINUE\020\002\022\010\n\004STOP\020\003\"`\n\005Fr"
+ "ame\022\036\n\004type\030\001 \001(\0162\020.Frame.FrameType\022\013\n\003p"
+ "os\030\002 \001(\003\022\013\n\003opt\030\003 \001(\t\"\035\n\tFrameType\022\007\n\003PO"
+ "S\020\001\022\007\n\003OPT\020\002\"#\n\tBacktrace\022\026\n\006frames\030\001 \003("
+ "\0132\006.Frame\"\376\001\n\010Response\022$\n\004type\030\001 \001(\0162\026.R"
+ "esponse.ResponseType\022\r\n\005token\030\002 \001(\003\022\030\n\010r"
+ "esponse\030\003 \003(\0132\006.Datum\022\035\n\tbacktrace\030\004 \001(\013"
+ "2\n.Backtrace\"\203\001\n\014ResponseType\022\020\n\014SUCCESS"
+ "_ATOM\020\001\022\024\n\020SUCCESS_SEQUENCE\020\002\022\023\n\017SUCCESS"
+ "_PARTIAL\020\003\022\020\n\014CLIENT_ERROR\020\020\022\021\n\rCOMPILE_"
+ "ERROR\020\021\022\021\n\rRUNTIME_ERROR\020\022\"\240\002\n\005Datum\022\036\n\004"
+ "type\030\001 \001(\0162\020.Datum.DatumType\022\016\n\006r_bool\030\002"
+ " \001(\010\022\r\n\005r_num\030\003 \001(\001\022\r\n\005r_str\030\004 \001(\t\022\027\n\007r_"
+ "array\030\005 \003(\0132\006.Datum\022\"\n\010r_object\030\006 \003(\0132\020."
+ "Datum.AssocPair\032-\n\tAssocPair\022\013\n\003key\030\001 \001("
+ "\t\022\023\n\003val\030\002 \001(\0132\006.Datum\"T\n\tDatumType\022\n\n\006R"
+ "_NULL\020\001\022\n\n\006R_BOOL\020\002\022\t\n\005R_NUM\020\003\022\t\n\005R_STR\020"
+ "\004\022\013\n\007R_ARRAY\020\005\022\014\n\010R_OBJECT\020\006*\007\010\220N\020\241\234\001\"\247\n"
+ "\n\004Term\022\034\n\004type\030\001 \001(\0162\016.Term.TermType\022\025\n\005"
+ "datum\030\002 \001(\0132\006.Datum\022\023\n\004args\030\003 \003(\0132\005.Term"
+ "\022 \n\007optargs\030\004 \003(\0132\017.Term.AssocPair\032,\n\tAs"
+ "socPair\022\013\n\003key\030\001 \001(\t\022\022\n\003val\030\002 \001(\0132\005.Term"
+ "\"\373\010\n\010TermType\022\t\n\005DATUM\020\001\022\016\n\nMAKE_ARRAY\020\002"
+ "\022\014\n\010MAKE_OBJ\020\003\022\007\n\003VAR\020\n\022\016\n\nJAVASCRIPT\020\013\022"
+ "\t\n\005ERROR\020\014\022\020\n\014IMPLICIT_VAR\020\r\022\006\n\002DB\020\016\022\t\n\005"
+ "TABLE\020\017\022\007\n\003GET\020\020\022\013\n\007GET_ALL\020N\022\006\n\002EQ\020\021\022\006\n"
+ "\002NE\020\022\022\006\n\002LT\020\023\022\006\n\002LE\020\024\022\006\n\002GT\020\025\022\006\n\002GE\020\026\022\007\n"
+ "\003NOT\020\027\022\007\n\003ADD\020\030\022\007\n\003SUB\020\031\022\007\n\003MUL\020\032\022\007\n\003DIV"
+ "\020\033\022\007\n\003MOD\020\034\022\n\n\006APPEND\020\035\022\013\n\007PREPEND\020P\022\016\n\n"
+ "DIFFERENCE\020_\022\016\n\nSET_INSERT\020X\022\024\n\020SET_INTE"
+ "RSECTION\020Y\022\r\n\tSET_UNION\020Z\022\022\n\016SET_DIFFERE"
+ "NCE\020[\022\t\n\005SLICE\020\036\022\010\n\004SKIP\020F\022\t\n\005LIMIT\020G\022\016\n"
+ "\nINDEXES_OF\020W\022\014\n\010CONTAINS\020]\022\013\n\007GETATTR\020\037"
+ "\022\010\n\004KEYS\020^\022\016\n\nHAS_FIELDS\020 \022\017\n\013WITH_FIELD"
+ "S\020`\022\t\n\005PLUCK\020!\022\013\n\007WITHOUT\020\"\022\t\n\005MERGE\020#\022\013"
+ "\n\007BETWEEN\020$\022\n\n\006REDUCE\020%\022\007\n\003MAP\020&\022\n\n\006FILT"
+ "ER\020\'\022\r\n\tCONCATMAP\020(\022\013\n\007ORDERBY\020)\022\014\n\010DIST"
+ "INCT\020*\022\t\n\005COUNT\020+\022\014\n\010IS_EMPTY\020V\022\t\n\005UNION"
+ "\020,\022\007\n\003NTH\020-\022\026\n\022GROUPED_MAP_REDUCE\020.\022\013\n\007G"
+ "ROUPBY\020/\022\016\n\nINNER_JOIN\0200\022\016\n\nOUTER_JOIN\0201"
+ "\022\013\n\007EQ_JOIN\0202\022\007\n\003ZIP\020H\022\r\n\tINSERT_AT\020R\022\r\n"
+ "\tDELETE_AT\020S\022\r\n\tCHANGE_AT\020T\022\r\n\tSPLICE_AT"
+ "\020U\022\r\n\tCOERCE_TO\0203\022\n\n\006TYPEOF\0204\022\n\n\006UPDATE\020"
+ "5\022\n\n\006DELETE\0206\022\013\n\007REPLACE\0207\022\n\n\006INSERT\0208\022\r"
+ "\n\tDB_CREATE\0209\022\013\n\007DB_DROP\020:\022\013\n\007DB_LIST\020;\022"
+ "\020\n\014TABLE_CREATE\020<\022\016\n\nTABLE_DROP\020=\022\016\n\nTAB"
+ "LE_LIST\020>\022\020\n\014INDEX_CREATE\020K\022\016\n\nINDEX_DRO"
+ "P\020L\022\016\n\nINDEX_LIST\020M\022\013\n\007FUNCALL\020@\022\n\n\006BRAN"
+ "CH\020A\022\007\n\003ANY\020B\022\007\n\003ALL\020C\022\013\n\007FOREACH\020D\022\010\n\004F"
+ "UNC\020E\022\007\n\003ASC\020I\022\010\n\004DESC\020J\022\010\n\004INFO\020O\022\t\n\005MA"
+ "TCH\020a\022\n\n\006SAMPLE\020Q\022\013\n\007DEFAULT\020\\*\007\010\220N\020\241\234\001", 2319);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+ "ql2.proto", &protobuf_RegisterTypes);
+ VersionDummy::default_instance_ = new VersionDummy();
+ Query::default_instance_ = new Query();
+ Query_AssocPair::default_instance_ = new Query_AssocPair();
+ Frame::default_instance_ = new Frame();
+ Backtrace::default_instance_ = new Backtrace();
+ Response::default_instance_ = new Response();
+ Datum::default_instance_ = new Datum();
+ Datum_AssocPair::default_instance_ = new Datum_AssocPair();
+ Term::default_instance_ = new Term();
+ Term_AssocPair::default_instance_ = new Term_AssocPair();
+ VersionDummy::default_instance_->InitAsDefaultInstance();
+ Query::default_instance_->InitAsDefaultInstance();
+ Query_AssocPair::default_instance_->InitAsDefaultInstance();
+ Frame::default_instance_->InitAsDefaultInstance();
+ Backtrace::default_instance_->InitAsDefaultInstance();
+ Response::default_instance_->InitAsDefaultInstance();
+ Datum::default_instance_->InitAsDefaultInstance();
+ Datum_AssocPair::default_instance_->InitAsDefaultInstance();
+ Term::default_instance_->InitAsDefaultInstance();
+ Term_AssocPair::default_instance_->InitAsDefaultInstance();
+ ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_ql2_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_ql2_2eproto {
+ StaticDescriptorInitializer_ql2_2eproto() {
+ protobuf_AddDesc_ql2_2eproto();
+ }
+} static_descriptor_initializer_ql2_2eproto_;
+
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* VersionDummy_Version_descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return VersionDummy_Version_descriptor_;
+}
+bool VersionDummy_Version_IsValid(int value) {
+ switch(value) {
+ case 1063369270:
+ case 1915781601:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
+const VersionDummy_Version VersionDummy::V0_1;
+const VersionDummy_Version VersionDummy::V0_2;
+const VersionDummy_Version VersionDummy::Version_MIN;
+const VersionDummy_Version VersionDummy::Version_MAX;
+const int VersionDummy::Version_ARRAYSIZE;
+#endif // _MSC_VER
+#ifndef _MSC_VER
+#endif // !_MSC_VER
+
+VersionDummy::VersionDummy()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void VersionDummy::InitAsDefaultInstance() {
+}
+
+VersionDummy::VersionDummy(const VersionDummy& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void VersionDummy::SharedCtor() {
+ _cached_size_ = 0;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+VersionDummy::~VersionDummy() {
+ SharedDtor();
+}
+
+void VersionDummy::SharedDtor() {
+ if (this != default_instance_) {
+ }
+}
+
+void VersionDummy::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* VersionDummy::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return VersionDummy_descriptor_;
+}
+
+const VersionDummy& VersionDummy::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+VersionDummy* VersionDummy::default_instance_ = NULL;
+
+VersionDummy* VersionDummy::New() const {
+ return new VersionDummy;
+}
+
+void VersionDummy::Clear() {
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool VersionDummy::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ }
+ return true;
+#undef DO_
+}
+
+void VersionDummy::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* VersionDummy::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int VersionDummy::ByteSize() const {
+ int total_size = 0;
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void VersionDummy::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const VersionDummy* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const VersionDummy*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void VersionDummy::MergeFrom(const VersionDummy& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void VersionDummy::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void VersionDummy::CopyFrom(const VersionDummy& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool VersionDummy::IsInitialized() const {
+
+ return true;
+}
+
+void VersionDummy::Swap(VersionDummy* other) {
+ if (other != this) {
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata VersionDummy::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = VersionDummy_descriptor_;
+ metadata.reflection = VersionDummy_reflection_;
+ return metadata;
+}
+
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* Query_QueryType_descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Query_QueryType_descriptor_;
+}
+bool Query_QueryType_IsValid(int value) {
+ switch(value) {
+ case 1:
+ case 2:
+ case 3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
+const Query_QueryType Query::START;
+const Query_QueryType Query::CONTINUE;
+const Query_QueryType Query::STOP;
+const Query_QueryType Query::QueryType_MIN;
+const Query_QueryType Query::QueryType_MAX;
+const int Query::QueryType_ARRAYSIZE;
+#endif // _MSC_VER
+#ifndef _MSC_VER
+const int Query_AssocPair::kKeyFieldNumber;
+const int Query_AssocPair::kValFieldNumber;
+#endif // !_MSC_VER
+
+Query_AssocPair::Query_AssocPair()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void Query_AssocPair::InitAsDefaultInstance() {
+ val_ = const_cast< ::Term*>(&::Term::default_instance());
+}
+
+Query_AssocPair::Query_AssocPair(const Query_AssocPair& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Query_AssocPair::SharedCtor() {
+ _cached_size_ = 0;
+ key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ val_ = NULL;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Query_AssocPair::~Query_AssocPair() {
+ SharedDtor();
+}
+
+void Query_AssocPair::SharedDtor() {
+ if (key_ != &::google::protobuf::internal::kEmptyString) {
+ delete key_;
+ }
+ if (this != default_instance_) {
+ delete val_;
+ }
+}
+
+void Query_AssocPair::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Query_AssocPair::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Query_AssocPair_descriptor_;
+}
+
+const Query_AssocPair& Query_AssocPair::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+Query_AssocPair* Query_AssocPair::default_instance_ = NULL;
+
+Query_AssocPair* Query_AssocPair::New() const {
+ return new Query_AssocPair;
+}
+
+void Query_AssocPair::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (has_key()) {
+ if (key_ != &::google::protobuf::internal::kEmptyString) {
+ key_->clear();
+ }
+ }
+ if (has_val()) {
+ if (val_ != NULL) val_->::Term::Clear();
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Query_AssocPair::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string key = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_key()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->key().data(), this->key().length(),
+ ::google::protobuf::internal::WireFormat::PARSE);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(18)) goto parse_val;
+ break;
+ }
+
+ // optional .Term val = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_val:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_val()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Query_AssocPair::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional string key = 1;
+ if (has_key()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->key().data(), this->key().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 1, this->key(), output);
+ }
+
+ // optional .Term val = 2;
+ if (has_val()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 2, this->val(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* Query_AssocPair::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // optional string key = 1;
+ if (has_key()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->key().data(), this->key().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 1, this->key(), target);
+ }
+
+ // optional .Term val = 2;
+ if (has_val()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 2, this->val(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int Query_AssocPair::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string key = 1;
+ if (has_key()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->key());
+ }
+
+ // optional .Term val = 2;
+ if (has_val()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->val());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Query_AssocPair::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Query_AssocPair* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Query_AssocPair*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Query_AssocPair::MergeFrom(const Query_AssocPair& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_key()) {
+ set_key(from.key());
+ }
+ if (from.has_val()) {
+ mutable_val()->::Term::MergeFrom(from.val());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Query_AssocPair::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Query_AssocPair::CopyFrom(const Query_AssocPair& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Query_AssocPair::IsInitialized() const {
+
+ if (has_val()) {
+ if (!this->val().IsInitialized()) return false;
+ }
+ return true;
+}
+
+void Query_AssocPair::Swap(Query_AssocPair* other) {
+ if (other != this) {
+ std::swap(key_, other->key_);
+ std::swap(val_, other->val_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Query_AssocPair::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Query_AssocPair_descriptor_;
+ metadata.reflection = Query_AssocPair_reflection_;
+ return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
+const int Query::kTypeFieldNumber;
+const int Query::kQueryFieldNumber;
+const int Query::kTokenFieldNumber;
+const int Query::kOBSOLETENoreplyFieldNumber;
+const int Query::kGlobalOptargsFieldNumber;
+#endif // !_MSC_VER
+
+Query::Query()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void Query::InitAsDefaultInstance() {
+ query_ = const_cast< ::Term*>(&::Term::default_instance());
+}
+
+Query::Query(const Query& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Query::SharedCtor() {
+ _cached_size_ = 0;
+ type_ = 1;
+ query_ = NULL;
+ token_ = GOOGLE_LONGLONG(0);
+ obsolete_noreply_ = false;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Query::~Query() {
+ SharedDtor();
+}
+
+void Query::SharedDtor() {
+ if (this != default_instance_) {
+ delete query_;
+ }
+}
+
+void Query::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Query::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Query_descriptor_;
+}
+
+const Query& Query::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+Query* Query::default_instance_ = NULL;
+
+Query* Query::New() const {
+ return new Query;
+}
+
+void Query::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ type_ = 1;
+ if (has_query()) {
+ if (query_ != NULL) query_->::Term::Clear();
+ }
+ token_ = GOOGLE_LONGLONG(0);
+ obsolete_noreply_ = false;
+ }
+ global_optargs_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Query::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional .Query.QueryType type = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ int value;
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+ input, &value)));
+ if (::Query_QueryType_IsValid(value)) {
+ set_type(static_cast< ::Query_QueryType >(value));
+ } else {
+ mutable_unknown_fields()->AddVarint(1, value);
+ }
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(18)) goto parse_query;
+ break;
+ }
+
+ // optional .Term query = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_query:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_query()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(24)) goto parse_token;
+ break;
+ }
+
+ // optional int64 token = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_token:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+ input, &token_)));
+ set_has_token();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(32)) goto parse_OBSOLETE_noreply;
+ break;
+ }
+
+ // optional bool OBSOLETE_noreply = 4 [default = false];
+ case 4: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_OBSOLETE_noreply:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &obsolete_noreply_)));
+ set_has_obsolete_noreply();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(50)) goto parse_global_optargs;
+ break;
+ }
+
+ // repeated .Query.AssocPair global_optargs = 6;
+ case 6: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_global_optargs:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, add_global_optargs()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(50)) goto parse_global_optargs;
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Query::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional .Query.QueryType type = 1;
+ if (has_type()) {
+ ::google::protobuf::internal::WireFormatLite::WriteEnum(
+ 1, this->type(), output);
+ }
+
+ // optional .Term query = 2;
+ if (has_query()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 2, this->query(), output);
+ }
+
+ // optional int64 token = 3;
+ if (has_token()) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt64(3, this->token(), output);
+ }
+
+ // optional bool OBSOLETE_noreply = 4 [default = false];
+ if (has_obsolete_noreply()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(4, this->obsolete_noreply(), output);
+ }
+
+ // repeated .Query.AssocPair global_optargs = 6;
+ for (int i = 0; i < this->global_optargs_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 6, this->global_optargs(i), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* Query::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // optional .Query.QueryType type = 1;
+ if (has_type()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+ 1, this->type(), target);
+ }
+
+ // optional .Term query = 2;
+ if (has_query()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 2, this->query(), target);
+ }
+
+ // optional int64 token = 3;
+ if (has_token()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(3, this->token(), target);
+ }
+
+ // optional bool OBSOLETE_noreply = 4 [default = false];
+ if (has_obsolete_noreply()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(4, this->obsolete_noreply(), target);
+ }
+
+ // repeated .Query.AssocPair global_optargs = 6;
+ for (int i = 0; i < this->global_optargs_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 6, this->global_optargs(i), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int Query::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional .Query.QueryType type = 1;
+ if (has_type()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
+ }
+
+ // optional .Term query = 2;
+ if (has_query()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->query());
+ }
+
+ // optional int64 token = 3;
+ if (has_token()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int64Size(
+ this->token());
+ }
+
+ // optional bool OBSOLETE_noreply = 4 [default = false];
+ if (has_obsolete_noreply()) {
+ total_size += 1 + 1;
+ }
+
+ }
+ // repeated .Query.AssocPair global_optargs = 6;
+ total_size += 1 * this->global_optargs_size();
+ for (int i = 0; i < this->global_optargs_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->global_optargs(i));
+ }
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Query::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Query* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Query*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Query::MergeFrom(const Query& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ global_optargs_.MergeFrom(from.global_optargs_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_type()) {
+ set_type(from.type());
+ }
+ if (from.has_query()) {
+ mutable_query()->::Term::MergeFrom(from.query());
+ }
+ if (from.has_token()) {
+ set_token(from.token());
+ }
+ if (from.has_obsolete_noreply()) {
+ set_obsolete_noreply(from.obsolete_noreply());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Query::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Query::CopyFrom(const Query& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Query::IsInitialized() const {
+
+ if (has_query()) {
+ if (!this->query().IsInitialized()) return false;
+ }
+ for (int i = 0; i < global_optargs_size(); i++) {
+ if (!this->global_optargs(i).IsInitialized()) return false;
+ }
+ return true;
+}
+
+void Query::Swap(Query* other) {
+ if (other != this) {
+ std::swap(type_, other->type_);
+ std::swap(query_, other->query_);
+ std::swap(token_, other->token_);
+ std::swap(obsolete_noreply_, other->obsolete_noreply_);
+ global_optargs_.Swap(&other->global_optargs_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Query::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Query_descriptor_;
+ metadata.reflection = Query_reflection_;
+ return metadata;
+}
+
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* Frame_FrameType_descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Frame_FrameType_descriptor_;
+}
+bool Frame_FrameType_IsValid(int value) {
+ switch(value) {
+ case 1:
+ case 2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
+const Frame_FrameType Frame::POS;
+const Frame_FrameType Frame::OPT;
+const Frame_FrameType Frame::FrameType_MIN;
+const Frame_FrameType Frame::FrameType_MAX;
+const int Frame::FrameType_ARRAYSIZE;
+#endif // _MSC_VER
+#ifndef _MSC_VER
+const int Frame::kTypeFieldNumber;
+const int Frame::kPosFieldNumber;
+const int Frame::kOptFieldNumber;
+#endif // !_MSC_VER
+
+Frame::Frame()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void Frame::InitAsDefaultInstance() {
+}
+
+Frame::Frame(const Frame& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Frame::SharedCtor() {
+ _cached_size_ = 0;
+ type_ = 1;
+ pos_ = GOOGLE_LONGLONG(0);
+ opt_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Frame::~Frame() {
+ SharedDtor();
+}
+
+void Frame::SharedDtor() {
+ if (opt_ != &::google::protobuf::internal::kEmptyString) {
+ delete opt_;
+ }
+ if (this != default_instance_) {
+ }
+}
+
+void Frame::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Frame::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Frame_descriptor_;
+}
+
+const Frame& Frame::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+Frame* Frame::default_instance_ = NULL;
+
+Frame* Frame::New() const {
+ return new Frame;
+}
+
+void Frame::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ type_ = 1;
+ pos_ = GOOGLE_LONGLONG(0);
+ if (has_opt()) {
+ if (opt_ != &::google::protobuf::internal::kEmptyString) {
+ opt_->clear();
+ }
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Frame::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional .Frame.FrameType type = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ int value;
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+ input, &value)));
+ if (::Frame_FrameType_IsValid(value)) {
+ set_type(static_cast< ::Frame_FrameType >(value));
+ } else {
+ mutable_unknown_fields()->AddVarint(1, value);
+ }
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(16)) goto parse_pos;
+ break;
+ }
+
+ // optional int64 pos = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_pos:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+ input, &pos_)));
+ set_has_pos();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(26)) goto parse_opt;
+ break;
+ }
+
+ // optional string opt = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_opt:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_opt()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->opt().data(), this->opt().length(),
+ ::google::protobuf::internal::WireFormat::PARSE);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Frame::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional .Frame.FrameType type = 1;
+ if (has_type()) {
+ ::google::protobuf::internal::WireFormatLite::WriteEnum(
+ 1, this->type(), output);
+ }
+
+ // optional int64 pos = 2;
+ if (has_pos()) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt64(2, this->pos(), output);
+ }
+
+ // optional string opt = 3;
+ if (has_opt()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->opt().data(), this->opt().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 3, this->opt(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* Frame::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // optional .Frame.FrameType type = 1;
+ if (has_type()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+ 1, this->type(), target);
+ }
+
+ // optional int64 pos = 2;
+ if (has_pos()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(2, this->pos(), target);
+ }
+
+ // optional string opt = 3;
+ if (has_opt()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->opt().data(), this->opt().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 3, this->opt(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int Frame::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional .Frame.FrameType type = 1;
+ if (has_type()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
+ }
+
+ // optional int64 pos = 2;
+ if (has_pos()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int64Size(
+ this->pos());
+ }
+
+ // optional string opt = 3;
+ if (has_opt()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->opt());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Frame::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Frame* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Frame*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Frame::MergeFrom(const Frame& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_type()) {
+ set_type(from.type());
+ }
+ if (from.has_pos()) {
+ set_pos(from.pos());
+ }
+ if (from.has_opt()) {
+ set_opt(from.opt());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Frame::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Frame::CopyFrom(const Frame& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Frame::IsInitialized() const {
+
+ return true;
+}
+
+void Frame::Swap(Frame* other) {
+ if (other != this) {
+ std::swap(type_, other->type_);
+ std::swap(pos_, other->pos_);
+ std::swap(opt_, other->opt_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Frame::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Frame_descriptor_;
+ metadata.reflection = Frame_reflection_;
+ return metadata;
+}
+
+
+// ===================================================================
+
+#ifndef _MSC_VER
+const int Backtrace::kFramesFieldNumber;
+#endif // !_MSC_VER
+
+Backtrace::Backtrace()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void Backtrace::InitAsDefaultInstance() {
+}
+
+Backtrace::Backtrace(const Backtrace& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Backtrace::SharedCtor() {
+ _cached_size_ = 0;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Backtrace::~Backtrace() {
+ SharedDtor();
+}
+
+void Backtrace::SharedDtor() {
+ if (this != default_instance_) {
+ }
+}
+
+void Backtrace::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Backtrace::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Backtrace_descriptor_;
+}
+
+const Backtrace& Backtrace::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+Backtrace* Backtrace::default_instance_ = NULL;
+
+Backtrace* Backtrace::New() const {
+ return new Backtrace;
+}
+
+void Backtrace::Clear() {
+ frames_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Backtrace::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // repeated .Frame frames = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_frames:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, add_frames()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(10)) goto parse_frames;
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Backtrace::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // repeated .Frame frames = 1;
+ for (int i = 0; i < this->frames_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 1, this->frames(i), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* Backtrace::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // repeated .Frame frames = 1;
+ for (int i = 0; i < this->frames_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 1, this->frames(i), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int Backtrace::ByteSize() const {
+ int total_size = 0;
+
+ // repeated .Frame frames = 1;
+ total_size += 1 * this->frames_size();
+ for (int i = 0; i < this->frames_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->frames(i));
+ }
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Backtrace::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Backtrace* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Backtrace*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Backtrace::MergeFrom(const Backtrace& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ frames_.MergeFrom(from.frames_);
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Backtrace::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Backtrace::CopyFrom(const Backtrace& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Backtrace::IsInitialized() const {
+
+ return true;
+}
+
+void Backtrace::Swap(Backtrace* other) {
+ if (other != this) {
+ frames_.Swap(&other->frames_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Backtrace::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Backtrace_descriptor_;
+ metadata.reflection = Backtrace_reflection_;
+ return metadata;
+}
+
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* Response_ResponseType_descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Response_ResponseType_descriptor_;
+}
+bool Response_ResponseType_IsValid(int value) {
+ switch(value) {
+ case 1:
+ case 2:
+ case 3:
+ case 16:
+ case 17:
+ case 18:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
+const Response_ResponseType Response::SUCCESS_ATOM;
+const Response_ResponseType Response::SUCCESS_SEQUENCE;
+const Response_ResponseType Response::SUCCESS_PARTIAL;
+const Response_ResponseType Response::CLIENT_ERROR;
+const Response_ResponseType Response::COMPILE_ERROR;
+const Response_ResponseType Response::RUNTIME_ERROR;
+const Response_ResponseType Response::ResponseType_MIN;
+const Response_ResponseType Response::ResponseType_MAX;
+const int Response::ResponseType_ARRAYSIZE;
+#endif // _MSC_VER
+#ifndef _MSC_VER
+const int Response::kTypeFieldNumber;
+const int Response::kTokenFieldNumber;
+const int Response::kResponseFieldNumber;
+const int Response::kBacktraceFieldNumber;
+#endif // !_MSC_VER
+
+Response::Response()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void Response::InitAsDefaultInstance() {
+ backtrace_ = const_cast< ::Backtrace*>(&::Backtrace::default_instance());
+}
+
+Response::Response(const Response& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Response::SharedCtor() {
+ _cached_size_ = 0;
+ type_ = 1;
+ token_ = GOOGLE_LONGLONG(0);
+ backtrace_ = NULL;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Response::~Response() {
+ SharedDtor();
+}
+
+void Response::SharedDtor() {
+ if (this != default_instance_) {
+ delete backtrace_;
+ }
+}
+
+void Response::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Response::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Response_descriptor_;
+}
+
+const Response& Response::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+Response* Response::default_instance_ = NULL;
+
+Response* Response::New() const {
+ return new Response;
+}
+
+void Response::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ type_ = 1;
+ token_ = GOOGLE_LONGLONG(0);
+ if (has_backtrace()) {
+ if (backtrace_ != NULL) backtrace_->::Backtrace::Clear();
+ }
+ }
+ response_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Response::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional .Response.ResponseType type = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ int value;
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+ input, &value)));
+ if (::Response_ResponseType_IsValid(value)) {
+ set_type(static_cast< ::Response_ResponseType >(value));
+ } else {
+ mutable_unknown_fields()->AddVarint(1, value);
+ }
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(16)) goto parse_token;
+ break;
+ }
+
+ // optional int64 token = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_token:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+ input, &token_)));
+ set_has_token();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(26)) goto parse_response;
+ break;
+ }
+
+ // repeated .Datum response = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_response:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, add_response()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(26)) goto parse_response;
+ if (input->ExpectTag(34)) goto parse_backtrace;
+ break;
+ }
+
+ // optional .Backtrace backtrace = 4;
+ case 4: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_backtrace:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_backtrace()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Response::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional .Response.ResponseType type = 1;
+ if (has_type()) {
+ ::google::protobuf::internal::WireFormatLite::WriteEnum(
+ 1, this->type(), output);
+ }
+
+ // optional int64 token = 2;
+ if (has_token()) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt64(2, this->token(), output);
+ }
+
+ // repeated .Datum response = 3;
+ for (int i = 0; i < this->response_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 3, this->response(i), output);
+ }
+
+ // optional .Backtrace backtrace = 4;
+ if (has_backtrace()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 4, this->backtrace(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* Response::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // optional .Response.ResponseType type = 1;
+ if (has_type()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+ 1, this->type(), target);
+ }
+
+ // optional int64 token = 2;
+ if (has_token()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(2, this->token(), target);
+ }
+
+ // repeated .Datum response = 3;
+ for (int i = 0; i < this->response_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 3, this->response(i), target);
+ }
+
+ // optional .Backtrace backtrace = 4;
+ if (has_backtrace()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 4, this->backtrace(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int Response::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional .Response.ResponseType type = 1;
+ if (has_type()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
+ }
+
+ // optional int64 token = 2;
+ if (has_token()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int64Size(
+ this->token());
+ }
+
+ // optional .Backtrace backtrace = 4;
+ if (has_backtrace()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->backtrace());
+ }
+
+ }
+ // repeated .Datum response = 3;
+ total_size += 1 * this->response_size();
+ for (int i = 0; i < this->response_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->response(i));
+ }
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Response::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Response* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Response*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Response::MergeFrom(const Response& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ response_.MergeFrom(from.response_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_type()) {
+ set_type(from.type());
+ }
+ if (from.has_token()) {
+ set_token(from.token());
+ }
+ if (from.has_backtrace()) {
+ mutable_backtrace()->::Backtrace::MergeFrom(from.backtrace());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Response::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Response::CopyFrom(const Response& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Response::IsInitialized() const {
+
+ for (int i = 0; i < response_size(); i++) {
+ if (!this->response(i).IsInitialized()) return false;
+ }
+ return true;
+}
+
+void Response::Swap(Response* other) {
+ if (other != this) {
+ std::swap(type_, other->type_);
+ std::swap(token_, other->token_);
+ response_.Swap(&other->response_);
+ std::swap(backtrace_, other->backtrace_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Response::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Response_descriptor_;
+ metadata.reflection = Response_reflection_;
+ return metadata;
+}
+
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* Datum_DatumType_descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Datum_DatumType_descriptor_;
+}
+bool Datum_DatumType_IsValid(int value) {
+ switch(value) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
+const Datum_DatumType Datum::R_NULL;
+const Datum_DatumType Datum::R_BOOL;
+const Datum_DatumType Datum::R_NUM;
+const Datum_DatumType Datum::R_STR;
+const Datum_DatumType Datum::R_ARRAY;
+const Datum_DatumType Datum::R_OBJECT;
+const Datum_DatumType Datum::DatumType_MIN;
+const Datum_DatumType Datum::DatumType_MAX;
+const int Datum::DatumType_ARRAYSIZE;
+#endif // _MSC_VER
+#ifndef _MSC_VER
+const int Datum_AssocPair::kKeyFieldNumber;
+const int Datum_AssocPair::kValFieldNumber;
+#endif // !_MSC_VER
+
+Datum_AssocPair::Datum_AssocPair()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void Datum_AssocPair::InitAsDefaultInstance() {
+ val_ = const_cast< ::Datum*>(&::Datum::default_instance());
+}
+
+Datum_AssocPair::Datum_AssocPair(const Datum_AssocPair& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Datum_AssocPair::SharedCtor() {
+ _cached_size_ = 0;
+ key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ val_ = NULL;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Datum_AssocPair::~Datum_AssocPair() {
+ SharedDtor();
+}
+
+void Datum_AssocPair::SharedDtor() {
+ if (key_ != &::google::protobuf::internal::kEmptyString) {
+ delete key_;
+ }
+ if (this != default_instance_) {
+ delete val_;
+ }
+}
+
+void Datum_AssocPair::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Datum_AssocPair::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Datum_AssocPair_descriptor_;
+}
+
+const Datum_AssocPair& Datum_AssocPair::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+Datum_AssocPair* Datum_AssocPair::default_instance_ = NULL;
+
+Datum_AssocPair* Datum_AssocPair::New() const {
+ return new Datum_AssocPair;
+}
+
+void Datum_AssocPair::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (has_key()) {
+ if (key_ != &::google::protobuf::internal::kEmptyString) {
+ key_->clear();
+ }
+ }
+ if (has_val()) {
+ if (val_ != NULL) val_->::Datum::Clear();
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Datum_AssocPair::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string key = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_key()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->key().data(), this->key().length(),
+ ::google::protobuf::internal::WireFormat::PARSE);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(18)) goto parse_val;
+ break;
+ }
+
+ // optional .Datum val = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_val:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_val()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Datum_AssocPair::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional string key = 1;
+ if (has_key()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->key().data(), this->key().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 1, this->key(), output);
+ }
+
+ // optional .Datum val = 2;
+ if (has_val()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 2, this->val(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* Datum_AssocPair::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // optional string key = 1;
+ if (has_key()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->key().data(), this->key().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 1, this->key(), target);
+ }
+
+ // optional .Datum val = 2;
+ if (has_val()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 2, this->val(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int Datum_AssocPair::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string key = 1;
+ if (has_key()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->key());
+ }
+
+ // optional .Datum val = 2;
+ if (has_val()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->val());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Datum_AssocPair::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Datum_AssocPair* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Datum_AssocPair*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Datum_AssocPair::MergeFrom(const Datum_AssocPair& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_key()) {
+ set_key(from.key());
+ }
+ if (from.has_val()) {
+ mutable_val()->::Datum::MergeFrom(from.val());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Datum_AssocPair::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Datum_AssocPair::CopyFrom(const Datum_AssocPair& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Datum_AssocPair::IsInitialized() const {
+
+ if (has_val()) {
+ if (!this->val().IsInitialized()) return false;
+ }
+ return true;
+}
+
+void Datum_AssocPair::Swap(Datum_AssocPair* other) {
+ if (other != this) {
+ std::swap(key_, other->key_);
+ std::swap(val_, other->val_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Datum_AssocPair::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Datum_AssocPair_descriptor_;
+ metadata.reflection = Datum_AssocPair_reflection_;
+ return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
+const int Datum::kTypeFieldNumber;
+const int Datum::kRBoolFieldNumber;
+const int Datum::kRNumFieldNumber;
+const int Datum::kRStrFieldNumber;
+const int Datum::kRArrayFieldNumber;
+const int Datum::kRObjectFieldNumber;
+#endif // !_MSC_VER
+
+Datum::Datum()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void Datum::InitAsDefaultInstance() {
+}
+
+Datum::Datum(const Datum& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Datum::SharedCtor() {
+ _cached_size_ = 0;
+ type_ = 1;
+ r_bool_ = false;
+ r_num_ = 0;
+ r_str_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Datum::~Datum() {
+ SharedDtor();
+}
+
+void Datum::SharedDtor() {
+ if (r_str_ != &::google::protobuf::internal::kEmptyString) {
+ delete r_str_;
+ }
+ if (this != default_instance_) {
+ }
+}
+
+void Datum::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Datum::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Datum_descriptor_;
+}
+
+const Datum& Datum::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+Datum* Datum::default_instance_ = NULL;
+
+Datum* Datum::New() const {
+ return new Datum;
+}
+
+void Datum::Clear() {
+ _extensions_.Clear();
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ type_ = 1;
+ r_bool_ = false;
+ r_num_ = 0;
+ if (has_r_str()) {
+ if (r_str_ != &::google::protobuf::internal::kEmptyString) {
+ r_str_->clear();
+ }
+ }
+ }
+ r_array_.Clear();
+ r_object_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Datum::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional .Datum.DatumType type = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ int value;
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+ input, &value)));
+ if (::Datum_DatumType_IsValid(value)) {
+ set_type(static_cast< ::Datum_DatumType >(value));
+ } else {
+ mutable_unknown_fields()->AddVarint(1, value);
+ }
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(16)) goto parse_r_bool;
+ break;
+ }
+
+ // optional bool r_bool = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_r_bool:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+ input, &r_bool_)));
+ set_has_r_bool();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(25)) goto parse_r_num;
+ break;
+ }
+
+ // optional double r_num = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED64) {
+ parse_r_num:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+ input, &r_num_)));
+ set_has_r_num();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(34)) goto parse_r_str;
+ break;
+ }
+
+ // optional string r_str = 4;
+ case 4: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_r_str:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_r_str()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->r_str().data(), this->r_str().length(),
+ ::google::protobuf::internal::WireFormat::PARSE);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(42)) goto parse_r_array;
+ break;
+ }
+
+ // repeated .Datum r_array = 5;
+ case 5: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_r_array:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, add_r_array()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(42)) goto parse_r_array;
+ if (input->ExpectTag(50)) goto parse_r_object;
+ break;
+ }
+
+ // repeated .Datum.AssocPair r_object = 6;
+ case 6: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_r_object:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, add_r_object()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(50)) goto parse_r_object;
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ if ((80000u <= tag && tag < 160008u)) {
+ DO_(_extensions_.ParseField(tag, input, default_instance_,
+ mutable_unknown_fields()));
+ continue;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Datum::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional .Datum.DatumType type = 1;
+ if (has_type()) {
+ ::google::protobuf::internal::WireFormatLite::WriteEnum(
+ 1, this->type(), output);
+ }
+
+ // optional bool r_bool = 2;
+ if (has_r_bool()) {
+ ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->r_bool(), output);
+ }
+
+ // optional double r_num = 3;
+ if (has_r_num()) {
+ ::google::protobuf::internal::WireFormatLite::WriteDouble(3, this->r_num(), output);
+ }
+
+ // optional string r_str = 4;
+ if (has_r_str()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->r_str().data(), this->r_str().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 4, this->r_str(), output);
+ }
+
+ // repeated .Datum r_array = 5;
+ for (int i = 0; i < this->r_array_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 5, this->r_array(i), output);
+ }
+
+ // repeated .Datum.AssocPair r_object = 6;
+ for (int i = 0; i < this->r_object_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 6, this->r_object(i), output);
+ }
+
+ // Extension range [10000, 20001)
+ _extensions_.SerializeWithCachedSizes(
+ 10000, 20001, output);
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* Datum::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // optional .Datum.DatumType type = 1;
+ if (has_type()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+ 1, this->type(), target);
+ }
+
+ // optional bool r_bool = 2;
+ if (has_r_bool()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->r_bool(), target);
+ }
+
+ // optional double r_num = 3;
+ if (has_r_num()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteDoubleToArray(3, this->r_num(), target);
+ }
+
+ // optional string r_str = 4;
+ if (has_r_str()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->r_str().data(), this->r_str().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 4, this->r_str(), target);
+ }
+
+ // repeated .Datum r_array = 5;
+ for (int i = 0; i < this->r_array_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 5, this->r_array(i), target);
+ }
+
+ // repeated .Datum.AssocPair r_object = 6;
+ for (int i = 0; i < this->r_object_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 6, this->r_object(i), target);
+ }
+
+ // Extension range [10000, 20001)
+ target = _extensions_.SerializeWithCachedSizesToArray(
+ 10000, 20001, target);
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int Datum::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional .Datum.DatumType type = 1;
+ if (has_type()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
+ }
+
+ // optional bool r_bool = 2;
+ if (has_r_bool()) {
+ total_size += 1 + 1;
+ }
+
+ // optional double r_num = 3;
+ if (has_r_num()) {
+ total_size += 1 + 8;
+ }
+
+ // optional string r_str = 4;
+ if (has_r_str()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->r_str());
+ }
+
+ }
+ // repeated .Datum r_array = 5;
+ total_size += 1 * this->r_array_size();
+ for (int i = 0; i < this->r_array_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->r_array(i));
+ }
+
+ // repeated .Datum.AssocPair r_object = 6;
+ total_size += 1 * this->r_object_size();
+ for (int i = 0; i < this->r_object_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->r_object(i));
+ }
+
+ total_size += _extensions_.ByteSize();
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Datum::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Datum* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Datum*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Datum::MergeFrom(const Datum& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ r_array_.MergeFrom(from.r_array_);
+ r_object_.MergeFrom(from.r_object_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_type()) {
+ set_type(from.type());
+ }
+ if (from.has_r_bool()) {
+ set_r_bool(from.r_bool());
+ }
+ if (from.has_r_num()) {
+ set_r_num(from.r_num());
+ }
+ if (from.has_r_str()) {
+ set_r_str(from.r_str());
+ }
+ }
+ _extensions_.MergeFrom(from._extensions_);
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Datum::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Datum::CopyFrom(const Datum& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Datum::IsInitialized() const {
+
+ for (int i = 0; i < r_array_size(); i++) {
+ if (!this->r_array(i).IsInitialized()) return false;
+ }
+ for (int i = 0; i < r_object_size(); i++) {
+ if (!this->r_object(i).IsInitialized()) return false;
+ }
+
+ if (!_extensions_.IsInitialized()) return false; return true;
+}
+
+void Datum::Swap(Datum* other) {
+ if (other != this) {
+ std::swap(type_, other->type_);
+ std::swap(r_bool_, other->r_bool_);
+ std::swap(r_num_, other->r_num_);
+ std::swap(r_str_, other->r_str_);
+ r_array_.Swap(&other->r_array_);
+ r_object_.Swap(&other->r_object_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ _extensions_.Swap(&other->_extensions_);
+ }
+}
+
+::google::protobuf::Metadata Datum::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Datum_descriptor_;
+ metadata.reflection = Datum_reflection_;
+ return metadata;
+}
+
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* Term_TermType_descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Term_TermType_descriptor_;
+}
+bool Term_TermType_IsValid(int value) {
+ switch(value) {
+ case 1:
+ case 2:
+ case 3:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 58:
+ case 59:
+ case 60:
+ case 61:
+ case 62:
+ case 64:
+ case 65:
+ case 66:
+ case 67:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 72:
+ case 73:
+ case 74:
+ case 75:
+ case 76:
+ case 77:
+ case 78:
+ case 79:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ case 85:
+ case 86:
+ case 87:
+ case 88:
+ case 89:
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#ifndef _MSC_VER
+const Term_TermType Term::DATUM;
+const Term_TermType Term::MAKE_ARRAY;
+const Term_TermType Term::MAKE_OBJ;
+const Term_TermType Term::VAR;
+const Term_TermType Term::JAVASCRIPT;
+const Term_TermType Term::ERROR;
+const Term_TermType Term::IMPLICIT_VAR;
+const Term_TermType Term::DB;
+const Term_TermType Term::TABLE;
+const Term_TermType Term::GET;
+const Term_TermType Term::GET_ALL;
+const Term_TermType Term::EQ;
+const Term_TermType Term::NE;
+const Term_TermType Term::LT;
+const Term_TermType Term::LE;
+const Term_TermType Term::GT;
+const Term_TermType Term::GE;
+const Term_TermType Term::NOT;
+const Term_TermType Term::ADD;
+const Term_TermType Term::SUB;
+const Term_TermType Term::MUL;
+const Term_TermType Term::DIV;
+const Term_TermType Term::MOD;
+const Term_TermType Term::APPEND;
+const Term_TermType Term::PREPEND;
+const Term_TermType Term::DIFFERENCE;
+const Term_TermType Term::SET_INSERT;
+const Term_TermType Term::SET_INTERSECTION;
+const Term_TermType Term::SET_UNION;
+const Term_TermType Term::SET_DIFFERENCE;
+const Term_TermType Term::SLICE;
+const Term_TermType Term::SKIP;
+const Term_TermType Term::LIMIT;
+const Term_TermType Term::INDEXES_OF;
+const Term_TermType Term::CONTAINS;
+const Term_TermType Term::GETATTR;
+const Term_TermType Term::KEYS;
+const Term_TermType Term::HAS_FIELDS;
+const Term_TermType Term::WITH_FIELDS;
+const Term_TermType Term::PLUCK;
+const Term_TermType Term::WITHOUT;
+const Term_TermType Term::MERGE;
+const Term_TermType Term::BETWEEN;
+const Term_TermType Term::REDUCE;
+const Term_TermType Term::MAP;
+const Term_TermType Term::FILTER;
+const Term_TermType Term::CONCATMAP;
+const Term_TermType Term::ORDERBY;
+const Term_TermType Term::DISTINCT;
+const Term_TermType Term::COUNT;
+const Term_TermType Term::IS_EMPTY;
+const Term_TermType Term::UNION;
+const Term_TermType Term::NTH;
+const Term_TermType Term::GROUPED_MAP_REDUCE;
+const Term_TermType Term::GROUPBY;
+const Term_TermType Term::INNER_JOIN;
+const Term_TermType Term::OUTER_JOIN;
+const Term_TermType Term::EQ_JOIN;
+const Term_TermType Term::ZIP;
+const Term_TermType Term::INSERT_AT;
+const Term_TermType Term::DELETE_AT;
+const Term_TermType Term::CHANGE_AT;
+const Term_TermType Term::SPLICE_AT;
+const Term_TermType Term::COERCE_TO;
+const Term_TermType Term::TYPEOF;
+const Term_TermType Term::UPDATE;
+const Term_TermType Term::DELETE;
+const Term_TermType Term::REPLACE;
+const Term_TermType Term::INSERT;
+const Term_TermType Term::DB_CREATE;
+const Term_TermType Term::DB_DROP;
+const Term_TermType Term::DB_LIST;
+const Term_TermType Term::TABLE_CREATE;
+const Term_TermType Term::TABLE_DROP;
+const Term_TermType Term::TABLE_LIST;
+const Term_TermType Term::INDEX_CREATE;
+const Term_TermType Term::INDEX_DROP;
+const Term_TermType Term::INDEX_LIST;
+const Term_TermType Term::FUNCALL;
+const Term_TermType Term::BRANCH;
+const Term_TermType Term::ANY;
+const Term_TermType Term::ALL;
+const Term_TermType Term::FOREACH;
+const Term_TermType Term::FUNC;
+const Term_TermType Term::ASC;
+const Term_TermType Term::DESC;
+const Term_TermType Term::INFO;
+const Term_TermType Term::MATCH;
+const Term_TermType Term::SAMPLE;
+const Term_TermType Term::DEFAULT;
+const Term_TermType Term::TermType_MIN;
+const Term_TermType Term::TermType_MAX;
+const int Term::TermType_ARRAYSIZE;
+#endif // _MSC_VER
+#ifndef _MSC_VER
+const int Term_AssocPair::kKeyFieldNumber;
+const int Term_AssocPair::kValFieldNumber;
+#endif // !_MSC_VER
+
+Term_AssocPair::Term_AssocPair()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void Term_AssocPair::InitAsDefaultInstance() {
+ val_ = const_cast< ::Term*>(&::Term::default_instance());
+}
+
+Term_AssocPair::Term_AssocPair(const Term_AssocPair& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Term_AssocPair::SharedCtor() {
+ _cached_size_ = 0;
+ key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ val_ = NULL;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Term_AssocPair::~Term_AssocPair() {
+ SharedDtor();
+}
+
+void Term_AssocPair::SharedDtor() {
+ if (key_ != &::google::protobuf::internal::kEmptyString) {
+ delete key_;
+ }
+ if (this != default_instance_) {
+ delete val_;
+ }
+}
+
+void Term_AssocPair::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Term_AssocPair::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Term_AssocPair_descriptor_;
+}
+
+const Term_AssocPair& Term_AssocPair::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+Term_AssocPair* Term_AssocPair::default_instance_ = NULL;
+
+Term_AssocPair* Term_AssocPair::New() const {
+ return new Term_AssocPair;
+}
+
+void Term_AssocPair::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (has_key()) {
+ if (key_ != &::google::protobuf::internal::kEmptyString) {
+ key_->clear();
+ }
+ }
+ if (has_val()) {
+ if (val_ != NULL) val_->::Term::Clear();
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Term_AssocPair::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string key = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_key()));
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->key().data(), this->key().length(),
+ ::google::protobuf::internal::WireFormat::PARSE);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(18)) goto parse_val;
+ break;
+ }
+
+ // optional .Term val = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_val:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_val()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Term_AssocPair::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional string key = 1;
+ if (has_key()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->key().data(), this->key().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 1, this->key(), output);
+ }
+
+ // optional .Term val = 2;
+ if (has_val()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 2, this->val(), output);
+ }
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* Term_AssocPair::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // optional string key = 1;
+ if (has_key()) {
+ ::google::protobuf::internal::WireFormat::VerifyUTF8String(
+ this->key().data(), this->key().length(),
+ ::google::protobuf::internal::WireFormat::SERIALIZE);
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 1, this->key(), target);
+ }
+
+ // optional .Term val = 2;
+ if (has_val()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 2, this->val(), target);
+ }
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int Term_AssocPair::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string key = 1;
+ if (has_key()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->key());
+ }
+
+ // optional .Term val = 2;
+ if (has_val()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->val());
+ }
+
+ }
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Term_AssocPair::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Term_AssocPair* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Term_AssocPair*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Term_AssocPair::MergeFrom(const Term_AssocPair& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_key()) {
+ set_key(from.key());
+ }
+ if (from.has_val()) {
+ mutable_val()->::Term::MergeFrom(from.val());
+ }
+ }
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Term_AssocPair::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Term_AssocPair::CopyFrom(const Term_AssocPair& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Term_AssocPair::IsInitialized() const {
+
+ if (has_val()) {
+ if (!this->val().IsInitialized()) return false;
+ }
+ return true;
+}
+
+void Term_AssocPair::Swap(Term_AssocPair* other) {
+ if (other != this) {
+ std::swap(key_, other->key_);
+ std::swap(val_, other->val_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::google::protobuf::Metadata Term_AssocPair::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Term_AssocPair_descriptor_;
+ metadata.reflection = Term_AssocPair_reflection_;
+ return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
+const int Term::kTypeFieldNumber;
+const int Term::kDatumFieldNumber;
+const int Term::kArgsFieldNumber;
+const int Term::kOptargsFieldNumber;
+#endif // !_MSC_VER
+
+Term::Term()
+ : ::google::protobuf::Message() {
+ SharedCtor();
+}
+
+void Term::InitAsDefaultInstance() {
+ datum_ = const_cast< ::Datum*>(&::Datum::default_instance());
+}
+
+Term::Term(const Term& from)
+ : ::google::protobuf::Message() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Term::SharedCtor() {
+ _cached_size_ = 0;
+ type_ = 1;
+ datum_ = NULL;
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Term::~Term() {
+ SharedDtor();
+}
+
+void Term::SharedDtor() {
+ if (this != default_instance_) {
+ delete datum_;
+ }
+}
+
+void Term::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Term::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return Term_descriptor_;
+}
+
+const Term& Term::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_ql2_2eproto(); return *default_instance_;
+}
+
+Term* Term::default_instance_ = NULL;
+
+Term* Term::New() const {
+ return new Term;
+}
+
+void Term::Clear() {
+ _extensions_.Clear();
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ type_ = 1;
+ if (has_datum()) {
+ if (datum_ != NULL) datum_->::Datum::Clear();
+ }
+ }
+ args_.Clear();
+ optargs_.Clear();
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+ mutable_unknown_fields()->Clear();
+}
+
+bool Term::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional .Term.TermType type = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ int value;
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+ input, &value)));
+ if (::Term_TermType_IsValid(value)) {
+ set_type(static_cast< ::Term_TermType >(value));
+ } else {
+ mutable_unknown_fields()->AddVarint(1, value);
+ }
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(18)) goto parse_datum;
+ break;
+ }
+
+ // optional .Datum datum = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_datum:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_datum()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(26)) goto parse_args;
+ break;
+ }
+
+ // repeated .Term args = 3;
+ case 3: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_args:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, add_args()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(26)) goto parse_args;
+ if (input->ExpectTag(34)) goto parse_optargs;
+ break;
+ }
+
+ // repeated .Term.AssocPair optargs = 4;
+ case 4: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_optargs:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, add_optargs()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(34)) goto parse_optargs;
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ if ((80000u <= tag && tag < 160008u)) {
+ DO_(_extensions_.ParseField(tag, input, default_instance_,
+ mutable_unknown_fields()));
+ continue;
+ }
+ DO_(::google::protobuf::internal::WireFormat::SkipField(
+ input, tag, mutable_unknown_fields()));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Term::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional .Term.TermType type = 1;
+ if (has_type()) {
+ ::google::protobuf::internal::WireFormatLite::WriteEnum(
+ 1, this->type(), output);
+ }
+
+ // optional .Datum datum = 2;
+ if (has_datum()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 2, this->datum(), output);
+ }
+
+ // repeated .Term args = 3;
+ for (int i = 0; i < this->args_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 3, this->args(i), output);
+ }
+
+ // repeated .Term.AssocPair optargs = 4;
+ for (int i = 0; i < this->optargs_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 4, this->optargs(i), output);
+ }
+
+ // Extension range [10000, 20001)
+ _extensions_.SerializeWithCachedSizes(
+ 10000, 20001, output);
+
+ if (!unknown_fields().empty()) {
+ ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+ unknown_fields(), output);
+ }
+}
+
+::google::protobuf::uint8* Term::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // optional .Term.TermType type = 1;
+ if (has_type()) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+ 1, this->type(), target);
+ }
+
+ // optional .Datum datum = 2;
+ if (has_datum()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 2, this->datum(), target);
+ }
+
+ // repeated .Term args = 3;
+ for (int i = 0; i < this->args_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 3, this->args(i), target);
+ }
+
+ // repeated .Term.AssocPair optargs = 4;
+ for (int i = 0; i < this->optargs_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 4, this->optargs(i), target);
+ }
+
+ // Extension range [10000, 20001)
+ target = _extensions_.SerializeWithCachedSizesToArray(
+ 10000, 20001, target);
+
+ if (!unknown_fields().empty()) {
+ target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+ unknown_fields(), target);
+ }
+ return target;
+}
+
+int Term::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional .Term.TermType type = 1;
+ if (has_type()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
+ }
+
+ // optional .Datum datum = 2;
+ if (has_datum()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->datum());
+ }
+
+ }
+ // repeated .Term args = 3;
+ total_size += 1 * this->args_size();
+ for (int i = 0; i < this->args_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->args(i));
+ }
+
+ // repeated .Term.AssocPair optargs = 4;
+ total_size += 1 * this->optargs_size();
+ for (int i = 0; i < this->optargs_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->optargs(i));
+ }
+
+ total_size += _extensions_.ByteSize();
+
+ if (!unknown_fields().empty()) {
+ total_size +=
+ ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+ unknown_fields());
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Term::MergeFrom(const ::google::protobuf::Message& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ const Term* source =
+ ::google::protobuf::internal::dynamic_cast_if_available<const Term*>(
+ &from);
+ if (source == NULL) {
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ MergeFrom(*source);
+ }
+}
+
+void Term::MergeFrom(const Term& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ args_.MergeFrom(from.args_);
+ optargs_.MergeFrom(from.optargs_);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_type()) {
+ set_type(from.type());
+ }
+ if (from.has_datum()) {
+ mutable_datum()->::Datum::MergeFrom(from.datum());
+ }
+ }
+ _extensions_.MergeFrom(from._extensions_);
+ mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+}
+
+void Term::CopyFrom(const ::google::protobuf::Message& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void Term::CopyFrom(const Term& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Term::IsInitialized() const {
+
+ if (has_datum()) {
+ if (!this->datum().IsInitialized()) return false;
+ }
+ for (int i = 0; i < args_size(); i++) {
+ if (!this->args(i).IsInitialized()) return false;
+ }
+ for (int i = 0; i < optargs_size(); i++) {
+ if (!this->optargs(i).IsInitialized()) return false;
+ }
+
+ if (!_extensions_.IsInitialized()) return false; return true;
+}
+
+void Term::Swap(Term* other) {
+ if (other != this) {
+ std::swap(type_, other->type_);
+ std::swap(datum_, other->datum_);
+ args_.Swap(&other->args_);
+ optargs_.Swap(&other->optargs_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ _unknown_fields_.Swap(&other->_unknown_fields_);
+ std::swap(_cached_size_, other->_cached_size_);
+ _extensions_.Swap(&other->_extensions_);
+ }
+}
+
+::google::protobuf::Metadata Term::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = Term_descriptor_;
+ metadata.reflection = Term_reflection_;
+ return metadata;
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+// @@protoc_insertion_point(global_scope)
diff --git a/external/glim/ql2.pb.h b/external/glim/ql2.pb.h
new file mode 100644
index 000000000..c8ac57a14
--- /dev/null
+++ b/external/glim/ql2.pb.h
@@ -0,0 +1,2532 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: ql2.proto
+
+#ifndef PROTOBUF_ql2_2eproto__INCLUDED
+#define PROTOBUF_ql2_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 2004000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 2004001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_message_reflection.h>
+// @@protoc_insertion_point(includes)
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_ql2_2eproto();
+void protobuf_AssignDesc_ql2_2eproto();
+void protobuf_ShutdownFile_ql2_2eproto();
+
+class VersionDummy;
+class Query;
+class Query_AssocPair;
+class Frame;
+class Backtrace;
+class Response;
+class Datum;
+class Datum_AssocPair;
+class Term;
+class Term_AssocPair;
+
+enum VersionDummy_Version {
+ VersionDummy_Version_V0_1 = 1063369270,
+ VersionDummy_Version_V0_2 = 1915781601
+};
+bool VersionDummy_Version_IsValid(int value);
+const VersionDummy_Version VersionDummy_Version_Version_MIN = VersionDummy_Version_V0_1;
+const VersionDummy_Version VersionDummy_Version_Version_MAX = VersionDummy_Version_V0_2;
+const int VersionDummy_Version_Version_ARRAYSIZE = VersionDummy_Version_Version_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* VersionDummy_Version_descriptor();
+inline const ::std::string& VersionDummy_Version_Name(VersionDummy_Version value) {
+ return ::google::protobuf::internal::NameOfEnum(
+ VersionDummy_Version_descriptor(), value);
+}
+inline bool VersionDummy_Version_Parse(
+ const ::std::string& name, VersionDummy_Version* value) {
+ return ::google::protobuf::internal::ParseNamedEnum<VersionDummy_Version>(
+ VersionDummy_Version_descriptor(), name, value);
+}
+enum Query_QueryType {
+ Query_QueryType_START = 1,
+ Query_QueryType_CONTINUE = 2,
+ Query_QueryType_STOP = 3
+};
+bool Query_QueryType_IsValid(int value);
+const Query_QueryType Query_QueryType_QueryType_MIN = Query_QueryType_START;
+const Query_QueryType Query_QueryType_QueryType_MAX = Query_QueryType_STOP;
+const int Query_QueryType_QueryType_ARRAYSIZE = Query_QueryType_QueryType_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* Query_QueryType_descriptor();
+inline const ::std::string& Query_QueryType_Name(Query_QueryType value) {
+ return ::google::protobuf::internal::NameOfEnum(
+ Query_QueryType_descriptor(), value);
+}
+inline bool Query_QueryType_Parse(
+ const ::std::string& name, Query_QueryType* value) {
+ return ::google::protobuf::internal::ParseNamedEnum<Query_QueryType>(
+ Query_QueryType_descriptor(), name, value);
+}
+enum Frame_FrameType {
+ Frame_FrameType_POS = 1,
+ Frame_FrameType_OPT = 2
+};
+bool Frame_FrameType_IsValid(int value);
+const Frame_FrameType Frame_FrameType_FrameType_MIN = Frame_FrameType_POS;
+const Frame_FrameType Frame_FrameType_FrameType_MAX = Frame_FrameType_OPT;
+const int Frame_FrameType_FrameType_ARRAYSIZE = Frame_FrameType_FrameType_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* Frame_FrameType_descriptor();
+inline const ::std::string& Frame_FrameType_Name(Frame_FrameType value) {
+ return ::google::protobuf::internal::NameOfEnum(
+ Frame_FrameType_descriptor(), value);
+}
+inline bool Frame_FrameType_Parse(
+ const ::std::string& name, Frame_FrameType* value) {
+ return ::google::protobuf::internal::ParseNamedEnum<Frame_FrameType>(
+ Frame_FrameType_descriptor(), name, value);
+}
+enum Response_ResponseType {
+ Response_ResponseType_SUCCESS_ATOM = 1,
+ Response_ResponseType_SUCCESS_SEQUENCE = 2,
+ Response_ResponseType_SUCCESS_PARTIAL = 3,
+ Response_ResponseType_CLIENT_ERROR = 16,
+ Response_ResponseType_COMPILE_ERROR = 17,
+ Response_ResponseType_RUNTIME_ERROR = 18
+};
+bool Response_ResponseType_IsValid(int value);
+const Response_ResponseType Response_ResponseType_ResponseType_MIN = Response_ResponseType_SUCCESS_ATOM;
+const Response_ResponseType Response_ResponseType_ResponseType_MAX = Response_ResponseType_RUNTIME_ERROR;
+const int Response_ResponseType_ResponseType_ARRAYSIZE = Response_ResponseType_ResponseType_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* Response_ResponseType_descriptor();
+inline const ::std::string& Response_ResponseType_Name(Response_ResponseType value) {
+ return ::google::protobuf::internal::NameOfEnum(
+ Response_ResponseType_descriptor(), value);
+}
+inline bool Response_ResponseType_Parse(
+ const ::std::string& name, Response_ResponseType* value) {
+ return ::google::protobuf::internal::ParseNamedEnum<Response_ResponseType>(
+ Response_ResponseType_descriptor(), name, value);
+}
+enum Datum_DatumType {
+ Datum_DatumType_R_NULL = 1,
+ Datum_DatumType_R_BOOL = 2,
+ Datum_DatumType_R_NUM = 3,
+ Datum_DatumType_R_STR = 4,
+ Datum_DatumType_R_ARRAY = 5,
+ Datum_DatumType_R_OBJECT = 6
+};
+bool Datum_DatumType_IsValid(int value);
+const Datum_DatumType Datum_DatumType_DatumType_MIN = Datum_DatumType_R_NULL;
+const Datum_DatumType Datum_DatumType_DatumType_MAX = Datum_DatumType_R_OBJECT;
+const int Datum_DatumType_DatumType_ARRAYSIZE = Datum_DatumType_DatumType_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* Datum_DatumType_descriptor();
+inline const ::std::string& Datum_DatumType_Name(Datum_DatumType value) {
+ return ::google::protobuf::internal::NameOfEnum(
+ Datum_DatumType_descriptor(), value);
+}
+inline bool Datum_DatumType_Parse(
+ const ::std::string& name, Datum_DatumType* value) {
+ return ::google::protobuf::internal::ParseNamedEnum<Datum_DatumType>(
+ Datum_DatumType_descriptor(), name, value);
+}
+enum Term_TermType {
+ Term_TermType_DATUM = 1,
+ Term_TermType_MAKE_ARRAY = 2,
+ Term_TermType_MAKE_OBJ = 3,
+ Term_TermType_VAR = 10,
+ Term_TermType_JAVASCRIPT = 11,
+ Term_TermType_ERROR = 12,
+ Term_TermType_IMPLICIT_VAR = 13,
+ Term_TermType_DB = 14,
+ Term_TermType_TABLE = 15,
+ Term_TermType_GET = 16,
+ Term_TermType_GET_ALL = 78,
+ Term_TermType_EQ = 17,
+ Term_TermType_NE = 18,
+ Term_TermType_LT = 19,
+ Term_TermType_LE = 20,
+ Term_TermType_GT = 21,
+ Term_TermType_GE = 22,
+ Term_TermType_NOT = 23,
+ Term_TermType_ADD = 24,
+ Term_TermType_SUB = 25,
+ Term_TermType_MUL = 26,
+ Term_TermType_DIV = 27,
+ Term_TermType_MOD = 28,
+ Term_TermType_APPEND = 29,
+ Term_TermType_PREPEND = 80,
+ Term_TermType_DIFFERENCE = 95,
+ Term_TermType_SET_INSERT = 88,
+ Term_TermType_SET_INTERSECTION = 89,
+ Term_TermType_SET_UNION = 90,
+ Term_TermType_SET_DIFFERENCE = 91,
+ Term_TermType_SLICE = 30,
+ Term_TermType_SKIP = 70,
+ Term_TermType_LIMIT = 71,
+ Term_TermType_INDEXES_OF = 87,
+ Term_TermType_CONTAINS = 93,
+ Term_TermType_GETATTR = 31,
+ Term_TermType_KEYS = 94,
+ Term_TermType_HAS_FIELDS = 32,
+ Term_TermType_WITH_FIELDS = 96,
+ Term_TermType_PLUCK = 33,
+ Term_TermType_WITHOUT = 34,
+ Term_TermType_MERGE = 35,
+ Term_TermType_BETWEEN = 36,
+ Term_TermType_REDUCE = 37,
+ Term_TermType_MAP = 38,
+ Term_TermType_FILTER = 39,
+ Term_TermType_CONCATMAP = 40,
+ Term_TermType_ORDERBY = 41,
+ Term_TermType_DISTINCT = 42,
+ Term_TermType_COUNT = 43,
+ Term_TermType_IS_EMPTY = 86,
+ Term_TermType_UNION = 44,
+ Term_TermType_NTH = 45,
+ Term_TermType_GROUPED_MAP_REDUCE = 46,
+ Term_TermType_GROUPBY = 47,
+ Term_TermType_INNER_JOIN = 48,
+ Term_TermType_OUTER_JOIN = 49,
+ Term_TermType_EQ_JOIN = 50,
+ Term_TermType_ZIP = 72,
+ Term_TermType_INSERT_AT = 82,
+ Term_TermType_DELETE_AT = 83,
+ Term_TermType_CHANGE_AT = 84,
+ Term_TermType_SPLICE_AT = 85,
+ Term_TermType_COERCE_TO = 51,
+ Term_TermType_TYPEOF = 52,
+ Term_TermType_UPDATE = 53,
+ Term_TermType_DELETE = 54,
+ Term_TermType_REPLACE = 55,
+ Term_TermType_INSERT = 56,
+ Term_TermType_DB_CREATE = 57,
+ Term_TermType_DB_DROP = 58,
+ Term_TermType_DB_LIST = 59,
+ Term_TermType_TABLE_CREATE = 60,
+ Term_TermType_TABLE_DROP = 61,
+ Term_TermType_TABLE_LIST = 62,
+ Term_TermType_INDEX_CREATE = 75,
+ Term_TermType_INDEX_DROP = 76,
+ Term_TermType_INDEX_LIST = 77,
+ Term_TermType_FUNCALL = 64,
+ Term_TermType_BRANCH = 65,
+ Term_TermType_ANY = 66,
+ Term_TermType_ALL = 67,
+ Term_TermType_FOREACH = 68,
+ Term_TermType_FUNC = 69,
+ Term_TermType_ASC = 73,
+ Term_TermType_DESC = 74,
+ Term_TermType_INFO = 79,
+ Term_TermType_MATCH = 97,
+ Term_TermType_SAMPLE = 81,
+ Term_TermType_DEFAULT = 92
+};
+bool Term_TermType_IsValid(int value);
+const Term_TermType Term_TermType_TermType_MIN = Term_TermType_DATUM;
+const Term_TermType Term_TermType_TermType_MAX = Term_TermType_MATCH;
+const int Term_TermType_TermType_ARRAYSIZE = Term_TermType_TermType_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* Term_TermType_descriptor();
+inline const ::std::string& Term_TermType_Name(Term_TermType value) {
+ return ::google::protobuf::internal::NameOfEnum(
+ Term_TermType_descriptor(), value);
+}
+inline bool Term_TermType_Parse(
+ const ::std::string& name, Term_TermType* value) {
+ return ::google::protobuf::internal::ParseNamedEnum<Term_TermType>(
+ Term_TermType_descriptor(), name, value);
+}
+// ===================================================================
+
+class VersionDummy : public ::google::protobuf::Message {
+ public:
+ VersionDummy();
+ virtual ~VersionDummy();
+
+ VersionDummy(const VersionDummy& from);
+
+ inline VersionDummy& operator=(const VersionDummy& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const VersionDummy& default_instance();
+
+ void Swap(VersionDummy* other);
+
+ // implements Message ----------------------------------------------
+
+ VersionDummy* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const VersionDummy& from);
+ void MergeFrom(const VersionDummy& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ typedef VersionDummy_Version Version;
+ static const Version V0_1 = VersionDummy_Version_V0_1;
+ static const Version V0_2 = VersionDummy_Version_V0_2;
+ static inline bool Version_IsValid(int value) {
+ return VersionDummy_Version_IsValid(value);
+ }
+ static const Version Version_MIN =
+ VersionDummy_Version_Version_MIN;
+ static const Version Version_MAX =
+ VersionDummy_Version_Version_MAX;
+ static const int Version_ARRAYSIZE =
+ VersionDummy_Version_Version_ARRAYSIZE;
+ static inline const ::google::protobuf::EnumDescriptor*
+ Version_descriptor() {
+ return VersionDummy_Version_descriptor();
+ }
+ static inline const ::std::string& Version_Name(Version value) {
+ return VersionDummy_Version_Name(value);
+ }
+ static inline bool Version_Parse(const ::std::string& name,
+ Version* value) {
+ return VersionDummy_Version_Parse(name, value);
+ }
+
+ // accessors -------------------------------------------------------
+
+ // @@protoc_insertion_point(class_scope:VersionDummy)
+ private:
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[1];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static VersionDummy* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Query_AssocPair : public ::google::protobuf::Message {
+ public:
+ Query_AssocPair();
+ virtual ~Query_AssocPair();
+
+ Query_AssocPair(const Query_AssocPair& from);
+
+ inline Query_AssocPair& operator=(const Query_AssocPair& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Query_AssocPair& default_instance();
+
+ void Swap(Query_AssocPair* other);
+
+ // implements Message ----------------------------------------------
+
+ Query_AssocPair* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Query_AssocPair& from);
+ void MergeFrom(const Query_AssocPair& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string key = 1;
+ inline bool has_key() const;
+ inline void clear_key();
+ static const int kKeyFieldNumber = 1;
+ inline const ::std::string& key() const;
+ inline void set_key(const ::std::string& value);
+ inline void set_key(const char* value);
+ inline void set_key(const char* value, size_t size);
+ inline ::std::string* mutable_key();
+ inline ::std::string* release_key();
+
+ // optional .Term val = 2;
+ inline bool has_val() const;
+ inline void clear_val();
+ static const int kValFieldNumber = 2;
+ inline const ::Term& val() const;
+ inline ::Term* mutable_val();
+ inline ::Term* release_val();
+
+ // @@protoc_insertion_point(class_scope:Query.AssocPair)
+ private:
+ inline void set_has_key();
+ inline void clear_has_key();
+ inline void set_has_val();
+ inline void clear_has_val();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::std::string* key_;
+ ::Term* val_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static Query_AssocPair* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Query : public ::google::protobuf::Message {
+ public:
+ Query();
+ virtual ~Query();
+
+ Query(const Query& from);
+
+ inline Query& operator=(const Query& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Query& default_instance();
+
+ void Swap(Query* other);
+
+ // implements Message ----------------------------------------------
+
+ Query* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Query& from);
+ void MergeFrom(const Query& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ typedef Query_AssocPair AssocPair;
+
+ typedef Query_QueryType QueryType;
+ static const QueryType START = Query_QueryType_START;
+ static const QueryType CONTINUE = Query_QueryType_CONTINUE;
+ static const QueryType STOP = Query_QueryType_STOP;
+ static inline bool QueryType_IsValid(int value) {
+ return Query_QueryType_IsValid(value);
+ }
+ static const QueryType QueryType_MIN =
+ Query_QueryType_QueryType_MIN;
+ static const QueryType QueryType_MAX =
+ Query_QueryType_QueryType_MAX;
+ static const int QueryType_ARRAYSIZE =
+ Query_QueryType_QueryType_ARRAYSIZE;
+ static inline const ::google::protobuf::EnumDescriptor*
+ QueryType_descriptor() {
+ return Query_QueryType_descriptor();
+ }
+ static inline const ::std::string& QueryType_Name(QueryType value) {
+ return Query_QueryType_Name(value);
+ }
+ static inline bool QueryType_Parse(const ::std::string& name,
+ QueryType* value) {
+ return Query_QueryType_Parse(name, value);
+ }
+
+ // accessors -------------------------------------------------------
+
+ // optional .Query.QueryType type = 1;
+ inline bool has_type() const;
+ inline void clear_type();
+ static const int kTypeFieldNumber = 1;
+ inline ::Query_QueryType type() const;
+ inline void set_type(::Query_QueryType value);
+
+ // optional .Term query = 2;
+ inline bool has_query() const;
+ inline void clear_query();
+ static const int kQueryFieldNumber = 2;
+ inline const ::Term& query() const;
+ inline ::Term* mutable_query();
+ inline ::Term* release_query();
+
+ // optional int64 token = 3;
+ inline bool has_token() const;
+ inline void clear_token();
+ static const int kTokenFieldNumber = 3;
+ inline ::google::protobuf::int64 token() const;
+ inline void set_token(::google::protobuf::int64 value);
+
+ // optional bool OBSOLETE_noreply = 4 [default = false];
+ inline bool has_obsolete_noreply() const;
+ inline void clear_obsolete_noreply();
+ static const int kOBSOLETENoreplyFieldNumber = 4;
+ inline bool obsolete_noreply() const;
+ inline void set_obsolete_noreply(bool value);
+
+ // repeated .Query.AssocPair global_optargs = 6;
+ inline int global_optargs_size() const;
+ inline void clear_global_optargs();
+ static const int kGlobalOptargsFieldNumber = 6;
+ inline const ::Query_AssocPair& global_optargs(int index) const;
+ inline ::Query_AssocPair* mutable_global_optargs(int index);
+ inline ::Query_AssocPair* add_global_optargs();
+ inline const ::google::protobuf::RepeatedPtrField< ::Query_AssocPair >&
+ global_optargs() const;
+ inline ::google::protobuf::RepeatedPtrField< ::Query_AssocPair >*
+ mutable_global_optargs();
+
+ // @@protoc_insertion_point(class_scope:Query)
+ private:
+ inline void set_has_type();
+ inline void clear_has_type();
+ inline void set_has_query();
+ inline void clear_has_query();
+ inline void set_has_token();
+ inline void clear_has_token();
+ inline void set_has_obsolete_noreply();
+ inline void clear_has_obsolete_noreply();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::Term* query_;
+ int type_;
+ bool obsolete_noreply_;
+ ::google::protobuf::int64 token_;
+ ::google::protobuf::RepeatedPtrField< ::Query_AssocPair > global_optargs_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static Query* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Frame : public ::google::protobuf::Message {
+ public:
+ Frame();
+ virtual ~Frame();
+
+ Frame(const Frame& from);
+
+ inline Frame& operator=(const Frame& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Frame& default_instance();
+
+ void Swap(Frame* other);
+
+ // implements Message ----------------------------------------------
+
+ Frame* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Frame& from);
+ void MergeFrom(const Frame& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ typedef Frame_FrameType FrameType;
+ static const FrameType POS = Frame_FrameType_POS;
+ static const FrameType OPT = Frame_FrameType_OPT;
+ static inline bool FrameType_IsValid(int value) {
+ return Frame_FrameType_IsValid(value);
+ }
+ static const FrameType FrameType_MIN =
+ Frame_FrameType_FrameType_MIN;
+ static const FrameType FrameType_MAX =
+ Frame_FrameType_FrameType_MAX;
+ static const int FrameType_ARRAYSIZE =
+ Frame_FrameType_FrameType_ARRAYSIZE;
+ static inline const ::google::protobuf::EnumDescriptor*
+ FrameType_descriptor() {
+ return Frame_FrameType_descriptor();
+ }
+ static inline const ::std::string& FrameType_Name(FrameType value) {
+ return Frame_FrameType_Name(value);
+ }
+ static inline bool FrameType_Parse(const ::std::string& name,
+ FrameType* value) {
+ return Frame_FrameType_Parse(name, value);
+ }
+
+ // accessors -------------------------------------------------------
+
+ // optional .Frame.FrameType type = 1;
+ inline bool has_type() const;
+ inline void clear_type();
+ static const int kTypeFieldNumber = 1;
+ inline ::Frame_FrameType type() const;
+ inline void set_type(::Frame_FrameType value);
+
+ // optional int64 pos = 2;
+ inline bool has_pos() const;
+ inline void clear_pos();
+ static const int kPosFieldNumber = 2;
+ inline ::google::protobuf::int64 pos() const;
+ inline void set_pos(::google::protobuf::int64 value);
+
+ // optional string opt = 3;
+ inline bool has_opt() const;
+ inline void clear_opt();
+ static const int kOptFieldNumber = 3;
+ inline const ::std::string& opt() const;
+ inline void set_opt(const ::std::string& value);
+ inline void set_opt(const char* value);
+ inline void set_opt(const char* value, size_t size);
+ inline ::std::string* mutable_opt();
+ inline ::std::string* release_opt();
+
+ // @@protoc_insertion_point(class_scope:Frame)
+ private:
+ inline void set_has_type();
+ inline void clear_has_type();
+ inline void set_has_pos();
+ inline void clear_has_pos();
+ inline void set_has_opt();
+ inline void clear_has_opt();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::google::protobuf::int64 pos_;
+ ::std::string* opt_;
+ int type_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static Frame* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Backtrace : public ::google::protobuf::Message {
+ public:
+ Backtrace();
+ virtual ~Backtrace();
+
+ Backtrace(const Backtrace& from);
+
+ inline Backtrace& operator=(const Backtrace& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Backtrace& default_instance();
+
+ void Swap(Backtrace* other);
+
+ // implements Message ----------------------------------------------
+
+ Backtrace* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Backtrace& from);
+ void MergeFrom(const Backtrace& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // repeated .Frame frames = 1;
+ inline int frames_size() const;
+ inline void clear_frames();
+ static const int kFramesFieldNumber = 1;
+ inline const ::Frame& frames(int index) const;
+ inline ::Frame* mutable_frames(int index);
+ inline ::Frame* add_frames();
+ inline const ::google::protobuf::RepeatedPtrField< ::Frame >&
+ frames() const;
+ inline ::google::protobuf::RepeatedPtrField< ::Frame >*
+ mutable_frames();
+
+ // @@protoc_insertion_point(class_scope:Backtrace)
+ private:
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::google::protobuf::RepeatedPtrField< ::Frame > frames_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static Backtrace* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Response : public ::google::protobuf::Message {
+ public:
+ Response();
+ virtual ~Response();
+
+ Response(const Response& from);
+
+ inline Response& operator=(const Response& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Response& default_instance();
+
+ void Swap(Response* other);
+
+ // implements Message ----------------------------------------------
+
+ Response* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Response& from);
+ void MergeFrom(const Response& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ typedef Response_ResponseType ResponseType;
+ static const ResponseType SUCCESS_ATOM = Response_ResponseType_SUCCESS_ATOM;
+ static const ResponseType SUCCESS_SEQUENCE = Response_ResponseType_SUCCESS_SEQUENCE;
+ static const ResponseType SUCCESS_PARTIAL = Response_ResponseType_SUCCESS_PARTIAL;
+ static const ResponseType CLIENT_ERROR = Response_ResponseType_CLIENT_ERROR;
+ static const ResponseType COMPILE_ERROR = Response_ResponseType_COMPILE_ERROR;
+ static const ResponseType RUNTIME_ERROR = Response_ResponseType_RUNTIME_ERROR;
+ static inline bool ResponseType_IsValid(int value) {
+ return Response_ResponseType_IsValid(value);
+ }
+ static const ResponseType ResponseType_MIN =
+ Response_ResponseType_ResponseType_MIN;
+ static const ResponseType ResponseType_MAX =
+ Response_ResponseType_ResponseType_MAX;
+ static const int ResponseType_ARRAYSIZE =
+ Response_ResponseType_ResponseType_ARRAYSIZE;
+ static inline const ::google::protobuf::EnumDescriptor*
+ ResponseType_descriptor() {
+ return Response_ResponseType_descriptor();
+ }
+ static inline const ::std::string& ResponseType_Name(ResponseType value) {
+ return Response_ResponseType_Name(value);
+ }
+ static inline bool ResponseType_Parse(const ::std::string& name,
+ ResponseType* value) {
+ return Response_ResponseType_Parse(name, value);
+ }
+
+ // accessors -------------------------------------------------------
+
+ // optional .Response.ResponseType type = 1;
+ inline bool has_type() const;
+ inline void clear_type();
+ static const int kTypeFieldNumber = 1;
+ inline ::Response_ResponseType type() const;
+ inline void set_type(::Response_ResponseType value);
+
+ // optional int64 token = 2;
+ inline bool has_token() const;
+ inline void clear_token();
+ static const int kTokenFieldNumber = 2;
+ inline ::google::protobuf::int64 token() const;
+ inline void set_token(::google::protobuf::int64 value);
+
+ // repeated .Datum response = 3;
+ inline int response_size() const;
+ inline void clear_response();
+ static const int kResponseFieldNumber = 3;
+ inline const ::Datum& response(int index) const;
+ inline ::Datum* mutable_response(int index);
+ inline ::Datum* add_response();
+ inline const ::google::protobuf::RepeatedPtrField< ::Datum >&
+ response() const;
+ inline ::google::protobuf::RepeatedPtrField< ::Datum >*
+ mutable_response();
+
+ // optional .Backtrace backtrace = 4;
+ inline bool has_backtrace() const;
+ inline void clear_backtrace();
+ static const int kBacktraceFieldNumber = 4;
+ inline const ::Backtrace& backtrace() const;
+ inline ::Backtrace* mutable_backtrace();
+ inline ::Backtrace* release_backtrace();
+
+ // @@protoc_insertion_point(class_scope:Response)
+ private:
+ inline void set_has_type();
+ inline void clear_has_type();
+ inline void set_has_token();
+ inline void clear_has_token();
+ inline void set_has_backtrace();
+ inline void clear_has_backtrace();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::google::protobuf::int64 token_;
+ ::google::protobuf::RepeatedPtrField< ::Datum > response_;
+ ::Backtrace* backtrace_;
+ int type_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static Response* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Datum_AssocPair : public ::google::protobuf::Message {
+ public:
+ Datum_AssocPair();
+ virtual ~Datum_AssocPair();
+
+ Datum_AssocPair(const Datum_AssocPair& from);
+
+ inline Datum_AssocPair& operator=(const Datum_AssocPair& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Datum_AssocPair& default_instance();
+
+ void Swap(Datum_AssocPair* other);
+
+ // implements Message ----------------------------------------------
+
+ Datum_AssocPair* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Datum_AssocPair& from);
+ void MergeFrom(const Datum_AssocPair& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string key = 1;
+ inline bool has_key() const;
+ inline void clear_key();
+ static const int kKeyFieldNumber = 1;
+ inline const ::std::string& key() const;
+ inline void set_key(const ::std::string& value);
+ inline void set_key(const char* value);
+ inline void set_key(const char* value, size_t size);
+ inline ::std::string* mutable_key();
+ inline ::std::string* release_key();
+
+ // optional .Datum val = 2;
+ inline bool has_val() const;
+ inline void clear_val();
+ static const int kValFieldNumber = 2;
+ inline const ::Datum& val() const;
+ inline ::Datum* mutable_val();
+ inline ::Datum* release_val();
+
+ // @@protoc_insertion_point(class_scope:Datum.AssocPair)
+ private:
+ inline void set_has_key();
+ inline void clear_has_key();
+ inline void set_has_val();
+ inline void clear_has_val();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::std::string* key_;
+ ::Datum* val_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static Datum_AssocPair* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Datum : public ::google::protobuf::Message {
+ public:
+ Datum();
+ virtual ~Datum();
+
+ Datum(const Datum& from);
+
+ inline Datum& operator=(const Datum& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Datum& default_instance();
+
+ void Swap(Datum* other);
+
+ // implements Message ----------------------------------------------
+
+ Datum* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Datum& from);
+ void MergeFrom(const Datum& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ typedef Datum_AssocPair AssocPair;
+
+ typedef Datum_DatumType DatumType;
+ static const DatumType R_NULL = Datum_DatumType_R_NULL;
+ static const DatumType R_BOOL = Datum_DatumType_R_BOOL;
+ static const DatumType R_NUM = Datum_DatumType_R_NUM;
+ static const DatumType R_STR = Datum_DatumType_R_STR;
+ static const DatumType R_ARRAY = Datum_DatumType_R_ARRAY;
+ static const DatumType R_OBJECT = Datum_DatumType_R_OBJECT;
+ static inline bool DatumType_IsValid(int value) {
+ return Datum_DatumType_IsValid(value);
+ }
+ static const DatumType DatumType_MIN =
+ Datum_DatumType_DatumType_MIN;
+ static const DatumType DatumType_MAX =
+ Datum_DatumType_DatumType_MAX;
+ static const int DatumType_ARRAYSIZE =
+ Datum_DatumType_DatumType_ARRAYSIZE;
+ static inline const ::google::protobuf::EnumDescriptor*
+ DatumType_descriptor() {
+ return Datum_DatumType_descriptor();
+ }
+ static inline const ::std::string& DatumType_Name(DatumType value) {
+ return Datum_DatumType_Name(value);
+ }
+ static inline bool DatumType_Parse(const ::std::string& name,
+ DatumType* value) {
+ return Datum_DatumType_Parse(name, value);
+ }
+
+ // accessors -------------------------------------------------------
+
+ // optional .Datum.DatumType type = 1;
+ inline bool has_type() const;
+ inline void clear_type();
+ static const int kTypeFieldNumber = 1;
+ inline ::Datum_DatumType type() const;
+ inline void set_type(::Datum_DatumType value);
+
+ // optional bool r_bool = 2;
+ inline bool has_r_bool() const;
+ inline void clear_r_bool();
+ static const int kRBoolFieldNumber = 2;
+ inline bool r_bool() const;
+ inline void set_r_bool(bool value);
+
+ // optional double r_num = 3;
+ inline bool has_r_num() const;
+ inline void clear_r_num();
+ static const int kRNumFieldNumber = 3;
+ inline double r_num() const;
+ inline void set_r_num(double value);
+
+ // optional string r_str = 4;
+ inline bool has_r_str() const;
+ inline void clear_r_str();
+ static const int kRStrFieldNumber = 4;
+ inline const ::std::string& r_str() const;
+ inline void set_r_str(const ::std::string& value);
+ inline void set_r_str(const char* value);
+ inline void set_r_str(const char* value, size_t size);
+ inline ::std::string* mutable_r_str();
+ inline ::std::string* release_r_str();
+
+ // repeated .Datum r_array = 5;
+ inline int r_array_size() const;
+ inline void clear_r_array();
+ static const int kRArrayFieldNumber = 5;
+ inline const ::Datum& r_array(int index) const;
+ inline ::Datum* mutable_r_array(int index);
+ inline ::Datum* add_r_array();
+ inline const ::google::protobuf::RepeatedPtrField< ::Datum >&
+ r_array() const;
+ inline ::google::protobuf::RepeatedPtrField< ::Datum >*
+ mutable_r_array();
+
+ // repeated .Datum.AssocPair r_object = 6;
+ inline int r_object_size() const;
+ inline void clear_r_object();
+ static const int kRObjectFieldNumber = 6;
+ inline const ::Datum_AssocPair& r_object(int index) const;
+ inline ::Datum_AssocPair* mutable_r_object(int index);
+ inline ::Datum_AssocPair* add_r_object();
+ inline const ::google::protobuf::RepeatedPtrField< ::Datum_AssocPair >&
+ r_object() const;
+ inline ::google::protobuf::RepeatedPtrField< ::Datum_AssocPair >*
+ mutable_r_object();
+
+ GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(Datum)
+ // @@protoc_insertion_point(class_scope:Datum)
+ private:
+ inline void set_has_type();
+ inline void clear_has_type();
+ inline void set_has_r_bool();
+ inline void clear_has_r_bool();
+ inline void set_has_r_num();
+ inline void clear_has_r_num();
+ inline void set_has_r_str();
+ inline void clear_has_r_str();
+
+ ::google::protobuf::internal::ExtensionSet _extensions_;
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ int type_;
+ bool r_bool_;
+ double r_num_;
+ ::std::string* r_str_;
+ ::google::protobuf::RepeatedPtrField< ::Datum > r_array_;
+ ::google::protobuf::RepeatedPtrField< ::Datum_AssocPair > r_object_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(6 + 31) / 32];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static Datum* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Term_AssocPair : public ::google::protobuf::Message {
+ public:
+ Term_AssocPair();
+ virtual ~Term_AssocPair();
+
+ Term_AssocPair(const Term_AssocPair& from);
+
+ inline Term_AssocPair& operator=(const Term_AssocPair& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Term_AssocPair& default_instance();
+
+ void Swap(Term_AssocPair* other);
+
+ // implements Message ----------------------------------------------
+
+ Term_AssocPair* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Term_AssocPair& from);
+ void MergeFrom(const Term_AssocPair& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string key = 1;
+ inline bool has_key() const;
+ inline void clear_key();
+ static const int kKeyFieldNumber = 1;
+ inline const ::std::string& key() const;
+ inline void set_key(const ::std::string& value);
+ inline void set_key(const char* value);
+ inline void set_key(const char* value, size_t size);
+ inline ::std::string* mutable_key();
+ inline ::std::string* release_key();
+
+ // optional .Term val = 2;
+ inline bool has_val() const;
+ inline void clear_val();
+ static const int kValFieldNumber = 2;
+ inline const ::Term& val() const;
+ inline ::Term* mutable_val();
+ inline ::Term* release_val();
+
+ // @@protoc_insertion_point(class_scope:Term.AssocPair)
+ private:
+ inline void set_has_key();
+ inline void clear_has_key();
+ inline void set_has_val();
+ inline void clear_has_val();
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::std::string* key_;
+ ::Term* val_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static Term_AssocPair* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Term : public ::google::protobuf::Message {
+ public:
+ Term();
+ virtual ~Term();
+
+ Term(const Term& from);
+
+ inline Term& operator=(const Term& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+ return _unknown_fields_;
+ }
+
+ inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+ return &_unknown_fields_;
+ }
+
+ static const ::google::protobuf::Descriptor* descriptor();
+ static const Term& default_instance();
+
+ void Swap(Term* other);
+
+ // implements Message ----------------------------------------------
+
+ Term* New() const;
+ void CopyFrom(const ::google::protobuf::Message& from);
+ void MergeFrom(const ::google::protobuf::Message& from);
+ void CopyFrom(const Term& from);
+ void MergeFrom(const Term& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::google::protobuf::Metadata GetMetadata() const;
+
+ // nested types ----------------------------------------------------
+
+ typedef Term_AssocPair AssocPair;
+
+ typedef Term_TermType TermType;
+ static const TermType DATUM = Term_TermType_DATUM;
+ static const TermType MAKE_ARRAY = Term_TermType_MAKE_ARRAY;
+ static const TermType MAKE_OBJ = Term_TermType_MAKE_OBJ;
+ static const TermType VAR = Term_TermType_VAR;
+ static const TermType JAVASCRIPT = Term_TermType_JAVASCRIPT;
+ static const TermType ERROR = Term_TermType_ERROR;
+ static const TermType IMPLICIT_VAR = Term_TermType_IMPLICIT_VAR;
+ static const TermType DB = Term_TermType_DB;
+ static const TermType TABLE = Term_TermType_TABLE;
+ static const TermType GET = Term_TermType_GET;
+ static const TermType GET_ALL = Term_TermType_GET_ALL;
+ static const TermType EQ = Term_TermType_EQ;
+ static const TermType NE = Term_TermType_NE;
+ static const TermType LT = Term_TermType_LT;
+ static const TermType LE = Term_TermType_LE;
+ static const TermType GT = Term_TermType_GT;
+ static const TermType GE = Term_TermType_GE;
+ static const TermType NOT = Term_TermType_NOT;
+ static const TermType ADD = Term_TermType_ADD;
+ static const TermType SUB = Term_TermType_SUB;
+ static const TermType MUL = Term_TermType_MUL;
+ static const TermType DIV = Term_TermType_DIV;
+ static const TermType MOD = Term_TermType_MOD;
+ static const TermType APPEND = Term_TermType_APPEND;
+ static const TermType PREPEND = Term_TermType_PREPEND;
+ static const TermType DIFFERENCE = Term_TermType_DIFFERENCE;
+ static const TermType SET_INSERT = Term_TermType_SET_INSERT;
+ static const TermType SET_INTERSECTION = Term_TermType_SET_INTERSECTION;
+ static const TermType SET_UNION = Term_TermType_SET_UNION;
+ static const TermType SET_DIFFERENCE = Term_TermType_SET_DIFFERENCE;
+ static const TermType SLICE = Term_TermType_SLICE;
+ static const TermType SKIP = Term_TermType_SKIP;
+ static const TermType LIMIT = Term_TermType_LIMIT;
+ static const TermType INDEXES_OF = Term_TermType_INDEXES_OF;
+ static const TermType CONTAINS = Term_TermType_CONTAINS;
+ static const TermType GETATTR = Term_TermType_GETATTR;
+ static const TermType KEYS = Term_TermType_KEYS;
+ static const TermType HAS_FIELDS = Term_TermType_HAS_FIELDS;
+ static const TermType WITH_FIELDS = Term_TermType_WITH_FIELDS;
+ static const TermType PLUCK = Term_TermType_PLUCK;
+ static const TermType WITHOUT = Term_TermType_WITHOUT;
+ static const TermType MERGE = Term_TermType_MERGE;
+ static const TermType BETWEEN = Term_TermType_BETWEEN;
+ static const TermType REDUCE = Term_TermType_REDUCE;
+ static const TermType MAP = Term_TermType_MAP;
+ static const TermType FILTER = Term_TermType_FILTER;
+ static const TermType CONCATMAP = Term_TermType_CONCATMAP;
+ static const TermType ORDERBY = Term_TermType_ORDERBY;
+ static const TermType DISTINCT = Term_TermType_DISTINCT;
+ static const TermType COUNT = Term_TermType_COUNT;
+ static const TermType IS_EMPTY = Term_TermType_IS_EMPTY;
+ static const TermType UNION = Term_TermType_UNION;
+ static const TermType NTH = Term_TermType_NTH;
+ static const TermType GROUPED_MAP_REDUCE = Term_TermType_GROUPED_MAP_REDUCE;
+ static const TermType GROUPBY = Term_TermType_GROUPBY;
+ static const TermType INNER_JOIN = Term_TermType_INNER_JOIN;
+ static const TermType OUTER_JOIN = Term_TermType_OUTER_JOIN;
+ static const TermType EQ_JOIN = Term_TermType_EQ_JOIN;
+ static const TermType ZIP = Term_TermType_ZIP;
+ static const TermType INSERT_AT = Term_TermType_INSERT_AT;
+ static const TermType DELETE_AT = Term_TermType_DELETE_AT;
+ static const TermType CHANGE_AT = Term_TermType_CHANGE_AT;
+ static const TermType SPLICE_AT = Term_TermType_SPLICE_AT;
+ static const TermType COERCE_TO = Term_TermType_COERCE_TO;
+ static const TermType TYPEOF = Term_TermType_TYPEOF;
+ static const TermType UPDATE = Term_TermType_UPDATE;
+ static const TermType DELETE = Term_TermType_DELETE;
+ static const TermType REPLACE = Term_TermType_REPLACE;
+ static const TermType INSERT = Term_TermType_INSERT;
+ static const TermType DB_CREATE = Term_TermType_DB_CREATE;
+ static const TermType DB_DROP = Term_TermType_DB_DROP;
+ static const TermType DB_LIST = Term_TermType_DB_LIST;
+ static const TermType TABLE_CREATE = Term_TermType_TABLE_CREATE;
+ static const TermType TABLE_DROP = Term_TermType_TABLE_DROP;
+ static const TermType TABLE_LIST = Term_TermType_TABLE_LIST;
+ static const TermType INDEX_CREATE = Term_TermType_INDEX_CREATE;
+ static const TermType INDEX_DROP = Term_TermType_INDEX_DROP;
+ static const TermType INDEX_LIST = Term_TermType_INDEX_LIST;
+ static const TermType FUNCALL = Term_TermType_FUNCALL;
+ static const TermType BRANCH = Term_TermType_BRANCH;
+ static const TermType ANY = Term_TermType_ANY;
+ static const TermType ALL = Term_TermType_ALL;
+ static const TermType FOREACH = Term_TermType_FOREACH;
+ static const TermType FUNC = Term_TermType_FUNC;
+ static const TermType ASC = Term_TermType_ASC;
+ static const TermType DESC = Term_TermType_DESC;
+ static const TermType INFO = Term_TermType_INFO;
+ static const TermType MATCH = Term_TermType_MATCH;
+ static const TermType SAMPLE = Term_TermType_SAMPLE;
+ static const TermType DEFAULT = Term_TermType_DEFAULT;
+ static inline bool TermType_IsValid(int value) {
+ return Term_TermType_IsValid(value);
+ }
+ static const TermType TermType_MIN =
+ Term_TermType_TermType_MIN;
+ static const TermType TermType_MAX =
+ Term_TermType_TermType_MAX;
+ static const int TermType_ARRAYSIZE =
+ Term_TermType_TermType_ARRAYSIZE;
+ static inline const ::google::protobuf::EnumDescriptor*
+ TermType_descriptor() {
+ return Term_TermType_descriptor();
+ }
+ static inline const ::std::string& TermType_Name(TermType value) {
+ return Term_TermType_Name(value);
+ }
+ static inline bool TermType_Parse(const ::std::string& name,
+ TermType* value) {
+ return Term_TermType_Parse(name, value);
+ }
+
+ // accessors -------------------------------------------------------
+
+ // optional .Term.TermType type = 1;
+ inline bool has_type() const;
+ inline void clear_type();
+ static const int kTypeFieldNumber = 1;
+ inline ::Term_TermType type() const;
+ inline void set_type(::Term_TermType value);
+
+ // optional .Datum datum = 2;
+ inline bool has_datum() const;
+ inline void clear_datum();
+ static const int kDatumFieldNumber = 2;
+ inline const ::Datum& datum() const;
+ inline ::Datum* mutable_datum();
+ inline ::Datum* release_datum();
+
+ // repeated .Term args = 3;
+ inline int args_size() const;
+ inline void clear_args();
+ static const int kArgsFieldNumber = 3;
+ inline const ::Term& args(int index) const;
+ inline ::Term* mutable_args(int index);
+ inline ::Term* add_args();
+ inline const ::google::protobuf::RepeatedPtrField< ::Term >&
+ args() const;
+ inline ::google::protobuf::RepeatedPtrField< ::Term >*
+ mutable_args();
+
+ // repeated .Term.AssocPair optargs = 4;
+ inline int optargs_size() const;
+ inline void clear_optargs();
+ static const int kOptargsFieldNumber = 4;
+ inline const ::Term_AssocPair& optargs(int index) const;
+ inline ::Term_AssocPair* mutable_optargs(int index);
+ inline ::Term_AssocPair* add_optargs();
+ inline const ::google::protobuf::RepeatedPtrField< ::Term_AssocPair >&
+ optargs() const;
+ inline ::google::protobuf::RepeatedPtrField< ::Term_AssocPair >*
+ mutable_optargs();
+
+ GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(Term)
+ // @@protoc_insertion_point(class_scope:Term)
+ private:
+ inline void set_has_type();
+ inline void clear_has_type();
+ inline void set_has_datum();
+ inline void clear_has_datum();
+
+ ::google::protobuf::internal::ExtensionSet _extensions_;
+
+ ::google::protobuf::UnknownFieldSet _unknown_fields_;
+
+ ::Datum* datum_;
+ ::google::protobuf::RepeatedPtrField< ::Term > args_;
+ ::google::protobuf::RepeatedPtrField< ::Term_AssocPair > optargs_;
+ int type_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
+
+ friend void protobuf_AddDesc_ql2_2eproto();
+ friend void protobuf_AssignDesc_ql2_2eproto();
+ friend void protobuf_ShutdownFile_ql2_2eproto();
+
+ void InitAsDefaultInstance();
+ static Term* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+// VersionDummy
+
+// -------------------------------------------------------------------
+
+// Query_AssocPair
+
+// optional string key = 1;
+inline bool Query_AssocPair::has_key() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Query_AssocPair::set_has_key() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Query_AssocPair::clear_has_key() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Query_AssocPair::clear_key() {
+ if (key_ != &::google::protobuf::internal::kEmptyString) {
+ key_->clear();
+ }
+ clear_has_key();
+}
+inline const ::std::string& Query_AssocPair::key() const {
+ return *key_;
+}
+inline void Query_AssocPair::set_key(const ::std::string& value) {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ key_->assign(value);
+}
+inline void Query_AssocPair::set_key(const char* value) {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ key_->assign(value);
+}
+inline void Query_AssocPair::set_key(const char* value, size_t size) {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ key_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Query_AssocPair::mutable_key() {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ return key_;
+}
+inline ::std::string* Query_AssocPair::release_key() {
+ clear_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = key_;
+ key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+
+// optional .Term val = 2;
+inline bool Query_AssocPair::has_val() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Query_AssocPair::set_has_val() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void Query_AssocPair::clear_has_val() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void Query_AssocPair::clear_val() {
+ if (val_ != NULL) val_->::Term::Clear();
+ clear_has_val();
+}
+inline const ::Term& Query_AssocPair::val() const {
+ return val_ != NULL ? *val_ : *default_instance_->val_;
+}
+inline ::Term* Query_AssocPair::mutable_val() {
+ set_has_val();
+ if (val_ == NULL) val_ = new ::Term;
+ return val_;
+}
+inline ::Term* Query_AssocPair::release_val() {
+ clear_has_val();
+ ::Term* temp = val_;
+ val_ = NULL;
+ return temp;
+}
+
+// -------------------------------------------------------------------
+
+// Query
+
+// optional .Query.QueryType type = 1;
+inline bool Query::has_type() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Query::set_has_type() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Query::clear_has_type() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Query::clear_type() {
+ type_ = 1;
+ clear_has_type();
+}
+inline ::Query_QueryType Query::type() const {
+ return static_cast< ::Query_QueryType >(type_);
+}
+inline void Query::set_type(::Query_QueryType value) {
+ GOOGLE_DCHECK(::Query_QueryType_IsValid(value));
+ set_has_type();
+ type_ = value;
+}
+
+// optional .Term query = 2;
+inline bool Query::has_query() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Query::set_has_query() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void Query::clear_has_query() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void Query::clear_query() {
+ if (query_ != NULL) query_->::Term::Clear();
+ clear_has_query();
+}
+inline const ::Term& Query::query() const {
+ return query_ != NULL ? *query_ : *default_instance_->query_;
+}
+inline ::Term* Query::mutable_query() {
+ set_has_query();
+ if (query_ == NULL) query_ = new ::Term;
+ return query_;
+}
+inline ::Term* Query::release_query() {
+ clear_has_query();
+ ::Term* temp = query_;
+ query_ = NULL;
+ return temp;
+}
+
+// optional int64 token = 3;
+inline bool Query::has_token() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void Query::set_has_token() {
+ _has_bits_[0] |= 0x00000004u;
+}
+inline void Query::clear_has_token() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+inline void Query::clear_token() {
+ token_ = GOOGLE_LONGLONG(0);
+ clear_has_token();
+}
+inline ::google::protobuf::int64 Query::token() const {
+ return token_;
+}
+inline void Query::set_token(::google::protobuf::int64 value) {
+ set_has_token();
+ token_ = value;
+}
+
+// optional bool OBSOLETE_noreply = 4 [default = false];
+inline bool Query::has_obsolete_noreply() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void Query::set_has_obsolete_noreply() {
+ _has_bits_[0] |= 0x00000008u;
+}
+inline void Query::clear_has_obsolete_noreply() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+inline void Query::clear_obsolete_noreply() {
+ obsolete_noreply_ = false;
+ clear_has_obsolete_noreply();
+}
+inline bool Query::obsolete_noreply() const {
+ return obsolete_noreply_;
+}
+inline void Query::set_obsolete_noreply(bool value) {
+ set_has_obsolete_noreply();
+ obsolete_noreply_ = value;
+}
+
+// repeated .Query.AssocPair global_optargs = 6;
+inline int Query::global_optargs_size() const {
+ return global_optargs_.size();
+}
+inline void Query::clear_global_optargs() {
+ global_optargs_.Clear();
+}
+inline const ::Query_AssocPair& Query::global_optargs(int index) const {
+ return global_optargs_.Get(index);
+}
+inline ::Query_AssocPair* Query::mutable_global_optargs(int index) {
+ return global_optargs_.Mutable(index);
+}
+inline ::Query_AssocPair* Query::add_global_optargs() {
+ return global_optargs_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::Query_AssocPair >&
+Query::global_optargs() const {
+ return global_optargs_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::Query_AssocPair >*
+Query::mutable_global_optargs() {
+ return &global_optargs_;
+}
+
+// -------------------------------------------------------------------
+
+// Frame
+
+// optional .Frame.FrameType type = 1;
+inline bool Frame::has_type() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Frame::set_has_type() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Frame::clear_has_type() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Frame::clear_type() {
+ type_ = 1;
+ clear_has_type();
+}
+inline ::Frame_FrameType Frame::type() const {
+ return static_cast< ::Frame_FrameType >(type_);
+}
+inline void Frame::set_type(::Frame_FrameType value) {
+ GOOGLE_DCHECK(::Frame_FrameType_IsValid(value));
+ set_has_type();
+ type_ = value;
+}
+
+// optional int64 pos = 2;
+inline bool Frame::has_pos() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Frame::set_has_pos() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void Frame::clear_has_pos() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void Frame::clear_pos() {
+ pos_ = GOOGLE_LONGLONG(0);
+ clear_has_pos();
+}
+inline ::google::protobuf::int64 Frame::pos() const {
+ return pos_;
+}
+inline void Frame::set_pos(::google::protobuf::int64 value) {
+ set_has_pos();
+ pos_ = value;
+}
+
+// optional string opt = 3;
+inline bool Frame::has_opt() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void Frame::set_has_opt() {
+ _has_bits_[0] |= 0x00000004u;
+}
+inline void Frame::clear_has_opt() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+inline void Frame::clear_opt() {
+ if (opt_ != &::google::protobuf::internal::kEmptyString) {
+ opt_->clear();
+ }
+ clear_has_opt();
+}
+inline const ::std::string& Frame::opt() const {
+ return *opt_;
+}
+inline void Frame::set_opt(const ::std::string& value) {
+ set_has_opt();
+ if (opt_ == &::google::protobuf::internal::kEmptyString) {
+ opt_ = new ::std::string;
+ }
+ opt_->assign(value);
+}
+inline void Frame::set_opt(const char* value) {
+ set_has_opt();
+ if (opt_ == &::google::protobuf::internal::kEmptyString) {
+ opt_ = new ::std::string;
+ }
+ opt_->assign(value);
+}
+inline void Frame::set_opt(const char* value, size_t size) {
+ set_has_opt();
+ if (opt_ == &::google::protobuf::internal::kEmptyString) {
+ opt_ = new ::std::string;
+ }
+ opt_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Frame::mutable_opt() {
+ set_has_opt();
+ if (opt_ == &::google::protobuf::internal::kEmptyString) {
+ opt_ = new ::std::string;
+ }
+ return opt_;
+}
+inline ::std::string* Frame::release_opt() {
+ clear_has_opt();
+ if (opt_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = opt_;
+ opt_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+
+// -------------------------------------------------------------------
+
+// Backtrace
+
+// repeated .Frame frames = 1;
+inline int Backtrace::frames_size() const {
+ return frames_.size();
+}
+inline void Backtrace::clear_frames() {
+ frames_.Clear();
+}
+inline const ::Frame& Backtrace::frames(int index) const {
+ return frames_.Get(index);
+}
+inline ::Frame* Backtrace::mutable_frames(int index) {
+ return frames_.Mutable(index);
+}
+inline ::Frame* Backtrace::add_frames() {
+ return frames_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::Frame >&
+Backtrace::frames() const {
+ return frames_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::Frame >*
+Backtrace::mutable_frames() {
+ return &frames_;
+}
+
+// -------------------------------------------------------------------
+
+// Response
+
+// optional .Response.ResponseType type = 1;
+inline bool Response::has_type() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Response::set_has_type() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Response::clear_has_type() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Response::clear_type() {
+ type_ = 1;
+ clear_has_type();
+}
+inline ::Response_ResponseType Response::type() const {
+ return static_cast< ::Response_ResponseType >(type_);
+}
+inline void Response::set_type(::Response_ResponseType value) {
+ GOOGLE_DCHECK(::Response_ResponseType_IsValid(value));
+ set_has_type();
+ type_ = value;
+}
+
+// optional int64 token = 2;
+inline bool Response::has_token() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Response::set_has_token() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void Response::clear_has_token() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void Response::clear_token() {
+ token_ = GOOGLE_LONGLONG(0);
+ clear_has_token();
+}
+inline ::google::protobuf::int64 Response::token() const {
+ return token_;
+}
+inline void Response::set_token(::google::protobuf::int64 value) {
+ set_has_token();
+ token_ = value;
+}
+
+// repeated .Datum response = 3;
+inline int Response::response_size() const {
+ return response_.size();
+}
+inline void Response::clear_response() {
+ response_.Clear();
+}
+inline const ::Datum& Response::response(int index) const {
+ return response_.Get(index);
+}
+inline ::Datum* Response::mutable_response(int index) {
+ return response_.Mutable(index);
+}
+inline ::Datum* Response::add_response() {
+ return response_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::Datum >&
+Response::response() const {
+ return response_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::Datum >*
+Response::mutable_response() {
+ return &response_;
+}
+
+// optional .Backtrace backtrace = 4;
+inline bool Response::has_backtrace() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void Response::set_has_backtrace() {
+ _has_bits_[0] |= 0x00000008u;
+}
+inline void Response::clear_has_backtrace() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+inline void Response::clear_backtrace() {
+ if (backtrace_ != NULL) backtrace_->::Backtrace::Clear();
+ clear_has_backtrace();
+}
+inline const ::Backtrace& Response::backtrace() const {
+ return backtrace_ != NULL ? *backtrace_ : *default_instance_->backtrace_;
+}
+inline ::Backtrace* Response::mutable_backtrace() {
+ set_has_backtrace();
+ if (backtrace_ == NULL) backtrace_ = new ::Backtrace;
+ return backtrace_;
+}
+inline ::Backtrace* Response::release_backtrace() {
+ clear_has_backtrace();
+ ::Backtrace* temp = backtrace_;
+ backtrace_ = NULL;
+ return temp;
+}
+
+// -------------------------------------------------------------------
+
+// Datum_AssocPair
+
+// optional string key = 1;
+inline bool Datum_AssocPair::has_key() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Datum_AssocPair::set_has_key() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Datum_AssocPair::clear_has_key() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Datum_AssocPair::clear_key() {
+ if (key_ != &::google::protobuf::internal::kEmptyString) {
+ key_->clear();
+ }
+ clear_has_key();
+}
+inline const ::std::string& Datum_AssocPair::key() const {
+ return *key_;
+}
+inline void Datum_AssocPair::set_key(const ::std::string& value) {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ key_->assign(value);
+}
+inline void Datum_AssocPair::set_key(const char* value) {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ key_->assign(value);
+}
+inline void Datum_AssocPair::set_key(const char* value, size_t size) {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ key_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Datum_AssocPair::mutable_key() {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ return key_;
+}
+inline ::std::string* Datum_AssocPair::release_key() {
+ clear_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = key_;
+ key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+
+// optional .Datum val = 2;
+inline bool Datum_AssocPair::has_val() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Datum_AssocPair::set_has_val() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void Datum_AssocPair::clear_has_val() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void Datum_AssocPair::clear_val() {
+ if (val_ != NULL) val_->::Datum::Clear();
+ clear_has_val();
+}
+inline const ::Datum& Datum_AssocPair::val() const {
+ return val_ != NULL ? *val_ : *default_instance_->val_;
+}
+inline ::Datum* Datum_AssocPair::mutable_val() {
+ set_has_val();
+ if (val_ == NULL) val_ = new ::Datum;
+ return val_;
+}
+inline ::Datum* Datum_AssocPair::release_val() {
+ clear_has_val();
+ ::Datum* temp = val_;
+ val_ = NULL;
+ return temp;
+}
+
+// -------------------------------------------------------------------
+
+// Datum
+
+// optional .Datum.DatumType type = 1;
+inline bool Datum::has_type() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Datum::set_has_type() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Datum::clear_has_type() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Datum::clear_type() {
+ type_ = 1;
+ clear_has_type();
+}
+inline ::Datum_DatumType Datum::type() const {
+ return static_cast< ::Datum_DatumType >(type_);
+}
+inline void Datum::set_type(::Datum_DatumType value) {
+ GOOGLE_DCHECK(::Datum_DatumType_IsValid(value));
+ set_has_type();
+ type_ = value;
+}
+
+// optional bool r_bool = 2;
+inline bool Datum::has_r_bool() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Datum::set_has_r_bool() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void Datum::clear_has_r_bool() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void Datum::clear_r_bool() {
+ r_bool_ = false;
+ clear_has_r_bool();
+}
+inline bool Datum::r_bool() const {
+ return r_bool_;
+}
+inline void Datum::set_r_bool(bool value) {
+ set_has_r_bool();
+ r_bool_ = value;
+}
+
+// optional double r_num = 3;
+inline bool Datum::has_r_num() const {
+ return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void Datum::set_has_r_num() {
+ _has_bits_[0] |= 0x00000004u;
+}
+inline void Datum::clear_has_r_num() {
+ _has_bits_[0] &= ~0x00000004u;
+}
+inline void Datum::clear_r_num() {
+ r_num_ = 0;
+ clear_has_r_num();
+}
+inline double Datum::r_num() const {
+ return r_num_;
+}
+inline void Datum::set_r_num(double value) {
+ set_has_r_num();
+ r_num_ = value;
+}
+
+// optional string r_str = 4;
+inline bool Datum::has_r_str() const {
+ return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void Datum::set_has_r_str() {
+ _has_bits_[0] |= 0x00000008u;
+}
+inline void Datum::clear_has_r_str() {
+ _has_bits_[0] &= ~0x00000008u;
+}
+inline void Datum::clear_r_str() {
+ if (r_str_ != &::google::protobuf::internal::kEmptyString) {
+ r_str_->clear();
+ }
+ clear_has_r_str();
+}
+inline const ::std::string& Datum::r_str() const {
+ return *r_str_;
+}
+inline void Datum::set_r_str(const ::std::string& value) {
+ set_has_r_str();
+ if (r_str_ == &::google::protobuf::internal::kEmptyString) {
+ r_str_ = new ::std::string;
+ }
+ r_str_->assign(value);
+}
+inline void Datum::set_r_str(const char* value) {
+ set_has_r_str();
+ if (r_str_ == &::google::protobuf::internal::kEmptyString) {
+ r_str_ = new ::std::string;
+ }
+ r_str_->assign(value);
+}
+inline void Datum::set_r_str(const char* value, size_t size) {
+ set_has_r_str();
+ if (r_str_ == &::google::protobuf::internal::kEmptyString) {
+ r_str_ = new ::std::string;
+ }
+ r_str_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Datum::mutable_r_str() {
+ set_has_r_str();
+ if (r_str_ == &::google::protobuf::internal::kEmptyString) {
+ r_str_ = new ::std::string;
+ }
+ return r_str_;
+}
+inline ::std::string* Datum::release_r_str() {
+ clear_has_r_str();
+ if (r_str_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = r_str_;
+ r_str_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+
+// repeated .Datum r_array = 5;
+inline int Datum::r_array_size() const {
+ return r_array_.size();
+}
+inline void Datum::clear_r_array() {
+ r_array_.Clear();
+}
+inline const ::Datum& Datum::r_array(int index) const {
+ return r_array_.Get(index);
+}
+inline ::Datum* Datum::mutable_r_array(int index) {
+ return r_array_.Mutable(index);
+}
+inline ::Datum* Datum::add_r_array() {
+ return r_array_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::Datum >&
+Datum::r_array() const {
+ return r_array_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::Datum >*
+Datum::mutable_r_array() {
+ return &r_array_;
+}
+
+// repeated .Datum.AssocPair r_object = 6;
+inline int Datum::r_object_size() const {
+ return r_object_.size();
+}
+inline void Datum::clear_r_object() {
+ r_object_.Clear();
+}
+inline const ::Datum_AssocPair& Datum::r_object(int index) const {
+ return r_object_.Get(index);
+}
+inline ::Datum_AssocPair* Datum::mutable_r_object(int index) {
+ return r_object_.Mutable(index);
+}
+inline ::Datum_AssocPair* Datum::add_r_object() {
+ return r_object_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::Datum_AssocPair >&
+Datum::r_object() const {
+ return r_object_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::Datum_AssocPair >*
+Datum::mutable_r_object() {
+ return &r_object_;
+}
+
+// -------------------------------------------------------------------
+
+// Term_AssocPair
+
+// optional string key = 1;
+inline bool Term_AssocPair::has_key() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Term_AssocPair::set_has_key() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Term_AssocPair::clear_has_key() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Term_AssocPair::clear_key() {
+ if (key_ != &::google::protobuf::internal::kEmptyString) {
+ key_->clear();
+ }
+ clear_has_key();
+}
+inline const ::std::string& Term_AssocPair::key() const {
+ return *key_;
+}
+inline void Term_AssocPair::set_key(const ::std::string& value) {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ key_->assign(value);
+}
+inline void Term_AssocPair::set_key(const char* value) {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ key_->assign(value);
+}
+inline void Term_AssocPair::set_key(const char* value, size_t size) {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ key_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Term_AssocPair::mutable_key() {
+ set_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ key_ = new ::std::string;
+ }
+ return key_;
+}
+inline ::std::string* Term_AssocPair::release_key() {
+ clear_has_key();
+ if (key_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = key_;
+ key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+
+// optional .Term val = 2;
+inline bool Term_AssocPair::has_val() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Term_AssocPair::set_has_val() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void Term_AssocPair::clear_has_val() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void Term_AssocPair::clear_val() {
+ if (val_ != NULL) val_->::Term::Clear();
+ clear_has_val();
+}
+inline const ::Term& Term_AssocPair::val() const {
+ return val_ != NULL ? *val_ : *default_instance_->val_;
+}
+inline ::Term* Term_AssocPair::mutable_val() {
+ set_has_val();
+ if (val_ == NULL) val_ = new ::Term;
+ return val_;
+}
+inline ::Term* Term_AssocPair::release_val() {
+ clear_has_val();
+ ::Term* temp = val_;
+ val_ = NULL;
+ return temp;
+}
+
+// -------------------------------------------------------------------
+
+// Term
+
+// optional .Term.TermType type = 1;
+inline bool Term::has_type() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Term::set_has_type() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Term::clear_has_type() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Term::clear_type() {
+ type_ = 1;
+ clear_has_type();
+}
+inline ::Term_TermType Term::type() const {
+ return static_cast< ::Term_TermType >(type_);
+}
+inline void Term::set_type(::Term_TermType value) {
+ GOOGLE_DCHECK(::Term_TermType_IsValid(value));
+ set_has_type();
+ type_ = value;
+}
+
+// optional .Datum datum = 2;
+inline bool Term::has_datum() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Term::set_has_datum() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void Term::clear_has_datum() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void Term::clear_datum() {
+ if (datum_ != NULL) datum_->::Datum::Clear();
+ clear_has_datum();
+}
+inline const ::Datum& Term::datum() const {
+ return datum_ != NULL ? *datum_ : *default_instance_->datum_;
+}
+inline ::Datum* Term::mutable_datum() {
+ set_has_datum();
+ if (datum_ == NULL) datum_ = new ::Datum;
+ return datum_;
+}
+inline ::Datum* Term::release_datum() {
+ clear_has_datum();
+ ::Datum* temp = datum_;
+ datum_ = NULL;
+ return temp;
+}
+
+// repeated .Term args = 3;
+inline int Term::args_size() const {
+ return args_.size();
+}
+inline void Term::clear_args() {
+ args_.Clear();
+}
+inline const ::Term& Term::args(int index) const {
+ return args_.Get(index);
+}
+inline ::Term* Term::mutable_args(int index) {
+ return args_.Mutable(index);
+}
+inline ::Term* Term::add_args() {
+ return args_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::Term >&
+Term::args() const {
+ return args_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::Term >*
+Term::mutable_args() {
+ return &args_;
+}
+
+// repeated .Term.AssocPair optargs = 4;
+inline int Term::optargs_size() const {
+ return optargs_.size();
+}
+inline void Term::clear_optargs() {
+ optargs_.Clear();
+}
+inline const ::Term_AssocPair& Term::optargs(int index) const {
+ return optargs_.Get(index);
+}
+inline ::Term_AssocPair* Term::mutable_optargs(int index) {
+ return optargs_.Mutable(index);
+}
+inline ::Term_AssocPair* Term::add_optargs() {
+ return optargs_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::Term_AssocPair >&
+Term::optargs() const {
+ return optargs_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::Term_AssocPair >*
+Term::mutable_optargs() {
+ return &optargs_;
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+#ifndef SWIG
+namespace google {
+namespace protobuf {
+
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::VersionDummy_Version>() {
+ return ::VersionDummy_Version_descriptor();
+}
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::Query_QueryType>() {
+ return ::Query_QueryType_descriptor();
+}
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::Frame_FrameType>() {
+ return ::Frame_FrameType_descriptor();
+}
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::Response_ResponseType>() {
+ return ::Response_ResponseType_descriptor();
+}
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::Datum_DatumType>() {
+ return ::Datum_DatumType_descriptor();
+}
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::Term_TermType>() {
+ return ::Term_TermType_descriptor();
+}
+
+} // namespace google
+} // namespace protobuf
+#endif // SWIG
+
+// @@protoc_insertion_point(global_scope)
+
+#endif // PROTOBUF_ql2_2eproto__INCLUDED
diff --git a/external/glim/raii.hpp b/external/glim/raii.hpp
new file mode 100644
index 000000000..a09d35776
--- /dev/null
+++ b/external/glim/raii.hpp
@@ -0,0 +1,34 @@
+#include <functional>
+namespace glim {
+
+// http://stackoverflow.com/questions/2121607/any-raii-template-in-boost-or-c0x/
+
+/// RAII helper. Keeps the functor and runs it in the destructor.
+/// Example: \code auto unmap = raiiFun ([&]() {munmap (fd, size);}); \endcode
+template<typename Fun> struct RAIIFun {
+ Fun _fun;
+ RAIIFun (RAIIFun&&) = default;
+ RAIIFun (const RAIIFun&) = default;
+ template<typename FunArg> RAIIFun (FunArg&& fun): _fun (std::forward<Fun> (fun)) {}
+ ~RAIIFun() {_fun();}
+};
+
+/// The idea to name it `finally` comes from http://www.codeproject.com/Tips/476970/finally-clause-in-Cplusplus.
+/// Example: \code finally unmap ([&]() {munmap (fd, size);}); \endcode
+typedef RAIIFun<std::function<void(void)>> finally;
+
+/// Runs the given functor when going out of scope.
+/// Example: \code
+/// auto closeFd = raiiFun ([&]() {close (fd);});
+/// auto unmap = raiiFun ([&]() {munmap (fd, size);});
+/// \endcode
+template<typename Fun> RAIIFun<Fun> raiiFun (const Fun& fun) {return RAIIFun<Fun> (fun);}
+
+/// Runs the given functor when going out of scope.
+/// Example: \code
+/// auto closeFd = raiiFun ([&]() {close (fd);});
+/// auto unmap = raiiFun ([&]() {munmap (fd, size);});
+/// \endcode
+template<typename Fun> RAIIFun<Fun> raiiFun (Fun&& fun) {return RAIIFun<Fun> (std::move (fun));}
+
+}
diff --git a/external/glim/runner.hpp b/external/glim/runner.hpp
new file mode 100644
index 000000000..57c7e5248
--- /dev/null
+++ b/external/glim/runner.hpp
@@ -0,0 +1,402 @@
+#ifndef _GLIM_RUNNER_INCLUDED
+#define _GLIM_RUNNER_INCLUDED
+
+#include <algorithm> // min
+#include <atomic>
+#include <condition_variable>
+#include <chrono>
+#include <functional>
+#include <mutex>
+#include <memory>
+#include <stdexcept>
+#include <thread>
+#include <unordered_map>
+
+#include <curl/curl.h>
+#include <event2/event.h> // cf. hiperfifo.cpp at http://article.gmane.org/gmane.comp.web.curl.library/37752
+
+#include <boost/intrusive_ptr.hpp>
+#include <boost/lockfree/queue.hpp> // http://www.boost.org/doc/libs/1_53_0/doc/html/boost/lockfree/queue.html
+#include <boost/log/trivial.hpp>
+
+#include <time.h>
+#include <stdlib.h> // rand
+#include <sys/eventfd.h>
+
+#include "gstring.hpp"
+#include "exception.hpp"
+
+namespace glim {
+
+/// Listens to messages returned by `curl_multi_info_read`.
+/// NB: When CURL is queued with `addToCURLM` the CURL's `CURLOPT_PRIVATE` must point to the instance of `CurlmInformationListener`.
+struct CurlmInformationListener {
+ enum FreeOptions {REMOVE_CURL_FROM_CURLM = 1, CURL_CLEANUP = 2, DELETE_LISTENER = 4, REMOVE_CLEAN_DELETE = 1|2|4};
+ virtual FreeOptions information (CURLMsg*, CURLM*) = 0;
+ virtual ~CurlmInformationListener() {}
+};
+
+/// Listener deferring to a lambda.
+struct FunCurlmLisneter: public glim::CurlmInformationListener {
+ std::function <void(CURLMsg*, CURLM*)> _fun;
+ FreeOptions _freeOptions;
+ FunCurlmLisneter (std::function <void(CURLMsg*, CURLM*)>&& fun, FreeOptions freeOptions): _fun (std::move (fun)), _freeOptions (freeOptions) {}
+ virtual FreeOptions information (CURLMsg* msg, CURLM* curlm) override {
+ if (__builtin_expect ((bool) _fun, 1))
+ try {_fun (msg, curlm);} catch (const std::exception& ex) {BOOST_LOG_TRIVIAL (error) << "FunCurlmLisneter] " << ex.what();}
+ return _freeOptions;
+ }
+};
+
+/// Running cURL jobs in a single thread.
+/// NB: The RunnerV2 *must* be allocated with `boost::intrusive_ptr` (typically you'd use `RunnerV2::instance()`).
+class RunnerV2 {
+ std::atomic_int_fast32_t _references {0}; // For intrusive_ptr.
+ CURLM* _multi = nullptr; ///< Initialized in `run`. Should not be used outside of it.
+ int _eventFd = 0; ///< Used to give the `curl_multi_wait` some work when there's no cURL descriptors and to wake it from `withCURLM`.
+ boost::lockfree::queue<CURL*, boost::lockfree::capacity<64>> _queue; ///< `CURL` handles waiting to be added to `CURL_MULTI`.
+ std::thread _thread;
+ std::atomic_bool _running {false}; /// True if the `_thread` is running.
+
+ using FreeOptions = CurlmInformationListener::FreeOptions;
+
+ friend inline void intrusive_ptr_add_ref (RunnerV2*);
+ friend inline void intrusive_ptr_release (RunnerV2*);
+
+ void run() noexcept {
+ try {
+ if (__builtin_expect (_references <= 0, 0)) GTHROW ("RunnerV2] Must be allocated with boost::intrusive_ptr!");
+ _running = true; // NB: _running only becomes true if we're in the intrusive_ptr. ^^
+ pthread_setname_np (pthread_self(), "Runner");
+ _multi = curl_multi_init(); if (__builtin_expect (_multi == nullptr, 0)) GTHROW ("!curl_multi_init");
+ _eventFd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK); // Used to pause `curl_multi_wait` when there's no other jobs.
+ if (__builtin_expect (_eventFd == -1, 0)) GTHROW (std::string ("eventfd: ") + ::strerror (errno));
+ while (__builtin_expect (_references > 0, 0)) {
+ // Reset the CURL_EVENT_FD value to 0, so that the `curl_multi_wait` can sleep.
+ if (__builtin_expect (_eventFd > 0, 1)) {eventfd_t count = 0; eventfd_read (_eventFd, &count);}
+
+ // Add the queued CURL handles to our CURLM.
+ CURL* easy = nullptr; while (_queue.pop (easy)) curl_multi_add_handle (_multi, easy);
+
+ // Run the cURL.
+ int runningHandles = 0;
+ CURLMcode rc = curl_multi_perform (_multi, &runningHandles); // http://curl.haxx.se/libcurl/c/curl_multi_perform.html
+ if (__builtin_expect (rc != CURLM_OK, 0)) BOOST_LOG_TRIVIAL (error) << "Runner] curl_multi_perform: " << curl_multi_strerror (rc);
+
+ // Process the finished handles.
+ for (;;) {
+ int messagesLeft = 0; CURLMsg* msg = curl_multi_info_read (_multi, &messagesLeft); if (msg) try {
+ CURL* curl = msg->easy_handle; CurlmInformationListener* listener = 0;
+ if (__builtin_expect (curl_easy_getinfo (curl, CURLINFO_PRIVATE, &listener) == CURLE_OK, 1)) {
+ using FOP = CurlmInformationListener::FreeOptions;
+ FOP fop = listener->information (msg, _multi);
+ if (fop & FOP::REMOVE_CURL_FROM_CURLM) curl_multi_remove_handle (_multi, curl);
+ if (fop & FOP::CURL_CLEANUP) curl_easy_cleanup (curl);
+ if (fop & FOP::DELETE_LISTENER) delete listener;
+ } else {
+ curl_multi_remove_handle (_multi, curl);
+ curl_easy_cleanup (curl);
+ }
+ } catch (const std::exception& ex) {BOOST_LOG_TRIVIAL (error) << "Runner] " << ex.what();}
+ if (messagesLeft == 0) break;
+ }
+
+ // Wait on the cURL file descriptors.
+ int descriptors = 0;
+ curl_waitfd waitfd = {_eventFd, CURL_WAIT_POLLIN, 0};
+ eventfd_t eValue = 0; eventfd_read (_eventFd, &eValue); // Reset the curlEventFd value to zero.
+ rc = curl_multi_wait (_multi, &waitfd, 1, 100, &descriptors); // http://curl.haxx.se/libcurl/c/curl_multi_wait.html
+ if (__builtin_expect (rc != CURLM_OK, 0)) BOOST_LOG_TRIVIAL (error) << "Runner] curl_multi_wait: " << curl_multi_strerror (rc);
+ }
+ } catch (const std::exception& ex) {BOOST_LOG_TRIVIAL (error) << "Runner] " << ex.what();}
+ // Delayed destruction: when we're in intrusive_ptr (_running == true) but no longer referenced.
+ if (_running && _references == 0) delete this; // http://www.parashift.com/c++-faq-lite/delete-this.html
+ else _running = false;
+ }
+public:
+ RunnerV2() {
+ // Start a thread using CURLM in a thread-safe way (that is, from this single thread only).
+ // NB: Handles *can* be passed between threads: http://article.gmane.org/gmane.comp.web.curl.library/33188
+ _thread = std::thread (&RunnerV2::run, this);
+ }
+ ~RunnerV2() {
+ _thread.detach();
+ }
+
+ /// A singletone instance of the Runner used in order for different programes to reuse the same cURL thread.
+ static boost::intrusive_ptr<RunnerV2>& instance() {
+ static boost::intrusive_ptr<RunnerV2> INSTANCE (new RunnerV2());
+ return INSTANCE;
+ }
+
+ /// Schedule a CURL handler to be executed in the cURL thread.
+ /// NB: If the handle have a `CURLOPT_PRIVATE` option then it MUST point to an instance of `CurlmInformationListener`.
+ void addToCURLM (CURL* easyHandle) {
+ if (__builtin_expect (!_queue.push (easyHandle), 0)) GTHROW ("Can't push CURL* into the queue.");
+ if (__builtin_expect (_eventFd > 0, 1)) eventfd_write (_eventFd, 1); // Will wake the `curl_multi_wait` up, in order to run the `curl_multi_add_handle`.
+ }
+
+ /// Schedule a CURL handler to be executed in the cURL thread.
+ /// NB: `CURLOPT_PRIVATE` is overwritten with a pointer to `FunCurlmLisneter`.
+ void addToCURLM (CURL* easyHandle, std::function <void(CURLMsg*, CURLM*)>&& listener,
+ FreeOptions freeOptions = static_cast<FreeOptions> (FreeOptions::REMOVE_CURL_FROM_CURLM | FreeOptions::DELETE_LISTENER)) {
+ FunCurlmLisneter* funListener = new FunCurlmLisneter (std::move (listener), freeOptions); // Will be deleted by the Runner.
+ curl_easy_setopt (easyHandle, CURLOPT_PRIVATE, funListener); // Tells `addToCURLM` to call this listener later.
+ addToCURLM (easyHandle);
+ }
+};
+
+inline void intrusive_ptr_add_ref (RunnerV2* runner) {++ runner->_references;}
+inline void intrusive_ptr_release (RunnerV2* runner) {if (-- runner->_references == 0 && !runner->_running) delete runner;}
+
+/// Run CURLM requests and completion handlers, as well as other periodic jobs.
+class Runner {
+ G_DEFINE_EXCEPTION (RunnerEx);
+ /// Free CURL during stack unwinding.
+ struct FreeCurl {
+ Runner* runner; CURL* curl;
+ FreeCurl (Runner* runner, CURL* curl): runner (runner), curl (curl) {}
+ ~FreeCurl() {
+ runner->_handlers.erase (curl);
+ curl_multi_remove_handle (runner->_curlm, curl);
+ curl_easy_cleanup (curl);
+ }
+ };
+ public:
+ struct JobInfo;
+ /// The job must return `true` if Runner is to continue invoking it.
+ typedef std::function<bool(JobInfo& jobInfo)> job_t;
+ struct JobInfo {
+ job_t job;
+ float pauseSec = 1.0f;
+ struct timespec ran = {0, 0};
+ };
+protected:
+ typedef std::function<void(CURLMsg*)> handler_t;
+ typedef std::function<void(const char* error)> errlog_t;
+ std::shared_ptr<struct event_base> _evbase;
+ errlog_t _errlog;
+ std::recursive_mutex _mutex;
+ typedef std::unique_ptr<struct event, void(*)(struct event*)> event_t;
+ std::unordered_map<CURL*, std::pair<handler_t, event_t>> _handlers;
+ /// Functions to run periodically.
+ typedef std::unordered_map<gstring, JobInfo> jobs_map_t;
+ jobs_map_t _jobs;
+ CURLM* _curlm = nullptr;
+ struct event* _timer = nullptr;
+
+ /// Schedule a function to be run on the event loop. Useful to run all cURL methods on the single event loop thread.
+ template<typename F>
+ void doInEv (F fun, struct timeval after = {0, 0}) {
+ struct Dugout {F fun; struct event* timer; Dugout (F&& fun): fun (std::move (fun)), timer (nullptr) {}} *dugout = new Dugout (std::move (fun));
+ event_callback_fn cb = [](evutil_socket_t, short, void* dugout_)->void {
+ Dugout* dugout = static_cast<Dugout*> (dugout_);
+ event_free (dugout->timer); dugout->timer = nullptr;
+ F fun = std::move (dugout->fun); delete dugout;
+ fun();
+ };
+ dugout->timer = evtimer_new (_evbase.get(), cb, dugout);
+ evtimer_add (dugout->timer, &after);
+ }
+
+ bool shouldRun (jobs_map_t::value_type& entry, const struct timespec& ct) {
+ JobInfo& jobInfo = entry.second;
+ if (jobInfo.pauseSec <= 0.f) return true; // Run always.
+ if (jobInfo.ran.tv_sec == 0) {jobInfo.ran = ct; return true;}
+ float delta = (float)(ct.tv_sec - jobInfo.ran.tv_sec);
+ delta += (float)(ct.tv_nsec - jobInfo.ran.tv_nsec) / 1000000000.0f;
+ if (delta >= jobInfo.pauseSec) {jobInfo.ran = ct; return true;}
+ return false;
+ }
+
+ /// Used for debugging.
+ static uint64_t ms() {
+ return std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::system_clock::now().time_since_epoch()) .count();
+ }
+ /// Tells CURL to check its sockets.
+ void callCurlWithTimeout() {
+ //std::cout << __LINE__ << ',' << ms() << ": callCurlWithTimeout" << std::endl;
+ int running_handles = 0;
+ CURLMcode rc = curl_multi_socket_action (_curlm, CURL_SOCKET_TIMEOUT, 0, &running_handles);
+ if (rc != CURLM_OK) {GSTRING_ON_STACK (err, 256) << "glim::Runner: curl_multi_socket_action: " << curl_multi_strerror (rc); _errlog (err.c_str());}
+ }
+
+ /// Should only be run when the _mutex is locked.
+ void checkForFinishedCurlJobs() {
+ //std::cout << __LINE__ << ',' << ms() << ": checkForFinishedCurlJobs" << std::endl;
+ nextMessage:
+ int msgs_in_queue = 0;
+ CURLMsg* msg = curl_multi_info_read (_curlm, &msgs_in_queue);
+ if (msg) try {
+ auto curl = msg->easy_handle;
+ FreeCurl freeCurl (this, curl);
+ auto it = _handlers.find (curl);
+ if (it != _handlers.end()) it->second.first (msg);
+ if (msgs_in_queue > 0) goto nextMessage;
+ } catch (const std::exception& ex) {
+ char eBuf[512]; gstring err (sizeof(eBuf), eBuf, false, 0);
+ err << "glim::Runner: handler: " << ex.what();
+ _errlog (err.c_str());
+ }
+ }
+ /// Will reset the timer unless there is a shorter timer already set.
+ void restartTimer (uint32_t nextInMicro = 100000) { // 100ms = 100000µs
+ struct timeval tv;
+ if (event_pending (_timer, EV_TIMEOUT, &tv) && !tv.tv_sec && tv.tv_usec < nextInMicro) return; // Already have a shorter timeout.
+ tv = {0, nextInMicro};
+ evtimer_add (_timer, &tv);
+ }
+ static void evTimerCB (evutil_socket_t, short, void* runner_) {
+ //std::cout << __LINE__ << ',' << ms() << ": evTimerCB" << std::endl;
+ Runner* runner = (Runner*) runner_;
+ runner->callCurlWithTimeout();
+ runner->run();
+ }
+ /// event_callback_fn: There is an activity on a socket we are monitoring for CURL.
+ static void evSocketCB (evutil_socket_t sock, short events, void* runner_) {
+ //std::cout << __LINE__ << ',' << ms() << ": evSocketCB; sock: " << sock << "; events: " << events << std::endl;
+ Runner* runner = (Runner*) runner_;
+ int ev_bitmask = (events & EV_READ ? CURL_CSELECT_IN : 0) | (events & EV_WRITE ? CURL_CSELECT_OUT : 0);
+ int running_handles = 0;
+ CURLMcode rc = curl_multi_socket_action (runner->_curlm, sock, ev_bitmask, &running_handles);
+ if (rc != CURLM_OK) {GSTRING_ON_STACK (err, 256) << "glim::Runner: curl_multi_socket_action: " << curl_multi_strerror (rc); runner->_errlog (err.c_str());}
+ }
+ static void deleteEvent (struct event* ev) {
+ //std::cout << __LINE__ << ',' << ms() << ": deleteEvent: " << ev << std::endl;
+ event_del (ev); event_free (ev);
+ };
+ /// curl_socket_callback: CURL asks us to monitor the socket.
+ static int curlSocketCB (CURL* easy, curl_socket_t sock, int what, void* runner_, void* socketp) {
+ //std::cout << __LINE__ << ',' << ms() << ": curlSocketCB; sock: " << sock << "; what: " << what;
+ //std::cout << " (" << (what == 0 ? "none" : what == 1 ? "in" : what == 2 ? "out" : what == 3 ? "inout" : what == 4 ? "remove" : "?") << ")" << std::endl;
+ Runner* runner = (Runner*) runner_;
+ std::lock_guard<std::recursive_mutex> lock (runner->_mutex);
+ if (what & CURL_POLL_REMOVE) {
+ auto it = runner->_handlers.find (easy); if (it != runner->_handlers.end()) it->second.second.reset();
+ // We can't run `checkForFinishedCurlJobs` from there or bad things would happen
+ // (`curl_multi_remove_handle` will be called while we are still in the `curl_multi_socket_action`),
+ // but we can schedule the check via the libevent timer.
+ runner->restartTimer (0);
+ } else {
+ auto it = runner->_handlers.find (easy); if (it != runner->_handlers.end() && !it->second.second) {
+ event_callback_fn cb = evSocketCB;
+ struct event* ev = event_new (runner->_evbase.get(), sock, EV_READ | EV_WRITE | EV_ET | EV_PERSIST, cb, runner);
+ event_add (ev, nullptr);
+ //std::cout << __LINE__ << ',' << ms() << ": new event: " << ev << std::endl;
+ it->second.second = event_t (ev, deleteEvent);
+ }
+ }
+ return 0;
+ }
+ /// curl_multi_timer_callback: Schedule a CURL timer event or if `timeout_ms` is 0 then run immediately.
+ static int curlTimerCB (CURLM* multi, long timeout_ms, void* runner_) {
+ //std::cout << __LINE__ << ',' << ms() << ": curlTimerCB; timeout_ms: " << timeout_ms << std::endl;
+ if (timeout_ms == -1) return 0; // CURL tells us it doesn't need no timer.
+ Runner* runner = (Runner*) runner_;
+ if (timeout_ms == 0) { // CURL tells us it wants to run NOW.
+ runner->callCurlWithTimeout();
+ return 0;
+ }
+ // CURL asks us to run it `timeout_ms` from now.
+ runner->restartTimer (std::min ((uint32_t) timeout_ms, (uint32_t) 100) * 1000); // We wait no more than 100ms.
+ return 0;
+ }
+public:
+ Runner (std::shared_ptr<struct event_base> evbase, errlog_t errlog): _evbase (evbase), _errlog (errlog) {
+ doInEv ([this]() {
+ std::lock_guard<std::recursive_mutex> lock (_mutex);
+ _curlm = curl_multi_init(); if (!_curlm) GNTHROW (RunnerEx, "!curl_multi_init");
+ auto check = [this](CURLMcode rc) {if (rc != CURLM_OK) {curl_multi_cleanup (_curlm); GNTHROW (RunnerEx, "curl_multi_setopt: " + std::to_string (rc));}};
+ check (curl_multi_setopt (_curlm, CURLMOPT_SOCKETDATA, this));
+ curl_socket_callback socketCB = curlSocketCB; check (curl_multi_setopt (_curlm, CURLMOPT_SOCKETFUNCTION, socketCB));
+ check (curl_multi_setopt (_curlm, CURLMOPT_TIMERDATA, this));
+ curl_multi_timer_callback curlTimerCB_ = curlTimerCB; check (curl_multi_setopt (_curlm, CURLMOPT_TIMERFUNCTION, curlTimerCB_));
+ event_callback_fn evTimerCB_ = evTimerCB; _timer = evtimer_new (_evbase.get(), evTimerCB_, this);
+ restartTimer();
+ });
+ }
+ ~Runner() {
+ //std::cout << __LINE__ << ',' << ms() << ": ~Runner" << std::endl;
+ std::lock_guard<std::recursive_mutex> lock (_mutex);
+ if (_timer) {evtimer_del (_timer); event_free (_timer); _timer = nullptr;}
+ doInEv ([curlm = _curlm, handlers = std::move (_handlers)]() {
+ for (auto it = handlers.begin(), end = handlers.end(); it != end; ++it) {
+ curl_multi_remove_handle (curlm, it->first);
+ curl_easy_cleanup (it->first);
+ }
+ if (curlm) {curl_multi_cleanup (curlm);}
+ });
+ _curlm = nullptr;
+ }
+
+ /** Turns HTTP Pipelining on (or off).
+ * See http://curl.haxx.se/libcurl/c/curl_multi_setopt.html#CURLMOPTPIPELINING */
+ Runner& pipeline (long enabled = 1) {
+ CURLMcode rc = curl_multi_setopt (_curlm, CURLMOPT_PIPELINING, enabled);
+ if (rc != CURLM_OK) GNTHROW (RunnerEx, "curl_multi_setopt: " + std::to_string (rc));
+ return *this;
+ }
+
+ /// Wait for the operation to complete, then call the `handler`, then free the `curl`.
+ void multi (CURL* curl, handler_t handler) {
+ { std::lock_guard<std::recursive_mutex> lock (_mutex);
+ _handlers.insert (std::make_pair (curl, std::make_pair (std::move (handler), event_t (nullptr, nullptr)))); }
+ doInEv ([this,curl]() {
+ curl_multi_add_handle (_curlm, curl);
+ });
+ }
+ /// Register a new job to be run on the thread loop.
+ JobInfo& job (const gstring& name) {
+ std::lock_guard<std::recursive_mutex> lock (_mutex);
+ return _jobs[name];
+ }
+ /// Register a new job to be run on the thread loop.
+ void schedule (const gstring& name, float pauseSec, job_t job) {
+ struct timespec ct; if (pauseSec > 0.f) clock_gettime (CLOCK_MONOTONIC, &ct);
+ std::lock_guard<std::recursive_mutex> lock (_mutex);
+ JobInfo& jobInfo = _jobs[name];
+ jobInfo.job = job;
+ jobInfo.pauseSec = pauseSec;
+ if (pauseSec > 0.f) jobInfo.ran = ct; // If we need a pause then we also need to know when the job was scheduled.
+ }
+ /// Register a new job to be run on the thread loop.
+ void schedule (float pauseSec, job_t job) {
+ // Find a unique job name.
+ anotherName:
+ GSTRING_ON_STACK (name, 64) << "job" << rand();
+ if (_jobs.find (name) != _jobs.end()) goto anotherName;
+ schedule (name, pauseSec, std::move (job));
+ }
+ void removeJob (const gstring& name) {
+ std::lock_guard<std::recursive_mutex> lock (_mutex);
+ _jobs.erase (name);
+ }
+ /// Invoked automatically from a libevent timer; can also be invoked manually.
+ void run() {
+ _mutex.lock();
+ checkForFinishedCurlJobs();
+ // Run non-CURL jobs. Copy jobs into a local array in order not to run them with the `_mutex` locked.
+ struct timespec ct; clock_gettime (CLOCK_MONOTONIC, &ct);
+ JobInfo jobs[_jobs.size()]; gstring jobNames[_jobs.size()]; int jn = -1; {
+ for (auto it = _jobs.begin(), end = _jobs.end(); it != end; ++it) if (shouldRun (*it, ct)) {
+ ++jn; jobNames[jn] = it->first; jobs[jn] = it->second;
+ } }
+ _mutex.unlock();
+
+ for (; jn >= 0; --jn) try {
+ if (!jobs[jn].job (jobs[jn])) removeJob (jobNames[jn]);
+ } catch (const std::exception& ex) {
+ char eBuf[512]; gstring err (sizeof(eBuf), eBuf, false, 0);
+ err << "glim::Runner: error in job " << jobNames[jn] << ": " << ex.what();
+ _errlog (err.c_str());
+ }
+ restartTimer();
+ }
+
+ /// Expose CURLM. Useful for curl_multi_setopt (http://curl.haxx.se/libcurl/c/curl_multi_setopt.html).
+ CURLM* curlm() const {return _curlm;}
+};
+
+} // namespace glim
+
+#endif // _GLIM_RUNNER_INCLUDED
diff --git a/external/glim/sqlite.hpp b/external/glim/sqlite.hpp
new file mode 100644
index 000000000..c7e92ac4a
--- /dev/null
+++ b/external/glim/sqlite.hpp
@@ -0,0 +1,538 @@
+#ifndef GLIM_SQLITE_HPP_
+#define GLIM_SQLITE_HPP_
+
+/**
+ * A threaded interface to <a href="http://sqlite.org/">SQLite</a>.
+ * This file is a header-only library,
+ * whose sole dependencies should be standard STL and posix threading libraries.
+ * You can extract this file out of the "glim" library to include it separately in your project.
+ * @code
+Copyright 2006-2012 Kozarezov Artem Aleksandrovich
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ * @endcode
+ * @file
+ */
+
+#include <stdexcept>
+#include <string>
+#include <sqlite3.h>
+#include <pthread.h>
+#include <string.h> // strerror
+#include <sys/types.h> // stat
+#include <sys/stat.h> // stat
+#include <unistd.h> // stat
+#include <errno.h> // stat
+#include <stdio.h> // snprintf
+#include <stdint.h>
+
+namespace glim {
+
+class SqliteSession;
+class SqliteQuery;
+
+struct SqliteEx: public std::runtime_error {
+ SqliteEx (const std::string& what): std::runtime_error (what) {}
+};
+
+/**
+ * The database.
+ * According to sqlite3_open <a href="http://sqlite.org/capi3ref.html#sqlite3_open">documentation</a>,
+ * only the thread that opened the database can safely access it. This restriction was
+ * relaxed, as described in the <a href="http://www.sqlite.org/faq.html#q8">FAQ</a>
+ * (the "Is SQLite threadsafe?" question), so we can use the library from multiple
+ * threads, but only if no more than one thread at a time accesses the database.
+ * This restriction is, in fact, beneficial if the database is used from a single application:
+ * by restricting access to a sigle thread at a time, we effectively avoid all deadlock issues.\n
+ * This library goals are:\n
+ * \li to ensure that SQLite is used in a thread-safe way,
+ * \li to provide additional threaded quirks, such as delayed updates (not implemented).
+ *
+ * The library is targeted at SQLite setup which is \b not \c -DTHREADSAFE,
+ * since this is the default setup on UNIX architectures.\n
+ * \n
+ * This file is a header-only library,
+ * whose sole dependencies should be standard STL and posix threading libraries.
+ * You can extract this file out of the "glim" library to include it separately in your project.\n
+ * \n
+ * This library is targeted at UTF-8 API. There is no plans to support the UTF-16 API.\n
+ * \n
+ * See also:\n
+ * \li http://www.sqlite.org/cvstrac/fileview?f=sqlite/src/server.c\n
+ * for another way of handling multithreading with SQLite.
+ */
+class Sqlite {
+ /// No copying allowed.
+ Sqlite& operator = (const Sqlite& other) {return *this;}
+ /// No copying allowed.
+ Sqlite (const Sqlite& other) = delete;
+ friend class SqliteSession;
+ protected:
+ /// Filename the database was opened with; we need it to reopen the database on fork()s.
+ /// std::string is used to avoid memory allocation issues.
+ std::string filename;
+ ::sqlite3* handler;
+ ::pthread_mutex_t mutex;
+ public:
+ /// Flags for the Sqlite constructor.
+ enum Flags {
+ /**
+ * The file will be checked for existence.
+ * SqliteEx is thrown if the file is not accessible;
+ * format of the error description is "$filename: $strerror".\n
+ * Usage example: \code Sqlite db ("filename", Sqlite::existing); \endcode
+ */
+ existing = 1
+ };
+ /**
+ * Opens the database.
+ * @param filename Database filename (UTF-8).
+ * @param flags Optional. Currently there is the #existing flag.
+ * @throws SqliteEx Thrown if we can't open the database.
+ */
+ Sqlite (std::string filename, int flags = 0) {
+ if (flags & existing) {
+ // Check if the file exists already.
+ struct stat st; if (stat (filename.c_str(), &st))
+ throw SqliteEx (filename + ": " + ::strerror(errno));
+ }
+ ::pthread_mutex_init (&mutex, NULL);
+ this->filename = filename;
+ if (::sqlite3_open(filename.c_str(), &handler) != SQLITE_OK)
+ throw SqliteEx (std::string("sqlite3_open(") + filename + "): " + ::sqlite3_errmsg(handler));
+ }
+ /**
+ * Closes the database.
+ * @throws SqliteEx Thrown if we can't close the database.
+ */
+ ~Sqlite () {
+ ::pthread_mutex_destroy (&mutex);
+ if (::sqlite3_close(handler) != SQLITE_OK)
+ throw SqliteEx (std::string ("sqlite3_close(): ") + ::sqlite3_errmsg(handler));
+ }
+
+ Sqlite& exec (const char* query);
+ /**
+ * Invokes `exec` on `query.c_str()`.
+ * Example:\code
+ * glim::Sqlite sqlite (":memory:");
+ * for (std::string pv: {"page_size = 4096", "secure_delete = 1"}) sqlite->exec2 ("PRAGMA " + pv); \endcode
+ */
+ template <typename StringLike> Sqlite& exec2 (StringLike query) {return exec (query.c_str());}
+};
+
+/**
+ * A single thread session with Sqlite.
+ * Only a sigle thread at a time can have an SqliteSession,
+ * all other threads will wait, in the SqliteSession constructor,
+ * till the active session is either closed or destructed.
+ */
+class SqliteSession {
+ /// No copying allowed.
+ SqliteSession& operator = (const SqliteSession& other) {return *this;}
+ /// No copying allowed.
+ SqliteSession(SqliteSession& other): db (NULL) {}
+ protected:
+ Sqlite* db;
+ public:
+ /**
+ * Locks the database.
+ * @throws SqliteEx if a mutex error occurs.
+ */
+ SqliteSession (Sqlite* sqlite): db (sqlite) {
+ int err = ::pthread_mutex_lock (&(db->mutex));
+ if (err != 0) throw SqliteEx (std::string ("error locking the mutex: ") + ::strerror(err));
+ }
+ /**
+ * A shorter way to construct query from the session.
+ * Usage example: \code ses.query(S("create table test (i integer)")).step() \endcode
+ * @see SqliteQuery#qstep
+ */
+ template <typename T>
+ SqliteQuery query (T t);
+ /// Automatically unlocks the database.
+ /// @see close
+ ~SqliteSession () {close();}
+ /**
+ * Unlock the database.
+ * It is safe to call this method multiple times.\n
+ * You must not use the session after it was closed.\n
+ * All resources allocated within this session must be released before the session is closed.
+ * @throws SqliteEx if a mutex error occurs.
+ */
+ void close () {
+ if (db == NULL) return;
+ int err = ::pthread_mutex_unlock (&(db->mutex));
+ db = NULL;
+ if (err != 0) throw SqliteEx (std::string ("error unlocking the mutex: ") + ::strerror(err));
+ }
+ /// True if the \c close method has been already called on this SqliteSession.
+ bool isClosed () const {
+ return db == NULL;
+ }
+ /**
+ * This class can be used in place of the SQLite handler.
+ * Make sure you've released any resources thus manually acquired before this SqliteSession is closed.
+ * Usage example:
+ * @code
+ * glim::Sqlite db (":memory:");
+ * glim::SqliteSession ses (&db);
+ * sqlite3_exec (ses, "PRAGMA page_size = 4096;", NULL, NULL, NULL);
+ * @endcode
+ */
+ operator ::sqlite3* () const {return db->handler;}
+};
+
+/**
+ * Execute the given query, throwing SqliteEx on failure.\n
+ * Example:\code
+ * glim::Sqlite sqlite (":memory:");
+ * sqlite.exec ("PRAGMA page_size = 4096") .exec ("PRAGMA secure_delete = 1"); \endcode
+ */
+inline Sqlite& Sqlite::exec (const char* query) {
+ SqliteSession ses (this); // Maintains the locks.
+ char* errmsg = NULL; ::sqlite3_exec (handler, query, NULL, NULL, &errmsg);
+ if (errmsg) throw SqliteEx (std::string ("Sqlite::exec, error in query (") + query + "): " + errmsg);
+ return *this;
+}
+
+/**
+ * Wraps the sqlite3_stmt; will prepare it, bind values, query and finalize.
+ */
+class SqliteQuery {
+ protected:
+ ::sqlite3_stmt* statement;
+ SqliteSession* session;
+ int bindCounter;
+ /// -1 if statement isn't DONE.
+ int mChanges;
+ void prepare (SqliteSession* session, char const* query, int queryLength) {
+ ::sqlite3* handler = *session;
+ if (::sqlite3_prepare_v2 (handler, query, queryLength, &statement, NULL) != SQLITE_OK)
+ throw SqliteEx (std::string(query, queryLength) + ": " + ::sqlite3_errmsg(handler));
+ }
+ /** Shan't copy. */
+ SqliteQuery (const SqliteQuery& other) = delete;
+ public:
+ SqliteQuery (SqliteQuery&& rvalue) {
+ statement = rvalue.statement;
+ session = rvalue.session;
+ bindCounter = rvalue.bindCounter;
+ mChanges = rvalue.mChanges;
+ rvalue.statement = nullptr;
+ }
+ /**
+ * Prepares the query.
+ * @throws SqliteEx if sqlite3_prepare fails; format of the error message is "$query: $errmsg".
+ */
+ SqliteQuery (SqliteSession* session, char const* query, int queryLength)
+ : statement (NULL), session (session), bindCounter (0), mChanges (-1) {
+ prepare (session, query, queryLength);
+ }
+ /**
+ * Prepares the query.
+ * @throws SqliteEx if sqlite3_prepare fails; format of the error message is "$query: $errmsg".
+ */
+ SqliteQuery (SqliteSession* session, std::pair<char const*, int> query)
+ : statement (NULL), session (session), bindCounter (0), mChanges (-1) {
+ prepare (session, query.first, query.second);
+ }
+ /**
+ * Prepares the query.
+ * @throws SqliteEx if sqlite3_prepare fails; format of the error message is "$query: $errmsg".
+ */
+ SqliteQuery (SqliteSession* session, std::string query)
+ : statement (NULL), session (session), bindCounter (0), mChanges (-1) {
+ prepare (session, query.c_str(), query.length());
+ }
+ /**
+ * Release resources.
+ * @see http://sqlite.org/capi3ref.html#sqlite3_finalize
+ */
+ ~SqliteQuery () {
+ if (statement) ::sqlite3_finalize (statement);
+ }
+
+ /// Call this (followed by the #step) if you need the query to be re-executed.
+ /// @see http://sqlite.org/capi3ref.html#sqlite3_reset
+ SqliteQuery& reset () {
+ bindCounter = 0;
+ mChanges = -1;
+ ::sqlite3_reset (statement);
+ return *this;
+ }
+
+ /// Synonym for #step.
+ bool next () {return step();}
+ /**
+ * Invokes sqlite3_step.
+ * @return \c true if there was a row fetched successfully, \c false if there is no more rows.
+ * @see http://sqlite.org/capi3ref.html#sqlite3_step
+ */
+ bool step () {
+ if (mChanges >= 0) {mChanges = 0; return false;}
+ int ret = ::sqlite3_step (statement);
+ if (ret == SQLITE_ROW) return true;
+ if (ret == SQLITE_DONE) {
+ mChanges = ::sqlite3_changes (*session);
+ return false;
+ }
+ throw SqliteEx (std::string(::sqlite3_errmsg(*session)));
+ }
+ /**
+ * Perform #step and throw an exception if #step has returned \c false.
+ * Usage example:
+ * \code (ses.query(S("select count(*) from test where idx = ?")) << 12345).qstep().intAt(1) \endcode
+ */
+ SqliteQuery& qstep () {
+ if (!step())
+ throw SqliteEx (std::string("qstep: no rows returned / affected"));
+ return *this;
+ }
+ /**
+ * Invokes a DML query and returns the number of rows affected.
+ * Example: \code
+ * int affected = (ses.query(S("update test set count = count + ? where id = ?")) << 1 << 9).ustep();
+ * \endcode
+ * @see http://sqlite.org/capi3ref.html#sqlite3_step
+ */
+ int ustep () {
+ int ret = ::sqlite3_step (statement);
+ if (ret == SQLITE_DONE) {
+ mChanges = ::sqlite3_changes (*session);
+ return mChanges;
+ }
+ if (ret == SQLITE_ROW) return 0;
+ throw SqliteEx (std::string(::sqlite3_errmsg(*session)));
+ }
+
+ /**
+ * The number of rows changed by the query.
+ * Providing the query was a DML (Data Modification Language),
+ * returns the number of rows updated.\n
+ * If the query wasn't a DML, returned value is undefined.\n
+ * -1 is returned if the query wasn't executed, or after #reset.\n
+ * Example: \code
+ * SqliteQuery query (&ses, S("update test set count = count + ? where id = ?"));
+ * query.bind (1, 1);
+ * query.bind (2, 9);
+ * query.step ();
+ * int affected = query.changes ();
+ * \endcode
+ * @see #ustep
+ */
+ int changes () {return mChanges;}
+
+ /**
+ * The integer value of the given column.
+ * @param column 1-based.
+ * @see http://sqlite.org/capi3ref.html#sqlite3_column_text
+ */
+ int intAt (int column) {
+ return ::sqlite3_column_int (statement, --column);
+ }
+
+ /**
+ * The integer value of the given column.
+ * @param column 1-based.
+ * @see http://sqlite.org/capi3ref.html#sqlite3_column_text
+ */
+ sqlite3_int64 int64at (int column) {
+ return ::sqlite3_column_int64 (statement, --column);
+ }
+
+ /**
+ * The floating point number from the given column.
+ * @param column 1-based.
+ * @see http://sqlite.org/capi3ref.html#sqlite3_column_text
+ */
+ double doubleAt (int column) {
+ return ::sqlite3_column_double (statement, --column);
+ }
+
+ /**
+ * Return the column as UTF-8 characters, which can be used until the next #step.
+ * @param column 1-based.
+ * @see http://sqlite.org/capi3ref.html#sqlite3_column_text
+ */
+ std::pair<char const*, int> charsAt (int column) {
+ return std::pair<char const*, int> ((char const*) ::sqlite3_column_text (statement, column-1),
+ ::sqlite3_column_bytes (statement, column-1));
+ }
+
+ /**
+ * Return the column as C++ string (UTF-8).
+ * @param column 1-based.
+ */
+ std::string stringAt (int column) {
+ return std::string ((char const*) ::sqlite3_column_text (statement, column-1),
+ ::sqlite3_column_bytes (statement, column-1));
+ }
+
+ /**
+ * The type of the column.
+ * SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB or SQLITE_NULL.
+ * @param column 1-based.
+ * @see http://sqlite.org/capi3ref.html#sqlite3_column_text
+ */
+ int typeAt (int column) {
+ return ::sqlite3_column_type (statement, --column);
+ }
+
+ /**
+ * Binds a value using one of the bind methods.
+ */
+ template<typename T>
+ SqliteQuery& operator << (T value) {
+ return bind (++bindCounter, value);
+ }
+ /**
+ * Binds a value using the named parameter and one of the bind methods.
+ * @throws SqliteEx if the name could not be found.
+ * @see http://sqlite.org/capi3ref.html#sqlite3_bind_parameter_index
+ */
+ template<typename T>
+ SqliteQuery& bind (char const* name, T value) {
+ int index = ::sqlite3_bind_parameter_index (statement, name);
+ if (index == 0)
+ throw SqliteEx (std::string ("No such parameter in the query: ") + name);
+ return bind (index, value);
+ }
+
+ /**
+ * Bind a string to the query.
+ * @param transient must be true, if lifetime of the string might be shorter than that of the query.
+ */
+ SqliteQuery& bind (int index, const char* text, int length, bool transient = false) {
+ if (::sqlite3_bind_text (statement, index, text, length,
+ transient ? SQLITE_TRANSIENT : SQLITE_STATIC) != SQLITE_OK)
+ throw SqliteEx (std::string (::sqlite3_errmsg (*session)));
+ return *this;
+ }
+ /**
+ * Bind a string to the query.
+ * @param transient must be true, if lifetime of the string might be shorter than that of the query.
+ */
+ SqliteQuery& bind (int index, std::pair<const char*, int> text, bool transient = false) {
+ if (::sqlite3_bind_text (statement, index, text.first, text.second,
+ transient ? SQLITE_TRANSIENT : SQLITE_STATIC) != SQLITE_OK)
+ throw SqliteEx (std::string (::sqlite3_errmsg (*session)));
+ return *this;
+ }
+ /**
+ * Bind a string to the query.
+ * @param transient must be true, if lifetime of the string might be shorter than that of the query.
+ */
+ SqliteQuery& bind (int index, const std::string& text, bool transient = true) {
+ if (::sqlite3_bind_text (statement, index, text.data(), text.length(),
+ transient ? SQLITE_TRANSIENT : SQLITE_STATIC) != SQLITE_OK)
+ throw SqliteEx (std::string (::sqlite3_errmsg (*session)));
+ return *this;
+ }
+ /**
+ * Bind an integer to the query.
+ */
+ SqliteQuery& bind (int index, int value) {
+ if (::sqlite3_bind_int (statement, index, value) != SQLITE_OK)
+ throw SqliteEx (std::string (::sqlite3_errmsg (*session)));
+ return *this;
+ }
+ /**
+ * Bind an 64-bit integer to the query.
+ */
+ SqliteQuery& bind (int index, sqlite3_int64 value) {
+ if (::sqlite3_bind_int64 (statement, index, value) != SQLITE_OK)
+ throw SqliteEx (std::string (::sqlite3_errmsg (*session)));
+ return *this;
+ }
+};
+
+/**
+ * Version of SqliteQuery suitable for using SQLite in parallel with other processes.
+ * Will automatically handle the SQLITE_SCHEMA error
+ * and will automatically repeat attempts after SQLITE_BUSY,
+ * but it requires that the query string supplied
+ * is constant and available during the SqliteParQuery lifetime.
+ * Error messages, contained in exceptions, may differ from SqliteQuery by containing the query
+ * (for example, the #step method will throw "$query: $errmsg" instead of just "$errmsg").
+ */
+class SqliteParQuery: public SqliteQuery {
+ protected:
+ char const* query;
+ int queryLength;
+ int repeat;
+ int wait;
+ public:
+ /**
+ * Prepares the query.
+ * @param repeat the number of times we try to repeat the query when SQLITE_BUSY is returned.
+ * @param wait how long, in milliseconds (1/1000 of a second) we are to wait before repeating.
+ * @throws SqliteEx if sqlite3_prepare fails; format of the error message is "$query: $errmsg".
+ */
+ SqliteParQuery (SqliteSession* session, char const* query, int queryLength, int repeat = 90, int wait = 20)
+ : SqliteQuery (session, query, queryLength) {
+ this->query = query;
+ this->queryLength = queryLength;
+ this->repeat = repeat;
+ this->wait = wait;
+ }
+ /**
+ * Prepares the query.
+ * @param query the SQL query together with its length.
+ * @param repeat the number of times we try to repeat the query when SQLITE_BUSY is returned.
+ * @param wait how long, in milliseconds (1/1000 of a second) we are to wait before repeating.
+ * @throws SqliteEx if sqlite3_prepare fails; format of the error message is "$query: $errmsg".
+ */
+ SqliteParQuery (SqliteSession* session, std::pair<char const*, int> query, int repeat = 90, int wait = 20)
+ : SqliteQuery (session, query) {
+ this->query = query.first;
+ this->queryLength = query.second;
+ this->repeat = repeat;
+ this->wait = wait;
+ }
+
+ bool next () {return step();}
+ bool step () {
+ if (mChanges >= 0) {mChanges = 0; return false;}
+ repeat:
+ int ret = ::sqlite3_step (statement);
+ if (ret == SQLITE_ROW) return true;
+ if (ret == SQLITE_DONE) {
+ mChanges = ::sqlite3_changes (*session);
+ return false;
+ }
+ if (ret == SQLITE_SCHEMA) {
+ ::sqlite3_stmt* old = statement;
+ prepare (session, query, queryLength);
+ ::sqlite3_transfer_bindings(old, statement);
+ ::sqlite3_finalize (old);
+ goto repeat;
+ }
+ if (ret == SQLITE_BUSY) for (int repeat = this->repeat; ret == SQLITE_BUSY && repeat >= 0; --repeat) {
+ //struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = wait * 1000000; // nan is 10^-9 of sec.
+ //while (::nanosleep (&ts, &ts) == EINTR);
+ ::sqlite3_sleep (wait);
+ ret = ::sqlite3_step (statement);
+ }
+ throw SqliteEx (std::string(query, queryLength) + ::sqlite3_errmsg(*session));
+ }
+};
+
+template <typename T>
+SqliteQuery SqliteSession::query (T t) {
+ return SqliteQuery (this, t);
+}
+
+}; // namespace glim
+
+#endif // GLIM_SQLITE_HPP_
diff --git a/external/glim/test_cbcoro.cc b/external/glim/test_cbcoro.cc
new file mode 100644
index 000000000..f47cdac39
--- /dev/null
+++ b/external/glim/test_cbcoro.cc
@@ -0,0 +1,89 @@
+// http://en.wikipedia.org/wiki/Setcontext; man 3 makecontext; man 2 getcontext
+// http://www.boost.org/doc/libs/1_53_0/libs/context/doc/html/index.html
+// g++ -std=c++11 -O1 -Wall -g test_cbcoro.cc -pthread && ./a.out
+
+#include <glim/exception.hpp>
+#include <glim/NsecTimer.hpp>
+
+#include "cbcoro.hpp"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> // sleep
+#include <string.h> // strerror
+#include <errno.h>
+#include <functional>
+using std::function;
+#include <thread>
+#include <memory>
+using std::shared_ptr; using std::make_shared;
+#include <string>
+using std::string; using std::to_string;
+#include <iostream>
+using std::cout; using std::endl;
+
+/** A typical remote service with callback. */
+void esDelete (int frople, std::function<void(int)> cb) {
+ std::thread th ([cb,frople]() {
+ cout << "esDelete: sleeping for a second" << endl;
+ std::this_thread::sleep_for (std::chrono::seconds (1));
+ cb (frople);
+ }); th.detach();
+}
+
+struct RemoveFroples: public glim::CBCoro {
+ const char* _argument;
+ RemoveFroples (const char* argument): _argument (argument) {
+ cout << "RF: constructor" << endl;
+ }
+ virtual ~RemoveFroples() {puts ("~RemoveFroples");}
+ virtual void run() override {
+ for (int i = 1; i <= 4; ++i) {
+ cout << "RF: Removing frople " << i << "..." << endl;
+ int returnedFrople = 0;
+ yieldForCallback ([this,i,&returnedFrople]() {
+ if (i != 2) {
+ // Sometimes we use a callback.
+ esDelete (i, [this,&returnedFrople](int frople) {
+ cout << "RF,CB: frople " << frople << "." << endl;
+ returnedFrople = frople;
+ invokeFromCallback();
+ });
+ } else {
+ // Sometimes we don't use a callback.
+ returnedFrople = 0;
+ invokeFromCallback();
+ }
+ });
+ cout << "RF: Returned from callback; _returnTo is: " << (intptr_t) _returnTo << "; frople " << returnedFrople << endl;
+ }
+ cout << "RF: finish! _returnTo is: " << (intptr_t) _returnTo << endl;
+ };
+};
+
+int main() {
+ glim::cbCoro ([](glim::CBCoro* cbcoro) {
+ cout << "main: run1, thread " << std::this_thread::get_id() << endl; // Runs on the `main` thread.
+ cbcoro->yieldForCallback ([&]() {
+ std::thread callbackThread ([&]() {
+ std::this_thread::sleep_for (std::chrono::seconds (4));
+ cbcoro->invokeFromCallback();
+ }); callbackThread.detach();
+ });
+ cout << "main: run2, thread " << std::this_thread::get_id() << endl; // Runs on the `callbackThread`.
+ });
+
+ (new RemoveFroples ("argument"))->start();
+ cout << "main: returned from RemoveFroples" << endl;
+
+ glim::NsecTimer timer; const int ops = RUNNING_ON_VALGRIND ? 999 : 9999;
+ for (int i = 0; i < ops; ++i) glim::cbCoro ([](glim::CBCoro* cbcoro) {});
+ double speedEmpty = ops / timer.sec();
+ timer.restart();
+ for (int i = 0; i < ops; ++i) glim::cbCoro ([](glim::CBCoro* cbcoro) {cbcoro->yieldForCallback ([&]() {cbcoro->invokeFromCallback();});});
+ double speedImmediate = ops / timer.sec();
+
+ sleep (5);
+ cout << "speed: empty: " << speedEmpty << " o/s" << endl;
+ cout << "speed: immediate: " << speedImmediate << " o/s" << endl;
+ return 0;
+}
diff --git a/external/glim/test_exception.cc b/external/glim/test_exception.cc
new file mode 100644
index 000000000..74759f4da
--- /dev/null
+++ b/external/glim/test_exception.cc
@@ -0,0 +1,73 @@
+#define _GLIM_ALL_EXCEPTIONS_CODE
+#include "exception.hpp"
+#include <iostream>
+#include <typeinfo>
+#include <assert.h>
+
+// NB: Controlling exceptions across shared object (.so) boundaries is tested separately in frople/src/test.cpp/testExceptionControl.
+
+static void testThrowLine() {
+ int line = 0; std::string message; try {
+ line = __LINE__; GTHROW ("message");
+ } catch (const std::exception& ex) {
+ message = ex.what();
+ }
+ //std::cout << message << ' ' << std::flush;
+ assert (message.size());
+ assert (std::string (message) .find (":" + std::to_string (line)) != std::string::npos);
+
+ line = 0; message.clear(); std::string name; try {
+ line = __LINE__; G_DEFINE_EXCEPTION (FooEx); GNTHROW (FooEx, "foo");
+ } catch (const std::exception& ex) {
+ message = ex.what(); name = typeid (ex) .name();
+ }
+ //std::cout << "testThrowLine: " << message << ' ' << name << ' ' << std::flush;
+ assert (message.size());
+ assert (std::string (message) .find (":" + std::to_string (line)) != std::string::npos);
+ assert (name.find ("FooEx") != std::string::npos);
+
+ message.clear(); try {
+ glim::ExceptionControl plainWhat (glim::Exception::PLAIN_WHAT);
+ GTHROW ("bar");
+ } catch (const std::exception& ex) {
+ message = ex.what();
+ }
+ assert (message == "bar");
+ assert (glim::Exception::options() == 0);
+}
+
+static void testBacktrace() {
+ assert (glim::Exception::options() == 0);
+ glim::ExceptionControl captureTrace (glim::Exception::CAPTURE_TRACE);
+ assert (glim::Exception::options() != 0);
+ std::string message;
+ try {
+ GTHROW ("message");
+ } catch (const std::exception& ex) {
+ message = ex.what();
+ }
+ //std::cout << "testBacktrace: " << message << std::endl;
+ if (message.find ("[at bin/test_exception") == std::string::npos && message.find ("[test_exception") == std::string::npos)
+ GTHROW ("No expected string in " + message);
+}
+
+static void testAllExceptionsHack() {
+ assert (glim::Exception::options() == 0);
+ std::string traceBuf;
+ glim::ExceptionHandler traceExceptions (glim::Exception::HANDLE_ALL | glim::Exception::RENDEZVOUS, glim::captureBacktrace, &traceBuf);
+ assert (glim::Exception::options() != 0);
+ try {
+ throw "catch me"; // Catched by `_GLIM_ALL_EXCEPTIONS_CODE` and handled with `glim::ExceptionControl::backtrace`.
+ } catch (const char* skip) {}
+ //std::cout << "testAllExceptionsHack: " << std::endl << traceBuf << std::endl;
+ assert (traceBuf.size());
+}
+
+int main () {
+ std::cout << "Testing exception.hpp ... " << std::flush;
+ testThrowLine();
+ testBacktrace();
+ testAllExceptionsHack();
+ std::cout << "pass." << std::endl;
+ return 0;
+}
diff --git a/external/glim/test_gstring.cc b/external/glim/test_gstring.cc
new file mode 100644
index 000000000..974fa2932
--- /dev/null
+++ b/external/glim/test_gstring.cc
@@ -0,0 +1,131 @@
+#include "gstring.hpp"
+using glim::gstring;
+#include <assert.h>
+#include <stdlib.h>
+#include <iostream>
+#include <string>
+#include <stdexcept>
+#include <sstream>
+#include <unordered_map>
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
+
+static void testIterators();
+static void testBoost();
+static void testStrftime();
+
+int main () {
+ std::cout << "Testing gstring.hpp ... " << std::flush;
+
+ gstring gs;
+ if (gs.needsFreeing()) throw std::runtime_error ("Default gstring needsFreeing");
+ if (gs.capacity() != 1) throw std::runtime_error ("Default gstring capacity is not 1");
+ char buf16[16];
+ gstring gs16 (sizeof (buf16), buf16, false, 0);
+ if (gs16.capacity() != 16) throw std::runtime_error ("gs16 capacity != 16");
+ if (gs16.size() != 0) throw std::runtime_error ("gs16 size != 0");
+ gstring gsFree (17, NULL, true, 0);
+ if (!gsFree.needsFreeing()) throw std::runtime_error ("!needsFreeing");
+ if (gsFree.capacity() != 16) throw std::runtime_error ("gsFree capacity != 16");
+ if (gsFree.size() != 0) throw std::runtime_error ("gsFree size != 0");
+ gstring gsRO (0, NULL, false, 0);
+ if (gsRO.needsFreeing()) throw std::runtime_error ("needsFreeing");
+ if (gsRO.capacity() != 1) throw std::runtime_error ("gsRO capacity != 1");
+ if (gsRO.size() != 0) throw std::runtime_error ("gsRO size != 0");
+ char buf32[32];
+ gstring gs32 (sizeof (buf32), buf32, false, 0);
+ if (gs32.capacity() != 32) throw std::runtime_error ("capacity != 32");
+ if (gs32.size() != 0) throw std::runtime_error ("gs32 size != 0");
+ const gstring foo = C2GSTRING ("foo");
+ if (foo.needsFreeing()) throw std::runtime_error ("foo needsFreeing");
+ if (foo != "foo") throw std::runtime_error ("foo != foo");
+ if (foo.size() != 3) throw std::runtime_error ("foo not 3");
+ std::ostringstream oss; oss << gs16 << gsFree << gsRO << gs32 << foo;
+ if (oss.str() != "foo") throw std::runtime_error ("oss foo != foo");
+ glim::gstring_stream gss (gs16); std::ostream gsos (&gss);
+ gsos << "bar" << std::flush;
+ if (gs16 != "bar") throw std::runtime_error ("gs16 != bar");
+ gsos << "beer" << std::flush;
+ if (gs16 != "barbeer") throw std::runtime_error ("gs16 != barbeer");
+ gsos << "123456789" << std::flush;
+ if (gs16 != "barbeer123456789") throw std::runtime_error ("gs16 != barbeer123456789");
+ if (gs16.capacity() != 16) throw std::runtime_error ("gs16 != 16");
+ gsos << '0' << std::flush;
+ if (gs16 != "barbeer1234567890") throw std::runtime_error ("gs16 != barbeer1234567890");
+ if (gs16.capacity() != 32) throw std::runtime_error ("gs16 != 32");
+
+ gstring gsb; std::string str ("abc");
+ gsb << 'a' << 1 << 2LL << str;
+ std::string ns ("1:3,"); std::istringstream nsi (ns);
+ gsb.readNetstring (nsi);
+ if (gsb != "a12abc3") throw std::runtime_error ("gsb != a12abc3");
+ if (strcmp (gsb.c_str(), "a12abc3") != 0) throw std::runtime_error ("strcmp ! 0");
+
+ gsb.clear().appendNetstring ("foo") .appendNetstring ("bar");
+ if (gsb != "3:foo,3:bar,") throw std::runtime_error ("gsb != 3:foo,3:bar,");
+ uint32_t pos = 0;
+ if (gsb.netstringAt (pos, &pos) != "foo" || gsb.netstringAt (pos, &pos) != "bar" || pos != gsb.length())
+ throw std::runtime_error ("gsb !netstringAt");
+
+ gs32.clear() << 12345 << ',';
+ if (gs32.intAt (0, &pos) != 12345 || pos != 5) throw std::runtime_error ("gsb !12345");
+ if (gs32.intAt (1, &pos) != 2345 || pos != 5) throw std::runtime_error ("gsb !2345");
+ if (gs32.intAt (5, &pos) != 0 || pos != 5) throw std::runtime_error ("gsb !0");
+
+ if ((gs32.clear() << 123).erase (0) != "23") throw std::runtime_error ("!23");
+ if ((gs32.clear() << 123).erase (1) != "13") throw std::runtime_error ("!13");
+ if ((gs32.clear() << 123).erase (2) != "12") throw std::runtime_error ("!12");
+
+ std::unordered_map<glim::gstring, int> map;
+ map[glim::gstring ("foo")] = 1;
+ glim::gstring bar ("bar");
+ map[bar] = 1;
+ map[glim::gstring ("sum")] = map[glim::gstring ("foo")] + map[glim::gstring ("bar")];
+ if (map[glim::gstring ("sum")] != 2) throw std::runtime_error ("sum != 2");
+ map.clear();
+
+ gstring gs1 ("foo"); gstring gs2 ("bar");
+ gs1 = gstring (gs2 << "_"); // Copying in order to malloc length() bytes.
+ if (gs1 != "bar_") throw std::runtime_error ("!bar_");
+ if (gs1.capacity() != 1) throw std::runtime_error ("bar_ != 4");
+
+ testIterators();
+ testBoost();
+ testStrftime();
+
+ std::cout << "pass." << std::endl;
+ return 0;
+}
+
+static void testIterators() {
+ gstring foo (C2GSTRING ("foo"));
+ gstring buf; for (auto it = foo.begin(), end = foo.end(); it != end; ++it) buf << *it;
+ assert (buf == "foo");
+ assert (boost::starts_with (foo, "f") && boost::ends_with (foo, "oo"));
+}
+
+static void testBoost() {
+ gstring str (" foo\t\r\n");
+ boost::trim (str);
+ assert (str == "foo");
+
+ gstring up ("FOO"); boost::to_lower (up);
+ assert (up == "foo");
+}
+
+static void testStrftime() {
+ time_t tim = time(0); struct tm ltime; memset (&ltime, 0, sizeof ltime); if (!localtime_r (&tim, &ltime)) GTHROW ("!localtime_r");
+ GSTRING_ON_STACK (t1, 8); assert (t1.capacity() == 8);
+ t1.appendTime ("", &ltime); assert (t1 == "");
+ t1.appendTime ("foo %a, %d %b %Y %T %z bar", &ltime);
+ assert (t1.capacity() > 8); // Capacity increased to account for the large string.
+ assert (boost::starts_with (t1, "foo "));
+ assert (boost::ends_with (t1, " bar"));
+
+ GSTRING_ON_STACK (t2, 8); assert (t2.capacity() == 8);
+ t2.appendTime ("%H", &ltime);
+ assert (t2.capacity() == 8); // 8 is big enought, isn't it?
+ assert (t2.intAt (0) == ltime.tm_hour); // NB: intAt is safe here because strftime adds an uncounted null-terminator.
+}
diff --git a/external/glim/test_ldb.cc b/external/glim/test_ldb.cc
new file mode 100644
index 000000000..74587ae10
--- /dev/null
+++ b/external/glim/test_ldb.cc
@@ -0,0 +1,165 @@
+#include "ldb.hpp"
+using glim::Ldb;
+using glim::gstring;
+#include <iostream>
+using std::cout; using std::flush; using std::endl;
+#include <assert.h>
+#include <boost/filesystem.hpp>
+
+void test1 (Ldb& ldb) {
+ ldb.put (std::string ("foo_"), std::string ("bar"));
+ ldb.put ((uint32_t) 123, 1);
+ ldb.put ((uint32_t) 123, 2);
+ ldb.put (C2GSTRING ("foo"), 3);
+ ldb.put (C2GSTRING ("foo"), 4);
+ ldb.put (C2GSTRING ("gsk"), C2GSTRING ("gsv"));
+ std::string ts; int ti; gstring tgs;
+ auto fail = [](std::string msg) {throw std::runtime_error ("assertion failed: " + msg);};
+ if (!ldb.get (std::string ("foo_"), ts) || ts != "bar") fail ("!foo_=bar");
+ if (!ldb.get ((uint32_t) 123, ti) || ti != 2) fail ("!123=2");
+ if (!ldb.get (C2GSTRING ("foo"), ti) || ti != 4) fail ("!foo=4");
+ if (!ldb.get (C2GSTRING ("gsk"), tgs) || tgs != "gsv") fail ("!gsk=gsv");
+
+ // Test range-based for.
+ int count = 0; bool haveGskGsv = false;
+ for (auto&& entry: ldb) {
+ if (!entry._lit->Valid()) fail ("!entry");
+ if (entry.keyView() == "gsk") {
+ if (entry.getKey<gstring>() != "gsk") fail ("getKey(gsk)!=gsk");
+ if (entry.getValue<gstring>() != "gsv") fail ("getValue(gsk)!=gsv");
+ haveGskGsv = true;
+ }
+ ++count;}
+ if (count != 4) fail ("count!=4"); // foo_=bar, 123=2, foo=4, gsk=gsv
+ if (!haveGskGsv) fail ("!haveGskGsv");
+
+ ldb.del ((uint32_t) 123); if (ldb.get ((uint32_t) 123, ti)) fail ("123");
+ ldb.del (C2GSTRING ("foo")); if (ldb.get (C2GSTRING ("foo"), ti)) fail ("foo");
+ ldb.del (std::string ("foo_"));
+
+ { // We've erased "123" and "foo", the only key left is "gsk" (gsk=gsv), let's test the iterator boundaries on this small dataset.
+ auto&& it = ldb.begin();
+ if (it->getKey<gstring>() != "gsk") fail ("first key !gsk " + it->keyView().str());
+ if (!(++it).end()) fail ("++it != end");
+ if ((--it)->getKey<gstring>() != "gsk") fail ("can't go back to gsk");
+ if (!(--it).end()) fail ("--it != end");
+ if ((++it)->getKey<gstring>() != "gsk") fail ("can't go forward to gsk");
+ }
+
+// todo: index trigger example
+// struct SimpleIndexTrigger: public Trigger { // Uses key space partitioning (cf. http://stackoverflow.com/a/12503799/257568)
+// const char* _name; Ldb _indexDb;
+// SimpleIndexTrigger (Ldb& ldb, const char* name = "index"): _name (name), _indexDb (ldb._env, name) {}
+// gstring triggerName() {return gstring (0, (void*) _name, false, strlen (_name), true);}
+// void add (Ldb& ldb, void* key, gstring& kbytes, void* value, gstring& vbytes, Transaction& txn) {
+// MDB_val mkey = {vbytes.size(), (void*) vbytes.data()};
+// MDB_val mvalue = {kbytes.size(), (void*) kbytes.data()};
+// int rc = ::ldb_put (txn.get(), _indexDb._dbi, &mkey, &mvalue, 0);
+// if (rc) GNTHROW (LdbEx, std::string ("index, ldb_put: ") + ::strerror (rc));
+// }
+// void erase (Ldb& ldb, void* ekey, gstring& kbytes, Transaction& txn) {
+// // Get all the values and remove them from the index.
+// MDB_cursor* cur = 0; int rc = ::ldb_cursor_open (txn.get(), ldb._dbi, &cur);
+// if (rc) GNTHROW (LdbEx, std::string ("index, erase, ldb_cursor_open: ") + ::strerror (rc));
+// std::unique_ptr<MDB_cursor, void(*)(MDB_cursor*)> curHolder (cur, ::ldb_cursor_close);
+// MDB_val mkey = {kbytes.size(), (void*) kbytes.data()}, val = {0, 0};
+// rc = ::ldb_cursor_get (cur, &mkey, &val, ::MDB_SET_KEY); if (rc == MDB_NOTFOUND) return;
+// if (rc) GNTHROW (LdbEx, std::string ("index, erase, ldb_cursor_get: ") + ::strerror (rc));
+// rc = ::ldb_del (txn.get(), _indexDb._dbi, &val, &mkey);
+// if (rc && rc != MDB_NOTFOUND) GNTHROW (LdbEx, std::string ("index, erase, ldb_del: ") + ::strerror (rc));
+// for (;;) {
+// rc = ::ldb_cursor_get (cur, &mkey, &val, ::MDB_NEXT_DUP); if (rc == MDB_NOTFOUND) return;
+// if (rc) GNTHROW (LdbEx, std::string ("index, erase, ldb_cursor_get: ") + ::strerror (rc));
+// rc = ::ldb_del (txn.get(), _indexDb._dbi, &val, &mkey);
+// if (rc && rc != MDB_NOTFOUND) GNTHROW (LdbEx, std::string ("index, erase, ldb_del: ") + ::strerror (rc));
+// }
+// }
+// void eraseKV (Ldb& ldb, void* key, gstring& kbytes, void* value, gstring& vbytes, Transaction& txn) {
+// MDB_val mkey = {vbytes.size(), (void*) vbytes.data()};
+// MDB_val mvalue = {kbytes.size(), (void*) kbytes.data()};
+// int rc = ::ldb_del (txn.get(), _indexDb._dbi, &mkey, &mvalue);
+// if (rc && rc != MDB_NOTFOUND) GNTHROW (LdbEx, std::string ("index, ldb_del: ") + ::strerror (rc));
+// }
+// };
+// auto indexTrigger = std::make_shared<SimpleIndexTrigger> (ldb); ldb.setTrigger (indexTrigger); auto& indexDb = indexTrigger->_indexDb;
+// ldb.erase (C2GSTRING ("gsk")); // NB: "gsk" wasn't indexed here. `IndexTrigger.erase` should handle this gracefully.
+
+ // Add indexed.
+// ldb.put (C2GSTRING ("ik"), C2GSTRING ("iv1"));
+// ldb.put (C2GSTRING ("ik"), string ("iv2"));
+// ldb.put (C2GSTRING ("ik"), 3);
+ // Check the index.
+// gstring ik;
+// if (!indexDb.first (C2GSTRING ("iv1"), ik) || ik != "ik") fail ("!iv1=ik");
+// if (!indexDb.first (string ("iv2"), ik) || ik != "ik") fail ("!iv2=ik");
+// if (!indexDb.first (3, ik) || ik != "ik") fail ("!iv3=ik");
+
+ // Remove indexed.
+// ldb.eraseKV (C2GSTRING ("ik"), string ("iv2"));
+ // Check the index.
+// if (!indexDb.first (C2GSTRING ("iv1"), ik) || ik != "ik") fail ("!iv1=ik");
+// if (indexDb.first (string ("iv2"), ik)) fail ("iv2=ik");
+// if (!indexDb.first (3, ik) || ik != "ik") fail ("!iv3=ik");
+
+ // Remove indexed.
+// ldb.erase (C2GSTRING ("ik"));
+ // Check the index.
+// if (indexDb.first (C2GSTRING ("iv1"), ik)) fail ("iv1");
+// if (indexDb.first (3, ik)) fail ("iv3");
+ // Check the data.
+// if (ldb.first (C2GSTRING ("ik"), ik)) fail ("ik");
+}
+
+void testStartsWith (Ldb& ldb) {
+ // Using `gstring`s because the Boost Serialization encoding for CStrings is not prefix-friendly.
+ ldb.put (C2GSTRING ("01"), ""); ldb.put (C2GSTRING ("02"), "");
+ ldb.put (C2GSTRING ("11"), "");
+ ldb.put (C2GSTRING ("21"), ""); ldb.put (C2GSTRING ("222"), ""); ldb.put (C2GSTRING ("2"), "");
+
+ auto range = ldb.startsWith (C2GSTRING ("0")); auto it = range.begin();
+ assert (it->keyView() == "01"); assert (it != range.end());
+ assert ((++it)->keyView() == "02"); assert (it != range.end());
+ assert ((++it)->keyView().empty()); assert (it == range.end());
+ assert ((--it)->keyView() == "02"); assert (it != range.end());
+ assert ((--it)->keyView() == "01"); assert (it != range.end());
+ assert ((--it)->keyView().empty()); assert (it == range.end());
+ // `it` and `range.begin` point to the same `leveldb::Iterator`.
+ assert (range.begin()._entry->_lit == it._entry->_lit);
+ assert (!range.begin()._entry->_valid); assert (range.begin()->keyView().empty());
+
+ range = ldb.startsWith (C2GSTRING ("0")); it = range.end();
+ assert (it.end() && it->keyView().empty()); assert (it != range.begin());
+ assert ((--it)->keyView() == "02"); assert (it != range.begin());
+ assert ((--it)->keyView() == "01"); assert (it == range.begin());
+ assert ((--it)->keyView().empty()); assert (it != range.begin());
+
+ int8_t count = 0; for (auto& en: ldb.startsWith (C2GSTRING ("1"))) {en.keyView(); ++count;} assert (count == 1);
+ count = 0; for (auto& en: ldb.startsWith (C2GSTRING ("2"))) {en.keyView(); ++count;} assert (count == 3);
+ count = 0; for (auto& en: ldb.startsWith (C2GSTRING ("-"))) {en.keyView(); ++count;} assert (count == 0);
+ count = 0; for (auto& en: ldb.startsWith (C2GSTRING (""))) {en.keyView(); ++count;} assert (count == 6);
+
+ assert (ldb.startsWith (C2GSTRING ("-")) .empty());
+
+ count = 0; for (auto& en: boost::make_iterator_range (ldb.end().seek ("1"), ldb.end().seek ("2"))) {en.keyView(); ++count;} assert (count == 1);
+ count = 0; for (auto& en: boost::make_iterator_range (ldb.end().seek ("2"), ldb.end().seek ("3"))) {en.keyView(); ++count;} assert (count == 3);
+ count = 0; for (auto& en: ldb.range (C2GSTRING ("1"), C2GSTRING ("2"))) {en.keyView(); ++count;} assert (count == 1);
+
+ { auto range = ldb.range (C2GSTRING ("0"), C2GSTRING ("1")); // 01 and 02, but not 11.
+ count = 0; for (auto& en: range) {en.keyView(); ++count;} assert (count == 2); }
+}
+
+int main() {
+ cout << "Testing ldb.hpp ... " << flush;
+ boost::filesystem::remove_all ("/dev/shm/ldbTest");
+
+ Ldb ldb ("/dev/shm/ldbTest");
+ test1 (ldb);
+
+ for (auto& en: ldb) ldb.del (en.keyView());
+ testStartsWith (ldb);
+
+ ldb._db.reset(); // Close.
+ boost::filesystem::remove_all ("/dev/shm/ldbTest");
+ cout << "pass." << endl;
+ return 0;
+}
diff --git a/external/glim/test_runner.cc b/external/glim/test_runner.cc
new file mode 100644
index 000000000..8d9e0838c
--- /dev/null
+++ b/external/glim/test_runner.cc
@@ -0,0 +1,74 @@
+#include "runner.hpp"
+#include "curl.hpp"
+#include <future>
+#include <thread>
+#include <iostream>
+#include <assert.h>
+
+static void testRunner() {
+ using glim::RunnerV2;
+ auto runner = RunnerV2::instance();
+
+ struct Dugout: public glim::CurlmInformationListener {
+ glim::Curl _curl;
+ std::promise<std::string> _promise;
+ void schedule (RunnerV2* runner) {
+ _curl.http ("http://glim.ru/", 2);
+ curl_easy_setopt (_curl._curl, CURLOPT_PRIVATE, this); // Tells `addToCURLM` to call this listener later.
+ runner->addToCURLM (_curl._curl);
+ }
+ virtual FreeOptions information (CURLMsg* msg, CURLM* curlm) override {
+ _promise.set_value (_curl.str());
+ return static_cast<FreeOptions> (REMOVE_CURL_FROM_CURLM | DELETE_LISTENER);
+ }
+ virtual ~Dugout() {}
+ };
+ { Dugout* dugout = new Dugout();
+ auto future = dugout->_promise.get_future();
+ dugout->schedule (runner.get());
+ if (future.get().find ("<html") == std::string::npos) GTHROW ("!html"); }
+
+ auto curl = std::make_shared<glim::Curl>(); curl->http ("http://glim.ru/", 2);
+ auto promise = std::make_shared<std::promise<std::string>>(); auto future = promise->get_future();
+ runner->addToCURLM (curl->_curl, [curl,promise](CURLMsg*, CURLM*) {promise->set_value (curl->str());});
+ if (future.get().find ("<html") == std::string::npos) GTHROW ("!html");
+}
+
+static void oldTest() {
+ std::shared_ptr<struct event_base> evbase (event_base_new(), event_base_free);
+ glim::Runner runner (evbase, [](const char* error) {std::cerr << error << std::endl;});
+
+ auto scheduledJobFired = std::make_shared<bool> (false);
+ runner.schedule (0.f, [=](glim::Runner::JobInfo&)->bool {*scheduledJobFired = true; return false;});
+
+ auto curl = std::make_shared<glim::Curl> (false); curl->http ("http://glim.ru/env.cgi?pause=50", 5);
+ auto curlDebug = std::make_shared<std::string>(); curl->debugListenerF ([curlDebug](const char* bytes, size_t size) {curlDebug->append (bytes, size);});
+ volatile bool ran = false;
+ runner.multi (curl->_curl, [curl,&ran,evbase,curlDebug](CURLMsg* msg) {
+ std::cout << " status: " << curl->status();
+ if (curl->status() == 200) std::cout << " ip: " << curl->gstr().view (0, std::max (curl->gstr().find ("\n"), 0));
+ if (curlDebug->find ("GET /env.cgi") == std::string::npos) std::cerr << " No headers in debug? " << *curlDebug << std::endl;
+ ran = true;
+ event_base_loopbreak (evbase.get());
+ });
+ //struct timeval tv {1, 0}; event_base_loopexit (evbase.get(), &tv); // Exit the loop in a sec.
+ event_base_dispatch (evbase.get());
+ if (!ran) GTHROW ("!ran");
+ if (!*scheduledJobFired) GTHROW ("!scheduledJobFired");
+
+ std::cout << " pass." << std::endl;
+ //waiting: "was introduced in Libevent 2.1.1-alpha"//libevent_global_shutdown();
+}
+
+int main () {
+ std::cout << "Testing runner.hpp ..." << std::flush; try {
+
+ testRunner();
+ oldTest();
+
+ } catch (const std::exception& ex) {
+ std::cerr << " exception: " << ex.what() << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/external/glim/test_sqlite.cc b/external/glim/test_sqlite.cc
new file mode 100644
index 000000000..726244875
--- /dev/null
+++ b/external/glim/test_sqlite.cc
@@ -0,0 +1,18 @@
+
+#include "sqlite.hpp"
+#define S(cstr) (std::pair<char const*, int> (cstr, sizeof (cstr) - 1))
+#include <assert.h>
+#include <iostream>
+using namespace glim;
+
+int main () {
+ std::cout << "Testing sqlite.hpp ... " << std::flush;
+ Sqlite sqlite (":memory:");
+ SqliteSession sqs (&sqlite);
+ assert (sqs.query ("CREATE TABLE test (t TEXT, i INTEGER)") .ustep() == 0);
+ assert (sqs.query ("INSERT INTO test VALUES (?, ?)") .bind (1, S("foo")) .bind (2, 27) .ustep() == 1);
+ assert (sqs.query ("SELECT t FROM test") .qstep() .stringAt (1) == "foo");
+ assert (sqs.query ("SELECT i FROM test") .qstep() .intAt (1) == 27);
+ std::cout << "pass." << std::endl;
+ return 0;
+}