if pos == null then pos = 0
if ln == null then ln = length - pos
if ln < 6 then return 0xFFFD.code_point
- var cp = from_utf16_digit(pos + 2)
- if cp < 0xD800 then return cp.code_point
- if cp > 0xDFFF then return cp.code_point
- if cp > 0xDBFF then return 0xFFFD.code_point
+ var cp = from_utf16_digit(pos + 2).to_u32
+ if cp < 0xD800u32 then return cp.code_point
+ if cp > 0xDFFFu32 then return cp.code_point
+ if cp > 0xDBFFu32 then return 0xFFFD.code_point
if ln == 6 then return 0xFFFD.code_point
if ln < 12 then return 0xFFFD.code_point
cp <<= 16
- cp += from_utf16_digit(pos + 8)
- var cplo = cp & 0xFFFF
- if cplo < 0xDC00 then return 0xFFFD.code_point
- if cplo > 0xDFFF then return 0xFFFD.code_point
+ cp += from_utf16_digit(pos + 8).to_u32
+ var cplo = cp & 0xFFFFu32
+ if cplo < 0xDC00u32 then return 0xFFFD.code_point
+ if cplo > 0xDFFFu32 then return 0xFFFD.code_point
return cp.from_utf16_surr.code_point
end
# Decode `self` from percent (or URL) encoding to a clear string
#
- # Replace invalid use of '%' with '?'.
+ # Invalid '%' are not decoded.
#
# assert "aBc09-._~".from_percent_encoding == "aBc09-._~"
# assert "%25%28%29%3c%20%3e".from_percent_encoding == "%()< >"
# assert ".com%2fpost%3fe%3dasdf%26f%3d123".from_percent_encoding == ".com/post?e=asdf&f=123"
# assert "%25%28%29%3C%20%3E".from_percent_encoding == "%()< >"
- # assert "incomplete %".from_percent_encoding == "incomplete ?"
- # assert "invalid % usage".from_percent_encoding == "invalid ? usage"
+ # assert "incomplete %".from_percent_encoding == "incomplete %"
+ # assert "invalid % usage".from_percent_encoding == "invalid % usage"
# assert "%c3%a9%e3%81%82%e3%81%84%e3%81%86".from_percent_encoding == "éあいう"
+ # assert "%1 %A %C3%A9A9".from_percent_encoding == "%1 %A éA9"
fun from_percent_encoding: String
do
var len = byte_length
if c == '%' then
if i + 2 >= length then
# What follows % has been cut off
- buf[l] = '?'.ascii
+ buf[l] = '%'.ascii
else
i += 1
var hex_s = substring(i, 2)
i += 1
else
# What follows a % is not Hex
- buf[l] = '?'.ascii
+ buf[l] = '%'.ascii
i -= 1
end
end
return "-inf"
end
- if decimals == 0 then return self.to_i.to_s
- var f = self
- for i in [0..decimals[ do f = f * 10.0
- if self > 0.0 then
- f = f + 0.5
- else
- f = f - 0.5
- end
- var i = f.to_i
- if i == 0 then return "0." + "0"*decimals
-
- # Prepare both parts of the float, before and after the "."
- var s = i.abs.to_s
- var sl = s.length
- var p1
- var p2
- if sl > decimals then
- # Has something before the "."
- p1 = s.substring(0, sl-decimals)
- p2 = s.substring(sl-decimals, decimals)
- else
- p1 = "0"
- p2 = "0"*(decimals-sl) + s
- end
+ var size = to_precision_size(decimals)
+ var cstr = new CString(size+1)
+ to_precision_fill(decimals, size+1, cstr)
+ return cstr.to_s_unsafe(byte_length=size, copy=false)
+ end
- if i < 0 then p1 = "-" + p1
+ # Required string length to hold `self` with `nb` decimals
+ #
+ # The length does not include the terminating null byte.
+ private fun to_precision_size(nb: Int): Int `{
+ return snprintf(NULL, 0, "%.*f", (int)nb, self);
+ `}
- return p1 + "." + p2
- end
+ # Fill `cstr` with `self` and `nb` decimals
+ private fun to_precision_fill(nb, size: Int, cstr: CString) `{
+ snprintf(cstr, size, "%.*f", (int)nb, self);
+ `}
end
redef class Char