Decimal conversion of Number to zt-string (still not precise enough). Zt-string copy and length calculation helpers.

This commit is contained in:
Ruben Ayrapetyan
2014-09-01 21:12:02 +04:00
parent e35f54fe86
commit 813831a23b
7 changed files with 287 additions and 65 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ typedef signed long ssize_t;
/** /**
* Constants * Constants
*/ */
#define JERRY_BITSINBYTE 8u #define JERRY_BITSINBYTE 8
/** /**
* Error codes * Error codes
+5
View File
@@ -527,6 +527,11 @@ typedef double ecma_number_t;
*/ */
#define ECMA_NUMBER_ONE ((ecma_number_t) 1) #define ECMA_NUMBER_ONE ((ecma_number_t) 1)
/**
* Null character (zt-string end marker)
*/
#define ECMA_CHAR_NULL ((ecma_char_t) '\0')
/** /**
* Maximum number of characters in string representation of ecma-number * Maximum number of characters in string representation of ecma-number
*/ */
+203 -55
View File
@@ -31,11 +31,16 @@
* See also: * See also:
* ECMA-262 v5, 9.3.1 * ECMA-262 v5, 9.3.1
* *
* Warning:
* the conversion routine may be not precise for some cases
*
* @return ecma-number * @return ecma-number
*/ */
ecma_number_t ecma_number_t
ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string */ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string */
{ {
TODO (Check conversion precision);
const ecma_char_t dec_digits_range[10] = { '0', '9' }; const ecma_char_t dec_digits_range[10] = { '0', '9' };
const ecma_char_t hex_lower_digits_range[10] = { 'a', 'f' }; const ecma_char_t hex_lower_digits_range[10] = { 'a', 'f' };
const ecma_char_t hex_upper_digits_range[10] = { 'A', 'F' }; const ecma_char_t hex_upper_digits_range[10] = { 'A', 'F' };
@@ -45,11 +50,10 @@ ecma_zt_string_to_number (const ecma_char_t *str_p) /**< zero-terminated string
const ecma_char_t plus_char = '+'; const ecma_char_t plus_char = '+';
const ecma_char_t minus_char = '-'; const ecma_char_t minus_char = '-';
const ecma_char_t dot_char = '.'; const ecma_char_t dot_char = '.';
const ecma_char_t null_char = '\0';
const ecma_char_t *begin_p = str_p; const ecma_char_t *begin_p = str_p;
const ecma_char_t *end_p = begin_p; const ecma_char_t *end_p = begin_p;
while (*end_p != null_char) while (*end_p != ECMA_CHAR_NULL)
{ {
end_p++; end_p++;
} }
@@ -332,10 +336,9 @@ ecma_uint32_to_string (uint32_t value, /**< value to convert */
ssize_t buffer_size) /**< size of buffer */ ssize_t buffer_size) /**< size of buffer */
{ {
const ecma_char_t digits[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; const ecma_char_t digits[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
const ecma_char_t null_char = '\0';
ecma_char_t *p = (ecma_char_t*) ((uint8_t*) out_buffer_p + buffer_size) - 1; ecma_char_t *p = (ecma_char_t*) ((uint8_t*) out_buffer_p + buffer_size) - 1;
*p-- = null_char; *p-- = ECMA_CHAR_NULL;
size_t bytes_copied = sizeof (ecma_char_t); size_t bytes_copied = sizeof (ecma_char_t);
@@ -435,6 +438,10 @@ ecma_number_to_int32 (ecma_number_t value) /**< unsigned 32-bit integer value */
* See also: * See also:
* ECMA-262 v5, 9.8.1 * ECMA-262 v5, 9.8.1
* *
* Warning:
* the conversion is not precise for all cases
* For example, 12345.0f converts to "12344.99931".
*
* @return length of zt-string * @return length of zt-string
*/ */
ecma_length_t ecma_length_t
@@ -442,18 +449,20 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */
ecma_char_t *buffer_p, /**< buffer for zt-string */ ecma_char_t *buffer_p, /**< buffer for zt-string */
ssize_t buffer_size) /**< size of buffer */ ssize_t buffer_size) /**< size of buffer */
{ {
FIXME (Conversion precision);
const ecma_char_t digits[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; const ecma_char_t digits[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
const ecma_char_t e_chars [2] = { 'e', 'E' }; const ecma_char_t e_chars [2] = { 'e', 'E' };
const ecma_char_t plus_char = '+'; const ecma_char_t plus_char = '+';
const ecma_char_t minus_char = '-'; const ecma_char_t minus_char = '-';
const ecma_char_t dot_char = '.'; const ecma_char_t dot_char = '.';
const ecma_char_t null_char = '\0';
if (ecma_number_is_nan (num)) if (ecma_number_is_nan (num))
{ {
// 1. // 1.
FIXME (/* Assert that buffer's size is enough */); ecma_copy_zt_string_to_buffer (ecma_get_magic_string_zt (ECMA_MAGIC_STRING_NAN),
__strncpy ((char*) buffer_p, (char*) ecma_get_magic_string_zt (ECMA_MAGIC_STRING_NAN), (size_t) buffer_size); buffer_p,
buffer_size);
} }
else else
{ {
@@ -463,7 +472,7 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */
{ {
// 2. // 2.
*dst_p++ = digits[0]; *dst_p++ = digits[0];
*dst_p++ = null_char; *dst_p++ = ECMA_CHAR_NULL;
JERRY_ASSERT ((uint8_t*)dst_p - (uint8_t*)buffer_p <= (ssize_t) buffer_size); JERRY_ASSERT ((uint8_t*)dst_p - (uint8_t*)buffer_p <= (ssize_t) buffer_size);
} }
@@ -477,129 +486,268 @@ ecma_number_to_zt_string (ecma_number_t num, /**< ecma-number */
else if (ecma_number_is_infinity (num)) else if (ecma_number_is_infinity (num))
{ {
// 4. // 4.
FIXME (/* Assert that buffer's size is enough */); ecma_copy_zt_string_to_buffer (ecma_get_magic_string_zt (ECMA_MAGIC_STRING_INFINITY),
__strncpy ((char*) buffer_p, (char*) ecma_get_magic_string_zt (ECMA_MAGIC_STRING_INFINITY), (size_t) buffer_size); buffer_p,
buffer_size);
} }
else else
{ {
// 5. // 5.
uint64_t fraction; #ifdef CONFIG_ECMA_NUMBER_FLOAT32
#define LL_T uint32_t
#define LL_MAX_DIGITS 10
#elif defined (CONFIG_ECMA_NUMBER_FLOAT64)
#define LL_T uint64_t
#define LL_MAX_DIGITS 18
#else /* !CONFIG_ECMA_NUMBER_FLOAT32 && !CONFIG_ECMA_NUMBER_FLOAT64 */
# error "!CONFIG_ECMA_NUMBER_FLOAT32 && !CONFIG_ECMA_NUMBER_FLOAT64"
#endif /* !CONFIG_ECMA_NUMBER_FLOAT32 && !CONFIG_ECMA_NUMBER_FLOAT64 */
uint64_t fraction_uint64;
LL_T fraction;
int32_t exponent; int32_t exponent;
int32_t dot_shift; int32_t dot_shift;
dot_shift = ecma_number_get_fraction_and_exponent (num, &fraction, &exponent); int32_t decimal_exp = 0;
FIXME (Decimal representation); dot_shift = ecma_number_get_fraction_and_exponent (num, &fraction_uint64, &exponent);
uint64_t s = fraction; fraction = (LL_T) fraction_uint64;
int32_t n = exponent + 1; JERRY_ASSERT (fraction == fraction_uint64);
int32_t k = dot_shift;
JERRY_ASSERT (s != 0); if (exponent != 0)
while (!(s & 1))
{ {
s >>= 1; ecma_number_t t = 1.0f;
k--; bool do_divide;
if (exponent < 0)
{
do_divide = true;
while (exponent <= 0)
{
t *= 2.0f;
exponent++;
if (t >= 10.0f)
{
t /= 10.0f;
decimal_exp--;
}
JERRY_ASSERT (t < 10.0f);
}
while (t > 1.0f)
{
exponent--;
t /= 2.0f;
}
}
else
{
do_divide = false;
while (exponent >= 0)
{
t *= 2.0f;
exponent--;
if (t >= 10.0f)
{
t /= 10.0f;
decimal_exp++;
}
JERRY_ASSERT (t < 10.0f);
}
while (t > 2.0f)
{
exponent++;
t /= 2.0f;
}
}
if (do_divide)
{
fraction = (LL_T) ((ecma_number_t) fraction / t);
}
else
{
fraction = (LL_T) ((ecma_number_t) fraction * t);
}
}
LL_T s;
int32_t n;
int32_t k;
if (exponent > 0)
{
fraction <<= exponent;
}
else
{
fraction >>= -exponent;
}
const int32_t int_part_shift = dot_shift;
const LL_T frac_part_mask = ((((LL_T)1) << int_part_shift) - 1);
LL_T int_part = fraction >> int_part_shift;
LL_T frac_part = fraction & frac_part_mask;
s = int_part;
k = 1;
n = decimal_exp + 1;
JERRY_ASSERT (int_part < 10);
while (k < LL_MAX_DIGITS
&& frac_part != 0)
{
frac_part *= 10;
LL_T new_frac_part = frac_part & frac_part_mask;
LL_T digit = (frac_part - new_frac_part) >> int_part_shift;
s = s * 10 + digit;
k++;
frac_part = new_frac_part;
} }
// 6. // 6.
if (k <= n && n <= 21) if (k <= n && n <= 21)
{ {
for (int32_t i = 0; i < k; i++) dst_p += n;
{ JERRY_ASSERT ((ssize_t) sizeof (ecma_char_t) * ((dst_p - buffer_p) + 1) <= buffer_size);
uint64_t bit_mask = 1ul << (k - i - 1);
*dst_p++ = digits [(s & bit_mask) ? 1 : 0]; *dst_p = ECMA_CHAR_NULL;
}
for (int32_t i = 0; i < n - k; i++) for (int32_t i = 0; i < n - k; i++)
{ {
*dst_p++ = digits [0]; *--dst_p = digits [0];
}
for (int32_t i = 0; i < k; i++)
{
*--dst_p = digits [s % 10];
s /= 10;
} }
} }
else if (0 < n && n <= 21) else if (0 < n && n <= 21)
{ {
// 7. // 7.
for (int32_t i = 0; i < n; i++) dst_p += k + 1;
JERRY_ASSERT ((ssize_t) sizeof (ecma_char_t) * ((dst_p - buffer_p) + 1) <= buffer_size);
*dst_p = ECMA_CHAR_NULL;
for (int32_t i = 0; i < k - n; i++)
{ {
uint64_t bit_mask = 1ul << (k - i - 1); *--dst_p = digits [s % 10];
*dst_p++ = digits [(s & bit_mask) ? 1 : 0]; s /= 10;
} }
*dst_p++ = dot_char; *--dst_p = dot_char;
for (int32_t i = n; i < k; i++) for (int32_t i = 0; i < n; i++)
{ {
uint64_t bit_mask = 1ul << (k - i - 1); *--dst_p = digits [s % 10];
*dst_p++ = digits [(s & bit_mask) ? 1 : 0]; s /= 10;
} }
} }
else if (-6 <= n && n <= 0) else if (-6 <= n && n <= 0)
{ {
// 8. // 8.
*dst_p++ = digits [0]; dst_p += k - n + 1 + 1;
*dst_p++ = '.'; JERRY_ASSERT ((ssize_t) sizeof (ecma_char_t) * ((dst_p - buffer_p) + 1) <= buffer_size);
*dst_p = ECMA_CHAR_NULL;
for (int32_t i = 0; i < k; i++) for (int32_t i = 0; i < k; i++)
{ {
uint64_t bit_mask = 1ul << (k - i - 1); *--dst_p = digits [s % 10];
*dst_p++ = digits [(s & bit_mask) ? 1 : 0]; s /= 10;
} }
for (int32_t i = 0; i < -n; i++)
{
*--dst_p = digits [0];
}
*--dst_p = dot_char;
*--dst_p = digits[0];
} }
else else
{ {
if (k == 1) if (k == 1)
{ {
// 9. // 9.
*dst_p++ = digits [s ? 1 : 0]; JERRY_ASSERT ((ssize_t) sizeof (ecma_char_t) <= buffer_size);
*dst_p++ = digits [s % 10];
s /= 10;
} }
else else
{ {
// 10. // 10.
uint64_t bit_mask = 1ul << (k - 1); dst_p += k + 1;
*dst_p++ = digits [(s & bit_mask) ? 1 : 0]; JERRY_ASSERT ((ssize_t) sizeof (ecma_char_t) * (dst_p - buffer_p) <= buffer_size);
*dst_p++ = dot_char;
for (int32_t i = 1; i < k; i++) for (int32_t i = 0; i < k - 1; i++)
{ {
bit_mask = 1ul << (k - i - 1); *--dst_p = digits [s % 10];
*dst_p++ = digits [(s & bit_mask) ? 1 : 0]; s /= 10;
} }
*--dst_p = dot_char;
*--dst_p = digits[s % 10];
s /= 10;
dst_p += k + 1;
} }
// 9., 10. // 9., 10.
JERRY_ASSERT ((ssize_t) sizeof (ecma_char_t) * (dst_p - buffer_p + 2) <= buffer_size);
*dst_p++ = e_chars[0]; *dst_p++ = e_chars[0];
*dst_p++ = (n >= 1) ? plus_char : minus_char; *dst_p++ = (n >= 1) ? plus_char : minus_char;
int32_t t = (n >= 1) ? (n - 1) : -(n - 1); int32_t t = (n >= 1) ? (n - 1) : -(n - 1);
if (t == 0) if (t == 0)
{ {
JERRY_ASSERT ((ssize_t) sizeof (ecma_char_t) * (dst_p - buffer_p + 1) <= buffer_size);
*dst_p++ = digits [0]; *dst_p++ = digits [0];
} }
else else
{ {
uint32_t t_bit = (1u << 31); int32_t t_mod = 1000000000u;
while ((t & (int32_t) t_bit) == 0) while ((t / t_mod) == 0)
{ {
t_bit >>= 1; t_mod /= 10;
JERRY_ASSERT (t_bit != 0); JERRY_ASSERT (t_mod != 0);
} }
while (t_bit != 0) while (t_mod != 0)
{ {
*dst_p++ = digits [(t & (int32_t) t_bit) ? 1 : 0]; JERRY_ASSERT ((ssize_t) sizeof (ecma_char_t) * (dst_p - buffer_p + 1) <= buffer_size);
*dst_p++ = digits [t / t_mod];
t_bit >>= 1; t -= (t / t_mod) * t_mod;
t_mod /= 10;
} }
} }
JERRY_ASSERT ((ssize_t) sizeof (ecma_char_t) * (dst_p - buffer_p + 1) <= buffer_size);
*dst_p++ = ECMA_CHAR_NULL;
} }
*dst_p++ = null_char; JERRY_ASSERT (s == 0);
JERRY_ASSERT ((uint8_t*)dst_p - (uint8_t*)buffer_p <= (ssize_t) buffer_size);
} }
} }
ecma_length_t length = (ecma_length_t) __strlen ((char*) buffer_p); ecma_length_t length = ecma_zt_string_length (buffer_p);
return length; return length;
} /* ecma_number_to_zt_string */ } /* ecma_number_to_zt_string */
+1 -1
View File
@@ -347,7 +347,7 @@ ecma_number_get_fraction_and_exponent (ecma_number_t num, /**< ecma-number */
*out_fraction_p = fraction; *out_fraction_p = fraction;
*out_exponent_p = exponent; *out_exponent_p = exponent;
return ECMA_NUMBER_FRACTION_WIDTH + 1; return ECMA_NUMBER_FRACTION_WIDTH;
} /* ecma_number_get_fraction_and_exponent */ } /* ecma_number_get_fraction_and_exponent */
/** /**
+70 -3
View File
@@ -427,7 +427,8 @@ ecma_string_to_zt_string (const ecma_string_t *string_desc_p, /**< ecma-string d
{ {
const ecma_char_t *str_p = deserialize_string_by_id ((idx_t) string_desc_p->u.lit_index); const ecma_char_t *str_p = deserialize_string_by_id ((idx_t) string_desc_p->u.lit_index);
JERRY_ASSERT (str_p != NULL); JERRY_ASSERT (str_p != NULL);
__strncpy ((char*)buffer_p, (const char*)str_p, string_desc_p->length + 1u);
ecma_copy_zt_string_to_buffer (str_p, buffer_p, required_buffer_size);
JERRY_ASSERT (__strlen ((char*)buffer_p) == string_desc_p->length); JERRY_ASSERT (__strlen ((char*)buffer_p) == string_desc_p->length);
bytes_copied = (ssize_t) ((string_desc_p->length + 1u) * sizeof (ecma_char_t)); bytes_copied = (ssize_t) ((string_desc_p->length + 1u) * sizeof (ecma_char_t));
@@ -767,12 +768,78 @@ bool
ecma_compare_zt_string_to_zt_string (const ecma_char_t *string1_p, /**< zero-terminated string */ ecma_compare_zt_string_to_zt_string (const ecma_char_t *string1_p, /**< zero-terminated string */
const ecma_char_t *string2_p) /**< zero-terminated string */ const ecma_char_t *string2_p) /**< zero-terminated string */
{ {
TODO (Implement comparison that supports UTF-16); const ecma_char_t *iter_1_p = string1_p;
const ecma_char_t *iter_2_p = string2_p;
return (__strcmp ( (char*)string1_p, (char*)string2_p) == 0); while (*iter_1_p != ECMA_CHAR_NULL)
{
if (*iter_1_p++ != *iter_2_p++)
{
return false;
}
}
return (*iter_2_p == ECMA_CHAR_NULL);
} /* ecma_compare_zt_string_to_zt_string */ } /* ecma_compare_zt_string_to_zt_string */
/** /**
* Copy zero-terminated string to buffer
*
* Warning:
* the routine requires that buffer size is enough
*
* @return number of bytes copied
*/
ssize_t
ecma_copy_zt_string_to_buffer (const ecma_char_t *string_p, /**< zero-terminated string */
ecma_char_t *buffer_p, /**< destination buffer */
ssize_t buffer_size) /**< size of buffer */
{
const ecma_char_t *str_iter_p = string_p;
ecma_char_t *buf_iter_p = buffer_p;
ssize_t bytes_copied = 0;
do
{
bytes_copied += (ssize_t) sizeof (ecma_char_t);
JERRY_ASSERT (bytes_copied <= buffer_size);
*buf_iter_p++ = *str_iter_p++;
}
while (*str_iter_p != ECMA_CHAR_NULL);
bytes_copied += (ssize_t) sizeof (ecma_char_t);
JERRY_ASSERT (bytes_copied <= buffer_size);
*buf_iter_p = ECMA_CHAR_NULL;
return bytes_copied;
} /* ecma_copy_zt_string_to_buffer */
/**
* Calculate zero-terminated string's length
*
* @return length of string
*/
ecma_length_t
ecma_zt_string_length (const ecma_char_t *string_p) /**< zero-terminated string */
{
const ecma_char_t *str_iter_p = string_p;
ecma_length_t length = 0;
while (*str_iter_p++)
{
length++;
/* checking overflow */
JERRY_ASSERT (length != 0);
}
return length;
} /* ecma_zt_string_length */
/**
* @} * @}
* @} * @}
*/ */
+3 -1
View File
@@ -107,9 +107,11 @@ extern ecma_number_t ecma_string_to_number (const ecma_string_t *str_p);
extern ssize_t ecma_string_to_zt_string (const ecma_string_t *string_desc_p, extern ssize_t ecma_string_to_zt_string (const ecma_string_t *string_desc_p,
ecma_char_t *buffer_p, ecma_char_t *buffer_p,
ssize_t buffer_size); ssize_t buffer_size);
extern bool ecma_compare_zt_string_to_zt_string (const ecma_char_t *string1_p, const ecma_char_t *string2_p);
extern bool ecma_compare_ecma_string_to_ecma_string (const ecma_string_t *string1_p, extern bool ecma_compare_ecma_string_to_ecma_string (const ecma_string_t *string1_p,
const ecma_string_t *string2_p); const ecma_string_t *string2_p);
extern bool ecma_compare_zt_string_to_zt_string (const ecma_char_t *string1_p, const ecma_char_t *string2_p);
extern ssize_t ecma_copy_zt_string_to_buffer (const ecma_char_t *string_p, ecma_char_t *buffer_p, ssize_t buffer_size);
extern ecma_length_t ecma_zt_string_length (const ecma_char_t *string_p);
/* ecma-helpers-number.c */ /* ecma-helpers-number.c */
extern ecma_number_t ecma_number_make_nan (void); extern ecma_number_t ecma_number_make_nan (void);
+4 -4
View File
@@ -30,10 +30,10 @@ main( int __unused argc,
const ecma_char_t* zt_strings[] = const ecma_char_t* zt_strings[] =
{ {
(const ecma_char_t*) "1", (const ecma_char_t*) "1",
(const ecma_char_t*) "0.1", (const ecma_char_t*) "0.5",
(const ecma_char_t*) "11000000111001", (const ecma_char_t*) "12344.99931",
(const ecma_char_t*) "1e-10010101", (const ecma_char_t*) "1.401298403e-45",
(const ecma_char_t*) "-1.01111000001010001e+1111111", (const ecma_char_t*) "-2.5e+38",
(const ecma_char_t*) "NaN", (const ecma_char_t*) "NaN",
(const ecma_char_t*) "Infinity", (const ecma_char_t*) "Infinity",
(const ecma_char_t*) "-Infinity", (const ecma_char_t*) "-Infinity",