Evo C++ Library v0.5.1
list.h
Go to the documentation of this file.
1 // Evo C++ Library
2 /* Copyright 2019 Justin Crowell
3 Distributed under the BSD 2-Clause License -- see included file LICENSE.txt for details.
4 */
6 
7 #pragma once
8 #ifndef INCL_evo_list_h
9 #define INCL_evo_list_h
10 
11 #include "impl/container.h"
12 #include "impl/iter.h"
13 
14 // Disable certain MSVC warnings for this file
15 #if defined(_MSC_VER)
16  #pragma warning(push)
17  #pragma warning(disable:4458)
18 #endif
19 
20 namespace evo {
23 
25 
239 template<class T,class TSize=SizeT>
240 class List : public ListBase<T,TSize> {
241 protected:
242  using ListBase<T,TSize>::data_; // Slice data pointer, NULL if null, EVO_PEMPTY if empty (null/empty: buffer unused, no reference)
243  using ListBase<T,TSize>::size_; // Slice size, 0 if empty
244 
245 public:
247  typedef TSize Size;
248  typedef Size Key;
249  typedef T Value;
250  typedef T Item;
251  typedef typename DataCopy<T>::PassType ItemVal;
252 
256 
257  // Iterator support types
259  typedef Key IterKey;
260  typedef T IterItem;
265 
271  struct Edit {
272  T* ptr;
273  Size size;
274  void* header;
275 
277  Edit() : ptr(NULL), size(0), header(NULL)
278  { }
279 
281  ~Edit() {
282  if (header != NULL)
283  ::free(header);
284  }
285 
287  void clear() {
288  if (header != NULL) {
289  ::free(header);
290  header = NULL;
291  }
292  ptr = NULL;
293  size = 0;
294  }
295 
307  Size write(const ListBaseType& src, Size start=0, Size count=ALL) {
308  if (start < src.size_ && count > 0) {
309  const Size maxcount = src.size_ - start;
310  if (count > maxcount)
311  count = maxcount;
312  DataInit<Item>::init(ptr + size, src.data_, count);
313  size += count;
314  } else
315  count = 0;
316  return count;
317  }
318 
329  Size write(const Item* data, Size count) {
330  if (count > 0) {
331  assert( data != NULL );
332  DataInit<Item>::init(ptr + size, data, count);
333  size += count;
334  }
335  return count;
336  }
337  };
338 
340  List() {
341  data_ = NULL;
342  size_ = 0;
343  #if EVO_LIST_OPT_REFTERM
344  terminated_ = false;
345  #endif
346  }
347 
351  explicit List(const ValEmpty& val) {
352  EVO_PARAM_UNUSED(val);
353  data_ = EVO_PEMPTY;
354  size_ = 0;
355  #if EVO_LIST_OPT_REFTERM
356  terminated_ = false;
357  #endif
358  }
359 
365  List(const ListType& data) {
366  data_ = NULL;
367  size_ = 0;
368  #if EVO_LIST_OPT_REFTERM
369  terminated_ = false;
370  #endif
371  ref(data);
372  }
373 
381  List(const ListType& data, Key index, Key size=ALL) {
382  data_ = NULL;
383  size_ = 0;
384  #if EVO_LIST_OPT_REFTERM
385  terminated_ = false;
386  #endif
387  ref(data, index, size);
388  }
389 
397  List(const ListBaseType& data, Key index=0, Key size=ALL) {
398  size_ = 0;
399  #if EVO_LIST_OPT_REFTERM
400  terminated_ = false;
401  #endif
402  if (data.data_ == NULL) {
403  data_ = NULL;
404  } else if (index < data.size_) {
405  const Size max_size = data.size_ - index;
406  if (size > max_size)
407  size = max_size;
408  if (size > 0)
409  copy(data.data_+index, size);
410  else
411  data_ = EVO_PEMPTY;
412  } else
413  data_ = EVO_PEMPTY;
414  }
415 
423  List(const ListBaseType* data, Key index=0, Key size=ALL) {
424  size_ = 0;
425  #if EVO_LIST_OPT_REFTERM
426  terminated_ = false;
427  #endif
428  if (data == NULL || data->data_ == NULL) {
429  data_ = NULL;
430  } else if (index < data->size_) {
431  const Size max_size = data->size_ - index;
432  if (size > max_size)
433  size = max_size;
434  if (size > 0)
435  copy(data->data_+index, size);
436  else
437  data_ = EVO_PEMPTY;
438  } else
439  data_ = EVO_PEMPTY;
440  }
441 
448  List(const Item* data, Size size) {
449  data_ = NULL;
450  size_ = 0;
451  #if EVO_LIST_OPT_REFTERM
452  terminated_ = false;
453  #endif
454  if (data != NULL)
455  ref(data, size);
456  }
457 
462  List(const PtrBase<Item>& data, Size size) {
463  data_ = NULL;
464  size_ = 0;
465  #if EVO_LIST_OPT_REFTERM
466  terminated_ = false;
467  #endif
468  if (data.ptr_ != NULL)
469  copy(data.ptr_, size);
470  }
471 
472 #if defined(EVO_CPP11)
473 
476  List(std::initializer_list<T> init) : List() {
477  assert( init.size() < IntegerT<Size>::MAX );
478  modAppend(NULL, (Size)init.size());
479  T* item = data_;
480  for (auto& val : init)
481  new(item++) T(val);
482  }
483 
487  List(ListType&& src) {
488  ::memcpy(this, &src, sizeof(ListType));
489  ::memset(&src, 0, sizeof(ListType));
490  }
491 
496  ListType& operator=(ListType&& src) {
497  clear();
498  capacity(0);
499  ::memcpy(this, &src, sizeof(ListType));
500  ::memset(&src, 0, sizeof(ListType));
501  return *this;
502  }
503 #endif
504 
510  const ListType& asconst() const {
511  return *this;
512  }
513 
514  // SET
515 
522  ListType& operator=(const ListType& data)
523  { return set(data); }
524 
531  ListType& operator=(const ListBaseType& data) {
532  if (data.data_ == NULL)
533  set();
534  else if (data.size_ > 0)
535  copy(data.data_, data.size_);
536  else
537  setempty();
538  return *this;
539  }
540 
550  ListType& operator=(const ValNull&)
551  { return set(); }
552 
560  ListType& operator=(const ValEmpty&)
561  { clear(); data_ = EVO_PEMPTY; return *this; }
562 
574  ListType& clear() {
575  if (data_ > EVO_PEMPTY) {
576  if (buf_.ptr != NULL) {
577  assert( buf_.header != NULL );
578  if (buf_.header->refs > 1) {
579  // Detach from shared
580  --buf_.header->refs;
581  buf_.header = NULL;
582  buf_.ptr = NULL;
583  data_ = EVO_PEMPTY;
584  } else if (buf_.header->used > 0) {
585  // Clear buffer, leave buffer for later use
586  assert( buf_.header->refs == 1 );
588  buf_.header->used = 0;
589  data_ = buf_.ptr;
590  }
591  } else {
592  data_ = EVO_PEMPTY;
593  #if !EVO_LIST_OPT_LAZYBUF
594  // Lazy buffer disabled
595  assert( buf_.header == NULL );
596  #endif
597  }
598  size_ = 0;
599  #if EVO_LIST_OPT_REFTERM
600  terminated_ = false;
601  #endif
602  }
603  #if !EVO_LIST_OPT_LAZYBUF
604  // Lazy buffer disabled
605  assert( (buf_.header != NULL) == (buf_.ptr != NULL) );
606  #endif
607  return *this;
608  }
609 
620  ListType& set()
621  { clear(); data_ = NULL; return *this; }
622 
630  ListType& set(const Item* data, Size size)
631  { ref(data, size); return *this; }
632 
639  ListType& set(const PtrBase<Item>& data, Size size) {
640  if (data.ptr_ == NULL)
641  set();
642  else
643  copy(data.ptr_, size);
644  return *this;
645  }
646 
653  ListType& set(const ListType& data)
654  { ref(data); return *this; }
655 
664  ListType& set(const ListType& data, Key index, Key size=ALL)
665  { ref(data, index, size); return *this; }
666 
675  ListType& set(const ListBaseType& data, Key index=0, Key size=ALL) {
676  if (data.data_ == NULL)
677  set();
678  else if (index < data.size_) {
679  const Size max_size = data.size_ - index;
680  if (size > max_size)
681  size = max_size;
682  if (size > 0)
683  copy(data.data_+index, size);
684  else
685  setempty();
686  } else
687  setempty();
688  return *this;
689  }
690 
700  ListType& set2(const ListType& data, Key index1, Key index2)
701  { ref(data, index1, (index1<index2?index2-index1:0)); return *this; }
702 
711  ListType& set2(const ListBaseType& data, Key index1, Key index2) {
712  if (data.data_ == NULL) {
713  set();
714  } else {
715  if (index2 > data.size_)
716  index2 = data.size_;
717  if (index1 < data.size_ && index2 > index1)
718  copy(data.data_+index1, (index2-index1));
719  else
720  setempty();
721  }
722  return *this;
723  }
724 
735  ListType& setempty()
736  { clear(); data_ = EVO_PEMPTY; return *this; }
737 
738  // INFO
739 
745  bool null() const
746  { return (data_ == NULL); }
747 
753  bool empty() const
754  { return (size_ == 0); }
755 
759  Size size() const
760  { return size_; }
761 
767  bool shared() const
768  { return (buf_.ptr == NULL ? (size_ > 0) : (buf_.header->refs > 1)); }
769 
777  Size capacity() const
778  { return (buf_.header == NULL ? 0 : buf_.header->size); }
779 
786  const Item* data() const
787  { return data_; }
788 
795  const Item& operator[](Key index) const
796  { assert( index < size_ ); return data_[index]; }
797 
804  const Item& item(Key index) const
805  { assert( index < size_ ); return data_[index]; }
806 
810  const Item* first() const
811  { return (size_ > 0 ? data_ : NULL); }
812 
816  const Item* last() const
817  { return (size_ > 0 ? data_+size_-1 : NULL); }
818 
826  Key iend(Size offset=0) const
827  { return (offset < size_ ? size_-1-offset : END); }
828 
833  ulong hash(ulong seed=0) const
834  { return DataHash<T>::hash(data_, size_, seed); }
835 
836  // COMPARE
837 
842  int compare(const ListBaseType& data) const {
843  int result;
844  if (data_ == NULL)
845  result = (data.data_ == NULL ? 0 : -1);
846  else if (data.data_ == NULL)
847  result = 1;
848  else
849  result = DataCompare<T>::compare(data_, size_, data.data_, data.size_);
850  return result;
851  }
852 
857  bool operator==(const ListBaseType& data) const {
858  bool result;
859  if (data_ == NULL)
860  result = (data.data_ == NULL);
861  else if (data.data_ == NULL || size_ != data.size_)
862  result = false;
863  else if (size_ == 0 || data_ == data.data_) {
864  result = true;
865  } else
866  result = DataEqual<T>::equal(data_, data.data_, data.size_);
867  return result;
868  }
869 
874  bool operator!=(const ListBaseType& data) const {
875  bool result;
876  if (data_ == NULL)
877  result = (data.data_ != NULL);
878  else if (data.data_ == NULL || size_ != data.size_)
879  result = true;
880  else if (size_ == 0 || data_ == data.data_) {
881  result = false;
882  } else
883  result = !DataEqual<T>::equal(data_, data.data_, data.size_);
884  return result;
885  }
886 
893  bool starts(ItemVal item) const
894  { return (size_ > 0 && data_[0] == item); }
895 
903  bool starts(const Item* items, Size size) const
904  { return (size > 0 && size_ >= size && DataEqual<T>::equal(data_, items, size)); }
905 
912  bool starts(const ListBaseType& items) const
913  { return (items.size_ > 0 && size_ >= items.size_ && DataEqual<T>::equal(data_, items.data_, items.size_)); }
914 
921  bool ends(ItemVal item) const
922  { return (size_ > 0 && data_[size_-1] == item); }
923 
931  bool ends(const Item* items, Size size) const
932  { return (size > 0 && size_ >= size && DataEqual<T>::equal(data_+(size_-size), items, size)); }
933 
940  bool ends(const ListBaseType& items) const
941  { return (items.size_ > 0 && size_ >= items.size_ && DataEqual<T>::equal(data_+(size_-items.size_), items.data_, items.size_)); }
942 
943  // FIND
944 
951  Iter cbegin() const
952  { return Iter(*this); }
953 
961  Iter cend() const
962  { return Iter(); }
963 
971  IterM begin()
972  { return IterM(*this); }
973 
980  Iter begin() const
981  { return Iter(*this); }
982 
990  IterM end()
991  { return IterM(); }
992 
1000  Iter end() const
1001  { return Iter(); }
1002 
1013  Key find(ItemVal item, Key start=0, Key end=END) const {
1014  if (end > size_)
1015  end = size_;
1016  for (; start < end; ++start)
1017  if (data_[start] == item)
1018  return start;
1019  return NONE;
1020  }
1021 
1032  Key findr(ItemVal item, Key start=0, Key end=END) const {
1033  if (end > size_)
1034  end = size_;
1035  while (end > start)
1036  if (data_[--end] == item)
1037  return end;
1038  return NONE;
1039  }
1040 
1051  Key findany(const Item* items, Size count, Key start=0, Key end=END) const {
1052  Size j;
1053  if (end > size_)
1054  end = size_;
1055  for (; start < end; ++start)
1056  for (j=0; j<count; ++j)
1057  if (data_[start] == items[j])
1058  return start;
1059  return NONE;
1060  }
1061 
1073  Key findanyr(const Item* items, Size count, Key start=0, Key end=END) const {
1074  Size j;
1075  if (end > size_)
1076  end = size_;
1077  while (end>start) {
1078  --end;
1079  for (j=0; j < count; ++j)
1080  if (data_[end] == items[j])
1081  return end;
1082  }
1083  return NONE;
1084  }
1085 
1092  bool contains(ItemVal item) const {
1093  bool result = false;
1094  for (Key i=0; i < size_; ++i)
1095  if (data_[i] == item)
1096  { result = true; break; }
1097  return result;
1098  }
1099 
1107  bool contains(const Item* data, Size size) const {
1108  bool result = false;
1109  if (size > 0 && size_ >= size) {
1110  const Size end = size_ - size;
1111  for (Key i=0; i <= end; ++i)
1112  if (DataEqual<T>::equal(data_+i, data, size))
1113  { result = true; break; }
1114  }
1115  return result;
1116  }
1117 
1124  bool contains(const ListBaseType& data) const {
1125  bool result = false;
1126  if (data.size_ > 0 && size_ >= data.size_) {
1127  const Size end = size_ - data.size_;
1128  for (Key i=0; i <= end; ++i)
1129  if (DataEqual<T>::equal(data_+i, data.data_, data.size_))
1130  { result = true; break; }
1131  }
1132  return result;
1133  }
1134 
1135  // SPLIT
1136 
1150  template<class T1,class T2>
1151  bool splitat(Key index, T1& left, T2& right) const {
1152  bool result;
1153  if (index >= size_) {
1154  left.set(*this);
1155  right.set();
1156  result = false;
1157  } else {
1158  left.set(*this, 0, index);
1159  right.set(*this, index+1, ALL);
1160  result = true;
1161  }
1162  return result;
1163  }
1164 
1176  template<class T1>
1177  bool splitat(Key index, T1& left) const {
1178  bool result;
1179  if (index >= size_) {
1180  left.set(*this);
1181  result = false;
1182  } else {
1183  left.set(*this, 0, index);
1184  result = true;
1185  }
1186  return result;
1187  }
1188 
1201  template<class T2>
1202  bool splitat(Key index, ValNull left, T2& right) const {
1203  EVO_PARAM_UNUSED(left);
1204  bool result;
1205  if (index >= size_) {
1206  right.set();
1207  result = false;
1208  } else {
1209  right.set(*this, index+1, ALL);
1210  result = true;
1211  }
1212  return result;
1213  }
1214 
1215  // SPLIT_SET
1216 
1224  bool splitat_setl(Key index) {
1225  bool result;
1226  if (index >= size_) {
1227  result = false;
1228  } else {
1229  slice(0, index);
1230  result = true;
1231  }
1232  return result;
1233  }
1234 
1243  template<class T2>
1244  bool splitat_setl(Key index, T2& right) {
1245  bool result;
1246  if (index >= size_) {
1247  right.set();
1248  result = false;
1249  } else {
1250  right.set(*this, index+1, ALL);
1251  slice(0, index);
1252  result = true;
1253  }
1254  return result;
1255  }
1256 
1264  bool splitat_setr(Key index) {
1265  bool result;
1266  if (index >= size_) {
1267  set();
1268  result = false;
1269  } else {
1270  slice(index+1, ALL);
1271  result = true;
1272  }
1273  return result;
1274  }
1275 
1284  template<class T1>
1285  bool splitat_setr(Key index, T1& left) {
1286  bool result;
1287  if (index >= size_) {
1288  left.set(*this);
1289  set();
1290  result = false;
1291  } else {
1292  left.set(*this, 0, index);
1293  slice(index+1, ALL);
1294  result = true;
1295  }
1296  return result;
1297  }
1298 
1299  // TRIM
1300 
1307  ListType& triml(Size size) {
1308  if (size > size_)
1309  size = size_;
1310  if (size > 0) {
1311  size_ -= size;
1312  data_ += size;
1313  }
1314  return *this;
1315  }
1316 
1323  ListType& trimr(Size size) {
1324  if (size > 0) {
1325  if (size < size_)
1326  size_ -= size;
1327  else
1328  size_ = 0;
1329  #if EVO_LIST_OPT_REFTERM
1330  terminated_ = false;
1331  #endif
1332  }
1333  return *this;
1334  }
1335 
1342  ListType& truncate(Size size=0) {
1343  if (size < size_) {
1344  size_ = size;
1345  #if EVO_LIST_OPT_REFTERM
1346  terminated_ = false;
1347  #endif
1348  }
1349  return *this;
1350  }
1351 
1352  // SLICE
1353 
1360  ListType& slice(Key index) {
1361  if (index > 0) {
1362  if (index >= size_) {
1363  // Empty end slice
1364  data_ = data_ + size_;
1365  size_ = 0;
1366  } else {
1367  // Normal slice
1368  data_ = data_ + index;
1369  size_ -= index;
1370  }
1371  }
1372  return *this;
1373  }
1374 
1382  ListType& slice(Key index, Size size) {
1383  if (index > 0) {
1384  if (index >= size_) {
1385  // Empty end slice
1386  size_ = 0;
1387  #if EVO_LIST_OPT_REFTERM
1388  terminated_ = false;
1389  #endif
1390  } else {
1391  // Normal slice
1392  data_ = data_ + index;
1393  size_ -= index;
1394  if (size < size_) {
1395  size_ = size;
1396  #if EVO_LIST_OPT_REFTERM
1397  terminated_ = false;
1398  #endif
1399  }
1400  }
1401  } else if (size < size_) {
1402  size_ = size;
1403  #if EVO_LIST_OPT_REFTERM
1404  terminated_ = false;
1405  #endif
1406  }
1407  return *this;
1408  }
1409 
1418  ListType& slice2(Key index1, Key index2)
1419  { return slice(index1, (index1 < index2 ? index2-index1 : 0)); }
1420 
1427  ListType& unslice() {
1428  if (buf_.ptr != NULL && buf_.header->used > size_) {
1429  if (buf_.header->refs > 1) {
1430  // New buffer, was shared
1431  --buf_.header->refs;
1432  if (size_ > 0) {
1433  assert( data_ != NULL );
1436  data_ = buf_.ptr;
1437  } else {
1438  buf_.header = NULL;
1439  buf_.ptr = NULL;
1440  data_ = EVO_PEMPTY;
1441  }
1442  } else {
1443  // Existing buffer, unslice
1444  assert( buf_.header->refs == 1 );
1445  assert( buf_.header->used > 0 );
1446  unsliceBuffer(size_);
1447  }
1448  #if EVO_LIST_OPT_REFTERM
1449  terminated_ = false;
1450  #endif
1451  }
1452  return *this;
1453  }
1454 
1455  // INFO_SET
1456 
1464  T* dataM()
1465  { unshare(); return data_; }
1466 
1475  T& operator()(Key index)
1476  { assert( index < size_ ); unshare(); return data_[index]; }
1477 
1487  T& itemM(Key index)
1488  { assert( index < size_ ); unshare(); return data_[index]; }
1489 
1495  Item* firstM()
1496  { unshare(); return (size_ > 0 ? data_ : NULL); }
1497 
1503  Item* lastM()
1504  { unshare(); return (size_ > 0 ? data_+size_-1 : NULL); }
1505 
1516  ListType& capacity(Size size) {
1517  #if !EVO_LIST_OPT_LAZYBUF
1518  // Lazy buffer disabled
1519  assert( (buf_.header != NULL) == (buf_.ptr != NULL) );
1520  #endif
1521  if (buf_.header != NULL) {
1522  #if EVO_LIST_OPT_LAZYBUF
1523  if (buf_.ptr == NULL) {
1524  // Existing buffer, unused
1525  assert( buf_.header->used == 0 );
1526  assert( buf_.header->refs == 1 );
1527  if (buf_.header->size != size) {
1528  if (size_ > size) {
1529  size_ = size;
1530  #if EVO_LIST_OPT_REFTERM
1531  terminated_ = false;
1532  #endif
1533  }
1534  buf_.memfree();
1535  if (size > 0)
1536  buf_.memalloc(size, 0, buf_.header);
1537  else {
1538  buf_.header = NULL;
1539  if (data_ != NULL)
1540  data_ = EVO_PEMPTY;
1541  }
1542  }
1543  } else
1544  #else
1545  // Lazy buffer disabled
1546  assert( buf_.ptr != NULL );
1547  #endif
1548  if (buf_.header->refs == 1) {
1549  // Existing buffer
1550  if (buf_.header->size != size) {
1551  if (size > 0) {
1552  if (buf_.header->used > 0) {
1553  unsliceBuffer(size_);
1554  if (size < size_) {
1555  // Shrinking capacity, removing items
1556  DataInit<T>::uninit(buf_.ptr+size, buf_.header->used-size);
1557  buf_.ptr = buf_.memrealloc(size);
1558  buf_.header->used = size;
1559  size_ = size;
1560  #if EVO_LIST_OPT_REFTERM
1561  terminated_ = false;
1562  #endif
1563  } else
1564  // Resizing without affecting items
1565  buf_.ptr = buf_.memrealloc(size);
1566  data_ = buf_.ptr;
1567  } else {
1568  // Empty, resizing buffer
1569  buf_.ptr = buf_.memrealloc(size);
1570  if (data_ != NULL)
1571  data_ = buf_.ptr;
1572  }
1573  } else {
1574  buf_.free();
1575  buf_.clear();
1576  if (data_ != NULL)
1577  data_ = EVO_PEMPTY;
1578  size_ = 0;
1579  #if EVO_LIST_OPT_REFTERM
1580  terminated_ = false;
1581  #endif
1582  }
1583  }
1584  } else {
1585  // Shared buffer
1586  assert( buf_.header->refs > 1);
1587  --buf_.header->refs;
1588  if (size > 0) {
1589  if (size_ > size)
1590  size_ = size;
1591  buf_.ptr = buf_.memalloc(size, size_, buf_.header);
1592  if (size_ > 0)
1594  data_ = buf_.ptr;
1595  } else {
1596  assert( data_ != NULL );
1597  buf_.clear();
1598  data_ = EVO_PEMPTY;
1599  size_ = 0;
1600  }
1601  #if EVO_LIST_OPT_REFTERM
1602  terminated_ = false;
1603  #endif
1604  }
1605  } else {
1606  // New buffer, leave unused
1607  assert( buf_.ptr == NULL );
1608  if (size_ > size) {
1609  size_ = size;
1610  #if EVO_LIST_OPT_REFTERM
1611  terminated_ = false;
1612  #endif
1613  }
1614  if (size > 0) {
1615  #if EVO_LIST_OPT_LAZYBUF
1616  buf_.memalloc(size, 0, buf_.header);
1617  #else
1618  // Lazy buffer disabled so use buffer
1619  buf_.ptr = buf_.memalloc(size, size_, buf_.header);
1620  if (size_ > 0) {
1622  data_ = buf_.ptr;
1623  } else if (data_ != NULL)
1624  data_ = buf_.ptr;
1625  #if EVO_LIST_OPT_REFTERM
1626  terminated_ = false;
1627  #endif
1628  #endif
1629  } else if (data_ != NULL)
1630  data_ = EVO_PEMPTY;
1631  }
1632  assert( size_ <= size );
1633  assert( size > 0 || data_ == NULL || data_ == EVO_PEMPTY );
1634  #if !EVO_LIST_OPT_LAZYBUF
1635  // Lazy buffer disabled
1636  assert( (buf_.header != NULL) == (buf_.ptr != NULL) );
1637  #endif
1638  return *this;
1639  }
1640 
1650  ListType& capacitymin(Size min) {
1651  if (buf_.header == NULL)
1652  capacity(size_ > min ? size_ : min);
1653  else if (min > buf_.header->size)
1654  capacity(min);
1655  return *this;
1656  }
1657 
1668  ListType& capacitymax(Size max) {
1669  if (buf_.header != NULL && buf_.header->size > max)
1670  capacity(max);
1671  else if (size_ > max) {
1672  size_ = max;
1673  #if EVO_LIST_OPT_REFTERM
1674  terminated_ = false;
1675  #endif
1676  }
1677  return *this;
1678  }
1679 
1686  ListType& compact() {
1687  if (buf_.header != NULL && buf_.header->refs == 1) {
1688  const Size min = size_ + CONSERVE;
1689  if (buf_.header->size > min)
1690  capacity(min);
1691  }
1692  return *this;
1693  }
1694 
1703  ListType& reserve(Size size, bool prefer_realloc=false) {
1704  const Size minsize = size_ + size;
1705  if (buf_.header != NULL) {
1706  #if EVO_LIST_OPT_LAZYBUF
1707  if (buf_.ptr == NULL) {
1708  if (buf_.header->size >= minsize) {
1709  // Use previous buffer
1710  assert( buf_.header->refs == 1 );
1711  assert( buf_.header->used == 0 );
1712  buf_.ptr = (Item*)(buf_.header + 1);
1713  if (size_ > 0)
1715  buf_.header->used = size_;
1716  data_ = buf_.ptr;
1717  #if EVO_LIST_OPT_REFTERM
1718  terminated_ = false;
1719  #endif
1720  return *this;
1721  } else {
1722  // Previous buffer not big enough, free it
1723  buf_.memfree();
1724  buf_.header = NULL;
1725  }
1726  } else
1727  #else
1728  // Lazy buffer disabled
1729  assert( buf_.ptr != NULL );
1730  #endif
1731  if (buf_.header->refs > 1) {
1732  // New buffer, was shared
1733  assert( buf_.ptr != NULL );
1734  --buf_.header->refs;
1735  } else {
1736  // Already unique, ensure buffer is ready, unslice if sliced
1737  assert( buf_.header->refs == 1 );
1738  assert( buf_.ptr != NULL );
1739  if (minsize > buf_.header->size) {
1740  if (data_ < buf_.ptr) {
1741  // Realloc previous buffer
1742  data_ = buf_.ptr = buf_.memrealloc(minsize);
1743  } else if (prefer_realloc || data_ == buf_.ptr) {
1744  // Either not sliced or prefer realloc
1745  assert( data_ >= buf_.ptr && data_ <= buf_.ptr+buf_.header->used );
1746  const Size offset = (Size)(data_ - buf_.ptr);
1747  buf_.ptr = buf_.memrealloc(minsize);
1748  data_ = buf_.ptr + offset;
1749  } else
1750  goto newbuf; // unslice and move to new buffer (below)
1751  } else if (data_ <= EVO_PEMPTY)
1752  data_ = buf_.ptr;
1753  return *this;
1754  }
1755  }
1756 
1757  // New buffer
1758  if (minsize > 0) {
1759  newbuf:
1760  if (size_ > 0) {
1761  buf_.ptr = buf_.memalloc(Capacity::init(minsize+1), size_, buf_.header);
1763  data_ = buf_.ptr;
1764  } else
1765  data_ = buf_.ptr = buf_.memalloc(Capacity::init(minsize+1), 0, buf_.header);
1766  #if EVO_LIST_OPT_REFTERM
1767  terminated_ = false;
1768  #endif
1769  } else {
1770  assert( buf_.header == NULL && buf_.ptr == NULL );
1771  }
1772  return *this;
1773  }
1774 
1783  ListType& unshare() {
1784  if (buf_.header != NULL) {
1785  #if EVO_LIST_OPT_LAZYBUF
1786  if (buf_.ptr == NULL) {
1787  if (buf_.header->size >= size_) {
1788  // Use previous buffer
1789  assert( buf_.header->refs == 1 );
1790  assert( buf_.header->used == 0 );
1791  buf_.ptr = (T*)(buf_.header + 1);
1792  if (size_ > 0)
1794  buf_.header->used = size_;
1795  data_ = buf_.ptr;
1796  #if EVO_LIST_OPT_REFTERM
1797  terminated_ = false;
1798  #endif
1799  return *this;
1800  } else {
1801  // Previous buffer not big enough, free it
1802  buf_.memfree();
1803  buf_.header = NULL;
1804  }
1805  } else
1806  #else
1807  // Lazy buffer disabled
1808  assert( buf_.ptr != NULL );
1809  #endif
1810  if (buf_.header->refs > 1) {
1811  // New buffer, was shared
1812  assert( buf_.ptr != NULL );
1813  --buf_.header->refs;
1814  } else {
1815  // Already unique
1816  assert( buf_.header->refs == 1 );
1817  assert( buf_.ptr != NULL );
1818  if (data_ <= EVO_PEMPTY)
1819  data_ = buf_.ptr;
1820  return *this;
1821  }
1822  }
1823 
1824  // New buffer
1825  if (size_ > 0) {
1826  assert( data_ != NULL );
1829  data_ = buf_.ptr;
1830  #if EVO_LIST_OPT_REFTERM
1831  terminated_ = false;
1832  #endif
1833  } else {
1834  assert( buf_.header == NULL && buf_.ptr == NULL );
1835  }
1836  return *this;
1837  }
1838 
1839  // RESIZE
1840 
1850  ListType& resize(Size size) {
1851  if (size == 0) {
1852  clear();
1853  capacity(0);
1854  } else {
1855  if (buf_.header != NULL) {
1856  #if EVO_LIST_OPT_LAZYBUF
1857  if (buf_.ptr == NULL) {
1858  // Use previous buffer
1859  assert( buf_.header->used == 0 );
1860  assert( buf_.header->refs == 1 );
1861  buf_.ptr = (T*)(buf_.header+1);
1862  if (size > buf_.header->size)
1863  // Grow previous buffer
1864  buf_.memrealloc(size);
1865  if (size <= size_) {
1866  DataInit<T>::init(buf_.ptr, data_, size);
1867  } else {
1868  if (size_ > 0)
1871  }
1872  data_ = buf_.ptr;
1873  buf_.header->used = size_ = size;
1874  return *this;
1875  } else
1876  #else
1877  // Lazy buffer disabled
1878  assert( buf_.ptr != NULL );
1879  #endif
1880  if (buf_.header->refs == 1) {
1881  // Existing buffer
1882  if (buf_.header->used > 0)
1883  unsliceBuffer(size < size_ ? size : size_);
1884  if (size > buf_.header->size)
1885  // Grow buffer
1886  buf_.ptr = buf_.memrealloc(size);
1887  if (buf_.header->used < size) {
1888  // Add items
1890  buf_.header->used = size;
1891  }
1892  data_ = buf_.ptr;
1893  size_ = size;
1894  return *this;
1895  } else {
1896  // New buffer, was shared
1897  assert( buf_.header->refs > 1 );
1898  --buf_.header->refs;
1899  }
1900  }
1901 
1902  // New buffer
1903  if (size_ > 0) {
1904  assert( data_ != NULL );
1905  buf_.ptr = (T*)buf_.memalloc(Capacity::init(size+1), size, buf_.header);
1907  data_ = buf_.ptr;
1908  } else {
1909  data_ = buf_.ptr = (T*)buf_.memalloc(Capacity::init(size+1), size, buf_.header);
1911  }
1912  size_ = size;
1913  #if EVO_LIST_OPT_REFTERM
1914  terminated_ = false;
1915  #endif
1916  }
1917  return *this;
1918  }
1919 
1920  // COPY
1921 
1929  ListType& copy(const Item* data, Size size) {
1930  if (buf_.header != NULL) {
1931  if (buf_.header->refs > 1) {
1932  // New buffer, was shared
1933  --buf_.header->refs;
1934  } else {
1935  // Existing buffer
1936  assert( buf_.header->refs == 1 );
1937  buf_.ptr = (T*)(buf_.header + 1);
1938  if (buf_.header->used > 0) {
1940  buf_.header->used = 0;
1941  }
1942  if (size > buf_.header->size)
1943  // Grow buffer
1944  buf_.memrealloc(size);
1945  if (size > 0) {
1946  DataInit<T>::init(buf_.ptr, data, size);
1947  buf_.header->used = size;
1948  data_ = buf_.ptr;
1949  } else
1950  data_ = EVO_PEMPTY;
1951  size_ = size;
1952  return *this;
1953  }
1954  }
1955 
1956  // New buffer
1957  if (size > 0) {
1958  assert( data != NULL );
1959  data_ = buf_.ptr = (T*)buf_.memalloc(Capacity::init(size+1), size, buf_.header);
1960  DataInit<T>::init(buf_.ptr, data, size);
1961  } else {
1962  buf_.header = NULL;
1963  buf_.ptr = NULL;
1964  data_ = EVO_PEMPTY;
1965  }
1966  #if EVO_LIST_OPT_REFTERM
1967  terminated_ = false;
1968  #endif
1969  size_ = size;
1970  return *this;
1971  }
1972 
1979  ListType& copy(const ListBaseType& data) {
1980  if (data.data_ == NULL)
1981  set();
1982  else
1983  copy(data.data_, data.size_);
1984  return *this;
1985  }
1986 
1987  // ADD
1988 
1996  ListType& addnew(Size size=1)
1997  { modAppend(EVO_PDEFAULT, size); return *this; }
1998 
2005  ListType& addmin(Size minsize) {
2006  if (minsize > size_)
2007  modAppend(EVO_PDEFAULT, minsize - size_);
2008  return *this;
2009  }
2010 
2019  ListType& add(const Item* data, Size size)
2020  { modAppend(data, size); return *this; }
2021 
2029  ListType& add(const ListBaseType& data)
2030  { modAppend(data.data_, data.size_); return *this; }
2031 
2039  ListType& add(const Item& data)
2040  { modAppend(&data, 1); return *this; }
2041 
2054  ListType& operator<<(const Item& data)
2055  { return add(data); }
2056 
2069  ListType& operator<<(const ListBaseType& data)
2070  { return add(data); }
2071 
2084  ListType& operator<<(const ValNull& val) {
2085  EVO_PARAM_UNUSED(val);
2086  clear(); data_ = NULL; return *this;
2087  }
2088 
2100  ListType& operator<<(const ValEmpty& val) {
2101  EVO_PARAM_UNUSED(val);
2102  clear(); data_ = EVO_PDEFAULT; return *this;
2103  }
2104 
2105  // PREPEND
2106 
2114  ListType& prependnew(Size size=1)
2115  { modPrepend(EVO_PDEFAULT, size); return *this; }
2116 
2125  ListType& prepend(const Item* data, Size size)
2126  { modPrepend(data, size); return *this; }
2127 
2135  ListType& prepend(const ListBaseType& data)
2136  { modPrepend(data.data_, data.size_); return *this; }
2137 
2144  ListType& prepend(const Item& data)
2145  { modPrepend(&data, 1); return *this; }
2146 
2147  // INSERT
2148 
2154  Size insertnew(Key index, Size size=1)
2155  { return modInsert(index, EVO_PDEFAULT, size); }
2156 
2163  Size insert(Key index, const Item* data, Size size)
2164  { return modInsert(index, data, size); }
2165 
2171  Size insert(Key index, const ListBaseType& data)
2172  { return modInsert(index, data.data_, data.size_); }
2173 
2179  Size insert(Key index, const Item& data)
2180  { return modInsert(index, &data, 1); }
2181 
2182  // REMOVE
2183 
2189  Size remove(Key index, Size size=1)
2190  { return modRemove(index, size); }
2191 
2192  // POP
2193 
2201  bool pop(T& item, Key index) {
2202  bool result;
2203  if (index < size_) {
2204  DataInit<T>::copy(&item, data_+index, 1);
2205  modRemove(index, 1);
2206  result = true;
2207  } else
2208  result = false;
2209  return result;
2210  }
2211 
2219  bool pop(T& item) {
2220  bool result;
2221  if (size_ > 0) {
2222  const Size index = size_ - 1;
2223  DataInit<T>::copy(&item, data_+index, 1);
2224  modRemove(index, 1);
2225  result = true;
2226  } else
2227  result = false;
2228  return result;
2229  }
2230 
2237  const Item* pop() {
2238  const Item* result;
2239  if (size_ > 0)
2240  result = data_ + --size_;
2241  else
2242  result = NULL;
2243  return result;
2244  }
2245 
2253  bool popq(T& item) {
2254  bool result;
2255  if (size_ > 0) {
2256  DataInit<T>::copy(&item, data_, 1);
2257  modRemove(0, 1);
2258  result = true;
2259  } else
2260  result = false;
2261  return result;
2262  }
2263 
2270  const Item* popq() {
2271  const Item* result;
2272  if (size_ > 0) {
2273  result = data_;
2274  data_ = data_ + 1;
2275  --size_;
2276  } else
2277  result = NULL;
2278  return result;
2279  }
2280 
2281  // FILL
2282 
2291  ListType& fill(const Item& item, Key index=0, Size size=ALL) {
2292  if (index == END)
2293  index = size_;
2294  if (size == ALL)
2295  size = (index < size_ ? size_ - index : 0);
2296  if (size > 0) {
2297  const Size newsize = index + size;
2298  if (newsize > size_)
2299  advResize(newsize);
2300  else
2301  unshare();
2302  DataFill<T>::fill(data_+index, size, item);
2303  }
2304  return *this;
2305  }
2306 
2307  // REPLACE
2308 
2316  ListType& replace(Key index, Size rsize, const Item* data, Size size) {
2317  if (rsize == 0)
2318  modInsert(index, data, size);
2319  else if (size == 0)
2320  modRemove(index, rsize);
2321  else if (index >= size_)
2322  modAppend(data, size);
2323  else
2324  modReplace(index, rsize, data, size);
2325  return *this;
2326  }
2327 
2328  // MOVE / SWAP
2329 
2338  void move(Key dest, Key index) {
2339  if (index < size_) {
2340  if (dest >= size_)
2341  dest = size_ - 1;
2342  if (index != dest) {
2343  unshare();
2344  char buf[sizeof(T)];
2345  memcpy(buf, data_+index, sizeof(T));
2346  if (index > dest)
2347  // Moving left, shift items right
2348  memmove(data_+dest+1, data_+dest, (index-dest)*sizeof(T));
2349  else
2350  // Moving right, shift items left
2351  memmove(data_+index, data_+index+1, (dest-index)*sizeof(T));
2352  memcpy(data_+dest, buf, sizeof(T));
2353  }
2354  }
2355  }
2356 
2365  Size move(Key dest, ListType& src, Key srcindex=0, Size size=ALL) {
2366  const Size maxsize = (srcindex < src.size_ ? src.size_-srcindex : 0);
2367  if (size > maxsize)
2368  size = maxsize;
2369  if (size > 0) {
2370  if (dest > size_)
2371  dest = size_;
2372  const Size newused = size_ + size;
2373  if (buf_.header != NULL) {
2374  #if EVO_LIST_OPT_LAZYBUF
2375  if (buf_.ptr == NULL) {
2376  if (buf_.header->size >= newused) {
2377  // Use previous buffer, there's room
2378  assert( size_ > 0 );
2379  buf_.ptr = (T*)(buf_.header + 1);
2380  if (dest > 0)
2381  DataInit<T>::init(buf_.ptr, data_, dest);
2382  const Size nextindex = dest + size;
2383  if (nextindex < newused)
2384  DataInit<T>::init(buf_.ptr+nextindex, data_+dest, newused-nextindex);
2385  buf_.header->used = newused;
2386  data_ = buf_.ptr;
2387  size_ = newused;
2388  #if EVO_LIST_OPT_REFTERM
2389  terminated_ = false;
2390  #endif
2391  goto movedata;
2392  }
2393  } else
2394  #else
2395  // Lazy buffer disabled
2396  assert( buf_.ptr != NULL );
2397  #endif
2398  if (buf_.header->refs == 1) {
2399  // Existing buffer -- mostly copied from modInsertMid()
2400  Size offset;
2401  if (buf_.header->used > 0) {
2402  assert( data_ >= buf_.ptr && data_ <= buf_.ptr+buf_.header->used );
2403  offset = (Size)(data_ - buf_.ptr);
2404 
2405  const Size tailsize = buf_.header->used - size_ - offset;
2406  if (tailsize > 0) {
2407  DataInit<T>::uninit(data_+size_, tailsize);
2408  buf_.header->used -= tailsize;
2409  }
2410  } else {
2411  offset = 0;
2412  data_ = buf_.ptr;
2413  }
2414  if (newused > buf_.header->size) {
2415  // Move to new bigger buffer
2416  Size newbufsize = Capacity::grow(buf_.header->size);
2417  if (newbufsize <= newused)
2418  newbufsize = newused + 1; // Leave extra space
2419  Header* newheader;
2420  T* newbuf = buf_.memalloc(newbufsize, newused, newheader);
2421  if (dest > 0)
2422  memcpy(newbuf, data_, sizeof(T)*dest);
2423  const Size tailsize = size_ - dest;
2424  if (tailsize > 0)
2425  memcpy(newbuf+dest+size, data_+dest, sizeof(T)*tailsize);
2426  if (offset > 0)
2427  DataInit<T>::uninit(buf_.ptr, offset);
2428  buf_.memfree();
2429  buf_.header = newheader;
2430  buf_.ptr = newbuf;
2431  data_ = newbuf;
2432  } else {
2433  if (size > offset) {
2434  // Shift beginning and end to make room
2435  if (offset > 0) {
2436  DataInit<T>::uninit(buf_.ptr, offset);
2437  if (dest > 0)
2438  memmove(buf_.ptr, data_, sizeof(T)*dest);
2439  data_ = buf_.ptr;
2440  }
2441  const Size tailsize = size_ - dest;
2442  if (tailsize > 0)
2443  memmove(data_+dest+size, data_+dest+offset, sizeof(T)*tailsize);
2444  buf_.header->used = newused;
2445  } else {
2446  // Shift beginning to make room
2447  const Size newoffset = offset - size;
2448  data_ = buf_.ptr + newoffset;
2449  DataInit<T>::uninit(buf_.ptr, offset-newoffset);
2450  if (dest > 0)
2451  memmove(data_, buf_.ptr+offset, sizeof(T)*dest);
2452  }
2453  }
2454  size_ = newused;
2455  goto movedata;
2456  }
2457  }
2458 
2459  // New buffer
2460  Header* newheader;
2461  T* newbuf = buf_.memalloc(newused, newheader);
2462  if (size_ > 0) {
2463  if (dest > 0)
2464  DataInit<T>::init(newbuf, data_, dest);
2465  const Size nextindex = dest + size;
2466  if (nextindex < newheader->used)
2467  DataInit<T>::init(newbuf+nextindex, data_+dest, newheader->used-nextindex);
2468  }
2469  data_ = buf_.replace(newbuf, newheader);
2470  size_ = buf_.header->used;
2471  #if EVO_LIST_OPT_REFTERM
2472  terminated_ = false;
2473  #endif
2474  goto movedata;
2475  }
2476  return 0;
2477 
2478  movedata:
2479  if (src.buf_.ptr != NULL && src.buf_.header->refs == 1) {
2480  // Move from src buffer, is unique
2481  memcpy(data_+dest, src.data_+srcindex, sizeof(T)*size);
2482  src.modRemove(srcindex, size, false);
2483  } else {
2484  // Copy and remove from src
2485  meminit(data_+dest, src.data_+srcindex, size);
2486  src.modRemove(srcindex, size, true);
2487  }
2488  return size;
2489  }
2490 
2497  void swap(Key index1, Key index2) {
2498  if (index1 != index2 && index1 < size_ && index2 < size_) {
2499  unshare();
2500  advSwap(index1, index2);
2501  }
2502  }
2503 
2509  void swap(ListType& list)
2510  { EVO_IMPL_CONTAINER_SWAP(this, &list, ThisType); }
2511 
2512  // ALGS
2513 
2519  ListType& reverse() {
2520  if (size_ > 0) {
2521  unshare();
2522  char temp[sizeof(T)];
2523  T* left = data_;
2524  T* right = data_ + (size_ - 1);
2525  while (left < right) {
2526  memcpy(temp, left, sizeof(T));
2527  memcpy(left, right, sizeof(T));
2528  memcpy(right, temp, sizeof(T));
2529  ++left;
2530  --right;
2531  }
2532  }
2533  return *this;
2534  }
2535 
2536  // ADVANCED
2537 
2552  ListType& advResize(Size size) {
2553  // Copied from resize(), only difference is init() and init_tail_fast()
2554  if (size == 0) {
2555  clear();
2556  capacity(0);
2557  } else {
2558  if (buf_.header != NULL) {
2559  #if EVO_LIST_OPT_LAZYBUF
2560  if (buf_.ptr == NULL) {
2561  // Use previous buffer
2562  assert( buf_.header->used == 0 );
2563  assert( buf_.header->refs == 1 );
2564  buf_.ptr = (T*)(buf_.header+1);
2565  if (size > buf_.header->size)
2566  // Grow previous buffer
2567  buf_.memrealloc(size);
2568  if (size <= size_) {
2569  DataInit<T>::init(buf_.ptr, data_, size);
2570  } else {
2571  if (size_ > 0)
2574  }
2575  data_ = buf_.ptr;
2576  buf_.header->used = size_ = size;
2577  return *this;
2578  } else
2579  #else
2580  // Lazy buffer disabled
2581  assert( buf_.ptr != NULL );
2582  #endif
2583  if (buf_.header->refs == 1) {
2584  // Existing buffer
2585  if (buf_.header->used > 0)
2586  unsliceBuffer(size < size_ ? size : size_);
2587  if (size > buf_.header->size)
2588  // Grow buffer
2589  buf_.ptr = buf_.memrealloc(size);
2590  if (buf_.header->used < size) {
2591  // Add items
2593  buf_.header->used = size;
2594  }
2595  data_ = buf_.ptr;
2596  size_ = size;
2597  return *this;
2598  } else {
2599  // New buffer, was shared
2600  assert( buf_.header->refs > 1 );
2601  --buf_.header->refs;
2602  }
2603  }
2604 
2605  // New buffer
2606  if (size_ > 0) {
2607  assert( data_ != NULL );
2608  buf_.ptr = (T*)buf_.memalloc(Capacity::init(size+1), size, buf_.header);
2610  data_ = buf_.ptr;
2611  } else {
2612  data_ = buf_.ptr = (T*)buf_.memalloc(Capacity::init(size+1), size, buf_.header);
2613  DataInit<T>::init(data_, size);
2614  }
2615  size_ = size;
2616  #if EVO_LIST_OPT_REFTERM
2617  terminated_ = false;
2618  #endif
2619  }
2620  return *this;
2621  }
2622 
2648  bool advEdit(Edit& edit, Size minsize, bool inplace=true) {
2649  assert( minsize > 0 );
2650  edit.clear();
2651  if (buf_.header != NULL) {
2652  #if EVO_LIST_OPT_LAZYBUF
2653  if (buf_.ptr == NULL) {
2654  if (buf_.header->size < minsize) {
2655  // Previous buffer not big enough, free it
2656  buf_.memfree();
2657  buf_.header = NULL;
2658  goto newbuf;
2659  } else {
2660  // Previous buffer is big enough, detach and use as new buffer
2661  assert( buf_.header->used == 0 );
2662  assert( buf_.header->refs == 1 );
2663  edit.ptr = (T*)(buf_.header+1);
2664  edit.header = (void*)buf_.header;
2665  edit.size = 0;
2666  buf_.ptr = NULL;
2667  buf_.header = NULL;
2668  return false;
2669  }
2670  }
2671  #else
2672  // Lazy buffer disabled
2673  assert( buf_.ptr != NULL );
2674  #endif
2675 
2676  // If unique buffer is big enough and beginning isn't sliced, stop here to edit in-place
2677  if (inplace && buf_.header->refs == 1 && buf_.header->size >= minsize && data_ == buf_.ptr) {
2678  edit.ptr = buf_.ptr;
2679  edit.size = size_;
2680  return true;
2681  }
2682  }
2683 
2684  newbuf:
2685  // Create new edit buffer
2686  edit.ptr = (T*)buf_.memalloc(Capacity::init(minsize+1), minsize, (Header*&)edit.header);
2687  edit.size = 0;
2688  return false;
2689  }
2690 
2697  void advEditDone(Edit& edit) {
2698  assert( edit.ptr != NULL );
2699  if (edit.header == NULL) {
2700  // Update size after in-place editing
2701  assert( buf_.header != NULL );
2702  size_ = buf_.header->used = edit.size;
2703  } else {
2704  // Switch to new buffer
2705  if (buf_.header != NULL && --buf_.header->refs == 0)
2706  buf_.memfree();
2707  buf_.header = (Header*)edit.header;
2708  buf_.ptr = edit.ptr;
2709  data_ = buf_.ptr;
2710  size_ = buf_.header->used = edit.size;
2711  assert( buf_.header->refs == 1 );
2712  edit.header = NULL;
2713  }
2714  edit.ptr = NULL;
2715  edit.size = 0;
2716  }
2717 
2728  T* advBuffer(Size size) {
2729  advResize(size);
2730  return buf_.ptr;
2731  }
2732 
2744  { return buf_.ptr; }
2745 
2754  void advSize(Size size) {
2755  assert( buf_.header != NULL );
2756  size_ = buf_.header->used = size;
2757  }
2758 
2768  T* advWrite(Size addsize) {
2769  assert( addsize > 0 );
2770  unslice();
2771  reserve(addsize);
2772  return buf_.ptr + buf_.header->used;
2773  }
2774 
2784  void advWriteDone(Size addsize) {
2785  assert( buf_.header != NULL );
2786  size_ = buf_.header->used += addsize;
2787  }
2788 
2796  T& advItem(Key index) {
2797  assert( index < size_ );
2798  return data_[index];
2799  }
2800 
2807  { return (size_ > 0 ? data_ : NULL); }
2808 
2814  T* advLast()
2815  { return (size_ > 0 ? data_+size_-1 : NULL); }
2816 
2824  void advAdd(Size size)
2825  { modAppend(NULL, size); }
2826 
2834  void advPrepend(Size size)
2835  { modPrepend(NULL, size); }
2836 
2846  Key advInsert(Key index, Size size)
2847  { return modInsert(index, NULL, size); }
2848 
2857  void advRemove(Key index, Size size)
2858  { modRemove(index, size, false); }
2859 
2867  void advSwap(Key index1, Key index2) {
2868  assert( index1 < size_ && index2 < size_ );
2869  char buf[sizeof(T)];
2870  memcpy(buf, data_+index1, sizeof(T));
2871  memcpy(data_+index1, data_+index2, sizeof(T));
2872  memcpy(data_+index2, buf, sizeof(T));
2873  }
2874 
2875  // INTERNAL
2876 
2877  // Internal methods
2879  Size used() const
2880  { return (buf_.ptr == NULL ? size_ : buf_.header->used); }
2883  // Testing methods
2885  #if EVO_UNIT_TEST_MODE
2886  bool utTerminated() const {
2887  #if EVO_LIST_OPT_REFTERM
2888  return terminated_;
2889  #else
2890  return false;
2891  #endif
2892  }
2893  Size utRefs() const
2894  { return (buf_.ptr == NULL ? 0 : buf_.header->refs); }
2895  const Item* utBuffer() const
2896  { return buf_.ptr; }
2897  void utSetEmptyBuffer(bool setempty, size_t size=1) {
2898  assert( size < IntegerT<Size>::MAX );
2899  resize((Size)size);
2900  DataInit<T>::uninit(buf_.ptr, (Size)size);
2901  buf_.header->used = 0;
2902  size_ = 0;
2903  if (setempty)
2904  data_ = EVO_PEMPTY;
2905  }
2906  void utSetUnusedBuffer(bool setempty, size_t size=1) {
2907  assert( size < IntegerT<Size>::MAX );
2908  resize((Size)size);
2909  DataInit<T>::uninit(buf_.ptr, (Size)size);
2910  buf_.header->used = 0;
2911  buf_.ptr = NULL;
2912  size_ = 0;
2913  if (setempty)
2914  data_ = EVO_PEMPTY;
2915  }
2916  void utSetBufPtr() {
2917  if (buf_.header != NULL)
2918  buf_.ptr = (T*)(buf_.header + 1);
2919  }
2920  #endif
2921 
2923  // Iterator support methods
2925  void iterInitMutable()
2926  { unshare(); }
2927  const IterItem* iterFirst(IterKey& key) const {
2928  const IterItem* result;
2929  if (size_ > 0) {
2930  key = 0;
2931  result = data_;
2932  } else {
2933  key = END;
2934  result = NULL;
2935  }
2936  return result;
2937  }
2938  const IterItem* iterNext(IterKey& key) const {
2939  const IterItem* result = NULL;
2940  if (key != END) {
2941  if (++key < size_)
2942  result = data_ + key;
2943  else
2944  key = END;
2945  }
2946  return result;
2947  }
2948  const IterItem* iterNext(Size count, IterKey& key) const {
2949  const Item* result = NULL;
2950  if (key != END) {
2951  if ( (key+=count) < size_ )
2952  result = data_ + key;
2953  else
2954  key = END;
2955  }
2956  return result;
2957  }
2958  const IterItem* iterLast(IterKey& key) const {
2959  const IterItem* result;
2960  if (size_ > 0) {
2961  key = size_ - 1;
2962  result = data_ + key;
2963  } else {
2964  key = END;
2965  result = NULL;
2966  }
2967  return result;
2968  }
2969  const IterItem* iterPrev(IterKey& key) const {
2970  const IterItem* result = NULL;
2971  if (key != END) {
2972  if (key > 0)
2973  result = data_ + --key;
2974  else
2975  key = END;
2976  }
2977  return result;
2978  }
2979  const IterItem* iterPrev(Size count, IterKey& key) const {
2980  const IterItem* result = NULL;
2981  if (key != END) {
2982  if (key > 0 && count <= key)
2983  result = data_ + (key-=count);
2984  else
2985  key = END;
2986  }
2987  return result;
2988  }
2989  Size iterCount() const
2990  { return size_; }
2991  const IterItem* iterSet(IterKey key) const {
2992  const IterItem* result = NULL;
2993  if (key < size_)
2994  result = data_ + key;
2995  return result;
2996  }
2999 protected:
3001  struct Header {
3002  Size used;
3003  Size size;
3004  Size refs;
3005  };
3006 
3008  struct Buf {
3010  T* ptr;
3011  #if EVO_ALLOCATORS
3012  Allocator* allocator;
3013  #endif
3014 
3016  Buf() {
3017  header = NULL;
3018  ptr = NULL;
3019  }
3020 
3023  { free(); }
3024 
3028  void clear() {
3029  header = NULL;
3030  ptr = NULL;
3031  }
3032 
3041  T* memalloc(Size size, Size used, Header*& header) {
3042  assert( size > 0 );
3043  const Size bytes = sizeof(Header) + (size*sizeof(T));
3044  #if EVO_ALLOCATORS
3045  if (allocator == NULL)
3046  header = (Header*)::malloc(bytes);
3047  else
3048  header = (Header*)allocator->alloc(bytes);
3049  #else
3050  header = (Header*)::malloc(bytes);
3051  #endif
3052  assert( header != NULL );
3053  header->refs = 1;
3054  header->used = used;
3055  header->size = size;
3056  return (T*)(header + 1);
3057  }
3058 
3068  T* memalloc(Size size, Header*& header)
3069  { return memalloc(Capacity::init(size), size, header); }
3070 
3077  T* memrealloc(Size size) {
3078  assert( (size_t)this->header > sizeof(Header) );
3079  assert( this->ptr != NULL );
3080  assert( size > 0 );
3081  const Size bytes = sizeof(Header) + (size*sizeof(T));
3082  #if EVO_ALLOCATORS
3083  if (allocator == NULL)
3084  this->header = (Header*)::realloc(this->header, bytes);
3085  else
3086  this->header = (Header*)allocator->realloc(this->header, bytes);
3087  #else
3088  this->header = (Header*)::realloc(this->header, bytes);
3089  #endif
3090  assert( this->header != NULL );
3091  this->ptr = (T*)(this->header+1);
3092  this->header->size = size;
3093  return this->ptr;
3094  }
3095 
3099  void memfree() {
3100  assert( (size_t)header > sizeof(Header) );
3101  #if EVO_ALLOCATORS
3102  if (this->allocator == NULL)
3103  ::free(header);
3104  else
3105  this->allocator->free(header);
3106  #else
3107  ::free(header);
3108  #endif
3109  }
3110 
3112  void free() {
3113  if (header != NULL && --header->refs == 0) {
3114  if (header->used > 0)
3115  DataInit<T>::uninit((T*)(header+1), header->used);
3116  memfree();
3117  }
3118  }
3119 
3125  T* replace(T* newptr, Header* newheader) {
3126  assert( newptr != NULL );
3127  assert( newheader != NULL );
3128  assert( newptr != ptr );
3129  free();
3130  header = newheader;
3131  ptr = newptr;
3132  return ptr;
3133  }
3134  };
3135 
3136  Buf buf_;
3137  #if EVO_LIST_OPT_REFTERM
3138  bool terminated_;
3139  #endif
3140 
3144  void ref(const ListType& data) {
3145  if (data.data_ == NULL) {
3146  set();
3147  } else if (data.size_ == 0) {
3148  setempty();
3149  #if EVO_ALLOCATORS
3150  } else if (buf_.allocator != NULL && data.buf_.ptr != NULL) {
3151  copy(data);
3152  #endif
3153  } else if (data.buf_.ptr == NULL) {
3154  // External reference
3155  if (buf_.ptr != NULL) {
3156  assert( buf_.header != NULL );
3157  if (buf_.header->refs > 1) {
3158  // Detach from shared buffer
3159  --buf_.header->refs;
3160  buf_.header = NULL;
3161  buf_.ptr = NULL;
3162  } else {
3163  // Leave buffer for later use
3164  assert( buf_.header->refs == 1 );
3165  if (buf_.header->used > 0)
3166  DataInit<T>::uninit(buf_.ptr, buf_.header->used);
3167  #if EVO_LIST_OPT_LAZYBUF
3168  buf_.header->used = 0;
3169  #else
3170  // Lazy buffer disabled -- can't leave for later use
3171  buf_.memfree();
3172  buf_.header = NULL;
3173  #endif
3174  buf_.ptr = NULL;
3175  }
3176  }
3177  data_ = data.data_;
3178  size_ = data.size_;
3179  #if EVO_LIST_OPT_REFTERM
3180  terminated_ = data.terminated_;
3181  #endif
3182  } else {
3183  // Shared
3184  assert( data.buf_.header != NULL );
3185  assert( data.buf_.ptr != NULL );
3186  buf_.free();
3187  buf_.header = data.buf_.header;
3188  buf_.ptr = data.buf_.ptr;
3189  ++buf_.header->refs;
3190  data_ = data.data_;
3191  size_ = data.size_;
3192  #if EVO_LIST_OPT_REFTERM
3193  terminated_ = data.terminated_;
3194  #endif
3195  }
3196  }
3197 
3203  void ref(const ListType& data, Size index, Size size) {
3204  if (data.data_ == NULL)
3205  set();
3206  else if (index >= data.size_)
3207  setempty();
3208  else {
3209  const Size max_size = (data.size_ - index);
3210  if (size > max_size)
3211  size = max_size;
3212  if (size == 0) {
3213  setempty();
3214  #if EVO_ALLOCATORS
3215  } else if (buf_.allocator != NULL && data.buf_.header != NULL) {
3216  copy(data.data_+index, size);
3217  #endif
3218  } else if (data.buf_.ptr == NULL) {
3219  // External reference
3220  if (buf_.ptr != NULL) {
3221  assert( buf_.header != NULL );
3222  if (buf_.header->refs > 1) {
3223  // Detach from shared buffer
3224  --buf_.header->refs;
3225  buf_.header = NULL;
3226  buf_.ptr = NULL;
3227  } else {
3228  // Leave buffer for later use
3229  assert( buf_.header->refs == 1 );
3230  if (buf_.header->used > 0)
3231  DataInit<T>::uninit(buf_.ptr, buf_.header->used);
3232  #if EVO_LIST_OPT_LAZYBUF
3233  buf_.header->used = 0;
3234  #else
3235  // Lazy buffer disabled -- can't leave for later use
3236  buf_.memfree();
3237  buf_.header = NULL;
3238  #endif
3239  buf_.ptr = NULL;
3240  }
3241  }
3242  data_ = data.data_ + index;
3243  size_ = size;
3244  #if EVO_LIST_OPT_REFTERM
3245  terminated_ = (data.terminated_ && size == max_size);
3246  #endif
3247  } else {
3248  // Shared
3249  assert( data.buf_.header != NULL );
3250  buf_.free();
3251  buf_.header = data.buf_.header;
3252  buf_.ptr = data.buf_.ptr;
3253  data_ = data.data_ + index;
3254  size_ = size;
3255  #if EVO_LIST_OPT_REFTERM
3256  terminated_ = data.terminated_;
3257  #endif
3258  ++buf_.header->refs;
3259  }
3260  }
3261  }
3262 
3268  void ref(const Item* data, Size size, bool term=false) {
3269  if (data == NULL)
3270  set();
3271  else if (size == 0)
3272  setempty();
3273  else {
3274  // External reference
3275  if (buf_.ptr != NULL) {
3276  assert( buf_.header != NULL );
3277  if (buf_.header->refs > 1) {
3278  // Detach from shared buffer
3279  --buf_.header->refs;
3280  buf_.header = NULL;
3281  buf_.ptr = NULL;
3282  } else {
3283  // Leave buffer for later use
3284  assert( buf_.header->refs == 1 );
3285  if (buf_.header->used > 0)
3286  DataInit<T>::uninit(buf_.ptr, buf_.header->used);
3287  #if EVO_LIST_OPT_LAZYBUF
3288  buf_.header->used = 0;
3289  #else
3290  // Lazy buffer disabled -- can't leave for later use
3291  buf_.memfree();
3292  buf_.header = NULL;
3293  #endif
3294  buf_.ptr = NULL;
3295  }
3296  }
3297  data_ = (T*)data;
3298  size_ = size;
3299  #if EVO_LIST_OPT_REFTERM
3300  terminated_ = term;
3301  #else
3302  EVO_PARAM_UNUSED(term);
3303  #endif
3304  }
3305  }
3306 
3307 private:
3309  static const Size CONSERVE = (sizeof(T) == 1 ? 1 : 0);
3310 
3316  void unsliceBuffer(Size size) {
3317  assert( buf_.header != NULL && buf_.ptr >= (T*)(buf_.header+1) );
3318  assert( data_ >= buf_.ptr && data_ <= buf_.ptr+buf_.header->used );
3319  const Size offset = (Size)(data_ - buf_.ptr);
3320 
3321  const Size tailsize = buf_.header->used - size - offset;
3322  if (tailsize > 0) {
3323  DataInit<T>::uninit(data_+size, tailsize);
3324  buf_.header->used -= tailsize;
3325  }
3326 
3327  if (offset > 0) {
3328  DataInit<T>::uninit(buf_.ptr, offset);
3329  if (size > 0)
3330  memmove((void*)buf_.ptr, (void*)(buf_.ptr+offset), size*sizeof(T));
3331  data_ = buf_.ptr;
3332  buf_.header->used -= offset;
3333  }
3334  }
3335 
3340  void modAppend(const Item* data, Size size) {
3341  if (size > 0) {
3342  const Size newused = size_ + size;
3343  if (buf_.header != NULL) {
3344  #if EVO_LIST_OPT_LAZYBUF
3345  if (buf_.ptr == NULL) {
3346  assert( buf_.header->refs == 1 );
3347  if (buf_.header->size >= newused) {
3348  // Use previous buffer
3349  buf_.ptr = (T*)(buf_.header + 1);
3350  if (size_ > 0)
3351  DataInit<T>::init(buf_.ptr, data_, size_);
3352  meminit(buf_.ptr+size_, data, size);
3353  buf_.header->used = newused;
3354  data_ = buf_.ptr;
3355  size_ = newused;
3356  #if EVO_LIST_OPT_REFTERM
3357  terminated_ = false;
3358  #endif
3359  return;
3360  }
3361  } else
3362  #else
3363  // Lazy buffer disabled
3364  assert( buf_.ptr != NULL );
3365  #endif
3366  if (buf_.header->refs == 1) {
3367  // Existing buffer
3368  Size offset;
3369  if (buf_.header->used > 0) {
3370  assert( data_ >= buf_.ptr && data_ <= buf_.ptr+buf_.header->used );
3371  offset = (Size)(data_ - buf_.ptr);
3372 
3373  const Size tailsize = buf_.header->used - size_ - offset;
3374  if (tailsize > 0) {
3375  DataInit<T>::uninit(data_+size_, tailsize);
3376  buf_.header->used -= tailsize;
3377  }
3378  } else
3379  offset = 0;
3380  if (newused > buf_.header->size) {
3381  // Move to new bigger buffer
3382  Size newbufsize = Capacity::grow(buf_.header->size);
3383  if (newbufsize <= newused)
3384  newbufsize = newused + 1; // Leave extra space
3385  Header* newheader;
3386  T* newbuf = buf_.memalloc(newbufsize, newused, newheader);
3387  if (size_ > 0)
3388  memcpy((void*)newbuf, (void*)data_, sizeof(T)*size_);
3389  if (offset > 0)
3390  DataInit<T>::uninit(buf_.ptr, offset);
3391 
3392  // Write new items
3393  meminit(newbuf+size_, data, size);
3394  size_ = newused;
3395 
3396  // Free old items, update state
3397  buf_.memfree();
3398  buf_.header = newheader;
3399  buf_.ptr = newbuf;
3400  data_ = newbuf;
3401  } else if (offset > 0 && size > buf_.header->size-buf_.header->used) {
3402  // Shift to make room at end
3403  DataInit<T>::uninit(buf_.ptr, offset);
3404  memmove((void*)buf_.ptr, (void*)data_, sizeof(T)*size_);
3405  if (data >= data_ && data < data_ + size_)
3406  data -= (data_ - buf_.ptr); // Copy from self
3407  buf_.header->used = newused;
3408  data_ = buf_.ptr;
3409 
3410  // Write new items
3411  meminit(data_+size_, data, size);
3412  size_ = newused;
3413  } else {
3414  // Enough room at end
3415  if (data_ < buf_.ptr) {
3416  assert( offset == 0 );
3417  data_ = buf_.ptr;
3418  }
3419  buf_.header->used += size;
3420 
3421  // Write new items
3422  meminit(data_+size_, data, size);
3423  size_ = newused;
3424  }
3425  return;
3426  }
3427  }
3428 
3429  // New buffer
3430  Header* newheader;
3431  T* newbuf = buf_.memalloc(Capacity::init(newused+1), newused, newheader);
3432  if (size_ > 0)
3433  DataInit<T>::init(newbuf, data_, size_);
3434  meminit(newbuf+size_, data, size);
3435  newheader->used = newused;
3436  data_ = buf_.replace(newbuf, newheader);
3437  size_ = newused;
3438  #if EVO_LIST_OPT_REFTERM
3439  terminated_ = false;
3440  #endif
3441  } else if (data_ == NULL)
3442  data_ = EVO_PEMPTY;
3443  }
3444 
3449  void modPrepend(const Item* data, Size size) {
3450  if (size > 0) {
3451  const Size newused = size_ + size;
3452  if (buf_.header != NULL) {
3453  #if EVO_LIST_OPT_LAZYBUF
3454  if (buf_.ptr == NULL) {
3455  if (buf_.header->size >= newused) {
3456  // Use previous buffer
3457  buf_.ptr = (T*)(buf_.header + 1);
3458  if (size_ > 0)
3459  DataInit<T>::init(buf_.ptr+size, data_, size_);
3460  meminit(buf_.ptr, data, size);
3461  buf_.header->used = newused;
3462  data_ = buf_.ptr;
3463  size_ = newused;
3464  #if EVO_LIST_OPT_REFTERM
3465  terminated_ = false;
3466  #endif
3467  return;
3468  }
3469  } else
3470  #else
3471  // Lazy buffer disabled
3472  assert( buf_.ptr != NULL );
3473  #endif
3474  if (buf_.header->refs == 1) {
3475  // Existing buffer
3476  Size offset;
3477  if (buf_.header->used > 0) {
3478  assert( data_ >= buf_.ptr && data_ <= buf_.ptr+buf_.header->used );
3479  offset = (ulong)(data_ - buf_.ptr);
3480 
3481  const Size tailsize = buf_.header->used - size_ - offset;
3482  if (tailsize > 0) {
3483  DataInit<T>::uninit(data_+size_, tailsize);
3484  buf_.header->used -= tailsize;
3485  }
3486  } else
3487  offset = 0;
3488  if (newused > buf_.header->size) {
3489  // Move to new bigger buffer
3490  Size newbufsize = Capacity::grow(buf_.header->size);
3491  if (newbufsize <= newused)
3492  newbufsize = newused + 1; // Leave extra space
3493  Header* newheader;
3494  T* newbuf = buf_.memalloc(newbufsize, newused, newheader);
3495  if (size_ > 0)
3496  memcpy((void*)(newbuf+size), (void*)data_, sizeof(T)*size_);
3497  if (offset > 0)
3498  DataInit<T>::uninit(buf_.ptr, offset);
3499 
3500  // Write new items
3501  meminit(newbuf, data, size);
3502 
3503  // Free old items, update state
3504  buf_.memfree();
3505  buf_.header = newheader;
3506  buf_.ptr = newbuf;
3507  data_ = newbuf;
3508  } else if (size > offset) {
3509  // Shift to make room at beginning
3510  if (offset > 0)
3511  DataInit<T>::uninit(buf_.ptr, offset);
3512  memmove((void*)(buf_.ptr+size), (void*)data_, sizeof(T)*size_);
3513  if (data >= data_ && data < data_ + size_)
3514  data += (buf_.ptr + size - data_); // Copy from self
3515  buf_.header->used = newused;
3516  data_ = buf_.ptr;
3517 
3518  // Write new items
3519  meminit(data_, data, size);
3520  } else {
3521  // Enough room at beginning
3522  data_ = buf_.ptr + (offset - size);
3523  DataInit<T>::uninit(data_, size);
3524 
3525  // Write new items
3526  meminit(data_, data, size);
3527  }
3528  size_ = newused;
3529  return;
3530  }
3531  }
3532 
3533  // New buffer
3534  Header* newheader;
3535  T* newbuf = buf_.memalloc(newused, newheader);
3536  if (size_ > 0) {
3537  assert( data_ != NULL );
3538  DataInit<T>::init(newbuf+size, data_, size_);
3539  }
3540  meminit(newbuf, data, size);
3541  data_ = buf_.replace(newbuf, newheader);
3542  size_ = buf_.header->used;
3543  #if EVO_LIST_OPT_REFTERM
3544  terminated_ = false;
3545  #endif
3546  } else if (data_ == NULL)
3547  data_ = EVO_PEMPTY;
3548  }
3549 
3556  Size modInsert(Size index, const Item* data, Size size) {
3557  if (index >= size_) {
3558  index = size_;
3559  modAppend(data, size);
3560  } else if (index == 0)
3561  modPrepend(data, size);
3562  else
3563  index = modInsertMid(index, data, size);
3564  return index;
3565  }
3566 
3573  Size modInsertMid(Size index, const Item* data, Size size) {
3574  assert( index > 0 && index < size_ );
3575  assert( size_ > 0 );
3576  if (size > 0) {
3577  if (buf_.header != NULL) {
3578  const Size newused = size_ + size;
3579  #if EVO_LIST_OPT_LAZYBUF
3580  if (buf_.ptr == NULL) {
3581  if (buf_.header->size >= newused) {
3582  // Use previous buffer
3583  buf_.ptr = (T*)(buf_.header + 1);
3584  DataInit<T>::init(buf_.ptr, data_, index);
3585  {
3586  const Size nextindex = index + size;
3587  assert( nextindex < newused );
3588  DataInit<T>::init(buf_.ptr+nextindex, data_+index, newused-nextindex);
3589  }
3590  meminit(buf_.ptr+index, data, size);
3591  buf_.header->used = newused;
3592  data_ = buf_.ptr;
3593  size_ = newused;
3594  #if EVO_LIST_OPT_REFTERM
3595  terminated_ = false;
3596  #endif
3597  return index;
3598  }
3599  } else
3600  #else
3601  // Lazy buffer disabled
3602  assert( buf_.ptr != NULL );
3603  #endif
3604  if (buf_.header->refs == 1) {
3605  // Existing buffer -- not empty
3606  assert( data_ >= buf_.ptr && data_ <= buf_.ptr+buf_.header->used );
3607  Size offset = (Size)(data_ - buf_.ptr);
3608  {
3609  const Size tailsize = buf_.header->used - size_ - offset;
3610  if (tailsize > 0) {
3611  DataInit<T>::uninit(data_+size_, tailsize);
3612  buf_.header->used -= tailsize;
3613  }
3614  }
3615  if (newused > buf_.header->size) {
3616  // Move to new bigger buffer
3617  Size newbufsize = Capacity::grow(buf_.header->size);
3618  if (newbufsize <= newused)
3619  newbufsize = newused + 1; // Leave extra space
3620  Header* newheader;
3621  T* newbuf = buf_.memalloc(newbufsize, newused, newheader);
3622  memcpy((void*)newbuf, (void*)data_, sizeof(T)*index);
3623  memcpy((void*)(newbuf+index+size), (void*)(data_+index), sizeof(T)*(size_-index));
3624  if (offset > 0)
3625  DataInit<T>::uninit(buf_.ptr, offset);
3626 
3627  // Write new items
3628  meminit(newbuf+index, data, size);
3629 
3630  // Free old items, update state
3631  buf_.memfree();
3632  buf_.header = newheader;
3633  buf_.ptr = newbuf;
3634  data_ = newbuf;
3635  } else if (size > offset) {
3636  // Shift beginning and end to make room
3637  if (offset > 0) {
3638  DataInit<T>::uninit(buf_.ptr, offset);
3639  memmove((void*)buf_.ptr, (void*)data_, sizeof(T)*index);
3640  if (data >= data_ && data < data_ + index)
3641  data -= offset; // Copy from self, adjust for shift
3642  data_ = buf_.ptr;
3643  }
3644  T* ptr = data_ + index;
3645  memmove((void*)(ptr+size), (void*)(ptr+offset), sizeof(T)*(size_-index));
3646  buf_.header->used = newused;
3647 
3648  // Write new items
3649  if (data >= data_ && data < ptr) {
3650  // Copy from self before insert point
3651  Size sz = (Size)(ptr - data);
3652  if (sz > size)
3653  sz = size;
3654  meminit(ptr, data, sz);
3655  if (size > sz)
3656  meminit(ptr+sz, ptr+size, size-sz);
3657  } else {
3658  if (data < (data_ + size_) && data >= data_)
3659  data += (size - offset); // Copy from self after insert point, adjust for shift
3660  meminit(data_+index, data, size);
3661  }
3662  } else {
3663  // Shift beginning to make room
3664  const Size newoffset = offset - size;
3665  DataInit<T>::uninit(buf_.ptr, offset-newoffset);
3666  if (data >= data_ && data < data_ + index) {
3667  // Copy from self, which is splitting to make room
3668  data_ = buf_.ptr + newoffset;
3669  memmove((void*)data_, (void*)(buf_.ptr+offset), sizeof(T)*index);
3670  data -= (offset - newoffset); // source moved, adjust pointer
3671 
3672  // Write new items
3673  if (size >= index) {
3674  // Insert splits source, copy from both sides of split -- data after insert hasn't moved
3675  T* ptr = data_ + index;
3676  const Size sz = (Size)(ptr - data);
3677  meminit(ptr, data, sz);
3678  meminit(ptr+sz, ptr+size, size-sz);
3679  } else
3680  meminit(data_+index, data, size);
3681  } else {
3682  data_ = buf_.ptr + newoffset;
3683  memmove((void*)data_, (void*)(buf_.ptr+offset), sizeof(T)*index);
3684 
3685  // Write new items
3686  meminit(data_+index, data, size);
3687  }
3688  }
3689  size_ = newused;
3690  return index;
3691  }
3692  }
3693 
3694  // New buffer
3695  Header* newheader;
3696  T* newbuf = buf_.memalloc(size_+size, newheader);
3697  {
3698  DataInit<T>::init(newbuf, data_, index);
3699  const Size nextindex = index + size;
3700  assert( nextindex < newheader->used );
3701  DataInit<T>::init(newbuf+nextindex, data_+index, newheader->used-nextindex);
3702  }
3703  meminit(newbuf+index, data, size);
3704  data_ = buf_.replace(newbuf, newheader);
3705  size_ = buf_.header->used;
3706  #if EVO_LIST_OPT_REFTERM
3707  terminated_ = false;
3708  #endif
3709  return index;
3710  }
3711  return NONE;
3712  }
3713 
3720  Size modRemove(Size index, Size size, bool uninit=true) {
3721  if (index < size_) {
3722  {
3723  const Size maxsize = size_ - index;
3724  if (size > maxsize)
3725  size = maxsize;
3726  }
3727  if (size >= size_) {
3728  // Remove all -- mostly copied from clear()
3729  assert( size == size_ );
3730  assert( data_ > EVO_PEMPTY );
3731  if (buf_.ptr != NULL) {
3732  assert( buf_.header != NULL );
3733  if (buf_.header->refs > 1) {
3734  // Detach from shared
3735  --buf_.header->refs;
3736  buf_.header = NULL;
3737  buf_.ptr = NULL;
3738  data_ = EVO_PEMPTY;
3739  } else if (buf_.header->used > 0) {
3740  // Clear buffer, leave buffer for later use
3741  assert( buf_.header->refs == 1 );
3742  if (uninit) {
3743  DataInit<T>::uninit(buf_.ptr, buf_.header->used);
3744  } else {
3745  // Uninitialize only previously removed items
3746  assert( data_ >= buf_.ptr && data_ <= buf_.ptr+buf_.header->used );
3747  const Size offset = (Size)(data_ - buf_.ptr);
3748  if (offset > 0)
3749  DataInit<T>::uninit(buf_.ptr, offset);
3750 
3751  const Size tailsize = buf_.header->used - size_ - offset;
3752  if (tailsize > 0) {
3753  DataInit<T>::uninit(data_+size_, tailsize);
3754  buf_.header->used -= tailsize;
3755  }
3756  }
3757  buf_.header->used = 0;
3758  data_ = buf_.ptr;
3759  }
3760  } else {
3761  data_ = EVO_PEMPTY;
3762  #if !EVO_LIST_OPT_LAZYBUF
3763  // Lazy buffer disabled
3764  assert( buf_.header == NULL );
3765  #endif
3766  }
3767  size_ = 0;
3768  #if EVO_LIST_OPT_REFTERM
3769  terminated_ = false;
3770  #endif
3771  } else if (size > 0) {
3772  // Remove some
3773  if (buf_.header != NULL) {
3774  const Size newsize = size_ - size;
3775  #if EVO_LIST_OPT_LAZYBUF
3776  if (buf_.ptr == NULL) {
3777  if (buf_.header->size >= newsize) {
3778  // Use previous buffer
3779  assert( buf_.header->used == 0 );
3780  buf_.ptr = (T*)(buf_.header + 1);
3781  if (index > 0)
3782  DataInit<T>::init(buf_.ptr, data_, index);
3783  const Size nextindex = index + size;
3784  if (nextindex < size_)
3785  DataInit<T>::init(buf_.ptr+index, data_+nextindex, size_-nextindex);
3786  buf_.header->used = newsize;
3787  data_ = buf_.ptr;
3788  size_ = newsize;
3789  #if EVO_LIST_OPT_REFTERM
3790  terminated_ = false;
3791  #endif
3792  return size;
3793  }
3794  } else
3795  #else
3796  // Lazy buffer disabled
3797  assert( buf_.ptr != NULL );
3798  #endif
3799  if (buf_.header->refs == 1) {
3800  // Existing buffer
3801  assert( data_ >= buf_.ptr && data_ <= buf_.ptr+buf_.header->used );
3802  const Size offset = (Size)(data_ - buf_.ptr);
3803  {
3804  const Size tailsize = buf_.header->used - size_ - offset;
3805  if (tailsize > 0) {
3806  DataInit<T>::uninit(data_+size_, tailsize);
3807  buf_.header->used -= tailsize;
3808  }
3809  }
3810 
3811  // Remove items
3812  if (uninit)
3813  DataInit<T>::uninit(data_+index, size);
3814  const Size nextindex = index + size;
3815  if (nextindex < size_)
3816  memmove((void*)(data_+index), (void*)(data_+nextindex), sizeof(T)*(size_-nextindex));
3817  buf_.header->used -= size;
3818  size_ = newsize;
3819  return size;
3820  }
3821  }
3822 
3823  // New buffer
3824  assert( data_ != NULL );
3825  Header* newheader;
3826  const Size newused = size_ - size;
3827  T* newbuf = buf_.memalloc(newused+1, newused, newheader); // Leave extra space
3828  {
3829  if (index > 0)
3830  DataInit<T>::init(newbuf, data_, index);
3831  const Size nextindex = index + size;
3832  if (nextindex < size_)
3833  DataInit<T>::init(newbuf+index, data_+nextindex, size_-nextindex);
3834  }
3835  data_ = buf_.replace(newbuf, newheader);
3836  size_ = buf_.header->used;
3837  #if EVO_LIST_OPT_REFTERM
3838  terminated_ = false;
3839  #endif
3840  }
3841  } else
3842  size = 0;
3843  #if !EVO_LIST_OPT_LAZYBUF
3844  // Lazy buffer disabled
3845  assert( (buf_.header != NULL) == (buf_.ptr != NULL) );
3846  #endif
3847  return size;
3848  }
3849 
3858  void modReplace(Size index, Size size, const Item* data, Size newsize) {
3859  assert( size > 0 && newsize > 0 );
3860  assert( index < size_ );
3861  assert( data != NULL );
3862  const Size maxsize = size_ - index;
3863  if (size > maxsize)
3864  size = maxsize;
3865  if (buf_.header != NULL) {
3866  const Size newdatasize = size_ - size + newsize;
3867  #if EVO_LIST_OPT_LAZYBUF
3868  if (buf_.ptr == NULL) {
3869  if (buf_.header->size >= newdatasize) {
3870  // Use previous buffer
3871  assert( buf_.header->used == 0 );
3872  buf_.ptr = (T*)(buf_.header + 1);
3873  if (index > 0)
3874  DataInit<T>::init(buf_.ptr, data_, index);
3875  DataInit<T>::init(buf_.ptr+index, data, newsize);
3876 
3877  const Size nextindex = index + size;
3878  if (nextindex < size_)
3879  DataInit<T>::init(buf_.ptr+index+newsize, data_+nextindex, size_-nextindex);
3880  buf_.header->used = newdatasize;
3881  data_ = buf_.ptr;
3882  size_ = newdatasize;
3883  #if EVO_LIST_OPT_REFTERM
3884  terminated_ = false;
3885  #endif
3886  return;
3887  }
3888  } else
3889  #else
3890  // Lazy buffer disabled
3891  assert( buf_.ptr != NULL );
3892  #endif
3893  if (buf_.header->refs == 1) {
3894  // Existing buffer
3895  assert( data_ >= buf_.ptr && data_ <= buf_.ptr+buf_.header->used );
3896  {
3897  // Replace existing items
3898  const Size copysize = (size < newsize ? size : newsize);
3899  assert( data < data_+index || data >= data_+index+copysize ); // Replacement source can't overlap with target to replace
3900  DataInit<T>::copy(data_+index, data, copysize);
3901  index += copysize;
3902  data += copysize;
3903  size -= copysize;
3904  newsize -= copysize;
3905  }
3906  if (size > 0) {
3907  // Remove extra items
3908  T* dataptr = data_ + index;
3909  DataInit<T>::uninit(dataptr, size);
3910  const Size nextindex = index + size;
3911  if (nextindex < size_)
3912  memmove(dataptr, data_+nextindex, sizeof(T)*(size_-nextindex));
3913  buf_.header->used -= size;
3914  size_ -= size;
3915  } else if (newsize > 0) {
3916  size = newsize;
3917  const Size newused = size_ + size;
3918 
3919  // Copied as-is from modInsertMid()
3920  Size offset = (Size)(data_ - buf_.ptr);
3921  {
3922  const Size tailsize = buf_.header->used - size_ - offset;
3923  if (tailsize > 0) {
3924  DataInit<T>::uninit(data_+size_, tailsize);
3925  buf_.header->used -= tailsize;
3926  }
3927  }
3928  if (newused > buf_.header->size) {
3929  // Move to new bigger buffer
3930  Size newbufsize = Capacity::grow(buf_.header->size);
3931  if (newbufsize <= newused)
3932  newbufsize = newused + 1; // Leave extra space
3933  Header* newheader;
3934  T* newbuf = buf_.memalloc(newbufsize, newused, newheader);
3935  memcpy((void*)newbuf, (void*)data_, sizeof(T)*index);
3936  memcpy((void*)(newbuf+index+size), (void*)(data_+index), sizeof(T)*(size_-index));
3937  if (offset > 0)
3938  DataInit<T>::uninit(buf_.ptr, offset);
3939 
3940  // Write new items
3941  meminit(newbuf+index, data, size);
3942 
3943  // Free old items, update state
3944  buf_.memfree();
3945  buf_.header = newheader;
3946  buf_.ptr = newbuf;
3947  data_ = newbuf;
3948  } else if (size > offset) {
3949  // Shift beginning and end to make room
3950  if (offset > 0) {
3951  DataInit<T>::uninit(buf_.ptr, offset);
3952  memmove((void*)buf_.ptr, (void*)data_, sizeof(T)*index);
3953  if (data >= data_ && data < data_ + index)
3954  data -= offset; // Copy from self, adjust for shift
3955  data_ = buf_.ptr;
3956  }
3957  T* ptr = data_ + index;
3958  memmove((void*)(ptr+size), (void*)(ptr+offset), sizeof(T)*(size_-index));
3959  buf_.header->used = newused;
3960 
3961  // Write new items
3962  if (data >= data_ && data < ptr) {
3963  // Copy from self before insert point
3964  Size sz = (Size)(ptr - data);
3965  if (sz > size)
3966  sz = size;
3967  meminit(ptr, data, sz);
3968  if (size > sz)
3969  meminit(ptr+sz, ptr+size, size-sz);
3970  } else {
3971  if (data < (data_ + size_) && data >= data_)
3972  data += (size - offset); // Copy from self after insert point, adjust for shift
3973  meminit(data_+index, data, size);
3974  }
3975  } else {
3976  // Shift beginning to make room
3977  const Size newoffset = (Size)(offset - size);
3978  DataInit<T>::uninit(buf_.ptr, offset-newoffset);
3979  if (data >= data_ && data < data_ + index) {
3980  // Copy from self, which is splitting to make room
3981  data_ = buf_.ptr + newoffset;
3982  memmove((void*)data_, (void*)(buf_.ptr+offset), sizeof(T)*index);
3983  data -= (offset - newoffset); // source moved, adjust pointer
3984 
3985  // Write new items
3986  if (size >= index) {
3987  // Insert splits source, copy from both sides of split -- data after insert hasn't moved
3988  T* ptr = data_ + index;
3989  const Size sz = (Size)(ptr - data);
3990  meminit(ptr, data, sz);
3991  meminit(ptr+sz, ptr+size, size-sz);
3992  } else
3993  meminit(data_+index, data, size);
3994  } else {
3995  data_ = buf_.ptr + newoffset;
3996  memmove((void*)data_, (void*)(buf_.ptr+offset), sizeof(T)*index);
3997 
3998  // Write new items
3999  meminit(data_+index, data, size);
4000  }
4001  }
4002  size_ = newused;
4003  }
4004  return;
4005  }
4006  }
4007 
4008  // New buffer
4009  Header* newheader;
4010  T* newbuf = buf_.memalloc(size_-size+newsize, newheader);
4011  {
4012  if (index > 0)
4013  DataInit<T>::init(newbuf, data_, index);
4014  DataInit<T>::init(newbuf+index, data, newsize);
4015  const Size fromindex = index + size;
4016  if (fromindex < size_)
4017  DataInit<T>::init(newbuf+index+newsize, data_+fromindex, size_-fromindex);
4018  }
4019  data_ = buf_.replace(newbuf, newheader);
4020  size_ = buf_.header->used;
4021  #if EVO_LIST_OPT_REFTERM
4022  terminated_ = false;
4023  #endif
4024  }
4025 
4031  static void meminit(T* ptr, const Item* data, Size size) {
4032  if (data == EVO_PDEFAULT)
4033  DataInit<T>::init(ptr, size);
4034  else if (data != NULL)
4035  DataInit<T>::init(ptr, data, size);
4036  }
4037 };
4038 
4040 
4041 }
4042 #if defined(_MSC_VER)
4043  #pragma warning(pop)
4044 #endif
4045 #endif
ListType & unslice()
Clean and remove hidden items previously removed via slicing (modifier).
Definition: list.h:1427
ListType & add(const Item *data, Size size)
Append new items copied from data pointer (modifier).
Definition: list.h:2019
Iter cend() const
Get iterator at end (const).
Definition: list.h:961
static void copy(Item *dest, const Item *src, ulong size)
Copy already initialized data (assignment operator).
Definition: container.h:297
List(const ListType &data, Key index, Key size=ALL)
Extended copy constructor.
Definition: list.h:381
bool pop(T &item)
Pop a copy of last item (stack) (modifier).
Definition: list.h:2219
Size size() const
Get size.
Definition: list.h:759
static void init_tail_safe(Item *data, ulong oldSize, ulong newSize)
Initialize new tail data (default constructor).
Definition: container.h:252
T & max(T &a, T &b)
Returns highest of given values.
Definition: alg.h:47
void swap(Key index1, Key index2)
Swap items.
Definition: list.h:2497
T * advWrite(Size addsize)
Advanced: Get buffer pointer to write/append (modifier).
Definition: list.h:2768
void advPrepend(Size size)
Advanced: Prepend new items without initializing (constructing) them.
Definition: list.h:2834
T * dataM()
Get data pointer (mutable).
Definition: list.h:1464
static ulong grow(ulong size)
Grow data size.
Definition: container.h:113
Key findr(ItemVal item, Key start=0, Key end=END) const
Find last occurrence of item with reverse search.
Definition: list.h:1032
ListType & add(const ListBaseType &data)
Append new items copied from another list (modifier).
Definition: list.h:2029
Size capacity() const
Get capacity.
Definition: list.h:777
const Item * pop()
Pop last item (stack).
Definition: list.h:2237
ListType & operator=(const ListType &data)
Assignment operator.
Definition: list.h:522
void clear()
Clear data and free buffer.
Definition: list.h:287
void swap(ListType &list)
Swap with another list.
Definition: list.h:2509
List buffer data helper.
Definition: list.h:3008
T & advItem(Key index)
Advanced: Get item (mutable).
Definition: list.h:2796
ValEmpty
Special empty value type, pass as vEMPTY.
Definition: sys.h:1101
ListType & operator=(ListType &&src)
Move assignment operator (C++11).
Definition: list.h:496
bool splitat(Key index, T1 &left, T2 &right) const
Split into left/right sublists at index.
Definition: list.h:1151
Iter begin() const
Get iterator at first item (const).
Definition: list.h:980
bool starts(const ListBaseType &items) const
Check if this starts with given items.
Definition: list.h:912
Key findany(const Item *items, Size count, Key start=0, Key end=END) const
Find first occurrence of any given items with forward search.
Definition: list.h:1051
Size insertnew(Key index, Size size=1)
Insert new items (modifier).
Definition: list.h:2154
void advSize(Size size)
Advanced: Set new size after writing directly to buffer.
Definition: list.h:2754
T Item
Item type (same as Value)
Definition: list.h:250
#define EVO_CONTAINER_TYPE
Identify current class/struct as an EvoContainer.
Definition: meta.h:482
ListType & set2(const ListType &data, Key index1, Key index2)
Set from subset of another list using start/end positions.
Definition: list.h:700
List(const Item *data, Size size)
Constructor for data pointer.
Definition: list.h:448
ListType & operator<<(const ListBaseType &data)
Append operator.
Definition: list.h:2069
Key iend(Size offset=0) const
Get index from last item using offset.
Definition: list.h:826
void ref(const ListType &data)
Set as reference to another list.
Definition: list.h:3144
int compare(const ListBaseType &data) const
Comparison.
Definition: list.h:842
void * header
Internal buffer data, do not modify.
Definition: list.h:274
ListType & reserve(Size size, bool prefer_realloc=false)
Reserve capacity for additional items (modifier).
Definition: list.h:1703
ListType & slice2(Key index1, Key index2)
Slice to given sublist using start/end positions.
Definition: list.h:1418
List(std::initializer_list< T > init)
Sequence constructor (C++11).
Definition: list.h:476
Random access iterator.
Definition: iter.h:904
ValNull
Unique null value type and value (vNULL).
Definition: sys.h:1096
ListType & fill(const Item &item, Key index=0, Size size=ALL)
Fill using item (modifier).
Definition: list.h:2291
ListType & prepend(const Item &data)
Prepend new item (modifier).
Definition: list.h:2144
void move(Key dest, Key index)
Move item to position (modifier).
Definition: list.h:2338
ListType & prepend(const Item *data, Size size)
Prepend new items copied from data pointer (modifier).
Definition: list.h:2125
void free()
Free and uninitialize allocated buffer.
Definition: list.h:3112
Size size
Data size, update after write.
Definition: list.h:273
bool contains(const ListBaseType &data) const
Check if contains given data.
Definition: list.h:1124
ListType & operator=(const ListBaseType &data)
Assignment operator to copy sublist.
Definition: list.h:531
Edit()
Constructor.
Definition: list.h:277
ListType & copy(const ListBaseType &data)
Set as full (unshared) copy of another list (modifier).
Definition: list.h:1979
ListType & compact()
Reduce capacity to fit current size (modifier).
Definition: list.h:1686
const ListType & asconst() const
Explicitly use a const reference to this.
Definition: list.h:510
static void init_tail_fast(Item *data, ulong oldSize, ulong newSize)
Initialize new tail data (default constructor).
Definition: container.h:270
void advWriteDone(Size addsize)
Advanced: Update size added after writing directly to buffer.
Definition: list.h:2784
T * ptr
Data pointer, use to write to buffer.
Definition: list.h:272
Size insert(Key index, const ListBaseType &data)
Insert new items copied from another list (modifier).
Definition: list.h:2171
ListType & capacitymin(Size min)
Set minimum capacity (modifier).
Definition: list.h:1650
Basic integer type.
Definition: type.h:980
T & operator()(Key index)
Get item at position (mutable).
Definition: list.h:1475
const Item & item(Key index) const
Get item at position (const).
Definition: list.h:804
ListType & reverse()
Reverse item order (modifier).
Definition: list.h:2519
void advEditDone(Edit &edit)
Advanced: Finish edit started with advEdit() (modifier).
Definition: list.h:2697
void ref(const ListType &data, Size index, Size size)
Set as sliced reference to another list.
Definition: list.h:3203
bool splitat(Key index, T1 &left) const
Split into left sublist at index.
Definition: list.h:1177
void memfree()
Free buffer memory.
Definition: list.h:3099
ulong hash(ulong seed=0) const
Get data hash value.
Definition: list.h:833
bool ends(ItemVal item) const
Check if this ends with given item.
Definition: list.h:921
Key advInsert(Key index, Size size)
Advanced: Insert new items without initializing (constructing) them.
Definition: list.h:2846
bool contains(ItemVal item) const
Check whether contains given item.
Definition: list.h:1092
TSize Size
List size integer type
Definition: list.h:247
ListType & prepend(const ListBaseType &data)
Prepend new items copied from another list (modifier).
Definition: list.h:2135
const Item * data() const
Get data pointer (const).
Definition: list.h:786
ListType & set2(const ListBaseType &data, Key index1, Key index2)
Set as copy of sublist using start/end positions.
Definition: list.h:711
ListType & add(const Item &data)
Append new item (modifier).
Definition: list.h:2039
~Edit()
Destructor, frees buffer if needed.
Definition: list.h:281
void advAdd(Size size)
Advanced: Append new items without initializing (constructing) them.
Definition: list.h:2824
#define EVO_PEMPTY
Special pointer value for empty but not NULL (used in containers).
Definition: type.h:1858
List(const ValEmpty &val)
Constructor sets as empty but not null.
Definition: list.h:351
Size write(const ListBaseType &src, Size start=0, Size count=ALL)
Write (copy) data from source.
Definition: list.h:307
Iter end() const
Get iterator at end (const).
Definition: list.h:1000
Size move(Key dest, ListType &src, Key srcindex=0, Size size=ALL)
Move items from another list.
Definition: list.h:2365
List< T, Size > ListType
List type for parameters
Definition: list.h:254
Data equality helper.
Definition: container.h:712
bool starts(const Item *items, Size size) const
Check if starts with given items.
Definition: list.h:903
bool empty() const
Get whether empty.
Definition: list.h:753
List(ListType &&src)
Move constructor (C++11).
Definition: list.h:487
Evo implementation detail: Container iterators.
bool ends(const ListBaseType &items) const
Check if this ends with given items.
Definition: list.h:940
bool null() const
Get whether null.
Definition: list.h:745
bool popq(T &item)
Pop a copy of first item (queue) (modifier).
Definition: list.h:2253
ListType & addmin(Size minsize)
Append new items up to a given minimum size (modifier).
Definition: list.h:2005
ListType & triml(Size size)
Trim left (beginning) items.
Definition: list.h:1307
ListType & operator<<(const ValNull &val)
Append operator to set as null and empty.
Definition: list.h:2084
static const EndT END
Special integer value for indicating end of items or no item.
Definition: type.h:1846
void ref(const Item *data, Size size, bool term=false)
Set as reference to given data.
Definition: list.h:3268
ListType & capacity(Size size)
Set new capacity (modifier).
Definition: list.h:1516
ListType & addnew(Size size=1)
Append new items (modifier).
Definition: list.h:1996
const Item * first() const
Get first item (const).
Definition: list.h:810
const Item & operator[](Key index) const
Get item at position (const).
Definition: list.h:795
static const EndT ALL
Special integer value for indicating all items or all remaining items.
Definition: type.h:1839
ListType & trimr(Size size)
Trim right (ending) items.
Definition: list.h:1323
Evo container foundation types and macros.
ListType & clear()
Clear by removing all items.
Definition: list.h:574
Edit buffer for advEdit().
Definition: list.h:271
Size size
Buffer size allocated as item count.
Definition: list.h:3003
Iter cbegin() const
Get iterator at first item (const).
Definition: list.h:951
bool shared() const
Get whether shared.
Definition: list.h:767
ListType & operator=(const ValNull &)
Assignment operator to set as null and empty.
Definition: list.h:550
List(const ListBaseType &data, Key index=0, Key size=ALL)
Constructor to copy sublist data.
Definition: list.h:397
Size refs
Buffer reference count.
Definition: list.h:3004
ListType & slice(Key index, Size size)
Slice to given sublist.
Definition: list.h:1382
static ulong hash(const T *data, ulong size, ulong seed=0)
Compute hash value from data.
Definition: container.h:899
T * advLast()
Advanced: Get last item (modifier).
Definition: list.h:2814
bool splitat_setl(Key index, T2 &right)
Split at index, set as left sublist, and save right sublist.
Definition: list.h:1244
Item * lastM()
Get last item (mutable).
Definition: list.h:1503
IterM end()
Get iterator at end.
Definition: list.h:990
ListType & setempty()
Set as empty but not null.
Definition: list.h:735
void advSwap(Key index1, Key index2)
Advanced: Swap given items.
Definition: list.h:2867
bool starts(ItemVal item) const
Check if this starts with given item.
Definition: list.h:893
Evo C++ Library namespace.
Definition: alg.h:11
ListType & prependnew(Size size=1)
Prepend new items (modifier).
Definition: list.h:2114
static const EndT NONE
Special integer value for indicating no item or unknown item.
Definition: type.h:1832
List(const PtrBase< Item > &data, Size size)
Constructor to copy from managed pointer.
Definition: list.h:462
static bool equal(const T *data1, const T *data2, ulong size)
Compare array data for equality.
Definition: container.h:721
T * advFirst()
Advanced: Get first item (modifier).
Definition: list.h:2806
T * memalloc(Size size, Header *&header)
Allocate new memory.
Definition: list.h:3068
T * memalloc(Size size, Size used, Header *&header)
Allocate new memory.
Definition: list.h:3041
bool advEdit(Edit &edit, Size minsize, bool inplace=true)
Advanced: Start optimized in-place/buffer edit.
Definition: list.h:2648
Size used
Buffer size used/initialized as item count.
Definition: list.h:3002
ListType & operator<<(const ValEmpty &val)
Append operator to set as empty but not null.
Definition: list.h:2100
bool ends(const Item *items, Size size) const
Check if this ends with given items.
Definition: list.h:931
bool operator==(const ListBaseType &data) const
Equality operator.
Definition: list.h:857
Size write(const Item *data, Size count)
Write (copy) data from buffer.
Definition: list.h:329
T * advBuffer()
Advanced: Get buffer pointer (modifier).
Definition: list.h:2743
static void uninit(Item *data, ulong size)
Uninitialize data (destructor).
Definition: container.h:311
Size Key
Key type (item index)
Definition: list.h:248
static int compare(const T *data1, ulong size1, const T *data2, ulong size2)
Compare data.
Definition: container.h:769
ListType & capacitymax(Size max)
Set maximum capacity (modifier).
Definition: list.h:1668
ListType & operator<<(const Item &data)
Append operator.
Definition: list.h:2054
List(const ListType &data)
Copy constructor.
Definition: list.h:365
Buf buf_
List buffer.
Definition: list.h:3136
ListType & resize(Size size)
Resize while preserving existing data (modifier).
Definition: list.h:1850
T * memrealloc(Size size)
Reallocate buffer memory.
Definition: list.h:3077
DataCopy< T >::PassType ItemVal
Item type as parameter (POD types passed by value, otherwise by const-ref)
Definition: list.h:251
T * data_
Data pointer, NULL if null.
Definition: sys.h:979
P ptr_
Pointer.
Definition: type.h:1566
List< T, Size > ThisType
This list type.
Definition: list.h:253
AddConst< T >::Type & PassType
Most efficient type for passing as parameter (const-reference or POD value).
Definition: container.h:551
IteratorRa< ThisType >::Const Iter
Iterator (const) - IteratorRa.
Definition: list.h:263
IteratorRa< ThisType > IterM
Iterator (mutable) - IteratorRa.
Definition: list.h:264
static void init(Item *data, ulong size=1)
Initialize data using default constructor.
Definition: container.h:198
List()
Default constructor sets as null.
Definition: list.h:340
ListType & operator=(const ValEmpty &)
Assignment operator to set as empty but not null.
Definition: list.h:560
ListBase< T, Size > ListBaseType
List base type for any Evo list
Definition: list.h:255
Key find(ItemVal item, Key start=0, Key end=END) const
Find first occurrence of item with forward search.
Definition: list.h:1013
T * advBuffer(Size size)
Advanced: Resize and get buffer pointer (modifier).
Definition: list.h:2728
bool splitat(Key index, ValNull left, T2 &right) const
Split into right sublist at index.
Definition: list.h:1202
T Value
Value type (same as Item)
Definition: list.h:249
Size insert(Key index, const Item *data, Size size)
Insert new items copied from data pointer (modifier).
Definition: list.h:2163
static void fill(T *dest, ulong size, const T &value)
Fill with copies of given item.
Definition: container.h:621
TSize size_
Data size as item count, 0 if empty or null.
Definition: sys.h:980
bool contains(const Item *data, Size size) const
Check if contains given data.
Definition: list.h:1107
Sequential list container with random access.
Definition: list.h:240
Buf()
Constructor.
Definition: list.h:3016
static void init_safe(Item *data, ulong size=1)
Initialize data using default constructor.
Definition: container.h:159
bool pop(T &item, Key index)
Pop a copy of given item (modifier).
Definition: list.h:2201
ListType & unshare()
Make data unique by allocating new buffer, if needed (modifier).
Definition: list.h:1783
ListType & truncate(Size size=0)
Truncate to given size.
Definition: list.h:1342
const Item * popq()
Pop first item (queue).
Definition: list.h:2270
bool splitat_setl(Key index)
Split at index and set as left sublist.
Definition: list.h:1224
~Buf()
Destructor.
Definition: list.h:3022
static ulong init(ulong size)
Get initial data size.
Definition: container.h:103
T & itemM(Key index)
Get item at position (mutable).
Definition: list.h:1487
bool operator!=(const ListBaseType &data) const
Inequality operator.
Definition: list.h:874
T * replace(T *newptr, Header *newheader)
Free and uninitialize current buffer and replace with new buffer.
Definition: list.h:3125
Base managed pointer.
Definition: type.h:1562
ListType & advResize(Size size)
Advanced: Resize while preserving existing data, POD items not initialized (modifier).
Definition: list.h:2552
Base for all Evo list types (used internally).
Definition: sys.h:976
ListType & replace(Key index, Size rsize, const Item *data, Size size)
Replace items with new data (modifier).
Definition: list.h:2316
T & min(T &a, T &b)
Returns lowest of given values.
Definition: alg.h:26
bool splitat_setr(Key index)
Split at index and set as right sublist.
Definition: list.h:1264
#define EVO_PDEFAULT
Special pointer value for default initialization (used in containers).
Definition: type.h:1853
ListType & copy(const Item *data, Size size)
Set as full (unshared) copy using data pointer (modifier).
Definition: list.h:1929
const Item * last() const
Get last item (const).
Definition: list.h:816
ListType & slice(Key index)
Slice beginning items.
Definition: list.h:1360
void advRemove(Key index, Size size)
Advanced: Remove given items without uninitializing (destructing) them.
Definition: list.h:2857
Key findanyr(const Item *items, Size count, Key start=0, Key end=END) const
Find last occurrence of any given items with reverse search.
Definition: list.h:1073
List data header.
Definition: list.h:3001
List(const ListBaseType *data, Key index=0, Key size=ALL)
Constructor to copy sublist data.
Definition: list.h:423
Item * firstM()
Get first item (mutable).
Definition: list.h:1495
T * ptr
Data pointer, NULL if buffer not used.
Definition: list.h:3010
bool splitat_setr(Key index, T1 &left)
Split at index, set as right sublist, and save left sublist.
Definition: list.h:1285
void clear()
Clear buffer data.
Definition: list.h:3028
#define EVO_PARAM_UNUSED(NAME)
Mark function parameter as unused to suppress "unreferenced parameter" compiler warnings on it...
Definition: sys.h:427
Size insert(Key index, const Item &data)
Insert new item (modifier).
Definition: list.h:2179
IterM begin()
Get iterator at first item (mutable).
Definition: list.h:971
Header * header
Data header pointer, NULL if no buffer allocated.
Definition: list.h:3009