ecere/com/Containers: Fixed comparison of 2 null containers
[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(!b && !this) return 0;
160       if(GetCount() > b.GetCount()) return 1;
161       if(GetCount() < b.GetCount()) return -1;
162
163       ia = GetFirst();
164       ib = b.GetFirst();
165       while(ia && ib)
166       {
167          D dataA = GetData(ia);
168          D dataB = b.GetData(ib);
169          int r = onCompare(Dclass, byRef ? &dataA : (const void *)(uintptr)dataA, byRef ? &dataB : (const void *)(uintptr)dataB);
170          if(r) return r;
171          ia = GetNext(ia);
172          ib = b.GetNext(ib);
173       }
174       if(ia) return 1;
175       if(ib) return -1;
176       return 0;
177    }
178
179    void OnCopy(Container<T> source)
180    {
181       if(source)
182       {
183          // BUG IN this = SYNTAX
184          Container<T> container = eInstance_New(source._class);
185          // See WARNING in Copy()
186          container.Copy(source);
187          //*(void **)this = container;
188          this = container;
189       }
190       else
191       {
192          this = null;
193       }
194    }
195
196    virtual IteratorPointer Find(const D value)
197    {
198       IteratorPointer i;
199       Class Dclass = class(D);
200       bool byRef = (Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass;
201       int (* onCompare)(void *, const void *, const void *) = (void *)Dclass._vTbl[__ecereVMethodID_class_OnCompare];
202
203       if(byRef)
204       {
205          for(i = GetFirst(); i; i = GetNext(i))
206          {
207             D data = GetData(i);
208             int result = onCompare(Dclass, &value, &data);
209             if(!result)
210                return i;
211          }
212       }
213       else
214       {
215          for(i = GetFirst(); i; i = GetNext(i))
216          {
217             D data = GetData(i);
218             int result = onCompare(Dclass, (const void *)(uintptr) value, (const void *)(uintptr) data);
219             if(!result)
220                return i;
221          }
222       }
223       return null;
224    }
225
226    virtual void FreeIterator(IteratorPointer it);
227
228    virtual int GetCount()
229    {
230       int count = 0;
231       IteratorPointer i;
232       for(i = GetFirst(); i; i = GetNext(i)) count++;
233       return count;
234    }
235
236    virtual void Free()
237    {
238       IteratorPointer i;
239       while((i = GetFirst()))
240          Delete(i);
241    }
242
243    virtual void Delete(IteratorPointer i)
244    {
245       D data = GetData(i);
246       delete data;
247       Remove(i);
248    }
249
250    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
251    {
252       if(this)
253       {
254          char itemString[4096];//1024];
255          bool first = true;
256          IteratorPointer i;
257          tempString[0] = '\0';
258          for(i = GetFirst(); i; i = GetNext(i))
259          {
260             Class Dclass = class(D);
261             D data = GetData(i);
262             const char * result;
263
264             itemString[0] = '\0';
265
266             result = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnGetString])(Dclass,
267                ((Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass) ? &data : (void *)data, itemString, null, null);
268             if(!first) strcat(tempString, ", ");
269
270             strcat(tempString, result);
271             first = false;
272          }
273       }
274       else
275          tempString[0] = 0;
276       return tempString;
277    }
278
279    void TakeOut(const D d)
280    {
281       IteratorPointer i = Find(d);
282       if(i) Remove(i);
283    }
284
285    ~Container()
286    {
287       RemoveAll();
288    }
289
290    void OnSerialize(IOChannel channel)
291    {
292       // NOTE: Null containers currently get serialized as empty
293       uint count = this ? GetCount() : 0;
294       IteratorPointer i;
295       Class Dclass = class(D);
296       bool isNormalClass = (Dclass.type == normalClass) && Dclass.structSize;
297
298       channel.Put(count);
299       if(this)
300          for(i = GetFirst(); i; i = GetNext(i))
301          {
302             D data = GetData(i);
303             Class Eclass = isNormalClass ? ((Instance)data)._class : Dclass;
304             ((void (*)(void *, void *, void *))(void *)Eclass._vTbl[__ecereVMethodID_class_OnSerialize])(Eclass,
305                ((Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass) ? &data : (void *)data, channel);
306          }
307    }
308
309    void OnUnserialize(IOChannel channel)
310    {
311       Container container = eInstance_New(_class.fullName);
312       uint count, c;
313       Class Dclass = class(D);
314       D data;
315       bool isStruct = Dclass.type == structClass;
316
317       channel.Get(count);
318       if(isStruct)
319          data = (D)(new byte[Dclass.structSize]);
320       for(c = 0; c < count; c++)
321       {
322          if(isStruct)
323             memset((char *)data, 0, Dclass.structSize);
324          else
325             data = (D)0;
326          ((void (*)(void *, void *, void *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnUnserialize])
327             (Dclass, isStruct ? (void *)data : &data, channel);
328          container.Add(data);
329       }
330       if(isStruct)
331          delete (void *)data;
332       this = container;
333    }
334 }