Merge: Model uml
[nit.git] / lib / standard / string.nit
index 011cfa1..a81bdd6 100644 (file)
@@ -659,6 +659,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
@@ -826,6 +830,38 @@ abstract class String
 
                return new_str.to_s
        end
+
+       # Returns a capitalized `self`
+       #
+       # Letters that follow a letter are lowercased
+       # Letters that follow a non-letter are upcased.
+       #
+       # SEE : `Char::is_letter` for the definition of letter.
+       #
+       #    assert "jAVASCRIPT".capitalized == "Javascript"
+       #    assert "i am root".capitalized == "I Am Root"
+       #    assert "ab_c -ab0c ab\nc".capitalized == "Ab_C -Ab0C Ab\nC"
+       fun capitalized: SELFTYPE do
+               if length == 0 then return self
+
+               var buf = new FlatBuffer.with_capacity(length)
+
+               var curr = chars[0].to_upper
+               var prev = curr
+               buf[0] = curr
+
+               for i in [1 .. length[ do
+                       prev = curr
+                       curr = self[i]
+                       if prev.is_letter then
+                               buf[i] = curr.to_lower
+                       else
+                               buf[i] = curr.to_upper
+                       end
+               end
+
+               return buf.to_s
+       end
 end
 
 private class FlatSubstringsIter
@@ -973,15 +1009,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)
@@ -1203,6 +1239,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
@@ -1265,6 +1309,38 @@ abstract class Buffer
        #     assert b == "hello world!"
        fun lower is abstract
 
+       # Capitalizes each word in `self`
+       #
+       # Letters that follow a letter are lowercased
+       # Letters that follow a non-letter are upcased.
+       #
+       # SEE: `Char::is_letter` for the definition of a letter.
+       #
+       #    var b = new FlatBuffer.from("jAVAsCriPt")"
+       #    b.capitalize
+       #    assert b == "Javascript"
+       #    b = new FlatBuffer.from("i am root")
+       #    b.capitalize
+       #    assert b == "I Am Root"
+       #    b = new FlatBuffer.from("ab_c -ab0c ab\nc")
+       #    b.capitalize
+       #    assert b == "Ab_C -Ab0C Ab\nC"
+       fun capitalize do
+               if length == 0 then return
+               var c = self[0].to_upper
+               self[0] = c
+               var prev: Char = c
+               for i in [1 .. length[ do
+                       prev = c
+                       c = self[i]
+                       if prev.is_letter then
+                               self[i] = c.to_lower
+                       else
+                               self[i] = c.to_upper
+                       end
+               end
+       end
+
        redef fun hash
        do
                if is_dirty then hash_cache = null
@@ -1289,6 +1365,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
@@ -1303,6 +1390,7 @@ class FlatBuffer
                        add(item)
                        return
                end
+               if written then reset
                assert index >= 0 and index < length
                items[index] = item
        end
@@ -1317,6 +1405,7 @@ class FlatBuffer
 
        redef fun clear do
                is_dirty = true
+               if written then reset
                length = 0
        end
 
@@ -1327,6 +1416,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
@@ -1335,7 +1427,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
@@ -1433,6 +1527,7 @@ class FlatBuffer
 
        redef fun reverse
        do
+               written = false
                var ns = calloc_string(capacity)
                var si = length - 1
                var ni = 0
@@ -1455,6 +1550,7 @@ class FlatBuffer
 
        redef fun upper
        do
+               if written then reset
                var it = items
                var id = length - 1
                while id >= 0 do
@@ -1465,6 +1561,7 @@ class FlatBuffer
 
        redef fun lower
        do
+               if written then reset
                var it = items
                var id = length - 1
                while id >= 0 do
@@ -1952,7 +2049,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
@@ -1960,7 +2059,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