more efficient str2num

This commit is contained in:
Valk Richard Li 2021-06-05 20:42:58 +08:00
parent fd7677f94f
commit b25a1bc3f4
4 changed files with 63 additions and 81 deletions

102
nasal.h
View File

@ -26,92 +26,84 @@
check if a string can be converted to a number
if this string cannot be converted to a number,it will return nan
*/
inline double hex_to_double(std::string& str)
inline double hex_to_double(const char* str)
{
double ret=0;
for(int i=2;str[i];++i)
for(;*str;++str)
{
ret*=16;
if('0'<=str[i] && str[i]<='9')
ret+=(str[i]-'0');
else if('a'<=str[i] && str[i]<='f')
ret+=(str[i]-'a'+10);
else if('A'<=str[i] && str[i]<='F')
ret+=(str[i]-'A'+10);
if('0'<=*str && *str<='9')
ret+=(*str-'0');
else if('a'<=*str && *str<='f')
ret+=(*str-'a'+10);
else if('A'<=*str && *str<='F')
ret+=(*str-'A'+10);
else
return std::nan("");
return nan("");
}
return ret;
}
inline double oct_to_double(std::string& str)
inline double oct_to_double(const char* str)
{
double ret=0;
for(int i=2;str[i];++i)
for(;*str;++str)
{
ret*=8;
if('0'<=str[i] && str[i]<='8')
ret+=(str[i]-'0');
if('0'<=*str && *str<='8')
ret+=(*str-'0');
else
return std::nan("");
return nan("");
}
return ret;
}
inline double dec_to_double(std::string& str,int len)
inline double dec_to_double(const char* str)
{
double ret=0;
int i=0;
while('0'<=str[i] && str[i]<='9' && i<len)
ret=ret*10+(str[i++]-'0');
if(i==len) return ret;
if(str[i]!='.' && str[i]!='e' && str[i]!='E')
return std::nan("");
if(str[i]=='.')
double ret=0,negative=1,num_pow=0;
while('0'<=*str && *str<='9')
ret=ret*10+(*str++-'0');
if(!*str) return ret;
if(*str=='.')
{
++i;
if(i==len) return std::nan("");
double num_pow=0.1;
while('0'<=str[i] && str[i]<='9' && i<len)
if(!*++str) return nan("");
num_pow=0.1;
while('0'<=*str && *str<='9')
{
ret+=num_pow*(str[i++]-'0');
ret+=num_pow*(*str++-'0');
num_pow*=0.1;
}
if(!*str) return ret;
}
if(i==len) return ret;
if(str[i]!='e' && str[i]!='E')
return std::nan("");
++i;
if(i==len) return std::nan("");
double negative=(str[i]=='-'? -1:1);
if(str[i]=='-' || str[i]=='+')
++i;
if(i==len) return std::nan("");
double num_pow=0;
for(;i<len;++i)
if(*str!='e' && *str!='E')
return nan("");
if(!*++str) return nan("");
if(*str=='-' || *str=='+')
negative=(*str++=='-'? -1:1);
if(!*str) return nan("");
num_pow=0;
for(;*str;++str)
{
if('0'<=str[i] && str[i]<='9')
num_pow=num_pow*10+(str[i]-'0');
if('0'<=*str && *str<='9')
num_pow=num_pow*10+(*str-'0');
else
return std::nan("");
return nan("");
}
return ret*std::pow(10,negative*num_pow);
}
double str2num(std::string str)
double str2num(const char* str)
{
bool is_negative=false;
int len=str.length();
double ret_num=0;
if(str[0]=='-' || str[0]=='+')
{
if(len==1) return std::nan("");
is_negative=(str[0]=='-');
str=str.substr(1,len--);
}
if(len>1 && str[0]=='0' && str[1]=='x')
ret_num=hex_to_double(str);
else if(len>1 && str[0]=='0' && str[1]=='o')
ret_num=oct_to_double(str);
if(*str=='-' || *str=='+')
is_negative=(*str++=='-');
if(!*str)
return nan("");
if(str[0]=='0' && str[1]=='x')
ret_num=hex_to_double(str+2);
else if(str[0]=='0' && str[1]=='o')
ret_num=oct_to_double(str+2);
else
ret_num=dec_to_double(str,len);
ret_num=dec_to_double(str);
return is_negative?-ret_num:ret_num;
}

View File

@ -24,12 +24,9 @@ const int increment[vm_type_size]=
8 // vm_hash
};
struct nasal_vec; //24 bytes
struct nasal_hash;//56 bytes
struct nasal_func;//120 bytes
struct nasal_val; // 16 bytes
struct nasal_val;//declaration of nasal_val
struct nasal_vec
struct nasal_vec// 24 bytes
{
std::vector<nasal_val*> elems;
@ -38,7 +35,7 @@ struct nasal_vec
nasal_val** get_mem(int);
};
struct nasal_hash
struct nasal_hash// 56 bytes
{
std::unordered_map<std::string,nasal_val*> elems;
@ -47,20 +44,20 @@ struct nasal_hash
nasal_val** get_mem(std::string&);
};
struct nasal_func
struct nasal_func// 120 bytes
{
int32_t dynpara;// dynamic parameter name index in hash
uint32_t offset;
uint32_t entry;
std::vector<nasal_val*> default_para;
int32_t dynpara;// dynamic parameter name index in hash
uint32_t offset; // arguments will be loaded into local scope from this offset
uint32_t entry; // pc will set to entry-1 to call this function
std::vector<nasal_val*> default_para;// default value(nasal_val*)
std::unordered_map<std::string,int> key_table;// parameter name hash
std::vector<nasal_val*> closure;
std::vector<nasal_val*> closure;// closure will be loaded to gc.local.back() as the local scope
nasal_func();
void clear();
};
struct nasal_val
struct nasal_val// 16 bytes
{
#define GC_UNCOLLECTED 0
#define GC_FOUND 1
@ -76,7 +73,6 @@ struct nasal_val
nasal_func* func;
}ptr;
nasal_val();
nasal_val(int);
~nasal_val();
double to_number();
@ -203,12 +199,6 @@ void nasal_func::clear()
}
/*functions of nasal_val*/
nasal_val::nasal_val()
{
mark=GC_COLLECTED;
type=vm_nil;
return;
}
nasal_val::nasal_val(int val_type)
{
mark=GC_COLLECTED;
@ -238,7 +228,7 @@ nasal_val::~nasal_val()
double nasal_val::to_number()
{
if(type==vm_str)
return str2num(*ptr.str);
return str2num(ptr.str->c_str());
return ptr.num;
}
std::string nasal_val::to_string()

View File

@ -315,7 +315,7 @@ nasal_ast nasal_parse::nil_gen()
nasal_ast nasal_parse::num_gen()
{
nasal_ast node(tok_list[ptr].line,ast_num);
node.set_num(str2num(tok_list[ptr].str));
node.set_num(str2num(tok_list[ptr].str.c_str()));
return node;
}
nasal_ast nasal_parse::str_gen()

View File

@ -135,7 +135,7 @@ bool nasal_vm::condition(nasal_val* val_addr)
else if(type==vm_str)
{
std::string& str=*val_addr->ptr.str;
double number=str2num(str);
double number=str2num(str.c_str());
if(std::isnan(number))
return !str.empty();
return number;
@ -267,7 +267,7 @@ void nasal_vm::opr_unot()
new_val=val->ptr.num?gc.zero_addr:gc.one_addr;
else if(type==vm_str)
{
double number=str2num(*val->ptr.str);
double number=str2num(val->ptr.str->c_str());
if(std::isnan(number))
new_val=val->ptr.str->empty()?gc.one_addr:gc.zero_addr;
else
@ -752,7 +752,7 @@ void nasal_vm::opr_slc()
switch(val->type)
{
case vm_num:num=val->ptr.num;break;
case vm_str:num=str2num(*val->ptr.str);break;
case vm_str:num=str2num(val->ptr.str->c_str());break;
default:die("slc: error value type");break;
}
nasal_val* res=(*stack_top)->ptr.vec->get_val((int)num);
@ -819,7 +819,7 @@ void nasal_vm::opr_mcallv()
switch(val->type)
{
case vm_num:num=(int)val->ptr.num;break;
case vm_str:num=(int)str2num(*val->ptr.str);break;
case vm_str:num=(int)str2num(val->ptr.str->c_str());break;
default:die("mcallv: error value type");break;
}
nasal_val** res=(*vec_addr)->ptr.vec->get_mem(num);