<commit_before>#pragma once

#include <cstring>
#include <cstdio>
#include <string>
#include <iostream>
#include <map>

namespace bson {

    // Basic types

    enum node_type {
        double_node = 0x01,
        string_node = 0x02,
        document_node = 0x03,
        binary_node = 0x05,
        boolean_node = 0x08,
        null_node = 0x0A,
        int32_node = 0x10,
        int64_node = 0x12,
        unknown_node = 0xFF
    };

    template<typename T> struct type_converter { };

    class node {
        public:
            virtual ~node() { }
            virtual void serialize(void* const buffer, const size_t count) const = 0;
            virtual size_t get_serialized_size() const = 0;
            virtual unsigned char get_node_code() const { return 0; }
            virtual node* copy() const = 0;
            virtual void dump(std::ostream&) const = 0;
            virtual void dump(std::ostream& stream, int level) const { dump(stream); }
            static node* create(node_type type, const void* const buffer, const size_t count);
    };

    // Value types

    class null : public node {
        public:
            null() { }

            null(const void* const buffer, const size_t count) { }

            void serialize(void* const buffer, const size_t count) const { }

            size_t get_serialized_size() const {
                return 0;
            }

            unsigned char get_node_code() const {
                return null_node;
            }

            node* copy() const {
                return new null();
            }

            void dump(std::ostream& stream) const { stream << "null"; };
    };

    template<typename T, node_type N>
        class scalar : public node {
            private:
                T value;
            public:
                scalar(const T value) : value(value) { }

                scalar(const void* const buffer, const size_t count) {
                    value = *reinterpret_cast<const T*>(buffer);
                };

                void serialize(void* const buffer, const size_t count) const {
                    *reinterpret_cast<T*>(buffer) = value;
                }

                size_t get_serialized_size() const {
                    return sizeof(T);
                }

                unsigned char get_node_code() const {
                    return N;
                }

                node* copy() const {
                    return new scalar<T, N>(value);
                }

                void dump(std::ostream& stream) const { stream << value; };

                const T& get_value() const { return value; }
        };

    class int32 : public scalar<int, int32_node> {
        public:
            int32(const int value) : scalar<int, int32_node>(value) { }

            int32(const void* const buffer, const size_t count) : scalar<int, int32_node>(buffer, count) { };
    };

    template<> struct type_converter<int> { enum { node_type_code = int32_node }; typedef int32 node_class; };

    class int64 : public scalar<long long int, int64_node> {
        public:
            int64(const long long int value) : scalar<long long int, int64_node>(value) { }

            int64(const void* const buffer, const size_t count) : scalar<long long int, int64_node>(buffer, count) { };
    };

    template<> struct type_converter<long long int> { enum { node_type_code = int64_node }; typedef int64 node_class; };

    class Double : public scalar<double, double_node> {
        public:
            Double(const double value) : scalar<double, double_node>(value) { }

            Double(const void* const buffer, const size_t count) : scalar<double, double_node>(buffer, count) { };
    };

    template<> struct type_converter<double> { enum { node_type_code = double_node }; typedef Double node_class; };

    class string : public node {
        private:
            std::string value;
        public:
            string(const std::string& value) : value(value) { }

            string(const void* const buffer, const size_t count) {
                value.assign(reinterpret_cast<const char*>(buffer));
            };

            void serialize(void* const buffer, const size_t count) const {
                std::strncpy(reinterpret_cast<char*>(buffer), value.c_str(), count);
            }

            size_t get_serialized_size() const {
                return value.length() + 1;
            }

            unsigned char get_node_code() const {
                return string_node;
            }

            node* copy() const {
                return new string(value);
            }

            void dump(std::ostream& stream) const { stream << "\"" << value << "\""; };

            const std::string& get_value() const { return value; }
    };

    template<> struct type_converter<std::string> { enum { node_type_code = string_node }; typedef string node_class; };

    class boolean : public node {
        private:
            bool value;
        public:
            boolean(const bool value) : value(value) { }

            boolean(const void* const buffer, const size_t count) {
                switch (*reinterpret_cast<const unsigned char*>(buffer)) {
                    case 1: value = true; break;
                    default: value = false; break;
                }
            };

            void serialize(void* const buffer, const size_t count) const {
                *reinterpret_cast<unsigned char*>(buffer) = value ? true : false;
            }

            size_t get_serialized_size() const {
                return 1;
            }

            unsigned char get_node_code() const {
                return boolean_node;
            }

            node* copy() const {
                return new boolean(value);
            }

            void dump(std::ostream& stream) const { stream << (value ? "true" : "false"); };

            const bool& get_value() const { return value; }
    };

    template<> struct type_converter<bool> { enum { node_type_code = boolean_node }; typedef boolean node_class; };

    class binary : public node {
        public:
            struct buffer {
                buffer(const buffer& other) : owned(true) {
                    length = other.length;
                    data = new unsigned char[length];
                    std::memcpy(data, other.data, length);
                }

                buffer(void* data, size_t length) : data(data), length(length), owned(false) { }

                ~buffer() {
                    if (owned)
                        delete[] reinterpret_cast<unsigned char*>(data);
                }

                void dump(std::ostream& stream) const { stream << "<binary: " << length << " bytes>"; };

                void* data;
                size_t length;
                bool owned;
            };

        private:
            buffer value;

        public:
            binary(const buffer& buffer) : value(buffer) { }

            binary(const void* const buffer, const size_t count, const bool create = false) : value(NULL, 0) {
                const unsigned char* byte_buffer = reinterpret_cast<const unsigned char*>(buffer);

                if (create) {
                    value.length = count;
                    value.data = new unsigned char[value.length];
                    std::memcpy(value.data, byte_buffer, value.length);
                }
                else {
                    value.length = *reinterpret_cast<const size_t*>(byte_buffer);
                    value.data = new unsigned char[value.length];
                    std::memcpy(value.data, byte_buffer + 5, value.length);
                }

                value.owned = true;
            };

            void serialize(void* const buffer, const size_t count) const {
                unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);

                *reinterpret_cast<size_t*>(byte_buffer) = value.length;
                std::memcpy(byte_buffer + 5, value.data, value.length);
            }

            size_t get_serialized_size() const {
                return 5 + value.length;
            }

            unsigned char get_node_code() const {
                return binary_node;
            }

            node* copy() const {
                return new binary(value.data, value.length, true);
            }

            void dump(std::ostream& stream) const { value.dump(stream); };

            const buffer get_value() const { return value; }
    };

    template<> struct type_converter< binary::buffer > { enum { node_type_code = binary_node }; typedef binary node_class; };

    // Composite types

    class element_list : protected std::map<std::string, node*>, public node {
        public:
            typedef std::map<std::string, node*>::const_iterator const_iterator;

            element_list() { }

            element_list(const element_list& other) {
                for (const_iterator i = other.begin(); i != other.end(); i++)
                    (*this)[i->first] = i->second->copy();
            }

            element_list(const void* const buffer, const size_t count) {
                const unsigned char* byte_buffer = reinterpret_cast<const unsigned char*>(buffer);
                size_t position = 0;

                while (position < count) {
                    node_type type = static_cast<node_type>(byte_buffer[position++]);
                    std::string name(reinterpret_cast<const char*>(byte_buffer + position));
                    node* node = NULL;

                    position += name.length() + 1;
                    node = node::create(type, byte_buffer + position, count - position);

                    if (node != NULL) {
                        position += node->get_serialized_size();
                        (*this)[name] = node;
                    }
                    else
                        break;
                }
            }

            void serialize(void* const buffer, const size_t count) const {
                unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);
                int position = 0;

                for (const_iterator i = begin(); i != end(); i++) {
                    // Header
                    byte_buffer[position] = i->second->get_node_code();
                    position++;
                    // Key
                    std::strcpy(reinterpret_cast<char*>(byte_buffer + position), i->first.c_str());
                    position += i->first.length() + 1;
                    // Value
                    i->second->serialize(byte_buffer + position, count - position);
                    position += i->second->get_serialized_size();
                }
            }

            size_t get_serialized_size() const {
                size_t result = 0;

                for (const_iterator i = begin(); i != end(); i++)
                    result += 1 + i->first.length() + 1 + i->second->get_serialized_size();

                return result;
            }

            node* copy() const {
                return new element_list(*this);
            }

            void dump(std::ostream& stream) const {
                stream << "{ ";

                for (const_iterator i = begin(); i != end(); i++) {
                    stream << "\"" << i->first << "\": ";
                    i->second->dump(stream);

                    if (++i != end())
                        stream << ", ";
                    --i;
                }

                stream << " }";
            }

            void dump(std::ostream& stream, const int level) const {
                stream << "{ ";

                for (const_iterator i = begin(); i != end(); i++) {
                    stream << std::endl;

                    for (int j = 0; j < level + 1; j++)
                        stream << "\t";

                    stream << "\"" << i->first << "\": ";
                    i->second->dump(stream, level + 1);

                    if (++i != end())
                        stream << ", ";
                    --i;
                }

                stream << std::endl;

                for (int j = 0; j < level; j++)
                    stream << "\t";

                stream << "}";
            }

            const_iterator begin() const {
                return std::map<std::string, node*>::begin();
            }

            const_iterator end() const {
                return std::map<std::string, node*>::end();
            }

            bool contains(const std::string& key) const {
                return (std::map<std::string, node*>::find(key) != end());
            }

            template<typename T>
            bool contains(const std::string& key) const {
                const_iterator position = std::map<std::string, node*>::find(key);
                return (position != end()) && (position->second->get_node_code() == type_converter<T>::node_type_code);
            }

            ~element_list() {
                for (const_iterator i = begin(); i != end(); i++)
                    delete i->second;
            }

    };

    class document : public element_list {
        public:
            document() { }

            document(const void* const buffer, const size_t count) : element_list(reinterpret_cast<const unsigned char*>(buffer) + 4, *reinterpret_cast<const size_t*>(buffer) - 4 - 1) { }

            void serialize(void* const buffer, const size_t count) const {
                size_t serialized_size = get_serialized_size();

                if (count >= serialized_size) {
                    unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);

                    *reinterpret_cast<int*>(buffer) = serialized_size;
                    element_list::serialize(byte_buffer + 4, count - 4 - 1);
                    byte_buffer[4 + element_list::get_serialized_size()] = 0;
                }
            }

            size_t get_serialized_size() const {
                return 4 + element_list::get_serialized_size() + 1;
            }

            unsigned char get_node_code() const {
                return document_node;
            }

            node* copy() const {
                return new document(*this);
            }

            template<typename result_type>
            const result_type get(const std::string& key, const result_type& _default) const {
                const node_type node_type_code = static_cast<node_type>(type_converter<result_type>::node_type_code);
                typedef typename type_converter<result_type>::node_class node_class;

                if ((find(key) != end()) && (at(key)->get_node_code() == node_type_code))
                    return reinterpret_cast<const node_class*>(at(key))->get_value();
                else
                    return _default;
            }

            const document& get(const std::string& key, const document& _default) const {
                if ((find(key) != end()) && (at(key)->get_node_code() == document_node))
                    return *reinterpret_cast<const document*>(at(key));
                else
                    return _default;
            }

            const std::string get(const std::string& key, const char* _default) const {
                if ((find(key) != end()) && (at(key)->get_node_code() == string_node))
                    return reinterpret_cast<const string*>(at(key))->get_value();
                else
                    return std::string(_default);
            }

            template<typename value_type>
            document& set(const std::string& key, const value_type& value) {
                typedef typename type_converter<value_type>::node_class node_class;

                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new node_class(value);
                return (*this);
            }

            document& set(const std::string& key, const char* value) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new string(value);
                return (*this);
            }

            document& set(const std::string& key, const document& value) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = value.copy();
                return (*this);
            }

            document& set(const std::string& key) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new null();
                return (*this);
            }
    };

    template<> struct type_converter< document > { enum { node_type_code = document_node }; typedef document node_class; };

    inline node* node::create(node_type type, const void * const buffer, const size_t count) {
        switch (type) {
            case null_node: return new null();
            case int32_node: return new int32(buffer, count);
            case int64_node: return new int64(buffer, count);
            case double_node: return new Double(buffer, count);
            case document_node: return new document(buffer, count);
            case string_node: return new string(buffer, count);
            case binary_node: return new binary(buffer, count);
            case boolean_node: return new boolean(buffer, count);
            default: return NULL;
        }
    }
}
<commit_msg>Fix string field enconding.<commit_after>#pragma once

#include <cstring>
#include <cstdio>
#include <string>
#include <iostream>
#include <map>

namespace bson {

    // Basic types

    enum node_type {
        double_node = 0x01,
        string_node = 0x02,
        document_node = 0x03,
        binary_node = 0x05,
        boolean_node = 0x08,
        null_node = 0x0A,
        int32_node = 0x10,
        int64_node = 0x12,
        unknown_node = 0xFF
    };

    template<typename T> struct type_converter { };

    class node {
        public:
            virtual ~node() { }
            virtual void serialize(void* const buffer, const size_t count) const = 0;
            virtual size_t get_serialized_size() const = 0;
            virtual unsigned char get_node_code() const { return 0; }
            virtual node* copy() const = 0;
            virtual void dump(std::ostream&) const = 0;
            virtual void dump(std::ostream& stream, int level) const { dump(stream); }
            static node* create(node_type type, const void* const buffer, const size_t count);
    };

    // Value types

    class null : public node {
        public:
            null() { }

            null(const void* const buffer, const size_t count) { }

            void serialize(void* const buffer, const size_t count) const { }

            size_t get_serialized_size() const {
                return 0;
            }

            unsigned char get_node_code() const {
                return null_node;
            }

            node* copy() const {
                return new null();
            }

            void dump(std::ostream& stream) const { stream << "null"; };
    };

    template<typename T, node_type N>
        class scalar : public node {
            private:
                T value;
            public:
                scalar(const T value) : value(value) { }

                scalar(const void* const buffer, const size_t count) {
                    value = *reinterpret_cast<const T*>(buffer);
                };

                void serialize(void* const buffer, const size_t count) const {
                    *reinterpret_cast<T*>(buffer) = value;
                }

                size_t get_serialized_size() const {
                    return sizeof(T);
                }

                unsigned char get_node_code() const {
                    return N;
                }

                node* copy() const {
                    return new scalar<T, N>(value);
                }

                void dump(std::ostream& stream) const { stream << value; };

                const T& get_value() const { return value; }
        };

    class int32 : public scalar<int, int32_node> {
        public:
            int32(const int value) : scalar<int, int32_node>(value) { }

            int32(const void* const buffer, const size_t count) : scalar<int, int32_node>(buffer, count) { };
    };

    template<> struct type_converter<int> { enum { node_type_code = int32_node }; typedef int32 node_class; };

    class int64 : public scalar<long long int, int64_node> {
        public:
            int64(const long long int value) : scalar<long long int, int64_node>(value) { }

            int64(const void* const buffer, const size_t count) : scalar<long long int, int64_node>(buffer, count) { };
    };

    template<> struct type_converter<long long int> { enum { node_type_code = int64_node }; typedef int64 node_class; };

    class Double : public scalar<double, double_node> {
        public:
            Double(const double value) : scalar<double, double_node>(value) { }

            Double(const void* const buffer, const size_t count) : scalar<double, double_node>(buffer, count) { };
    };

    template<> struct type_converter<double> { enum { node_type_code = double_node }; typedef Double node_class; };

    class string : public node {
        private:
            std::string value;
        public:
            string(const std::string& value) : value(value) { }

            string(const void* const buffer, const size_t count) {
                value.assign(reinterpret_cast<const char*>(buffer) + sizeof(unsigned int), *reinterpret_cast<const unsigned int*>(buffer) - 1);
            };

            void serialize(void* const buffer, const size_t count) const {
                *reinterpret_cast<unsigned int*>(buffer) = value.length() + 1;
                std::memcpy(reinterpret_cast<char*>(buffer) + sizeof(unsigned int), value.c_str(), value.length());
                *(reinterpret_cast<char*>(buffer) + count - 1) = '\0';
            }

            size_t get_serialized_size() const {
                return sizeof(unsigned int) + value.length() + 1;
            }

            unsigned char get_node_code() const {
                return string_node;
            }

            node* copy() const {
                return new string(value);
            }

            void dump(std::ostream& stream) const { stream << "\"" << value << "\""; };

            const std::string& get_value() const { return value; }
    };

    template<> struct type_converter<std::string> { enum { node_type_code = string_node }; typedef string node_class; };

    class boolean : public node {
        private:
            bool value;
        public:
            boolean(const bool value) : value(value) { }

            boolean(const void* const buffer, const size_t count) {
                switch (*reinterpret_cast<const unsigned char*>(buffer)) {
                    case 1: value = true; break;
                    default: value = false; break;
                }
            };

            void serialize(void* const buffer, const size_t count) const {
                *reinterpret_cast<unsigned char*>(buffer) = value ? true : false;
            }

            size_t get_serialized_size() const {
                return 1;
            }

            unsigned char get_node_code() const {
                return boolean_node;
            }

            node* copy() const {
                return new boolean(value);
            }

            void dump(std::ostream& stream) const { stream << (value ? "true" : "false"); };

            const bool& get_value() const { return value; }
    };

    template<> struct type_converter<bool> { enum { node_type_code = boolean_node }; typedef boolean node_class; };

    class binary : public node {
        public:
            struct buffer {
                buffer(const buffer& other) : owned(true) {
                    length = other.length;
                    data = new unsigned char[length];
                    std::memcpy(data, other.data, length);
                }

                buffer(void* data, size_t length) : data(data), length(length), owned(false) { }

                ~buffer() {
                    if (owned)
                        delete[] reinterpret_cast<unsigned char*>(data);
                }

                void dump(std::ostream& stream) const { stream << "<binary: " << length << " bytes>"; };

                void* data;
                size_t length;
                bool owned;
            };

        private:
            buffer value;

        public:
            binary(const buffer& buffer) : value(buffer) { }

            binary(const void* const buffer, const size_t count, const bool create = false) : value(NULL, 0) {
                const unsigned char* byte_buffer = reinterpret_cast<const unsigned char*>(buffer);

                if (create) {
                    value.length = count;
                    value.data = new unsigned char[value.length];
                    std::memcpy(value.data, byte_buffer, value.length);
                }
                else {
                    value.length = *reinterpret_cast<const size_t*>(byte_buffer);
                    value.data = new unsigned char[value.length];
                    std::memcpy(value.data, byte_buffer + 5, value.length);
                }

                value.owned = true;
            };

            void serialize(void* const buffer, const size_t count) const {
                unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);

                *reinterpret_cast<size_t*>(byte_buffer) = value.length;
                std::memcpy(byte_buffer + 5, value.data, value.length);
            }

            size_t get_serialized_size() const {
                return 5 + value.length;
            }

            unsigned char get_node_code() const {
                return binary_node;
            }

            node* copy() const {
                return new binary(value.data, value.length, true);
            }

            void dump(std::ostream& stream) const { value.dump(stream); };

            const buffer get_value() const { return value; }
    };

    template<> struct type_converter< binary::buffer > { enum { node_type_code = binary_node }; typedef binary node_class; };

    // Composite types

    class element_list : protected std::map<std::string, node*>, public node {
        public:
            typedef std::map<std::string, node*>::const_iterator const_iterator;

            element_list() { }

            element_list(const element_list& other) {
                for (const_iterator i = other.begin(); i != other.end(); i++)
                    (*this)[i->first] = i->second->copy();
            }

            element_list(const void* const buffer, const size_t count) {
                const unsigned char* byte_buffer = reinterpret_cast<const unsigned char*>(buffer);
                size_t position = 0;

                while (position < count) {
                    node_type type = static_cast<node_type>(byte_buffer[position++]);
                    std::string name(reinterpret_cast<const char*>(byte_buffer + position));
                    node* node = NULL;

                    position += name.length() + 1;
                    node = node::create(type, byte_buffer + position, count - position);

                    if (node != NULL) {
                        position += node->get_serialized_size();
                        (*this)[name] = node;
                    }
                    else
                        break;
                }
            }

            void serialize(void* const buffer, const size_t count) const {
                unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);
                int position = 0;

                for (const_iterator i = begin(); i != end(); i++) {
                    // Header
                    byte_buffer[position] = i->second->get_node_code();
                    position++;
                    // Key
                    std::strcpy(reinterpret_cast<char*>(byte_buffer + position), i->first.c_str());
                    position += i->first.length() + 1;
                    // Value
                    i->second->serialize(byte_buffer + position, count - position);
                    position += i->second->get_serialized_size();
                }
            }

            size_t get_serialized_size() const {
                size_t result = 0;

                for (const_iterator i = begin(); i != end(); i++)
                    result += 1 + i->first.length() + 1 + i->second->get_serialized_size();

                return result;
            }

            node* copy() const {
                return new element_list(*this);
            }

            void dump(std::ostream& stream) const {
                stream << "{ ";

                for (const_iterator i = begin(); i != end(); i++) {
                    stream << "\"" << i->first << "\": ";
                    i->second->dump(stream);

                    if (++i != end())
                        stream << ", ";
                    --i;
                }

                stream << " }";
            }

            void dump(std::ostream& stream, const int level) const {
                stream << "{ ";

                for (const_iterator i = begin(); i != end(); i++) {
                    stream << std::endl;

                    for (int j = 0; j < level + 1; j++)
                        stream << "\t";

                    stream << "\"" << i->first << "\": ";
                    i->second->dump(stream, level + 1);

                    if (++i != end())
                        stream << ", ";
                    --i;
                }

                stream << std::endl;

                for (int j = 0; j < level; j++)
                    stream << "\t";

                stream << "}";
            }

            const_iterator begin() const {
                return std::map<std::string, node*>::begin();
            }

            const_iterator end() const {
                return std::map<std::string, node*>::end();
            }

            bool contains(const std::string& key) const {
                return (std::map<std::string, node*>::find(key) != end());
            }

            template<typename T>
            bool contains(const std::string& key) const {
                const_iterator position = std::map<std::string, node*>::find(key);
                return (position != end()) && (position->second->get_node_code() == type_converter<T>::node_type_code);
            }

            ~element_list() {
                for (const_iterator i = begin(); i != end(); i++)
                    delete i->second;
            }

    };

    class document : public element_list {
        public:
            document() { }

            document(const void* const buffer, const size_t count) : element_list(reinterpret_cast<const unsigned char*>(buffer) + 4, *reinterpret_cast<const size_t*>(buffer) - 4 - 1) { }

            void serialize(void* const buffer, const size_t count) const {
                size_t serialized_size = get_serialized_size();

                if (count >= serialized_size) {
                    unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);

                    *reinterpret_cast<int*>(buffer) = serialized_size;
                    element_list::serialize(byte_buffer + 4, count - 4 - 1);
                    byte_buffer[4 + element_list::get_serialized_size()] = 0;
                }
            }

            size_t get_serialized_size() const {
                return 4 + element_list::get_serialized_size() + 1;
            }

            unsigned char get_node_code() const {
                return document_node;
            }

            node* copy() const {
                return new document(*this);
            }

            template<typename result_type>
            const result_type get(const std::string& key, const result_type& _default) const {
                const node_type node_type_code = static_cast<node_type>(type_converter<result_type>::node_type_code);
                typedef typename type_converter<result_type>::node_class node_class;

                if ((find(key) != end()) && (at(key)->get_node_code() == node_type_code))
                    return reinterpret_cast<const node_class*>(at(key))->get_value();
                else
                    return _default;
            }

            const document& get(const std::string& key, const document& _default) const {
                if ((find(key) != end()) && (at(key)->get_node_code() == document_node))
                    return *reinterpret_cast<const document*>(at(key));
                else
                    return _default;
            }

            const std::string get(const std::string& key, const char* _default) const {
                if ((find(key) != end()) && (at(key)->get_node_code() == string_node))
                    return reinterpret_cast<const string*>(at(key))->get_value();
                else
                    return std::string(_default);
            }

            template<typename value_type>
            document& set(const std::string& key, const value_type& value) {
                typedef typename type_converter<value_type>::node_class node_class;

                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new node_class(value);
                return (*this);
            }

            document& set(const std::string& key, const char* value) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new string(value);
                return (*this);
            }

            document& set(const std::string& key, const document& value) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = value.copy();
                return (*this);
            }

            document& set(const std::string& key) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new null();
                return (*this);
            }
    };

    template<> struct type_converter< document > { enum { node_type_code = document_node }; typedef document node_class; };

    inline node* node::create(node_type type, const void * const buffer, const size_t count) {
        switch (type) {
            case null_node: return new null();
            case int32_node: return new int32(buffer, count);
            case int64_node: return new int64(buffer, count);
            case double_node: return new Double(buffer, count);
            case document_node: return new document(buffer, count);
            case string_node: return new string(buffer, count);
            case binary_node: return new binary(buffer, count);
            case boolean_node: return new boolean(buffer, count);
            default: return NULL;
        }
    }
}
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_MAP_HXX
#define _ABACLADE_MAP_HXX

#ifndef _ABACLADE_HXX
   #error Please #include <abaclade.hxx> before this file
#endif
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::map

namespace abc {

//! Key/value map using a simplified hopscotch hashing collision resolution algorithm.
template <typename TKey, typename TValue, typename THasher = std::hash<TKey>>
class map : public THasher {
public:
   //! Hash generator for TKey.
   typedef THasher hasher;

   //! Iterator type.
   class iterator {
   public:
      /*! Constructor.

      @param pmap
         Pointer to the map owning the iterated objects.
      @param iBucket
         Index of the current bucket.
      */
      iterator(map const * pmap, std::size_t iBucket) :
         mc_pmap(pmap),
         m_iBucket(iBucket) {
      }

   private:
      //! Pointer to the map to iterate over.
      map const * const mc_pmap;
      //! Current bucket index.
      std::size_t m_iBucket;
   };

public:
   /*! Constructor.

   @param m
      Source object.
   */
   map() :
      m_cBuckets(0),
      m_cUsedBuckets(0) {
   }
   map(map && m) :
      m_piHashes(std::move(m.m_piHashes)),
      m_pkeys(std::move(m.m_pkeys)),
      m_pvalues(std::move(m.m_pvalues)),
      m_cBuckets(m.m_cBuckets),
      m_cUsedBuckets(m.m_cUsedBuckets) {
      m.m_cBuckets = 0;
      m.m_cUsedBuckets = 0;
   }

   //! Destructor.
   ~map() {
      clear();
   }

   /*! Assignment operator.

   @param m
      Source object.
   */
   map & operator=(map && m) {
      m_piHashes = std::move(m.m_piHashes);
      m_pkeys = std::move(m.m_pkeys);
      m_pvalues = std::move(m.m_pvalues);
      m_cBuckets = m.m_cBuckets;
      m.m_cBuckets = 0;
      m_cUsedBuckets = m.m_cUsedBuckets;
      m.m_cUsedBuckets = 0;
      return *this;
   }

   /*! Element lookup operator.

   @param key
      Key to lookup.
   @return
      Value corresponding to key. If key is not in the map, an exception will be thrown.
   */
   TValue & operator[](TKey const & key) const {
      std::size_t iBucket = bucket_index_from_key(key);
      if (iBucket == smc_iNullIndex) {
         // TODO: throw proper exception.
         throw 0;
      }
      return m_pvalues[iBucket];
   }

   /*! Adds a key/value pair to the map, overwriting the value if key is already associated to one.

   @param key
      Key to add.
   @param value
      Value to add.
   */
   iterator add(TKey key, TValue value) {
      return iterator(this, 0);
   }

   //! Removes all elements from the map.
   void clear() {
      std::size_t * piHash = m_piHashes, * piHashesEnd = piHash + m_cBuckets;
      TKey * pkey = &get_key(0);
      TValue * pvalue = &get_value(0);
      for (; piHash < piHashesEnd; ++piHash, ++pkey, ++pvalue) {
         if (*piHash != smc_iEmptyBucketHash) {
            *piHash = smc_iEmptyBucketHash;
            pkey->~TKey();
            pvalue->~TValue();
         }
      }
      m_cUsedBuckets = 0;
   }

   /*! Removes a key/value pair given the key, which must be in the map.

   @param key
      Key associated to the value to remove.
   */
   void remove(TKey const & key) {
      std::size_t iBucket = bucket_index_from_key(key);
      if (iBucket == smc_iNullIndex) {
         // TODO: throw proper exception.
         throw 0;
      }
      // Mark the bucket as free and destruct the corresponding key and value.
      m_piHashes[iBucket] = smc_iEmptyBucketHash;
      get_key(iBucket).~TKey();
      get_value(iBucket).~TValue();
   }

private:
   void create_empty_buckets(std::size_t cBuckets = smc_cBucketsMin) {
      m_cBuckets = cBuckets;
      m_piHashes.reset(new std::size_t[m_cBuckets]);
      m_pkeys.reset(new std::max_align_t[ABC_ALIGNED_SIZE(sizeof(TKey) * m_cBuckets)]);
      m_pvalues.reset(new std::max_align_t[ABC_ALIGNED_SIZE(sizeof(TValue) * m_cBuckets)]);
   }

   std::size_t bucket_index_from_key(TKey const & key) const {
      return bucket_index_from_key(key, get_and_adjust_hash(key));
   }
   std::size_t bucket_index_from_key(TKey const & key, std::size_t iHash) const {
      if (!m_cBuckets) {
         // No buckets, so key/iHash cannot be in the map.
         return smc_iNullIndex;
      }
      auto pairRanges(get_neighborhood_ranges_from_hash(iHash));
      // Scan till the end of the neighborhood (clipped to the end of the array).
      std::size_t iBucket = bucket_index_from_key_and_bucket_range(
         key, iHash, pairRanges.first.first, pairRanges.first.second
      );
      if (iBucket == smc_iNullIndex && pairRanges.second.first < pairRanges.second.second) {
         // This neighborhood wraps, so we have a second range of buckets to scan.
         iBucket = bucket_index_from_key_and_bucket_range(
            key, iHash, pairRanges.second.first, pairRanges.second.second
         );
      }
      return iBucket;
   }

   /*! Calculates, adjusts and returns the hash value for the specified key.

   @param key
      Key to calculate a hash value for.
   @return
      Hash value of key.
   */
   std::size_t get_and_adjust_hash(TKey const & key) const {
      std::size_t iHash = hasher::operator()(key);
      return iHash == smc_iEmptyBucketHash ? smc_iZeroHash : iHash;
   }

   TKey & get_key(std::size_t i) const {
      return reinterpret_cast<TKey *>(m_pkeys.get())[i];
   }

   /*! Returns the current neighborhood size.

   @return
      Current neighborhood size, which is not necessarily the same as smc_cNeighborhoodBuckets.
   */
   std::size_t get_neighborhood_size() const {
      // Can’t have a neighborhood larger than the total count of buckets.
      return std::min(smc_cNeighborhoodBuckets, m_cBuckets);
   }

   TValue & get_value(std::size_t i) const {
      return reinterpret_cast<TValue *>(m_pvalues.get())[i];
   }

   /*! Returns the neighborhood index (index of the first bucket in a neighborhood) for the given
   hash.

   @param iHash
      Hash to get the neighborhood index for.
   @return
      Index of the first bucket in the neighborhood.
   */
   std::size_t neighborhood_index_from_hash(std::size_t iHash) const {
      return iHash & (m_cBuckets - 1);
   }

   /*! Returns the neighborhood bucket index ranges for the given hash.

   @param iHash
      Hash to return the neighborhood of.
   @return
      The neighborhood bucket index range is expressed by [return.first.first, return.first.second);
      if the neighborhood wraps from the end of the bucket array back to its start, the wrapped
      portion is expressed by [return.second.first, return.second.second). The second interval will
      be [0, 0) (i.e. empty) if the neighborhood doesn’t wrap.
   */
   std::pair<
      std::pair<std::size_t, std::size_t>, std::pair<std::size_t, std::size_t>
   > get_neighborhood_ranges_from_hash(std::size_t iHash) const {
      // Get a range of indices representing the neighborhood.
      std::size_t iNeighborhoodBegin = neighborhood_index_from_hash(iHash);
      std::size_t iNeighborhoodEnd = iNeighborhoodBegin + get_neighborhood_size();
      // Check if the neighborhood wraps around the end of the bucket array.
      if (iNeighborhoodEnd > m_cBuckets) {
         // Return two ranges.
         return std::make_pair(
            std::make_pair(iNeighborhoodBegin, m_cBuckets),
            std::make_pair(0, iNeighborhoodEnd - m_cBuckets)
         );
      } else {
         // Return a single range.
         return std::make_pair(
            std::make_pair(iNeighborhoodBegin, iNeighborhoodEnd),
            std::make_pair(0, 0)
         );
      }
   }

   bool keys_equal(TKey const & key1, TKey const & key2) const {
      return key1 == key2;
   }

   /*! Scans a range of buckets, looking for a specific key.

   @param key
      Key to scan for.
   @param iHash
      Hash of key.
   @param iBegin
      Start of the bucket range.
   @param iEnd
      End of the bucket range.
   @return
      Index of the bucket at which the key could be found, or smc_iNullIndex if the key was not
      found.
   */
   std::size_t bucket_index_from_key_and_bucket_range(
      TKey const & key, std::size_t iHash, std::size_t iBegin, std::size_t iEnd
   ) const {
      std::size_t const * piHashesBegin = m_piHashes + iBegin, * piHashesEnd = m_piHashes + iEnd;
      TKey const * pkey = m_pkeys + iBegin;
      for (std::size_t const * piHash = piHashesBegin; piHash < piHashesEnd; ++piHash, ++pkey) {
         if (*piHash == iHash && keys_equal(*pkey == key)) {
            return static_cast<std::size_t>(piHash - piHashesBegin);
         }
      }
      return smc_iNullIndex;
   }

private:
   //! Array containing the hash of each key.
   std::unique_ptr<std::size_t[]> m_piHashes;
   //! Array of keys.
   std::unique_ptr<std::max_align_t[]> m_pkeys;
   //! Array of buckets.
   std::unique_ptr<std::max_align_t[]> m_pvalues;
   //! Count of total buckets.
   std::size_t m_cBuckets;
   //! Count of elements / occupied buckets.
   std::size_t m_cUsedBuckets;
   //! Minimum bucket count.
   static std::size_t const smc_cBucketsMin = 8;
   //! Special hash value used to indicate that a bucket is empty.
   static std::size_t const smc_iEmptyBucketHash = 0;
   //! Neighborhood size.
   static std::size_t const smc_cNeighborhoodBuckets = sizeof(std::size_t) * CHAR_BIT;
   //! Special index returned by several methods to indicate a logical “null index”.
   static std::size_t const smc_iNullIndex = numeric::max<std::size_t>::value;
   /*! Hash value substituted when the hash function returns 0; this is so we can use 0 (aliased by
   smc_iEmptyBucketHash) as a special value. This specific value is merely the largest prime number
   that will fit in 2^16, which is the (future, if ever) minimum word size supported by Abaclade. */
   static std::size_t const smc_iZeroHash = 65521;
};

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifndef _ABACLADE_MAP_HXX

<commit_msg>Make abc::map::create_empty_buckets() exception-safe<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_MAP_HXX
#define _ABACLADE_MAP_HXX

#ifndef _ABACLADE_HXX
   #error Please #include <abaclade.hxx> before this file
#endif
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::map

namespace abc {

//! Key/value map using a simplified hopscotch hashing collision resolution algorithm.
template <typename TKey, typename TValue, typename THasher = std::hash<TKey>>
class map : public THasher {
public:
   //! Hash generator for TKey.
   typedef THasher hasher;

   //! Iterator type.
   class iterator {
   public:
      /*! Constructor.

      @param pmap
         Pointer to the map owning the iterated objects.
      @param iBucket
         Index of the current bucket.
      */
      iterator(map const * pmap, std::size_t iBucket) :
         mc_pmap(pmap),
         m_iBucket(iBucket) {
      }

   private:
      //! Pointer to the map to iterate over.
      map const * const mc_pmap;
      //! Current bucket index.
      std::size_t m_iBucket;
   };

public:
   /*! Constructor.

   @param m
      Source object.
   */
   map() :
      m_cBuckets(0),
      m_cUsedBuckets(0) {
   }
   map(map && m) :
      m_piHashes(std::move(m.m_piHashes)),
      m_pkeys(std::move(m.m_pkeys)),
      m_pvalues(std::move(m.m_pvalues)),
      m_cBuckets(m.m_cBuckets),
      m_cUsedBuckets(m.m_cUsedBuckets) {
      m.m_cBuckets = 0;
      m.m_cUsedBuckets = 0;
   }

   //! Destructor.
   ~map() {
      clear();
   }

   /*! Assignment operator.

   @param m
      Source object.
   */
   map & operator=(map && m) {
      m_piHashes = std::move(m.m_piHashes);
      m_pkeys = std::move(m.m_pkeys);
      m_pvalues = std::move(m.m_pvalues);
      m_cBuckets = m.m_cBuckets;
      m.m_cBuckets = 0;
      m_cUsedBuckets = m.m_cUsedBuckets;
      m.m_cUsedBuckets = 0;
      return *this;
   }

   /*! Element lookup operator.

   @param key
      Key to lookup.
   @return
      Value corresponding to key. If key is not in the map, an exception will be thrown.
   */
   TValue & operator[](TKey const & key) const {
      std::size_t iBucket = bucket_index_from_key(key);
      if (iBucket == smc_iNullIndex) {
         // TODO: throw proper exception.
         throw 0;
      }
      return m_pvalues[iBucket];
   }

   /*! Adds a key/value pair to the map, overwriting the value if key is already associated to one.

   @param key
      Key to add.
   @param value
      Value to add.
   */
   iterator add(TKey key, TValue value) {
      return iterator(this, 0);
   }

   //! Removes all elements from the map.
   void clear() {
      std::size_t * piHash = m_piHashes, * piHashesEnd = piHash + m_cBuckets;
      TKey * pkey = &get_key(0);
      TValue * pvalue = &get_value(0);
      for (; piHash < piHashesEnd; ++piHash, ++pkey, ++pvalue) {
         if (*piHash != smc_iEmptyBucketHash) {
            *piHash = smc_iEmptyBucketHash;
            pkey->~TKey();
            pvalue->~TValue();
         }
      }
      m_cUsedBuckets = 0;
   }

   /*! Removes a key/value pair given the key, which must be in the map.

   @param key
      Key associated to the value to remove.
   */
   void remove(TKey const & key) {
      std::size_t iBucket = bucket_index_from_key(key);
      if (iBucket == smc_iNullIndex) {
         // TODO: throw proper exception.
         throw 0;
      }
      // Mark the bucket as free and destruct the corresponding key and value.
      m_piHashes[iBucket] = smc_iEmptyBucketHash;
      get_key(iBucket).~TKey();
      get_value(iBucket).~TValue();
   }

private:
   void create_empty_buckets(std::size_t cBuckets = smc_cBucketsMin) {
      std::unique_ptr<std::size_t[]> piHashes(new std::size_t[cBuckets]);
      std::unique_ptr<std::max_align_t[]> pkeys(
         new std::max_align_t[ABC_ALIGNED_SIZE(sizeof(TKey) * cBuckets)]
      );
      std::unique_ptr<std::max_align_t[]> pvalues(
         new std::max_align_t[ABC_ALIGNED_SIZE(sizeof(TValue) * cBuckets)]
      );
      // Assign the new arrays and set the remaining members in an exception-safe sequence.
      m_piHashes = std::move(piHashes);
      m_pkeys = std::move(pkeys);
      m_pvalues = std::move(pvalues);
      m_cBuckets = cBuckets;
      m_cUsedBuckets = 0;
      memory::clear(m_piHashes.get(), cBuckets);
   }

   std::size_t bucket_index_from_key(TKey const & key) const {
      return bucket_index_from_key(key, get_and_adjust_hash(key));
   }
   std::size_t bucket_index_from_key(TKey const & key, std::size_t iHash) const {
      if (!m_cBuckets) {
         // No buckets, so key/iHash cannot be in the map.
         return smc_iNullIndex;
      }
      auto pairRanges(get_neighborhood_ranges_from_hash(iHash));
      // Scan till the end of the neighborhood (clipped to the end of the array).
      std::size_t iBucket = bucket_index_from_key_and_bucket_range(
         key, iHash, pairRanges.first.first, pairRanges.first.second
      );
      if (iBucket == smc_iNullIndex && pairRanges.second.first < pairRanges.second.second) {
         // This neighborhood wraps, so we have a second range of buckets to scan.
         iBucket = bucket_index_from_key_and_bucket_range(
            key, iHash, pairRanges.second.first, pairRanges.second.second
         );
      }
      return iBucket;
   }

   /*! Calculates, adjusts and returns the hash value for the specified key.

   @param key
      Key to calculate a hash value for.
   @return
      Hash value of key.
   */
   std::size_t get_and_adjust_hash(TKey const & key) const {
      std::size_t iHash = hasher::operator()(key);
      return iHash == smc_iEmptyBucketHash ? smc_iZeroHash : iHash;
   }

   TKey & get_key(std::size_t i) const {
      return reinterpret_cast<TKey *>(m_pkeys.get())[i];
   }

   /*! Returns the current neighborhood size.

   @return
      Current neighborhood size, which is not necessarily the same as smc_cNeighborhoodBuckets.
   */
   std::size_t get_neighborhood_size() const {
      // Can’t have a neighborhood larger than the total count of buckets.
      return std::min(smc_cNeighborhoodBuckets, m_cBuckets);
   }

   TValue & get_value(std::size_t i) const {
      return reinterpret_cast<TValue *>(m_pvalues.get())[i];
   }

   /*! Returns the neighborhood index (index of the first bucket in a neighborhood) for the given
   hash.

   @param iHash
      Hash to get the neighborhood index for.
   @return
      Index of the first bucket in the neighborhood.
   */
   std::size_t neighborhood_index_from_hash(std::size_t iHash) const {
      return iHash & (m_cBuckets - 1);
   }

   /*! Returns the neighborhood bucket index ranges for the given hash.

   @param iHash
      Hash to return the neighborhood of.
   @return
      The neighborhood bucket index range is expressed by [return.first.first, return.first.second);
      if the neighborhood wraps from the end of the bucket array back to its start, the wrapped
      portion is expressed by [return.second.first, return.second.second). The second interval will
      be [0, 0) (i.e. empty) if the neighborhood doesn’t wrap.
   */
   std::pair<
      std::pair<std::size_t, std::size_t>, std::pair<std::size_t, std::size_t>
   > get_neighborhood_ranges_from_hash(std::size_t iHash) const {
      // Get a range of indices representing the neighborhood.
      std::size_t iNeighborhoodBegin = neighborhood_index_from_hash(iHash);
      std::size_t iNeighborhoodEnd = iNeighborhoodBegin + get_neighborhood_size();
      // Check if the neighborhood wraps around the end of the bucket array.
      if (iNeighborhoodEnd > m_cBuckets) {
         // Return two ranges.
         return std::make_pair(
            std::make_pair(iNeighborhoodBegin, m_cBuckets),
            std::make_pair(0, iNeighborhoodEnd - m_cBuckets)
         );
      } else {
         // Return a single range.
         return std::make_pair(
            std::make_pair(iNeighborhoodBegin, iNeighborhoodEnd),
            std::make_pair(0, 0)
         );
      }
   }

   bool keys_equal(TKey const & key1, TKey const & key2) const {
      return key1 == key2;
   }

   /*! Scans a range of buckets, looking for a specific key.

   @param key
      Key to scan for.
   @param iHash
      Hash of key.
   @param iBegin
      Start of the bucket range.
   @param iEnd
      End of the bucket range.
   @return
      Index of the bucket at which the key could be found, or smc_iNullIndex if the key was not
      found.
   */
   std::size_t bucket_index_from_key_and_bucket_range(
      TKey const & key, std::size_t iHash, std::size_t iBegin, std::size_t iEnd
   ) const {
      std::size_t const * piHashesBegin = m_piHashes + iBegin, * piHashesEnd = m_piHashes + iEnd;
      TKey const * pkey = m_pkeys + iBegin;
      for (std::size_t const * piHash = piHashesBegin; piHash < piHashesEnd; ++piHash, ++pkey) {
         if (*piHash == iHash && keys_equal(*pkey == key)) {
            return static_cast<std::size_t>(piHash - piHashesBegin);
         }
      }
      return smc_iNullIndex;
   }

private:
   //! Array containing the hash of each key.
   std::unique_ptr<std::size_t[]> m_piHashes;
   //! Array of keys.
   std::unique_ptr<std::max_align_t[]> m_pkeys;
   //! Array of buckets.
   std::unique_ptr<std::max_align_t[]> m_pvalues;
   //! Count of total buckets.
   std::size_t m_cBuckets;
   //! Count of elements / occupied buckets.
   std::size_t m_cUsedBuckets;
   //! Minimum bucket count.
   static std::size_t const smc_cBucketsMin = 8;
   //! Special hash value used to indicate that a bucket is empty.
   static std::size_t const smc_iEmptyBucketHash = 0;
   //! Neighborhood size.
   static std::size_t const smc_cNeighborhoodBuckets = sizeof(std::size_t) * CHAR_BIT;
   //! Special index returned by several methods to indicate a logical “null index”.
   static std::size_t const smc_iNullIndex = numeric::max<std::size_t>::value;
   /*! Hash value substituted when the hash function returns 0; this is so we can use 0 (aliased by
   smc_iEmptyBucketHash) as a special value. This specific value is merely the largest prime number
   that will fit in 2^16, which is the (future, if ever) minimum word size supported by Abaclade. */
   static std::size_t const smc_iZeroHash = 65521;
};

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifndef _ABACLADE_MAP_HXX

<|endoftext|>


<commit_before>#pragma once

///////////////////////////////////////////////////////////////////////////////
/// @file Bun.hpp
/// @author BrainlessLabs
/// @version 0.3
/// @brief The include file for Bun ORM. This file includes all the source
///        to make the class/struct persist in sqlite. Users need to include
///        only this file.
///////////////////////////////////////////////////////////////////////////////
#include <string>
#include <memory>
#include <boost/preprocessor.hpp>
#include <third_party/fmt/format.hpp>
#include "blib/bun/PRefHelper.hpp"
#include "blib/bun/DbBackend.hpp"
#include "blib/bun/DbLogger.hpp"
#include "blib/bun/CppTypeToSQLString.hpp"

///////////////////////////////////////////////////////////////////////////////
/// @basic Basic Persistance Start
/// @details We will be using the Bun class for all the examples and
///          understanding
///          struct Bun {
///            std::string bun_name,
///            float sugar_quantity;
///            float flour_quantity;
///            float milk_quantity;
///            float yeast_quantity;
///            float butter_quantity;
///            int bun_length;
///          };
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
/// Helper Macros Start
///////////////////////////////////////////////////////////////////////////////

/// @brief Make this 0 if no log is needed, else make it 1
#define QUERY_LOG_ON 1
/// @brief Log the query
#define QUERY_LOG(log_string) BOOST_PP_EXPR_IF(QUERY_LOG_ON, l().info(log_string))

/// @brief SOCI ORM Helper Macros
/// @details from_base
/// @param ELEMS_TUP = (bun_name, sugar_quantity, flour_quantity, milk_quantity, yeast_quantity, butter_quantity, bun_length)
#define EXPAND_MEMBER_ASSIGNENTS_from_base_I(z, n, ELEMS_TUP) c.BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP) = v.get<decltype(c.BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP))>(BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)));
#define EXPAND_MEMBER_ASSIGNENTS_from_base(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_MEMBER_ASSIGNENTS_from_base_I, ELEMS_TUP)

/// @details to_base
/// @param ELEMS_TUP = (bun_name, sugar_quantity, flour_quantity, milk_quantity, yeast_quantity, butter_quantity, bun_length)
#define EXPAND_MEMBER_ASSIGNENTS_to_base_I(z, n, ELEMS_TUP) v.set(BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)), c.BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP));
#define EXPAND_MEMBER_ASSIGNENTS_to_base(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_MEMBER_ASSIGNENTS_to_base_I, ELEMS_TUP)

/// @brief createSchema Helper Macros
/// @details We need to pass only the data members as a tuple to this macro
/// @param ELEMS_TUP = (bun_name, sugar_quantity, flour_quantity, milk_quantity, yeast_quantity, butter_quantity, bun_length)
/// @brief Expands the class members for CREATE TABLE
#define EXPAND_CLASS_MEMBERS_createSchema_I(z, n, ELEMS_TUP) BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)) " {}"
#define EXPAND_CLASS_MEMBERS_createSchema(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_CLASS_MEMBERS_createSchema_I, ELEMS_TUP)

/// @brief Expands the class members for CREATE TABLE to get the type info
#define EXPAND_CLASS_TYPE_MEMBERS_createSchema_I(z, n, CLASS_ELEMS_TUP) BOOST_PP_COMMA_IF(n) blib::bun::cppTypeToDbTypeString<decltype(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP)::BOOST_PP_TUPLE_ELEM(BOOST_PP_ADD(n,1), CLASS_ELEMS_TUP))>()
#define EXPAND_CLASS_TYPE_MEMBERS_createSchema(CLASS_ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_SUB(BOOST_PP_TUPLE_SIZE(CLASS_ELEMS_TUP), 1), EXPAND_CLASS_TYPE_MEMBERS_createSchema_I, CLASS_ELEMS_TUP)

/// @brief persistObj Helper Macros
/// @brief Changes related to INSERT INTO
/// @brief EXPAND_CLASS_TYPE_MEMBERS_persistObj
#define EXPAND_FIELDS_persistObj_I(z, n, ELEMS_TUP) BOOST_PP_IDENTITY(",")() BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP))
#define EXPAND_FIELDS_persistObj(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_FIELDS_persistObj_I, ELEMS_TUP)

/// @brief Expand the variables for persistObj
#define EXPAND_VARIABLES_persistObj_I(z, n, ELEMS_TUP) BOOST_PP_COMMA_IF(n)obj->BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)
#define EXPAND_VARIABLES_persistObj(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_VARIABLES_persistObj_I, ELEMS_TUP)

/// @brief updateObj Helper Macros
/// @brief Changes related to UPDATE table SET
/// @brief Expand the braces for updateObj
#define EXPAND_BRACES_updateObj_I(z, n, ELEMS_TUP) BOOST_PP_EXPR_IF(n, ",")BOOST_STRINGIZE({} = {})
#define EXPAND_BRACES_updateObj(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_BRACES_updateObj_I, ELEMS_TUP)

/// @brief Expand the variables for updateObj
#define EXPAND_VARIABLES_updateObj_I(z, n, ELEMS_TUP) BOOST_PP_COMMA()BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP))BOOST_PP_COMMA()obj->BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)
#define EXPAND_VARIABLES_updateObj(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_VARIABLES_updateObj_I, ELEMS_TUP)

/// @brief getObj Helper Macros
/// @brief getObj will get a autoptr to

/// @brief Assorted Helper Macros
/// @brief Create n number of string
#define Repeat_N_String_With_Precomma_I(z, n, text)  BOOST_PP_IDENTITY(",")() BOOST_STRINGIZE(text)
#define Repeat_N_String_With_Precomma(n, text) BOOST_PP_REPEAT(n, Repeat_N_String_With_Precomma_I, text)

/// @brief Macro to output comments
#define BLIB_MACRO_COMMENTS_ENABLED 1
#define BLIB_MACRO_COMMENTS_IF(a) BOOST_PP_EXPR_IF(BLIB_MACRO_COMMENTS_ENABLED, a)

///////////////////////////////////////////////////////////////////////////////
/// Helper Macros End
///////////////////////////////////////////////////////////////////////////////

/// SPECIALIZE_BUN_HELPER Start
#define SPECIALIZE_BUN_HELPER(CLASS_ELEMS_TUP) namespace soci{\
BLIB_MACRO_COMMENTS_IF("@brief --Specialization for SOCI ORM Start---");\
template<>\
struct type_conversion<BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP)>{\
typedef values base_type;\
using ClassType = BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP);\
static void from_base(values const& v, indicator ind, ClassType& c){\
BLIB_MACRO_COMMENTS_IF("@brief from_base gets the values from db");\
EXPAND_MEMBER_ASSIGNENTS_from_base(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP ));\
}\
static void to_base(const ClassType& c, values& v, indicator& ind){\
BLIB_MACRO_COMMENTS_IF("@brief to_base puts the values to db");\
EXPAND_MEMBER_ASSIGNENTS_to_base(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP ));\
}\
};\
}\
namespace blib{namespace bun{namespace __private{\
BLIB_MACRO_COMMENTS_IF("@brief --Specialization for PRefHelper Start---");\
template<>\
struct PRefHelper<BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP)>{\
using T = BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP);\
\
inline static void createSchema(){\
BLIB_MACRO_COMMENTS_IF("@brief createSchema for creating the schema of an object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const query = "CREATE TABLE IF NOT EXISTS '{}' (oid_high INTEGER PRIMARY KEY AUTOINCREMENT, oid_low INTEGER NOT NULL" \
EXPAND_CLASS_MEMBERS_createSchema(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP )) \
 ")";\
static std::string const sql = fmt::format(query, class_name, EXPAND_CLASS_TYPE_MEMBERS_createSchema(CLASS_ELEMS_TUP));\
QUERY_LOG(sql);\
blib::bun::_private::DbBackend().i().session() << sql;\
}\
\
inline static void deleteSchema(){\
BLIB_MACRO_COMMENTS_IF("@brief deleteSchema for deleting the schema of an object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const sql = fmt::format("DROP TABLE '{}'", class_name);\
QUERY_LOG(sql);\
blib::bun::_private::DbBackend().i().session() << sql;\
}\
\
inline static SimpleOID persistObj( T* obj ){\
BLIB_MACRO_COMMENTS_IF("@brief persistObj for persisting the object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
SimpleOID oid;\
oid.populateLow();\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const query = "INSERT INTO '{}' (oid_low" \
EXPAND_FIELDS_persistObj(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP ))\
") VALUES ({}" \
Repeat_N_String_With_Precomma(BOOST_PP_TUPLE_SIZE(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP )), {})\
;\
std::string const sql = fmt::format(query, class_name, oid.low,\
EXPAND_VARIABLES_persistObj(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP ))\
);\
QUERY_LOG(sql);\
return oid;\
}\
inline static void updateObj( T* obj, SimpleOID const& oid ){\
BLIB_MACRO_COMMENTS_IF("@brief updateObj for updating a persisted object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const query = "UPDATE {} SET " \
EXPAND_BRACES_updateObj(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP )) \
" WHERE oid_low={} AND oid_high={}";\
std::string const sql = fmt::format(query, class_name \
EXPAND_VARIABLES_updateObj(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP )) \
,oid.low, oid.high);\
QUERY_LOG(sql);\
}\
inline static void deleteObj( SimpleOID const& oid ){\
BLIB_MACRO_COMMENTS_IF("@brief deleteObj for deleting a persisted object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const query = "DELETE FROM {} WHERE oid_high={} AND oid_low={}";\
std::string const sql = fmt::format(query, class_name, oid.high, oid.low);\
QUERY_LOG(sql);\
}\
inline static std::unique_ptr<T> getObj( SimpleOID const& oid ){\
BLIB_MACRO_COMMENTS_IF("@brief getObj for getting a persisted object with the oid");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
std::unique_ptr<T> obj = std::make_unique<T>();\
static std::string const query = "SELECT "\
EXPAND_QUERY_VARIABLES_getObj()\
" FROM {} WHERE oid_high={} AND oid_low={}";\
std::string const sql = fmt::format(query, class_name, oid.high, oid.low);\
QUERY_LOG(sql);\
return std::move(obj);\
}\
};\
BLIB_MACRO_COMMENTS_IF("@brief ---Specialization for PRefHelper End---");\
BLIB_MACRO_COMMENTS_IF("@brief ---===---");\
BLIB_MACRO_COMMENTS_IF("@brief --Specialization for QueryHelper Start---");\
template<>\
struct QueryHelper<BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP)>{\
using ClassType = BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP);\
inline static std::vector <SimpleOID> getAllOids(){\
}\
};\
BLIB_MACRO_COMMENTS_IF("@brief ---Specialization for QueryHelper End---");\
}\
}\
}\

/// SPECIALIZE_BUN_HELPER End

///////////////////////////////////////////////////////////////////////////////
/// @basic Basic Persistance End
///////////////////////////////////////////////////////////////////////////////<commit_msg>Adding the query to the statemants<commit_after>#pragma once

///////////////////////////////////////////////////////////////////////////////
/// @file Bun.hpp
/// @author BrainlessLabs
/// @version 0.3
/// @brief The include file for Bun ORM. This file includes all the source
///        to make the class/struct persist in sqlite. Users need to include
///        only this file.
///////////////////////////////////////////////////////////////////////////////
#include <string>
#include <memory>
#include <boost/preprocessor.hpp>
#include <third_party/fmt/format.hpp>
#include "blib/bun/PRefHelper.hpp"
#include "blib/bun/DbBackend.hpp"
#include "blib/bun/DbLogger.hpp"
#include "blib/bun/CppTypeToSQLString.hpp"

///////////////////////////////////////////////////////////////////////////////
/// @basic Basic Persistance Start
/// @details We will be using the Bun class for all the examples and
///          understanding
///          struct Bun {
///            std::string bun_name,
///            float sugar_quantity;
///            float flour_quantity;
///            float milk_quantity;
///            float yeast_quantity;
///            float butter_quantity;
///            int bun_length;
///          };
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
/// Helper Macros Start
///////////////////////////////////////////////////////////////////////////////

/// @brief Make this 0 if no log is needed, else make it 1
#define QUERY_LOG_ON 1
/// @brief Log the query
#define QUERY_LOG(log_string) BOOST_PP_EXPR_IF(QUERY_LOG_ON, l().info(log_string))

/// @brief SOCI ORM Helper Macros
/// @details from_base
/// @param ELEMS_TUP = (bun_name, sugar_quantity, flour_quantity, milk_quantity, yeast_quantity, butter_quantity, bun_length)
#define EXPAND_MEMBER_ASSIGNENTS_from_base_I(z, n, ELEMS_TUP) c.BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP) = v.get<decltype(c.BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP))>(BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)));
#define EXPAND_MEMBER_ASSIGNENTS_from_base(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_MEMBER_ASSIGNENTS_from_base_I, ELEMS_TUP)

/// @details to_base
/// @param ELEMS_TUP = (bun_name, sugar_quantity, flour_quantity, milk_quantity, yeast_quantity, butter_quantity, bun_length)
#define EXPAND_MEMBER_ASSIGNENTS_to_base_I(z, n, ELEMS_TUP) v.set(BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)), c.BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP));
#define EXPAND_MEMBER_ASSIGNENTS_to_base(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_MEMBER_ASSIGNENTS_to_base_I, ELEMS_TUP)

/// @brief createSchema Helper Macros
/// @details We need to pass only the data members as a tuple to this macro
/// @param ELEMS_TUP = (bun_name, sugar_quantity, flour_quantity, milk_quantity, yeast_quantity, butter_quantity, bun_length)
/// @brief Expands the class members for CREATE TABLE
#define EXPAND_CLASS_MEMBERS_createSchema_I(z, n, ELEMS_TUP) BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)) " {}"
#define EXPAND_CLASS_MEMBERS_createSchema(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_CLASS_MEMBERS_createSchema_I, ELEMS_TUP)

/// @brief Expands the class members for CREATE TABLE to get the type info
#define EXPAND_CLASS_TYPE_MEMBERS_createSchema_I(z, n, CLASS_ELEMS_TUP) BOOST_PP_COMMA_IF(n) blib::bun::cppTypeToDbTypeString<decltype(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP)::BOOST_PP_TUPLE_ELEM(BOOST_PP_ADD(n,1), CLASS_ELEMS_TUP))>()
#define EXPAND_CLASS_TYPE_MEMBERS_createSchema(CLASS_ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_SUB(BOOST_PP_TUPLE_SIZE(CLASS_ELEMS_TUP), 1), EXPAND_CLASS_TYPE_MEMBERS_createSchema_I, CLASS_ELEMS_TUP)

/// @brief persistObj Helper Macros
/// @brief Changes related to INSERT INTO
/// @brief EXPAND_CLASS_TYPE_MEMBERS_persistObj
#define EXPAND_FIELDS_persistObj_I(z, n, ELEMS_TUP) BOOST_PP_IDENTITY(",")() BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP))
#define EXPAND_FIELDS_persistObj(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_FIELDS_persistObj_I, ELEMS_TUP)

/// @brief Expand the variables for persistObj
#define EXPAND_VARIABLES_persistObj_I(z, n, ELEMS_TUP) BOOST_PP_COMMA_IF(n)obj->BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)
#define EXPAND_VARIABLES_persistObj(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_VARIABLES_persistObj_I, ELEMS_TUP)

/// @brief updateObj Helper Macros
/// @brief Changes related to UPDATE table SET
/// @brief Expand the braces for updateObj
#define EXPAND_BRACES_updateObj_I(z, n, ELEMS_TUP) BOOST_PP_EXPR_IF(n, ",")BOOST_STRINGIZE({} = {})
#define EXPAND_BRACES_updateObj(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_BRACES_updateObj_I, ELEMS_TUP)

/// @brief Expand the variables for updateObj
#define EXPAND_VARIABLES_updateObj_I(z, n, ELEMS_TUP) BOOST_PP_COMMA()BOOST_STRINGIZE(BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP))BOOST_PP_COMMA()obj->BOOST_PP_TUPLE_ELEM(n, ELEMS_TUP)
#define EXPAND_VARIABLES_updateObj(ELEMS_TUP) BOOST_PP_REPEAT(BOOST_PP_TUPLE_SIZE(ELEMS_TUP), EXPAND_VARIABLES_updateObj_I, ELEMS_TUP)

/// @brief getObj Helper Macros
/// @brief getObj will get a autoptr to

/// @brief Assorted Helper Macros
/// @brief Create n number of string
#define Repeat_N_String_With_Precomma_I(z, n, text)  BOOST_PP_IDENTITY(",")() BOOST_STRINGIZE(text)
#define Repeat_N_String_With_Precomma(n, text) BOOST_PP_REPEAT(n, Repeat_N_String_With_Precomma_I, text)

/// @brief Macro to output comments
#define BLIB_MACRO_COMMENTS_ENABLED 1
#define BLIB_MACRO_COMMENTS_IF(a) BOOST_PP_EXPR_IF(BLIB_MACRO_COMMENTS_ENABLED, a)

///////////////////////////////////////////////////////////////////////////////
/// Helper Macros End
///////////////////////////////////////////////////////////////////////////////

/// SPECIALIZE_BUN_HELPER Start
#define SPECIALIZE_BUN_HELPER(CLASS_ELEMS_TUP) namespace soci{\
BLIB_MACRO_COMMENTS_IF("@brief --Specialization for SOCI ORM Start---");\
template<>\
struct type_conversion<BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP)>{\
typedef values base_type;\
using ClassType = BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP);\
inline static void from_base(values const& v, indicator ind, ClassType& c){\
BLIB_MACRO_COMMENTS_IF("@brief from_base gets the values from db");\
EXPAND_MEMBER_ASSIGNENTS_from_base(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP ));\
}\
inline static void to_base(const ClassType& c, values& v, indicator& ind){\
BLIB_MACRO_COMMENTS_IF("@brief to_base puts the values to db");\
EXPAND_MEMBER_ASSIGNENTS_to_base(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP ));\
}\
};\
}\
namespace blib{namespace bun{namespace __private{\
BLIB_MACRO_COMMENTS_IF("@brief --Specialization for PRefHelper Start---");\
template<>\
struct PRefHelper<BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP)>{\
using T = BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP);\
\
inline static void createSchema(){\
BLIB_MACRO_COMMENTS_IF("@brief createSchema for creating the schema of an object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const query = "CREATE TABLE IF NOT EXISTS '{}' (oid_high INTEGER PRIMARY KEY AUTOINCREMENT, oid_low INTEGER NOT NULL" \
EXPAND_CLASS_MEMBERS_createSchema(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP )) \
 ")";\
static std::string const sql = fmt::format(query, class_name, EXPAND_CLASS_TYPE_MEMBERS_createSchema(CLASS_ELEMS_TUP));\
QUERY_LOG(sql);\
blib::bun::_private::DbBackend().i().session() << sql;\
}\
\
inline static void deleteSchema(){\
BLIB_MACRO_COMMENTS_IF("@brief deleteSchema for deleting the schema of an object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const sql = fmt::format("DROP TABLE '{}'", class_name);\
QUERY_LOG(sql);\
blib::bun::_private::DbBackend().i().session() << sql;\
}\
\
inline static SimpleOID persistObj( T* obj ){\
BLIB_MACRO_COMMENTS_IF("@brief persistObj for persisting the object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
SimpleOID oid;\
oid.populateLow();\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const query = "INSERT INTO '{}' (oid_low" \
EXPAND_FIELDS_persistObj(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEM S_TUP ))\
") VALUES ({}" \
Repeat_N_String_With_Precomma(BOOST_PP_TUPLE_SIZE(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP )), {})\
;\
std::string const sql = fmt::format(query, class_name, oid.low,\
EXPAND_VARIABLES_persistObj(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP ))\
);\
QUERY_LOG(sql);\
blib::bun::_private::DbBackend().i().session() << sql, use(*obj);\
return oid;\
}\
inline static void updateObj( T* obj, SimpleOID const& oid ){\
BLIB_MACRO_COMMENTS_IF("@brief updateObj for updating a persisted object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const query = "UPDATE {} SET " \
EXPAND_BRACES_updateObj(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP )) \
" WHERE oid_low={} AND oid_high={}";\
std::string const sql = fmt::format(query, class_name \
EXPAND_VARIABLES_updateObj(BOOST_PP_TUPLE_POP_FRONT( CLASS_ELEMS_TUP )) \
,oid.low, oid.high);\
QUERY_LOG(sql);\
blib::bun::_private::DbBackend().i().session() << sql, use(*obj);\
}\
inline static void deleteObj( SimpleOID const& oid ){\
BLIB_MACRO_COMMENTS_IF("@brief deleteObj for deleting a persisted object");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
static std::string const query = "DELETE FROM {} WHERE oid_high={} AND oid_low={}";\
std::string const sql = fmt::format(query, class_name, oid.high, oid.low);\
QUERY_LOG(sql);\
blib::bun::_private::DbBackend().i().session() << sql;\
}\
inline static std::unique_ptr<T> getObj( SimpleOID const& oid ){\
BLIB_MACRO_COMMENTS_IF("@brief getObj for getting a persisted object with the oid");\
static std::string const class_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP));\
std::unique_ptr<T> obj = std::make_unique<T>();\
static std::string const query = "SELECT "\
EXPAND_QUERY_VARIABLES_getObj()\
" FROM {} WHERE oid_high={} AND oid_low={}";\
std::string const sql = fmt::format(query, class_name, oid.high, oid.low);\
QUERY_LOG(sql);\
blib::bun::_private::DbBackend().i().session() << sql, into(*obj);\
return std::move(obj);\
}\
};\
BLIB_MACRO_COMMENTS_IF("@brief ---Specialization for PRefHelper End---");\
BLIB_MACRO_COMMENTS_IF("@brief ---===---");\
BLIB_MACRO_COMMENTS_IF("@brief --Specialization for QueryHelper Start---");\
template<>\
struct QueryHelper<BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP)>{\
using ClassType = BOOST_PP_TUPLE_ELEM(0, CLASS_ELEMS_TUP);\
inline static std::vector <SimpleOID> getAllOids(){\
}\
};\
BLIB_MACRO_COMMENTS_IF("@brief ---Specialization for QueryHelper End---");\
}\
}\
}\

/// SPECIALIZE_BUN_HELPER End

///////////////////////////////////////////////////////////////////////////////
/// @basic Basic Persistance End
///////////////////////////////////////////////////////////////////////////////<|endoftext|>


<commit_before>#pragma once

#include <type_list.hpp>
#include <integer_sequence.hpp>
#include <sfinae.hpp>

#include "reflection_info.hpp"
#include "director.hpp"

namespace shadow
{

template <class CompileTimeTypeInfo>
struct extract_name
{
    static constexpr const char* value = CompileTimeTypeInfo::name;
};

template <class TypeListOfCompileTimeTypeInfo>
using generate_array_of_strings =
    metamusil::t_list::value_transform<TypeListOfCompileTimeTypeInfo,
                                       extract_name>;

template <class CompileTimeTypeInfo>
struct extract_type_info
{
    static constexpr type_info value = {CompileTimeTypeInfo::name,
                                        CompileTimeTypeInfo::size};
};

template <class TypeListOfCompileTimeTypeInfo>
using generate_array_of_type_info =
    metamusil::t_list::value_transform<TypeListOfCompileTimeTypeInfo,
                                       extract_type_info>;

template <template <std::size_t> class CTI, class IntSeqRange>
struct generate_valid_compile_time_type_infos
{
    template <typename IntSeqRange::value_type LineNum>
    using is_defined_predicate =
        metamusil::integral_specialization_defined<std::size_t, CTI, LineNum>;

    typedef metamusil::int_seq::filter_t<IntSeqRange, is_defined_predicate>
        filtered_line_range;

    typedef metamusil::t_list::from_integer_template_instantiations_t<
        std::size_t,
        CTI,
        filtered_line_range>
        type;
};

template <template <std::size_t> class CTI, class IntSeqRange>
using generate_valid_compile_time_type_infos_t =
    typename generate_valid_compile_time_type_infos<CTI, IntSeqRange>::type;
}

////////////////////////////////////////////////////////////////////////////////
// Type registration
#define REGISTER_TYPE_BEGIN()                                                  \
    constexpr std::size_t type_line_begin = __LINE__;                          \
    template <std::size_t LineNum>                                             \
    struct compile_time_type_info;

#define REGISTER_TYPE(type_name)                                               \
    template <>                                                                \
    struct compile_time_type_info<__LINE__>                                    \
    {                                                                          \
        typedef type_name type;                                                \
        static constexpr char name[] = #type_name;                             \
        static const std::size_t size = sizeof(type_name);                     \
    };                                                                         \
                                                                               \
    constexpr char compile_time_type_info<__LINE__>::name[];

#define REGISTER_TYPE_END()                                                    \
    constexpr std::size_t type_line_end = __LINE__;                            \
                                                                               \
    typedef metamusil::int_seq::integer_sequence_from_range_t<                 \
        std::size_t,                                                           \
        type_line_begin + 1,                                                   \
        type_line_end>                                                         \
        type_line_range;                                                       \
                                                                               \
    typedef shadow::generate_valid_compile_time_type_infos_t<                  \
        compile_time_type_info,                                                \
        type_line_range>                                                       \
        instantiated_compile_time_infos;                                       \
                                                                               \
    typedef shadow::generate_array_of_strings<instantiated_compile_time_infos> \
        type_name_array_holder;                                                \
                                                                               \
    typedef shadow::generate_array_of_type_info<                               \
        instantiated_compile_time_infos>                                       \
        type_info_array_holder;

////////////////////////////////////////////////////////////////////////////////
// Constructor registration
#define REGISTER_CONSTRUCTOR_BEGIN()                                           \
    constexpr std::size_t constructor_line_begin = __LINE__;

#define REGISTER_CONSTRUCTOR(type_name, ...)

#define REGISTER_CONSTRUCTOR_END()                                             \
    constexpr std::size_t constructor_line_end = __LINE__;

////////////////////////////////////////////////////////////////////////////////
// Initialize Shadow reflection library
#define SHADOW_INIT()                                                          \
    static const shadow::director reflection_director{                         \
        type_name_array_holder(), type_info_array_holder()};
<commit_msg>Shuffle some code. 	modified:   include/compile_time.hpp<commit_after>#pragma once

#include <type_list.hpp>
#include <integer_sequence.hpp>
#include <sfinae.hpp>

#include "reflection_info.hpp"
#include "director.hpp"

namespace shadow
{
// generate type_list of instantiated compile_time_type_info to feed
// generate_array_of_type_info and generate_array_of_strings
template <template <std::size_t> class CTI, class IntSeqRange>
struct generate_valid_compile_time_type_infos
{
    template <typename IntSeqRange::value_type LineNum>
    using is_defined_predicate =
        metamusil::integral_specialization_defined<std::size_t, CTI, LineNum>;

    typedef metamusil::int_seq::filter_t<IntSeqRange, is_defined_predicate>
        filtered_line_range;

    typedef metamusil::t_list::from_integer_template_instantiations_t<
        std::size_t,
        CTI,
        filtered_line_range>
        type;
};

template <template <std::size_t> class CTI, class IntSeqRange>
using generate_valid_compile_time_type_infos_t =
    typename generate_valid_compile_time_type_infos<CTI, IntSeqRange>::type;

// extract name and make an array of type names at compile time
template <class CompileTimeTypeInfo>
struct extract_name
{
    static constexpr const char* value = CompileTimeTypeInfo::name;
};

template <class TypeListOfCompileTimeTypeInfo>
using generate_array_of_strings =
    metamusil::t_list::value_transform<TypeListOfCompileTimeTypeInfo,
                                       extract_name>;

// extract type info and make array of type_info at compile time
template <class CompileTimeTypeInfo>
struct extract_type_info
{
    static constexpr type_info value = {CompileTimeTypeInfo::name,
                                        CompileTimeTypeInfo::size};
};

template <class TypeListOfCompileTimeTypeInfo>
using generate_array_of_type_info =
    metamusil::t_list::value_transform<TypeListOfCompileTimeTypeInfo,
                                       extract_type_info>;
}

////////////////////////////////////////////////////////////////////////////////
// Type registration
#define REGISTER_TYPE_BEGIN()                                                  \
    constexpr std::size_t type_line_begin = __LINE__;                          \
    template <std::size_t LineNum>                                             \
    struct compile_time_type_info;

#define REGISTER_TYPE(type_name)                                               \
    template <>                                                                \
    struct compile_time_type_info<__LINE__>                                    \
    {                                                                          \
        typedef type_name type;                                                \
        static constexpr char name[] = #type_name;                             \
        static const std::size_t size = sizeof(type_name);                     \
    };                                                                         \
                                                                               \
    constexpr char compile_time_type_info<__LINE__>::name[];

#define REGISTER_TYPE_END()                                                    \
    constexpr std::size_t type_line_end = __LINE__;                            \
                                                                               \
    typedef metamusil::int_seq::integer_sequence_from_range_t<                 \
        std::size_t,                                                           \
        type_line_begin + 1,                                                   \
        type_line_end>                                                         \
        type_line_range;                                                       \
                                                                               \
    typedef shadow::generate_valid_compile_time_type_infos_t<                  \
        compile_time_type_info,                                                \
        type_line_range>                                                       \
        instantiated_compile_time_infos;                                       \
                                                                               \
    typedef shadow::generate_array_of_strings<instantiated_compile_time_infos> \
        type_name_array_holder;                                                \
                                                                               \
    typedef shadow::generate_array_of_type_info<                               \
        instantiated_compile_time_infos>                                       \
        type_info_array_holder;

////////////////////////////////////////////////////////////////////////////////
// Constructor registration
#define REGISTER_CONSTRUCTOR_BEGIN()                                           \
    constexpr std::size_t constructor_line_begin = __LINE__;

#define REGISTER_CONSTRUCTOR(type_name, ...)

#define REGISTER_CONSTRUCTOR_END()                                             \
    constexpr std::size_t constructor_line_end = __LINE__;

////////////////////////////////////////////////////////////////////////////////
// Initialize Shadow reflection library
#define SHADOW_INIT()                                                          \
    static const shadow::director reflection_director{                         \
        type_name_array_holder(), type_info_array_holder()};
<|endoftext|>