Skip to content

Commit cfd9d73

Browse files
Merge pull request #10 from tukl-msd/feat/CollapsingVector
implemented collapsing vector
2 parents 00c2710 + 95a0f5f commit cfd9d73

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#ifndef DRAMUTILS_UTIL_COLLAPSINGVECTOR
2+
#define DRAMUTILS_UTIL_COLLAPSINGVECTOR
3+
4+
#include "json.h"
5+
6+
#include <vector>
7+
8+
9+
namespace DRAMUtils::util
10+
{
11+
12+
template <typename T, typename Alloc = std::allocator<T>>
13+
class CollapsingVector : public std::vector<T, Alloc>
14+
{
15+
public:
16+
enum class Type
17+
{
18+
SINGLE,
19+
ARRAY
20+
};
21+
22+
using std::vector<T>::vector;
23+
24+
// Forward constructor
25+
// Single element represented as the element type in serialization
26+
template <typename... Ts, typename = decltype(std::vector<T>{std::declval<Ts>()...})>
27+
CollapsingVector(Ts&&... ts) : std::vector<T> {std::forward<Ts>(ts)...} {
28+
if (this->size() == 1) {
29+
set_type(Type::SINGLE);
30+
} else {
31+
set_type(Type::ARRAY);
32+
}
33+
}
34+
35+
// Forward constructor with type
36+
// This constructor allows a single element to be represented as an array in serialization
37+
template <typename... Ts, typename = decltype(std::vector<T>{std::declval<Ts>()...})>
38+
explicit CollapsingVector(Type type, Ts&&... ts) : std::vector<T> {std::forward<Ts>(ts)...} {
39+
// Overwrite type for multiple elements
40+
if (this->size() > 1) {
41+
set_type(Type::ARRAY);
42+
} else {
43+
set_type(type);
44+
}
45+
}
46+
47+
private:
48+
void set_type(Type type)
49+
{
50+
this->type = type;
51+
}
52+
53+
public:
54+
Type get_type() const
55+
{
56+
return type;
57+
}
58+
59+
void from_json(const json_t& j)
60+
{
61+
this->clear();
62+
if (!j.is_array()) {
63+
// Single element
64+
this->emplace_back(j.get<T>());
65+
set_type(Type::SINGLE);
66+
} else {
67+
// Array
68+
for (const auto& element : j) {
69+
this->emplace_back(element.get<T>());
70+
}
71+
set_type(Type::ARRAY);
72+
}
73+
}
74+
75+
void to_json(json_t& j) const
76+
{
77+
if (get_type() == Type::SINGLE && this->size() == 1) {
78+
// Single element
79+
j = this->operator[](0);
80+
} else {
81+
// Array
82+
j = json_t::array();
83+
for (const auto& element : *this) {
84+
j.emplace_back(element);
85+
}
86+
}
87+
}
88+
89+
private:
90+
Type type = Type::ARRAY;
91+
};
92+
93+
} // namespace DRAMUtils::util
94+
95+
#endif /* DRAMUTILS_UTIL_COLLAPSINGVECTOR */

include/DRAMUtils/DRAMUtils/util/json_utils.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@
4141
#include "json.h"
4242

4343
#include "id_variant.h"
44+
#include "collapsingvector.h"
4445

4546
#include <optional>
4647
#include <variant>
4748
#include <string>
49+
#include <string_view>
4850

4951

5052

@@ -71,6 +73,32 @@ void variant_to_json(json_t& j, const std::variant<Ts...> &data)
7173
}
7274

7375

76+
template <typename T>
77+
void collapsingvector_to_json(json_t& j, const CollapsingVector<T>& data, std::optional<std::string_view> key)
78+
{
79+
if (key) {
80+
data.to_json(j[*key]);
81+
} else {
82+
data.to_json(j);
83+
}
84+
}
85+
86+
template <typename T>
87+
void collapsing_from_json(const json_t& j, CollapsingVector<T>& data, std::optional<std::string_view> key)
88+
{
89+
if (key) {
90+
const auto it = j.find(*key);
91+
if (it == j.end()) {
92+
// Key not in json
93+
throw std::runtime_error("Key " + std::string(*key) + " not found in json");
94+
}
95+
data.from_json(*it);
96+
} else {
97+
data.from_json(j);
98+
}
99+
}
100+
101+
74102
template <typename T>
75103
void optional_to_json(json_t& j, const std::optional<T>& data, std::optional<std::string_view> key)
76104
{
@@ -149,13 +177,20 @@ constexpr bool is_id_variant = false;
149177
template <char const * id_field_name, typename Seq>
150178
constexpr bool is_id_variant<IdVariant<id_field_name, Seq>> = true;
151179

180+
template <typename>
181+
constexpr bool is_collapsing_vector = false;
182+
template <typename T>
183+
constexpr bool is_collapsing_vector<CollapsingVector<T>> = true;
184+
152185

153186
template <typename T> void extended_to_json(const char* key, json_t& j, const T& value)
154187
{
155188
if constexpr (is_optional<T>)
156189
optional_to_json(j, value, key);
157190
else if constexpr (is_id_variant<T>)
158191
id_variant_to_json(j, value, key);
192+
else if constexpr (is_collapsing_vector<T>)
193+
collapsingvector_to_json(j, value, key);
159194
else if constexpr (is_variant<T>)
160195
variant_to_json(j, value);
161196
else
@@ -168,6 +203,8 @@ template <typename T> void extended_from_json(const char* key, const json_t& j,
168203
optional_from_json(j, value, key);
169204
else if constexpr (is_id_variant<T>)
170205
id_variant_from_json(j, value, key);
206+
else if constexpr (is_collapsing_vector<T>)
207+
collapsing_from_json(j, value, key);
171208
else if constexpr (is_variant<T>)
172209
variant_from_json<T>(j, value);
173210
else
@@ -220,6 +257,20 @@ template <typename... Ts> struct adl_serializer<std::variant<Ts...>>
220257
};
221258

222259

260+
template <typename T> struct adl_serializer<DRAMUtils::util::CollapsingVector<T>>
261+
{
262+
static void to_json(json_t& j, const DRAMUtils::util::CollapsingVector<T>& data)
263+
{
264+
DRAMUtils::util::collapsingvector_to_json<T>(j, data, std::nullopt);
265+
}
266+
267+
static void from_json(const json_t& j, DRAMUtils::util::CollapsingVector<T>& data)
268+
{
269+
(DRAMUtils::util::collapsing_from_json<T>(j, data, std::nullopt));
270+
}
271+
};
272+
273+
223274
template <const char * id_field_name, typename Seq> struct adl_serializer<DRAMUtils::util::IdVariant<id_field_name, Seq>>
224275
{
225276
static void to_json(json_t& j, const DRAMUtils::util::IdVariant<id_field_name, Seq>& data)

0 commit comments

Comments
 (0)