Skip to content

Commit

Permalink
Add get_optional method to maps.
Browse files Browse the repository at this point in the history
This returns an optional either containing the map's element for the
given key if that entry exists, or an unset optional if it does not.

Closes #1608.

(Note that we cannot use the same, improved implementation for the
existing `get()` method because that needs to return a reference.)
  • Loading branch information
rsmmr committed Jun 6, 2024
1 parent 83bc845 commit 09ee9b5
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 1 deletion.
5 changes: 5 additions & 0 deletions doc/autogen/types/map.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
exist, returns the default value if provided; otherwise throws a
runtime error.

.. spicy:method:: map::get_optional map get_optional False optional<type~of~element> (key: <any>)
Returns an optional either containing the map's element for the given
key if that entry exists, or an unset optional if it does not.

.. rubric:: Operators

.. spicy:operator:: map::Begin <iterator> begin(<container>)
Expand Down
13 changes: 13 additions & 0 deletions hilti/runtime/include/types/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,19 @@ class Map : protected std::map<K, V> {
}
}

/**
* Attempts to get the value for a key.
*
* @param k key to retrieve
* @return the value, or an unset optional if the key is not set in the map
*/
std::optional<V> get_optional(const K& k) const& {
if ( auto it = this->find(k); it != static_cast<const M&>(*this).end() )
return it->second;
else
return {};
}

/** Access an element by key
*
* @param k key of the element
Expand Down
1 change: 1 addition & 0 deletions hilti/toolchain/include/ast/forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ class IndexConst;
class IndexNonConst;
class IndexAssign;
class Get;
class GetOptional;
class Clear;

} // namespace map
Expand Down
1 change: 1 addition & 0 deletions hilti/toolchain/include/ast/node-tag.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ constexpr Tag IndexConst = 1906;
constexpr Tag IndexNonConst = 1907;
constexpr Tag Size = 1908;
constexpr Tag Unequal = 1909;
constexpr Tag GetOptional = 1910;

namespace iterator {
constexpr Tag Deref = 2000;
Expand Down
1 change: 1 addition & 0 deletions hilti/toolchain/include/ast/operators/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ HILTI_NODE_OPERATOR(map, IndexConst)
HILTI_NODE_OPERATOR(map, IndexNonConst)
HILTI_NODE_OPERATOR(map, IndexAssign)
HILTI_NODE_OPERATOR(map, Get)
HILTI_NODE_OPERATOR(map, GetOptional)
HILTI_NODE_OPERATOR(map, Clear)

} // namespace hilti::operator_
1 change: 1 addition & 0 deletions hilti/toolchain/include/ast/visitor-dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ class Dispatcher {
virtual void operator()(hilti::operator_::map::IndexNonConst* n) {}
virtual void operator()(hilti::operator_::map::IndexAssign* n) {}
virtual void operator()(hilti::operator_::map::Get* n) {}
virtual void operator()(hilti::operator_::map::GetOptional* n) {}
virtual void operator()(hilti::operator_::map::Clear* n) {}
virtual void operator()(hilti::operator_::network::Equal* n) {}
virtual void operator()(hilti::operator_::network::Unequal* n) {}
Expand Down
30 changes: 30 additions & 0 deletions hilti/toolchain/src/ast/operators/map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,36 @@ the default value if provided; otherwise throws a runtime error.
};
HILTI_OPERATOR_IMPLEMENTATION(Get);

class GetOptional : public BuiltInMemberCall {
public:
Signature signature(Builder* builder) const final {
return Signature{
.kind = Kind::MemberCall,
.self = {parameter::Kind::In, builder->typeMap(type::Wildcard())},
.member = "get_optional",
.param0 =
{
.name = "key",
.type = {parameter::Kind::In, builder->typeAny()},
},
.result_doc = "optional<type of element>",
.ns = "map",
.doc = R"(
Returns an optional either containing the map's element for the given key if
that entry exists, or an unset optional if it does not.
)",
};
}

QualifiedType* result(Builder* builder, const Expressions& operands, const Meta& meta) const final {
return builder->qualifiedType(builder->typeOptional(operands[0]->type()->type()->as<type::Map>()->valueType()),
Constness::Const);
}

HILTI_OPERATOR(hilti, map::GetOptional);
};
HILTI_OPERATOR_IMPLEMENTATION(GetOptional);

class Clear : public BuiltInMemberCall {
public:
Signature signature(Builder* builder) const final {
Expand Down
7 changes: 6 additions & 1 deletion hilti/toolchain/src/compiler/codegen/operators.cc
Original file line number Diff line number Diff line change
Expand Up @@ -423,12 +423,17 @@ struct Visitor : hilti::visitor::PreOrder {

if ( auto default_ = optionalArgument(args, 1); ! default_.empty() )
result = fmt(
"[](auto&& m, auto&& k, auto&& default_) { return m.contains(k)? m.get(k) : default_; }(%s, %s, %s)",
"[](auto&& m, auto&& k, auto&& default_) { return m.contains(k) ? m.get(k) : default_; }(%s, %s, %s)",
self, k, default_);
else
result = fmt("%s.get(%s)", self, k);
}

void operator()(operator_::map::GetOptional* n) final {
auto [self, args] = methodArguments(n);
result = fmt("%s.get_optional(%s)", self, args[0]);
}

void operator()(operator_::map::IndexAssign* n) final {
const auto& map = op0(n);
const auto& key = op1(n);
Expand Down
2 changes: 2 additions & 0 deletions tests/Baseline/spicy.types.map.ops/output
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ BBB
0
43
43
[$i=43]
(not set)
3 changes: 3 additions & 0 deletions tests/spicy/types/map/ops.spicy
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ u.i = 42;
global m2 = map<string, U>("foo": u);
m2["foo"].i = 43;
print m2["foo"].i;

print m2.get_optional("foo");
print m2.get_optional("bar");

0 comments on commit 09ee9b5

Please sign in to comment.