private unsafe static bool TryParseFloatFormat_v2(Char16 *ptr_source, int length, out int sign, out int i_start, out int dot_pos, out int exp_pos, out int n_pow) { // check sign on front i_start = 0; if (ptr_source[0].IsSign(out sign)) { i_start = 1; } // eat zeros on the head bool is_zero_head = false; for (int i = i_start; i < length; i++) { UInt16 c = ptr_source[i]; if (c == UTF16CodeSet.code_0) { is_zero_head = true; i_start++; } else { break; } } // initialize value dot_pos = -1; exp_pos = -1; n_pow = 0; if (length > 2048) { return(false); } // check dot pos // check exp pos int dummy; bool is_digit_found = false; for (int i = i_start; i < length; i++) { Char16 c = ptr_source[i]; if (!is_digit_found && c.IsDigit(out dummy)) { is_digit_found = true; } else if (c.IsDot()) { if (dot_pos >= 0) { return(false); // # of dots must be 0 or 1 in string. } dot_pos = i; } else if (c.IsExp()) { if (!is_digit_found && !is_zero_head) { return(false); // must have digits before [E/e] mark. } if (exp_pos > 0) { return(false); // # of [E/e] marks must be 0 or 1 in string. } exp_pos = i; } } // check exp sign int exp_start = exp_pos + 1; int exp_sign = 1; if (exp_pos > 0) { if (ptr_source[exp_start].IsSign(out exp_sign)) { exp_start += 1; } if (exp_start == length) { return(false); // no digits in exp } } else { exp_pos = (short)length; exp_start = exp_pos; } // check mantissa region is digits only or not for (int i = i_start; i < exp_pos; i++) { Char16 c = ptr_source[i]; if (!c.IsDigit(out dummy) && !c.IsDot()) { return(false); } } // check exp region and extract n_pow if (exp_start > 0) { for (int i = 0; i < math.min(length - exp_start, 64); i++) // up to 64 digits for pow { Char16 c = ptr_source[i + exp_start]; if (!c.IsDigit(out int d)) { return(false); // exp region must be digits only } n_pow = n_pow * 10 + (int)d; if (n_pow > 350) { if (exp_sign > 0) { // overflow return(false); } break; } } n_pow *= exp_sign; } // parsing manntissa search [i_start, exp_pos] and use dot_pos to calc 10^m in mantissa. if (dot_pos < 0) { dot_pos = exp_pos; } return(true); }
private unsafe static bool TryParseFloatFormat(Char16 *ptr_source, int length, out int sign, out int i_start, out int dot_pos, out int exp_pos, out int n_pow) { i_start = 0; if (ptr_source[0].IsSign(out sign)) { i_start = 1; } bool zero_head = false; // eat zeros on the head for (int i = i_start; i < length; i++) { UInt16 c = ptr_source[i]; if (c == UTF16CodeSet.code_0) { i_start++; zero_head = true; } else { break; } } dot_pos = -1; exp_pos = -1; n_pow = 0; int exp_sign = 1; int digit_count = 0; int dummy; int dummy_sign; int exp_start = -1;; // format check for (int i = i_start; i < length; i++) { Char16 c = ptr_source[i]; //UnityEngine.Debug.Log($"parse format: i={i}, c={c}"); if (c.IsDigit(out dummy)) { if (exp_pos == -1) { digit_count++; } // do nothing //UnityEngine.Debug.Log("c is number"); } else { if (exp_start > 0 && i >= exp_start) { return(false); // after [e/E] region must be digits. } if (c.IsDot()) { if (dot_pos != -1 || dot_pos == i_start + 1) { return(false); } if (exp_pos > 0 && i >= exp_pos) { return(false); } dot_pos = i; //UnityEngine.Debug.Log("c is dot"); } else if (c.IsExp()) { //UnityEngine.Debug.Log("c is EXP"); if (exp_pos != -1) { return(false); // 2nd [e/E] found } if (digit_count == 0 && !zero_head) { return(false); // no digits before [e/E] } if (length - i == 0) { return(false); // no digits after [e/E] } if ((length - i == 1) && !ptr_source[i + 1].IsDigit(out dummy)) { return(false); } exp_pos = i; exp_start = i + 1; if (ptr_source[i + 1].IsSign(out exp_sign)) { if (exp_start + 1 >= length) { return(false); // ended by [e/E][+/-]. no pow digits. } exp_start += 1; } } else if (c.IsSign(out dummy_sign)) { if (i != exp_pos + 1) { return(false); } exp_start = i + 1; } else { //UnityEngine.Debug.Log("failure to parse"); return(false); } } } // decode exp part if (exp_start > 0) { for (int i = 0; i < math.min(length - exp_start, 32); i++) // up to 32 digits for pow { n_pow = n_pow * 10 + ptr_source[i + exp_start].ToInt(); //UnityEngine.Debug.Log("n_pow(1)=" + n_pow.ToString()); if (n_pow > 350) { if (exp_sign < 0) { n_pow = -400; if (dot_pos < 0) { dot_pos = exp_pos; } return(true); // underflow, round to zero. } else { return(false); // overflow } } } n_pow *= exp_sign; } else { // no [e/E+-[int]] part exp_pos = length; } if (dot_pos < 0) { dot_pos = exp_pos; } //UnityEngine.Debug.Log("ParseFloatFormat=" + true.ToString()); return(true); }