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