include/wrenbind17/std.hpp

include/wrenbind17/std.hpp #

Namespaces #

Name
wrenbind17

Classes #

Name
class wrenbind17::StdVectorBindings
class wrenbind17::StdListBindings
class wrenbind17::AbstractMapBindings

Source code #

#pragma once

#include <algorithm>
#include <list>
#include <map>
#include <unordered_map>
#include <vector>

#include "module.hpp"

namespace wrenbind17 {
#ifndef DOXYGEN_SHOULD_SKIP_THIS
    namespace detail {
        template <typename T, typename = void> struct is_equality_comparable : std::false_type {};

        template <typename T>
        struct is_equality_comparable<
            T, typename std::enable_if<true, decltype(std::declval<T&>() == std::declval<T&>(), (void)0)>::type>
            : std::true_type {};
    } // namespace detail

    template <typename T, typename T2 = void> class StdVectorHelper;

    template <typename T>
    class StdVectorHelper<T, typename std::enable_if<detail::is_equality_comparable<T>::value>::type> {
    public:
        static bool contains(std::vector<T>& self, const T& value) {
            return std::find(self.begin(), self.end(), value) != self.end();
        }
    };

    template <typename T>
    class StdVectorHelper<T, typename std::enable_if<!detail::is_equality_comparable<T>::value>::type> {
    public:
        static bool contains(std::vector<T>& self, const T& value) {
            return std::find_if(self.begin(), self.end(), [&](const T& e) -> bool { return &e == &value; }) !=
                   self.end();
        }
    };
#endif

    template <typename T> class StdVectorBindings {
    public:
        typedef typename std::vector<T>::iterator Iterator;
        typedef typename std::vector<T> Vector;

        static void setIndex(Vector& self, size_t index, T value) {
            self[index] = std::move(value);
        }

        static const T& getIndex(Vector& self, size_t index) {
            return self[index];
        }

        static void add(Vector& self, T value) {
            self.push_back(std::move(value));
        }

        static std::variant<bool, Iterator> iterate(Vector& self, std::variant<std::nullptr_t, Iterator> other) {
            if (other.index() == 1) {
                auto it = std::get<Iterator>(other);
                ++it;
                if (it != self.end()) {
                    return {it};
                }

                return {false};
            } else {
                if (self.empty())
                    return {false};
                return {self.begin()};
            }
        }

        static const T& iteratorValue(Vector& self, std::shared_ptr<Iterator> other) {
            auto& it = *other;
            return *it;
        }

        static size_t count(Vector& self) {
            return self.size();
        }

        static T removeAt(Vector& self, int32_t index) {
            if (index == -1) {
                auto ret = std::move(self.back());
                self.pop_back();
                return std::move(ret);
            } else {
                if (index < 0) {
                    index = static_cast<int32_t>(self.size()) + index;
                }

                if (index > static_cast<int32_t>(self.size())) {
                    throw std::out_of_range("invalid index");
                } else if (index == static_cast<int32_t>(self.size())) {
                    auto ret = std::move(self.back());
                    self.pop_back();
                    return std::move(ret);
                } else {
                    auto ret = std::move(self.at(index));
                    self.erase(self.begin() + index);
                    return std::move(ret);
                }
            }
        }

        static void insert(Vector& self, int32_t index, T value) {
            if (index == -1) {
                self.push_back(std::move(value));
            } else {
                if (index < 0) {
                    index = static_cast<int32_t>(self.size()) + index;
                }

                if (index > static_cast<int32_t>(self.size())) {
                    throw std::out_of_range("invalid index");
                } else if (index == static_cast<int32_t>(self.size())) {
                    self.push_back(std::move(value));
                } else {
                    auto it = self.begin() + index;
                    self.insert(it, std::move(value));
                }
            }
        }

        static bool contains(Vector& self, const T& value) {
            // return std::find(self.begin(), self.end(), value) != self.end();
            return StdVectorHelper<T>::contains(self, value);
        }

        static T pop(Vector& self) {
            auto ret = std::move(self.back());
            self.pop_back();
            return std::move(ret);
        }

        static void clear(Vector& self) {
            self.clear();
        }

        static size_t size(Vector& self) {
            return self.size();
        }

        static bool empty(Vector& self) {
            return self.empty();
        }

        static void bind(ForeignModule& m, const std::string& name) {
            auto& iter = m.klass<Iterator>(name + "Iter");
            iter.ctor();

            auto& cls = m.klass<Vector>(name);
            cls.ctor();

            cls.template funcExt<&StdVectorBindings<T>::getIndex>(OPERATOR_GET_INDEX);
            cls.template funcExt<&StdVectorBindings<T>::setIndex>(OPERATOR_SET_INDEX);
            cls.template funcExt<&StdVectorBindings<T>::add>("add");
            cls.template funcExt<&StdVectorBindings<T>::iterate>("iterate");
            cls.template funcExt<&StdVectorBindings<T>::iteratorValue>("iteratorValue");
            cls.template funcExt<&StdVectorBindings<T>::removeAt>("removeAt");
            cls.template funcExt<&StdVectorBindings<T>::insert>("insert");
            cls.template funcExt<&StdVectorBindings<T>::contains>("contains");
            cls.template funcExt<&StdVectorBindings<T>::pop>("pop");
            cls.template funcExt<&StdVectorBindings<T>::clear>("clear");
            cls.template funcExt<&StdVectorBindings<T>::size>("size");
            cls.template funcExt<&StdVectorBindings<T>::empty>("empty");
            cls.template propReadonlyExt<&StdVectorBindings<T>::count>("count");
        }
    };

    template <typename T> class StdListBindings {
    public:
        typedef typename std::list<T>::iterator Iterator;
        typedef typename std::list<T> List;

        static void setIndex(List& self, size_t index, T value) {
            auto it = self.begin();
            std::advance(it, index);
            *it = std::move(value);
        }

        static const T& getIndex(List& self, size_t index) {
            auto it = self.begin();
            std::advance(it, index);
            return *it;
        }

        static void add(List& self, T value) {
            self.push_back(std::move(value));
        }

        static std::variant<bool, Iterator> iterate(List& self, std::variant<std::nullptr_t, Iterator> other) {
            if (other.index() == 1) {
                auto it = std::get<Iterator>(other);
                ++it;
                if (it != self.end()) {
                    return {it};
                }

                return {false};
            } else {
                if (self.empty())
                    return {false};
                return {self.begin()};
            }
        }

        static const T& iteratorValue(List& self, std::shared_ptr<Iterator> other) {
            auto& it = *other;
            return *it;
        }

        static size_t count(List& self) {
            return self.size();
        }

        static T removeAt(List& self, int32_t index) {
            if (index == -1) {
                auto ret = std::move(self.back());
                self.pop_back();
                return std::move(ret);
            } else {
                if (index < 0) {
                    index = static_cast<int32_t>(self.size()) + index;
                }

                if (index > static_cast<int32_t>(self.size())) {
                    throw std::out_of_range("invalid index");
                } else if (index == static_cast<int32_t>(self.size())) {
                    auto ret = std::move(self.back());
                    self.pop_back();
                    return std::move(ret);
                } else {
                    auto it = self.begin();
                    std::advance(it, index);
                    auto ret = std::move(*it);
                    self.erase(it);
                    return std::move(ret);
                }
            }
        }

        static void insert(List& self, int32_t index, T value) {
            if (index == -1) {
                self.push_back(std::move(value));
            } else {
                if (index < 0) {
                    index = static_cast<int32_t>(self.size()) + index;
                }

                if (index > static_cast<int32_t>(self.size())) {
                    throw std::out_of_range("invalid index");
                } else if (index == static_cast<int32_t>(self.size())) {
                    self.push_back(std::move(value));
                } else {
                    auto it = self.begin();
                    std::advance(it, index);
                    self.insert(it, std::move(value));
                }
            }
        }

        static bool contains(List& self, const T& value) {
            return std::find(self.begin(), self.end(), value) != self.end();
        }

        static T pop(List& self) {
            auto ret = std::move(self.back());
            self.pop_back();
            return std::move(ret);
        }

        static void clear(List& self) {
            self.clear();
        }

        static size_t size(List& self) {
            return self.size();
        }

        static bool empty(List& self) {
            return self.empty();
        }

        static void bind(ForeignModule& m, const std::string& name) {
            auto& iter = m.klass<Iterator>(name + "Iter");
            iter.ctor();

            auto& cls = m.klass<List>(name);
            cls.ctor();

            cls.template funcExt<&StdListBindings<T>::getIndex>(OPERATOR_GET_INDEX);
            cls.template funcExt<&StdListBindings<T>::setIndex>(OPERATOR_SET_INDEX);
            cls.template funcExt<&StdListBindings<T>::add>("add");
            cls.template funcExt<&StdListBindings<T>::iterate>("iterate");
            cls.template funcExt<&StdListBindings<T>::iteratorValue>("iteratorValue");
            cls.template funcExt<&StdListBindings<T>::removeAt>("removeAt");
            cls.template funcExt<&StdListBindings<T>::insert>("insert");
            cls.template funcExt<&StdListBindings<T>::contains>("contains");
            cls.template funcExt<&StdListBindings<T>::pop>("pop");
            cls.template funcExt<&StdListBindings<T>::clear>("clear");
            cls.template funcExt<&StdListBindings<T>::size>("size");
            cls.template funcExt<&StdListBindings<T>::empty>("empty");
            cls.template propReadonlyExt<&StdListBindings<T>::count>("count");
        }
    };

    template <typename Map> class AbstractMapBindings {
    public:
        typedef typename Map::key_type K;
        typedef typename Map::mapped_type T;
        typedef typename Map::iterator Iterator;
        typedef typename Map::value_type Pair;

        static void setIndex(Map& self, const K& key, T value) {
            self[key] = std::move(value);
        }

        static T& getIndex(Map& self, const K& key) {
            return self[key];
        }

        static std::variant<T, std::nullptr_t> remove(Map& self, const K& key) {
            auto it = self.find(key);
            if (it != self.end()) {
                auto ret = std::move(it->second);
                self.erase(it);
                return {ret};
            } else {
                return {nullptr};
            }
        }

        static bool containsKey(Map& self, const K& key) {
            return self.find(key) != self.end();
        }

        static size_t count(Map& self) {
            return self.size();
        }

        static void clear(Map& self) {
            self.clear();
        }

        static size_t size(Map& self) {
            return self.size();
        }

        static bool empty(Map& self) {
            return self.empty();
        }

        static std::variant<bool, Iterator> iterate(Map& self, std::variant<std::nullptr_t, Iterator> other) {
            if (other.index() == 1) {
                auto it = std::get<Iterator>(other);
                ++it;
                if (it != self.end()) {
                    return {it};
                }

                return {false};
            } else {
                return {self.begin()};
            }
        }

        static Pair iteratorValue(Map& self, std::shared_ptr<Iterator> other) {
            auto& it = *other;
            return *it;
        }

        static const K& pairKey(Pair& pair) {
            return pair.first;
        }

        static const T& pairValue(Pair& pair) {
            return pair.second;
        }

        static void bind(ForeignModule& m, const std::string& name) {
            auto& pair = m.klass<Pair>(name + "Pair");
            pair.template propReadonlyExt<&AbstractMapBindings<Map>::pairKey>("key");
            pair.template propReadonlyExt<&AbstractMapBindings<Map>::pairValue>("value");

            auto& iter = m.klass<Iterator>(name + "Iter");
            iter.ctor();

            auto& cls = m.klass<Map>(name);
            cls.ctor();

            cls.template funcExt<&AbstractMapBindings<Map>::getIndex>(OPERATOR_GET_INDEX);
            cls.template funcExt<&AbstractMapBindings<Map>::setIndex>(OPERATOR_SET_INDEX);
            cls.template funcExt<&AbstractMapBindings<Map>::remove>("remove");
            cls.template funcExt<&AbstractMapBindings<Map>::containsKey>("containsKey");
            cls.template funcExt<&AbstractMapBindings<Map>::iterate>("iterate");
            cls.template funcExt<&AbstractMapBindings<Map>::iteratorValue>("iteratorValue");
            cls.template funcExt<&AbstractMapBindings<Map>::clear>("clear");
            cls.template funcExt<&AbstractMapBindings<Map>::size>("size");
            cls.template funcExt<&AbstractMapBindings<Map>::empty>("empty");
            cls.template propReadonlyExt<&AbstractMapBindings<Map>::count>("count");
        }
    };

    template <typename K, typename V> using StdMapBindings = AbstractMapBindings<std::map<K, V>>;

    template <typename K, typename V> using StdUnorderedMapBindings = AbstractMapBindings<std::unordered_map<K, V>>;
} // namespace wrenbind17

Updated on 17 October 2023 at 12:26:25 UTC