Add a range and initializer list constructor to Struct

This commit is contained in:
Simon Hausmann 2021-03-18 15:27:55 +01:00
parent 09b7b92dbe
commit 8916b7e13e
2 changed files with 67 additions and 35 deletions

View file

@ -52,33 +52,26 @@ public:
}
~Struct() { cbindgen_private::sixtyfps_interpreter_struct_destructor(&inner); }
#if 0
Struct(std::initializer_list<std::pair<std::string_view, Value>>) template<
typename InputIterator,
typename = std::enable_if<
std::is_same(decltype(*std::declval<InputIterator>())),
std::pair<std::string_view, Value>>> // InputIterator produces
// std::pair<std::string, Value>
Struct(InputIterator begin,
InputIterator end); // Creates
// Value::Struct
#endif
inline Struct(std::initializer_list<std::pair<std::string_view, Value>> args);
template<typename InputIterator>
inline Struct(InputIterator begin, InputIterator end);
// FIXME: this probably miss a lot of iterator api
struct iterator
{
using value_type = std::pair<std::string_view, const Value &>;
private:
cbindgen_private::StructIteratorOpaque inner;
const Value *v = nullptr;
std::string_view k;
friend Struct;
explicit iterator(cbindgen_private::StructIteratorOpaque inner) : inner(inner) {
next();
}
explicit iterator(cbindgen_private::StructIteratorOpaque inner) : inner(inner) { next(); }
// construct a end iterator
iterator() = default;
void next() {
void next()
{
auto next = cbindgen_private::sixtyfps_interpreter_struct_iterator_next(&inner);
v = reinterpret_cast<const Value *>(next.v);
k = std::string_view(reinterpret_cast<char *>(next.k.ptr), next.k.len);
@ -86,8 +79,10 @@ public:
cbindgen_private::sixtyfps_interpreter_struct_iterator_destructor(&inner);
}
}
public:
~iterator() {
~iterator()
{
if (v) {
cbindgen_private::sixtyfps_interpreter_struct_iterator_destructor(&inner);
}
@ -97,28 +92,22 @@ public:
iterator &operator=(const iterator &) = delete;
iterator(iterator &&) = default;
iterator &operator=(iterator &&) = default;
iterator &operator++() {
iterator &operator++()
{
if (v)
next();
return *this;
}
value_type operator*() const {
return {k, *v};
}
friend bool operator==(const iterator&a, const iterator&b) {
return a.v == b.v;
}
friend bool operator!=(const iterator&a, const iterator&b) {
return a.v != b.v;
}
value_type operator*() const { return { k, *v }; }
friend bool operator==(const iterator &a, const iterator &b) { return a.v == b.v; }
friend bool operator!=(const iterator &a, const iterator &b) { return a.v != b.v; }
};
iterator begin() const {
iterator begin() const
{
return iterator(cbindgen_private::sixtyfps_interpreter_struct_make_iter(&inner));
}
iterator end() const {
return iterator();
}
iterator end() const { return iterator(); }
inline std::optional<Value> get_field(std::string_view name) const;
inline void set_field(std::string_view name, const Value &value);
@ -135,6 +124,15 @@ private:
friend class Value;
};
template<typename InputIterator>
inline Struct::Struct(InputIterator it, InputIterator end) : Struct()
{
for (; it != end; ++it) {
auto [key, value] = *it;
set_field(key, value);
}
}
class Value
{
public:
@ -317,6 +315,11 @@ inline Value::Value(const std::shared_ptr<sixtyfps::Model<Value>> &model)
cbindgen_private::sixtyfps_interpreter_value_new_model(wrap, &inner);
}
inline Struct::Struct(std::initializer_list<std::pair<std::string_view, Value>> args)
: Struct(args.begin(), args.end())
{
}
inline std::optional<Value> Struct::get_field(std::string_view name) const
{
cbindgen_private::Slice<uint8_t> name_view {

View file

@ -198,16 +198,45 @@ SCENARIO("Struct API")
int count = 0;
for (auto [k, value] : struc) {
REQUIRE(count == 0);
count ++;
count++;
REQUIRE(k == "field_a");
REQUIRE(value.to_string().value() == "Hallo");
}
struc.set_field("field_b", Value(sixtyfps::SharedString("World")));
std::map<std::string, sixtyfps::SharedString> map;
for (auto [k, value] : struc) map[std::string(k)] = *value.to_string();
REQUIRE(map == std::map<std::string, sixtyfps::SharedString>{ {"field_a", sixtyfps::SharedString("Hallo") }, {"field_b", sixtyfps::SharedString("World") } });
for (auto [k, value] : struc)
map[std::string(k)] = *value.to_string();
REQUIRE(map
== std::map<std::string, sixtyfps::SharedString> {
{ "field_a", sixtyfps::SharedString("Hallo") },
{ "field_b", sixtyfps::SharedString("World") } });
}
SCENARIO("Struct Iterator Constructor")
{
using namespace sixtyfps::interpreter;
std::vector<std::pair<std::string_view, Value>> values = { { "field_a", Value(true) },
{ "field_b", Value(42.0) } };
Struct struc(values.begin(), values.end());
REQUIRE(!struc.get_field("foo").has_value());
REQUIRE(struc.get_field("field_a").has_value());
REQUIRE(struc.get_field("field_a").value().to_bool().value());
REQUIRE(struc.get_field("field_b").value().to_number().value() == 42.0);
}
SCENARIO("Struct Initializer List Constructor")
{
using namespace sixtyfps::interpreter;
Struct struc({ { "field_a", Value(true) }, { "field_b", Value(42.0) } });
REQUIRE(!struc.get_field("foo").has_value());
REQUIRE(struc.get_field("field_a").has_value());
REQUIRE(struc.get_field("field_a").value().to_bool().value());
REQUIRE(struc.get_field("field_b").value().to_number().value() == 42.0);
}