LCOV - code coverage report
Current view: top level - extra/webserver/pug - SPPugVariable.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 274 343 79.9 %
Date: 2024-05-12 00:16:13 Functions: 46 49 93.9 %

          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             : }

Generated by: LCOV version 1.14