-
-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
328 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<ValueHolder,ValueHolder> &&values) { | ||
for (auto &value : values) { | ||
this->values.insert(std::move(value)); | ||
} | ||
} | ||
|
||
|
||
ValueHolder Dict::copy() const { | ||
// TODO | ||
// return {std::make_shared<Dict>(*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<const Set *>(&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<const OrderedSet *>(&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<const Dict *>(&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<nyan_op> &Dict::allowed_operations(const Type &with_type) const { | ||
|
||
if (not with_type.is_container()) { | ||
return no_nyan_ops; | ||
} | ||
|
||
const static std::unordered_set<nyan_op> set_ops{ | ||
nyan_op::SUBTRACT_ASSIGN, | ||
nyan_op::INTERSECT_ASSIGN, | ||
}; | ||
|
||
const static std::unordered_set<nyan_op> 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// Copyright 2020-2020 the nyan authors, LGPLv3+. See copying.md for legal info. | ||
#pragma once | ||
|
||
|
||
#include <unordered_map> | ||
|
||
#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<typename iter_type, typename elem_type> | ||
class DictIterator : public ContainerIterBase<elem_type> { | ||
public: | ||
using this_type = DictIterator<iter_type, elem_type>; | ||
using base_type = ContainerIterBase<elem_type>; | ||
|
||
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<const this_type &>(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<ValueHolder,ValueHolder>; | ||
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<ValueHolder,ValueHolder> &&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<nyan_op> &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<const Dict &>(other); | ||
|
||
return values == other_val.values; | ||
} | ||
|
||
/** | ||
* Dict value storage (this is an unordered map). | ||
*/ | ||
value_storage values; | ||
}; | ||
|
||
} // namespace nyan |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters