ecere/com/Map: Fixed unserializing Maps with struct Key/Value
[sdk] / ecere / src / com / containers / Map.ec
1 namespace com;
2
3 #if !defined(_DEBUG) || defined(MEMINFO)
4 import "instance"  // TOFIX: This is required to build Debug on Ubuntu 10.04, GCC 4.4.3
5 #endif
6 import "CustomAVLTree"
7
8 default:
9 extern int __ecereVMethodID_class_OnCopy;
10 extern int __ecereVMethodID_class_OnFree;
11 extern int __ecereVMethodID_class_OnSerialize;
12 extern int __ecereVMethodID_class_OnUnserialize;
13 private:
14
15 public class MapNode<class KT, class V> : private AVLNode<KT>
16 {
17 class_fixed
18
19 public:
20    // public(key)
21    // THIS IS MISSING CODE FOR struct KEYS
22    property const KT key
23    {
24       get { return AVLNode::key; }
25       set { AVLNode::key = value; }
26    };
27    property V value
28    {
29       get { return this ? this.value : (V)0; }
30       set { this.value = value; }
31    };
32    V value;
33
34    // BECAUSE WE'RE PRIVATELY INHERITING, UNTIL public() works
35    property thisclass prev { get { return (MapNode<KT,V>)AVLNode::prev; } }
36    property thisclass next { get { return (MapNode<KT,V>)AVLNode::next; } }
37    property thisclass minimum { get { return (MapNode<KT,V>)AVLNode::minimum; } }
38    property thisclass maximum { get { return (MapNode<KT,V>)AVLNode::maximum; } }
39 }
40
41 public struct MapIterator<class KT, class V> : Iterator<V, IT = KT>
42 {
43    property Map map
44    {
45       set { container = (Container<V, IT>)value; }
46       get { return (Map<KT, V>)container; }
47    }
48    property const KT key
49    {
50       get { return ((Map<KT, V>)container).GetKey((MapNode<KT, V>)pointer); }
51    }
52    property V value
53    {
54       get { return container.GetData(pointer); }
55       set { container.SetData(pointer, value); }
56    }
57 };
58
59 public class Map<class MT, class V> : CustomAVLTree<MapNode<MT, V>, I = MT, D = V, KT = MT>
60 {
61    class_fixed
62
63    MT GetKey(MapNode<KT, V> node)
64    {
65       if(class(MT).type == structClass)
66          return (MT)(((byte *)&(uint64)node.key) + __ENDIAN_PAD(sizeof(void *)));
67       return node.key;
68    }
69
70    V GetData(MapNode<MT, V> node)
71    {
72       if(node)
73       {
74          // Adjust node pointer for non-standard AVLNode
75          if(class(MT).type == structClass)
76             node = (MapNode<MT, V>)(((byte *) node) + class(MT).structSize - sizeof(node.AVLNode::key));
77          return (class(V).type == structClass) ? (MT)&node.value : node.value;
78       }
79       return (MT)0;
80    }
81
82    bool SetData(MapNode<MT, V> node, MT value)
83    {
84       // Adjust node pointer for non-standard AVLNode
85       if(class(MT).type == structClass)
86          node = (MapNode<MT, V>)(((byte *) node) + class(MT).structSize - sizeof(node.AVLNode::key));
87
88       if(class(V).type == structClass)
89          memcpy((void *)&node.value, (void *)value, class(V).structSize);
90       else
91          node.value = value;
92       return true;
93    }
94
95    MapNode<MT, V> Add(BT _newNode)
96    {
97       MapNode<MT, V> newNode = (MapNode<MT, V>) _newNode;
98       if(class(MT).type == structClass || class(V).type == structClass)
99       {
100          MapNode<MT, V> realNode = (MapNode<MT, V>)GetAtPosition(newNode.key, true, null);
101          SetData(realNode, newNode.value);
102          return newNode;
103       }
104       else
105       {
106          MapNode<MT, V> node = root ? root.Find(class(MT), (T)newNode.key) : null;
107          if(!node)
108          {
109             Class Tclass = class(MT);
110             void (* onCopy)(void *, void *, void *) = Tclass._vTbl[__ecereVMethodID_class_OnCopy];
111             // Copy key here
112             if((Tclass.type == systemClass && !Tclass.byValueSystemClass) || Tclass.type == bitClass || Tclass.type == enumClass || Tclass.type == unitClass)
113                onCopy(Tclass, (byte *)&newNode.key + __ENDIAN_PAD(Tclass.typeSize), (byte *)&newNode.key + __ENDIAN_PAD(Tclass.typeSize));
114             else
115                onCopy(Tclass, (byte *)&newNode.key + __ENDIAN_PAD(sizeof(void *)), (void *)newNode.key);
116
117             CustomAVLTree::Add((T)newNode);
118             return newNode;
119          }
120          else
121          {
122             delete newNode;
123             return null;
124          }
125       }
126    }
127
128    void FreeKey(MapNode<MT, V> node)
129    {
130       if(class(MT).type == structClass)
131       {
132          // TODO: Make this easier...
133          Class Tclass = class(MT);
134          ((void (*)(void *, void *))(void *)Tclass._vTbl[__ecereVMethodID_class_OnFree])(Tclass, (((byte *)&node.key) + __ENDIAN_PAD(sizeof(void *))));
135       }
136       else
137          delete node.key;
138    }
139
140    void RemoveAll()
141    {
142       MapNode<MT, V> node = root;
143       while(node)
144       {
145          if(node.left)
146          {
147             MapNode<MT, V> left = node.left;
148             node.left = null;
149             node = left;
150          }
151          else if(node.right)
152          {
153             MapNode<MT, V> right = node.right;
154             node.right = null;
155             node = right;
156          }
157          else
158          {
159             MapNode<MT, V> parent = node.parent;
160             FreeKey(node);
161             delete node;
162
163             node = parent;
164          }
165       }
166       root = null;
167       count = 0;
168    }
169
170    void Remove(MapNode<MT, V> node)
171    {
172       CustomAVLTree::Remove(node);
173       FreeKey(node);
174       delete node;
175    }
176
177    void Free()
178    {
179       MapNode<MT, V> node = root;
180       while(node)
181       {
182          if(node.left)
183          {
184             MapNode<MT, V> left = node.left;
185             node.left = null;
186             node = left;
187          }
188          else if(node.right)
189          {
190             MapNode<MT, V> right = node.right;
191             node.right = null;
192             node = right;
193          }
194          else
195          {
196             MapNode<MT, V> parent = node.parent;
197             V value = GetData(node);
198             delete value;
199             FreeKey(node);
200             delete node;
201
202             node = parent;
203          }
204       }
205       root = null;
206       count = 0;
207    }
208
209    void Delete(MapNode<MT, V> node)
210    {
211       V value = GetData(node);
212       delete value;
213       FreeKey(node);
214       Remove(node);
215    }
216
217    MapNode<MT, V> Find(V value)
218    {
219       return (MapNode<MT, V>)Container::Find(value);
220    }
221
222    MapNode<MT, V> GetAtPosition(const MT pos, bool create, bool * justAdded)
223    {
224       AVLNode addNode = null;
225       AddSide addSide = compare;
226       MapNode<MT, V> node = root ? root.FindEx(class(MT), pos, &addNode, &addSide) : null;
227       if(!node && create)
228       {
229          Class Tclass = class(MT);
230          void (* onCopy)(void *, void *, void *) = Tclass._vTbl[__ecereVMethodID_class_OnCopy];
231          if(class(MT).type == structClass || class(V).type == structClass)
232          {
233             uint size = sizeof(class MapNode<MT, V>);
234
235             if(class(MT).type == structClass) size += class(MT).typeSize - sizeof(node.AVLNode::key);
236             if(class(V).type == structClass)
237                size += class(V).typeSize - sizeof(uint64); //sizeof(*&node.value);  // TODO: Simplify code generation for this sizeof
238             node = (MapNode<MT, V>)new0 byte[size];
239          }
240          else
241          {
242             node = MapNode<MT, V> { key = pos };
243          }
244          if((Tclass.type == systemClass && !Tclass.byValueSystemClass) || Tclass.type == bitClass || Tclass.type == enumClass || Tclass.type == unitClass)
245             // onCopy(Tclass, (byte *)&node.key + __ENDIAN_PAD(Tclass.typeSize), (byte *)&pos + __ENDIAN_PAD(Tclass.typeSize));
246             memcpy((byte *)&node.key + __ENDIAN_PAD(Tclass.typeSize), (byte *)&pos + __ENDIAN_PAD(Tclass.typeSize), Tclass.typeSize);
247          else
248             onCopy(Tclass, (byte *)&node.key + __ENDIAN_PAD(sizeof(void *)), (void *)pos);
249          CustomAVLTree::AddEx((T)(uintptr)node, (T)(uintptr)addNode, addSide);
250          if(justAdded) *justAdded = true;
251       }
252       return node;
253    }
254
255    void Copy(Container<T> source)
256    {
257       IteratorPointer i;
258       RemoveAll();
259       if(!eClass_IsDerived(source._class, class(Map)))
260       {
261          for(i = source.GetFirst(); i; i = source.GetNext(i))
262          {
263             MapNode<MT, V> srcNode = (MapNode<MT, V>)source.GetData(i);
264             MapNode<MT, V> destNode = (MapNode<MT, V>)GetAtPosition(srcNode.key, true, null);
265             SetData(destNode, srcNode.value);
266          }
267          // ADDED THIS HERE TO FREE BUILTIN CONTAINERS ASSIGNED TO A MAP
268          if(source._class == class(BuiltInContainer))
269             source.Free();
270       }
271    }
272
273    public property Map mapSrc
274    {
275       set
276       {
277          IteratorPointer i;
278          RemoveAll();
279          if(value && eClass_IsDerived(value._class, class(Map)))
280          {
281             for(i = value.GetFirst(); i; i = value.GetNext(i))
282             {
283                MapNode<MT, V> srcNode = (MapNode<MT, V>)i;
284                MapNode<MT, V> destNode = (MapNode<MT, V>)GetAtPosition(srcNode.key, true, null);
285                SetData(destNode, GetData(srcNode));
286             }
287          }
288       }
289    }
290
291    void OnSerialize(IOChannel channel)
292    {
293       uint count = GetCount();
294       IteratorPointer i;
295       Class Kclass = class(MT);
296       Class Dclass = class(V);
297       bool kIsNormalClass = (Kclass.type == normalClass) && Kclass.structSize;
298       bool dIsNormalClass = (Dclass.type == normalClass) && Dclass.structSize;
299
300       channel.Put(count);
301       for(i = GetFirst(); i; i = GetNext(i))
302       {
303          MapNode<MT, V> srcNode = (MapNode<MT, V>)i;
304          MT key = GetKey((MapNode<KT, V>)srcNode);
305          D data = GetData(srcNode);
306          Class kEclass = kIsNormalClass ? ((Instance)key)._class : Kclass;
307          Class dEclass = dIsNormalClass ? ((Instance)data)._class : Dclass;
308
309          ((void (*)(void *, void *, void *))(void *)kEclass._vTbl[__ecereVMethodID_class_OnSerialize])(kEclass,
310             ((Kclass.type == systemClass && !Kclass.byValueSystemClass) || Kclass.type == bitClass || Kclass.type == enumClass || Kclass.type == unitClass) ? &key : (void *)key, channel);
311          ((void (*)(void *, void *, void *))(void *)dEclass._vTbl[__ecereVMethodID_class_OnSerialize])(dEclass,
312             ((Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass) ? &data : (void *)data, channel);
313       }
314    }
315
316    void OnUnserialize(IOChannel channel)
317    {
318       uint c, count;
319       thisclass container = eInstance_New(_class.fullName);
320       Class Kclass = class(MT);
321       Class Dclass = class(V);
322       incref container;
323
324       channel.Get(count);
325       for(c = 0; c < count; c++)
326       {
327          MapNode<MT, V> destNode;
328          uint64 key  = (Kclass.type == structClass) ? (uint64)(uintptr)new byte[Kclass.structSize] : 0;
329          uint64 data = (Dclass.type == structClass) ? (uint64)(uintptr)new byte[Dclass.structSize] : 0;
330          ((void (*)(void *, void *, void *))(void *)Kclass._vTbl[__ecereVMethodID_class_OnUnserialize])(Kclass, &key, channel);
331          ((void (*)(void *, void *, void *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnUnserialize])(Dclass, (Dclass.type == structClass) ? (void *)data : &data, channel);
332          destNode = (MapNode<MT, V>)container.GetAtPosition((MT)key, true, null);
333          container.SetData(destNode, (V)data);
334          if(Kclass.type == structClass)
335             delete (void *)key;
336          if(Dclass.type == structClass)
337             delete (void *)data;
338       }
339       this = container;
340    }
341 }