Line data Source code
1 : /**
2 : Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "SPPugVariable.h"
24 :
25 : namespace STAPPLER_VERSIONIZED stappler::pug {
26 :
27 82050 : VarData::~VarData() {
28 82050 : clear();
29 82050 : }
30 :
31 8950 : VarData::VarData() : type(Null) { }
32 24375 : VarData::VarData(bool isConst, const Value *val) : type(Reference) {
33 24375 : pointer.isConstant = isConst;
34 24375 : pointer.value = val;
35 24375 : }
36 2125 : VarData::VarData(const Value &val) : type(Inline) {
37 2125 : new (&value) Value(val);
38 2125 : }
39 7425 : VarData::VarData(Value &&val) : type(Inline) {
40 7425 : new (&value) Value(move(val));
41 7425 : }
42 :
43 25 : VarData::VarData(const VarData &other) : type(other.type) {
44 25 : switch (type) {
45 0 : case Null: break;
46 0 : case Inline: new (&value) Value(other.value); break;
47 25 : case Reference: pointer = other.pointer; break;
48 : }
49 25 : }
50 39150 : VarData::VarData(VarData &&other) : type(other.type) {
51 39150 : switch (type) {
52 13150 : case Null: break;
53 9700 : case Inline: new (&value) Value(move(other.value)); break;
54 16300 : case Reference: pointer = other.pointer; break;
55 : }
56 39150 : }
57 :
58 350 : VarData& VarData::operator=(const VarData &other) {
59 350 : clear();
60 350 : type = other.type;
61 350 : switch (type) {
62 225 : case Null: break;
63 50 : case Inline: new (&value) Value(other.value); break;
64 75 : case Reference: pointer = other.pointer; break;
65 : }
66 350 : return *this;
67 : }
68 :
69 5925 : VarData& VarData::operator=(VarData &&other) {
70 5925 : clear();
71 5925 : type = other.type;
72 5925 : switch (type) {
73 0 : case Null: break;
74 2125 : case Inline: new (&value) Value(move(other.value)); break;
75 3800 : case Reference: pointer = other.pointer; break;
76 : }
77 5925 : return *this;
78 : }
79 :
80 99800 : void VarData::clear() {
81 99800 : switch (type) {
82 23250 : case Inline: value.~Value(); break;
83 76550 : default: break;
84 : }
85 99800 : memset((void *)this, 0, sizeof(VarData));
86 99800 : }
87 :
88 50650 : const Value &VarData::readValue() const {
89 50650 : switch (type) {
90 0 : case Null: return Value::Null; break;
91 14925 : case Inline: return value; break;
92 35725 : case Reference: return *pointer.value; break;
93 : }
94 0 : return Value::Null;
95 : }
96 :
97 2125 : Value *VarData::getMutable() const {
98 2125 : switch (type) {
99 0 : case Null: return nullptr; break;
100 600 : case Inline: return const_cast<Value *>(&value); break;
101 1525 : case Reference: return pointer.isConstant ? nullptr : const_cast<Value *>(pointer.value); break;
102 : }
103 0 : return nullptr;
104 : }
105 :
106 2075 : void VarData::assign(const VarData &other) {
107 2075 : clear();
108 2075 : switch (other.type) {
109 0 : case Null: type = Null; break;
110 725 : case Inline: type = Inline; new (&value) Value(other.value); break;
111 1350 : case Reference:
112 1350 : if (other.pointer.isConstant) {
113 1100 : type = Inline;
114 1100 : new (&value) Value(*other.pointer.value);
115 : } else {
116 250 : type = Reference;
117 250 : pointer = other.pointer;
118 : }
119 1350 : break;
120 : }
121 2075 : }
122 :
123 125 : void VarStorage::set(const Value &val, VarClass *cl) {
124 125 : clear();
125 125 : type = cl ? ObjectReference : ValueReference;
126 125 : classPointer = cl;
127 125 : switch (val.getType()) {
128 125 : case Value::Type::ARRAY:
129 : case Value::Type::DICTIONARY:
130 125 : value = VarData(false, new Value(val));
131 125 : break;
132 0 : default:
133 0 : value = VarData(val);
134 0 : break;
135 : }
136 125 : }
137 :
138 3300 : void VarStorage::set(Value &&val, VarClass *cl) {
139 3300 : clear();
140 3300 : type = cl ? ObjectReference : ValueReference;
141 3300 : classPointer = cl;
142 3300 : switch (val.getType()) {
143 1175 : case Value::Type::ARRAY:
144 : case Value::Type::DICTIONARY:
145 1175 : value = VarData(false, new Value(val));
146 1175 : break;
147 2125 : default:
148 2125 : value = VarData(val);
149 2125 : break;
150 : }
151 3300 : }
152 :
153 2475 : void VarStorage::set(bool isConst, const Value *val, VarClass *cl) {
154 2475 : clear();
155 2475 : type = cl ? ObjectReference : ValueReference;
156 2475 : classPointer = cl;
157 2475 : value = VarData(isConst, val);
158 2475 : }
159 :
160 975 : void VarStorage::set(Callback *cb) {
161 975 : clear();
162 975 : type = StandaloneFunction;
163 975 : functionPointer = cb;
164 975 : }
165 :
166 375 : void VarStorage::set(VarClass *cl) {
167 375 : clear();
168 375 : type = ClassPointer;
169 375 : classPointer = cl;
170 375 : }
171 :
172 2150 : bool VarStorage::assign(const Var &var) {
173 2150 : clear();
174 2150 : switch (var.type) {
175 0 : case Var::Undefined: break;
176 0 : case Var::SoftUndefined: break;
177 0 : case Var::Writable: break;
178 2075 : case Var::Static: value.assign(var.staticStorage); type = ValueReference; return true; break;
179 0 : case Var::Temporary: *this = var.temporaryStorage; return true; break;
180 75 : case Var::Variable: *this = *var.variableStorage; return true; break;
181 : }
182 0 : return false;
183 : }
184 :
185 9400 : void VarStorage::clear() {
186 9400 : value.clear();
187 9400 : classPointer = nullptr;
188 9400 : functionPointer = nullptr;
189 9400 : type = Undefined;
190 9400 : }
191 :
192 19250 : const Value &VarStorage::readValue() const {
193 19250 : switch (type) {
194 18225 : case ValueReference:
195 : case ObjectReference:
196 : case ValueFunction:
197 : case MemberFunction:
198 18225 : return value.readValue();
199 : break;
200 1025 : default:
201 1025 : break;
202 : }
203 1025 : return Value::Null;
204 : }
205 :
206 1050 : Value *VarStorage::getMutable() const {
207 1050 : switch (type) {
208 1050 : case ValueReference:
209 : case ObjectReference:
210 1050 : return value.getMutable();
211 : break;
212 0 : default:
213 0 : break;
214 : }
215 0 : return nullptr;
216 : }
217 :
218 350 : VarStorage::Callback * VarStorage::getCallable() const {
219 350 : return functionPointer;
220 : }
221 :
222 :
223 107675 : Var::~Var() {
224 107675 : clear();
225 107675 : }
226 :
227 27900 : Var::Var() { }
228 :
229 2075 : Var::Var(nullptr_t) : type(SoftUndefined) { }
230 :
231 1875 : Var::Var(const Var &var) {
232 1875 : type = var.type;
233 1875 : switch (type) {
234 0 : case Undefined: break;
235 0 : case SoftUndefined: break;
236 0 : case Static: new (&staticStorage) VarData(var.staticStorage); break;
237 25 : case Temporary: new (&temporaryStorage) VarStorage(var.temporaryStorage); break;
238 1850 : case Variable: variableStorage = var.variableStorage; break;
239 0 : case Writable: writableStorage = var.writableStorage; break;
240 : }
241 1875 : }
242 27625 : Var::Var(Var &&var) {
243 27625 : type = var.type;
244 27625 : switch (type) {
245 50 : case Undefined: break;
246 75 : case SoftUndefined: break;
247 8000 : case Static: new (&staticStorage) VarData(move(var.staticStorage)); break;
248 275 : case Temporary: new (&temporaryStorage) VarStorage(move(var.temporaryStorage)); break;
249 19200 : case Variable: variableStorage = var.variableStorage; break;
250 25 : case Writable: writableStorage = var.writableStorage; break;
251 : }
252 27625 : }
253 :
254 7425 : Var::Var(Value && data) : type(Static) {
255 7425 : new (&staticStorage) VarData(move(data));
256 7425 : }
257 0 : Var::Var(const Value &data) : type(Static) {
258 0 : new (&staticStorage) VarData(data);
259 0 : }
260 20575 : Var::Var(bool isConst, const Value *data) : type(Static) {
261 20575 : new (&staticStorage) VarData(isConst, data);
262 20575 : }
263 :
264 25 : Var::Var(Value *val) : type(Temporary) {
265 25 : new (&temporaryStorage) VarStorage();
266 25 : temporaryStorage.type = VarStorage::ValueReference;
267 25 : temporaryStorage.value = VarData(false, val);
268 25 : }
269 :
270 25 : Var::Var(Value *storage, const StringView &key) : type(Writable) {
271 25 : new (&writableStorage) VarWritable();
272 25 : writableStorage.value = storage;
273 25 : writableStorage.key = key;
274 25 : }
275 :
276 19875 : Var::Var(VarStorage *storage) : type(Variable) {
277 19875 : variableStorage = storage;
278 19875 : }
279 0 : Var::Var(VarClass *cl) : type(Temporary) {
280 0 : new (&temporaryStorage) VarStorage();
281 0 : temporaryStorage.type = VarStorage::ClassPointer;
282 0 : temporaryStorage.classPointer = cl;
283 0 : }
284 :
285 275 : Var::Var(const Var &var, Callback &cb, VarStorage::Type t) : type(Temporary) {
286 275 : new (&temporaryStorage) VarStorage();
287 :
288 275 : if (auto s = var.getStorage()) {
289 275 : temporaryStorage.type = t;
290 275 : temporaryStorage.classPointer = s->classPointer;
291 275 : temporaryStorage.functionPointer = &cb;
292 275 : temporaryStorage.value = s->value;
293 : }
294 275 : }
295 :
296 0 : Var& Var::operator=(const Var &var) {
297 0 : clear();
298 0 : type = var.type;
299 0 : switch (type) {
300 0 : case Undefined: break;
301 0 : case SoftUndefined: break;
302 0 : case Static: new (&staticStorage) VarData(var.staticStorage); break;
303 0 : case Temporary: new (&temporaryStorage) VarStorage(var.temporaryStorage); break;
304 0 : case Variable: variableStorage = var.variableStorage; break;
305 0 : case Writable: writableStorage = var.writableStorage; break;
306 : }
307 0 : return *this;
308 : }
309 21225 : Var& Var::operator=(Var &&var) {
310 21225 : clear();
311 21225 : type = var.type;
312 21225 : switch (type) {
313 400 : case Undefined: break;
314 0 : case SoftUndefined: break;
315 1600 : case Static: new (&staticStorage) VarData(move(var.staticStorage)); break;
316 25 : case Temporary: new (&temporaryStorage) VarStorage(move(var.temporaryStorage)); break;
317 19200 : case Variable: variableStorage = var.variableStorage; break;
318 0 : case Writable: writableStorage = var.writableStorage; break;
319 : }
320 21225 : return *this;
321 : }
322 :
323 83425 : Var::operator bool () const {
324 83425 : return type != Undefined;
325 : }
326 :
327 52675 : const Value &Var::readValue() const {
328 52675 : switch (type) {
329 50 : case Undefined: break;
330 2150 : case SoftUndefined: break;
331 25 : case Writable: break;
332 31275 : case Static: return staticStorage.readValue(); break;
333 0 : case Temporary: return temporaryStorage.readValue(); break;
334 19175 : case Variable: return variableStorage->readValue(); break;
335 : }
336 2225 : return Value::Null;
337 : }
338 :
339 1350 : Value *Var::getMutable() const {
340 1350 : switch (type) {
341 0 : case Undefined: break;
342 0 : case SoftUndefined: break;
343 0 : case Writable: break;
344 300 : case Static: return staticStorage.getMutable(); break;
345 0 : case Temporary: return temporaryStorage.getMutable(); break;
346 1050 : case Variable: return variableStorage->getMutable(); break;
347 : }
348 0 : return nullptr;
349 : }
350 :
351 129100 : void Var::clear() {
352 129100 : switch (type) {
353 28550 : case Undefined: break;
354 2150 : case SoftUndefined: break;
355 37600 : case Static: staticStorage.~VarData(); break;
356 625 : case Temporary: temporaryStorage.~VarStorage(); break;
357 60125 : case Variable: break;
358 50 : case Writable: writableStorage.~VarWritable(); break;
359 : }
360 129100 : type = Undefined;
361 129100 : }
362 :
363 1575 : bool Var::assign(const Var &var) {
364 1575 : switch (type) {
365 25 : case Undefined: break;
366 0 : case SoftUndefined: break;
367 0 : case Static: break;
368 0 : case Temporary: return temporaryStorage.assign(var); break;
369 1525 : case Variable: return variableStorage->assign(var); break;
370 25 : case Writable:
371 25 : if (auto r = var.readValue()) {
372 25 : writableStorage.value->setValue(var.readValue(), writableStorage.key.str<memory::PoolInterface>());
373 25 : *this = Var(writableStorage.value);
374 25 : return true;
375 25 : }
376 0 : break;
377 : }
378 25 : return false;
379 : }
380 :
381 9375 : Var Var::subscript(const StringView &str, bool mut) {
382 9375 : if (mut) {
383 25 : if (auto m = getMutable()) {
384 25 : if (m->isDictionary()) {
385 25 : auto &dict = m->asDict();
386 25 : auto it = dict.find(str);
387 25 : if (it != dict.end()) {
388 0 : return Var(&it->second); // make writable temporary
389 : } else {
390 25 : return Var(m, str);
391 : }
392 : }
393 : }
394 : } else {
395 9075 : auto read = [&, this] () -> Var {
396 9075 : auto &r = readValue();
397 9075 : if (str == "length" && (r.isArray() || r.isDictionary())) {
398 0 : return Var(Value(uint64_t(r.size())));
399 9075 : } else if (r.isDictionary()) {
400 9075 : auto &dict = r.asDict();
401 9075 : auto it = dict.find(str);
402 9075 : if (it != dict.end()) {
403 7350 : return Var(true, &it->second);
404 : }
405 : }
406 1725 : return Var();
407 9350 : };
408 :
409 9350 : if (auto storage = getStorage()) {
410 9325 : switch (storage->type) {
411 75 : case VarStorage::ObjectReference:
412 75 : if (storage->classPointer) {
413 75 : auto it = storage->classPointer->functions.find(str);
414 75 : if (it != storage->classPointer->functions.end()) {
415 125 : return Var(*this, it->second, VarStorage::MemberFunction);
416 : }
417 25 : it = storage->classPointer->staticFunctions.find(str);
418 25 : if (it != storage->classPointer->staticFunctions.end()) {
419 25 : return Var(*this, it->second, VarStorage::ClassFunction);
420 : }
421 : }
422 0 : break;
423 200 : case VarStorage::ClassPointer:
424 200 : if (storage->classPointer) {
425 200 : auto it = storage->classPointer->staticFunctions.find(str);
426 200 : if (it != storage->classPointer->staticFunctions.end()) {
427 200 : return Var(*this, it->second, VarStorage::ClassFunction);
428 : }
429 : }
430 0 : break;
431 9050 : default: break;
432 : }
433 : }
434 :
435 9075 : return read();
436 : }
437 0 : return Var();
438 : }
439 :
440 25 : Var Var::subscript(int64_t idx, bool mut) {
441 25 : if (idx < 0) {
442 0 : return Var();
443 : }
444 25 : if (mut) {
445 0 : if (auto m = getMutable()) {
446 0 : if (m->isArray()) {
447 0 : auto &arr = m->asArray();
448 0 : if (size_t(idx) < arr.size()) {
449 0 : return Var(&arr.at(idx));
450 : }
451 : }
452 : }
453 : } else {
454 25 : auto &r = readValue();
455 25 : if (r.isArray()) {
456 25 : auto &arr = r.asArray();
457 25 : if (size_t(idx) < arr.size()) {
458 25 : return Var(true, &arr.at(idx));
459 : }
460 : }
461 : }
462 0 : return Var();
463 : }
464 :
465 350 : Var::Callback * Var::getCallable() const {
466 350 : switch (type) {
467 0 : case Undefined:
468 : case SoftUndefined:
469 : case Static:
470 : case Writable:
471 0 : break;
472 275 : case Temporary: return temporaryStorage.getCallable(); break;
473 75 : case Variable: return variableStorage->getCallable(); break;
474 : }
475 0 : return nullptr;
476 : }
477 :
478 9975 : VarStorage * Var::getStorage() const {
479 9975 : switch (type) {
480 25 : case Undefined:
481 : case SoftUndefined:
482 : case Static:
483 : case Writable:
484 25 : break;
485 275 : case Temporary: return const_cast<VarStorage *>(&temporaryStorage); break;
486 9675 : case Variable: return variableStorage; break;
487 : }
488 25 : return nullptr;
489 : }
490 :
491 18075 : Var::Type Var::getType() const {
492 18075 : return type;
493 : }
494 :
495 : }
|