stdlib/strings: Minor style fix
[nit.git] / lib / standard / string.nit
index e47399b..aa3cef5 100644 (file)
@@ -38,6 +38,8 @@ abstract class Text
        # Type of self (used for factorization of several methods, ex : substring_from, empty...)
        type SELFTYPE: Text
 
+       var hash_cache: nullable Int = null
+
        # Gets a view on the chars of the Text object
        fun chars: SELFVIEW is abstract
 
@@ -121,6 +123,9 @@ abstract class Text
                return last_index_of_from(c, length - 1)
        end
 
+       # Return a null terminated char *
+       fun to_cstring: NativeString do return flatten.to_cstring
+
        # The index of the last occurrence of an element starting from pos (in reverse order).
        # Example :
        #               assert "/etc/bin/test/test.nit".last_index_of_from('/', length-1) == 13
@@ -174,6 +179,9 @@ abstract class Text
                return substring(from, length - from)
        end
 
+       # Returns a reversed version of self
+       fun reversed: SELFTYPE is abstract
+
        # Does self have a substring `str` starting from position `pos`?
        #
        #     assert "abcd".has_substring("bc",1)            ==  true
@@ -456,6 +464,23 @@ abstract class Text
        # Flat representation of self
        fun flatten: FlatText is abstract
 
+       redef fun hash
+       do
+               if hash_cache == null then
+                       # djb2 hash algorithm
+                       var h = 5381
+                       var i = length - 1
+
+                       for char in self.chars do
+                               h = (h * 32) + h + char.ascii
+                               i -= 1
+                       end
+
+                       hash_cache = h
+               end
+               return hash_cache.as(not null)
+       end
+
 end
 
 # All kinds of array-based text representations.
@@ -464,6 +489,9 @@ abstract class FlatText
 
        private var items: NativeString
 
+       # Real items, used as cache for to_cstring is called
+       private var real_items: nullable NativeString = null
+
        redef var length: Int
 
        init do end
@@ -626,6 +654,19 @@ class FlatString
                return items[index + index_from]
        end
 
+       redef fun reversed
+       do
+               var native = calloc_string(self.length + 1)
+               var reviter = chars.reverse_iterator
+               var pos = 0
+               while reviter.is_ok do
+                       native[pos] = reviter.item
+                       pos += 1
+                       reviter.next
+               end
+               return native.to_s_with_length(self.length)
+       end
+
        redef fun substring(from, count)
        do
                assert count >= 0
@@ -712,12 +753,14 @@ class FlatString
        end
 
        # Return a null terminated char *
-       fun to_cstring: NativeString
+       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
                        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
@@ -848,21 +891,25 @@ class FlatString
 
        redef fun hash
        do
-               # djb2 hash algorythm
-               var h = 5381
-               var i = length - 1
+               if hash_cache == null then
+                       # djb2 hash algorythm
+                       var h = 5381
+                       var i = length - 1
 
-               var myitems = items
-               var strStart = index_from
+                       var myitems = items
+                       var strStart = index_from
 
-               i += strStart
+                       i += strStart
+
+                       while i >= strStart do
+                               h = (h * 32) + h + self.items[i].ascii
+                               i -= 1
+                       end
 
-               while i >= strStart do
-                       h = (h * 32) + h + self.items[i].ascii
-                       i -= 1
+                       hash_cache = h
                end
 
-               return h
+               return hash_cache.as(not null)
        end
 end
 
@@ -944,6 +991,8 @@ abstract class Buffer
        redef type SELFVIEW: BufferCharView
        redef type SELFTYPE: Buffer
 
+       var is_dirty = true
+
        # Modifies the char contained at pos `index`
        #
        # DEPRECATED : Use self.chars.[]= instead
@@ -963,6 +1012,12 @@ abstract class Buffer
        # Adds the content of text `s` at the end of self
        fun append(s: Text) is abstract
 
+       redef fun hash
+       do
+               if is_dirty then hash_cache = null
+               return super
+       end
+
 end
 
 # Mutable strings of characters.
@@ -979,6 +1034,7 @@ class FlatBuffer
 
        redef fun []=(index, item)
        do
+               is_dirty = true
                if index == length then
                        add(item)
                        return
@@ -989,17 +1045,22 @@ class FlatBuffer
 
        redef fun add(c)
        do
+               is_dirty = true
                if capacity <= length then enlarge(length + 5)
                items[length] = c
                length += 1
        end
 
-       redef fun clear do length = 0
+       redef fun clear do
+               is_dirty = true
+               length = 0
+       end
 
        redef fun empty do return new FlatBuffer
 
        redef fun enlarge(cap)
        do
+               is_dirty = true
                var c = capacity
                if cap <= c then return
                while c <= cap do c = c * 2 + 2
@@ -1012,22 +1073,24 @@ class FlatBuffer
 
        redef fun to_s: String
        do
-               var l = length
-               var a = calloc_string(l+1)
-               items.copy_to(a, l, 0, 0)
-
-               # Ensure the afterlast byte is '\0' to nul-terminated char *
-               a[length] = '\0'
-
-               return a.to_s_with_length(length)
+               return to_cstring.to_s_with_length(length)
        end
 
-       # Create a new empty string.
-       init
+       redef fun to_cstring
        do
-               with_capacity(5)
+               if is_dirty then
+                       var new_native = calloc_string(length + 1)
+                       new_native[length] = '\0'
+                       items.copy_to(new_native, length, 0, 0)
+                       real_items = new_native
+                       is_dirty = false
+               end
+               return real_items.as(not null)
        end
 
+       # Create a new empty string.
+       init do with_capacity(5)
+
        init from(s: Text)
        do
                capacity = s.length + 1
@@ -1058,6 +1121,7 @@ class FlatBuffer
 
        redef fun append(s)
        do
+               is_dirty = true
                var sl = s.length
                if capacity < length + sl then enlarge(length + sl)
                if s isa FlatString then
@@ -1102,6 +1166,17 @@ class FlatBuffer
                end
        end
 
+       redef fun reversed
+       do
+               var new_buf = new FlatBuffer.with_capacity(self.length)
+               var reviter = self.chars.reverse_iterator
+               while reviter.is_ok do
+                       new_buf.add(reviter.item)
+                       reviter.next
+               end
+               return new_buf
+       end
+
        redef fun +(other)
        do
                var new_buf = new FlatBuffer.with_capacity(self.length + other.length)