forked from deepsig/libsigmf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvariadic_data_class.h
265 lines (231 loc) · 8.67 KB
/
variadic_data_class.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
* Copyright 2019, 2021, 2022 DeepSig Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBSIGMF_VARIADICDATACLASS_H
#define LIBSIGMF_VARIADICDATACLASS_H
#include "flatbuffers_json_visitor.h"
#include <tuple>
#include <string>
#include <typeinfo>
#include <cxxabi.h>
namespace sigmf {
template<class T1, class T2>
struct SameType {
static const bool value = false;
};
template<class T>
struct SameType<T, T> {
static const bool value = true;
};
template<size_t T1, size_t T2>
struct ReachedEnd {
static const bool value = false;
};
template<size_t T>
struct ReachedEnd<T, T> {
static const bool value = true;
};
template<typename... SigMFNamespaces>
class VariadicDataClass {
public:
/**
* Access a reference to the (first) element of the tuple that is of type T
* @tparam T
* @return
*/
template<typename T>
T &access() {
return MatchingField<0, T, sigmftypes, SigMFNamespaceOfType<0, T>::value>::get(sigmf_namespaces);
}
/**
* Overload of access that accepts an object of type T rather than type T as template param
* @tparam T
* @return
*/
template<typename T>
T &access(T) {
return access<T>();
}
template<typename T>
T &operator[](T) {
return access<T>();
}
/**
* return a json object representing the data class with namespaces to match sigmf-spec
* @return
*/
json to_json() const {
constexpr auto tuple_size = std::tuple_size<sigmftypes>::value;
constexpr auto at_the_end = ReachedEnd<0, tuple_size>::value;
json r = TupleIterator<0, sigmftypes, at_the_end>::to_json(sigmf_namespaces);
return r;
}
/**
* fill in data elements from a json object
* @return
*/
void from_json(json j) {
constexpr auto tuple_size = std::tuple_size<sigmftypes>::value;
constexpr auto at_the_end = ReachedEnd<0, tuple_size>::value;
TupleIterator<0, sigmftypes, at_the_end>::from_json(sigmf_namespaces, j);
}
private:
typedef std::tuple<SigMFNamespaces...> sigmftypes;
sigmftypes sigmf_namespaces;
/**
* Convenience class for iterating over every element in Tuple at compile time.
* @tparam Index
* @tparam Size
* @tparam Tuple
* @tparam End
*/
template<size_t Index, class Tuple, bool End = false>
struct TupleIterator {
/**
* Stringify the object's namespace (using cxxabi from compiler) so we can use the literal
* c++ namespace as a prefix in the sigmf record (the sigmf namespace); this function also
* removes the outer `sigmf::` class form the literal namespace
* @tparam T
* @param ttype
* @return
*/
template<typename T>
static std::string get_namespace(const T *ttype) {
// TODO: can we do this once at compile-time/ctor, store result, and just look it up?
std::string mangled_name = typeid(ttype).name();
size_t size_of_demangled_name = 1024;
char *demangled_name = static_cast<char *>(malloc(size_of_demangled_name));
int status;
demangled_name = abi::__cxa_demangle(mangled_name.c_str(), demangled_name, &size_of_demangled_name,
&status);
auto demangled_string = std::string(demangled_name);
free(static_cast<void *>(demangled_name));
auto ns_start = demangled_string.find("::");
auto ns_end = demangled_string.rfind("::");
auto ns_part = std::string("");
if (ns_start != std::string::npos && ns_end != std::string::npos) {
ns_start += 2;
ns_part = demangled_string.substr(ns_start, ns_end - ns_start + 1);
}
return ns_part;
}
/**
* Iterate through the types in tuple (namespaces) creating a json object with field
* names prefixed by the object's owning namespace
* @param tp
* @return
*/
static json to_json(const Tuple &tp) {
typename std::tuple_element<Index, sigmftypes>::type::TableType *ttype=nullptr;
auto &flatbuffers_type = std::get<Index>(tp);
auto reflection_table = ttype->MiniReflectTypeTable();
std::string namespace_part = get_namespace(ttype);
flatbuffers::FlatBufferBuilder fbb;
auto loc = ttype->Pack(fbb, &flatbuffers_type);
fbb.Finish(loc);
auto bfrptr = fbb.GetBufferPointer();
auto rtptr = flatbuffers::GetRoot<uint8_t>(bfrptr);
json asjson = FlatBufferToJson(rtptr, reflection_table, namespace_part);
constexpr auto next = Index + 1;
constexpr auto size = std::tuple_size<sigmftypes>::value;
json existing_vals = TupleIterator<next, Tuple, ReachedEnd<next, size>::value>::to_json(tp);
for (auto &val : asjson.items()) {
existing_vals[val.key()] = val.value();
}
return existing_vals;
}
/**
* From json with namespaces ("core:fieldname", core is the namespace) fill in the corresponding fields
* of our tuple'd objects
* @param tp
* @param j
*/
static void from_json(Tuple &tp, const json j) {
typename std::tuple_element<Index, sigmftypes>::type::TableType *ttype=nullptr;
auto &flatbuffers_type = std::get<Index>(tp);
auto reflection_table = ttype->MiniReflectTypeTable();
std::string namespace_part = get_namespace(ttype);
FromSigMFVisitor dumb_ripoff_visitor(namespace_part, j);
IterateType(reflection_table, &dumb_ripoff_visitor, j);
dumb_ripoff_visitor.fbb.Finish(flatbuffers::Offset<void>(dumb_ripoff_visitor._stop));
auto *annoptr = flatbuffers::GetRoot<typename std::tuple_element<Index, sigmftypes>::type::TableType>(
dumb_ripoff_visitor.fbb.GetBufferPointer());
annoptr->UnPackTo(&flatbuffers_type);
constexpr auto next = Index + 1;
constexpr auto size = std::tuple_size<sigmftypes>::value;
TupleIterator<next, Tuple, ReachedEnd<next, size>::value>::from_json(tp, j);
}
};
/**
* Template specialization for reaching the end of compile-time loop over Tuple
* @tparam Index
* @tparam Size
* @tparam Tuple
*/
template<size_t Index, class Tuple>
struct TupleIterator<Index, Tuple, true> {
static json to_json(const Tuple &tp) {
json r;
return r;
}
static void from_json(const Tuple &tp, json j) {
}
};
/**
* Convenience class for determining if the Nth element of sigmftypes is of type T. Will have bool ::value
* @tparam N
* @tparam T
*/
template<int N, typename T>
struct SigMFNamespaceOfType : SameType<T, typename std::tuple_element<N, sigmftypes>::type> {
};
/**
* MatchingField::get to compile-time loop over sigmf_namespaces until the current index N is of type T
* at which point it calls the end-condition (because of the template specialization)
* @tparam N
* @tparam T
* @tparam Tuple
* @tparam Match
*/
template<int N, class T, class Tuple, bool Match = false>
struct MatchingField {
static T &get(const Tuple &tp) {
return MatchingField<N + 1, T, Tuple, SigMFNamespaceOfType<N + 1, T>::value>::get(tp);
}
};
/**
* MatchingField::get template-specializes the loop condition (true) to match when the object in Tuple at
* index N is of type T.
* @tparam N
* @tparam T
* @tparam Tuple
*/
template<int N, class T, class Tuple>
struct MatchingField<N, T, Tuple, true> {
static T &get(const Tuple &tp) {
return const_cast<T &>(std::get<N>(tp));
}
};
};
template<typename... SigMFNamespaces>
void to_json(json &j, const VariadicDataClass<SigMFNamespaces...> t) {
j = t.to_json();
}
template<typename... SigMFNamespaces>
void from_json(json &j, const VariadicDataClass<SigMFNamespaces...> t) {
t.from_json(j);
}
} // namespace sigmf
#endif