1 #ifndef INDEXINGOBJECT_H 2 #define INDEXINGOBJECT_H 3 4 #include <cstddef> 5 #include <string> 6 #include <vector> 7 8 #include "attribute_.h" 9 #include "object.h" 10 11 /** an object that carries a vector of children objects, each accessible by its 12 * index 13 */ 14 template<typename T> 15 class IndexingObject : public Object { 16 public: IndexingObject()17 IndexingObject() 18 : count(this, "count", &IndexingObject<T>::sizeUnsignedLong) 19 { } addIndexed(T * newChild)20 void addIndexed(T* newChild) { 21 // the current array size is the index for the new child 22 unsigned long index = data.size(); 23 data.push_back(newChild); 24 // add a child object 25 addChild(newChild, std::to_string(index)); 26 newChild->setIndexAttribute(index); 27 } ~IndexingObject()28 ~IndexingObject() override { 29 clearChildren(); 30 } 31 removeIndexed(size_t idx)32 void removeIndexed(size_t idx) { 33 if (idx >= data.size()) { 34 // index does not exist 35 return; 36 } 37 38 T* child = byIdx(idx); 39 data.erase(data.begin() + idx); 40 41 removeChild(std::to_string(idx)); 42 43 // Update indices for remaining children 44 for (size_t new_idx = idx; new_idx < data.size(); new_idx++) { 45 std::string old_idx_str = std::to_string(new_idx + 1); 46 removeChild(old_idx_str); 47 addChild(data[new_idx], std::to_string(new_idx)); 48 data[new_idx]->setIndexAttribute(new_idx); 49 } 50 51 delete child; 52 } 53 index_of(T * child)54 int index_of(T* child) { 55 for (size_t i = 0; i < data.size(); i++) { 56 if (&* data[i] == child) { 57 return i; 58 } 59 } 60 return -1; 61 } 62 63 T& operator[](size_t idx) { 64 return *data[idx]; 65 } 66 byIdx(size_t idx)67 T* byIdx(size_t idx) { 68 return idx < data.size() ? data[idx] : nullptr; 69 } 70 size()71 size_t size() { 72 return data.size(); 73 } 74 75 // remove all "indexed" children clearChildren()76 void clearChildren() { 77 for (size_t idx = 0; idx < data.size(); idx++) { 78 removeChild(std::to_string(idx)); 79 } 80 for (auto child : data) { 81 delete child; 82 } 83 data.erase(data.begin(), data.end()); 84 } 85 indexChangeRequested(T * object,size_t newIndex)86 void indexChangeRequested(T* object, size_t newIndex) { 87 if (newIndex < data.size() && data[newIndex] == object) { 88 // nothing to do 89 return; 90 } 91 if (data.empty()) { 92 return; 93 } 94 if (newIndex >= data.size()) { 95 newIndex = data.size() - 1; 96 } 97 int oldIndexSigned = index_of(object); 98 if (oldIndexSigned < 0) { 99 return; 100 } 101 size_t oldIndex = static_cast<size_t>(oldIndexSigned); 102 if (newIndex == oldIndex) { 103 return; 104 } 105 // go from newIndex to oldIndex 106 int delta = (newIndex < oldIndex) ? 1 : -1; 107 T* lastValue = object; 108 for (size_t i = newIndex; i != oldIndex; i+= delta) { 109 // swap data[i] with lastValue 110 T* tmp = data[i]; 111 data[i] = lastValue; 112 lastValue = tmp; 113 } 114 data[oldIndex] = lastValue; 115 // for each of these, update the index 116 for (size_t i = newIndex; i != oldIndex; i+= delta) { 117 data[i]->setIndexAttribute(i); 118 addChild(data[i], std::to_string(i)); 119 } 120 data[oldIndex]->setIndexAttribute(oldIndex); 121 addChild(data[oldIndex], std::to_string(oldIndex)); 122 indicesChanged.emit(); 123 } 124 125 DynAttribute_<unsigned long> count; 126 Signal indicesChanged; 127 128 // iterators 129 typedef typename std::vector<T*>::iterator iterator_type; begin()130 iterator_type begin() { return data.begin(); } end()131 iterator_type end() { return data.end(); } 132 private: sizeUnsignedLong()133 unsigned long sizeUnsignedLong() { 134 return static_cast<unsigned long>(data.size()); 135 } 136 137 std::vector<T*> data; 138 }; 139 140 141 #endif 142