-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenvironment.hpp
103 lines (93 loc) · 3.09 KB
/
environment.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// environment.hpp
//
// Defines the ALisp Environment.
//
// Design considerations:
// - Insertion speed is highly relevant; items will constantly be inserted or
// updated into environments.
// - Lookups will be very random; no point ordering keys.
// ** Use unordered_map due to above
#pragma once
#include <memory>
#include <unordered_map>
#include "acore.hpp"
#include "cell.hpp"
#include "excepts.hpp"
namespace ALisp {
class Environment {
public:
typedef AtomType key_type;
typedef Cell val_type;
typedef std::unordered_map<AtomType, Cell> map_type;
typedef EnvironmentType outer_type;
typedef typename map_type::const_iterator const_iterator;
private:
map_type _map;
outer_type _outer;
protected:
void addRange(const ListType &keys, const ListType &values) {
for (auto it1 = keys.cbegin(), it2 = values.cbegin();
it1 != keys.cend() && it2 != values.cend();
++it1, ++it2) {
create(it1->atomId(), *it2);
}
}
public:
Environment(outer_type parent = nullptr) : _map(), _outer(parent) {}
Environment(const Cell &keys, const ListType &values, outer_type parent = nullptr)
: _map(), _outer(parent) {
ListType lt_keys, lt_values;
if (keys.type() == CellType::List) {
// List of keys and values
lt_keys.insert(lt_keys.end(), keys.cbegin(), keys.cend());
lt_values.insert(lt_values.end(), values.cbegin(), values.cend());
} else {
// Single key capturing multiple values
lt_keys.push_back(keys);
lt_values.push_back(ListCell(values.cbegin(), values.cend()));
}
addRange(lt_keys, lt_values);
}
bool has_parent() const { return _outer != nullptr; }
outer_type get_parent() const { return _outer; }
void create(const Cell &cell, val_type val) {
switch (cell.type()) {
case CellType::Atom: return create(cell.atomId(), val);
case CellType::String: return create(Atoms::Declare(cell.str().c_str()), val);
default: throw Exception("Cannot convert cell to atom");
}
}
void create(key_type key, val_type val) {
// Note function signature: val is copied not referenced
_map[key] = val;
}
bool has_key(key_type key) const {
return _map.find(key) != _map.end();
}
const_iterator find_key(key_type key) const {
return _map.find(key);
}
const_iterator cbegin() const { return _map.cbegin(); }
const_iterator cend() const { return _map.cend(); }
bool has_key_any(key_type key) const {
if (has_key(key)) return true;
if (has_parent()) return _outer->has_key_any(key);
return false;
}
void set(key_type key, val_type val) EXCEPT {
// Note function signature: val is copied not referenced
if (has_key(key)) create(key, val);
else if (has_parent()) _outer->set(key, val);
else throw KeyNotFoundException(key);
}
Cell get(key_type key) EXCEPT {
auto it = find_key(key);
if (it != cend())
return it->second;
else if (has_parent())
return _outer->get(key);
throw KeyNotFoundException(key);
}
void clear() { _map.clear(); if (has_parent()) _outer->clear(); }
};
}