lib/standard/ropes: Adapted to_cstring for Ropes.
[nit.git] / lib / standard / ropes.nit
index 9da5d60..33d02ee 100644 (file)
@@ -96,6 +96,9 @@ abstract class Rope
        # Root node, entry point of a Rope.
        private var root: RopeNode
 
+       # Cached version of self as a flat String
+       private var str_representation: nullable NativeString = null
+
        # Empty Rope
        init do from("")
 
@@ -123,6 +126,32 @@ abstract class Rope
        # Iterator on the substrings, starting at position `from`, in forward order
        fun substrings_from(from: Int): IndexedIterator[Text] do return new SubstringsIterator(self, from)
 
+       redef fun to_cstring
+       do
+               if str_representation != null then return str_representation.as(not null)
+
+               var native_final_str = calloc_string(length + 1)
+
+               native_final_str[length] = '\0'
+
+               if self.length == 0 then
+                       str_representation = native_final_str
+                       return native_final_str
+               end
+
+               var offset = 0
+
+               for i in substrings do
+                       var str = i.flatten
+                       if str isa FlatString then str.items.copy_to(native_final_str, str.length, str.index_from, offset)
+                       offset += i.length
+               end
+
+               str_representation = native_final_str
+
+               return native_final_str
+       end
+
        # Path to the Leaf for `position`
        private fun node_at(position: Int): Path
        do
@@ -154,6 +183,17 @@ abstract class Rope
                end
        end
 
+       redef fun ==(o)
+       do
+               if not o isa Text then return false
+               if o.length != self.length then return false
+               var oit = o.chars.iterator
+               for i in self.chars.iterator do
+                       if i != oit.item then return false
+                       oit.next
+               end
+               return true
+       end
 end
 
 # Rope that cannot be modified
@@ -163,6 +203,46 @@ class RopeString
 
        redef fun to_s do return self
 
+       redef fun empty do return once new RopeString.from("")
+
+       redef fun reversed
+       do
+               var ret = empty.as(RopeString)
+               for i in substrings do
+                       ret = ret.prepend(i.reversed.to_s).as(RopeString)
+               end
+               return ret
+       end
+
+       redef fun to_upper
+       do
+               var ret = empty
+               for i in substrings do
+                       ret += i.to_upper
+               end
+               return ret
+       end
+
+       redef fun to_lower
+       do
+               var ret = empty
+               for i in substrings do
+                       ret += i.to_lower
+               end
+               return ret
+       end
+
+       redef fun +(o) do return insert_at(o.to_s, length)
+
+       redef fun *(n)
+       do
+               var ret = new RopeString.from("")
+               for i in [0..n[ do
+                       ret = (ret + self).as(RopeString)
+               end
+               return ret
+       end
+
        # Inserts a String `str` at position `pos`
        fun insert_at(str: String, pos: Int): RopeString
        do
@@ -210,6 +290,9 @@ class RopeString
                return new RopeString.from_root(last_concat)
        end
 
+       # Adds `s` at the beginning of self
+       fun prepend(s: String): String do return insert_at(s, 0)
+
        # Adds `s` at the end of self
        fun append(s: String): String
        do
@@ -477,3 +560,47 @@ class SubstringsIterator
 
 end
 
+class RopeCharIterator
+       super IndexedIterator[Char]
+
+       var substrings: IndexedIterator[Text]
+
+       var pos: Int
+
+       var max: Int
+
+       var substr_iter: IndexedIterator[Char]
+
+       init(tgt: Rope, from: Int)
+       do
+               substrings = tgt.substrings_from(from)
+               max = tgt.length - 1
+               if not substrings.is_ok then
+                       pos = tgt.length
+                       return
+               end
+               pos = from
+               substr_iter = substrings.item.chars.iterator
+       end
+
+       redef fun item do return substr_iter.item
+
+       redef fun is_ok do return pos <= max
+
+       redef fun index do return pos
+
+       redef fun next
+       do
+               pos += 1
+               if substr_iter.is_ok then
+                       substr_iter.next
+               end
+               if not substr_iter.is_ok then
+                       substrings.next
+                       if substrings.is_ok then
+                               substr_iter = substrings.item.chars.iterator
+                       end
+               end
+       end
+end
+