Merge: lib/standard/string: Introducting Copy-on-Write FlatBuffers
[nit.git] / lib / standard / string.nit
index c4c68ed..cbd86f1 100644 (file)
@@ -651,6 +651,10 @@ end
 abstract class FlatText
        super Text
 
+       # Underlying C-String (`char*`)
+       #
+       # Warning : Might be void in some subclasses, be sure to check
+       # if set before using it.
        private var items: NativeString
 
        # Real items, used as cache for to_cstring is called
@@ -997,15 +1001,15 @@ class FlatString
 
        redef fun to_cstring: NativeString
        do
-               if real_items != null then return real_items.as(not null)
-               if index_from > 0 or index_to != items.cstring_length - 1 then
+               if real_items != null then
+                       return real_items.as(not null)
+               else
                        var newItems = calloc_string(length + 1)
                        self.items.copy_to(newItems, length, index_from, 0)
                        newItems[length] = '\0'
                        self.real_items = newItems
                        return newItems
                end
-               return items
        end
 
        redef fun ==(other)
@@ -1227,6 +1231,14 @@ abstract class Buffer
        # Specific implementations MUST set this to `true` in order to invalidate caches
        protected var is_dirty = true
 
+       # Copy-On-Write flag
+       #
+       # If the `Buffer` was to_s'd, the next in-place altering
+       # operation will cause the current `Buffer` to be re-allocated.
+       #
+       # The flag will then be set at `false`.
+       protected var written = false
+
        # Modifies the char contained at pos `index`
        #
        # DEPRECATED : Use self.chars.[]= instead
@@ -1345,6 +1357,17 @@ class FlatBuffer
 
        redef fun substrings do return new FlatSubstringsIter(self)
 
+       # Re-copies the `NativeString` into a new one and sets it as the new `Buffer`
+       #
+       # This happens when an operation modifies the current `Buffer` and
+       # the Copy-On-Write flag `written` is set at true.
+       private fun reset do
+               var nns = new NativeString(capacity)
+               items.copy_to(nns, length, 0, 0)
+               items = nns
+               written = false
+       end
+
        redef fun [](index)
        do
                assert index >= 0
@@ -1359,6 +1382,7 @@ class FlatBuffer
                        add(item)
                        return
                end
+               if written then reset
                assert index >= 0 and index < length
                items[index] = item
        end
@@ -1373,6 +1397,7 @@ class FlatBuffer
 
        redef fun clear do
                is_dirty = true
+               if written then reset
                length = 0
        end
 
@@ -1383,6 +1408,9 @@ class FlatBuffer
                var c = capacity
                if cap <= c then return
                while c <= cap do c = c * 2 + 2
+               # The COW flag can be set at false here, since
+               # it does a copy of the current `Buffer`
+               written = false
                var a = calloc_string(c+1)
                if length > 0 then items.copy_to(a, length, 0, 0)
                items = a
@@ -1391,7 +1419,9 @@ class FlatBuffer
 
        redef fun to_s: String
        do
-               return to_cstring.to_s_with_length(length)
+               written = true
+               if length == 0 then items = new NativeString(1)
+               return new FlatString.with_infos(items, length, 0, length - 1)
        end
 
        redef fun to_cstring
@@ -1489,6 +1519,7 @@ class FlatBuffer
 
        redef fun reverse
        do
+               written = false
                var ns = calloc_string(capacity)
                var si = length - 1
                var ni = 0
@@ -1511,6 +1542,7 @@ class FlatBuffer
 
        redef fun upper
        do
+               if written then reset
                var it = items
                var id = length - 1
                while id >= 0 do
@@ -1521,6 +1553,7 @@ class FlatBuffer
 
        redef fun lower
        do
+               if written then reset
                var it = items
                var id = length - 1
                while id >= 0 do
@@ -2008,7 +2041,9 @@ extern class NativeString `{ char* `}
        fun to_s_with_length(length: Int): FlatString
        do
                assert length >= 0
-               return new FlatString.with_infos(self, length, 0, length - 1)
+               var str = new FlatString.with_infos(self, length, 0, length - 1)
+               str.real_items = self
+               return str
        end
 
        fun to_s_with_copy: FlatString
@@ -2016,7 +2051,9 @@ extern class NativeString `{ char* `}
                var length = cstring_length
                var new_self = calloc_string(length + 1)
                copy_to(new_self, length, 0, 0)
-               return new FlatString.with_infos(new_self, length, 0, length - 1)
+               var str = new FlatString.with_infos(new_self, length, 0, length - 1)
+               str.real_items = self
+               return str
        end
 end