core: fix typos in union_find
[nit.git] / lib / core / bytes.nit
index 9bf70c0..84276ac 100644 (file)
@@ -214,7 +214,7 @@ class Bytes
                return slice(st, ed - st + 1)
        end
 
-       # Returns a subset of the content of `self` starting at `from` and of length `count`
+       # Copy a subset of `self` starting at `from` and of `count` bytes
        #
        #     var b = "abcd".to_bytes
        #     assert b.slice(1, 2).hexdigest == "6263"
@@ -239,7 +239,7 @@ class Bytes
                return ret
        end
 
-       # Returns a copy of `self` starting at `from`
+       # Copy of `self` starting at `from`
        #
        #     var b = "abcd".to_bytes
        #     assert b.slice_from(1).hexdigest  == "626364"
@@ -328,35 +328,48 @@ class Bytes
                return new FlatString.full(ns, elen, 0, elen)
        end
 
-       # Interprets `self` as a big-endian positive integer.
+       # Interprets `self` as a big-endian integer (unsigned by default)
        #
        # ~~~
        # var b = "0102".hexdigest_to_bytes
        # assert b.to_i == 258
+       #
+       # assert   "01".hexdigest_to_bytes.to_i == 1
+       # assert   "FF".hexdigest_to_bytes.to_i == 255
+       # assert "0000".hexdigest_to_bytes.to_i == 0
        # ~~~
        #
-       # Nul bytes on the left are trimmed.
-       # 0 is returned for an empty Bytes object.
+       # If `self.is_empty`, 0 is returned.
        #
        # ~~~
-       # assert "01".hexdigest_to_bytes.to_i == 1
-       # assert "0001".hexdigest_to_bytes.to_i == 1
-       #
-       # assert "0000".hexdigest_to_bytes.to_i == 0
-       # assert "00".hexdigest_to_bytes.to_i == 0
        # assert "".hexdigest_to_bytes.to_i == 0
        # ~~~
        #
+       # If `signed == true`, the bytes are read as a signed integer.
+       # As usual, the sign bit is the left most bit, no matter the
+       # `length` of `self`.
+       #
+       # ~~~
+       # assert     "01".hexdigest_to_bytes.to_i(true) ==      1
+       # assert     "FF".hexdigest_to_bytes.to_i(true) ==     -1
+       # assert   "00FF".hexdigest_to_bytes.to_i(true) ==    255
+       # assert     "E0".hexdigest_to_bytes.to_i(true) ==    -32
+       # assert   "FE00".hexdigest_to_bytes.to_i(true) ==   -512
+       # assert "FEFEFE".hexdigest_to_bytes.to_i(true) == -65794
+       # ~~~
+       #
        # `Int::to_bytes` is a loosely reverse method.
        #
        # ~~~
        # assert b.to_i.to_bytes == b
        # assert (b.to_i + 1).to_bytes.hexdigest == "0103"
        # assert "0001".hexdigest_to_bytes.to_i.to_bytes.hexdigest == "01"
+       #
+       # assert (-32).to_bytes.to_i(true) == -32
        # ~~~
        #
        # Warning: `Int` might overflow for bytes with more than 60 bits.
-       fun to_i: Int do
+       fun to_i(signed: nullable Bool): Int do
                var res = 0
                var i = 0
                while i < length do
@@ -364,6 +377,18 @@ class Bytes
                        res += self[i].to_i
                        i += 1
                end
+
+               # Two's complement is `signed`
+               if signed == true and not_empty and first > 0x80u8 then
+                       var ff = 0
+                       for j in [0..length[ do
+                               ff *= 0x100
+                               ff += 0xFF
+                       end
+
+                       res = -((res ^ ff) + 1)
+               end
+
                return res
        end
 
@@ -453,18 +478,15 @@ class Bytes
                length += ln
        end
 
-       # Appends the bytes of `s` to `selftextextt`
-       fun append_text(s: Text) do
-               for i in s.substrings do
-                       append_ns(i.fast_cstring, i.byte_length)
-               end
-       end
+       # Appends the bytes of `str` to `self`
+       fun append_text(str: Text) do str.append_to_bytes self
 
        redef fun append_to(b) do b.append self
 
        redef fun enlarge(sz) do
                if capacity >= sz then return
                persisted = false
+               if capacity < 16 then capacity = 16
                while capacity < sz do capacity = capacity * 2 + 2
                var ns = new CString(capacity)
                items.copy_to(ns, length, 0, 0)
@@ -474,7 +496,7 @@ class Bytes
        redef fun to_s do
                persisted = true
                var b = self
-               var r = b.items.to_s_with_length(length)
+               var r = b.items.to_s_unsafe(length, copy=false)
                if r != items then persisted = false
                return r
        end
@@ -654,7 +676,7 @@ private class BytesIterator
 end
 
 redef class Int
-       # A big-endian representation of self.
+       # A signed big-endian representation of `self`
        #
        # ~~~
        # assert     1.to_bytes.hexdigest ==     "01"
@@ -664,43 +686,86 @@ redef class Int
        # assert 65536.to_bytes.hexdigest == "010000"
        # ~~~
        #
+       # Negative values are converted to their two's complement.
+       # Be careful as the result can be ambiguous.
+       #
+       # ~~~
+       # assert     (-1).to_bytes.hexdigest ==     "FF"
+       # assert    (-32).to_bytes.hexdigest ==     "E0"
+       # assert   (-512).to_bytes.hexdigest ==   "FE00"
+       # assert (-65794).to_bytes.hexdigest == "FEFEFE"
+       # ~~~
+       #
+       # Optionally, set `n_bytes` to the desired number of bytes in the output.
+       # This setting can disambiguate the result between positive and negative
+       # integers. Be careful with this parameter as the result may overflow.
+       #
+       # ~~~
+       # assert        1.to_bytes(2).hexdigest ==     "0001"
+       # assert    65535.to_bytes(2).hexdigest ==     "FFFF"
+       # assert     (-1).to_bytes(2).hexdigest ==     "FFFF"
+       # assert   (-512).to_bytes(4).hexdigest == "FFFFFE00"
+       # assert 0x123456.to_bytes(2).hexdigest ==     "3456"
+       # ~~~
+       #
        # For 0, a Bytes object with single nul byte is returned (instead of an empty Bytes object).
        #
        # ~~~
        # assert 0.to_bytes.hexdigest == "00"
        # ~~~
        #
-       # `Bytes::to_i` can be used to do the reverse operation.
+       # For positive integers, `Bytes::to_i` can reverse the operation.
        #
        # ~~~
        # assert 1234.to_bytes.to_i == 1234
        # ~~~
        #
        # Require self >= 0
-       fun to_bytes: Bytes do
-               if self == 0 then return "\0".to_bytes
-               assert self > 0
+       fun to_bytes(n_bytes: nullable Int): Bytes do
+
+               # If 0, force using at least one byte
+               if self == 0 and n_bytes == null then n_bytes = 1
 
                # Compute the len (log256)
                var len = 1
                var max = 256
-               while self >= max do
+               var s = self.abs
+               while s >= max do
                        len += 1
                        max *= 256
                end
 
+               # Two's complement
+               s = self
+               if self < 0 then
+                       var ff = 0
+                       for j in [0..len[ do
+                               ff *= 0x100
+                               ff += 0xFF
+                       end
+
+                       s = ((-self) ^ ff) + 1
+               end
+
+               # Cut long values
+               if n_bytes != null and len > n_bytes then len = n_bytes
+
                # Allocate the buffer
-               var res = new Bytes.with_capacity(len)
-               for i in [0..len[ do res[i] = 0u8
+               var cap = n_bytes or else len
+               var res = new Bytes.with_capacity(cap)
+
+               var filler = if self < 0 then 0xFFu8 else 0u8
+               for i in [0..cap[ do res[i] = filler
 
                # Fill it starting with the end
-               var i = len
-               var sum = self
-               while i > 0 do
+               var i = cap
+               var sum = s
+               while i > cap - len do
                        i -= 1
                        res[i] = (sum % 256).to_b
                        sum /= 256
                end
+
                return res
        end
 end
@@ -931,7 +996,7 @@ end
 redef class FlatText
        redef fun append_to_bytes(b) do
                var from = if self isa FlatString then first_byte else 0
-               b.append_ns_from(items, byte_length, from)
+               if isset _items then b.append_ns_from(items, byte_length, from)
        end
 end