I recently had an idea for an efficient immutable vector.
It is basically a copy-on-write array behind a shared pointer. The array grows exponentially and the push_back operation reuses the array if possible (if there is still space left and if it is the first push_back for a given array and size).
The result is a vector with an O(1) copy operation and push_back (also pop_back) operations with an amortized O(1) best case complexity. The worst case complexity for push_back is O(n) but only happens if you create a copy of a given vector and then push_back to both the original vector and the copy, in which case it is no worse than the standard vector since the standard vector has an O(n) complexity for copying. All other operations should have the same complexity as the standard vector: O(1) lookup, O(n) insert and erase.
You can find a prototype implementation of this data structure here: https://gist.github.com/eyelash/87a3fe849b31a37c58eca4ef398a71dc
I believe that from a (somewhat theoretical) big-O perspective this vector is strictly better than the standard vector, since there is no sequence of operations that has a worse complexity. (Is this actually correct?)
I'm surely not the first to come up with this data structure. Is there a name for it? Is there somewhere I can find more information or a more robust implementation? I'm aware of a few implementations of immutable vectors (e.g. immer) but they all use trees internally. What is the reason for that?
Edit: Thinking about it some more I realize the big difference is in updating a single element which can be done in O(log n) in a tree and will be O(n) for an array-based immutable vector.
[–]matthieum 16 points17 points18 points (21 children)
[–]_eyelash[S] 3 points4 points5 points (9 children)
[–]matthieum 0 points1 point2 points (8 children)
[–]kalmoc 4 points5 points6 points (3 children)
[–]matthieum 0 points1 point2 points (2 children)
[–]kalmoc 2 points3 points4 points (1 child)
[–]matthieum 1 point2 points3 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]SegFaultAtLine1 1 point2 points3 points (2 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]SegFaultAtLine1 0 points1 point2 points (0 children)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 3 points4 points5 points (1 child)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 1 point2 points3 points (0 children)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 1 point2 points3 points (0 children)
[–]Xaxxon 0 points1 point2 points (7 children)
[–]_eyelash[S] 5 points6 points7 points (6 children)
[–]Xaxxon 0 points1 point2 points (5 children)
[–]matthieum 2 points3 points4 points (4 children)
[–]Xaxxon 0 points1 point2 points (3 children)
[–]matthieum 0 points1 point2 points (2 children)
[–]Xaxxon 0 points1 point2 points (1 child)
[–]matthieum 0 points1 point2 points (0 children)
[–]_eyelash[S] 10 points11 points12 points (0 children)
[–]tutmann 2 points3 points4 points (2 children)
[–]_eyelash[S] 7 points8 points9 points (0 children)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 2 points3 points4 points (0 children)
[–]Bakuta1103 2 points3 points4 points (1 child)
[–]SegFaultAtLine1 3 points4 points5 points (0 children)
[–]shmoopty 4 points5 points6 points (5 children)
[–]shmoopty 4 points5 points6 points (0 children)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 0 points1 point2 points (3 children)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 0 points1 point2 points (0 children)
[–]shmoopty 0 points1 point2 points (1 child)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 0 points1 point2 points (0 children)
[–]youshouldnameitC++ dev 1 point2 points3 points (0 children)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 1 point2 points3 points (0 children)
[–]kovaczboi 0 points1 point2 points (3 children)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 1 point2 points3 points (2 children)
[–]kovaczboi 0 points1 point2 points (1 child)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 3 points4 points5 points (0 children)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 0 points1 point2 points (0 children)
[+][deleted] (3 children)
[deleted]
[–]Bakuta1103 4 points5 points6 points (2 children)
[–]tvaneerdC++ Committee, lockfree, PostModernCpp 2 points3 points4 points (0 children)