|
|
| version 1.11, 2024/09/28 14:15:13 | version 1.35, 2024/11/04 03:53:25 |
|---|---|
| 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 46 static void _create_or_add(Request& r, M | Line 46 static void _create_or_add(Request& r, M |
| if(VArray* src=dynamic_cast<VArray*>(&vsrc)) { | if(VArray* src=dynamic_cast<VArray*>(&vsrc)) { |
| if(src==&self) | if(src==&self) |
| throw Exception(PARSER_RUNTIME, 0, "source and destination are the same array"); | return; |
| self_array.append(src->array()); | if(self_array.count()){ |
| for(ArrayValue::Iterator i(src->array()); i; i.next()){ | |
| if(i.value()) | |
| self_array.put(i.index(), i.value()); | |
| } | |
| } else { | |
| self_array.copy(src->array()); | |
| return; | |
| } | |
| } else { | } else { |
| HashStringValue* src_hash=vsrc.get_hash(); | HashStringValue* src_hash=vsrc.as_hash("param must be array or"); |
| if(!src_hash) | if(!src_hash) |
| return; | return; |
| for(HashStringValue::Iterator i(*src_hash); i; i.next()){ | for(HashStringValue::Iterator i(*src_hash); i; i.next()){ |
| self_array.put(VArray::index(i.key()), i.value()); | self_array.put(VArray::index(i.key()), i.value()); |
| } | } |
| } | } |
| self.invalidate(); | self_array.invalidate(); |
| } | } |
| } | } |
| Line 119 static void _join(Request& r, MethodPara | Line 127 static void _join(Request& r, MethodPara |
| } | } |
| } | } |
| } else { | } else { |
| HashStringValue* src_hash=vsrc.get_hash(); | HashStringValue* src_hash=vsrc.as_hash("param must be array or"); |
| if(!src_hash) | if(!src_hash) |
| return; | return; |
| if(o.defined){ | if(o.defined){ |
| Line 138 static void _join(Request& r, MethodPara | Line 146 static void _join(Request& r, MethodPara |
| } | } |
| } | } |
| } | } |
| self.invalidate(); | self_array.invalidate(); |
| } | } |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| Line 150 class SparseArray_sql_event_handlers: pu | Line 158 class SparseArray_sql_event_handlers: pu |
| ArrayValue& result; | ArrayValue& result; |
| Value* row_value; | Value* row_value; |
| int column_index; | int column_index; |
| ArrayString& columns; | ArrayString* columns; |
| bool one_bool_column; | bool one_bool_column; |
| Table2hash_value_type value_type; | Table2hash_value_type value_type; |
| int columns_count; | int columns_count; |
| Line 162 public: | Line 170 public: |
| result(aresult), | result(aresult), |
| row_value(0), | row_value(0), |
| column_index(0), | column_index(0), |
| columns(*new ArrayString), | columns(new ArrayString), |
| one_bool_column(false), | one_bool_column(false), |
| value_type(avalue_type), | value_type(avalue_type), |
| empty(0) { | empty(0) { |
| Line 170 public: | Line 178 public: |
| bool add_column(SQL_Error& error, const char* str, size_t ) { | bool add_column(SQL_Error& error, const char* str, size_t ) { |
| try { | try { |
| columns+=&STRING(str); | if(columns_count){ |
| // another query in multi_statements mode | |
| columns=new ArrayString; | |
| columns_count=0; | |
| } | |
| *columns+=&STRING(str); | |
| return false; | return false; |
| } catch(...) { | } catch(...) { |
| error=SQL_Error("exception occurred in Hash_sql_event_handlers::add_column"); | error=SQL_Error("exception occurred in Hash_sql_event_handlers::add_column"); |
| Line 179 public: | Line 192 public: |
| } | } |
| bool before_rows(SQL_Error& error) { | bool before_rows(SQL_Error& error) { |
| if(columns.count()<1) { | columns_count=columns->count(); |
| if(columns_count<1) { | |
| error=SQL_Error("no columns"); | error=SQL_Error("no columns"); |
| return true; | return true; |
| } | } |
| if(columns.count()==1) { | if(columns_count==1) { |
| one_bool_column=true; | one_bool_column=true; |
| } else { | } else { |
| switch(value_type){ | switch(value_type){ |
| case C_STRING: { | case C_STRING: { |
| if(columns.count()>2){ | if(columns_count>2){ |
| error=SQL_Error("only 2 columns allowed for $.type[string] and $.sparse(true)."); | error=SQL_Error("only 2 columns allowed for $.type[string] and $.sparse(true)"); |
| return true; | return true; |
| } | } |
| break; | break; |
| } | } |
| case C_TABLE: { | case C_TABLE: { |
| // create empty table which we'll copy later | // create empty table which we'll copy later |
| empty=new Table(&columns); | empty=new Table(columns); |
| columns_count=columns.count(); | |
| break; | break; |
| } | } |
| } | } |
| Line 212 public: | Line 225 public: |
| bool add_row_cell(SQL_Error& error, const char *str, size_t ) { | bool add_row_cell(SQL_Error& error, const char *str, size_t ) { |
| try { | try { |
| if(column_index==columns_count){ | |
| // should never happen, buggy driver case | |
| error=SQL_Error("columns index exceed the columns count"); | |
| return true; | |
| } | |
| bool duplicate=false; | bool duplicate=false; |
| if(one_bool_column) { | if(one_bool_column) { |
| size_t index=str ? pa_atoui(str) : 0; | size_t index=str ? pa_atoui(str) : 0; |
| Line 248 public: | Line 267 public: |
| ArrayString* row=new ArrayString(columns_count); | ArrayString* row=new ArrayString(columns_count); |
| *row+=&STRING(str); | *row+=&STRING(str); |
| *vtable->get_table()+=row; | *vtable->get_table()+=row; |
| row_value=(Value*)row; | |
| break; | break; |
| } | } |
| } | } |
| Line 255 public: | Line 275 public: |
| const String& cell=STRING(str); | const String& cell=STRING(str); |
| switch(value_type) { | switch(value_type) { |
| case C_HASH: { | case C_HASH: { |
| row_value->get_hash()->put(*columns[column_index], new VString(cell)); | row_value->get_hash()->put(*columns->get(column_index), new VString(cell)); |
| break; | break; |
| } | } |
| case C_STRING: { | case C_STRING: { |
| Line 292 class Array_sql_event_handlers: public S | Line 312 class Array_sql_event_handlers: public S |
| ArrayValue& result; | ArrayValue& result; |
| Value* row_value; | Value* row_value; |
| int column_index; | int column_index; |
| ArrayString& columns; | ArrayString* columns; |
| Table2hash_value_type value_type; | Table2hash_value_type value_type; |
| int columns_count; | int columns_count; |
| public: | public: |
| Line 302 public: | Line 322 public: |
| result(aresult), | result(aresult), |
| row_value(0), | row_value(0), |
| column_index(0), | column_index(0), |
| columns(*new ArrayString), | columns(new ArrayString), |
| value_type(avalue_type), | value_type(avalue_type), |
| empty(0) { | empty(0) { |
| } | } |
| bool add_column(SQL_Error& error, const char* str, size_t ) { | bool add_column(SQL_Error& error, const char* str, size_t ) { |
| try { | try { |
| columns+=&STRING(str); | if(columns_count){ |
| // another query in multi_statements mode | |
| columns=new ArrayString; | |
| columns_count=0; | |
| } | |
| *columns+=&STRING(str); | |
| return false; | return false; |
| } catch(...) { | } catch(...) { |
| error=SQL_Error("exception occurred in Hash_sql_event_handlers::add_column"); | error=SQL_Error("exception occurred in Hash_sql_event_handlers::add_column"); |
| Line 318 public: | Line 343 public: |
| } | } |
| bool before_rows(SQL_Error& error) { | bool before_rows(SQL_Error& error) { |
| if(columns.count()<1) { | columns_count=columns->count(); |
| if(columns_count<1) { | |
| error=SQL_Error("no columns"); | error=SQL_Error("no columns"); |
| return true; | return true; |
| } | } |
| switch(value_type){ | switch(value_type){ |
| case C_STRING: { | case C_STRING: { |
| if(columns.count()>1){ | if(columns_count>1){ |
| error=SQL_Error("only one column allowed for $.type[string]."); | error=SQL_Error("only one column allowed for $.type[string]"); |
| return true; | return true; |
| } | } |
| break; | break; |
| } | } |
| case C_TABLE: { | case C_TABLE: { |
| // create empty table which we'll copy later | // create empty table which we'll copy later |
| empty=new Table(&columns); | empty=new Table(columns); |
| columns_count=columns.count(); | |
| break; | break; |
| } | } |
| } | } |
| Line 347 public: | Line 372 public: |
| bool add_row_cell(SQL_Error& error, const char *str, size_t ) { | bool add_row_cell(SQL_Error& error, const char *str, size_t ) { |
| try { | try { |
| if(column_index==columns_count){ | |
| // should never happen, buggy driver case | |
| error=SQL_Error("columns index exceed the columns count"); | |
| return true; | |
| } | |
| if(column_index==0) { | if(column_index==0) { |
| switch(value_type){ | switch(value_type){ |
| case C_HASH: { | case C_HASH: { |
| Line 365 public: | Line 396 public: |
| // creating table of same structure as source | // creating table of same structure as source |
| Table::Action_options table_options(0, 0); | Table::Action_options table_options(0, 0); |
| VTable* vtable=new VTable(new Table(*empty, table_options/*no rows, just structure*/)); | VTable* vtable=new VTable(new Table(*empty, table_options/*no rows, just structure*/)); |
| result+=vtable; | |
| ArrayString* row=new ArrayString(columns_count); | ArrayString* row=new ArrayString(columns_count); |
| *vtable->get_table()+=row; | *vtable->get_table()+=row; |
| row_value=(Value*)row; | |
| result+=vtable; | |
| break; | break; |
| } | } |
| } | } |
| Line 377 public: | Line 408 public: |
| const String& cell=STRING(str); | const String& cell=STRING(str); |
| switch(value_type) { | switch(value_type) { |
| case C_HASH: { | case C_HASH: { |
| row_value->get_hash()->put(*columns[column_index], new VString(cell)); | row_value->get_hash()->put(*columns->get(column_index), new VString(cell)); |
| break; | break; |
| } | } |
| case C_STRING: { | case C_STRING: { |
| Line 422 static void _sql(Request& r, MethodParam | Line 453 static void _sql(Request& r, MethodParam |
| if(params.count()>1) | if(params.count()>1) |
| if(HashStringValue* options=params.as_hash(1, "sql options")) { | if(HashStringValue* options=params.as_hash(1, "sql options")) { |
| int valid_options=0; | int valid_options=0; |
| bool distinct_specified=false; | |
| for(HashStringValue::Iterator i(*options); i; i.next() ){ | for(HashStringValue::Iterator i(*options); i; i.next() ){ |
| String::Body key=i.key(); | String::Body key=i.key(); |
| Value* value=i.value(); | Value* value=i.value(); |
| Line 436 static void _sql(Request& r, MethodParam | Line 468 static void _sql(Request& r, MethodParam |
| valid_options++; | valid_options++; |
| } else if (key == sql_distinct_name) { | } else if (key == sql_distinct_name) { |
| distinct=r.process(*value).as_bool(); | distinct=r.process(*value).as_bool(); |
| distinct_specified=true; | |
| valid_options++; | valid_options++; |
| } else if (key == sql_value_type_name) { | } else if (key == sql_value_type_name) { |
| sparse=r.process(*value).as_bool(); | value_type=get_value_type(r.process(*value)); |
| valid_options++; | valid_options++; |
| } else if (key == "sparse") { | } else if (key == "sparse") { |
| value_type=get_value_type(r.process(*value)); | sparse=r.process(*value).as_bool(); |
| valid_options++; | valid_options++; |
| } | } |
| } | } |
| if(valid_options!=options->count()) | if(valid_options!=options->count()) |
| throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); | throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); |
| if(distinct_specified && !sparse) | |
| throw Exception(PARSER_RUNTIME, 0, "'distinct' option can only be used when $.sparse(true) is specified"); | |
| } | } |
| SQL_Driver::Placeholder* placeholders=0; | SQL_Driver::Placeholder* placeholders=0; |
| Line 458 static void _sql(Request& r, MethodParam | Line 493 static void _sql(Request& r, MethodParam |
| const char* statement_cstr=statement_string.untaint_cstr(String::L_SQL, r.connection()); | const char* statement_cstr=statement_string.untaint_cstr(String::L_SQL, r.connection()); |
| VArray& self=GET_SELF(r, VArray); | VArray& self=GET_SELF(r, VArray); |
| ArrayValue& array=self.array(); | |
| self.array().clear(); self.invalidate(); // just in case if called as method | |
| if(array.count()){ | |
| array.clear(); array.invalidate(); // just in case if called as method | |
| } | |
| if(sparse){ | if(sparse){ |
| SparseArray_sql_event_handlers handlers(distinct, self.array(), value_type); | SparseArray_sql_event_handlers handlers(distinct, array, value_type); |
| r.connection()->query(statement_cstr, placeholders_count, placeholders, offset, limit, handlers, statement_string); | r.connection()->query(statement_cstr, placeholders_count, placeholders, offset, limit, handlers, statement_string); |
| } else { | } else { |
| Array_sql_event_handlers handlers(self.array(), value_type); | Array_sql_event_handlers handlers(array, value_type); |
| r.connection()->query(statement_cstr, placeholders_count, placeholders, offset, limit, handlers, statement_string); | r.connection()->query(statement_cstr, placeholders_count, placeholders, offset, limit, handlers, statement_string); |
| } | } |
| array.confirm_all_used(); | |
| if(bind) | if(bind) |
| unmarshal_bind_updates(*bind, placeholders_count, placeholders); | unmarshal_bind_updates(*bind, placeholders_count, placeholders); |
| } | } |
| static void mid(Request& r, size_t offset=0, size_t limit=ARRAY_OPTION_LIMIT_ALL) { | static void mid(Request& r, size_t offset=0, size_t limit=ARRAY_OPTION_LIMIT_ALL) { |
| ArrayValue& array=GET_SELF(r, VArray).array(); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| if(limit>0){ | if(limit>0){ |
| Line 491 static void mid(Request& r, size_t offse | Line 530 static void mid(Request& r, size_t offse |
| result_array+=i.value(); | result_array+=i.value(); |
| } | } |
| } | } |
| result_array.confirm_all_used(); | |
| r.write(*result); | r.write(*result); |
| } else { | } else { |
| r.write(*new VArray); | r.write(*new VArray); |
| Line 507 static void _right(Request& r, MethodPar | Line 547 static void _right(Request& r, MethodPar |
| if(sn>0){ | if(sn>0){ |
| size_t used=GET_SELF(r, VArray).array().used(); | size_t used=GET_SELF(r, VArray).array().used(); |
| if(sn<used){ | if((size_t)sn<used){ |
| mid(r, used-sn, sn); | mid(r, used-sn, sn); |
| } else { | } else { |
| mid(r); | mid(r); |
| Line 518 static void _right(Request& r, MethodPar | Line 558 static void _right(Request& r, MethodPar |
| } | } |
| static void _mid(Request& r, MethodParams& params) { | 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); | int begin=params.as_int(0, "p must be int", r); |
| if(begin<0) | if(begin<0) |
| throw Exception(PARSER_RUNTIME, 0, "p(%d) must be >=0", begin); | throw Exception(PARSER_RUNTIME, 0, "p(%d) must be >=0", begin); |
| size_t end; | |
| size_t length=0; | |
| if(params.count()>1) { | if(params.count()>1) { |
| int n=params.as_int(1, "n must be int", r); | int n=params.as_int(1, "n must be int", r); |
| if(n<0) | if(n<0) |
| Line 573 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) { |
| VArray& self=GET_SELF(r, VArray); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| ArrayValue& array=self.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(); | |
| } | } |
| self.invalidate(); | |
| } | } |
| static void _insert(Request& r, MethodParams& params) { | static void _insert(Request& r, MethodParams& params) { |
| VArray& self=GET_SELF(r, VArray); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| ArrayValue& array=self.array(); | |
| int count=params.count(); | int count=params.count(); |
| size_t index=VArray::index(params.as_int(0, PARAM_INDEX, 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++, &r.process(params[i])); | array.insert(index++, &r.process(params[i])); |
| array.change_used(+1); // after each element, since an exception can occur | |
| } | } |
| self.invalidate(); | |
| } | } |
| static void _delete(Request& r, MethodParams& params) { | static void _delete(Request& r, MethodParams& params) { |
| VArray& self=GET_SELF(r, VArray); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| if(params.count()>0) | if(params.count()>0) { |
| self.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())); |
| self.array().clear(); | } else { |
| self.invalidate(); | array.clear(VArray::index(params.as_int(0, PARAM_INDEX, r))); |
| } | |
| } else | |
| array.clear(); | |
| array.invalidate(); | |
| } | } |
| static void _remove(Request& r, MethodParams& params) { | static void _remove(Request& r, MethodParams& params) { |
| VArray& self=GET_SELF(r, VArray); | ArrayValue& array=GET_SELF(r, VArray).array(); |
| self.array().remove(VArray::index(params.as_int(0, PARAM_INDEX, r))); | array.remove(VArray::index(params.as_int(0, PARAM_INDEX, r))); |
| self.invalidate(); | array.invalidate(); |
| } | |
| static void _pop(Request& r, MethodParams& params) { | |
| 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 823 static void _sort(Request& r, MethodPara | Line 879 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.confirm_all_used(); | |
| delete[] seq; | delete[] seq; |
| } | } |
| Line 832 enum AtResultType { | Line 889 enum AtResultType { |
| AtResultTypeHash = 2 | AtResultTypeHash = 2 |
| }; | }; |
| inline Value& SingleElementHash(String::Body akey, Value* avalue) { | static Value& SingleElementHash(String::Body akey, Value* avalue) { |
| Value& result=*new VHash; | Value& result=*new VHash; |
| result.put_element(*new String(akey, String::L_TAINTED), avalue); | result.put_element(*new String(akey, String::L_TAINTED), avalue); |
| return result; | return result; |
| } | } |
| 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 856 static void _at(Request& r, MethodParams | Line 910 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){ |
| switch(result_type) { | if(count == array.count()){ |
| case AtResultTypeKey: | l1: switch(result_type) { |
| { | case AtResultTypeKey: |
| for(ArrayValue::Iterator i(array); i; i.next() ){ | r.write(*new VString(*new String(pa_uitoa(pos), String::L_TAINTED))); |
| if(i.value() && !(pos--)){ | break; |
| case AtResultTypeValue: | |
| r.write(*array.get(pos)); | |
| break; | |
| case AtResultTypeHash: | |
| r.write(SingleElementHash(pa_uitoa(pos), array.get(pos))); | |
| break; | |
| } | |
| } else if((size_t)pos == count-1){ | |
| pos=array.count()-1; | |
| goto l1; | |
| } else { | |
| for(ArrayValue::Iterator i(array); i; i.next() ){ | |
| if(i.value() && !(pos--)){ | |
| switch(result_type) { | |
| case AtResultTypeKey: | |
| r.write(*new VString(*new String(i.key(), String::L_TAINTED))); | r.write(*new VString(*new String(i.key(), String::L_TAINTED))); |
| break; | break; |
| } | case AtResultTypeValue: |
| } | |
| break; | |
| } | |
| case AtResultTypeValue: | |
| { | |
| for(ArrayValue::Iterator i(array); i; i.next() ) | |
| if(i.value() &&!(pos--)){ | |
| r.write(*i.value()); | r.write(*i.value()); |
| break; | break; |
| } | case AtResultTypeHash: |
| break; | |
| } | |
| case AtResultTypeHash: | |
| { | |
| for(ArrayValue::Iterator i(array); i; i.next() ) | |
| if(i.value() &&!(pos--)){ | |
| r.write(SingleElementHash(i.key(), i.value())); | r.write(SingleElementHash(i.key(), i.value())); |
| break; | break; |
| } | } |
| break; | break; |
| } | } |
| } | |
| } | } |
| } | } |
| } | } |
| 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 983 static void _select(Request& r, MethodPa | Line 1056 static void _select(Request& r, MethodPa |
| } | } |
| } | } |
| result_array.confirm_all_used(); | |
| r.write(*result); | r.write(*result); |
| } | } |
| static void _reverse(Request& r, MethodParams& params) { | static void _reverse(Request& r, MethodParams&) { |
| ArrayValue& source_array=GET_SELF(r, VArray).array(); | ArrayValue& source_array=GET_SELF(r, VArray).array(); |
| VArray& result=*new VArray(source_array.count()); | VArray& result=*new VArray(source_array.count()); |
| Line 999 static void _reverse(Request& r, MethodP | Line 1073 static void _reverse(Request& r, MethodP |
| r.write(result); | r.write(result); |
| } | } |
| static void _compact(Request& r, MethodParams& params) { | |
| bool compact_undef=false; | |
| if(params.count()>0){ | |
| const String& what=params.as_string(0, PARAMETER_MUST_BE_STRING); | |
| if(!what.is_empty()){ | |
| if(what != "undef") | |
| throw Exception(PARSER_RUNTIME, &what, "param must be empty or 'undef'"); | |
| compact_undef=true; | |
| } | |
| } | |
| ArrayValue& array=GET_SELF(r, VArray).array(); | |
| array.compact(compact_undef); | |
| array.confirm_all_used(); | |
| } | |
| // constructor | // constructor |
| MArray::MArray(): Methoded(VARRAY_TYPE) { | MArray::MArray(): Methoded(VARRAY_TYPE) { |
| // ^array::create[[copy_from]] | // ^array::copy[[copy_from]] |
| add_native_method("create", 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...]] | |
| add_native_method("create", Method::CT_DYNAMIC, _create_or_append_or_push, 0, 10000); | |
| // ^array.append[value[;value...]] | |
| add_native_method("append", Method::CT_DYNAMIC, _create_or_append_or_push, 1, 10000); | |
| // ^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); | |
| // ^array.left(n) | // ^array.left(n) |
| add_native_method("left", Method::CT_DYNAMIC, _left, 1, 1); | add_native_method("left", Method::CT_DYNAMIC, _left, 1, 1); |
| // ^array.right(n) | // ^array.right(n) |
| Line 1019 MArray::MArray(): Methoded(VARRAY_TYPE) | Line 1117 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::new[value;value] | // ^array.delete(index) or ^array.delete[index] |
| add_native_method("new", Method::CT_DYNAMIC, _append, 0, 10000); | |
| // ^array.append[value;value] | |
| add_native_method("append", Method::CT_DYNAMIC, _append, 1, 10000); | |
| // ^array.insert[index;value...] | |
| add_native_method("insert", Method::CT_DYNAMIC, _insert, 2, 10000); | |
| // ^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 1058 MArray::MArray(): Methoded(VARRAY_TYPE) | Line 1151 MArray::MArray(): Methoded(VARRAY_TYPE) |
| // ^array.reverse[] | // ^array.reverse[] |
| add_native_method("reverse", Method::CT_DYNAMIC, _reverse, 0, 0); | add_native_method("reverse", Method::CT_DYNAMIC, _reverse, 0, 0); |
| // ^array.compact[[undef]] | |
| 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); |
| add_native_method("count", Method::CT_DYNAMIC, _count, 0, 0); | add_native_method("count", Method::CT_DYNAMIC, _count, 0, 1); |
| add_native_method("at", Method::CT_DYNAMIC, _at, 1, 2); | add_native_method("at", Method::CT_DYNAMIC, _at, 1, 2); |
| #endif | #endif |