载入中...
搜索中...
未找到
StateValue.cpp
浏览该文件的文档.
1#include "common/StateValue.h"
2
3#include <cctype>
4#include <utility>
5
6namespace eve {
7namespace {
8
13bool parseSegment(const std::string& seg, std::string& key, std::vector<size_t>& indexes) {
14 key.clear();
15 indexes.clear();
16 if (seg.empty()) return false;
17
18 size_t i = 0;
19 if (seg[0] != '[') {
20 while (i < seg.size() && seg[i] != '[') key.push_back(seg[i++]);
21 }
22 if (key.empty() && (i >= seg.size())) return false;
23
24 while (i < seg.size()) {
25 if (seg[i] != '[') return false;
26 const size_t close = seg.find(']', i);
27 if (close == std::string::npos) return false;
28 const std::string idx = seg.substr(i + 1, close - i - 1);
29 if (idx.empty() || idx.find_first_not_of("0123456789") != std::string::npos) return false;
30 indexes.push_back(static_cast<size_t>(std::stoull(idx)));
31 i = close + 1;
32 }
33 return true;
34}
35
36} // namespace
37
40 sv.i_ = v;
41 return sv;
42}
43
46 sv.f_ = v;
47 return sv;
48}
49
52 sv.b_ = v;
53 return sv;
54}
55
58 sv.s_ = std::move(v);
59 return sv;
60}
61
62void StateValue::pushBack(StateValue v) { arr_.push_back(std::move(v)); }
63
64void StateValue::set(const std::string& key, StateValue v) {
65 for (auto& kv : obj_) {
66 if (kv.first == key) {
67 kv.second = std::move(v);
68 return;
69 }
70 }
71 obj_.emplace_back(key, std::move(v));
72}
73
74const StateValue* StateValue::find(const std::string& key) const {
75 for (const auto& kv : obj_)
76 if (kv.first == key) return &kv.second;
77 return nullptr;
78}
79
80StateValue* StateValue::find(const std::string& key) {
81 for (auto& kv : obj_)
82 if (kv.first == key) return &kv.second;
83 return nullptr;
84}
85
86std::vector<std::string> StateValue::keys() const {
87 std::vector<std::string> out;
88 out.reserve(obj_.size());
89 for (const auto& kv : obj_) out.push_back(kv.first);
90 return out;
91}
92
93const StateValue* StateValue::get(const std::string& dottedPath) const {
94 const StateValue* cur = this;
95 size_t start = 0;
96 while (true) {
97 const size_t dot = dottedPath.find('.', start);
98 const bool last = (dot == std::string::npos);
99 const std::string seg = dottedPath.substr(start, last ? std::string::npos : dot - start);
100
101 std::string key;
102 std::vector<size_t> indexes;
103 if (!parseSegment(seg, key, indexes)) return nullptr;
104 if (!key.empty()) {
105 cur = cur->find(key);
106 if (!cur) return nullptr;
107 }
108 for (const size_t idx : indexes) {
109 if (!cur->isArray() || idx >= cur->arr_.size()) return nullptr;
110 cur = &cur->arr_[idx];
111 }
112 if (last) return cur;
113 start = dot + 1;
114 }
115}
116
117StateValue* StateValue::get(const std::string& dottedPath) {
118 return const_cast<StateValue*>(static_cast<const StateValue*>(this)->get(dottedPath));
119}
120
121bool StateValue::setPath(const std::string& dottedPath, StateValue v) {
122 std::vector<std::string> segs;
123 size_t start = 0;
124 while (true) {
125 const size_t dot = dottedPath.find('.', start);
126 if (dot == std::string::npos) {
127 segs.push_back(dottedPath.substr(start));
128 break;
129 }
130 segs.push_back(dottedPath.substr(start, dot - start));
131 start = dot + 1;
132 }
133 if (segs.empty() || (segs.size() == 1 && segs[0].empty())) return false;
134
135 StateValue* cur = this;
136 for (size_t si = 0; si + 1 < segs.size(); ++si) {
137 std::string key;
138 std::vector<size_t> indexes;
139 // Intermediate segments must be plain object keys; array traversal is
140 // only supported on the final segment.
141 if (!parseSegment(segs[si], key, indexes) || key.empty() || !indexes.empty()) return false;
142 if (!cur->isObject()) return false;
143 StateValue* next = cur->find(key);
144 if (!next) {
145 cur->set(key, StateValue::object());
146 next = cur->find(key);
147 }
148 cur = next;
149 }
150
151 std::string key;
152 std::vector<size_t> indexes;
153 if (!parseSegment(segs.back(), key, indexes)) return false;
154 if (!indexes.empty()) {
155 if (!key.empty()) {
156 if (!cur->isObject()) return false;
157 const StateValue* arr = cur->find(key);
158 if (!arr || !arr->isArray()) return false;
159 cur = cur->find(key);
160 }
161 if (!cur->isArray() || indexes.size() != 1 || indexes[0] >= cur->arr_.size()) return false;
162 cur->arr_[indexes[0]] = std::move(v);
163 return true;
164 }
165 if (!cur->isObject() || key.empty()) return false;
166 cur->set(key, std::move(v));
167 return true;
168}
169
171 if (!isObject() || !defaults.isObject()) return false;
172 bool changed = false;
173 for (const auto& kv : defaults.obj_) {
174 StateValue* mine = find(kv.first);
175 if (!mine) {
176 set(kv.first, kv.second);
177 changed = true;
178 } else if (mine->isObject() && kv.second.isObject()) {
179 changed = mine->mergeDefaults(kv.second) || changed;
180 }
181 }
182 return changed;
183}
184
185bool StateValue::operator==(const StateValue& o) const {
186 if (kind_ != o.kind_) return false;
187 switch (kind_) {
188 case Kind::Null: return true;
189 case Kind::Int: return i_ == o.i_;
190 case Kind::Float: return f_ == o.f_;
191 case Kind::Bool: return b_ == o.b_;
192 case Kind::String: return s_ == o.s_;
193 case Kind::Array: return arr_ == o.arr_;
194 case Kind::Object: return obj_ == o.obj_;
195 }
196 return false;
197}
198
199} // namespace eve
int idx
int v
JSON-compatible state value tree used by state hot reload.
Definition StateValue.h:20
static StateValue object()
Empty object.
Definition StateValue.h:39
static StateValue boolean(bool v)
Boolean value.
bool setPath(const std::string &dottedPath, StateValue v)
Set a value at a dotted path, creating missing intermediate objects along the way.
static StateValue integer(int64_t v)
Integer value.
bool mergeDefaults(const StateValue &defaults)
Fill missing members from defaults; object members merge recursively, existing values are never overw...
void pushBack(StateValue v)
Append an element; only valid on arrays.
const StateValue * get(const std::string &dottedPath) const
Navigate a dotted path ("a.b[2].c").
bool isObject() const
Definition StateValue.h:49
bool isArray() const
Definition StateValue.h:50
bool operator==(const StateValue &o) const
static StateValue number(double v)
Floating-point value.
const StateValue * find(const std::string &key) const
Look up key; nullptr when absent.
std::vector< std::string > keys() const
Member names in insertion order.
static StateValue string(std::string v)
String value.
void set(const std::string &key, StateValue v)
Insert or replace key; only valid on objects.
Definition Build.cpp:11