|
|
| version 1.24, 2024/10/26 00:21:02 | version 1.41, 2025/05/28 00:58:02 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: @b array parser class. | Parser: @b array parser class. |
| Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com) | Copyright (c) 2001-2024 Art. Lebedev Studio (http://www.artlebedev.com) |
| Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru> | Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru> |
| */ | */ |
| Line 38 const char* const PARAM_INDEX = "index m | Line 38 const char* const PARAM_INDEX = "index m |
| // methods | // methods |
| static void _create_or_add(Request& r, MethodParams& params) { | static void _copy_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); |
| VArray& self=GET_SELF(r, VArray); | VArray& self=GET_SELF(r, VArray); |
| Line 53 static void _create_or_add(Request& r, M | Line 53 static void _create_or_add(Request& r, M |
| self_array.put(i.index(), i.value()); | self_array.put(i.index(), i.value()); |
| } | } |
| } else { | } else { |
| self_array.append(src->array()); | self_array.copy(src->array()); |
| return; | |
| } | } |
| } else { | } else { |
| HashStringValue* src_hash=vsrc.as_hash("param must be array or"); | HashStringValue* src_hash=vsrc.as_hash("param must be array or"); |
| Line 587 static void _keys(Request& r, MethodPara | Line 588 static void _keys(Request& r, MethodPara |
| for(ArrayValue::Iterator i(array); i; i.next()){ | for(ArrayValue::Iterator i(array); i; i.next()){ |
| if(i.value()){ | if(i.value()){ |
| Table::element_type row(new ArrayString(1)); | Table::element_type row(new ArrayString(1)); |
| *row+=new String(i.key(), String::L_TAINTED); | *row+=new String(pa_uitoa(i.index())); |
| *table+=row; | *table+=row; |
| } | } |
| } | } |
| Line 608 static void _count(Request& r, MethodPar | Line 609 static void _count(Request& r, MethodPar |
| r.write(*new VInt(array.used())); | r.write(*new VInt(array.used())); |
| } | } |
| static void _append(Request& r, MethodParams& params) { | static void _create_or_append_or_push(Request& r, MethodParams& params) { |
| ArrayValue& array=GET_SELF(r, VArray).array(); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| int count=params.count(); | int count=params.count(); |
| for(int i=0; i<count; i++){ | if(array.count()){ |
| array+=&r.process(params[i]); | for(int i=0; i<count; i++){ |
| array+=&r.process(params[i]); | |
| array.change_used(+1); // after each element, since an exception can occur | |
| } | |
| } else { | |
| for(int i=0; i<count; i++) | |
| array+=&r.process(params[i]); | |
| array.confirm_all_used(); | |
| } | } |
| array.invalidate(); | |
| } | } |
| static void _insert(Request& r, MethodParams& params) { | static void _insert(Request& r, MethodParams& params) { |
| Line 627 static void _insert(Request& r, MethodPa | Line 634 static void _insert(Request& r, MethodPa |
| for(int i=1; i<count; i++){ | for(int i=1; i<count; i++){ |
| array.insert(index++, &r.process(params[i])); | array.insert(index++, &r.process(params[i])); |
| array.change_used(+1); // after each element, since an exception can occur | |
| } | } |
| array.invalidate(); | |
| } | } |
| static void _delete(Request& r, MethodParams& params) { | static void _delete(Request& r, MethodParams& params) { |
| ArrayValue& array=GET_SELF(r, VArray).array(); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| if(params.count()>0) | if(params.count()>0) { |
| array.clear(VArray::index(params.as_int(0, PARAM_INDEX, r))); | if(params[0].is_string()) { |
| else | array.clear(VArray::index(*params[0].get_string())); |
| } else { | |
| array.clear(VArray::index(params.as_int(0, PARAM_INDEX, r))); | |
| } | |
| } else | |
| array.clear(); | array.clear(); |
| array.invalidate(); | array.invalidate(); |
| } | } |
| Line 646 static void _remove(Request& r, MethodPa | Line 657 static void _remove(Request& r, MethodPa |
| array.invalidate(); | array.invalidate(); |
| } | } |
| static void _pop(Request& r, MethodParams&) { | |
| ArrayValue& array=GET_SELF(r, VArray).array(); | |
| Value *result=array.pop(); | |
| if(result){ | |
| r.write(*result); | |
| array.change_used(-1); | |
| } else { | |
| r.write(*VVoid::get()); | |
| } | |
| } | |
| 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, PARAM_INDEX, r))); | |
| bool result=self.contains(params[0].is_string() ? VArray::index(*params[0].get_string()) : VArray::index(params.as_int(0, PARAM_INDEX, r))); | |
| r.write(VBool::get(result)); | r.write(VBool::get(result)); |
| } | } |
| Line 668 static void _for(Request& r, MethodParam | Line 691 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::RobustIterator i(array); i; i.next()){ |
| if(key_var_name){ | if(key_var_name) |
| VString* vkey=new VString(*new String(i.key(), String::L_TAINTED)); | r.put_element(caller, *key_var_name, VString::uitoa(i.index())); |
| 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 694 static void _for(Request& r, MethodParam | Line 714 static void _for(Request& r, MethodParam |
| break; | break; |
| } | } |
| } else { | } else { |
| for(ArrayValue::Iterator i(array); i; i.next()){ | for(ArrayValue::RobustIterator i(array); i; i.next()){ |
| if(key_var_name){ | if(key_var_name) |
| VString* vkey=new VString(*new String(i.key(), String::L_TAINTED)); | r.put_element(caller, *key_var_name, VString::uitoa(i.index())); |
| 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 727 static void _foreach(Request& r, MethodP | Line 744 static void _foreach(Request& r, MethodP |
| 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::RobustIterator i(array); i; i.next()){ |
| if(i.value()){ | if(i.value()){ |
| if(key_var_name){ | if(key_var_name) |
| VString* vkey=new VString(*new String(i.key(), String::L_TAINTED)); | r.put_element(caller, *key_var_name, VString::uitoa(i.index())); |
| 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()); | r.put_element(caller, *value_var_name, i.value()); |
| Line 755 static void _foreach(Request& r, MethodP | Line 769 static void _foreach(Request& r, MethodP |
| } | } |
| } | } |
| } else { | } else { |
| for(ArrayValue::Iterator i(array); i; i.next()){ | for(ArrayValue::RobustIterator i(array); i; i.next()){ |
| if(i.value()){ | if(i.value()){ |
| if(key_var_name){ | if(key_var_name) |
| VString* vkey=new VString(*new String(i.key(), String::L_TAINTED)); | r.put_element(caller, *key_var_name, VString::uitoa(i.index())); |
| 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()); | r.put_element(caller, *value_var_name, i.value()); |
| Line 819 static void _sort(Request& r, MethodPara | Line 830 static void _sort(Request& r, MethodPara |
| int pos=0; | int pos=0; |
| bool key_values_are_strings=true; | bool key_values_are_strings=true; |
| for(ArrayValue::Iterator i(array); i; i.next() ){ | for(ArrayValue::RobustIterator i(array); i; i.next() ){ |
| if(i.value()){ | if(i.value()){ |
| if(key_var) | if(key_var) |
| r.put_element(*context, *key_var, new VString(*new String(i.key(), String::L_TAINTED))); | r.put_element(*context, *key_var, VString::uitoa(i.index())); |
| if(value_var) | if(value_var) |
| r.put_element(*context, *value_var, i.value()); | r.put_element(*context, *value_var, i.value()); |
| Line 856 static void _sort(Request& r, MethodPara | Line 867 static void _sort(Request& r, MethodPara |
| for(pos=0; pos<count; pos++) | for(pos=0; pos<count; pos++) |
| array+=seq[pos].array_data; | array+=seq[pos].array_data; |
| array.invalidate(); | array.confirm_all_used(); |
| delete[] seq; | delete[] seq; |
| } | } |
| Line 873 static Value& SingleElementHash(String:: | Line 884 static Value& SingleElementHash(String:: |
| } | } |
| static void _at(Request& r, MethodParams& params) { | static void _at(Request& r, MethodParams& params) { |
| VArray& self=GET_SELF(r, VArray); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| ArrayValue& array=self.array(); | |
| size_t count=array.used(); // not array.count() | size_t count=array.used(); // not array.count() |
| int pos=0; | |
| AtResultType result_type=AtResultTypeValue; | AtResultType result_type=AtResultTypeValue; |
| if(params.count() > 1) { | if(params.count() > 1) { |
| const String& stype=params.as_string(1, "type must be string"); | const String& stype=params.as_string(1, "type must be string"); |
| Line 890 static void _at(Request& r, MethodParams | Line 898 static void _at(Request& r, MethodParams |
| throw Exception(PARSER_RUNTIME, &stype, "type must be 'key', 'value' or 'hash'"); | throw Exception(PARSER_RUNTIME, &stype, "type must be 'key', 'value' or 'hash'"); |
| } | } |
| Value& vwhence=params[0]; | int pos=params.as_index(0, count, r); |
| if(vwhence.is_string()) { | |
| const String& swhence=*vwhence.get_string(); | |
| if(swhence == "last") | |
| pos=count-1; | |
| else if(swhence != "first") | |
| throw Exception(PARSER_RUNTIME, &swhence, "whence must be 'first', 'last' or expression"); | |
| } else { | |
| pos=r.process(vwhence).as_int(); | |
| if(pos < 0) | |
| pos+=count; | |
| } | |
| if(count && pos >= 0 && (size_t)pos < count){ | if(count && pos >= 0 && (size_t)pos < count){ |
| if(count == array.count()){ | if(count == array.count()){ |
| switch(result_type) { | l1: switch(result_type) { |
| case AtResultTypeKey: | case AtResultTypeKey: |
| r.write(*new VString(*new String(pa_uitoa(pos), String::L_TAINTED))); | r.write(*VString::uitoa(pos)); |
| break; | break; |
| case AtResultTypeValue: | case AtResultTypeValue: |
| r.write(*array[pos]); | r.write(*array.get(pos)); |
| break; | break; |
| case AtResultTypeHash: | case AtResultTypeHash: |
| r.write(SingleElementHash(pa_uitoa(pos), array[pos])); | r.write(SingleElementHash(String::Body::uitoa(pos), array.get(pos))); |
| break; | break; |
| } | } |
| } else if((size_t)pos == count-1){ | |
| pos=array.count()-1; | |
| goto l1; | |
| } else { | } else { |
| for(ArrayValue::Iterator i(array); i; i.next() ){ | for(ArrayValue::Iterator i(array); i; i.next() ){ |
| if(i.value() && !(pos--)){ | if(i.value() && !(pos--)){ |
| switch(result_type) { | switch(result_type) { |
| case AtResultTypeKey: | case AtResultTypeKey: |
| r.write(*new VString(*new String(i.key(), String::L_TAINTED))); | r.write(*VString::uitoa(i.index())); |
| break; | break; |
| case AtResultTypeValue: | case AtResultTypeValue: |
| r.write(*i.value()); | r.write(*i.value()); |
| break; | break; |
| case AtResultTypeHash: | case AtResultTypeHash: |
| r.write(SingleElementHash(i.key(), i.value())); | r.write(SingleElementHash(String::Body::uitoa(i.index()), i.value())); |
| break; | break; |
| } | } |
| break; | break; |
| Line 937 static void _at(Request& r, MethodParams | Line 937 static void _at(Request& r, MethodParams |
| } | } |
| } | } |
| static void _set(Request& r, MethodParams& params) { | |
| ArrayValue& array=GET_SELF(r, VArray).array(); | |
| size_t count=array.used(); // not array.count() | |
| int pos=params.as_index(0, count, r); | |
| if(count && pos >= 0 && (size_t)pos < count){ | |
| if(count == array.count()){ | |
| array.put(pos, &r.process(params[1])); | |
| return; | |
| } else if((size_t)pos == count-1){ | |
| array.put(array.count()-1, &r.process(params[1])); | |
| return; | |
| } else { | |
| for(ArrayValue::Iterator i(array); i; i.next() ){ | |
| if(i.value() && !(pos--)){ | |
| array.put(i.index(), &r.process(params[1])); | |
| return; | |
| } | |
| } | |
| } | |
| } | |
| if(count) | |
| throw Exception(PARSER_RUNTIME, 0, "index '%d' is out of range 0..%d", pos, count-1); | |
| throw Exception(PARSER_RUNTIME, 0, "index '%d' is out of range: array is empty", pos); | |
| } | |
| extern String table_reverse_name; | extern String table_reverse_name; |
| Line 978 static void _select(Request& r, MethodPa | Line 1005 static void _select(Request& r, MethodPa |
| for(ArrayValue::ReverseIterator i(source_array); i; ){ | for(ArrayValue::ReverseIterator i(source_array); i; ){ |
| if(Value *value=i.prev()){ // here for correct i.key() | if(Value *value=i.prev()){ // here for correct i.key() |
| if(key_var_name) | if(key_var_name) |
| r.put_element(caller, *key_var_name, new VString(*new String(i.key(), String::L_TAINTED))); | r.put_element(caller, *key_var_name, VString::uitoa(i.index())); |
| if(value_var_name) | if(value_var_name) |
| r.put_element(caller, *value_var_name, value); | r.put_element(caller, *value_var_name, value); |
| Line 995 static void _select(Request& r, MethodPa | Line 1022 static void _select(Request& r, MethodPa |
| } | } |
| } | } |
| } else { | } else { |
| for(ArrayValue::Iterator i(source_array); i; i.next() ){ | for(ArrayValue::RobustIterator i(source_array); i; i.next() ){ |
| if(Value *value=i.value()){ | if(Value *value=i.value()){ |
| if(key_var_name) | if(key_var_name) |
| r.put_element(caller, *key_var_name, new VString(*new String(i.key(), String::L_TAINTED))); | r.put_element(caller, *key_var_name, VString::uitoa(i.index())); |
| if(value_var_name) | if(value_var_name) |
| r.put_element(caller, *value_var_name, value); | r.put_element(caller, *value_var_name, value); |
| Line 1044 static void _compact(Request& r, MethodP | Line 1071 static void _compact(Request& r, MethodP |
| compact_undef=true; | compact_undef=true; |
| } | } |
| } | } |
| GET_SELF(r, VArray).array().compact(compact_undef); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| array.compact(compact_undef); | |
| array.confirm_all_used(); | |
| } | } |
| Line 1053 static void _compact(Request& r, MethodP | Line 1082 static void _compact(Request& r, MethodP |
| MArray::MArray(): Methoded(VARRAY_TYPE) { | MArray::MArray(): Methoded(VARRAY_TYPE) { |
| // ^array::copy[[copy_from]] | // ^array::copy[[copy_from]] |
| add_native_method("copy", Method::CT_DYNAMIC, _create_or_add, 0, 1); | add_native_method("copy", Method::CT_DYNAMIC, _copy_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, _copy_or_add, 1, 1); |
| // ^array.join[join_from[;options]] | // ^array.join[join_from[;options]] |
| add_native_method("join", Method::CT_DYNAMIC, _join, 1, 2); | add_native_method("join", Method::CT_DYNAMIC, _join, 1, 2); |
| // ^array::create[value;value] | // ^array::create[value[;value...]] |
| add_native_method("create", Method::CT_DYNAMIC, _append, 0, 10000); | add_native_method("create", Method::CT_DYNAMIC, _create_or_append_or_push, 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, _create_or_append_or_push, 1, 10000); |
| // ^array.insert[index;value...] | // ^array.push[value[;value...]] |
| add_native_method("push", Method::CT_DYNAMIC, _create_or_append_or_push, 1, 10000); | |
| // ^array.insert(index)[value[;value...]] | |
| add_native_method("insert", Method::CT_DYNAMIC, _insert, 2, 10000); | add_native_method("insert", Method::CT_DYNAMIC, _insert, 2, 10000); |
| // ^array.left(n) | // ^array.left(n) |
| Line 1074 MArray::MArray(): Methoded(VARRAY_TYPE) | Line 1105 MArray::MArray(): Methoded(VARRAY_TYPE) |
| // ^array.mid(p;n) | // ^array.mid(p;n) |
| add_native_method("mid", Method::CT_DYNAMIC, _mid, 1, 2); | add_native_method("mid", Method::CT_DYNAMIC, _mid, 1, 2); |
| // ^array.delete[index] | // ^array.delete(index) or ^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] | // ^array.remove(index) |
| add_native_method("remove", Method::CT_DYNAMIC, _remove, 1, 1); | add_native_method("remove", Method::CT_DYNAMIC, _remove, 1, 1); |
| // ^array.pop[] | |
| add_native_method("pop", Method::CT_DYNAMIC, _pop, 0, 0); | |
| // ^array.contains[index] | // ^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); |
| // ^array::sql[query][options array] | // ^array::sql[query][options array] |
| Line 1110 MArray::MArray(): Methoded(VARRAY_TYPE) | Line 1143 MArray::MArray(): Methoded(VARRAY_TYPE) |
| add_native_method("compact", Method::CT_DYNAMIC, _compact, 0, 1); | add_native_method("compact", Method::CT_DYNAMIC, _compact, 0, 1); |
| // ^array._at[first|last[;'key'|'value'|'hash']] | // ^array._at[first|last[;'key'|'value'|'hash']] |
| // ^array._at([-+]offset)[['key'|'value'|'hash']] | // ^array._at([-+]index)[['key'|'value'|'hash']] |
| add_native_method("_at", Method::CT_DYNAMIC, _at, 1, 2); | add_native_method("_at", Method::CT_DYNAMIC, _at, 1, 2); |
| // ^array.set[first|last;value] | |
| // ^array.set([-+]index)[value] | |
| add_native_method("set", Method::CT_DYNAMIC, _set, 2, 2); | |
| #ifdef FEATURE_GET_ELEMENT4CALL | #ifdef FEATURE_GET_ELEMENT4CALL |
| // aliases without "_" | // aliases without "_" |
| add_native_method("keys", Method::CT_DYNAMIC, _keys, 0, 1); | add_native_method("keys", Method::CT_DYNAMIC, _keys, 0, 1); |