From 32df34b649b6557316e619eb97f1db2adf8419a1 Mon Sep 17 00:00:00 2001 From: heinezen Date: Tue, 27 Oct 2020 02:34:17 +0100 Subject: [PATCH] nyan: Dict data type. --- nyan/CMakeLists.txt | 1 + nyan/value/dict.cpp | 199 +++++++++++++++++++++++++++++++++++++++++ nyan/value/dict.h | 123 +++++++++++++++++++++++++ nyan/value/set.h | 3 - nyan/value/set_types.h | 4 +- nyan/value/value.cpp | 3 + 6 files changed, 328 insertions(+), 5 deletions(-) create mode 100644 nyan/value/dict.cpp create mode 100644 nyan/value/dict.h diff --git a/nyan/CMakeLists.txt b/nyan/CMakeLists.txt index 870f1bf..5a244f1 100644 --- a/nyan/CMakeLists.txt +++ b/nyan/CMakeLists.txt @@ -68,6 +68,7 @@ add_library(nyan SHARED value_token.cpp value/boolean.cpp value/container.cpp + value/dict.cpp value/file.cpp value/number.cpp value/object.cpp diff --git a/nyan/value/dict.cpp b/nyan/value/dict.cpp new file mode 100644 index 0000000..23b3192 --- /dev/null +++ b/nyan/value/dict.cpp @@ -0,0 +1,199 @@ +// Copyright 2020-2020 the nyan authors, LGPLv3+. See copying.md for legal info. + +#include "dict.h" + +#include "orderedset.h" +#include "set.h" +#include "../error.h" +#include "../util.h" + + +namespace nyan { + +Dict::Dict() = default; + +Dict::Dict(std::unordered_map &&values) { + for (auto &value : values) { + this->values.insert(std::move(value)); + } +} + + +ValueHolder Dict::copy() const { + // TODO + // return {std::make_shared(*this)}; + return ValueHolder(); +} + + +std::string Dict::str() const { + // same as repr(), except we use str(). + + std::ostringstream builder; + builder << "{"; + builder << util::strjoin( + ", ", this->values, + [] (const auto &val) { + return val.first->str() + ": " + val.second->str(); + } + ); + builder << "}"; + + return builder.str(); +} + + +std::string Dict::repr() const { + // same as str(), except we use repr(). + + std::ostringstream builder; + builder << "{"; + builder << util::strjoin( + ", ", this->values, + [] (const auto &val) { + return val.first->repr() + ": " + val.second->repr(); + } + ); + builder << "}"; + + return builder.str(); +} + + +const BasicType &Dict::get_type() const { + constexpr static BasicType type{ + primitive_t::CONTAINER, + container_t::DICT, + }; + + return type; +} + +void Dict::apply_value(const Value &value, nyan_op operation) { + auto dict_applier = [](auto &member_value, auto operand, nyan_op operation) { + switch (operation) { + case nyan_op::ASSIGN: + member_value.clear(); + // fall through + + // TODO + case nyan_op::UNION_ASSIGN: + case nyan_op::ADD_ASSIGN: { + for (auto &val : operand) { + member_value.insert(val); + } + break; + } + + case nyan_op::INTERSECT_ASSIGN: + // TODO + break; + + default: + throw InternalError{"unknown dict value application"}; + } + }; + + auto set_applier = [](auto &member_value, auto operand, nyan_op operation) { + switch (operation) { + case nyan_op::SUBTRACT_ASSIGN: { + for (auto &val : operand) { + member_value.erase(val); + } + break; + } + + case nyan_op::INTERSECT_ASSIGN: + // TODO + break; + + default: + throw InternalError{"unknown dict value application"}; + } + }; + + + if (typeid(Set&) == typeid(value)) { + const Set *change = dynamic_cast(&value); + + if (unlikely(change == nullptr)) { + using namespace std::string_literals; + throw InternalError{ + "set value application was not a container, it was: "s + + util::demangle(typeid(value).name()) + + " and couldn't cast to " + + util::demangle(typeid(change).name())}; + } + + set_applier(this->values, change->get(), operation); + + } + else if (typeid(OrderedSet&) == typeid(value)) { + const OrderedSet *change = dynamic_cast(&value); + + if (unlikely(change == nullptr)) { + using namespace std::string_literals; + throw InternalError{ + "set value application was not a container, it was: "s + + util::demangle(typeid(value).name()) + + " and couldn't cast to " + + util::demangle(typeid(change).name())}; + } + + set_applier(this->values, change->get(), operation); + + } + else if (typeid(Dict&) == typeid(value)) { + const Dict *change = dynamic_cast(&value); + + if (unlikely(change == nullptr)) { + using namespace std::string_literals; + throw InternalError{ + "set value application was not a container, it was: "s + + util::demangle(typeid(value).name()) + + " and couldn't cast to " + + util::demangle(typeid(change).name())}; + } + + dict_applier(this->values, change->get(), operation); + } + else { + throw InternalError("expected Container instance for operation, but got" + + std::string(typeid(value).name())); + } + + +} + +const std::unordered_set &Dict::allowed_operations(const Type &with_type) const { + + if (not with_type.is_container()) { + return no_nyan_ops; + } + + const static std::unordered_set set_ops{ + nyan_op::SUBTRACT_ASSIGN, + nyan_op::INTERSECT_ASSIGN, + }; + + const static std::unordered_set dict_ops{ + nyan_op::ASSIGN, + nyan_op::ADD_ASSIGN, + nyan_op::UNION_ASSIGN, + nyan_op::INTERSECT_ASSIGN, + }; + + switch (with_type.get_container_type()) { + case container_t::SET: + case container_t::ORDEREDSET: + return set_ops; + + case container_t::DICT: + return dict_ops; + + default: + return no_nyan_ops; + } +} + +} // namespace nyan diff --git a/nyan/value/dict.h b/nyan/value/dict.h new file mode 100644 index 0000000..a4c1b20 --- /dev/null +++ b/nyan/value/dict.h @@ -0,0 +1,123 @@ +// Copyright 2020-2020 the nyan authors, LGPLv3+. See copying.md for legal info. +#pragma once + + +#include + +#include "../api_error.h" +#include "../compiler.h" +#include "../util.h" +#include "container.h" +#include "value.h" + + +namespace nyan { + +/** + * Container iterator for the Set. + * + * Used for walking over the contained values, + * i.e. it unpacks the ValueHolders! + * + */ +template +class DictIterator : public ContainerIterBase { +public: + using this_type = DictIterator; + using base_type = ContainerIterBase; + + explicit DictIterator(iter_type &&iter) + : + iterator{std::move(iter)} {} + + /** + * Advance the iterator to the next element in the dict. + */ + base_type &operator ++() override { + ++this->iterator; + return *this; + } + + /** + * Get the element the iterator is currently pointing to. + */ + elem_type &operator *() const override { + // unpack the ValueHolder! + return *(*this->iterator); + } + +protected: + /** + * compare two iterators + */ + bool equals(const base_type &other) const override { + auto other_me = dynamic_cast(other); + return (this->iterator == other_me.iterator); + } + + /** + * The wrapped std::iterator, from the Set std::unordered_set. + */ + iter_type iterator; +}; + + +/** + * Nyan value to store a dict/map/assocated array of things. + * + * T is the underlying storage type to store the Values. + */ +class Dict : Value { +public: + using value_storage = std::unordered_map; + using key_type = typename value_storage::key_type; + using element_type = typename value_storage::value_type; + using value_const_iterator = typename value_storage::const_iterator; + + Dict(); + Dict(std::unordered_map &&values); + + + size_t hash() const override { + throw APIError{"Dicts are not hashable."}; + } + + + size_t size() const { + return this->values.size(); + } + + + void clear() { + this->values.clear(); + } + + + const value_storage &get() const { + return this->values; + } + + ValueHolder copy() const override; + std::string str() const override; + std::string repr() const override; + + const std::unordered_set &allowed_operations(const Type &with_type) const override; + const BasicType &get_type() const override; + +protected: + void apply_value(const Value &value, nyan_op operation) override; + + + bool equals(const Value &other) const override { + auto &other_val = dynamic_cast(other); + + return values == other_val.values; + } + + /** + * Dict value storage (this is an unordered map). + */ + value_storage values; +}; + +} // namespace nyan diff --git a/nyan/value/set.h b/nyan/value/set.h index dc2daec..d98c90e 100644 --- a/nyan/value/set.h +++ b/nyan/value/set.h @@ -11,9 +11,6 @@ namespace nyan { -/** datatype used for unordered set storage */ -using set_t = std::unordered_set; - /** * Nyan value to store a unordered set of things. diff --git a/nyan/value/set_types.h b/nyan/value/set_types.h index cd12262..7a42c4a 100644 --- a/nyan/value/set_types.h +++ b/nyan/value/set_types.h @@ -1,4 +1,4 @@ -// Copyright 2019-2019 the nyan authors, LGPLv3+. See copying.md for legal info. +// Copyright 2019-2020 the nyan authors, LGPLv3+. See copying.md for legal info. #pragma once #include @@ -9,7 +9,7 @@ namespace nyan { -/** datatype used for ordered set storage */ +/** datatype used for (unordered) set storage */ using set_t = std::unordered_set; diff --git a/nyan/value/value.cpp b/nyan/value/value.cpp index 3c8d6ac..bd596fc 100644 --- a/nyan/value/value.cpp +++ b/nyan/value/value.cpp @@ -136,6 +136,9 @@ ValueHolder Value::from_ast(const Type &target_type, case container_t::ORDEREDSET: return {std::make_shared(std::move(values))}; + case container_t::DICT: + // TODO + default: throw InternalError{"value creation for unhandled container type"}; }