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"
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"
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
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
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)
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
end
redef class Int
- # A big-endian representation of self.
+ # A signed big-endian representation of `self`
#
# ~~~
# assert 1.to_bytes.hexdigest == "01"
# 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
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