// IWYU pragma: always_keep #ifndef ENTT_META_CONTAINER_HPP #define ENTT_META_CONTAINER_HPP #include "../core/concepts.hpp" #include "../core/type_traits.hpp" #include "../stl/concepts.hpp" #include "../stl/cstddef.hpp" #include "../stl/iterator.hpp" #include "../stl/type_traits.hpp" #include "../stl/utility.hpp" #include "context.hpp" #include "fwd.hpp" #include "meta.hpp" #include "type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct sequence_container_extent: integral_constant {}; template requires is_complete_v> struct sequence_container_extent: integral_constant> {}; template inline constexpr stl::size_t sequence_container_extent_v = sequence_container_extent::value; template concept meta_sequence_container_like = requires(Type elem) { typename Type::value_type; typename Type::iterator; requires entt::stl::forward_iterator; { elem.begin() } -> stl::same_as; { elem.end() } -> stl::same_as; requires !requires { typename Type::key_type; }; requires !requires { elem.substr(); }; }; template concept meta_associative_container_like = requires(Type value) { typename Type::key_type; typename Type::value_type; typename Type::iterator; requires entt::stl::forward_iterator; { value.begin() } -> stl::same_as; { value.end() } -> stl::same_as; value.find(stl::declval()); }; } // namespace internal /*! @endcond */ /** * @brief General purpose implementation of meta sequence container traits. * @tparam Type Type of underlying sequence container. */ template struct basic_meta_sequence_container_traits { /*! @brief Unsigned integer type. */ using size_type = meta_sequence_container::size_type; /*! @brief Meta iterator type. */ using iterator = meta_sequence_container::iterator; /*! @brief Number of elements, or `meta_dynamic_extent` if dynamic. */ static constexpr stl::size_t extent = internal::sequence_container_extent_v; /** * @brief Returns the number of elements in a container. * @param container Opaque pointer to a container of the given type. * @return Number of elements. */ [[nodiscard]] static size_type size(const void *container) { return static_cast(container)->size(); } /** * @brief Clears a container. * @param container Opaque pointer to a container of the given type. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool clear([[maybe_unused]] void *container) { if constexpr(requires(Type elem) { elem.clear(); }) { static_cast(container)->clear(); return true; } else { return false; } } /** * @brief Increases the capacity of a container. * @param container Opaque pointer to a container of the given type. * @param sz Desired capacity. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { if constexpr(requires(Type elem) { elem.reserve(sz); }) { static_cast(container)->reserve(sz); return true; } else { return false; } } /** * @brief Resizes a container. * @param container Opaque pointer to a container of the given type. * @param sz The new number of elements. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { if constexpr(stl::is_default_constructible_v && requires(Type elem) { elem.resize(sz); }) { static_cast(container)->resize(sz); return true; } else { return false; } } /** * @brief Returns a possibly const iterator to the beginning or the end. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param as_const Const opaque pointer fallback. * @param end False to get a pointer that is past the last element. * @return An iterator to the first or past the last element of the * container. */ static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) { return (container == nullptr) ? iterator{area, end ? static_cast(as_const)->cend() : static_cast(as_const)->cbegin()} : iterator{area, end ? static_cast(container)->end() : static_cast(container)->begin()}; } /** * @brief Assigns one element to a container and constructs its object from * a given opaque instance. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param value Optional opaque instance of the object to construct (as * value type). * @param cref Optional opaque instance of the object to construct (as * decayed const reference type). * @param it Iterator before which the element will be inserted. * @return A possibly invalid iterator to the inserted element. */ [[nodiscard]] static iterator insert([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const void *value, [[maybe_unused]] const void *cref, [[maybe_unused]] const iterator &it) { if constexpr(requires(Type elem, typename Type::const_iterator iter, Type::value_type instance) { elem.insert(iter, instance); }) { auto *const non_const = any_cast(&it.base()); return {area, static_cast(container)->insert( non_const ? *non_const : any_cast(it.base()), (value != nullptr) ? *static_cast(value) : *static_cast *>(cref))}; } else { return iterator{}; } } /** * @brief Erases an element from a container. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param it An opaque iterator to the element to erase. * @return A possibly invalid iterator following the last removed element. */ [[nodiscard]] static iterator erase([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) { if constexpr(requires(Type elem, typename Type::const_iterator iter) { elem.erase(iter); }) { auto *const non_const = any_cast(&it.base()); return {area, static_cast(container)->erase(non_const ? *non_const : any_cast(it.base()))}; } else { return iterator{}; } } }; /** * @brief General purpose implementation of meta associative container traits. * @tparam Type Type of underlying associative container. */ template struct basic_meta_associative_container_traits { /*! @brief Unsigned integer type. */ using size_type = meta_associative_container::size_type; /*! @brief Meta iterator type. */ using iterator = meta_associative_container::iterator; /*! @brief True in case of key-only containers, false otherwise. */ static constexpr bool key_only = !requires { typename Type::mapped_type; }; /** * @brief Returns the number of elements in a container. * @param container Opaque pointer to a container of the given type. * @return Number of elements. */ [[nodiscard]] static size_type size(const void *container) { return static_cast(container)->size(); } /** * @brief Clears a container. * @param container Opaque pointer to a container of the given type. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool clear(void *container) { static_cast(container)->clear(); return true; } /** * @brief Increases the capacity of a container. * @param container Opaque pointer to a container of the given type. * @param sz Desired capacity. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { if constexpr(requires(Type elem) { elem.reserve(sz); }) { static_cast(container)->reserve(sz); return true; } else { return false; } } /** * @brief Returns a possibly const iterator to the beginning or the end. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param as_const Const opaque pointer fallback. * @param end False to get a pointer that is past the last element. * @return An iterator to the first or past the last element of the * container. */ static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) { return (container == nullptr) ? iterator{area, stl::bool_constant{}, end ? static_cast(as_const)->cend() : static_cast(as_const)->cbegin()} : iterator{area, stl::bool_constant{}, end ? static_cast(container)->end() : static_cast(container)->begin()}; } /** * @brief Inserts an element into a container, if the key does not exist. * @param container Opaque pointer to a container of the given type. * @param key An opaque key value of an element to insert. * @param value Optional opaque value to insert (key-value containers). * @return True if the insertion took place, false otherwise. */ [[nodiscard]] static bool insert(void *container, const void *key, [[maybe_unused]] const void *value) { if constexpr(key_only) { return static_cast(container)->insert(*static_cast(key)).second; } else { return static_cast(container)->emplace(*static_cast(key), *static_cast(value)).second; } } /** * @brief Removes an element from a container. * @param container Opaque pointer to a container of the given type. * @param key An opaque key value of an element to remove. * @return Number of elements removed (either 0 or 1). */ [[nodiscard]] static size_type erase(void *container, const void *key) { return static_cast(container)->erase(*static_cast(key)); } /** * @brief Finds an element with a given key. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param as_const Const opaque pointer fallback. * @param key Opaque key value of an element to search for. * @return An iterator to the element with the given key, if any. */ static iterator find(const meta_ctx &area, void *container, const void *as_const, const void *key) { return (container != nullptr) ? iterator{area, stl::bool_constant{}, static_cast(container)->find(*static_cast(key))} : iterator{area, stl::bool_constant{}, static_cast(as_const)->find(*static_cast(key))}; } }; /** * @brief Traits meta sequence container like types. * @tparam Type Container type to inspect. */ template struct meta_sequence_container_traits: basic_meta_sequence_container_traits {}; /** * @brief Traits for meta associative container like types. * @tparam Type Container type to inspect. */ template struct meta_associative_container_traits: basic_meta_associative_container_traits {}; } // namespace entt #endif