LCOV - code coverage report
Current view: top level - xenolith/renderer/material2d/base - MaterialDataSource.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 88 282 31.2 %
Date: 2024-05-12 00:16:13 Functions: 18 46 39.1 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 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 "MaterialDataSource.h"
      24             : 
      25             : namespace STAPPLER_VERSIONIZED stappler::xenolith::material2d {
      26             : 
      27             : DataSource::Id DataSource::Self(DataSource::Id::max());
      28             : 
      29             : struct DataSource::Slice {
      30             :         Id::Type idx;
      31             :         size_t len;
      32             :         DataSource *cat;
      33             :         size_t offset;
      34             :         bool recieved;
      35             : 
      36          20 :         Slice(Id::Type idx, size_t len, DataSource *cat)
      37          20 :         : idx(idx), len(len), cat(cat), offset(0), recieved(false) { }
      38             : };
      39             : 
      40             : struct DataSource::SliceRequest : public Ref {
      41             :         std::vector<Slice> vec;
      42             :         BatchCallback cb;
      43             :         size_t ready = 0;
      44             :         size_t requests = 0;
      45             :         Map<Id, Value> data;
      46             : 
      47          20 :         SliceRequest(const BatchCallback &cb) : cb(cb) { }
      48             : 
      49          20 :         size_t request(size_t off) {
      50          20 :                 size_t ret = 0;
      51             : 
      52          20 :                 requests = vec.size();
      53          40 :                 for (auto &it : vec) {
      54          20 :                         it.offset = off;
      55          20 :                         off += it.len;
      56          20 :                         auto ptr = &it;
      57          20 :                         auto cat = it.cat;
      58             : 
      59          20 :                         auto callId = retain();
      60          20 :                         auto linkId = cat->retain();
      61          20 :                         cat->onSliceRequest([this, ptr, cat, linkId, callId] (Map<Id, Value> &val) {
      62          20 :                                 onSliceData(ptr, val);
      63          20 :                                 cat->release(linkId);
      64          20 :                                 release(callId);
      65          20 :                         }, it.idx, it.len);
      66          20 :                         ret += it.len;
      67             :                 }
      68             :                 // this will destroy (*this), if direct data access available
      69          20 :                 release(0); // free or decrement ref-count
      70          20 :                 return ret;
      71             :         }
      72             : 
      73          20 :         bool onSliceData(Slice *ptr, Map<Id, Value> &val) {
      74          20 :                 ptr->recieved = true;
      75             : 
      76          20 :                 auto front = val.begin()->first;
      77         420 :                 for(auto &it : val) {
      78         400 :                         if (it.first != Self) {
      79         400 :                                 data.emplace(it.first + Id(ptr->offset) - front, std::move(it.second));
      80             :                         } else {
      81           0 :                                 data.emplace(Id(ptr->offset), std::move(it.second));
      82             :                         }
      83             :                 }
      84             : 
      85          20 :                 ready ++;
      86          20 :                 requests --;
      87             : 
      88          20 :                 if (ready >= vec.size() && requests == 0) {
      89          40 :                         for (auto &it : vec) {
      90          20 :                                 if (!it.recieved) {
      91           0 :                                         return false;
      92             :                                 }
      93             :                         }
      94             : 
      95          20 :                         cb(data);
      96          20 :                         return true;
      97             :                 }
      98             : 
      99           0 :                 return false;
     100             :         }
     101             : };
     102             : 
     103             : struct DataSource::BatchRequest {
     104             :         std::vector<Id> vec;
     105             :         BatchCallback cb;
     106             :         size_t requests = 0;
     107             :         Rc<DataSource> cat;
     108             :         Map<Id, Value> map;
     109             : 
     110          20 :         static void request(const BatchCallback &cb, Id::Type first, size_t size, DataSource *cat, const DataSourceCallback &scb) {
     111          20 :                 new BatchRequest(cb, first, size, cat, scb);
     112          20 :         }
     113             : 
     114          20 :         BatchRequest(const BatchCallback &cb, Id::Type first, size_t size, DataSource *cat, const DataSourceCallback &scb)
     115          20 :         : cb(cb), cat(cat) {
     116         420 :                 for (auto i = first; i < first + size; i++) {
     117         400 :                         vec.emplace_back(i);
     118             :                 }
     119             : 
     120          20 :                 requests += vec.size();
     121         420 :                 for (auto &it : vec) {
     122         400 :                         scb([this, it] (Value &&val) {
     123         400 :                                 if (val.isArray()) {
     124           0 :                                         onData(it, std::move(val.getValue(0)));
     125             :                                 } else {
     126         400 :                                         onData(it, std::move(val));
     127             :                                 }
     128         400 :                         }, it);
     129             :                 }
     130          20 :         }
     131             : 
     132         400 :         void onData(Id id, Value &&val) {
     133         400 :                 map.insert(std::make_pair(id, std::move(val)));
     134         400 :                 requests --;
     135             : 
     136         400 :                 if (requests == 0) {
     137          20 :                         cb(map);
     138          20 :                         delete this;
     139             :                 }
     140         400 :         }
     141             : };
     142             : 
     143           0 : void DataSource::clear() {
     144           0 :         _subCats.clear();
     145           0 :         _count = _orphanCount;
     146           0 :         setDirty();
     147           0 : }
     148             : 
     149           0 : void DataSource::addSubcategry(DataSource *cat) {
     150           0 :         _subCats.emplace_back(cat);
     151           0 :         _count += cat->getGlobalCount();
     152           0 :         setDirty();
     153           0 : }
     154             : 
     155          20 : DataSource::~DataSource() { }
     156             : 
     157           0 : DataSource * DataSource::getCategory(size_t n) {
     158           0 :         if (n < getSubcatCount()) {
     159           0 :                 return _subCats.at(n);
     160             :         }
     161           0 :         return nullptr;
     162             : }
     163             : 
     164          20 : size_t DataSource::getCount(uint32_t l, bool subcats) const {
     165          20 :         auto c = _orphanCount + ((subcats)?_subCats.size():0);
     166          20 :         if (l > 0) {
     167           0 :                 for (auto cat : _subCats) {
     168           0 :                         c += cat->getCount(l - 1, subcats);
     169           0 :                 }
     170             :         }
     171          20 :         return c;
     172             : }
     173             : 
     174           0 : size_t DataSource::getSubcatCount() const {
     175           0 :         return _subCats.size();
     176             : }
     177           0 : size_t DataSource::getItemsCount() const {
     178           0 :         return _orphanCount;
     179             : }
     180           0 : size_t DataSource::getGlobalCount() const {
     181           0 :         return _count;
     182             : }
     183             : 
     184           0 : DataSource::Id DataSource::getId() const {
     185           0 :         return _categoryId;
     186             : }
     187             : 
     188           0 : void DataSource::setSubCategories(Vector<Rc<DataSource>> &&vec) {
     189           0 :         _subCats = std::move(vec);
     190           0 :         setDirty();
     191           0 : }
     192           0 : void DataSource::setSubCategories(const Vector<Rc<DataSource>> &vec) {
     193           0 :         _subCats = vec;
     194           0 :         setDirty();
     195           0 : }
     196           0 : const Vector<Rc<DataSource>> &DataSource::getSubCategories() const {
     197           0 :         return _subCats;
     198             : }
     199             : 
     200           0 : void DataSource::setChildsCount(size_t count) {
     201           0 :         _count -= _orphanCount;
     202           0 :         _orphanCount = count;
     203           0 :         _count += _orphanCount;
     204           0 :         setDirty();
     205           0 : }
     206             : 
     207           0 : size_t DataSource::getChildsCount() const {
     208           0 :         return _orphanCount;
     209             : }
     210             : 
     211           0 : void DataSource::setData(const Value &val) {
     212           0 :         _data = val;
     213           0 : }
     214             : 
     215           0 : void DataSource::setData(Value &&val) {
     216           0 :         _data = std::move(val);
     217           0 : }
     218             : 
     219           0 : const Value &DataSource::getData() const {
     220           0 :         return _data;
     221             : }
     222             : 
     223           0 : void DataSource::setDirty() {
     224           0 :         Subscription::setDirty();
     225           0 : }
     226             : 
     227           0 : void DataSource::setCategoryBounds(Id & first, size_t & count, uint32_t l, bool subcats) {
     228             :         // first should be 0 or bound value, that <= first
     229           0 :         if (l == 0 || _subCats.size() == 0) {
     230           0 :                 first = Id(0);
     231           0 :                 count = getCount(l, subcats);
     232           0 :                 return;
     233             :         }
     234             : 
     235           0 :         size_t lowerBound = 0, subcat = 0, offset = 0;
     236             :         do {
     237           0 :                 lowerBound += offset;
     238           0 :                 offset = _subCats.at(subcat)->getCount(l - 1, subcats);
     239           0 :                 subcat ++;
     240           0 :         } while(subcat < (size_t)_subCats.size() && lowerBound + offset <= (size_t)first.get());
     241             : 
     242             :         // check if we should skip last subcategory
     243           0 :         if (lowerBound + offset <= first.get()) {
     244           0 :                 lowerBound += offset;
     245             :         }
     246             : 
     247           0 :         offset = size_t(first.get()) - lowerBound;
     248           0 :         first = Id(lowerBound);
     249           0 :         count += offset; // increment size to match new bound
     250             : 
     251           0 :         size_t upperBound = getCount(l, subcats);
     252           0 :         if (upperBound - _orphanCount >= lowerBound + count) {
     253           0 :                 upperBound -= _orphanCount;
     254             :         }
     255             : 
     256           0 :         offset = 0;
     257           0 :         subcat = _subCats.size();
     258           0 :         while (subcat > 0 && upperBound - offset >= lowerBound + count) {
     259           0 :                 upperBound -= offset;
     260           0 :                 offset = _subCats.at(subcat - 1)->getCount(l - 1, subcats);
     261           0 :                 subcat --;
     262             :         }
     263             : 
     264           0 :         count = upperBound - lowerBound;
     265             : }
     266             : 
     267           0 : bool DataSource::getItemData(const DataCallback &cb, Id index) {
     268           0 :         if (index.get() >= _orphanCount && index != Self) {
     269           0 :                 return false;
     270             :         }
     271             : 
     272           0 :         if (index == Self && _data) {
     273           0 :                 cb(Value(_data));
     274             :         }
     275             : 
     276           0 :         _sourceCallback(cb, index);
     277           0 :         return true;
     278             : }
     279             : 
     280           0 : bool DataSource::getItemData(const DataCallback &cb, Id n, uint32_t l, bool subcats) {
     281           0 :         if (l > 0) {
     282           0 :                 for (auto &cat : _subCats) {
     283           0 :                         if (subcats) {
     284           0 :                                 if (n.empty()) {
     285           0 :                                         return cat->getItemData(cb, Self);
     286             :                                 } else {
     287           0 :                                         n --;
     288             :                                 }
     289             :                         }
     290           0 :                         auto c = Id(cat->getCount(l - 1, subcats));
     291           0 :                         if (n < c) {
     292           0 :                                 return cat->getItemData(cb, n, l - 1, subcats);
     293             :                         } else {
     294           0 :                                 n -= c;
     295             :                         }
     296             :                 }
     297             :         }
     298             : 
     299           0 :         if (!subcats) {
     300           0 :                 return getItemData(cb, Id(n));
     301             :         } else {
     302           0 :                 if (!_subCats.empty() && n < Id(_subCats.size())) {
     303           0 :                         return _subCats.at(size_t(n.get()))->getItemData(cb, Self);
     304             :                 }
     305             : 
     306           0 :                 return getItemData(cb, n - Id(_subCats.size()));
     307             :         }
     308             : }
     309             : 
     310           0 : bool DataSource::removeItem(Id index, const Value &v) {
     311           0 :         if (index.get() >= _orphanCount && index != Self) {
     312           0 :                 return false;
     313             :         }
     314             : 
     315           0 :         if (_removeCallback && index != Self) {
     316           0 :                 if (_removeCallback(index, v)) {
     317           0 :                         _orphanCount -= 1;
     318           0 :                         return true;
     319             :                 }
     320             :         }
     321           0 :         return false;
     322             : }
     323             : 
     324           0 : bool DataSource::removeItem(Id n, const Value &v, uint32_t l, bool subcats) {
     325           0 :         if (l > 0) {
     326           0 :                 for (auto catIt = _subCats.begin(); catIt != _subCats.end(); ++ catIt) {
     327           0 :                         auto &cat = *catIt;
     328           0 :                         if (subcats) {
     329           0 :                                 if (n.empty()) {
     330           0 :                                         if (cat->removeItem(Self, v)) {
     331           0 :                                                 _subCats.erase(catIt);
     332           0 :                                                 return true;
     333             :                                         }
     334           0 :                                         return false;
     335             :                                 } else {
     336           0 :                                         n --;
     337             :                                 }
     338             :                         }
     339           0 :                         auto c = Id(cat->getCount(l - 1, subcats));
     340           0 :                         if (n < c) {
     341           0 :                                 return cat->removeItem(n, v, l - 1, subcats);
     342             :                         } else {
     343           0 :                                 n -= c;
     344             :                         }
     345             :                 }
     346             :         }
     347             : 
     348           0 :         if (!subcats) {
     349           0 :                 return removeItem(Id(n), v);
     350             :         } else {
     351           0 :                 if (!_subCats.empty() && n < Id(_subCats.size())) {
     352           0 :                         _subCats.at(size_t(n.get()))->removeItem(Self, v);
     353             :                 }
     354             : 
     355           0 :                 return removeItem(n - Id(_subCats.size()), v);
     356             :         }
     357             : }
     358             : 
     359          20 : size_t DataSource::getSliceData(const BatchCallback &cb, Id first, size_t count, uint32_t l, bool subcats) {
     360          20 :         SliceRequest *req = new SliceRequest(cb);
     361             : 
     362          20 :         size_t f = size_t(first.get());
     363          20 :         onSlice(req->vec, f, count, l, subcats);
     364             : 
     365          20 :         if (!req->vec.empty()) {
     366          20 :                 return req->request(size_t(first.get()));
     367             :         } else {
     368           0 :                 delete req;
     369           0 :                 return 0;
     370             :         }
     371             : }
     372             : 
     373           0 : std::pair<DataSource *, bool> DataSource::getItemCategory(Id n, uint32_t l, bool subcats) {
     374           0 :         if (l > 0) {
     375           0 :                 for (auto &cat : _subCats) {
     376           0 :                         if (subcats) {
     377           0 :                                 if (n.empty()) {
     378           0 :                                         return std::make_pair(cat, true);
     379             :                                 } else {
     380           0 :                                         n --;
     381             :                                 }
     382             :                         }
     383           0 :                         auto c = cat->getCount(l - 1, subcats);
     384           0 :                         if (n.get() < c) {
     385           0 :                                 return cat->getItemCategory(n, l - 1, subcats);
     386             :                         } else {
     387           0 :                                 n -= Id(c);
     388             :                         }
     389             :                 }
     390             :         }
     391             : 
     392           0 :         if (!subcats) {
     393           0 :                 return std::make_pair(this, false);
     394             :         } else {
     395           0 :                 if (!_subCats.empty() && n.get() < (size_t)_subCats.size()) {
     396           0 :                         return std::make_pair(_subCats.at(size_t(n.get())), true);
     397             :                 }
     398             : 
     399           0 :                 return std::make_pair(this, false);
     400             :         }
     401             : }
     402             : 
     403          20 : void DataSource::onSlice(std::vector<Slice> &vec, size_t &first, size_t &count, uint32_t l, bool subcats) {
     404          20 :         if (l > 0) {
     405           0 :                 for (auto it = _subCats.begin(); it != _subCats.end(); it ++) {
     406           0 :                         if (first > 0) {
     407           0 :                                 if (subcats) {
     408           0 :                                         first --;
     409             :                                 }
     410             : 
     411           0 :                                 auto sCount = (*it)->getCount(l - 1, subcats);
     412           0 :                                 if (sCount <= first) {
     413           0 :                                         first -= sCount;
     414             :                                 } else {
     415           0 :                                         (*it)->onSlice(vec, first, count, l - 1, subcats);
     416             :                                 }
     417           0 :                         } else if (count > 0) {
     418           0 :                                 if (subcats) {
     419           0 :                                         vec.push_back(Slice(Self.get(), 1, *it));
     420           0 :                                         count -= 1;
     421             :                                 }
     422             : 
     423           0 :                                 if (count > 0) {
     424           0 :                                         (*it)->onSlice(vec, first, count, l - 1, subcats);
     425             :                                 }
     426             :                         }
     427             :                 }
     428             :         }
     429             : 
     430          20 :         if (count > 0 && first < _orphanCount) {
     431          20 :                 auto c = std::min(count, _orphanCount - first);
     432          20 :                 vec.push_back(Slice(first, c, this));
     433             : 
     434          20 :                 first = 0;
     435          20 :                 count -= c;
     436          20 :         } else if (first >= _orphanCount) {
     437           0 :                 first -= _orphanCount;
     438             :         }
     439          20 : }
     440             : 
     441          20 : void DataSource::onSliceRequest(const BatchCallback &cb, Id::Type first, size_t size) {
     442          20 :         if (first == Self.get()) {
     443           0 :                 if (!_data) {
     444           0 :                         _sourceCallback([cb] (Value &&val) {
     445           0 :                                 Map<Id, Value> map;
     446           0 :                                 if (val.isArray()) {
     447           0 :                                         map.insert(std::make_pair(Self, std::move(val.getValue(0))));
     448             :                                 } else {
     449           0 :                                         map.insert(std::make_pair(Self, std::move(val)));
     450             :                                 }
     451           0 :                                 cb(map);
     452           0 :                         }, Self);
     453             :                 } else {
     454           0 :                         Map<Id, Value> map;
     455           0 :                         map.insert(std::make_pair(Self, _data));
     456           0 :                         cb(map);
     457           0 :                 }
     458             :         } else {
     459          20 :                 if (!_batchCallback) {
     460          20 :                         BatchRequest::request(cb, first, size, this, _sourceCallback);
     461             :                 } else {
     462           0 :                         _batchCallback(cb, first, size);
     463             :                 }
     464             :         }
     465          20 : }
     466             : 
     467          10 : bool DataSource::init() {
     468          10 :         return true;
     469             : }
     470             : 
     471           0 : bool DataSource::initValue() {
     472           0 :         return true;
     473             : }
     474             : 
     475          10 : bool DataSource::initValue(const DataSourceCallback &cb) {
     476          10 :         _sourceCallback = cb;
     477          10 :         return true;
     478             : }
     479             : 
     480           0 : bool DataSource::initValue(const BatchSourceCallback &cb) {
     481           0 :         _batchCallback = cb;
     482           0 :         return true;
     483             : }
     484             : 
     485           0 : bool DataSource::initValue(const Id &id) {
     486           0 :         _categoryId = id;
     487           0 :         return true;
     488             : }
     489             : 
     490          10 : bool DataSource::initValue(const ChildsCount &count) {
     491          10 :         _orphanCount = count.get();
     492          10 :         return true;
     493             : }
     494             : 
     495           0 : bool DataSource::initValue(const Value &val) {
     496           0 :         _data = val;
     497           0 :         return true;
     498             : }
     499             : 
     500           0 : bool DataSource::initValue(Value &&val) {
     501           0 :         _data = std::move(val);
     502           0 :         return true;
     503             : }
     504             : 
     505             : }

Generated by: LCOV version 1.14