Merge: Websockets
[nit.git] / lib / standard / string.nit
index e443433..2c46179 100644 (file)
@@ -448,13 +448,39 @@ abstract class Text
                return " " * before + self + " " * (diff-before)
        end
 
-       # Mangle a string to be a unique string only made of alphanumeric characters
+       # Mangle a string to be a unique string only made of alphanumeric characters and underscores.
+       #
+       # This method is injective (two different inputs never produce the same
+       # output) and the returned string always respect the following rules:
+       #
+       # * Contains only US-ASCII letters, digits and underscores.
+       # * Never starts with a digit.
+       # * Never ends with an underscore.
+       # * Never contains two contiguous underscores.
+       #
+       #     assert "42_is/The answer!".to_cmangle == "_52d2_is_47dThe_32danswer_33d"
+       #     assert "__".to_cmangle == "_95d_95d"
+       #     assert "__d".to_cmangle == "_95d_d"
+       #     assert "_d_".to_cmangle == "_d_95d"
+       #     assert "_42".to_cmangle == "_95d42"
+       #     assert "foo".to_cmangle == "foo"
+       #     assert "".to_cmangle == ""
        fun to_cmangle: String
        do
+               if is_empty then return ""
                var res = new FlatBuffer
                var underscore = false
-               for i in [0..length[ do
-                       var c = chars[i]
+               var start = 0
+               var c = chars[0]
+
+               if c >= '0' and c <= '9' then
+                       res.add('_')
+                       res.append(c.ascii.to_s)
+                       res.add('d')
+                       start = 1
+               end
+               for i in [start..length[ do
+                       c = chars[i]
                        if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
                                res.add(c)
                                underscore = false
@@ -477,6 +503,10 @@ abstract class Text
                                underscore = false
                        end
                end
+               if underscore then
+                       res.append('_'.ascii.to_s)
+                       res.add('d')
+               end
                return res.to_s
        end
 
@@ -1062,15 +1092,19 @@ class FlatString
                        from = 0
                end
 
-               var realFrom = index_from + from
+               var new_from = index_from + from
 
-               if (realFrom + count) > index_to then return new FlatString.with_infos(items, index_to - realFrom + 1, realFrom, index_to)
+               if (new_from + count) > index_to then
+                       var new_len = index_to - new_from + 1
+                       if new_len <= 0 then return empty
+                       return new FlatString.with_infos(items, new_len, new_from, index_to)
+               end
 
-               if count == 0 then return empty
+               if count <= 0 then return empty
 
-               var to = realFrom + count - 1
+               var to = new_from + count - 1
 
-               return new FlatString.with_infos(items, to - realFrom + 1, realFrom, to)
+               return new FlatString.with_infos(items, to - new_from + 1, new_from, to)
        end
 
        redef fun empty do return "".as(FlatString)
@@ -2144,7 +2178,7 @@ redef class Map[K,V]
                var i = iterator
                var k = i.key
                var e = i.item
-               s.append("{k}{couple_sep}{e or else "<null>"}")
+               s.append("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
 
                # Concat other items
                i.next
@@ -2152,7 +2186,7 @@ redef class Map[K,V]
                        s.append(sep)
                        k = i.key
                        e = i.item
-                       s.append("{k}{couple_sep}{e or else "<null>"}")
+                       s.append("{k or else "<null>"}{couple_sep}{e or else "<null>"}")
                        i.next
                end
                return s.to_s