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