Skip to content

Commit 8d4597e

Browse files
committed
meta: auto-detect meta containers, use traits to opt-out
1 parent e14033b commit 8d4597e

File tree

2 files changed

+56
-100
lines changed

2 files changed

+56
-100
lines changed

src/entt/meta/container.hpp

Lines changed: 34 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,11 @@
33
#ifndef ENTT_META_CONTAINER_HPP
44
#define ENTT_META_CONTAINER_HPP
55

6-
#include <array>
76
#include <concepts>
87
#include <cstddef>
9-
#include <deque>
108
#include <iterator>
11-
#include <list>
12-
#include <map>
13-
#include <set>
149
#include <type_traits>
15-
#include <unordered_map>
16-
#include <unordered_set>
17-
#include <vector>
18-
#include "../container/dense_map.hpp"
19-
#include "../container/dense_set.hpp"
10+
#include <utility>
2011
#include "../core/concepts.hpp"
2112
#include "../core/type_traits.hpp"
2213
#include "context.hpp"
@@ -39,15 +30,27 @@ struct sequence_container_extent<Type>: integral_constant<std::tuple_size_v<Type
3930
template<typename Type>
4031
inline constexpr std::size_t sequence_container_extent_v = sequence_container_extent<Type>::value;
4132

42-
template<typename>
43-
struct key_only_associative_container: std::true_type {};
44-
4533
template<typename Type>
46-
requires requires { typename Type::mapped_type; }
47-
struct key_only_associative_container<Type>: std::false_type {};
34+
concept meta_sequence_container_like = requires(Type elem) {
35+
typename Type::value_type;
36+
typename Type::iterator;
37+
requires std::forward_iterator<typename Type::iterator>;
38+
{ elem.begin() } -> std::same_as<typename Type::iterator>;
39+
{ elem.end() } -> std::same_as<typename Type::iterator>;
40+
requires !requires { typename Type::key_type; };
41+
requires !requires { elem.substr(); };
42+
};
4843

4944
template<typename Type>
50-
inline constexpr bool key_only_associative_container_v = key_only_associative_container<Type>::value;
45+
concept meta_associative_container_like = requires(Type value) {
46+
typename Type::key_type;
47+
typename Type::value_type;
48+
typename Type::iterator;
49+
requires std::forward_iterator<typename Type::iterator>;
50+
{ value.begin() } -> std::same_as<typename Type::iterator>;
51+
{ value.end() } -> std::same_as<typename Type::iterator>;
52+
value.find(std::declval<typename Type::key_type>());
53+
};
5154

5255
} // namespace internal
5356
/*! @endcond */
@@ -81,7 +84,7 @@ struct basic_meta_sequence_container_traits {
8184
* @return True in case of success, false otherwise.
8285
*/
8386
[[nodiscard]] static bool clear([[maybe_unused]] void *container) {
84-
if constexpr(extent == meta_dynamic_extent) {
87+
if constexpr(requires(Type elem) { elem.clear(); }) {
8588
static_cast<Type *>(container)->clear();
8689
return true;
8790
} else {
@@ -96,7 +99,7 @@ struct basic_meta_sequence_container_traits {
9699
* @return True in case of success, false otherwise.
97100
*/
98101
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
99-
if constexpr(requires(Type elem) { { elem.reserve(sz) }; }) {
102+
if constexpr(requires(Type elem) { elem.reserve(sz); }) {
100103
static_cast<Type *>(container)->reserve(sz);
101104
return true;
102105
} else {
@@ -111,7 +114,7 @@ struct basic_meta_sequence_container_traits {
111114
* @return True in case of success, false otherwise.
112115
*/
113116
[[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
114-
if constexpr((extent == meta_dynamic_extent) && std::is_default_constructible_v<typename Type::value_type>) {
117+
if constexpr(std::is_default_constructible_v<typename Type::value_type> && requires(Type elem) { elem.resize(sz); }) {
115118
static_cast<Type *>(container)->resize(sz);
116119
return true;
117120
} else {
@@ -147,7 +150,7 @@ struct basic_meta_sequence_container_traits {
147150
* @return A possibly invalid iterator to the inserted element.
148151
*/
149152
[[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) {
150-
if constexpr(extent == meta_dynamic_extent) {
153+
if constexpr(requires(Type elem, typename Type::const_iterator it, Type::value_type instance) { elem.insert(it, instance); }) {
151154
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
152155
return {area, static_cast<Type *>(container)->insert(
153156
non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()),
@@ -165,7 +168,7 @@ struct basic_meta_sequence_container_traits {
165168
* @return A possibly invalid iterator following the last removed element.
166169
*/
167170
[[nodiscard]] static iterator erase([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) {
168-
if constexpr(extent == meta_dynamic_extent) {
171+
if constexpr(requires(Type elem, typename Type::const_iterator it) { elem.erase(it); }) {
169172
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
170173
return {area, static_cast<Type *>(container)->erase(non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()))};
171174
} else {
@@ -186,7 +189,7 @@ struct basic_meta_associative_container_traits {
186189
using iterator = meta_associative_container::iterator;
187190

188191
/*! @brief True in case of key-only containers, false otherwise. */
189-
static constexpr bool key_only = internal::key_only_associative_container_v<Type>;
192+
static constexpr bool key_only = !requires { typename Type::mapped_type; };
190193

191194
/**
192195
* @brief Returns the number of elements in a container.
@@ -214,7 +217,7 @@ struct basic_meta_associative_container_traits {
214217
* @return True in case of success, false otherwise.
215218
*/
216219
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
217-
if constexpr(requires(Type elem) { { elem.reserve(sz) }; }) {
220+
if constexpr(requires(Type elem) { elem.reserve(sz); }) {
218221
static_cast<Type *>(container)->reserve(sz);
219222
return true;
220223
} else {
@@ -277,87 +280,18 @@ struct basic_meta_associative_container_traits {
277280
};
278281

279282
/**
280-
* @brief Meta sequence container traits for `std::vector`s of any type.
281-
* @tparam Args Template arguments for the container.
282-
*/
283-
template<typename... Args>
284-
struct meta_sequence_container_traits<std::vector<Args...>>
285-
: basic_meta_sequence_container_traits<std::vector<Args...>> {};
286-
287-
/**
288-
* @brief Meta sequence container traits for `std::array`s of any type.
289-
* @tparam Type Template arguments for the container.
290-
* @tparam N Template arguments for the container.
291-
*/
292-
template<typename Type, auto N>
293-
struct meta_sequence_container_traits<std::array<Type, N>>
294-
: basic_meta_sequence_container_traits<std::array<Type, N>> {};
295-
296-
/**
297-
* @brief Meta sequence container traits for `std::list`s of any type.
298-
* @tparam Args Template arguments for the container.
299-
*/
300-
template<typename... Args>
301-
struct meta_sequence_container_traits<std::list<Args...>>
302-
: basic_meta_sequence_container_traits<std::list<Args...>> {};
303-
304-
/**
305-
* @brief Meta sequence container traits for `std::deque`s of any type.
306-
* @tparam Args Template arguments for the container.
307-
*/
308-
template<typename... Args>
309-
struct meta_sequence_container_traits<std::deque<Args...>>
310-
: basic_meta_sequence_container_traits<std::deque<Args...>> {};
311-
312-
/**
313-
* @brief Meta associative container traits for `std::map`s of any type.
314-
* @tparam Args Template arguments for the container.
315-
*/
316-
template<typename... Args>
317-
struct meta_associative_container_traits<std::map<Args...>>
318-
: basic_meta_associative_container_traits<std::map<Args...>> {};
319-
320-
/**
321-
* @brief Meta associative container traits for `std::unordered_map`s of any
322-
* type.
323-
* @tparam Args Template arguments for the container.
324-
*/
325-
template<typename... Args>
326-
struct meta_associative_container_traits<std::unordered_map<Args...>>
327-
: basic_meta_associative_container_traits<std::unordered_map<Args...>> {};
328-
329-
/**
330-
* @brief Meta associative container traits for `std::set`s of any type.
331-
* @tparam Args Template arguments for the container.
332-
*/
333-
template<typename... Args>
334-
struct meta_associative_container_traits<std::set<Args...>>
335-
: basic_meta_associative_container_traits<std::set<Args...>> {};
336-
337-
/**
338-
* @brief Meta associative container traits for `std::unordered_set`s of any
339-
* type.
340-
* @tparam Args Template arguments for the container.
341-
*/
342-
template<typename... Args>
343-
struct meta_associative_container_traits<std::unordered_set<Args...>>
344-
: basic_meta_associative_container_traits<std::unordered_set<Args...>> {};
345-
346-
/**
347-
* @brief Meta associative container traits for `dense_map`s of any type.
348-
* @tparam Args Template arguments for the container.
283+
* @brief Traits meta sequence container like types.
284+
* @tparam Type Container type to inspect.
349285
*/
350-
template<typename... Args>
351-
struct meta_associative_container_traits<dense_map<Args...>>
352-
: basic_meta_associative_container_traits<dense_map<Args...>> {};
286+
template<internal::meta_sequence_container_like Type>
287+
struct meta_sequence_container_traits<Type>: basic_meta_sequence_container_traits<Type> {};
353288

354289
/**
355-
* @brief Meta associative container traits for `dense_set`s of any type.
356-
* @tparam Args Template arguments for the container.
290+
* @brief Traits for meta associative container like types.
291+
* @tparam Type Container type to inspect.
357292
*/
358-
template<typename... Args>
359-
struct meta_associative_container_traits<dense_set<Args...>>
360-
: basic_meta_associative_container_traits<dense_set<Args...>> {};
293+
template<internal::meta_associative_container_like Type>
294+
struct meta_associative_container_traits<Type>: basic_meta_associative_container_traits<Type> {};
361295

362296
} // namespace entt
363297

test/entt/meta/meta_container.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <list>
44
#include <map>
55
#include <set>
6+
#include <string>
7+
#include <string_view>
68
#include <utility>
79
#include <vector>
810
#include <gtest/gtest.h>
@@ -63,6 +65,26 @@ TEST(SequenceContainer, Iterator) {
6365
ASSERT_EQ((--first)->cast<int>(), 2);
6466
}
6567

68+
TEST(SequenceContainer, StdString) {
69+
std::string str{};
70+
auto any = entt::forward_as_meta(str);
71+
auto view = any.as_sequence_container();
72+
auto cview = std::as_const(any).as_sequence_container();
73+
74+
ASSERT_FALSE(view);
75+
ASSERT_FALSE(cview);
76+
}
77+
78+
TEST(SequenceContainer, StdStringView) {
79+
std::string_view str{};
80+
auto any = entt::forward_as_meta(str);
81+
auto view = any.as_sequence_container();
82+
auto cview = std::as_const(any).as_sequence_container();
83+
84+
ASSERT_FALSE(view);
85+
ASSERT_FALSE(cview);
86+
}
87+
6688
TEST(SequenceContainer, StdVector) {
6789
std::vector<int> vec{};
6890
auto any = entt::forward_as_meta(vec);

0 commit comments

Comments
 (0)