Browse Source

Refactor Vector and PODVector implementation.

Eugene Kozlov 9 years ago
parent
commit
7a600befd2
1 changed files with 121 additions and 185 deletions
  1. 121 185
      Source/Urho3D/Container/Vector.h

+ 121 - 185
Source/Urho3D/Container/Vector.h

@@ -36,8 +36,6 @@
 #pragma warning(disable:6293)
 #pragma warning(disable:6293)
 #endif
 #endif
 
 
-#define URHO3D_VECTOR_ISINSIDE(val) (&val >= Buffer() && &val < Buffer() + size_)
-
 namespace Urho3D
 namespace Urho3D
 {
 {
 
 
@@ -57,13 +55,21 @@ public:
     /// Construct with initial size.
     /// Construct with initial size.
     explicit Vector(unsigned size)
     explicit Vector(unsigned size)
     {
     {
-        Resize(size, 0);
+        Resize(size);
+    }
+
+    /// Construct with initial size and default value.
+    Vector(unsigned size, const T& value)
+    {
+        Resize(size);
+        for (unsigned i = 0; i < size; ++i)
+            At(i) = value;
     }
     }
 
 
     /// Construct with initial data.
     /// Construct with initial data.
     Vector(const T* data, unsigned size)
     Vector(const T* data, unsigned size)
     {
     {
-        Resize(size, data);
+        InsertElements(0, data, data + size);
     }
     }
 
 
     /// Construct from another vector.
     /// Construct from another vector.
@@ -84,7 +90,7 @@ public:
     /// Destruct.
     /// Destruct.
     ~Vector()
     ~Vector()
     {
     {
-        Clear();
+        DestructElements(Buffer(), size_);
         delete[] buffer_;
         delete[] buffer_;
     }
     }
 
 
@@ -92,7 +98,7 @@ public:
     Vector<T>& operator =(const Vector<T>& rhs)
     Vector<T>& operator =(const Vector<T>& rhs)
     {
     {
         Clear();
         Clear();
-        Resize(rhs.size_, rhs.Buffer());
+        InsertElements(0, rhs.Begin(), rhs.End());
         return *this;
         return *this;
     }
     }
 
 
@@ -192,14 +198,7 @@ public:
 #ifndef COVERITY_SCAN_MODEL
 #ifndef COVERITY_SCAN_MODEL
     void Push(const T& value)
     void Push(const T& value)
     {
     {
-        if (!URHO3D_VECTOR_ISINSIDE(value))
-            Resize(size_ + 1, &value);
-        else
-        {
-            // Value is inside vector; make copy to avoid iterator invalidation
-            T valueCopy(value);
-            Resize(size_ + 1, &valueCopy);
-        }
+        InsertElements(size_, &value, &value + 1);
     }
     }
 #else
 #else
     // FIXME: Attempt had been made to use this model in the Coverity-Scan model file without any success
     // FIXME: Attempt had been made to use this model in the Coverity-Scan model file without any success
@@ -207,109 +206,58 @@ public:
     void Push(const T& value)
     void Push(const T& value)
     {
     {
         T array[] = {value};
         T array[] = {value};
-        Resize(size_ + 1, array);
+        InsertElements(size_, array, array + 1);
     }
     }
 #endif
 #endif
 
 
     /// Add another vector at the end.
     /// Add another vector at the end.
-    void Push(const Vector<T>& vector) { Resize(size_ + vector.size_, vector.Buffer()); }
+    void Push(const Vector<T>& vector) { InsertElements(size_, vector.Begin(), vector.End()); }
 
 
     /// Remove the last element.
     /// Remove the last element.
     void Pop()
     void Pop()
     {
     {
         if (size_)
         if (size_)
-            Resize(size_ - 1, 0);
+            Resize(size_ - 1);
     }
     }
 
 
     /// Insert an element at position.
     /// Insert an element at position.
     void Insert(unsigned pos, const T& value)
     void Insert(unsigned pos, const T& value)
     {
     {
-        if (pos > size_)
-            pos = size_;
-
-        unsigned oldSize = size_;
-
-        if (!URHO3D_VECTOR_ISINSIDE(value))
-        {
-            Resize(size_ + 1, 0);
-            MoveRange(pos + 1, pos, oldSize - pos);
-            Buffer()[pos] = value;
-        }
-        else
-        {
-            T valueCopy(value);
-            Resize(size_ + 1, 0);
-            MoveRange(pos + 1, pos, oldSize - pos);
-            Buffer()[pos] = valueCopy;
-        }
+        InsertElements(pos, &value, &value + 1);
     }
     }
 
 
     /// Insert another vector at position.
     /// Insert another vector at position.
     void Insert(unsigned pos, const Vector<T>& vector)
     void Insert(unsigned pos, const Vector<T>& vector)
     {
     {
-        if (pos > size_)
-            pos = size_;
-
-        unsigned oldSize = size_;
-        Resize(size_ + vector.size_, 0);
-        MoveRange(pos + vector.size_, pos, oldSize - pos);
-        CopyElements(Buffer() + pos, vector.Buffer(), vector.size_);
+        InsertElements(pos, vector.Begin(), vector.End());
     }
     }
 
 
     /// Insert an element by iterator.
     /// Insert an element by iterator.
     Iterator Insert(const Iterator& dest, const T& value)
     Iterator Insert(const Iterator& dest, const T& value)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        Insert(pos, value);
-
-        return Begin() + pos;
+        return InsertElements(pos, &value, &value + 1);
     }
     }
 
 
     /// Insert a vector by iterator.
     /// Insert a vector by iterator.
     Iterator Insert(const Iterator& dest, const Vector<T>& vector)
     Iterator Insert(const Iterator& dest, const Vector<T>& vector)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        Insert(pos, vector);
-
-        return Begin() + pos;
+        return InsertElements(pos, vector.Begin(), vector.End());
     }
     }
 
 
     /// Insert a vector partially by iterators.
     /// Insert a vector partially by iterators.
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        unsigned length = (unsigned)(end - start);
-        Resize(size_ + length, 0);
-        MoveRange(pos + length, pos, size_ - pos - length);
-
-        T* destPtr = Buffer() + pos;
-        for (ConstIterator it = start; it != end; ++it)
-            *destPtr++ = *it;
-
-        return Begin() + pos;
+        return InsertElements(pos, start, end);
     }
     }
 
 
     /// Insert elements.
     /// Insert elements.
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        unsigned length = (unsigned)(end - start);
-        Resize(size_ + length, 0);
-        MoveRange(pos + length, pos, size_ - pos - length);
-
-        T* destPtr = Buffer() + pos;
-        for (const T* i = start; i != end; ++i)
-            *destPtr++ = *i;
-
-        return Begin() + pos;
+        return InsertElements(pos, start, end);
     }
     }
 
 
     /// Erase a range of elements.
     /// Erase a range of elements.
@@ -320,7 +268,7 @@ public:
             return;
             return;
 
 
         MoveRange(pos, pos + length, size_ - pos - length);
         MoveRange(pos, pos + length, size_ - pos - length);
-        Resize(size_ - length, 0);
+        Resize(size_ - length);
     }
     }
 
 
     /// Erase a range of elements by swapping elements from the end of the array.
     /// Erase a range of elements by swapping elements from the end of the array.
@@ -343,7 +291,7 @@ public:
             // Swap elements from the end of the array into the empty space
             // Swap elements from the end of the array into the empty space
             CopyElements(Buffer() + pos, Buffer() + newSize, length);
             CopyElements(Buffer() + pos, Buffer() + newSize, length);
         }
         }
-        Resize(newSize, 0);
+        Resize(newSize);
     }
     }
 
 
     /// Erase an element by iterator. Return iterator to the next element.
     /// Erase an element by iterator. Return iterator to the next element.
@@ -399,7 +347,7 @@ public:
     void Clear() { Resize(0); }
     void Clear() { Resize(0); }
 
 
     /// Resize the vector.
     /// Resize the vector.
-    void Resize(unsigned newSize) { Resize(newSize, 0); }
+    void Resize(unsigned newSize) { Vector<T> tempBuffer; Resize(newSize, 0, tempBuffer); }
 
 
     /// Set new capacity.
     /// Set new capacity.
     void Reserve(unsigned newCapacity)
     void Reserve(unsigned newCapacity)
@@ -503,8 +451,8 @@ public:
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
 
 
 private:
 private:
-    /// Resize the vector and create/remove new elements as necessary.
-    void Resize(unsigned newSize, const T* src)
+    /// Resize the vector and create/remove new elements as necessary. Current buffer will be stored in tempBuffer in case of reallocation.
+    void Resize(unsigned newSize, const T* src, Vector<T>& tempBuffer)
     {
     {
         // If size shrinks, destruct the removed elements
         // If size shrinks, destruct the removed elements
         if (newSize < size_)
         if (newSize < size_)
@@ -514,6 +462,10 @@ private:
             // Allocate new buffer if necessary and copy the current elements
             // Allocate new buffer if necessary and copy the current elements
             if (newSize > capacity_)
             if (newSize > capacity_)
             {
             {
+                Swap(tempBuffer);
+                size_ = tempBuffer.size_;
+                capacity_ = tempBuffer.capacity_;
+
                 if (!capacity_)
                 if (!capacity_)
                     capacity_ = newSize;
                     capacity_ = newSize;
                 else
                 else
@@ -522,14 +474,11 @@ private:
                         capacity_ += (capacity_ + 1) >> 1;
                         capacity_ += (capacity_ + 1) >> 1;
                 }
                 }
 
 
-                unsigned char* newBuffer = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
-                if (buffer_)
+                buffer_ = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
+                if (tempBuffer.Buffer())
                 {
                 {
-                    ConstructElements(reinterpret_cast<T*>(newBuffer), Buffer(), size_);
-                    DestructElements(Buffer(), size_);
-                    delete[] buffer_;
+                    ConstructElements(Buffer(), tempBuffer.Buffer(), size_);
                 }
                 }
-                buffer_ = newBuffer;
             }
             }
 
 
             // Initialize the new elements
             // Initialize the new elements
@@ -539,6 +488,26 @@ private:
         size_ = newSize;
         size_ = newSize;
     }
     }
 
 
+    /// Insert elements.
+    template <typename RandomIteratorT>
+    Iterator InsertElements(unsigned pos, RandomIteratorT start, RandomIteratorT end)
+    {
+        assert(start <= end);
+
+        if (pos > size_)
+            pos = size_;
+        unsigned length = (unsigned)(end - start);
+        Vector<T> tempBuffer;
+        Resize(size_ + length, 0, tempBuffer);
+        MoveRange(pos + length, pos, size_ - pos - length);
+
+        T* destPtr = Buffer() + pos;
+        for (RandomIteratorT it = start; it != end; ++it)
+            *destPtr++ = *it;
+
+        return Begin() + pos;
+    }
+
     /// Move a range of elements within the vector.
     /// Move a range of elements within the vector.
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     {
     {
@@ -607,11 +576,18 @@ public:
         Resize(size);
         Resize(size);
     }
     }
 
 
+    /// Construct with initial size and default value.
+    PODVector(unsigned size, const T& value)
+    {
+        Resize(size);
+        for (unsigned i = 0; i < size; ++i)
+            At(i) = value;
+    }
+
     /// Construct with initial data.
     /// Construct with initial data.
     PODVector(const T* data, unsigned size)
     PODVector(const T* data, unsigned size)
     {
     {
-        Resize(size);
-        CopyElements(Buffer(), data, size);
+        InsertElements(0, data, data + size);
     }
     }
 
 
     /// Construct from another vector.
     /// Construct from another vector.
@@ -638,8 +614,8 @@ public:
     /// Assign from another vector.
     /// Assign from another vector.
     PODVector<T>& operator =(const PODVector<T>& rhs)
     PODVector<T>& operator =(const PODVector<T>& rhs)
     {
     {
-        Resize(rhs.size_);
-        CopyElements(Buffer(), rhs.Buffer(), rhs.size_);
+        Clear();
+        InsertElements(0, rhs.Begin(), rhs.End());
         return *this;
         return *this;
     }
     }
 
 
@@ -738,32 +714,13 @@ public:
     /// Add an element at the end.
     /// Add an element at the end.
     void Push(const T& value)
     void Push(const T& value)
     {
     {
-        if (!URHO3D_VECTOR_ISINSIDE(value))
-        {
-            if (size_ < capacity_)
-                ++size_;
-            else
-                Resize(size_ + 1);
-            Back() = value;
-        }
-        else
-        {
-            // Value is inside vector; make copy to avoid iterator invalidation
-            T valueCopy(value);
-            if (size_ < capacity_)
-                ++size_;
-            else
-                Resize(size_ + 1);
-            Back() = valueCopy;
-        }
+        InsertElements(size_, &value, &value + 1);
     }
     }
 
 
     /// Add another vector at the end.
     /// Add another vector at the end.
     void Push(const PODVector<T>& vector)
     void Push(const PODVector<T>& vector)
     {
     {
-        unsigned oldSize = size_;
-        Resize(size_ + vector.size_);
-        CopyElements(Buffer() + oldSize, vector.Buffer(), vector.size_);
+        InsertElements(size_, vector.Begin(), vector.End());
     }
     }
 
 
     /// Remove the last element.
     /// Remove the last element.
@@ -776,89 +733,41 @@ public:
     /// Insert an element at position.
     /// Insert an element at position.
     void Insert(unsigned pos, const T& value)
     void Insert(unsigned pos, const T& value)
     {
     {
-        if (pos > size_)
-            pos = size_;
-
-        unsigned oldSize = size_;
-
-        if (!URHO3D_VECTOR_ISINSIDE(value))
-        {
-            Resize(size_ + 1);
-            MoveRange(pos + 1, pos, oldSize - pos);
-            Buffer()[pos] = value;
-        }
-        else
-        {
-            T valueCopy(value);
-            Resize(size_ + 1);
-            MoveRange(pos + 1, pos, oldSize - pos);
-            Buffer()[pos] = valueCopy;
-        }
+        InsertElements(pos, &value, &value + 1);
     }
     }
 
 
     /// Insert another vector at position.
     /// Insert another vector at position.
     void Insert(unsigned pos, const PODVector<T>& vector)
     void Insert(unsigned pos, const PODVector<T>& vector)
     {
     {
-        if (pos > size_)
-            pos = size_;
-
-        unsigned oldSize = size_;
-        Resize(size_ + vector.size_);
-        MoveRange(pos + vector.size_, pos, oldSize - pos);
-        CopyElements(Buffer() + pos, vector.Buffer(), vector.size_);
+        InsertElements(pos, vector.Begin(), vector.End());
     }
     }
 
 
     /// Insert an element by iterator.
     /// Insert an element by iterator.
     Iterator Insert(const Iterator& dest, const T& value)
     Iterator Insert(const Iterator& dest, const T& value)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        Insert(pos, value);
-
-        return Begin() + pos;
+        return InsertElements(pos, &value, &value + 1);
     }
     }
 
 
     /// Insert a vector by iterator.
     /// Insert a vector by iterator.
     Iterator Insert(const Iterator& dest, const PODVector<T>& vector)
     Iterator Insert(const Iterator& dest, const PODVector<T>& vector)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        Insert(pos, vector);
-
-        return Begin() + pos;
+        return InsertElements(pos, vector.Begin(), vector.End());
     }
     }
 
 
     /// Insert a vector partially by iterators.
     /// Insert a vector partially by iterators.
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        unsigned length = (unsigned)(end - start);
-        Resize(size_ + length);
-        MoveRange(pos + length, pos, size_ - pos - length);
-        CopyElements(Buffer() + pos, &(*start), length);
-
-        return Begin() + pos;
+        return InsertElements(pos, start, end);
     }
     }
 
 
     /// Insert elements.
     /// Insert elements.
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        unsigned length = (unsigned)(end - start);
-        Resize(size_ + length);
-        MoveRange(pos + length, pos, size_ - pos - length);
-
-        T* destPtr = Buffer() + pos;
-        for (const T* i = start; i != end; ++i)
-            *destPtr++ = *i;
-
-        return Begin() + pos;
+        return InsertElements(pos, start, end);
     }
     }
 
 
     /// Erase a range of elements.
     /// Erase a range of elements.
@@ -950,27 +859,8 @@ public:
     /// Resize the vector.
     /// Resize the vector.
     void Resize(unsigned newSize)
     void Resize(unsigned newSize)
     {
     {
-        if (newSize > capacity_)
-        {
-            if (!capacity_)
-                capacity_ = newSize;
-            else
-            {
-                while (capacity_ < newSize)
-                    capacity_ += (capacity_ + 1) >> 1;
-            }
-
-            unsigned char* newBuffer = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
-            // Move the data into the new buffer and delete the old
-            if (buffer_)
-            {
-                CopyElements(reinterpret_cast<T*>(newBuffer), Buffer(), size_);
-                delete[] buffer_;
-            }
-            buffer_ = newBuffer;
-        }
-
-        size_ = newSize;
+        PODVector<T> tempBuffer;
+        Resize(newSize, tempBuffer);
     }
     }
 
 
     /// Set new capacity.
     /// Set new capacity.
@@ -1066,6 +956,52 @@ public:
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
 
 
 private:
 private:
+    /// Resize the vector. Current buffer will be stored in tempBuffer in case of reallocation.
+    void Resize(unsigned newSize, PODVector<T>& tempBuffer)
+    {
+        if (newSize > capacity_)
+        {
+            Swap(tempBuffer);
+            size_ = tempBuffer.size_;
+            capacity_ = tempBuffer.capacity_;
+
+            if (!capacity_)
+                capacity_ = newSize;
+            else
+            {
+                while (capacity_ < newSize)
+                    capacity_ += (capacity_ + 1) >> 1;
+            }
+
+            buffer_ = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
+            // Move the data into the new buffer
+            if (tempBuffer.Buffer())
+            {
+                CopyElements(Buffer(), tempBuffer.Buffer(), size_);
+            }
+        }
+
+        size_ = newSize;
+    }
+
+    /// Insert elements.
+    template <typename RandomIteratorT>
+    Iterator InsertElements(unsigned pos, RandomIteratorT start, RandomIteratorT end)
+    {
+        if (pos > size_)
+            pos = size_;
+        unsigned length = (unsigned)(end - start);
+        PODVector<T> tempBuffer;
+        Resize(size_ + length, tempBuffer);
+        MoveRange(pos + length, pos, size_ - pos - length);
+
+        T* destPtr = Buffer() + pos;
+        for (RandomIteratorT i = start; i != end; ++i)
+            *destPtr++ = *i;
+
+        return Begin() + pos;
+    }
+
     /// Move a range of elements within the vector.
     /// Move a range of elements within the vector.
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     {
     {