ecere/containers: Saving null containers as empty
[sdk] / ecere / src / com / containers / Container.ec
1 namespace com;
2
3 import "BuiltInContainer"
4
5 default:
6
7 static __attribute__((unused)) void UnusedFunction()
8 {
9    int a;
10    a.OnCompare(null);
11    a.OnCopy(null);
12    a.OnGetString(null, null, null);
13    a.OnSerialize(null);
14    a.OnUnserialize(null);
15 }
16
17 extern int __ecereVMethodID_class_OnCompare;
18 extern int __ecereVMethodID_class_OnGetString;
19 extern int __ecereVMethodID_class_OnSerialize;
20 extern int __ecereVMethodID_class_OnUnserialize;
21 private:
22
23 // CAUSES PROBLEM WHEN AFTER
24 public struct Iterator<class T, class IT = int>
25 {
26    Container<T, IT> container;
27 // private:
28    IteratorPointer pointer;
29
30 public:
31    property T data
32    {
33       get { return container.GetData(pointer); }
34       set { container.SetData(pointer, value); }
35    }
36
37    bool Prev()
38    {
39       if(pointer && container)
40          pointer = container.GetPrev(pointer);
41       else if(container)
42          pointer = container.GetLast();
43       return pointer != null;
44    }
45
46    bool Next()
47    {
48       if(pointer && container)
49          pointer = container.GetNext(pointer);
50       else if(container)
51          pointer = container.GetFirst();
52       return pointer != null;
53    }
54
55    T GetData()
56    {
57       return container.GetData(pointer);
58    }
59
60    bool SetData(T value)
61    {
62       return container.SetData(pointer, value);
63    };
64
65    bool Find(const T value)
66    {
67       if(container)
68       {
69          Free();
70          pointer = container.Find(value);
71       }
72       return pointer != null;
73    }
74
75    void Remove()
76    {
77       if(container)
78          container.Remove(pointer);
79       pointer = null;
80    }
81
82    void Free()
83    {
84       if(container)
85          container.FreeIterator(pointer);
86    }
87
88    bool Index(const IT index, bool create)
89    {
90       if(container)
91       {
92          bool justAdded = false;
93          Free();
94          pointer = container.GetAtPosition(index, create, &justAdded);
95          return !justAdded && pointer != null;
96       }
97       return false;
98    }
99 };
100
101 public class Container<class T, class I = int, class D = T>
102 {
103 public:
104    class_fixed
105    public property Container<T> copySrc { set { if(value) Copy(value); } }
106    property Iterator<T> firstIterator { get { value = { (Container<T>)this, pointer = GetFirst() }; } }
107    property Iterator<T> lastIterator  { get { value = { (Container<T>)this, pointer = GetLast() }; } }
108
109    virtual IteratorPointer GetFirst() { return null; }
110    virtual IteratorPointer GetLast()  { return null; }
111    virtual IteratorPointer GetPrev(IteratorPointer pointer) { return null; }
112    virtual IteratorPointer GetNext(IteratorPointer pointer) { return null; }
113    virtual D GetData(IteratorPointer pointer) { return (D)0; }
114    virtual bool SetData(IteratorPointer pointer, D data);
115    virtual IteratorPointer GetAtPosition(const I pos, bool create, bool * justAdded) { return null; }
116
117    virtual IteratorPointer Insert(IteratorPointer after, T value);
118    virtual IteratorPointer Add(T value);
119    virtual void Remove(IteratorPointer it);
120    virtual void Move(IteratorPointer it, IteratorPointer after);
121
122    virtual void RemoveAll()
123    {
124       IteratorPointer i, next;
125       for(i = GetFirst(), next = i ? GetNext(i) : null; i; i = next, next = i ? GetNext(i) : null)
126          Remove(i);
127    }
128
129    virtual void Copy(Container<T> source)
130    {
131       IteratorPointer i;
132       RemoveAll();
133       for(i = source.GetFirst(); i; i = source.GetNext(i))
134       {
135          D data = source.GetData(i);
136          // WARNING: This doesn't make a new copy of the elements it adds
137          Add(data);
138       }
139    }
140
141    void OnFree()
142    {
143       if(this)
144       {
145          Free();
146          delete this;
147       }
148    }
149
150    int OnCompare(Container<T> b)
151    {
152       IteratorPointer ia, ib;
153       Class Dclass = class(D);
154       bool byRef = (Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass;
155       int (* onCompare)(void *, const void *, const void *) = (void *)Dclass._vTbl[__ecereVMethodID_class_OnCompare];
156
157       if(this && !b) return 1;
158       if(b && !this) return -1;
159       if(GetCount() > b.GetCount()) return 1;
160       if(GetCount() < b.GetCount()) return -1;
161
162       ia = GetFirst();
163       ib = b.GetFirst();
164       while(ia && ib)
165       {
166          D dataA = GetData(ia);
167          D dataB = b.GetData(ib);
168          int r = onCompare(Dclass, byRef ? &dataA : (const void *)(uintptr)dataA, byRef ? &dataB : (const void *)(uintptr)dataB);
169          if(r) return r;
170          ia = GetNext(ia);
171          ib = b.GetNext(ib);
172       }
173       if(ia) return 1;
174       if(ib) return -1;
175       return 0;
176    }
177
178    void OnCopy(Container<T> source)
179    {
180       if(source)
181       {
182          // BUG IN this = SYNTAX
183          Container<T> container = eInstance_New(source._class);
184          // See WARNING in Copy()
185          container.Copy(source);
186          //*(void **)this = container;
187          this = container;
188       }
189       else
190       {
191          this = null;
192       }
193    }
194
195    virtual IteratorPointer Find(const D value)
196    {
197       IteratorPointer i;
198       Class Dclass = class(D);
199       bool byRef = (Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass;
200       int (* onCompare)(void *, const void *, const void *) = (void *)Dclass._vTbl[__ecereVMethodID_class_OnCompare];
201
202       if(byRef)
203       {
204          for(i = GetFirst(); i; i = GetNext(i))
205          {
206             D data = GetData(i);
207             int result = onCompare(Dclass, &value, &data);
208             if(!result)
209                return i;
210          }
211       }
212       else
213       {
214          for(i = GetFirst(); i; i = GetNext(i))
215          {
216             D data = GetData(i);
217             int result = onCompare(Dclass, (const void *)(uintptr) value, (const void *)(uintptr) data);
218             if(!result)
219                return i;
220          }
221       }
222       return null;
223    }
224
225    virtual void FreeIterator(IteratorPointer it);
226
227    virtual int GetCount()
228    {
229       int count = 0;
230       IteratorPointer i;
231       for(i = GetFirst(); i; i = GetNext(i)) count++;
232       return count;
233    }
234
235    virtual void Free()
236    {
237       IteratorPointer i;
238       while((i = GetFirst()))
239          Delete(i);
240    }
241
242    virtual void Delete(IteratorPointer i)
243    {
244       D data = GetData(i);
245       delete data;
246       Remove(i);
247    }
248
249    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
250    {
251       if(this)
252       {
253          char itemString[4096];//1024];
254          bool first = true;
255          IteratorPointer i;
256          tempString[0] = '\0';
257          for(i = GetFirst(); i; i = GetNext(i))
258          {
259             Class Dclass = class(D);
260             D data = GetData(i);
261             const char * result;
262
263             itemString[0] = '\0';
264
265             result = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnGetString])(Dclass,
266                ((Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass) ? &data : (void *)data, itemString, null, null);
267             if(!first) strcat(tempString, ", ");
268
269             strcat(tempString, result);
270             first = false;
271          }
272       }
273       else
274          tempString[0] = 0;
275       return tempString;
276    }
277
278    void TakeOut(const D d)
279    {
280       IteratorPointer i = Find(d);
281       if(i) Remove(i);
282    }
283
284    ~Container()
285    {
286       RemoveAll();
287    }
288
289    void OnSerialize(IOChannel channel)
290    {
291       // NOTE: Null containers currently get serialized as empty
292       uint count = this ? GetCount() : 0;
293       IteratorPointer i;
294       Class Dclass = class(D);
295       bool isNormalClass = (Dclass.type == normalClass) && Dclass.structSize;
296
297       channel.Put(count);
298       if(this)
299          for(i = GetFirst(); i; i = GetNext(i))
300          {
301             D data = GetData(i);
302             Class Eclass = isNormalClass ? ((Instance)data)._class : Dclass;
303             ((void (*)(void *, void *, void *))(void *)Eclass._vTbl[__ecereVMethodID_class_OnSerialize])(Eclass,
304                ((Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass) ? &data : (void *)data, channel);
305          }
306    }
307
308    void OnUnserialize(IOChannel channel)
309    {
310       Container container = eInstance_New(_class.fullName);
311       uint count, c;
312       Class Dclass = class(D);
313       D data;
314       bool isStruct = Dclass.type == structClass;
315
316       channel.Get(count);
317       if(isStruct)
318          data = (D)(new byte[Dclass.structSize]);
319       for(c = 0; c < count; c++)
320       {
321          if(isStruct)
322             memset((char *)data, 0, Dclass.structSize);
323          else
324             data = (D)0;
325          ((void (*)(void *, void *, void *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnUnserialize])
326             (Dclass, isStruct ? (void *)data : &data, channel);
327          container.Add(data);
328       }
329       if(isStruct)
330          delete (void *)data;
331       this = container;
332    }
333 }