|
|
| version 1.5, 2024/09/20 01:13:50 | version 1.9, 2024/09/22 17:01:23 |
|---|---|
| Line 34 public: | Line 34 public: |
| DECLARE_CLASS_VAR(array, new MArray); | DECLARE_CLASS_VAR(array, new MArray); |
| const char* const PARAM_ARRAY_OR_HASH = "param must be array or hash"; | const char* const PARAM_ARRAY_OR_HASH = "param must be array or hash"; |
| const char* const PARAM_INDEX = "index must be integer"; | |
| // methods | // methods |
| enum HState { | |
| HS_FIRST, | |
| HS_STRING, | |
| HS_NUMBER | |
| }; | |
| static void _create_or_add(Request& r, MethodParams& params) { | static void _create_or_add(Request& r, MethodParams& params) { |
| if(params.count()) { | if(params.count()) { |
| Value& vsrc=params.as_no_junction(0, PARAM_ARRAY_OR_HASH); | Value& vsrc=params.as_no_junction(0, PARAM_ARRAY_OR_HASH); |
| Line 50 static void _create_or_add(Request& r, M | Line 45 static void _create_or_add(Request& r, M |
| ArrayValue& self_array=self.array(); | ArrayValue& self_array=self.array(); |
| if(VArray* src=dynamic_cast<VArray*>(&vsrc)) { | if(VArray* src=dynamic_cast<VArray*>(&vsrc)) { |
| if(src==&self) // same: doing nothing | if(src==&self) |
| return; | throw Exception(PARSER_RUNTIME, 0, "source and destination are the same array"); |
| self_array.append(src->array()); | self_array.append(src->array()); |
| } else { | } else { |
| HashStringValue* src_hash=vsrc.get_hash(); | HashStringValue* src_hash=vsrc.get_hash(); |
| if(!src_hash) | if(!src_hash) |
| return; | return; |
| HState hs=HS_FIRST; | |
| for(HashStringValue::Iterator i(*src_hash); i; i.next()){ | for(HashStringValue::Iterator i(*src_hash); i; i.next()){ |
| if (hs==HS_STRING){ | self_array.put(VArray::index(i.key()), i.value()); |
| self_array+=i.value(); | } |
| } else if(hs==HS_NUMBER){ | } |
| self_array.put(VArray::index(i.key()), i.value()); | self.invalidate(); |
| } else { | } |
| try { | } |
| self_array.put(VArray::index(i.key()), i.value()); | |
| hs==HS_NUMBER; | static ArrayValue::Action_options get_action_options(Request& r, MethodParams& params, size_t options_index) { |
| } catch(...) { | ArrayValue::Action_options result; |
| self_array+=i.value(); | if(params.count() <= options_index) |
| hs==HS_STRING; | return result; |
| HashStringValue* options=params.as_hash(options_index); | |
| if(!options) | |
| return result; | |
| result.defined=true; | |
| int valid_options=0; | |
| if(Value* voffset=options->get(sql_offset_name)) { | |
| valid_options++; | |
| int offset=r.process(*voffset).as_int(); | |
| result.offset=offset < 0 ? 0 : offset; | |
| } | |
| if(Value* vlimit=options->get(sql_limit_name)) { | |
| valid_options++; | |
| int limit=r.process(*vlimit).as_int(); | |
| result.limit=limit < 0 ? 0: limit; | |
| } | |
| if(valid_options!=options->count()) | |
| throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); | |
| return result; | |
| } | |
| static void _join(Request& r, MethodParams& params) { | |
| Value& vsrc=params.as_no_junction(0, PARAM_ARRAY_OR_HASH); | |
| ArrayValue::Action_options o=get_action_options(r, params, 1); | |
| VArray& self=GET_SELF(r, VArray); | |
| ArrayValue& self_array=self.array(); | |
| if(VArray* src=dynamic_cast<VArray*>(&vsrc)) { | |
| if(src==&self) | |
| throw Exception(PARSER_RUNTIME, 0, "source and destination are the same array"); | |
| if(o.defined){ | |
| for(ArrayValue::Iterator i(src->array()); i; i.next()){ | |
| if(i.value()){ | |
| if(o.offset > 0){ | |
| o.offset--; | |
| continue; | |
| } | } |
| if(o.limit-- == 0) | |
| break; | |
| self_array+=i.value(); | |
| } | } |
| } | } |
| } else { | |
| for(ArrayValue::Iterator i(src->array()); i; i.next()){ | |
| if(i.value()) | |
| self_array+=i.value(); | |
| } | |
| } | |
| } else { | |
| HashStringValue* src_hash=vsrc.get_hash(); | |
| if(!src_hash) | |
| return; | |
| if(o.defined){ | |
| for(HashStringValue::Iterator i(*src_hash); i; i.next()){ | |
| if(o.offset > 0){ | |
| o.offset--; | |
| continue; | |
| } | |
| if(o.limit-- == 0) | |
| break; | |
| self_array+=i.value(); | |
| } | |
| } else { | |
| for(HashStringValue::Iterator i(*src_hash); i; i.next()){ | |
| self_array+=i.value(); | |
| } | |
| } | } |
| self.invalidate(); | |
| } | } |
| self.invalidate(); | |
| } | } |
| static void _sql(Request& r, MethodParams& params) {} | static void _sql(Request& r, MethodParams& params) {} |
| static void _sub(Request& r, MethodParams& params) {} | |
| static void _union(Request& r, MethodParams& params) {} | static void mid(Request& r, ArrayValue::Action_options o) { |
| ArrayValue& array=GET_SELF(r, VArray).array(); | |
| if(o.limit>0){ | |
| VArray *result=new VArray; | |
| ArrayValue& result_array=result->array(); | |
| for(ArrayValue::Iterator i(array); i; i.next()){ | |
| if(i.value()){ | |
| if(o.offset > 0){ | |
| o.offset--; | |
| continue; | |
| } | |
| if(o.limit-- == 0) | |
| break; | |
| result_array+=i.value(); | |
| } | |
| } | |
| r.write(*result); | |
| } else { | |
| r.write(*new VArray); | |
| } | |
| } | |
| static void _intersection(Request& r, MethodParams& params) {} | static void _left(Request& r, MethodParams& params) { |
| int sn=params.as_int(0, "n must be int", r); | |
| mid(r, ArrayValue::Action_options(0, sn < 0 ? 0 : sn)); | |
| } | |
| static void _intersects(Request& r, MethodParams& params) {} | static void _right(Request& r, MethodParams& params) { |
| int sn=params.as_int(0, "n must be int", r); | |
| if(sn>0){ | |
| size_t used=GET_SELF(r, VArray).array().used(); | |
| if(sn<used){ | |
| mid(r, ArrayValue::Action_options(used-sn, sn)); | |
| } else { | |
| mid(r, ArrayValue::Action_options()); | |
| } | |
| } else { | |
| mid(r, ArrayValue::Action_options(0, 0)); | |
| } | |
| } | |
| static void _mid(Request& r, MethodParams& params) { | |
| const String& string=GET_SELF(r, VString).string(); | |
| int begin=params.as_int(0, "p must be int", r); | |
| if(begin<0) | |
| throw Exception(PARSER_RUNTIME, 0, "p(%d) must be >=0", begin); | |
| size_t end; | |
| size_t length=0; | |
| if(params.count()>1) { | |
| int n=params.as_int(1, "n must be int", r); | |
| if(n<0) | |
| throw Exception(PARSER_RUNTIME, 0, "n(%d) must be >=0", n); | |
| mid(r, ArrayValue::Action_options(begin, n)); | |
| } else { | |
| mid(r, ArrayValue::Action_options(begin)); | |
| } | |
| } | |
| static void _keys(Request& r, MethodParams& params) { | static void _keys(Request& r, MethodParams& params) { |
| const String* keys_column_name; | const String* keys_column_name; |
| Line 141 static void _insert(Request& r, MethodPa | Line 259 static void _insert(Request& r, MethodPa |
| ArrayValue& array=self.array(); | ArrayValue& array=self.array(); |
| int count=params.count(); | int count=params.count(); |
| size_t index=VArray::index(params.as_int(0, "index must be integer", r)); | size_t index=VArray::index(params.as_int(0, PARAM_INDEX, r)); |
| for(int i=1; i<count; i++){ | for(int i=1; i<count; i++){ |
| array.insert(index+i-1, &r.process(params[i])); | array.insert(index++, &r.process(params[i])); |
| } | } |
| self.invalidate(); | self.invalidate(); |
| } | } |
| static void _delete(Request& r, MethodParams& params) { | static void _delete(Request& r, MethodParams& params) { |
| VArray& self=GET_SELF(r, VArray); | |
| if(params.count()>0) | if(params.count()>0) |
| GET_SELF(r, VArray).clear(VArray::index(params.as_int(0, "index must be integer", r))); | self.array().clear(VArray::index(params.as_int(0, PARAM_INDEX, r))); |
| else | else |
| GET_SELF(r, VArray).clear(); | self.array().clear(); |
| self.invalidate(); | |
| } | |
| static void _remove(Request& r, MethodParams& params) { | |
| VArray& self=GET_SELF(r, VArray); | |
| self.array().remove(VArray::index(params.as_int(0, PARAM_INDEX, r))); | |
| self.invalidate(); | |
| } | } |
| static void _contains(Request& r, MethodParams& params) { | static void _contains(Request& r, MethodParams& params) { |
| VArray& self=GET_SELF(r, VArray); | VArray& self=GET_SELF(r, VArray); |
| bool result=self.contains(VArray::index(params.as_int(0, "index must be integer", r))); | bool result=self.contains(VArray::index(params.as_int(0, PARAM_INDEX, r))); |
| r.write(VBool::get(result)); | r.write(VBool::get(result)); |
| } | } |
| static void _for(Request& r, MethodParams& params) { | static void _for(Request& r, MethodParams& params) { |
| InCycle temp(r); | InCycle temp(r); |
| const String* value_var_name=¶ms.as_string(0, "value-var name must be string"); | const String* key_var_name=¶ms.as_string(0, "key-var name must be string"); |
| Value* body_code=¶ms.as_junction(1, "body must be code"); | const String* value_var_name=¶ms.as_string(1, "value-var name must be string"); |
| Value* delim_maybe_code=params.count()>2?¶ms[2]:0; | Value* body_code=¶ms.as_junction(2, "body must be code"); |
| Value* delim_maybe_code=params.count()>3 ? ¶ms[3] : 0; | |
| Value& caller=*r.get_method_frame()->caller(); | Value& caller=*r.get_method_frame()->caller(); |
| if(key_var_name->is_empty()) key_var_name=0; | |
| if(value_var_name->is_empty()) value_var_name=0; | if(value_var_name->is_empty()) value_var_name=0; |
| ArrayValue& array=GET_SELF(r, VArray).array(); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| Line 177 static void _for(Request& r, MethodParam | Line 305 static void _for(Request& r, MethodParam |
| if(delim_maybe_code){ // delimiter set | if(delim_maybe_code){ // delimiter set |
| bool need_delim=false; | bool need_delim=false; |
| for(ArrayValue::Iterator i(array); i; i.next()){ | for(ArrayValue::Iterator i(array); i; i.next()){ |
| if(key_var_name){ | |
| VString* vkey=new VString(*new String(i.key(), String::L_TAINTED)); | |
| r.put_element(caller, *key_var_name, vkey); | |
| } | |
| if(value_var_name) | if(value_var_name) |
| r.put_element(caller, *value_var_name, i.value() ? i.value() : VVoid::get()); | r.put_element(caller, *value_var_name, i.value() ? i.value() : VVoid::get()); |
| Line 198 static void _for(Request& r, MethodParam | Line 331 static void _for(Request& r, MethodParam |
| } | } |
| } else { | } else { |
| for(ArrayValue::Iterator i(array); i; i.next()){ | for(ArrayValue::Iterator i(array); i; i.next()){ |
| if(key_var_name){ | |
| VString* vkey=new VString(*new String(i.key(), String::L_TAINTED)); | |
| r.put_element(caller, *key_var_name, vkey); | |
| } | |
| if(value_var_name) | if(value_var_name) |
| r.put_element(caller, *value_var_name, i.value() ? i.value() : VVoid::get()); | r.put_element(caller, *value_var_name, i.value() ? i.value() : VVoid::get()); |
| Line 210 static void _for(Request& r, MethodParam | Line 348 static void _for(Request& r, MethodParam |
| } | } |
| static void _foreach(Request& r, MethodParams& params) { | static void _foreach(Request& r, MethodParams& params) { |
| if(params[1].get_junction()) | |
| return _for(r, params); | |
| InCycle temp(r); | InCycle temp(r); |
| const String* key_var_name=¶ms.as_string(0, "key-var name must be string"); | const String* key_var_name=¶ms.as_string(0, "key-var name must be string"); |
| const String* value_var_name=¶ms.as_string(1, "value-var name must be string"); | const String* value_var_name=¶ms.as_string(1, "value-var name must be string"); |
| Value* body_code=¶ms.as_junction(2, "body must be code"); | Value* body_code=¶ms.as_junction(2, "body must be code"); |
| Value* delim_maybe_code=params.count()>3?¶ms[3]:0; | Value* delim_maybe_code=params.count()>3 ? ¶ms[3] : 0; |
| Value& caller=*r.get_method_frame()->caller(); | Value& caller=*r.get_method_frame()->caller(); |
| if(key_var_name->is_empty()) key_var_name=0; | if(key_var_name->is_empty()) key_var_name=0; |
| Line 542 MArray::MArray(): Methoded(VARRAY_TYPE) | Line 677 MArray::MArray(): Methoded(VARRAY_TYPE) |
| add_native_method("create", Method::CT_DYNAMIC, _create_or_add, 0, 1); | add_native_method("create", Method::CT_DYNAMIC, _create_or_add, 0, 1); |
| // ^array.add[add_from] | // ^array.add[add_from] |
| add_native_method("add", Method::CT_DYNAMIC, _create_or_add, 1, 1); | add_native_method("add", Method::CT_DYNAMIC, _create_or_add, 1, 1); |
| // ^array.join[join_from[;options]] | |
| add_native_method("join", Method::CT_DYNAMIC, _join, 1, 2); | |
| // ^array.sub[sub_from] | // ^array.left(n) |
| add_native_method("sub", Method::CT_DYNAMIC, _sub, 1, 1); | add_native_method("left", Method::CT_DYNAMIC, _left, 1, 1); |
| // ^array.union[b] = array | // ^array.right(n) |
| add_native_method("union", Method::CT_DYNAMIC, _union, 1, 1); | add_native_method("right", Method::CT_DYNAMIC, _right, 1, 1); |
| // ^array.intersection[b][options array] = array | // ^array.mid(p) |
| add_native_method("intersection", Method::CT_DYNAMIC, _intersection, 1, 2); | // ^array.mid(p;n) |
| // ^array.intersects[b] = bool | add_native_method("mid", Method::CT_DYNAMIC, _mid, 1, 2); |
| add_native_method("intersects", Method::CT_DYNAMIC, _intersects, 1, 1); | |
| // ^array::new[value;value] | |
| add_native_method("new", Method::CT_DYNAMIC, _append, 0, 10000); | |
| // ^array.append[value;value] | // ^array.append[value;value] |
| add_native_method("append", Method::CT_DYNAMIC, _append, 1, 10000); | add_native_method("append", Method::CT_DYNAMIC, _append, 1, 10000); |
| // ^array.insert[index;value...] | // ^array.insert[index;value...] |
| add_native_method("insert", Method::CT_DYNAMIC, _insert, 2, 10000); | add_native_method("insert", Method::CT_DYNAMIC, _insert, 2, 10000); |
| // ^array.delete[index] | // ^array.delete[index] |
| add_native_method("delete", Method::CT_DYNAMIC, _delete, 0, 1); | add_native_method("delete", Method::CT_DYNAMIC, _delete, 0, 1); |
| // ^array.remove[index] | |
| add_native_method("remove", Method::CT_DYNAMIC, _remove, 1, 1); | |
| // ^array.contains[index] | // ^array.contains[index] |
| add_native_method("contains", Method::CT_DYNAMIC, _contains, 1, 1); | add_native_method("contains", Method::CT_DYNAMIC, _contains, 1, 1); |
| Line 573 MArray::MArray(): Methoded(VARRAY_TYPE) | Line 712 MArray::MArray(): Methoded(VARRAY_TYPE) |
| // ^array._count[[all]] | // ^array._count[[all]] |
| add_native_method("_count", Method::CT_DYNAMIC, _count, 0, 1); | add_native_method("_count", Method::CT_DYNAMIC, _count, 0, 1); |
| // ^array.for[index;value]{code}[delim] | |
| add_native_method("for", Method::CT_DYNAMIC, _for, 3, 3+1); | |
| // ^array.foreach[index;value]{code}[delim] | // ^array.foreach[index;value]{code}[delim] |
| add_native_method("foreach", Method::CT_DYNAMIC, _foreach, 2, 2+1+1); | add_native_method("foreach", Method::CT_DYNAMIC, _foreach, 3, 3+1); |
| // ^array.sort[index;value]{string-key-maker}[[asc|desc]] | // ^array.sort[index;value]{string-key-maker}[[asc|desc]] |
| // ^array.sort[index;value](numeric-key-maker)[[asc|desc]] | // ^array.sort[index;value](numeric-key-maker)[[asc|desc]] |