Skip to content

Commit 5572e29

Browse files
committed
CaptureKeys: Add support for std::map and std::unordered_map
1 parent 4afa2ff commit 5572e29

File tree

3 files changed

+305
-14
lines changed

3 files changed

+305
-14
lines changed

test/integration/capture_keys.toml

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
# This file contains tests for core key-capture features at the top, followed
2+
# by basic tests for each container type which supports key capture.
3+
4+
includes = ["map"]
5+
definitions = '''
6+
struct MapHolder {
7+
std::map<int, int> captureMyKeys;
8+
std::map<int, int> dontCaptureKeysHere;
9+
};
10+
11+
enum class MyEnum {
12+
One = 1,
13+
Two = 2,
14+
Three = 3,
15+
};
16+
'''
17+
[cases]
18+
[cases.int]
19+
oid_skip = "Requires TreeBuilderV2"
20+
param_types = ["const std::map<int, int>&"]
21+
setup = "return {{{1,2},{3,4}}};"
22+
config_suffix = '''
23+
[[codegen.capture_keys]]
24+
top_level = true
25+
'''
26+
expect_json_v2 = '''[{
27+
"name": "a0",
28+
"typePath": ["a0"],
29+
"members": [
30+
{
31+
"name": "[]",
32+
"typePath": ["a0","[]"],
33+
"data": 1,
34+
"members": [
35+
{"name": "key", "typePath": ["a0","[]","key"]},
36+
{"name": "value", "typePath": ["a0","[]","value"]}
37+
]
38+
},
39+
{
40+
"name": "[]",
41+
"typePath": ["a0","[]"],
42+
"data": 3,
43+
"members": [
44+
{"name": "key", "typePath": ["a0","[]","key"]},
45+
{"name": "value", "typePath": ["a0","[]","value"]}
46+
]
47+
}
48+
]
49+
}]'''
50+
51+
[cases.string]
52+
oid_skip = "Requires TreeBuilderV2"
53+
param_types = ["const std::map<std::string, int>&"]
54+
setup = '''return
55+
{{
56+
{"abc", 1},
57+
{"hohoho", 2}
58+
}};'''
59+
config_suffix = '''
60+
[[codegen.capture_keys]]
61+
top_level = true
62+
'''
63+
expect_json_v2 = '''[{
64+
"name": "a0",
65+
"typePath": ["a0"],
66+
"members": [
67+
{
68+
"name": "[]",
69+
"typePath": ["a0","[]"],
70+
"data": "abc",
71+
"members": [
72+
{"name": "key", "typePath": ["a0","[]","key"]},
73+
{"name": "value", "typePath": ["a0","[]","value"]}
74+
]
75+
},
76+
{
77+
"name": "[]",
78+
"typePath": ["a0","[]"],
79+
"data": "hohoho",
80+
"members": [
81+
{"name": "key", "typePath": ["a0","[]","key"]},
82+
{"name": "value", "typePath": ["a0","[]","value"]}
83+
]
84+
}
85+
]
86+
}]'''
87+
88+
[cases.enum]
89+
oid_skip = "Requires TreeBuilderV2"
90+
param_types = ["const std::map<MyEnum, int>&"]
91+
setup = "return {{{MyEnum::One,2},{MyEnum::Three,4}}};"
92+
config_suffix = '''
93+
[[codegen.capture_keys]]
94+
top_level = true
95+
'''
96+
expect_json_v2 = '''[{
97+
"name": "a0",
98+
"typePath": ["a0"],
99+
"members": [
100+
{
101+
"name": "[]",
102+
"typePath": ["a0","[]"],
103+
"data": 1,
104+
"members": [
105+
{"name": "key", "typePath": ["a0","[]","key"]},
106+
{"name": "value", "typePath": ["a0","[]","value"]}
107+
]
108+
},
109+
{
110+
"name": "[]",
111+
"typePath": ["a0","[]"],
112+
"data": 3,
113+
"members": [
114+
{"name": "key", "typePath": ["a0","[]","key"]},
115+
{"name": "value", "typePath": ["a0","[]","value"]}
116+
]
117+
}
118+
]
119+
}]'''
120+
121+
[cases.multi_level]
122+
oid_skip = "Requires TreeBuilderV2"
123+
param_types = ["const std::map<int, std::map<std::string, std::vector<int>>>&"]
124+
setup = '''return
125+
{{
126+
{123, {
127+
{"haha", {1,2}}
128+
}},
129+
{456, {
130+
{"uh oh", {3}},
131+
{"spaghettio", {4,5,6}}
132+
}}
133+
}};'''
134+
config_suffix = '''
135+
[[codegen.capture_keys]]
136+
top_level = true
137+
'''
138+
expect_json_v2 = '''[{
139+
"name": "a0",
140+
"typePath": ["a0"],
141+
"members": [
142+
{
143+
"name": "[]",
144+
"typePath": ["a0","[]"],
145+
"data": 123,
146+
"members": [
147+
{"name": "key", "typePath": ["a0","[]","key"]},
148+
{
149+
"name": "value",
150+
"typePath": ["a0","[]","value"],
151+
"members": [
152+
{
153+
"name": "[]",
154+
"typePath": ["a0","[]","value","[]"],
155+
"NOT":"data",
156+
"members": [
157+
{"name": "key", "typePath": ["a0","[]","value","[]","key"]},
158+
{"name": "value", "typePath": ["a0","[]","value","[]","value"]}
159+
]
160+
}
161+
]
162+
}
163+
]
164+
},
165+
{
166+
"name": "[]",
167+
"typePath": ["a0","[]"],
168+
"data": 456,
169+
"members": [
170+
{"name": "key", "typePath": ["a0","[]","key"]},
171+
{
172+
"name": "value",
173+
"typePath": ["a0","[]","value"],
174+
"members": [
175+
{
176+
"name": "[]",
177+
"typePath": ["a0","[]","value","[]"],
178+
"NOT":"data",
179+
"members": [
180+
{"name": "key", "typePath": ["a0","[]","value","[]","key"]},
181+
{"name": "value", "typePath": ["a0","[]","value","[]","value"]}
182+
]
183+
},
184+
{
185+
"name": "[]",
186+
"typePath": ["a0","[]","value","[]"],
187+
"NOT":"data",
188+
"members": [
189+
{"name": "key", "typePath": ["a0","[]","value","[]","key"]},
190+
{"name": "value", "typePath": ["a0","[]","value","[]","value"]}
191+
]
192+
}
193+
]
194+
}
195+
]
196+
}
197+
]
198+
}]'''
199+
200+
[cases.config]
201+
oid_skip = "Requires TreeBuilderV2"
202+
param_types = ["const MapHolder&"]
203+
setup = '''return {MapHolder{
204+
.captureMyKeys{ {1,2},{3,4} },
205+
.dontCaptureKeysHere{ {5,6} },
206+
}};'''
207+
config_suffix = '''
208+
[[codegen.capture_keys]]
209+
type = "MapHolder"
210+
members = ["captureMyKeys"]
211+
'''
212+
expect_json_v2 = '''[{
213+
"members": [
214+
{
215+
"name": "captureMyKeys",
216+
"typePath": ["a0","captureMyKeys"],
217+
"members": [
218+
{
219+
"name": "[]",
220+
"typePath": ["a0","captureMyKeys","[]"],
221+
"data": 1,
222+
"members": [
223+
{"name": "key", "typePath": ["a0","captureMyKeys","[]","key"]},
224+
{"name": "value", "typePath": ["a0","captureMyKeys","[]","value"]}
225+
]
226+
},
227+
{
228+
"name": "[]",
229+
"typePath": ["a0","captureMyKeys","[]"],
230+
"data": 3,
231+
"members": [
232+
{"name": "key", "typePath": ["a0","captureMyKeys","[]","key"]},
233+
{"name": "value", "typePath": ["a0","captureMyKeys","[]","value"]}
234+
]
235+
}
236+
]
237+
},
238+
{
239+
"name": "dontCaptureKeysHere",
240+
"typePath": ["a0","dontCaptureKeysHere"],
241+
"members": [
242+
{
243+
"name": "[]",
244+
"typePath": ["a0","dontCaptureKeysHere","[]"],
245+
"NOT":"data",
246+
"members": [
247+
{"name": "key", "typePath": ["a0","dontCaptureKeysHere","[]","key"]},
248+
{"name": "value", "typePath": ["a0","dontCaptureKeysHere","[]","value"]}
249+
]
250+
}
251+
]
252+
}
253+
]
254+
}]'''
255+
256+
[cases.std_unordered_map]
257+
oid_skip = "Requires TreeBuilderV2"
258+
param_types = ["const std::unordered_map<int, int>&"]
259+
setup = "return {{{1,2}}};"
260+
config_suffix = '''
261+
[[codegen.capture_keys]]
262+
top_level = true
263+
'''
264+
expect_json_v2 = '[{"members": [{"data": 1}]}]'

types/std_map_type.toml

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ auto tail = returnArg
7676
7777
for (const auto &entry: container) {
7878
tail = tail.delegate([&key = entry.first, &value = entry.second](auto ret) {
79-
auto next = ret.delegate([&key](typename TypeHandler<DB, T0>::type ret) {
79+
auto start = maybeCaptureKey<captureKeys, DB, T0>(key, ret);
80+
auto next = start.delegate([&key](typename TypeHandler<DB, T0>::type ret) {
8081
return OIInternal::getSizeType<DB>(key, ret);
8182
});
8283
return OIInternal::getSizeType<DB>(value, next);
@@ -92,9 +93,18 @@ func = "el.pointer = std::get<ParsedData::VarInt>(d.val).value;"
9293

9394
[[codegen.processor]]
9495
type = """
95-
types::st::List<DB, types::st::Pair<DB,
96-
typename TypeHandler<DB, T0>::type,
97-
typename TypeHandler<DB, T1>::type>>
96+
std::conditional_t<captureKeys,
97+
types::st::List<DB,
98+
types::st::Pair<DB,
99+
typename CaptureKeyHandler<DB, T0>::type,
100+
types::st::Pair<DB,
101+
typename TypeHandler<DB, T0>::type,
102+
typename TypeHandler<DB, T1>::type>>>,
103+
types::st::List<DB,
104+
types::st::Pair<DB,
105+
typename TypeHandler<DB, T0>::type,
106+
typename TypeHandler<DB, T1>::type>>
107+
>
98108
"""
99109
func = """
100110
#ifdef __GLIBCXX__
@@ -147,13 +157,16 @@ static constexpr std::array<inst::Field, 2> element_fields{
147157
make_field<DB, T0>("key"),
148158
make_field<DB, T1>("value"),
149159
};
160+
161+
static constexpr auto processors = maybeCaptureKeysProcessor<captureKeys, DB, T0>();
162+
150163
static constexpr inst::Field element{
151164
element_size,
152165
element_size - sizeof(T0) - sizeof(T1),
153166
"[]",
154167
std::array<std::string_view, 0>{},
155168
element_fields,
156-
std::array<inst::ProcessorInst, 0>{},
169+
processors,
157170
};
158171
159172
auto list = std::get<ParsedData::List>(d.val);

types/std_unordered_map_type.toml

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ void getSizeType(const %1%<K, T, H, KE, A> &container, size_t& returnArg)
3333
3434
for (auto const& it : container)
3535
{
36-
getSizeType(it.first, returnArg);
37-
getSizeType(it.second, returnArg);
36+
getSizeType(it.first, returnArg);
37+
getSizeType(it.second, returnArg);
3838
}
3939
}
4040
"""
@@ -81,9 +81,13 @@ auto tail = returnArg
8181
.write(container.bucket_count())
8282
.write(container.size());
8383
84-
for (const auto &it : container) {
85-
tail = tail.delegate([&it](auto ret) {
86-
return OIInternal::getSizeType<DB>(it, ret);
84+
for (const auto& kv : container) {
85+
tail = tail.delegate([&kv](auto ret) {
86+
auto start = maybeCaptureKey<captureKeys, DB, T0>(kv.first, ret);
87+
auto next = start.delegate([&kv](typename TypeHandler<DB, T0>::type ret) {
88+
return OIInternal::getSizeType<DB>(kv.first, ret);
89+
});
90+
return OIInternal::getSizeType<DB>(kv.second, next);
8791
});
8892
}
8993
@@ -108,9 +112,17 @@ el.container_stats.emplace(result::Element::ContainerStats {
108112

109113
[[codegen.processor]]
110114
type = """
111-
types::st::List<DB, types::st::Pair<DB,
112-
typename TypeHandler<DB, T0>::type,
113-
typename TypeHandler<DB, T1>::type>>
115+
std::conditional_t<captureKeys,
116+
types::st::List<DB,
117+
types::st::Pair<DB,
118+
typename CaptureKeyHandler<DB, T0>::type,
119+
types::st::Pair<DB,
120+
typename TypeHandler<DB, T0>::type,
121+
typename TypeHandler<DB, T1>::type>>>,
122+
types::st::List<DB, types::st::Pair<DB,
123+
typename TypeHandler<DB, T0>::type,
124+
typename TypeHandler<DB, T1>::type>>
125+
>
114126
"""
115127
func = """
116128
#ifdef __GLIBCXX__
@@ -150,13 +162,15 @@ static constexpr std::array<inst::Field, 2> element_fields{
150162
make_field<DB, T1>("value"),
151163
};
152164
165+
static constexpr auto processors = maybeCaptureKeysProcessor<captureKeys, DB, T0>();
166+
153167
static constexpr auto element = inst::Field{
154168
element_size,
155169
element_size - sizeof(T0) - sizeof(T1),
156170
"[]",
157171
std::array<std::string_view, 0>{},
158172
element_fields,
159-
std::array<inst::ProcessorInst, 0>{},
173+
processors,
160174
};
161175
162176
for (size_t i = 0; i < list.length; i++)

0 commit comments

Comments
 (0)