Просмотр исходного кода

meta: meta container support review

Michele Caini 5 лет назад
Родитель
Сommit
8a344cd9b2

+ 2 - 0
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)

+ 2 - 0
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"

+ 541 - 0
src/entt/meta/container.hpp

@@ -0,0 +1,541 @@
+#ifndef ENTT_META_CONTAINER_HPP
+#define ENTT_META_CONTAINER_HPP
+
+
+#include <array>
+#include <map>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+#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<typename Type, typename... Args>
+struct meta_sequence_container_traits_t<std::vector<Type, Args...>> {
+    /*! @brief Iterator type of the sequence container. */
+    using iterator = typename std::vector<Type, Args...>::iterator;
+    /*! @brief Unsigned integer type. */
+    using size_type = typename std::vector<Type, Args...>::size_type;
+    /*! @brief Value type of the sequence container. */
+    using value_type = typename std::vector<Type, Args...>::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<Type, Args...> &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<Type, Args...> &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<Type, Args...> &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<Type, Args...> &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<iterator, bool> insert(std::vector<Type, Args...> &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<iterator, bool> erase(std::vector<Type, Args...> &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<Type, Args...> &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<typename Type, auto N>
+struct meta_sequence_container_traits_t<std::array<Type, N>> {
+    /*! @brief Iterator type of the sequence container. */
+    using iterator = typename std::array<Type, N>::iterator;
+    /*! @brief Unsigned integer type. */
+    using size_type = typename std::array<Type, N>::size_type;
+    /*! @brief Value type of the sequence container. */
+    using value_type = typename std::array<Type, N>::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<Type, N> &arr) ENTT_NOEXCEPT {
+        return arr.size();
+    }
+
+    /**
+     * @brief Does nothing.
+     * @return False to indicate failure in all cases.
+     */
+    [[nodiscard]] static bool clear(std::array<Type, N> &) {
+        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<Type, N> &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<Type, N> &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<iterator, bool> insert(std::array<Type, N> &, 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<iterator, bool> erase(std::array<Type, N> &, 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<Type, N> &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<typename Key, typename Value, typename... Args>
+struct meta_associative_container_traits_t<std::map<Key, Value, Args...>> {
+    /*! @brief Iterator type of the associative container. */
+    using iterator = typename std::map<Key, Value, Args...>::iterator;
+    /*! @brief Unsigned integer type. */
+    using size_type = typename std::map<Key, Value, Args...>::size_type;
+    /*! @brief Key type of the sequence container. */
+    using key_type = typename std::map<Key, Value, Args...>::key_type;
+    /*! @brief Mapped type of the sequence container. */
+    using mapped_type = typename std::map<Key, Value, Args...>::mapped_type;
+    /*! @brief Value type of the sequence container. */
+    using value_type = typename std::map<Key, Value, Args...>::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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<typename Key, typename Value, typename... Args>
+struct meta_associative_container_traits_t<std::unordered_map<Key, Value, Args...>> {
+    /*! @brief Iterator type of the associative container. */
+    using iterator = typename std::unordered_map<Key, Value, Args...>::iterator;
+    /*! @brief Unsigned integer type. */
+    using size_type = typename std::unordered_map<Key, Value, Args...>::size_type;
+    /*! @brief Key type of the sequence container. */
+    using key_type = typename std::unordered_map<Key, Value, Args...>::key_type;
+    /*! @brief Mapped type of the sequence container. */
+    using mapped_type = typename std::unordered_map<Key, Value, Args...>::mapped_type;
+    /*! @brief Value type of the sequence container. */
+    using value_type = typename std::unordered_map<Key, Value, Args...>::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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<Key, Value, Args...> &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<typename Key, typename... Args>
+struct meta_associative_container_traits_t<std::set<Key, Args...>> {
+    /*! @brief Iterator type of the associative container. */
+    using iterator = typename std::set<Key, Args...>::iterator;
+    /*! @brief Unsigned integer type. */
+    using size_type = typename std::set<Key, Args...>::size_type;
+    /*! @brief Key type of the sequence container. */
+    using key_type = typename std::set<Key, Args...>::key_type;
+    /*! @brief Value type of the sequence container. */
+    using value_type = typename std::set<Key, Args...>::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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &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<typename Key, typename... Args>
+struct meta_associative_container_traits_t<std::unordered_set<Key, Args...>> {
+    /*! @brief Iterator type of the associative container. */
+    using iterator = typename std::unordered_set<Key, Args...>::iterator;
+    /*! @brief Unsigned integer type. */
+    using size_type = typename std::unordered_set<Key, Args...>::size_type;
+    /*! @brief Key type of the sequence container. */
+    using key_type = typename std::unordered_set<Key, Args...>::key_type;
+    /*! @brief Value type of the sequence container. */
+    using value_type = typename std::unordered_set<Key, Args...>::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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &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<Key, Args...> &set, const key_type &key) {
+        return set.find(key);
+    }
+};
+
+
+}
+
+
+#endif

+ 3 - 2
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<Type>,
             std::is_member_function_pointer_v<Type>,
             is_dereferenceable_v<Type>,
-            is_sequence_container_v<Type>,
-            is_associative_container_v<Type>,
+            has_meta_sequence_container_traits_v<Type>,
+            has_meta_associative_container_traits_v<Type>,
             std::rank_v<Type>,
             [](meta_type_node::size_type dim) {
                 return extent(dim, std::make_index_sequence<std::rank_v<Type>>{});

+ 609 - 370
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;
+/*! @brief Proxy object for sequence containers. */
+class meta_sequence_container {
+    template<typename>
+    struct meta_sequence_container_proxy;
 
-    struct meta_iterator;
+public:
+    /*! @brief Unsigned integer type. */
+    using size_type = std::size_t;
+    /*! @brief Meta iterator type. */
+    using iterator = 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;
-    };
+    template<typename Type>
+    meta_sequence_container(Type &);
 
-    meta_container(meta_view *impl, void *container)
-        : view{impl},
-          instance{container}
-    {}
+    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<iterator, bool> insert(iterator, meta_any);
+    inline std::pair<iterator, bool> erase(iterator);
+    inline meta_any operator[](size_type);
+
+    inline explicit operator bool() const ENTT_NOEXCEPT;
+
+private:
+    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<iterator, bool>(* insert_fn)(void *, iterator, meta_any);
+    std::pair<iterator, bool>(* erase_fn)(void *, iterator);
+    meta_any(* get_fn)(void *, size_type);
+    void *instance;
+};
+
+
+/*! @brief Proxy object for associative containers. */
+class meta_associative_container {
+    template<typename, typename = void>
+    struct has_mapped_type: std::false_type {};
+
+    template<typename Type>
+    struct has_mapped_type<Type, std::void_t<typename meta_associative_container_traits_t<Type>::mapped_type>>
+            : std::true_type
+    {};
+
+    template<typename>
+    struct meta_associative_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{}
-    {}
-
-    [[nodiscard]] inline size_type size() const ENTT_NOEXCEPT;
+    template<typename Type>
+    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);
-    [[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 iterator find(meta_any);
+
+    inline explicit operator bool() const ENTT_NOEXCEPT;
 
 private:
-    meta_view *view;
+    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<typename, typename = void>
-    struct container_view {
-        [[nodiscard]] static meta_container::meta_view * instance() {
-            return nullptr;
-        }
-    };
-
-    template<typename Type>
-    struct container_view<Type, std::enable_if_t<is_sequence_container_v<Type>>>: 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<const Type *>(container)->size();
-        }
-
-        [[nodiscard]] bool insert(void *container, meta_any it, meta_any value) override {
-            bool ret = false;
-
-            if constexpr(is_dynamic_sequence_container_v<Type>) {
-                if(auto *iter = it.try_cast<typename Type::iterator>(); iter) {
-                    if(const auto *curr = value.try_cast<typename Type::value_type>(); curr) {
-                        *iter = static_cast<Type *>(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<Type>) {
-                if(auto *iter = it.try_cast<typename Type::iterator>(); iter) {
-                    *iter = static_cast<Type *>(container)->erase(*iter);
-                    ret = true;
-                }
-            }
-
-            return ret;
-        }
-
-        [[nodiscard]] meta_any begin(void *container) const ENTT_NOEXCEPT override {
-            return static_cast<Type *>(container)->begin();
-        }
-
-        [[nodiscard]] meta_any end(void *container) const ENTT_NOEXCEPT override {
-            return static_cast<Type *>(container)->end();
-        }
-
-        [[nodiscard]] meta_any deref(meta_any it) const ENTT_NOEXCEPT override {
-            return std::ref(*it.cast<typename Type::iterator>());
-        }
-
-        [[nodiscard]] meta_any find(void *container, meta_any idx) const ENTT_NOEXCEPT override {
-            meta_any any{};
-
-            if(const auto *curr = idx.try_cast<std::size_t>(); curr) {
-                any = std::next(static_cast<Type *>(container)->begin(), *curr);
-            }
-
-            return any;
-        }
-
-        void incr(meta_any it) const ENTT_NOEXCEPT override {
-            ++it.cast<typename Type::iterator>();
-        }
-    };
-
-    template<typename Type>
-    struct container_view<Type, std::enable_if_t<is_associative_container_v<Type>>>: 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<const Type *>(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<Type>) {
-                if(const auto *curr = key.try_cast<typename Type::key_type>(); curr) {
-                    static_cast<Type *>(container)->insert(*curr);
-                    ret = true;
-                }
-            } else {
-                if(const auto *k_curr = key.try_cast<typename Type::key_type>(); k_curr) {
-                    if(const auto *v_curr = value.try_cast<typename Type::mapped_type>(); v_curr) {
-                        static_cast<Type *>(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<typename Type::key_type>(); curr) {
-                static_cast<Type *>(container)->erase(*curr);
-                ret = true;
-            }
-
-            return ret;
-        }
-
-        [[nodiscard]] meta_any begin(void *container) const ENTT_NOEXCEPT override {
-            return static_cast<Type *>(container)->begin();
-        }
-
-        [[nodiscard]] meta_any end(void *container) const ENTT_NOEXCEPT override {
-            return static_cast<Type *>(container)->end();
-        }
-
-        [[nodiscard]] meta_any deref(meta_any it) const ENTT_NOEXCEPT override {
-            if constexpr(is_key_only_associative_container_v<Type>) {
-                return *it.cast<typename Type::iterator>();
-            } else {
-                return std::ref(*it.cast<typename Type::iterator>());
-            }
-        }
-
-        [[nodiscard]] meta_any find(void *container, meta_any key) const ENTT_NOEXCEPT override {
-            meta_any any{};
-
-            if constexpr(is_key_only_associative_container_v<Type>) {
-                if(const auto *curr = key.try_cast<typename Type::key_type>(); curr) {
-                    auto *cont = static_cast<Type *>(container);
-                    any = std::find(cont->begin(), cont->end(), *curr);
-                }
-            } else {
-                if(const auto *curr = key.try_cast<typename Type::key_type>(); curr) {
-                    any = static_cast<Type *>(container)->find(*curr);
-                }
-            }
-
-            return any;
-        }
-
-        void incr(meta_any it) const ENTT_NOEXCEPT override {
-            it.cast<typename Type::iterator>().operator++();
-        }
-    };
-
     template<typename Type>
     static meta_any dereference_operator(meta_any &any) {
         meta_any other{};
@@ -249,13 +143,32 @@ class meta_any {
         return other;
     }
 
+    template<typename Type>
+    [[nodiscard]] static auto * meta_sequence_container_factory() ENTT_NOEXCEPT {
+        if constexpr(has_meta_sequence_container_traits_v<Type>) {
+            return +[](void *container) -> meta_sequence_container { return *static_cast<Type *>(container); };
+        } else {
+            return static_cast<decltype(seq_factory)>(nullptr);
+        }
+    }
+
+    template<typename Type>
+    [[nodiscard]] static auto * meta_associative_container_factory() ENTT_NOEXCEPT {
+        if constexpr(has_meta_associative_container_traits_v<Type>) {
+            return +[](void *container) -> meta_associative_container { return *static_cast<Type *>(container); };
+        } else {
+            return static_cast<decltype(assoc_factory)>(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<Type>, std::forward<Args>(args)...),
           node{internal::meta_info<Type>::resolve()},
           deref{&dereference_operator<Type>},
-          cview{container_view<Type>::instance()}
+          seq_factory{meta_sequence_container_factory<Type>()},
+          assoc_factory{meta_associative_container_factory<Type>()}
     {}
 
     /**
@@ -282,7 +196,8 @@ public:
         : storage{value},
           node{internal::meta_info<Type>::resolve()},
           deref{&dereference_operator<Type>},
-          cview{container_view<Type>::instance()}
+          seq_factory{meta_sequence_container_factory<Type>()},
+          assoc_factory{meta_associative_container_factory<Type>()}
     {}
 
     /**
@@ -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<bool>(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.<br/>
- * 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<typename Type>
+    static void incr(meta_any any) {
+        ++any.cast<typename Type::iterator>();
+    }
+
+    template<typename Type>
+    static meta_any deref(meta_any any) {
+        if constexpr(std::is_const_v<std::remove_reference_t<decltype(*std::declval<typename Type::iterator>())>>) {
+            return *any.cast<typename Type::iterator>();
+        } else {
+            return std::ref(*any.cast<typename Type::iterator>());
+        }
+    }
+
+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<typename Type>
+    meta_iterator(std::in_place_type_t<Type>, typename Type::iterator iter)
+        : next_fn{&incr<Type>},
+          get_fn{&deref<Type>},
+          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<bool>(it);
+    }
+
+private:
+    void(* next_fn)(meta_any);
+    meta_any(* get_fn)(meta_any);
+    entt::meta_any it;
+};
+
+
+template<typename Type>
+struct meta_sequence_container::meta_sequence_container_proxy {
+    static meta_type value_type() {
+        return internal::meta_info<typename meta_sequence_container_traits_t<Type>::value_type>::resolve();
+    }
+
+    static meta_sequence_container::size_type size(const void *container) {
+        return meta_sequence_container_traits_t<Type>::size(*static_cast<const Type *>(container));
+    }
+
+    static bool clear(void *container) {
+        return meta_sequence_container_traits_t<Type>::clear(*static_cast<Type *>(container));
+    }
+
+    static iterator begin(void *container) {
+        return iterator{std::in_place_type<Type>, meta_sequence_container_traits_t<Type>::begin(*static_cast<Type *>(container))};
+    }
+
+    static iterator end(void *container) {
+        return iterator{std::in_place_type<Type>, meta_sequence_container_traits_t<Type>::end(*static_cast<Type *>(container))};
+    }
+
+    static std::pair<iterator, bool> insert(void *container, iterator it, meta_any any) {
+        std::pair<typename meta_sequence_container_traits_t<Type>::iterator, bool> ret{{}, false};
+
+        if(const auto *value = any.try_cast<typename meta_sequence_container_traits_t<Type>::value_type>(); value) {
+            ret = meta_sequence_container_traits_t<Type>::insert(*static_cast<Type *>(container), it.handle().cast<typename meta_sequence_container_traits_t<Type>::iterator>(), *value);
+        }
+
+        return {iterator{std::in_place_type<Type>, std::move(ret.first)}, ret.second};
+    }
+
+    static std::pair<iterator, bool> erase(void *container, iterator it) {
+        auto ret = meta_sequence_container_traits_t<Type>::erase(*static_cast<Type *>(container), it.handle().cast<typename meta_sequence_container_traits_t<Type>::iterator>());
+        return {iterator{std::in_place_type<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<Type>::get(*static_cast<Type *>(container), pos));
+    }
+};
+
+
+/**
+ * @brief Construct a proxy object for sequence containers.
+ * @tparam Type Type of container to wrap.
+ * @param container The container to wrap.
+ */
+template<typename Type>
+meta_sequence_container::meta_sequence_container(Type &container)
+    : value_type_fn{&meta_sequence_container_proxy<Type>::value_type},
+      size_fn{&meta_sequence_container_proxy<Type>::size},
+      clear_fn{&meta_sequence_container_proxy<Type>::clear},
+      begin_fn{&meta_sequence_container_proxy<Type>::begin},
+      end_fn{&meta_sequence_container_proxy<Type>::end},
+      insert_fn{&meta_sequence_container_proxy<Type>::insert},
+      erase_fn{&meta_sequence_container_proxy<Type>::erase},
+      get_fn{&meta_sequence_container_proxy<Type>::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::iterator, bool> 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::iterator, bool> 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<typename Type>
+struct meta_associative_container::meta_associative_container_proxy {
+    static constexpr auto has_mapped_type = meta_associative_container::has_mapped_type<Type>::value;
+
+    static meta_type key_type() {
+        return internal::meta_info<typename meta_associative_container_traits_t<Type>::key_type>::resolve();
+    }
+
+    static meta_type mapped_type() {
+        if constexpr(has_mapped_type) {
+            return internal::meta_info<typename meta_associative_container_traits_t<Type>::mapped_type>::resolve();
+        } else {
+            return meta_type{};
+        }
+    }
+
+    static meta_type value_type() {
+        return internal::meta_info<typename meta_associative_container_traits_t<Type>::value_type>::resolve();
+    }
+
+    static meta_associative_container::size_type size(const void *container) {
+        return meta_associative_container_traits_t<Type>::size(*static_cast<const Type *>(container));
+    }
+
+    static bool clear(void *container) {
+        return meta_associative_container_traits_t<Type>::clear(*static_cast<Type *>(container));
+    }
+
+    static iterator begin(void *container) {
+        return iterator{std::in_place_type<Type>, meta_associative_container_traits_t<Type>::begin(*static_cast<Type *>(container))};
+    }
+
+    static iterator end(void *container) {
+        return iterator{std::in_place_type<Type>, meta_associative_container_traits_t<Type>::end(*static_cast<Type *>(container))};
+    }
+
+    static bool insert(void *container, meta_any key, meta_any value) {
+        bool ret = false;
+
+        if(const auto *k_ptr = key.try_cast<typename meta_associative_container_traits_t<Type>::key_type>(); k_ptr) {
+            if constexpr(has_mapped_type) {
+                if(auto *m_ptr = value.try_cast<typename meta_associative_container_traits_t<Type>::mapped_type>(); m_ptr) {
+                    ret = meta_associative_container_traits_t<Type>::insert(*static_cast<Type *>(container), *k_ptr, *m_ptr);
+                }
+            } else {
+                ret = meta_associative_container_traits_t<Type>::insert(*static_cast<Type *>(container), *k_ptr);
+            }
+        }
+
+        return ret;
+    }
+
+    static bool erase(void *container, meta_any key) {
+        bool ret = false;
+
+        if(const auto *k_ptr = key.try_cast<typename meta_associative_container_traits_t<Type>::key_type>(); k_ptr) {
+            ret = meta_associative_container_traits_t<Type>::erase(*static_cast<Type *>(container), *k_ptr);
+        }
+
+        return ret;
+    }
+
+    static iterator find(void *container, meta_any key) {
+        iterator ret{};
+
+        if(const auto *k_ptr = key.try_cast<typename meta_associative_container_traits_t<Type>::key_type>(); k_ptr) {
+            ret = iterator{std::in_place_type<Type>, meta_associative_container_traits_t<Type>::find(*static_cast<Type *>(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<typename Type>
+meta_associative_container::meta_associative_container(Type &container)
+    : key_only_container{!meta_associative_container_proxy<Type>::has_mapped_type},
+      key_type_fn{&meta_associative_container_proxy<Type>::key_type},
+      mapped_type_fn{&meta_associative_container_proxy<Type>::mapped_type},
+      value_type_fn{&meta_associative_container_proxy<Type>::value_type},
+      size_fn{&meta_associative_container_proxy<Type>::size},
+      clear_fn{&meta_associative_container_proxy<Type>::clear},
+      begin_fn{&meta_associative_container_proxy<Type>::begin},
+      end_fn{&meta_associative_container_proxy<Type>::end},
+      insert_fn{&meta_associative_container_proxy<Type>::insert},
+      erase_fn{&meta_associative_container_proxy<Type>::erase},
+      find_fn{&meta_associative_container_proxy<Type>::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);
+}
+
+
 }
 
 

+ 78 - 0
src/entt/meta/type_traits.hpp

@@ -0,0 +1,78 @@
+#ifndef ENTT_META_TYPE_TRAITS_HPP
+#define ENTT_META_TYPE_TRAITS_HPP
+
+
+#include <type_traits>
+
+
+namespace entt {
+
+
+/**
+ * @brief Traits class template to be specialized to enable support for meta
+ * sequence containers.
+ */
+template<typename>
+struct meta_sequence_container_traits_t;
+
+
+/**
+ * @brief Traits class template to be specialized to enable support for meta
+ * associative containers.
+ */
+template<typename>
+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<typename Type, typename = void>
+struct has_meta_sequence_container_traits: std::false_type {};
+
+
+/*! @copydoc has_meta_sequence_container_traits */
+template<typename Type>
+struct has_meta_sequence_container_traits<Type, std::void_t<typename meta_sequence_container_traits_t<Type>::value_type>>
+        : std::true_type
+{};
+
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Potentially sequence container type.
+ */
+template<typename Type>
+inline constexpr auto has_meta_sequence_container_traits_v = has_meta_sequence_container_traits<Type>::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<typename, typename = void>
+struct has_meta_associative_container_traits: std::false_type {};
+
+
+/*! @copydoc has_meta_associative_container_traits */
+template<typename Type>
+struct has_meta_associative_container_traits<Type, std::void_t<typename meta_associative_container_traits_t<Type>::key_type>>
+        : std::true_type
+{};
+
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Potentially associative container type.
+ */
+template<typename Type>
+inline constexpr auto has_meta_associative_container_traits_v = has_meta_associative_container_traits<Type>::value;
+
+
+}
+
+
+#endif

+ 53 - 38
test/entt/meta/meta_container.cpp

@@ -1,32 +1,30 @@
-#include <array>
-#include <map>
-#include <set>
-#include <utility>
-#include <vector>
 #include <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
+#include <entt/meta/container.hpp>
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
 #include <entt/meta/resolve.hpp>
+#include <entt/meta/type_traits.hpp>
 
-TEST(MetaContainer, Empty) {
-    entt::meta_container container{};
+TEST(MetaSequenceContainer, Empty) {
+    entt::meta_sequence_container container{};
 
     ASSERT_FALSE(container);
 
     entt::meta_any any{std::vector<int>{}};
-    container = any.view();
+    container = any.as_sequence_container();
 
     ASSERT_TRUE(container);
 }
 
-TEST(MetaContainer, DynamicSequenceContainer) {
+TEST(MetaSequenceContainer, StdVector) {
     std::vector<int> 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<int>());
     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<int>(), 3);
+    ASSERT_EQ(view[1u].cast<int>(), 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<int>(), 0);
     ASSERT_EQ((*++view.begin()).cast<int>(), 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<int>(), 1);
+    ASSERT_EQ((*ret.first).cast<int>(), 1);
 
-    (*view[std::size_t{}]).cast<int>() = 5;
+    view[0].cast<int>() = 5;
 
     ASSERT_EQ((*view.begin()).cast<int>(), 5);
 }
 
-TEST(MetaContainer, FixedSizeSequenceContainer) {
+TEST(MetaSequenceContainer, StdArray) {
     std::array<int, 3> 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<int>());
     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<int>(), 3);
+    ASSERT_EQ(view[1u].cast<int>(), 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<int>(), 2);
     ASSERT_EQ((*++view.begin()).cast<int>(), 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<int>(), 2);
 
-    (*view[std::size_t{}]).cast<int>() = 5;
+    view[0].cast<int>() = 5;
 
     ASSERT_EQ((*view.begin()).cast<int>(), 5);
 }
 
-TEST(MetaContainer, KeyValueAssociativeContainer) {
+TEST(MetaAssociativeContainer, StdMap) {
     std::map<int, char> 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<const int, char>>()), (std::pair<const int, char>{3, 'd'}));
+    ASSERT_EQ(((*view.find(3)).cast<std::pair<const int, char>>()), (std::pair<const int, char>{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<const int, char>>()), (std::pair<const int, char>{0, 'a'}));
-    ASSERT_EQ(((*view[1]).cast<std::pair<const int, char>>()), (std::pair<const int, char>{1, 'b'}));
+    ASSERT_EQ(((*view.find(0)).cast<std::pair<const int, char>>()), (std::pair<const int, char>{0, 'a'}));
+    ASSERT_EQ(((*view.find(1)).cast<std::pair<const int, char>>()), (std::pair<const int, char>{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<std::pair<const int, char>>().second = 'f';
+    (*view.find(1)).cast<std::pair<const int, char>>().second = 'f';
 
-    ASSERT_EQ(((*view[1]).cast<std::pair<const int, char>>()), (std::pair<const int, char>{1, 'f'}));
+    ASSERT_EQ(((*view.find(1)).cast<std::pair<const int, char>>()), (std::pair<const int, char>{1, 'f'}));
 }
 
-TEST(MetaContainer, KeyOnlyAssociativeContainer) {
+TEST(MetaAssociativeContainer, StdSet) {
     std::set<int> 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<int>(), 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<int>(), 0);
+    ASSERT_EQ((*view.find(1)).cast<int>(), 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<int>() = 42;
+
+    ASSERT_EQ((*view.find(1)).cast<int>(), 1);
 }

+ 1 - 0
test/entt/meta/meta_type.cpp

@@ -6,6 +6,7 @@
 #include <entt/meta/factory.hpp>
 #include <entt/meta/meta.hpp>
 #include <entt/meta/resolve.hpp>
+#include <entt/meta/container.hpp>
 
 template<typename Type>
 void set(Type &prop, Type value) {