diff --git a/TODO b/TODO index c3218cda7..97c112f53 100644 --- a/TODO +++ b/TODO @@ -31,3 +31,5 @@ Next: - use a dedicate class template to specialize meta views for a better support to customizations - add const meta container support to meta any - meta_any deref fails if operator* returns a temporary + - remove container detector from type traits (is broken) + - remove dereferenceable detector from type traits (is broken) diff --git a/src/entt/entt.hpp b/src/entt/entt.hpp index 3a86c517d..9b8039899 100644 --- a/src/entt/entt.hpp +++ b/src/entt/entt.hpp @@ -20,6 +20,7 @@ #include "entity/utility.hpp" #include "entity/view.hpp" #include "locator/locator.hpp" +#include "meta/container.hpp" #include "meta/ctx.hpp" #include "meta/factory.hpp" #include "meta/internal.hpp" @@ -27,6 +28,7 @@ #include "meta/policy.hpp" #include "meta/range.hpp" #include "meta/resolve.hpp" +#include "meta/type_traits.hpp" #include "process/process.hpp" #include "process/scheduler.hpp" #include "resource/cache.hpp" diff --git a/src/entt/meta/container.hpp b/src/entt/meta/container.hpp new file mode 100644 index 000000000..677b3aeda --- /dev/null +++ b/src/entt/meta/container.hpp @@ -0,0 +1,541 @@ +#ifndef ENTT_META_CONTAINER_HPP +#define ENTT_META_CONTAINER_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include "../config/config.h" +#include "type_traits.hpp" + + +namespace entt { + + +/** + * @brief Meta sequence container traits for `std::vector`s of any type. + * @tparam Type The type of elements. + * @tparam Args Other arguments. + */ +template +struct meta_sequence_container_traits_t> { + /*! @brief Iterator type of the sequence container. */ + using iterator = typename std::vector::iterator; + /*! @brief Unsigned integer type. */ + using size_type = typename std::vector::size_type; + /*! @brief Value type of the sequence container. */ + using value_type = typename std::vector::value_type; + + /** + * @brief Returns the size of given a container. + * @param vec The container of which to return the size. + * @return The size of the given container. + */ + [[nodiscard]] static size_type size(const std::vector &vec) ENTT_NOEXCEPT { + return vec.size(); + } + + /** + * @brief Clears the content of a given container. + * @param vec The container of which to clear the content. + * @return True in case of success, false otherwise. + */ + [[nodiscard]] static bool clear(std::vector &vec) { + return vec.clear(), true; + } + + /** + * @brief Returns an iterator to the first element of a given container. + * @param vec The container of which to return the iterator. + * @return An iterator to the first element of the given container. + */ + [[nodiscard]] static iterator begin(std::vector &vec) { + return vec.begin(); + } + + /** + * @brief Returns an iterator past the last element of a given container. + * @param vec The container of which to return the iterator. + * @return An iterator past the last element of the given container. + */ + [[nodiscard]] static iterator end(std::vector &vec) { + return vec.end(); + } + + /** + * @brief Inserts an element at a specified location of a given container. + * @param vec The container in which to insert the element. + * @param it Iterator before which the element will be inserted. + * @param value Element value to insert. + * @return A pair consisting of an iterator to the inserted element (in case + * of success) and a bool denoting whether the insertion took place. + */ + [[nodiscard]] static std::pair insert(std::vector &vec, iterator it, const Type &value) { + return { vec.insert(it, value), true }; + } + + /** + * @brief Removes the specified element from a given container. + * @param vec The container from which to remove the element. + * @param it Iterator to the element to remove. + * @return A pair consisting of an iterator following the last removed + * element (in case of success) and a bool denoting whether the insertion + * took place. + */ + [[nodiscard]] static std::pair erase(std::vector &vec, iterator it) { + return { vec.erase(it), true }; + } + + /** + * @brief Returns a reference to the element at a specified location of a + * given container (no bounds checking is performed). + * @param vec The container from which to get the element. + * @param pos The position of the element to return. + * @return A reference to the requested element. + */ + [[nodiscard]] static Type & get(std::vector &vec, size_type pos) { + return vec[pos]; + } +}; + + +/** + * @brief Meta sequence container traits for `std::array`s of any type. + * @tparam Type The type of elements. + * @tparam N The number of elements. + */ +template +struct meta_sequence_container_traits_t> { + /*! @brief Iterator type of the sequence container. */ + using iterator = typename std::array::iterator; + /*! @brief Unsigned integer type. */ + using size_type = typename std::array::size_type; + /*! @brief Value type of the sequence container. */ + using value_type = typename std::array::value_type; + + /** + * @brief Returns the size of given a container. + * @param arr The container of which to return the size. + * @return The size of the given container. + */ + [[nodiscard]] static size_type size(const std::array &arr) ENTT_NOEXCEPT { + return arr.size(); + } + + /** + * @brief Does nothing. + * @return False to indicate failure in all cases. + */ + [[nodiscard]] static bool clear(std::array &) { + return false; + } + + /** + * @brief Returns an iterator to the first element of a given container. + * @param arr The container of which to return the iterator. + * @return An iterator to the first element of the given container. + */ + [[nodiscard]] static iterator begin(std::array &arr) { + return arr.begin(); + } + + /** + * @brief Returns an iterator past the last element of a given container. + * @param arr The container of which to return the iterator. + * @return An iterator past the last element of the given container. + */ + [[nodiscard]] static iterator end(std::array &arr) { + return arr.end(); + } + + /** + * @brief Does nothing. + * @return A pair consisting of an invalid iterator and a false value to + * indicate failure in all cases. + */ + [[nodiscard]] static std::pair insert(std::array &, iterator, const Type &) { + return { {}, false }; + } + + /** + * @brief Does nothing. + * @return A pair consisting of an invalid iterator and a false value to + * indicate failure in all cases. + */ + [[nodiscard]] static std::pair erase(std::array &, iterator) { + return { {}, false }; + } + + /** + * @brief Returns a reference to the element at a specified location of a + * given container (no bounds checking is performed). + * @param arr The container from which to get the element. + * @param pos The position of the element to return. + * @return A reference to the requested element. + */ + [[nodiscard]] static Type & get(std::array &arr, size_type pos) { + return arr[pos]; + } +}; + + +/** + * @brief Meta associative container traits for `std::map`s of any type. + * @tparam Key The key type of elements. + * @tparam Value The value type of elements. + * @tparam Args Other arguments. + */ +template +struct meta_associative_container_traits_t> { + /*! @brief Iterator type of the associative container. */ + using iterator = typename std::map::iterator; + /*! @brief Unsigned integer type. */ + using size_type = typename std::map::size_type; + /*! @brief Key type of the sequence container. */ + using key_type = typename std::map::key_type; + /*! @brief Mapped type of the sequence container. */ + using mapped_type = typename std::map::mapped_type; + /*! @brief Value type of the sequence container. */ + using value_type = typename std::map::value_type; + + /** + * @brief Returns the size of given a container. + * @param map The container of which to return the size. + * @return The size of the given container. + */ + [[nodiscard]] static size_type size(const std::map &map) ENTT_NOEXCEPT { + return map.size(); + } + + /** + * @brief Clears the content of a given container. + * @param map The container of which to clear the content. + * @return True in case of success, false otherwise. + */ + [[nodiscard]] static bool clear(std::map &map) { + return map.clear(), true; + } + + /** + * @brief Returns an iterator to the first element of a given container. + * @param map The container of which to return the iterator. + * @return An iterator to the first element of the given container. + */ + [[nodiscard]] static iterator begin(std::map &map) { + return map.begin(); + } + + /** + * @brief Returns an iterator past the last element of a given container. + * @param map The container of which to return the iterator. + * @return An iterator past the last element of the given container. + */ + [[nodiscard]] static iterator end(std::map &map) { + return map.end(); + } + + /** + * @brief Inserts an element (a key/value pair) into a given container. + * @param map The container in which to insert the element. + * @param key The key of the element to insert. + * @param value The value of the element to insert. + * @return A bool denoting whether the insertion took place. + */ + [[nodiscard]] static bool insert(std::map &map, const key_type &key, const mapped_type &value) { + return map.insert(std::make_pair(key, value)).second; + } + + /** + * @brief Removes the specified element from a given container. + * @param map The container from which to remove the element. + * @param key The key of the element to remove. + * @return A bool denoting whether the removal took place. + */ + [[nodiscard]] static bool erase(std::map &map, const key_type &key) { + const auto sz = map.size(); + return map.erase(key) != sz; + } + + /** + * @brief Returns an iterator to the element with key equivalent to a given + * one, if any. + * @param map The container in which to search for the element. + * @param key The key of the element to search. + * @return An iterator to the element with the given key, if any. + */ + [[nodiscard]] static iterator find(std::map &map, const key_type &key) { + return map.find(key); + } +}; + + +/** + * @brief Meta associative container traits for `std::unordered_map`s of any + * type. + * @tparam Key The key type of elements. + * @tparam Value The value type of elements. + * @tparam Args Other arguments. + */ +template +struct meta_associative_container_traits_t> { + /*! @brief Iterator type of the associative container. */ + using iterator = typename std::unordered_map::iterator; + /*! @brief Unsigned integer type. */ + using size_type = typename std::unordered_map::size_type; + /*! @brief Key type of the sequence container. */ + using key_type = typename std::unordered_map::key_type; + /*! @brief Mapped type of the sequence container. */ + using mapped_type = typename std::unordered_map::mapped_type; + /*! @brief Value type of the sequence container. */ + using value_type = typename std::unordered_map::value_type; + + /** + * @brief Returns the size of given a container. + * @param map The container of which to return the size. + * @return The size of the given container. + */ + [[nodiscard]] static size_type size(const std::unordered_map &map) ENTT_NOEXCEPT { + return map.size(); + } + + /** + * @brief Clears the content of a given container. + * @param map The container of which to clear the content. + * @return True in case of success, false otherwise. + */ + [[nodiscard]] static bool clear(std::unordered_map &map) { + return map.clear(), true; + } + + /** + * @brief Returns an iterator to the first element of a given container. + * @param map The container of which to return the iterator. + * @return An iterator to the first element of the given container. + */ + [[nodiscard]] static iterator begin(std::unordered_map &map) { + return map.begin(); + } + + /** + * @brief Returns an iterator past the last element of a given container. + * @param map The container of which to return the iterator. + * @return An iterator past the last element of the given container. + */ + [[nodiscard]] static iterator end(std::unordered_map &map) { + return map.end(); + } + + /** + * @brief Inserts an element (a key/value pair) into a given container. + * @param map The container in which to insert the element. + * @param key The key of the element to insert. + * @param value The value of the element to insert. + * @return A bool denoting whether the insertion took place. + */ + [[nodiscard]] static bool insert(std::unordered_map &map, const key_type &key, const mapped_type &value) { + return map.insert(std::make_pair(key, value)).second; + } + + /** + * @brief Removes the specified element from a given container. + * @param map The container from which to remove the element. + * @param key The key of the element to remove. + * @return A bool denoting whether the removal took place. + */ + [[nodiscard]] static bool erase(std::unordered_map &map, const key_type &key) { + const auto sz = map.size(); + return map.erase(key) != sz; + } + + /** + * @brief Returns an iterator to the element with key equivalent to a given + * one, if any. + * @param map The container in which to search for the element. + * @param key The key of the element to search. + * @return An iterator to the element with the given key, if any. + */ + [[nodiscard]] static iterator find(std::unordered_map &map, const key_type &key) { + return map.find(key); + } +}; + + +/** + * @brief Meta associative container traits for `std::set`s of any type. + * @tparam Key The type of elements. + * @tparam Args Other arguments. + */ +template +struct meta_associative_container_traits_t> { + /*! @brief Iterator type of the associative container. */ + using iterator = typename std::set::iterator; + /*! @brief Unsigned integer type. */ + using size_type = typename std::set::size_type; + /*! @brief Key type of the sequence container. */ + using key_type = typename std::set::key_type; + /*! @brief Value type of the sequence container. */ + using value_type = typename std::set::value_type; + + /** + * @brief Returns the size of given a container. + * @param set The container of which to return the size. + * @return The size of the given container. + */ + [[nodiscard]] static size_type size(const std::set &set) ENTT_NOEXCEPT { + return set.size(); + } + + /** + * @brief Clears the content of a given container. + * @param set The container of which to clear the content. + * @return True in case of success, false otherwise. + */ + [[nodiscard]] static bool clear(std::set &set) { + return set.clear(), true; + } + + /** + * @brief Returns an iterator to the first element of a given container. + * @param set The container of which to return the iterator. + * @return An iterator to the first element of the given container. + */ + [[nodiscard]] static iterator begin(std::set &set) { + return set.begin(); + } + + /** + * @brief Returns an iterator past the last element of a given container. + * @param set The container of which to return the iterator. + * @return An iterator past the last element of the given container. + */ + [[nodiscard]] static iterator end(std::set &set) { + return set.end(); + } + + /** + * @brief Inserts an element into a given container. + * @param set The container in which to insert the element. + * @param key The element to insert. + * @return A bool denoting whether the insertion took place. + */ + [[nodiscard]] static bool insert(std::set &set, const key_type &key) { + return set.insert(key).second; + } + + /** + * @brief Removes the specified element from a given container. + * @param set The container from which to remove the element. + * @param key The element to remove. + * @return A bool denoting whether the removal took place. + */ + [[nodiscard]] static bool erase(std::set &set, const key_type &key) { + const auto sz = set.size(); + return set.erase(key) != sz; + } + + /** + * @brief Returns an iterator to a given element, if any. + * @param set The container in which to search for the element. + * @param key The element to search. + * @return An iterator to the given element, if any. + */ + [[nodiscard]] static iterator find(std::set &set, const key_type &key) { + return set.find(key); + } +}; + + +/** + * @brief Meta associative container traits for `std::unordered_set`s of any + * type. + * @tparam Key The type of elements. + * @tparam Args Other arguments. + */ +template +struct meta_associative_container_traits_t> { + /*! @brief Iterator type of the associative container. */ + using iterator = typename std::unordered_set::iterator; + /*! @brief Unsigned integer type. */ + using size_type = typename std::unordered_set::size_type; + /*! @brief Key type of the sequence container. */ + using key_type = typename std::unordered_set::key_type; + /*! @brief Value type of the sequence container. */ + using value_type = typename std::unordered_set::value_type; + + /** + * @brief Returns the size of given a container. + * @param set The container of which to return the size. + * @return The size of the given container. + */ + [[nodiscard]] static size_type size(const std::unordered_set &set) ENTT_NOEXCEPT { + return set.size(); + } + + /** + * @brief Clears the content of a given container. + * @param set The container of which to clear the content. + * @return True in case of success, false otherwise. + */ + [[nodiscard]] static bool clear(std::unordered_set &set) { + return set.clear(), true; + } + + /** + * @brief Returns an iterator to the first element of a given container. + * @param set The container of which to return the iterator. + * @return An iterator to the first element of the given container. + */ + [[nodiscard]] static iterator begin(std::unordered_set &set) { + return set.begin(); + } + + /** + * @brief Returns an iterator past the last element of a given container. + * @param set The container of which to return the iterator. + * @return An iterator past the last element of the given container. + */ + [[nodiscard]] static iterator end(std::unordered_set &set) { + return set.end(); + } + + /** + * @brief Inserts an element into a given container. + * @param set The container in which to insert the element. + * @param key The element to insert. + * @return A bool denoting whether the insertion took place. + */ + [[nodiscard]] static bool insert(std::unordered_set &set, const key_type &key) { + return set.insert(key).second; + } + + /** + * @brief Removes the specified element from a given container. + * @param set The container from which to remove the element. + * @param key The element to remove. + * @return A bool denoting whether the removal took place. + */ + [[nodiscard]] static bool erase(std::unordered_set &set, const key_type &key) { + const auto sz = set.size(); + return set.erase(key) != sz; + } + + /** + * @brief Returns an iterator to a given element, if any. + * @param set The container in which to search for the element. + * @param key The element to search. + * @return An iterator to the given element, if any. + */ + [[nodiscard]] static iterator find(std::unordered_set &set, const key_type &key) { + return set.find(key); + } +}; + + +} + + +#endif diff --git a/src/entt/meta/internal.hpp b/src/entt/meta/internal.hpp index 6dcf0b9ef..e5b539e4d 100644 --- a/src/entt/meta/internal.hpp +++ b/src/entt/meta/internal.hpp @@ -12,6 +12,7 @@ #include "../core/fwd.hpp" #include "../core/type_info.hpp" #include "../core/type_traits.hpp" +#include "type_traits.hpp" namespace entt { @@ -419,8 +420,8 @@ public: std::is_member_object_pointer_v, std::is_member_function_pointer_v, is_dereferenceable_v, - is_sequence_container_v, - is_associative_container_v, + has_meta_sequence_container_traits_v, + has_meta_associative_container_traits_v, std::rank_v, [](meta_type_node::size_type dim) { return extent(dim, std::make_index_sequence>{}); diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index 8eb88c8d0..631c2a551 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -14,6 +14,7 @@ #include "ctx.hpp" #include "internal.hpp" #include "range.hpp" +#include "type_traits.hpp" namespace entt { @@ -21,53 +22,99 @@ namespace entt { class meta_type; class meta_any; +class meta_iterator; -/*! @brief Proxy object for containers of any type. */ -class meta_container { - /*! @brief A meta_any is allowed to create proxies. */ - friend class meta_any; - - struct meta_iterator; - - struct meta_view { - [[nodiscard]] virtual std::size_t size(const void *) const ENTT_NOEXCEPT = 0; - [[nodiscard]] virtual bool insert(void *, meta_any, meta_any) = 0; - [[nodiscard]] virtual bool erase(void *, meta_any) = 0; - [[nodiscard]] virtual meta_any begin(void *) const ENTT_NOEXCEPT = 0; - [[nodiscard]] virtual meta_any end(void *) const ENTT_NOEXCEPT = 0; - [[nodiscard]] virtual meta_any find(void *, meta_any) const ENTT_NOEXCEPT = 0; - [[nodiscard]] virtual meta_any deref(meta_any) const ENTT_NOEXCEPT = 0; - virtual void incr(meta_any) const ENTT_NOEXCEPT = 0; - }; - - meta_container(meta_view *impl, void *container) - : view{impl}, - instance{container} - {} +/*! @brief Proxy object for sequence containers. */ +class meta_sequence_container { + template + struct meta_sequence_container_proxy; public: /*! @brief Unsigned integer type. */ using size_type = std::size_t; - /*! @brief Input iterator type. */ + /*! @brief Meta iterator type. */ using iterator = meta_iterator; - /*! @brief Default constructor. */ - meta_container() - : view{}, - instance{} - {} + template + meta_sequence_container(Type &); - [[nodiscard]] inline size_type size() const ENTT_NOEXCEPT; - inline bool insert(meta_any, meta_any); - inline bool erase(meta_any); - [[nodiscard]] inline iterator begin(); - [[nodiscard]] inline iterator end(); - [[nodiscard]] inline iterator operator[](meta_any pos_or_key); - [[nodiscard]] inline explicit operator bool() const ENTT_NOEXCEPT; + inline meta_sequence_container(); + + inline meta_type value_type() const ENTT_NOEXCEPT; + inline size_type size() const ENTT_NOEXCEPT; + inline bool clear(); + inline iterator begin(); + inline iterator end(); + inline std::pair insert(iterator, meta_any); + inline std::pair erase(iterator); + inline meta_any operator[](size_type); + + inline explicit operator bool() const ENTT_NOEXCEPT; private: - meta_view *view; + meta_type(* value_type_fn)(); + size_type(* size_fn)(const void *); + bool(* clear_fn)(void *); + iterator(* begin_fn)(void *); + iterator(* end_fn)(void *); + std::pair(* insert_fn)(void *, iterator, meta_any); + std::pair(* erase_fn)(void *, iterator); + meta_any(* get_fn)(void *, size_type); + void *instance; +}; + + +/*! @brief Proxy object for associative containers. */ +class meta_associative_container { + template + struct has_mapped_type: std::false_type {}; + + template + struct has_mapped_type::mapped_type>> + : std::true_type + {}; + + template + struct meta_associative_container_proxy; + +public: + /*! @brief Unsigned integer type. */ + using size_type = std::size_t; + /*! @brief Meta iterator type. */ + using iterator = meta_iterator; + + template + meta_associative_container(Type &); + + inline meta_associative_container(); + + inline bool key_only() const ENTT_NOEXCEPT; + inline meta_type key_type() const ENTT_NOEXCEPT; + inline meta_type mapped_type() const ENTT_NOEXCEPT; + inline meta_type value_type() const ENTT_NOEXCEPT; + inline size_type size() const ENTT_NOEXCEPT; + inline bool clear(); + inline iterator begin(); + inline iterator end(); + inline bool insert(meta_any, meta_any); + inline bool erase(meta_any); + inline iterator find(meta_any); + + inline explicit operator bool() const ENTT_NOEXCEPT; + +private: + bool key_only_container; + meta_type(* key_type_fn)(); + meta_type(* mapped_type_fn)(); + meta_type(* value_type_fn)(); + size_type(* size_fn)(const void *); + bool(* clear_fn)(void *); + iterator(* begin_fn)(void *); + iterator(* end_fn)(void *); + bool(* insert_fn)(void *, meta_any, meta_any); + bool(* erase_fn)(void *, meta_any); + iterator(* find_fn)(void *, meta_any); void *instance; }; @@ -81,159 +128,6 @@ private: class meta_any { using dereference_operator_type = meta_any(meta_any &); - template - struct container_view { - [[nodiscard]] static meta_container::meta_view * instance() { - return nullptr; - } - }; - - template - struct container_view>>: meta_container::meta_view { - [[nodiscard]] static meta_container::meta_view * instance() { - static container_view common{}; - return &common; - } - - [[nodiscard]] std::size_t size(const void *container) const ENTT_NOEXCEPT override { - return static_cast(container)->size(); - } - - [[nodiscard]] bool insert(void *container, meta_any it, meta_any value) override { - bool ret = false; - - if constexpr(is_dynamic_sequence_container_v) { - if(auto *iter = it.try_cast(); iter) { - if(const auto *curr = value.try_cast(); curr) { - *iter = static_cast(container)->insert(*iter, *curr); - ret = true; - } - } - } - - return ret; - } - - [[nodiscard]] bool erase(void *container, meta_any it) override { - bool ret = false; - - if constexpr(is_dynamic_sequence_container_v) { - if(auto *iter = it.try_cast(); iter) { - *iter = static_cast(container)->erase(*iter); - ret = true; - } - } - - return ret; - } - - [[nodiscard]] meta_any begin(void *container) const ENTT_NOEXCEPT override { - return static_cast(container)->begin(); - } - - [[nodiscard]] meta_any end(void *container) const ENTT_NOEXCEPT override { - return static_cast(container)->end(); - } - - [[nodiscard]] meta_any deref(meta_any it) const ENTT_NOEXCEPT override { - return std::ref(*it.cast()); - } - - [[nodiscard]] meta_any find(void *container, meta_any idx) const ENTT_NOEXCEPT override { - meta_any any{}; - - if(const auto *curr = idx.try_cast(); curr) { - any = std::next(static_cast(container)->begin(), *curr); - } - - return any; - } - - void incr(meta_any it) const ENTT_NOEXCEPT override { - ++it.cast(); - } - }; - - template - struct container_view>>: meta_container::meta_view { - [[nodiscard]] static meta_container::meta_view * instance() { - static container_view common{}; - return &common; - } - - [[nodiscard]] std::size_t size(const void *container) const ENTT_NOEXCEPT override { - return static_cast(container)->size(); - } - - [[nodiscard]] bool insert(void *container, meta_any key, meta_any value) override { - bool ret = false; - - if constexpr(is_key_only_associative_container_v) { - if(const auto *curr = key.try_cast(); curr) { - static_cast(container)->insert(*curr); - ret = true; - } - } else { - if(const auto *k_curr = key.try_cast(); k_curr) { - if(const auto *v_curr = value.try_cast(); v_curr) { - static_cast(container)->insert(std::make_pair(*k_curr, *v_curr)); - ret = true; - } - } - } - - return ret; - } - - [[nodiscard]] bool erase(void *container, meta_any key) override { - bool ret = false; - - if(const auto *curr = key.try_cast(); curr) { - static_cast(container)->erase(*curr); - ret = true; - } - - return ret; - } - - [[nodiscard]] meta_any begin(void *container) const ENTT_NOEXCEPT override { - return static_cast(container)->begin(); - } - - [[nodiscard]] meta_any end(void *container) const ENTT_NOEXCEPT override { - return static_cast(container)->end(); - } - - [[nodiscard]] meta_any deref(meta_any it) const ENTT_NOEXCEPT override { - if constexpr(is_key_only_associative_container_v) { - return *it.cast(); - } else { - return std::ref(*it.cast()); - } - } - - [[nodiscard]] meta_any find(void *container, meta_any key) const ENTT_NOEXCEPT override { - meta_any any{}; - - if constexpr(is_key_only_associative_container_v) { - if(const auto *curr = key.try_cast(); curr) { - auto *cont = static_cast(container); - any = std::find(cont->begin(), cont->end(), *curr); - } - } else { - if(const auto *curr = key.try_cast(); curr) { - any = static_cast(container)->find(*curr); - } - } - - return any; - } - - void incr(meta_any it) const ENTT_NOEXCEPT override { - it.cast().operator++(); - } - }; - template static meta_any dereference_operator(meta_any &any) { meta_any other{}; @@ -249,13 +143,32 @@ class meta_any { return other; } + template + [[nodiscard]] static auto * meta_sequence_container_factory() ENTT_NOEXCEPT { + if constexpr(has_meta_sequence_container_traits_v) { + return +[](void *container) -> meta_sequence_container { return *static_cast(container); }; + } else { + return static_cast(nullptr); + } + } + + template + [[nodiscard]] static auto * meta_associative_container_factory() ENTT_NOEXCEPT { + if constexpr(has_meta_associative_container_traits_v) { + return +[](void *container) -> meta_associative_container { return *static_cast(container); }; + } else { + return static_cast(nullptr); + } + } + public: /*! @brief Default constructor. */ meta_any() ENTT_NOEXCEPT : storage{}, node{}, deref{}, - cview{} + seq_factory{nullptr}, + assoc_factory{nullptr} {} /** @@ -269,7 +182,8 @@ public: : storage(std::in_place_type, std::forward(args)...), node{internal::meta_info::resolve()}, deref{&dereference_operator}, - cview{container_view::instance()} + seq_factory{meta_sequence_container_factory()}, + assoc_factory{meta_associative_container_factory()} {} /** @@ -282,7 +196,8 @@ public: : storage{value}, node{internal::meta_info::resolve()}, deref{&dereference_operator}, - cview{container_view::instance()} + seq_factory{meta_sequence_container_factory()}, + assoc_factory{meta_associative_container_factory()} {} /** @@ -460,16 +375,25 @@ public: other.node = node; other.storage = storage.ref(); other.deref = deref; - other.cview = cview; + other.seq_factory = seq_factory; + other.assoc_factory = assoc_factory; return other; } /** - * @brief Returns a container view. - * @return A container view for the underlying object. + * @brief Returns a sequence container proxy. + * @return A sequence container proxy for the underlying object. */ - [[nodiscard]] meta_container view() ENTT_NOEXCEPT { - return { cview, storage.data() }; + [[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT { + return seq_factory ? seq_factory(storage.data()) : meta_sequence_container{}; + } + + /** + * @brief Returns an associative container proxy. + * @return An associative container proxy for the underlying object. + */ + [[nodiscard]] meta_associative_container as_associative_container() ENTT_NOEXCEPT { + return assoc_factory ? assoc_factory(storage.data()) : meta_associative_container{}; } /** @@ -508,14 +432,16 @@ public: swap(lhs.node, rhs.node); swap(lhs.storage, rhs.storage); swap(lhs.deref, rhs.deref); - swap(lhs.cview, rhs.cview); + swap(lhs.seq_factory, rhs.seq_factory); + swap(lhs.assoc_factory, rhs.assoc_factory); } private: internal::meta_storage storage; const internal::meta_type_node *node; dereference_operator_type *deref; - meta_container::meta_view *cview; + meta_sequence_container(* seq_factory)(void *); + meta_associative_container(* assoc_factory)(void *); }; @@ -530,181 +456,6 @@ private: } -/*! @brief Opaque iterator for meta containers. */ -struct meta_container::meta_iterator { - /*! @brief Signed integer type. */ - using difference_type = std::ptrdiff_t; - /*! @brief Type of elements returned by the iterator. */ - using value_type = meta_any; - /*! @brief Pointer type, `void` on purpose. */ - using pointer = void; - /*! @brief Reference type, it is **not** an actual reference. */ - using reference = value_type; - /*! @brief Iterator category. */ - using iterator_category = std::input_iterator_tag; - - /*! @brief Default constructor. */ - meta_iterator() ENTT_NOEXCEPT = default; - - /** - * @brief Constructs a meta iterator that wraps an actual iterator. - * @param ref A proxy object that _knows_ how to use the wrapped iterator. - * @param iter The actual iterator, properly wrapped. - */ - meta_iterator(meta_container::meta_view *ref, meta_any iter) - : view{ref}, - it{std::move(iter)} - {} - - /*! @brief Pre-increment operator. @return This iterator. */ - meta_iterator & operator++() ENTT_NOEXCEPT { - return view->incr(handle()), *this; - } - - /*! @brief Post-increment operator. @return This iterator. */ - meta_iterator operator++(int) ENTT_NOEXCEPT { - iterator orig = *this; - return view->incr(handle()), orig; - } - - /** - * @brief Checks if two meta iterators refer to the same element. - * @param other The meta iterator with which to compare. - * @return True if the two meta iterators refer to the same element, false - * otherwise. - */ - [[nodiscard]] bool operator==(const meta_iterator &other) const ENTT_NOEXCEPT { - return it == other.it; - } - - /** - * @brief Checks if two meta iterators refer to the same element. - * @param other The meta iterator with which to compare. - * @return False if the two meta iterators refer to the same element, true - * otherwise. - */ - [[nodiscard]] bool operator!=(const meta_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - /** - * @brief Indirection operator. - * @return The element to which the meta pointer points. - */ - [[nodiscard]] reference operator*() const { - return view->deref(handle()); - } - - /** - * @brief Returns a handle to the underlying iterator. - * @return The actual iterator, properly wrapped. - */ - [[nodiscard]] meta_any handle() const ENTT_NOEXCEPT { - return it.ref(); - } - - /** - * @brief Returns false if an iterator is invalid, true otherwise. - * @return False if the iterator is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(it); - } - -private: - meta_container::meta_view *view; - entt::meta_any it; -}; - - -/** - * @brief Returns the number of elements. - * @return Number of elements. - */ -[[nodiscard]] meta_container::size_type meta_container::size() const ENTT_NOEXCEPT { - return view->size(instance); -} - - -/** - * @brief Inserts an element in the container. - * - * In case of sequence containers, the first parameter must be a valid iterator - * handle. In case of associative containers, the type of the key must be such - * that a cast or conversion to the key type of the container is possible.
- * The type of the value must be such that a cast or conversion to the value - * type of the container is possible. - * - * @param it_or_key A valid iterator handle in case of sequence containers, a - * key in case of associative containers. - * @param value The element to insert in the container. - * @return True in case of success, false otherwise. - */ -inline bool meta_container::insert(meta_any it_or_key, meta_any value = {}) { - return view->insert(instance, std::move(it_or_key), std::move(value)); -} - - -/** - * @brief Erases an element from the container. - * - * In case of sequence containers, the parameter must be a valid iterator - * handle. In case of associative containers, the type of the key must be such - * that a cast or conversion to the key type of the container is possible. - * - * @param it_or_key A valid iterator handle in case of sequence containers, a - * key in case of associative containers. - * @return True in case of success, false otherwise. - */ -inline bool meta_container::erase(meta_any it_or_key) { - return view->erase(instance, std::move(it_or_key)); -} - - -/** - * @brief Returns an iterator to the first element of the container. - * @return An iterator to the first element of the container. - */ -[[nodiscard]] inline meta_container::iterator meta_container::begin() { - return {view, view->begin(instance)}; -} - - -/** - * @brief Returns an iterator that is past the last element of the container. - * @return An iterator that is past the last element of the container. - */ -[[nodiscard]] inline meta_container::iterator meta_container::end() { - return {view, view->end(instance)}; -} - - -/** - * @brief Returns an iterator to the required element. - * - * In case of sequence containers, the parameter must be a valid position (no - * bounds checking is performed) and such that a cast or conversion to size_type - * is possible. In case of associative containers, the type of the key must be - * such that a cast or conversion to the key type of the container is possible. - * - * @param pos_or_key A valid position in case of sequence containers, a key in - * case of associative containers. - * @return An iterator to the required element. - */ -[[nodiscard]] inline meta_container::iterator meta_container::operator[](meta_any pos_or_key) { - return {view, view->find(instance, std::move(pos_or_key))}; -} - - -/** - * @brief Returns true if a meta container is valid, false otherwise. - * @return True if the meta container is valid, false otherwise. - */ -meta_container::operator bool() const ENTT_NOEXCEPT { - return (view != nullptr); -} - - /** * @brief Opaque pointers to instances of any type. * @@ -1740,6 +1491,494 @@ private: } +/*! @brief Opaque iterator for meta containers. */ +class meta_iterator { + template + static void incr(meta_any any) { + ++any.cast(); + } + + template + static meta_any deref(meta_any any) { + if constexpr(std::is_const_v())>>) { + return *any.cast(); + } else { + return std::ref(*any.cast()); + } + } + +public: + /*! @brief Signed integer type. */ + using difference_type = std::ptrdiff_t; + /*! @brief Type of elements returned by the iterator. */ + using value_type = meta_any; + /*! @brief Pointer type, `void` on purpose. */ + using pointer = void; + /*! @brief Reference type, it is **not** an actual reference. */ + using reference = value_type; + /*! @brief Iterator category. */ + using iterator_category = std::input_iterator_tag; + + /*! @brief Default constructor. */ + meta_iterator() ENTT_NOEXCEPT + : next_fn{nullptr}, + get_fn{nullptr}, + it{} + {} + + /** + * @brief Constructs a meta iterator from a given iterator. + * @tparam Type Type of container to which the iterator belongs. + * @param iter The actual iterator with which to build the meta iterator. + */ + template + meta_iterator(std::in_place_type_t, typename Type::iterator iter) + : next_fn{&incr}, + get_fn{&deref}, + it{std::move(iter)} + {} + + /*! @brief Pre-increment operator. @return This iterator. */ + meta_iterator & operator++() ENTT_NOEXCEPT { + return next_fn(it.ref()), *this; + } + + /*! @brief Post-increment operator. @return This iterator. */ + meta_iterator operator++(int) ENTT_NOEXCEPT { + meta_iterator orig = *this; + return next_fn(it.ref()), orig; + } + + /** + * @brief Checks if two meta iterators refer to the same element. + * @param other The meta iterator with which to compare. + * @return True if the two meta iterators refer to the same element, false + * otherwise. + */ + [[nodiscard]] bool operator==(const meta_iterator &other) const ENTT_NOEXCEPT { + return it == other.it; + } + + /** + * @brief Checks if two meta iterators refer to the same element. + * @param other The meta iterator with which to compare. + * @return False if the two meta iterators refer to the same element, true + * otherwise. + */ + [[nodiscard]] bool operator!=(const meta_iterator &other) const ENTT_NOEXCEPT { + return !(*this == other); + } + + /** + * @brief Indirection operator. + * @return The element to which the meta pointer points. + */ + [[nodiscard]] reference operator*() const { + return get_fn(it.ref()); + } + + /** + * @brief Returns a handle to the underlying iterator. + * @return The actual iterator, properly wrapped. + */ + [[nodiscard]] meta_any handle() const ENTT_NOEXCEPT { + return it.ref(); + } + + /** + * @brief Returns false if an iterator is invalid, true otherwise. + * @return False if the iterator is invalid, true otherwise. + */ + [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { + return static_cast(it); + } + +private: + void(* next_fn)(meta_any); + meta_any(* get_fn)(meta_any); + entt::meta_any it; +}; + + +template +struct meta_sequence_container::meta_sequence_container_proxy { + static meta_type value_type() { + return internal::meta_info::value_type>::resolve(); + } + + static meta_sequence_container::size_type size(const void *container) { + return meta_sequence_container_traits_t::size(*static_cast(container)); + } + + static bool clear(void *container) { + return meta_sequence_container_traits_t::clear(*static_cast(container)); + } + + static iterator begin(void *container) { + return iterator{std::in_place_type, meta_sequence_container_traits_t::begin(*static_cast(container))}; + } + + static iterator end(void *container) { + return iterator{std::in_place_type, meta_sequence_container_traits_t::end(*static_cast(container))}; + } + + static std::pair insert(void *container, iterator it, meta_any any) { + std::pair::iterator, bool> ret{{}, false}; + + if(const auto *value = any.try_cast::value_type>(); value) { + ret = meta_sequence_container_traits_t::insert(*static_cast(container), it.handle().cast::iterator>(), *value); + } + + return {iterator{std::in_place_type, std::move(ret.first)}, ret.second}; + } + + static std::pair erase(void *container, iterator it) { + auto ret = meta_sequence_container_traits_t::erase(*static_cast(container), it.handle().cast::iterator>()); + return {iterator{std::in_place_type, std::move(ret.first)}, ret.second}; + } + + static meta_any get(void *container, meta_sequence_container::size_type pos) { + return std::ref(meta_sequence_container_traits_t::get(*static_cast(container), pos)); + } +}; + + +/** + * @brief Construct a proxy object for sequence containers. + * @tparam Type Type of container to wrap. + * @param container The container to wrap. + */ +template +meta_sequence_container::meta_sequence_container(Type &container) + : value_type_fn{&meta_sequence_container_proxy::value_type}, + size_fn{&meta_sequence_container_proxy::size}, + clear_fn{&meta_sequence_container_proxy::clear}, + begin_fn{&meta_sequence_container_proxy::begin}, + end_fn{&meta_sequence_container_proxy::end}, + insert_fn{&meta_sequence_container_proxy::insert}, + erase_fn{&meta_sequence_container_proxy::erase}, + get_fn{&meta_sequence_container_proxy::get}, + instance{&container} +{} + + +/*! @brief Default constructor. */ +inline meta_sequence_container::meta_sequence_container() + : value_type_fn{nullptr}, + size_fn{nullptr}, + clear_fn{nullptr}, + begin_fn{nullptr}, + end_fn{nullptr}, + insert_fn{nullptr}, + erase_fn{nullptr}, + get_fn{nullptr}, + instance{nullptr} +{} + + +/** + * @brief Returns the value meta type of the wrapped container type. + * @return The value meta type of the wrapped container type. + */ +inline meta_type meta_sequence_container::value_type() const ENTT_NOEXCEPT { + return value_type_fn(); +} + + +/** + * @brief Returns the size of the wrapped container. + * @return The size of the wrapped container. + */ +inline meta_sequence_container::size_type meta_sequence_container::size() const ENTT_NOEXCEPT { + return size_fn(instance); +} + + +/** + * @brief Clears the content of the wrapped container. + * @return True in case of success, false otherwise. + */ +inline bool meta_sequence_container::clear() { + return clear_fn(instance); +} + + +/** + * @brief Returns a meta iterator to the first element of the wrapped container. + * @return A meta iterator to the first element of the wrapped container. + */ +inline meta_sequence_container::iterator meta_sequence_container::begin() { + return begin_fn(instance); +} + + +/** + * @brief Returns a meta iterator that is past the last element of the wrapped + * container. + * @return A meta iterator that is past the last element of the wrapped + * container. + */ +inline meta_sequence_container::iterator meta_sequence_container::end() { + return end_fn(instance); +} + + +/** + * @brief Inserts an element at a specified location of the wrapped container. + * @param it Meta iterator before which the element will be inserted. + * @param value Element value to insert. + * @return A pair consisting of a meta iterator to the inserted element (in + * case of success) and a bool denoting whether the insertion took place. + */ +inline std::pair meta_sequence_container::insert(iterator it, meta_any value) { + return insert_fn(instance, it, value.ref()); +} + + +/** + * @brief Removes the specified element from the wrapped container. + * @param it Meta iterator to the element to remove. + * @return A pair consisting of a meta iterator following the last removed + * element (in case of success) and a bool denoting whether the insertion + * took place. + */ +inline std::pair meta_sequence_container::erase(iterator it) { + return erase_fn(instance, it); +} + + +/** + * @brief Returns a reference to the element at a specified location of the + * wrapped container (no bounds checking is performed). + * @param pos The position of the element to return. + * @return A reference to the requested element properly wrapped. + */ +inline meta_any meta_sequence_container::operator[](size_type pos) { + return get_fn(instance, pos); +} + + +/** + * @brief Returns false if a proxy is invalid, true otherwise. + * @return False if the proxy is invalid, true otherwise. + */ +inline meta_sequence_container::operator bool() const ENTT_NOEXCEPT { + return (instance != nullptr); +} + + +template +struct meta_associative_container::meta_associative_container_proxy { + static constexpr auto has_mapped_type = meta_associative_container::has_mapped_type::value; + + static meta_type key_type() { + return internal::meta_info::key_type>::resolve(); + } + + static meta_type mapped_type() { + if constexpr(has_mapped_type) { + return internal::meta_info::mapped_type>::resolve(); + } else { + return meta_type{}; + } + } + + static meta_type value_type() { + return internal::meta_info::value_type>::resolve(); + } + + static meta_associative_container::size_type size(const void *container) { + return meta_associative_container_traits_t::size(*static_cast(container)); + } + + static bool clear(void *container) { + return meta_associative_container_traits_t::clear(*static_cast(container)); + } + + static iterator begin(void *container) { + return iterator{std::in_place_type, meta_associative_container_traits_t::begin(*static_cast(container))}; + } + + static iterator end(void *container) { + return iterator{std::in_place_type, meta_associative_container_traits_t::end(*static_cast(container))}; + } + + static bool insert(void *container, meta_any key, meta_any value) { + bool ret = false; + + if(const auto *k_ptr = key.try_cast::key_type>(); k_ptr) { + if constexpr(has_mapped_type) { + if(auto *m_ptr = value.try_cast::mapped_type>(); m_ptr) { + ret = meta_associative_container_traits_t::insert(*static_cast(container), *k_ptr, *m_ptr); + } + } else { + ret = meta_associative_container_traits_t::insert(*static_cast(container), *k_ptr); + } + } + + return ret; + } + + static bool erase(void *container, meta_any key) { + bool ret = false; + + if(const auto *k_ptr = key.try_cast::key_type>(); k_ptr) { + ret = meta_associative_container_traits_t::erase(*static_cast(container), *k_ptr); + } + + return ret; + } + + static iterator find(void *container, meta_any key) { + iterator ret{}; + + if(const auto *k_ptr = key.try_cast::key_type>(); k_ptr) { + ret = iterator{std::in_place_type, meta_associative_container_traits_t::find(*static_cast(container), *k_ptr)}; + } + + return ret; + } +}; + + +/** + * @brief Construct a proxy object for associative containers. + * @tparam Type Type of container to wrap. + * @param container The container to wrap. + */ +template +meta_associative_container::meta_associative_container(Type &container) + : key_only_container{!meta_associative_container_proxy::has_mapped_type}, + key_type_fn{&meta_associative_container_proxy::key_type}, + mapped_type_fn{&meta_associative_container_proxy::mapped_type}, + value_type_fn{&meta_associative_container_proxy::value_type}, + size_fn{&meta_associative_container_proxy::size}, + clear_fn{&meta_associative_container_proxy::clear}, + begin_fn{&meta_associative_container_proxy::begin}, + end_fn{&meta_associative_container_proxy::end}, + insert_fn{&meta_associative_container_proxy::insert}, + erase_fn{&meta_associative_container_proxy::erase}, + find_fn{&meta_associative_container_proxy::find}, + instance{&container} +{} + + +/*! @brief Default constructor. */ +inline meta_associative_container::meta_associative_container() + : key_only_container{false}, + key_type_fn{nullptr}, + mapped_type_fn{nullptr}, + value_type_fn{nullptr}, + size_fn{nullptr}, + clear_fn{nullptr}, + begin_fn{nullptr}, + end_fn{nullptr}, + insert_fn{nullptr}, + erase_fn{nullptr}, + find_fn{nullptr}, + instance{nullptr} +{} + + +/** + * @brief Returns true if the associative container is also key-only, false + * otherwise. + * @return True if the associative container is also key-only, false otherwise. + */ +inline bool meta_associative_container::key_only() const ENTT_NOEXCEPT { + return key_only_container; +} + + +/** + * @brief Returns the key meta type of the wrapped container type. + * @return The key meta type of the wrapped container type. + */ +inline meta_type meta_associative_container::key_type() const ENTT_NOEXCEPT { + return key_type_fn(); +} + + +/** + * @brief Returns the mapped meta type of the wrapped container type. + * @return The mapped meta type of the wrapped container type. + */ +inline meta_type meta_associative_container::mapped_type() const ENTT_NOEXCEPT { + return mapped_type_fn(); +} + + +/*! @copydoc meta_sequence_container::value_type */ +inline meta_type meta_associative_container::value_type() const ENTT_NOEXCEPT { + return value_type_fn(); +} + + +/*! @copydoc meta_sequence_container::size */ +inline meta_associative_container::size_type meta_associative_container::size() const ENTT_NOEXCEPT { + return size_fn(instance); +} + + +/*! @copydoc meta_sequence_container::clear */ +inline bool meta_associative_container::clear() { + return clear_fn(instance); +} + + +/*! @copydoc meta_sequence_container::begin */ +inline meta_associative_container::iterator meta_associative_container::begin() { + return begin_fn(instance); +} + + +/*! @copydoc meta_sequence_container::end */ +inline meta_associative_container::iterator meta_associative_container::end() { + return end_fn(instance); +} + + +/** + * @brief Inserts an element (a key/value pair) into the wrapped container. + * @param key The key of the element to insert. + * @param value The value of the element to insert. + * @return A bool denoting whether the insertion took place. + */ +inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) { + return insert_fn(instance, key.ref(), value.ref()); +} + + +/** + * @brief Removes the specified element from the wrapped container. + * @param key The key of the element to remove. + * @return A bool denoting whether the removal took place. + */ +inline bool meta_associative_container::erase(meta_any key) { + return erase_fn(instance, key.ref()); +} + + +/** + * @brief Returns an iterator to the element with key equivalent to a given + * one, if any. + * @param key The key of the element to search. + * @return An iterator to the element with the given key, if any. + */ +inline meta_associative_container::iterator meta_associative_container::find(meta_any key) { + return find_fn(instance, key.ref()); +} + + +/** + * @brief Returns false if a proxy is invalid, true otherwise. + * @return False if the proxy is invalid, true otherwise. + */ +inline meta_associative_container::operator bool() const ENTT_NOEXCEPT { + return (instance != nullptr); +} + + } diff --git a/src/entt/meta/type_traits.hpp b/src/entt/meta/type_traits.hpp new file mode 100644 index 000000000..0ca52f6a3 --- /dev/null +++ b/src/entt/meta/type_traits.hpp @@ -0,0 +1,78 @@ +#ifndef ENTT_META_TYPE_TRAITS_HPP +#define ENTT_META_TYPE_TRAITS_HPP + + +#include + + +namespace entt { + + +/** + * @brief Traits class template to be specialized to enable support for meta + * sequence containers. + */ +template +struct meta_sequence_container_traits_t; + + +/** + * @brief Traits class template to be specialized to enable support for meta + * associative containers. + */ +template +struct meta_associative_container_traits_t; + + +/** + * @brief Provides the member constant `value` to true if support for meta + * sequence containers is enabled for the given type, false otherwise. + * @tparam Type Potentially sequence container type. + */ +template +struct has_meta_sequence_container_traits: std::false_type {}; + + +/*! @copydoc has_meta_sequence_container_traits */ +template +struct has_meta_sequence_container_traits::value_type>> + : std::true_type +{}; + + +/** + * @brief Helper variable template. + * @tparam Type Potentially sequence container type. + */ +template +inline constexpr auto has_meta_sequence_container_traits_v = has_meta_sequence_container_traits::value; + + +/** + * @brief Provides the member constant `value` to true if support for meta + * associative containers is enabled for the given type, false otherwise. + * @tparam Type Potentially associative container type. + */ +template +struct has_meta_associative_container_traits: std::false_type {}; + + +/*! @copydoc has_meta_associative_container_traits */ +template +struct has_meta_associative_container_traits::key_type>> + : std::true_type +{}; + + +/** + * @brief Helper variable template. + * @tparam Type Potentially associative container type. + */ +template +inline constexpr auto has_meta_associative_container_traits_v = has_meta_associative_container_traits::value; + + +} + + +#endif diff --git a/test/entt/meta/meta_container.cpp b/test/entt/meta/meta_container.cpp index 83481a9fb..d02a3404f 100644 --- a/test/entt/meta/meta_container.cpp +++ b/test/entt/meta/meta_container.cpp @@ -1,32 +1,30 @@ -#include -#include -#include -#include -#include #include #include +#include #include #include #include +#include -TEST(MetaContainer, Empty) { - entt::meta_container container{}; +TEST(MetaSequenceContainer, Empty) { + entt::meta_sequence_container container{}; ASSERT_FALSE(container); entt::meta_any any{std::vector{}}; - container = any.view(); + container = any.as_sequence_container(); ASSERT_TRUE(container); } -TEST(MetaContainer, DynamicSequenceContainer) { +TEST(MetaSequenceContainer, StdVector) { std::vector vec{2, 3, 4}; entt::meta_any any{std::ref(vec)}; - auto view = any.view(); + auto view = any.as_sequence_container(); ASSERT_TRUE(view); + ASSERT_EQ(view.value_type(), entt::resolve()); ASSERT_EQ(view.size(), 3u); auto first = view.begin(); @@ -44,35 +42,39 @@ TEST(MetaContainer, DynamicSequenceContainer) { ASSERT_TRUE(first == last); ASSERT_FALSE(first != last); - ASSERT_EQ((*view[std::size_t{1u}]).cast(), 3); + ASSERT_EQ(view[1u].cast(), 3); auto it = view.begin(); + auto ret = view.insert(it, 0); - ASSERT_TRUE(view.insert(it.handle(), 0)); - ASSERT_TRUE(view.insert((++it).handle(), 1)); + ASSERT_TRUE(ret.second); + ASSERT_FALSE(view.insert(ret.first, 'c').second); + ASSERT_TRUE(view.insert(++ret.first, 1).second); ASSERT_EQ(view.size(), 5u); ASSERT_EQ((*view.begin()).cast(), 0); ASSERT_EQ((*++view.begin()).cast(), 1); it = view.begin(); + ret = view.erase(it); - ASSERT_TRUE(view.erase(it.handle())); + ASSERT_TRUE(ret.second); ASSERT_EQ(view.size(), 4u); - ASSERT_EQ((*it).cast(), 1); + ASSERT_EQ((*ret.first).cast(), 1); - (*view[std::size_t{}]).cast() = 5; + view[0].cast() = 5; ASSERT_EQ((*view.begin()).cast(), 5); } -TEST(MetaContainer, FixedSizeSequenceContainer) { +TEST(MetaSequenceContainer, StdArray) { std::array arr{2, 3, 4}; entt::meta_any any{std::ref(arr)}; - auto view = any.view(); + auto view = any.as_sequence_container(); ASSERT_TRUE(view); + ASSERT_EQ(view.value_type(), entt::resolve()); ASSERT_EQ(view.size(), 3u); auto first = view.begin(); @@ -90,33 +92,37 @@ TEST(MetaContainer, FixedSizeSequenceContainer) { ASSERT_TRUE(first == last); ASSERT_FALSE(first != last); - ASSERT_EQ((*view[std::size_t{1u}]).cast(), 3); + ASSERT_EQ(view[1u].cast(), 3); auto it = view.begin(); + auto ret = view.insert(it, 0); - ASSERT_FALSE(view.insert(it.handle(), 0)); - ASSERT_FALSE(view.insert((++it).handle(), 1)); + ASSERT_FALSE(ret.second); + ASSERT_FALSE(view.insert(ret.first, 'c').second); + ASSERT_FALSE(view.insert(++ret.first, 1).second); ASSERT_EQ(view.size(), 3u); ASSERT_EQ((*view.begin()).cast(), 2); ASSERT_EQ((*++view.begin()).cast(), 3); it = view.begin(); + ret = view.erase(it); - ASSERT_FALSE(view.erase(it.handle())); + + ASSERT_FALSE(ret.second); ASSERT_EQ(view.size(), 3u); ASSERT_EQ((*it).cast(), 2); - (*view[std::size_t{}]).cast() = 5; + view[0].cast() = 5; ASSERT_EQ((*view.begin()).cast(), 5); } -TEST(MetaContainer, KeyValueAssociativeContainer) { +TEST(MetaAssociativeContainer, StdMap) { std::map map{{2, 'c'}, {3, 'd'}, {4, 'e'}}; entt::meta_any any{std::ref(map)}; - auto view = any.view(); + auto view = any.as_associative_container(); ASSERT_TRUE(view); ASSERT_EQ(view.size(), 3u); @@ -136,29 +142,32 @@ TEST(MetaContainer, KeyValueAssociativeContainer) { ASSERT_TRUE(first == last); ASSERT_FALSE(first != last); - ASSERT_EQ(((*view[3]).cast>()), (std::pair{3, 'd'})); + ASSERT_EQ(((*view.find(3)).cast>()), (std::pair{3, 'd'})); + + ASSERT_FALSE(view.insert('a', 'a')); + ASSERT_FALSE(view.insert(1, 1)); ASSERT_TRUE(view.insert(0, 'a')); ASSERT_TRUE(view.insert(1, 'b')); ASSERT_EQ(view.size(), 5u); - ASSERT_EQ(((*view[0]).cast>()), (std::pair{0, 'a'})); - ASSERT_EQ(((*view[1]).cast>()), (std::pair{1, 'b'})); + ASSERT_EQ(((*view.find(0)).cast>()), (std::pair{0, 'a'})); + ASSERT_EQ(((*view.find(1)).cast>()), (std::pair{1, 'b'})); ASSERT_TRUE(view.erase(0)); ASSERT_EQ(view.size(), 4u); - ASSERT_EQ(view[0], view.end()); + ASSERT_EQ(view.find(0), view.end()); - (*view[1]).cast>().second = 'f'; + (*view.find(1)).cast>().second = 'f'; - ASSERT_EQ(((*view[1]).cast>()), (std::pair{1, 'f'})); + ASSERT_EQ(((*view.find(1)).cast>()), (std::pair{1, 'f'})); } -TEST(MetaContainer, KeyOnlyAssociativeContainer) { +TEST(MetaAssociativeContainer, StdSet) { std::set set{2, 3, 4}; entt::meta_any any{std::ref(set)}; - auto view = any.view(); + auto view = any.as_associative_container(); ASSERT_TRUE(view); ASSERT_EQ(view.size(), 3u); @@ -178,16 +187,22 @@ TEST(MetaContainer, KeyOnlyAssociativeContainer) { ASSERT_TRUE(first == last); ASSERT_FALSE(first != last); - ASSERT_NE(view[3], view.end()); + ASSERT_EQ((*view.find(3)).cast(), 3); - ASSERT_TRUE(view.insert(0, 'a')); + ASSERT_FALSE(view.insert('0')); + + ASSERT_TRUE(view.insert(0)); ASSERT_TRUE(view.insert(1)); ASSERT_EQ(view.size(), 5u); - ASSERT_NE(view[0], view.end()); - ASSERT_NE(view[1], view.end()); + ASSERT_EQ((*view.find(0)).cast(), 0); + ASSERT_EQ((*view.find(1)).cast(), 1); ASSERT_TRUE(view.erase(0)); ASSERT_EQ(view.size(), 4u); - ASSERT_EQ(view[0], view.end()); + ASSERT_EQ(view.find(0), view.end()); + + (*view.find(1)).cast() = 42; + + ASSERT_EQ((*view.find(1)).cast(), 1); } diff --git a/test/entt/meta/meta_type.cpp b/test/entt/meta/meta_type.cpp index f7b79a4e9..e62650e5d 100644 --- a/test/entt/meta/meta_type.cpp +++ b/test/entt/meta/meta_type.cpp @@ -6,6 +6,7 @@ #include #include #include +#include template void set(Type &prop, Type value) {