doc/Container: Some container class documentation
[sdk] / ecere / src / com / containers / Container.ec
index ba68445..808251e 100644 (file)
@@ -4,7 +4,7 @@ import "BuiltInContainer"
 
 default:
 
-static void UnusedFunction()
+static __attribute__((unused)) void UnusedFunction()
 {
    int a;
    a.OnCompare(null);
@@ -62,7 +62,7 @@ public:
       return container.SetData(pointer, value);
    };
 
-   bool Find(T value)
+   bool Find(const T value)
    {
       if(container)
       {
@@ -85,13 +85,14 @@ public:
          container.FreeIterator(pointer);
    }
 
-   bool Index(IT index, bool create)
+   bool Index(const IT index, bool create)
    {
       if(container)
       {
+         bool justAdded = false;
          Free();
-         pointer = container.GetAtPosition(index, create);
-         return pointer != null;
+         pointer = container.GetAtPosition(index, create, &justAdded);
+         return !justAdded && pointer != null;
       }
       return false;
    }
@@ -101,7 +102,7 @@ public class Container<class T, class I = int, class D = T>
 {
 public:
    class_fixed
-   public property Container<T> copySrc { set { Copy(value); } }
+   public property Container<T> copySrc { set { if(value) Copy(value); } }
    property Iterator<T> firstIterator { get { value = { (Container<T>)this, pointer = GetFirst() }; } }
    property Iterator<T> lastIterator  { get { value = { (Container<T>)this, pointer = GetLast() }; } }
 
@@ -111,7 +112,7 @@ public:
    virtual IteratorPointer GetNext(IteratorPointer pointer) { return null; }
    virtual D GetData(IteratorPointer pointer) { return (D)0; }
    virtual bool SetData(IteratorPointer pointer, D data);
-   virtual IteratorPointer GetAtPosition(I pos, bool create) { return null; }
+   virtual IteratorPointer GetAtPosition(const I pos, bool create, bool * justAdded) { return null; }
 
    virtual IteratorPointer Insert(IteratorPointer after, T value);
    virtual IteratorPointer Add(T value);
@@ -145,7 +146,36 @@ public:
          delete this;
       }
    }
-   
+
+   int OnCompare(Container<T> b)
+   {
+      IteratorPointer ia, ib;
+      Class Dclass = class(D);
+      bool byRef = (Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass;
+      int (* onCompare)(void *, const void *, const void *) = (void *)Dclass._vTbl[__ecereVMethodID_class_OnCompare];
+
+      if(this && !b) return 1;
+      if(b && !this) return -1;
+      if(!b && !this) return 0;
+      if(GetCount() > b.GetCount()) return 1;
+      if(GetCount() < b.GetCount()) return -1;
+
+      ia = GetFirst();
+      ib = b.GetFirst();
+      while(ia && ib)
+      {
+         D dataA = GetData(ia);
+         D dataB = b.GetData(ib);
+         int r = onCompare(Dclass, byRef ? &dataA : (const void *)(uintptr)dataA, byRef ? &dataB : (const void *)(uintptr)dataB);
+         if(r) return r;
+         ia = GetNext(ia);
+         ib = b.GetNext(ib);
+      }
+      if(ia) return 1;
+      if(ib) return -1;
+      return 0;
+   }
+
    void OnCopy(Container<T> source)
    {
       if(source)
@@ -163,16 +193,19 @@ public:
       }
    }
 
-   virtual IteratorPointer Find(D value)
+   virtual IteratorPointer Find(const D value)
    {
       IteratorPointer i;
       Class Dclass = class(D);
-      if((Dclass.type == systemClass || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass))
+      bool byRef = (Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass;
+      int (* onCompare)(void *, const void *, const void *) = (void *)Dclass._vTbl[__ecereVMethodID_class_OnCompare];
+
+      if(byRef)
       {
          for(i = GetFirst(); i; i = GetNext(i))
          {
             D data = GetData(i);
-            int result = ((int (*)(void *, void *, void *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnCompare])(Dclass, &value,&data);
+            int result = onCompare(Dclass, &value, &data);
             if(!result)
                return i;
          }
@@ -182,7 +215,7 @@ public:
          for(i = GetFirst(); i; i = GetNext(i))
          {
             D data = GetData(i);
-            int result = ((int (*)(void *, void *, void *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnCompare])(Dclass, (void *)value, (void *)data);
+            int result = onCompare(Dclass, (const void *)(uintptr) value, (const void *)(uintptr) data);
             if(!result)
                return i;
          }
@@ -191,7 +224,7 @@ public:
    }
 
    virtual void FreeIterator(IteratorPointer it);
-   
+
    virtual int GetCount()
    {
       int count = 0;
@@ -203,7 +236,7 @@ public:
    virtual void Free()
    {
       IteratorPointer i;
-      while(i = GetFirst())
+      while((i = GetFirst()))
          Delete(i);
    }
 
@@ -214,7 +247,7 @@ public:
       Remove(i);
    }
 
-   char * OnGetString(char * tempString, void * fieldData, bool * needClass)
+   const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
    {
       if(this)
       {
@@ -226,15 +259,15 @@ public:
          {
             Class Dclass = class(D);
             D data = GetData(i);
-            char * result;
+            const char * result;
 
             itemString[0] = '\0';
-            
-            result = ((char *(*)(void *, void *, char *, void *, bool *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnGetString])(Dclass,
-               (Dclass.type == systemClass || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass) ? &data : (void *)data, itemString, null, null);
+
+            result = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnGetString])(Dclass,
+               ((Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass) ? &data : (void *)data, itemString, null, null);
             if(!first) strcat(tempString, ", ");
 
-            strcat(tempString, result);         
+            strcat(tempString, result);
             first = false;
          }
       }
@@ -243,7 +276,8 @@ public:
       return tempString;
    }
 
-   void TakeOut(D d)
+   // TODO: Warn against the danger of using TakeOut with 'normal' classes, as they will be considered equivalent if onCompare says so
+   void TakeOut(const D d)
    {
       IteratorPointer i = Find(d);
       if(i) Remove(i);
@@ -256,17 +290,21 @@ public:
 
    void OnSerialize(IOChannel channel)
    {
-      uint count = GetCount();
+      // NOTE: Null containers currently get serialized as empty
+      uint count = this ? GetCount() : 0;
       IteratorPointer i;
       Class Dclass = class(D);
+      bool isNormalClass = (Dclass.type == normalClass) && Dclass.structSize;
 
       channel.Put(count);
-      for(i = GetFirst(); i; i = GetNext(i))
-      {
-         D data = GetData(i);
-         ((void (*)(void *, void *, void *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnSerialize])(Dclass, 
-            (Dclass.type == systemClass || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass) ? &data : (void *)data, channel);
-      }
+      if(this)
+         for(i = GetFirst(); i; i = GetNext(i))
+         {
+            D data = GetData(i);
+            Class Eclass = isNormalClass ? ((Instance)data)._class : Dclass;
+            ((void (*)(void *, void *, void *))(void *)Eclass._vTbl[__ecereVMethodID_class_OnSerialize])(Eclass,
+               ((Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass) ? &data : (void *)data, channel);
+         }
    }
 
    void OnUnserialize(IOChannel channel)
@@ -274,14 +312,114 @@ public:
       Container container = eInstance_New(_class.fullName);
       uint count, c;
       Class Dclass = class(D);
+      D data;
+      bool isStruct = Dclass.type == structClass;
 
       channel.Get(count);
+      if(isStruct)
+         data = (D)(new byte[Dclass.structSize]);
       for(c = 0; c < count; c++)
       {
-         D data;
-         ((void (*)(void *, void *, void *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnUnserialize])(Dclass, &data, channel);
+         if(isStruct)
+            memset((char *)data, 0, Dclass.structSize);
+         else
+            data = (D)0;
+         ((void (*)(void *, void *, void *))(void *)Dclass._vTbl[__ecereVMethodID_class_OnUnserialize])
+            (Dclass, isStruct ? (void *)data : &data, channel);
          container.Add(data);
       }
+      if(isStruct)
+         delete (void *)data;
       this = container;
    }
+private:
+   // FIXME: Static is not overriding private
+   static void _Sort(bool ascending, Container * lists)
+   {
+      // Only sort containers with more than 1 items and which are integer indexable
+      int count = GetCount();
+      if(count >= 2 && class(I) == class(int))
+      {
+         Iterator a { this };
+         Iterator b { this };
+         Iterator mid { this };
+
+         Class Dclass = class(D);
+         bool byRef = (Dclass.type == systemClass && !Dclass.byValueSystemClass) || Dclass.type == bitClass || Dclass.type == enumClass || Dclass.type == unitClass;
+         int (* onCompare)(void *, const void *, const void *) = (void *)Dclass._vTbl[__ecereVMethodID_class_OnCompare];
+
+         Container listA = lists[0];
+         Container listB = lists[1];
+
+         // Find midpoint
+         mid.Index(count / 2-1, false);
+
+         // Split into 2 lists
+         while(a.Next())
+         {
+            listA.Add(a.data);
+            if(a.pointer == mid.pointer)
+               break;
+         }
+
+         b.pointer = mid.pointer;
+         while(b.Next())
+            listB.Add(b.data);
+
+         RemoveAll();
+
+         // Sort each of the 2 lists
+         listA._Sort(ascending, lists + 2);
+         listB._Sort(ascending, lists + 2);
+
+         // Merge
+         a = { listA };
+         b = { listB };
+         a.Next();
+         b.Next();
+
+         while(a.pointer || b.pointer)
+         {
+            int r;
+            if(a.pointer && b.pointer)
+            {
+               D dataA = a.data, dataB = b.data;
+               r = onCompare(Dclass, byRef ? &dataA : (const void *)(uintptr)dataA, byRef ? &dataB : (const void *)(uintptr)dataB);
+            }
+            else if(a.pointer)
+               r = -1;
+            else
+               r = 1;
+            if(!ascending) r *= -1;
+
+            if(r < 0)
+            {
+               Add(a.data);
+               a.Next();
+            }
+            else
+            {
+               Add(b.data);
+               b.Next();
+            }
+         }
+
+         listA.RemoveAll();
+         listB.RemoveAll();
+      }
+   }
+
+public:
+   virtual void Sort(bool ascending)
+   {
+      // Pre-allocate 2 log2(n) containers
+      int i, numLists = log2i(GetCount()) * 2;
+      Container * lists = new Container[numLists];
+      for(i = 0; i < numLists; i++)
+         lists[i] = eInstance_New(_class);
+      _Sort(ascending, lists);
+      for(i = 0; i < numLists; i++)
+         delete lists[i];
+      delete lists;
+   }
 }