lib/string_exp: add a missing FFI `import UnicodeChar.len`
[nit.git] / lib / string_experimentations / utf8_noindex.nit
index cef60f7..bf49334 100644 (file)
@@ -73,7 +73,7 @@ extern class UnicodeChar `{ uint32_t* `}
        # Returns the Unicode code point representing the character
        #
        # Note : A unicode character might not be a visible glyph, but it will be used to determine canonical equivalence
-       fun code_point: Int `{
+       fun code_point: Int import UnicodeChar.len `{
                uint32_t val = *recv;
                uint32_t ret = 0;
                switch(UnicodeChar_len(recv)){
@@ -171,6 +171,14 @@ extern class UnicodeChar `{ uint32_t* `}
        `}
 end
 
+# Used to keep track of the last accessed char in a String
+class CharCache
+       # The position (as in char) of a String
+       var position: Int
+       # The position in the NativeString underlying the String
+       var bytepos: Int
+end
+
 class FlatStringReviter
        super IndexedIterator[UnicodeChar]
 
@@ -263,6 +271,9 @@ redef class FlatString
        # Length in bytes of the string (e.g. the length of the C string)
        redef var bytelen: Int
 
+       # Cache for the last accessed character in the char
+       var cache = new CharCache(-1,-1)
+
        redef var length = length_l is lazy
 
        private init full(items: NativeString, from, to, bytelen, len: Int)
@@ -324,22 +335,57 @@ redef class FlatString
        private fun byte_index(index: Int): Int do
                assert index >= 0
                assert index < length
-               var ns_i = index_from
-               var my_i = 0
-               while my_i != index do
-                       if items[ns_i].ascii.bin_and(0x80) == 0 then
+
+               # Find best insertion point
+               var delta_begin = index
+               var delta_end = (length - 1) - index
+               var delta_cache = (cache.position - index).abs
+               var min = delta_begin
+
+               if delta_cache < min then min = delta_cache
+               if delta_end < min then min = delta_end
+
+               var ns_i: Int
+               var my_i: Int
+               var myits = items
+
+               if min == delta_begin then
+                       ns_i = index_from
+                       my_i = 0
+               else if min == delta_cache then
+                       ns_i = cache.bytepos
+                       my_i = cache.position
+               else
+                       ns_i = index_to
+                       my_i = length
+               end
+
+               while my_i < index do
+                       if myits[ns_i].ascii.bin_and(0x80) == 0 then
                                ns_i += 1
-                       else if items[ns_i].ascii.bin_and(0xE0) == 0xC0 then
+                       else if myits[ns_i].ascii.bin_and(0xE0) == 0xC0 then
                                ns_i += 2
-                       else if items[ns_i].ascii.bin_and(0xF0) == 0xE0 then
+                       else if myits[ns_i].ascii.bin_and(0xF0) == 0xE0 then
                                ns_i += 3
-                       else if items[ns_i].ascii.bin_and(0xF7) == 0xF0 then
+                       else if myits[ns_i].ascii.bin_and(0xF7) == 0xF0 then
                                ns_i += 4
                        else
                                ns_i += 1
                        end
                        my_i += 1
                end
+
+               while my_i > index do
+                       if myits[ns_i].ascii.bin_and(0xC0) != 0x80 then
+                               my_i -= 1
+                               if my_i == index then break
+                       end
+                       ns_i -= 1
+               end
+
+               cache.position = index
+               cache.bytepos = ns_i
+
                return ns_i
        end