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

View File

@ -24,12 +24,9 @@ const int increment[vm_type_size]=
8 // vm_hash 8 // vm_hash
}; };
struct nasal_vec; //24 bytes struct nasal_val;//declaration of nasal_val
struct nasal_hash;//56 bytes
struct nasal_func;//120 bytes
struct nasal_val; // 16 bytes
struct nasal_vec struct nasal_vec// 24 bytes
{ {
std::vector<nasal_val*> elems; std::vector<nasal_val*> elems;
@ -38,7 +35,7 @@ struct nasal_vec
nasal_val** get_mem(int); nasal_val** get_mem(int);
}; };
struct nasal_hash struct nasal_hash// 56 bytes
{ {
std::unordered_map<std::string,nasal_val*> elems; std::unordered_map<std::string,nasal_val*> elems;
@ -47,20 +44,20 @@ struct nasal_hash
nasal_val** get_mem(std::string&); nasal_val** get_mem(std::string&);
}; };
struct nasal_func struct nasal_func// 120 bytes
{ {
int32_t dynpara;// dynamic parameter name index in hash int32_t dynpara;// dynamic parameter name index in hash
uint32_t offset; uint32_t offset; // arguments will be loaded into local scope from this offset
uint32_t entry; uint32_t entry; // pc will set to entry-1 to call this function
std::vector<nasal_val*> default_para; std::vector<nasal_val*> default_para;// default value(nasal_val*)
std::unordered_map<std::string,int> key_table;// parameter name hash 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(); nasal_func();
void clear(); void clear();
}; };
struct nasal_val struct nasal_val// 16 bytes
{ {
#define GC_UNCOLLECTED 0 #define GC_UNCOLLECTED 0
#define GC_FOUND 1 #define GC_FOUND 1
@ -76,7 +73,6 @@ struct nasal_val
nasal_func* func; nasal_func* func;
}ptr; }ptr;
nasal_val();
nasal_val(int); nasal_val(int);
~nasal_val(); ~nasal_val();
double to_number(); double to_number();
@ -203,12 +199,6 @@ void nasal_func::clear()
} }
/*functions of nasal_val*/ /*functions of nasal_val*/
nasal_val::nasal_val()
{
mark=GC_COLLECTED;
type=vm_nil;
return;
}
nasal_val::nasal_val(int val_type) nasal_val::nasal_val(int val_type)
{ {
mark=GC_COLLECTED; mark=GC_COLLECTED;
@ -238,7 +228,7 @@ nasal_val::~nasal_val()
double nasal_val::to_number() double nasal_val::to_number()
{ {
if(type==vm_str) if(type==vm_str)
return str2num(*ptr.str); return str2num(ptr.str->c_str());
return ptr.num; return ptr.num;
} }
std::string nasal_val::to_string() 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 nasal_parse::num_gen()
{ {
nasal_ast node(tok_list[ptr].line,ast_num); 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; return node;
} }
nasal_ast nasal_parse::str_gen() 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) else if(type==vm_str)
{ {
std::string& str=*val_addr->ptr.str; std::string& str=*val_addr->ptr.str;
double number=str2num(str); double number=str2num(str.c_str());
if(std::isnan(number)) if(std::isnan(number))
return !str.empty(); return !str.empty();
return number; return number;
@ -267,7 +267,7 @@ void nasal_vm::opr_unot()
new_val=val->ptr.num?gc.zero_addr:gc.one_addr; new_val=val->ptr.num?gc.zero_addr:gc.one_addr;
else if(type==vm_str) else if(type==vm_str)
{ {
double number=str2num(*val->ptr.str); double number=str2num(val->ptr.str->c_str());
if(std::isnan(number)) if(std::isnan(number))
new_val=val->ptr.str->empty()?gc.one_addr:gc.zero_addr; new_val=val->ptr.str->empty()?gc.one_addr:gc.zero_addr;
else else
@ -752,7 +752,7 @@ void nasal_vm::opr_slc()
switch(val->type) switch(val->type)
{ {
case vm_num:num=val->ptr.num;break; 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; default:die("slc: error value type");break;
} }
nasal_val* res=(*stack_top)->ptr.vec->get_val((int)num); nasal_val* res=(*stack_top)->ptr.vec->get_val((int)num);
@ -819,7 +819,7 @@ void nasal_vm::opr_mcallv()
switch(val->type) switch(val->type)
{ {
case vm_num:num=(int)val->ptr.num;break; 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; default:die("mcallv: error value type");break;
} }
nasal_val** res=(*vec_addr)->ptr.vec->get_mem(num); nasal_val** res=(*vec_addr)->ptr.vec->get_mem(num);