1 #define LLOG(x) // DLOG(x)
2
3 int64 NewInVectorSerial();
4
5 template <class T>
Init()6 void InVector<T>::Init()
7 {
8 serial = NewInVectorSerial();
9 slave = 0;
10 Reset();
11 }
12
13 template <class T>
InVector()14 InVector<T>::InVector()
15 {
16 Init();
17 }
18
19 template <class T>
Reset()20 void InVector<T>::Reset()
21 {
22 hcount = count = 0;
23 SetBlkPar();
24 }
25
26 template <class T>
Clear()27 void InVector<T>::Clear()
28 {
29 if(slave)
30 Slave()->Clear();
31 data.Clear();
32 index.Clear();
33 Reset();
34 ClearCache();
35 }
36
37 void SetInvectorCache__(int64 serial, int blki, int offset, int end);
38 void ClearInvectorCache__();
39 int FindInvectorCache__(int64 serial, int& pos, int& off);
40
41 template <class T>
SetCache(int blki,int offset) const42 force_inline void InVector<T>::SetCache(int blki, int offset) const
43 {
44 #ifdef flagIVTEST
45 Check(0, 0);
46 #endif
47 SetInvectorCache__(serial, blki, offset, offset + data[blki].GetCount());
48 }
49
50 template <class T>
ClearCache() const51 force_inline void InVector<T>::ClearCache() const
52 {
53 ClearInvectorCache__();
54 }
55
56 template <class T>
FindBlock(int & pos,int & off) const57 force_inline int InVector<T>::FindBlock(int& pos, int& off) const
58 {
59 int i = FindInvectorCache__(serial, pos, off);
60 return i >= 0 ? i : FindBlock0(pos, off);
61 }
62
63 template <class T>
FindBlock0(int & pos,int & off) const64 int InVector<T>::FindBlock0(int& pos, int& off) const
65 {
66 LLOG("FindBlock " << pos);
67 ASSERT(pos >= 0 && pos <= count);
68 if(pos == count) {
69 LLOG("Found last");
70 pos = data.Top().GetCount();
71 off = count - pos;
72 return data.GetCount() - 1;
73 }
74 int blki = 0;
75 int offset = 0;
76 for(int i = index.GetCount(); --i >= 0;) {
77 int n = index[i][blki];
78 if(pos >= n) {
79 blki++;
80 pos -= n;
81 offset += n;
82 }
83 blki += blki;
84 }
85 int n = data[blki].GetCount();
86 if(pos >= n) {
87 blki++;
88 pos -= n;
89 offset += n;
90 }
91
92 SetCache(blki, offset);
93
94 off = offset;
95 return blki;
96 }
97
98 template <class T>
FindBlock(int & pos) const99 force_inline int InVector<T>::FindBlock(int& pos) const
100 {
101 int h;
102 return FindBlock(pos, h);
103 }
104
105 template <class T>
operator [](int i) const106 const T& InVector<T>::operator[](int i) const
107 {
108 LLOG("operator[] " << i);
109 ASSERT(i >= 0 && i < count);
110 int blki = FindBlock(i);
111 return data[blki][i];
112 }
113
114 template <class T>
operator [](int i)115 T& InVector<T>::operator[](int i)
116 {
117 LLOG("operator[] " << i);
118 ASSERT(i >= 0 && i < count);
119 int blki = FindBlock(i);
120 return data[blki][i];
121 }
122
123 template <class T>
Reindex()124 void InVector<T>::Reindex()
125 {
126 LLOG("--- Reindexing");
127 ClearCache();
128 SetBlkPar();
129 index.Clear();
130 if(slave)
131 Slave()->Reindex();
132 hcount = 0;
133 Vector<T> *ds = data.Begin();
134 Vector<T> *dend = data.End();
135 int n = data.GetCount();
136 if(n <= 2)
137 return;
138 Vector<int>& w = index.Add();
139 hcount = 2;
140 w.SetCount((n + 1) >> 1);
141 int *t = w.Begin();
142 while(ds != dend) {
143 *t = (ds++)->GetCount();
144 if(ds == dend)
145 break;
146 *t++ += (ds++)->GetCount();
147 }
148 int *s = w.Begin();
149 int *end = w.End();
150 n = w.GetCount();
151 while(n > 2) {
152 Vector<int>& w = index.Add();
153 hcount += hcount;
154 w.SetCount((n + 1) >> 1);
155 t = w.Begin();
156 while(s != end) {
157 *t = *s++;
158 if(s == end)
159 break;
160 *t++ += *s++;
161 }
162 s = w.Begin();
163 end = w.End();
164 n = w.GetCount();
165 }
166 #ifdef flagIVTEST
167 Check(0, 0);
168 #endif
169 }
170
171 template <class T>
SetBlkPar()172 void InVector<T>::SetBlkPar()
173 {
174 #if defined(_DEBUG) && defined(flagIVTEST)
175 blk_high = 11;
176 blk_low = 5;
177 #else
178 int n = 2500 + data.GetCount() / 4;
179 blk_high = minmax(n / (int)sizeof(T), 16, 65000);
180 blk_low = minmax(n / 3 / (int)sizeof(T), 16, 65000);
181 #endif
182 }
183
184 template <class T>
Index(int q,int n)185 void InVector<T>::Index(int q, int n)
186 {
187 for(int i = 0; i < index.GetCount(); i++)
188 index[i].At(q >>= 1, 0) += n;
189 }
190
191 template <class T>
Insert0(int ii,int blki,int pos,int off,const T * val)192 T *InVector<T>::Insert0(int ii, int blki, int pos, int off, const T *val)
193 {
194 if(data[blki].GetCount() > blk_high) {
195 if(slave)
196 Slave()->Split(blki, data[blki].GetCount() / 2);
197 Vector<T>& x = data.Insert(blki + 1);
198 x.InsertSplit(0, data[blki], data[blki].GetCount() / 2);
199 data[blki].Shrink();
200 Reindex();
201 pos = ii;
202 blki = FindBlock(pos, off);
203 }
204 LLOG("blki: " << blki << ", pos: " << pos);
205 count++;
206 if(slave) {
207 Slave()->Count(1);
208 Slave()->Index(blki, 1);
209 Slave()->Insert(blki, pos);
210 }
211 Index(blki, 1);
212 if(val)
213 data[blki].Insert(pos, *val);
214 else
215 data[blki].Insert(pos);
216 SetCache(blki, off);
217 return &data[blki][pos];
218 }
219
220 template <class T>
Insert0(int ii,const T * val)221 T *InVector<T>::Insert0(int ii, const T *val)
222 {
223 ASSERT(ii >= 0 && ii <= GetCount());
224 if(data.GetCount() == 0) {
225 count++;
226 ClearCache();
227 if(slave) {
228 Slave()->Count(1);
229 Slave()->AddFirst();
230 }
231 if(val) {
232 data.Add().Add(*val);
233 return &data[0][0];
234 }
235 return &data.Add().Add();
236 }
237 int pos = ii;
238 int off;
239 int blki = FindBlock(pos, off);
240 return Insert0(ii, blki, pos, off, val);
241 }
242
243 template <class T>
244 template <class Range>
Insert_(int ii,const Range & r,bool def)245 void InVector<T>::Insert_(int ii, const Range& r, bool def)
246 {
247 int n = r.GetCount();
248
249 ASSERT(ii >= 0 && ii <= GetCount() && n >= 0 && !slave);
250
251 if(n <= 0)
252 return;
253
254 auto s = r.begin();
255
256 if(data.GetCount() == 0) {
257 int m = (blk_high + blk_low) / 2;
258 count = n;
259 while(n > 0) {
260 int n1 = min(m, n);
261 if(def)
262 data.Add().SetCount(n1);
263 else
264 data.Add().AppendRange(SubRange(s, n1));
265 s += n1;
266 n -= n1;
267 }
268 Reindex();
269 return;
270 }
271
272 int pos = ii;
273 int off;
274 int blki = FindBlock(pos, off);
275 int bc = data[blki].GetCount();
276
277 count += n;
278
279 if(bc + n < blk_high) { // block will not be bigger than threshold after insert
280 if(def)
281 data[blki].InsertN(pos, n);
282 else
283 data[blki].InsertRange(pos, SubRange(s, n));
284 Index(blki, n);
285 SetCache(blki, off);
286 }
287 else
288 if(bc - pos + n < blk_high) { // splitting into 2 blocks is enough
289 Vector<T>& t = data.Insert(blki + 1);
290 if(def)
291 t.InsertN(0, n);
292 else
293 t.InsertRange(0, SubRange(s, n));
294 t.InsertSplit(n, data[blki], pos);
295 data[blki].Shrink();
296 Reindex();
297 }
298 else { // need to insert several blocks
299 int m = (blk_high + blk_low) / 2;
300 int bn = (n + m - 1) / m;
301 int ti;
302 if(pos) { // need to split first block
303 ti = blki + 1; // TODO should add some of data to splitted blocks
304 data.InsertN(ti, bn + 1);
305 data[ti + bn].InsertSplit(0, data[blki], pos);
306 data[blki].Shrink();
307 }
308 else {
309 ti = blki;
310 data.InsertN(ti, bn);
311 }
312 for(int i = 0; i < bn; i++) {
313 int q = min(m, n);
314 if(def)
315 data[ti + i].SetCount(q);
316 else
317 data[ti + i].AppendRange(SubRange(s, q));
318 s += q;
319 n -= q;
320 }
321 ASSERT(n == 0);
322 Reindex();
323 }
324 #ifdef flagIVTEST
325 Check(0, 0);
326 #endif
327 }
328
329 template <class T>
Join(int blki)330 void InVector<T>::Join(int blki)
331 {
332 data[blki].AppendPick(pick(data[blki + 1]));
333 data.Remove(blki + 1);
334 }
335
336 template <class T>
JoinSmall(int blki)337 force_inline bool InVector<T>::JoinSmall(int blki)
338 {
339 if(blki < data.GetCount()) {
340 int n = data[blki].GetCount();
341 if(n == 0) {
342 if(slave)
343 Slave()->RemoveBlk(blki, 1);
344 data.Remove(blki);
345 return true;
346 }
347 if(n < blk_low) {
348 if(blki > 0 && data[blki - 1].GetCount() + n <= blk_high) {
349 if(slave)
350 Slave()->Join(blki - 1);
351 Join(blki - 1);
352 return true;
353 }
354 if(blki + 1 < data.GetCount() && n + data[blki + 1].GetCount() <= blk_high) {
355 if(slave)
356 Slave()->Join(blki);
357 Join(blki);
358 return true;
359 }
360 }
361 }
362 return false;
363 }
364
365 template <class T>
Remove(int pos,int n)366 void InVector<T>::Remove(int pos, int n)
367 {
368 ASSERT(pos >= 0 && pos + n <= GetCount());
369 if(n == 0)
370 return;
371 int off;
372 int blki = FindBlock(pos, off);
373 count -= n;
374 if(slave)
375 Slave()->Count(-n);
376 if(pos + n < data[blki].GetCount()) {
377 if(slave)
378 Slave()->Remove(blki, pos, n);
379 data[blki].Remove(pos, n);
380 if(JoinSmall(blki))
381 Reindex();
382 else {
383 if(slave)
384 Slave()->Index(blki, -n);
385 Index(blki, -n);
386 SetCache(blki, off);
387 }
388 }
389 else {
390 int b1 = blki;
391 int nn = min(n, data[b1].GetCount() - pos);
392 if(slave)
393 Slave()->Remove(b1, pos, nn);
394 data[b1++].Remove(pos, nn);
395 n -= nn;
396 int b2 = b1;
397 while(b2 < data.GetCount() && n >= data[b2].GetCount()) {
398 n -= min(n, data[b2].GetCount());
399 b2++;
400 }
401 if(slave)
402 Slave()->RemoveBlk(b1, b2 - b1);
403 data.Remove(b1, b2 - b1);
404 if(b1 < data.GetCount()) {
405 if(slave)
406 Slave()->Remove(b1, 0, n);
407 data[b1].Remove(0, n);
408 }
409 JoinSmall(blki + 1);
410 JoinSmall(blki);
411 Reindex();
412 }
413 #ifdef flagIVTEST
414 Check(0, 0);
415 #endif
416 }
417
418 template <class T>
SetCount(int n)419 void InVector<T>::SetCount(int n)
420 {
421 if(n < GetCount())
422 Trim(n);
423 else
424 InsertN(GetCount(), n - GetCount());
425 }
426
427 template <class T>
Shrink()428 void InVector<T>::Shrink()
429 {
430 for(int i = 0; i < data.GetCount(); i++)
431 data[i].Shrink();
432 data.Shrink();
433 for(int i = 0; i < index.GetCount(); i++)
434 index[i].Shrink();
435 index.Shrink();
436 }
437
438 template <class T>
Set(int i,const T & x,int count)439 void InVector<T>::Set(int i, const T& x, int count)
440 {
441 Iterator it = GetIter(i);
442 while(count-- > 0)
443 *it++ = x;
444 }
445
446 template <class T>
InVector(const InVector<T> & v,int)447 InVector<T>::InVector(const InVector<T>& v, int)
448 {
449 data <<= v.data;
450 index <<= v.index;
451 count = v.count;
452 hcount = v.hcount;
453 blk_high = v.blk_high;
454 blk_low = v.blk_low;
455 serial = NewInVectorSerial();
456 slave = v.slave;
457 }
458
459 template <class T>
Pick(InVector && v)460 void InVector<T>::Pick(InVector&& v)
461 {
462 data = pick(v.data);
463 index = pick(v.index);
464 count = v.count;
465 hcount = v.hcount;
466 blk_high = v.blk_high;
467 blk_low = v.blk_low;
468 serial = v.serial;
469 slave = v.slave;
470
471 v.Init();
472 }
473
474
475 template <class T>
476 template <class L>
FindUpperBound(const T & val,const L & less,int & off,int & pos) const477 int InVector<T>::FindUpperBound(const T& val, const L& less, int& off, int& pos) const
478 {
479 if(data.GetCount() == 0) {
480 pos = off = 0;
481 return 0;
482 }
483 int blki = 0;
484 int ii = 0;
485 int offset = 0;
486 int half = hcount;
487 for(int i = index.GetCount(); --i >= 0;) {
488 int m = blki + half;
489 if(m - 1 < data.GetCount() && !less(val, data[m - 1].Top())) {
490 blki = m;
491 offset += index[i][ii];
492 ii++;
493 }
494 ii += ii;
495 half >>= 1;
496 }
497 #ifdef flagIVTEST
498 Check(blki, offset);
499 #endif
500 if(blki < data.GetCount()) {
501 if(!less(val, data[blki].Top()))
502 offset += data[blki++].GetCount();
503 if(blki < data.GetCount()) {
504 pos = Upp::FindUpperBound(data[blki], val, less);
505 off = offset;
506 SetCache(blki, offset);
507 return blki;
508 }
509 }
510 pos = data.Top().GetCount();
511 off = count - pos;
512 blki--;
513 SetCache(blki, off);
514 return blki;
515 }
516
517 template <class T>
518 template <class L>
FindLowerBound(const T & val,const L & less,int & off,int & pos) const519 int InVector<T>::FindLowerBound(const T& val, const L& less, int& off, int& pos) const
520 {
521 if(data.GetCount() == 0) {
522 pos = off = 0;
523 return 0;
524 }
525 int blki = 0;
526 int ii = 0;
527 int offset = 0;
528 int half = hcount;
529 for(int i = index.GetCount(); --i >= 0;) {
530 int m = blki + half;
531 if(m < data.GetCount() && less(data[m][0], val)) {
532 blki = m;
533 offset += index[i][ii];
534 ii++;
535 }
536 ii += ii;
537 half >>= 1;
538 }
539 #ifdef flagIVTEST
540 Check(blki, offset);
541 #endif
542 if(blki < data.GetCount()) {
543 if(blki + 1 < data.GetCount() && less(data[blki + 1][0], val))
544 offset += data[blki++].GetCount();
545 if(blki < data.GetCount()) {
546 pos = Upp::FindLowerBound(data[blki], val, less);
547 off = offset;
548 SetCache(blki, offset);
549 return blki;
550 }
551 }
552 pos = data.Top().GetCount();
553 off = count - pos;
554 blki--;
555 SetCache(blki, off);
556 return blki;
557 }
558
559 template <class T>
560 template <class L>
InsertUpperBound(const T & val,const L & less)561 int InVector<T>::InsertUpperBound(const T& val, const L& less)
562 {
563 if(data.GetCount() == 0) {
564 count++;
565 ClearCache();
566 if(slave) {
567 Slave()->Count(1);
568 Slave()->AddFirst();
569 }
570 data.Add().Insert(0) = val;
571 return 0;
572 }
573 int off;
574 int pos;
575 int blki = FindUpperBound(val, less, off, pos);
576 Insert0(off + pos, blki, pos, off, &val);
577 return off + pos;
578 }
579
580 template <class T>
581 template <class L>
Find(const T & val,const L & less) const582 int InVector<T>::Find(const T& val, const L& less) const
583 {
584 int i = FindLowerBound(val, less);
585 return i < GetCount() && !less(val, (*this)[i]) ? i : -1;
586 }
587
588
589 template <class T>
SetIter(ConstIterator & it,int ii) const590 void InVector<T>::SetIter(ConstIterator& it, int ii) const
591 {
592 if(count) {
593 it.v = this;
594 it.blki = FindBlock(ii, it.offset);
595 it.begin = data[it.blki].Begin();
596 it.end = data[it.blki].End();
597 it.ptr = it.begin + ii;
598 }
599 else
600 SetEnd(it);
601 }
602
603 template <class T>
SetBegin(ConstIterator & it) const604 void InVector<T>::SetBegin(ConstIterator& it) const
605 {
606 if(count) {
607 it.v = this;
608 it.blki = 0;
609 it.ptr = it.begin = data[0].Begin();
610 it.end = data[0].End();
611 it.offset = 0;
612 }
613 else
614 SetEnd(it);
615 }
616
617 template <class T>
SetEnd(ConstIterator & it) const618 void InVector<T>::SetEnd(ConstIterator& it) const
619 {
620 if(count) {
621 it.v = this;
622 it.blki = data.GetCount() - 1;
623 it.begin = data.Top().Begin();
624 it.ptr = it.end = data.Top().End();
625 it.offset = count - data.Top().GetCount();
626 }
627 else {
628 it.v = this;
629 it.blki = 0;
630 it.ptr = it.begin = it.end = NULL;
631 it.offset = 0;
632 }
633 }
634
635 template <typename T>
operator +=(int d)636 force_inline typename InVector<T>::ConstIterator& InVector<T>::ConstIterator::operator+=(int d)
637 {
638 if(d >= 0 ? d < end - ptr : -d < ptr - begin)
639 ptr += d;
640 else
641 v->SetIter(*this, GetIndex() + d);
642 ASSERT(end - begin == v->data[blki].GetCount());
643 return *this;
644 }
645
646 template <typename T>
NextBlk()647 void InVector<T>::ConstIterator::NextBlk()
648 {
649 ASSERT(end - begin == v->data[blki].GetCount());
650 if(blki + 1 < v->data.GetCount()) {
651 offset += v->data[blki].GetCount();
652 ++blki;
653 ptr = begin = v->data[blki].Begin();
654 end = v->data[blki].End();
655 }
656 }
657
658 template <typename T>
PrevBlk()659 void InVector<T>::ConstIterator::PrevBlk()
660 {
661 --blki;
662 begin = v->data[blki].Begin();
663 ptr = end = v->data[blki].End();
664 offset -= v->data[blki].GetCount();
665 }
666
667 template <typename T>
Swap(InVector & b)668 void InVector<T>::Swap(InVector& b)
669 {
670 Upp::Swap(data, b.data);
671 Upp::Swap(index, b.index);
672 Upp::Swap(count, b.count);
673 Upp::Swap(hcount, b.hcount);
674 Upp::Swap(serial, b.serial);
675 Upp::Swap(blk_high, b.blk_high);
676 Upp::Swap(blk_low, b.blk_low);
677 Upp::Swap(slave, b.slave);
678 }
679
680 template <class T>
Xmlize(XmlIO & xio,const char * itemtag)681 void InVector<T>::Xmlize(XmlIO& xio, const char *itemtag)
682 {
683 XmlizeContainer(xio, itemtag, *this);
684 }
685
686 template <class T>
Jsonize(JsonIO & jio)687 void InVector<T>::Jsonize(JsonIO& jio)
688 {
689 JsonizeArray<InVector<T>>(jio, *this);
690 }
691
692 template <class T>
ToString() const693 String InVector<T>::ToString() const
694 {
695 return AsStringArray(*this);
696 }
697
698 template <class T>
DumpIndex() const699 void InVector<T>::DumpIndex() const
700 {
701 String h;
702 RLOG("------- InVector dump, count: " << GetCount() << ", index depth: " << index.GetCount());
703 int64 alloc = 0;
704 for(int i = 0; i < data.GetCount(); i++) {
705 if(i)
706 h << ", ";
707 h << data[i].GetCount() << " (" << data[i].GetAlloc() << ")";
708 alloc += data[i].GetAlloc();
709 }
710 RLOG("Data blocks: " << data.GetCount() << ", sizeof: " << data.GetCount() * sizeof(Vector<T>));
711 RLOG("Total alloc: " << alloc);
712 RLOG(h);
713 for(int j = 0; j < index.GetCount(); j++) {
714 h.Clear();
715 h << index[j].GetCount() << ": ";
716 for(int k = 0; k < index[j].GetCount(); k++) {
717 if(k)
718 h << ", ";
719 h << index[j][k];
720 }
721 RLOG(h);
722 }
723 RLOG(".");
724 }
725
726 #ifdef flagIVTEST
727 template <class T>
Check(int blki,int offset) const728 void InVector<T>::Check(int blki, int offset) const
729 {
730 int off = 0;
731 int all = 0;
732 for(int i = 0; i < data.GetCount(); i++) {
733 if(i < blki)
734 off += data[i].GetCount();
735 all += data[i].GetCount();
736 }
737 ASSERT(off == offset);
738 ASSERT(all == count);
739 }
740 #endif
741
742 template <class T>
Delete(IVIter it,int count)743 void InArray<T>::Delete(IVIter it, int count)
744 {
745 ASSERT(count >= 0);
746 while(count--)
747 delete (T *)*it++;
748 }
749
750 template <class T>
Delete(int i,int count)751 void InArray<T>::Delete(int i, int count)
752 {
753 Delete(iv.GetIter(i), count);
754 }
755
756 template <class T>
Init(int i,int count)757 void InArray<T>::Init(int i, int count)
758 {
759 ASSERT(count >= 0);
760 IVIter it = iv.GetIter(i);
761 while(count--)
762 *it++ = new T;
763 }
764
765 template <class T>
InsertN(int i,int count)766 void InArray<T>::InsertN(int i, int count)
767 {
768 iv.InsertN(i, count);
769 Init(i, count);
770 }
771
772 template <class T>
773 template <class Range>
InsertRange(int i,const Range & r)774 void InArray<T>::InsertRange(int i, const Range& r)
775 {
776 int count = r.GetCount();
777 iv.InsertN(i, count);
778 IVIter it = iv.begin() + i;
779 auto s = r.begin();
780 while(count--)
781 *it++ = new T(*s++);
782 }
783
784 template <class T>
Remove(int i,int count)785 void InArray<T>::Remove(int i, int count)
786 {
787 Delete(i, count);
788 iv.Remove(i, count);
789 }
790
791 template <class T>
SetCount(int n)792 void InArray<T>::SetCount(int n)
793 {
794 if(n < GetCount())
795 Trim(n);
796 else
797 InsertN(GetCount(), n - GetCount());
798 }
799
800 template <class T>
Clear()801 void InArray<T>::Clear()
802 {
803 Free();
804 iv.Clear();
805 }
806
807 template <class T>
Set(int i,const T & x,int count)808 void InArray<T>::Set(int i, const T& x, int count)
809 {
810 Iterator it = GetIter(i);
811 while(count-- > 0)
812 *it++ = x;
813 }
814
815 template <class T>
SetIter(ConstIterator & it,int ii) const816 void InArray<T>::SetIter(ConstIterator& it, int ii) const
817 {
818 it.it = iv.GetIter(ii);
819 }
820
821 template <class T>
SetBegin(ConstIterator & it) const822 void InArray<T>::SetBegin(ConstIterator& it) const
823 {
824 it.it = iv.Begin();
825 }
826
827 template <class T>
SetEnd(ConstIterator & it) const828 void InArray<T>::SetEnd(ConstIterator& it) const
829 {
830 it.it = iv.End();
831 }
832
833 template <class T>
InArray(const InArray & v,int)834 InArray<T>::InArray(const InArray& v, int)
835 {
836 int n = v.GetCount();
837 iv.SetCount(v.GetCount());
838 ConstIterator s = v.Begin();
839 IVIter it = iv.Begin();
840 while(n--)
841 *it++ = new T(clone(*s++));
842 }
843
844 #ifdef UPP
845 template <class T>
Xmlize(XmlIO & xio,const char * itemtag)846 void InArray<T>::Xmlize(XmlIO& xio, const char *itemtag)
847 {
848 XmlizeContainer(xio, itemtag, *this);
849 }
850
851 template <class T>
Jsonize(JsonIO & jio)852 void InArray<T>::Jsonize(JsonIO& jio)
853 {
854 JsonizeArray<InArray<T>>(jio, *this);
855 }
856
857 template <class T>
ToString() const858 String InArray<T>::ToString() const
859 {
860 return AsStringArray(*this);
861 }
862
863 #endif
864
865 #ifdef LLOG
866 #undef LLOG
867 #endif