--- parser3/src/classes/hash.C 2021/12/21 14:24:54 1.154 +++ parser3/src/classes/hash.C 2024/09/23 23:16:41 1.159 @@ -1,8 +1,8 @@ /** @file Parser: @b hash parser class. - Copyright (c) 2001-2020 Art. Lebedev Studio (http://www.artlebedev.com) - Author: Alexandr Petrosian (http://paf.design.ru) + Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com) + Authors: Konstantin Morshnev , Alexandr Petrosian */ #include "classes.h" @@ -17,7 +17,7 @@ #include "pa_vbool.h" #include "pa_vmethod_frame.h" -volatile const char * IDENT_HASH_C="$Id: hash.C,v 1.154 2021/12/21 14:24:54 moko Exp $"; +volatile const char * IDENT_HASH_C="$Id: hash.C,v 1.159 2024/09/23 23:16:41 moko Exp $"; // class @@ -38,20 +38,19 @@ DECLARE_CLASS_VAR(hash, new MHash); #ifndef DOXYGEN class Hash_sql_event_handlers: public SQL_Driver_query_event_handlers { bool distinct; - HashStringValue& rows_hash; + HashStringValue& result; Value* row_value; int column_index; ArrayString& columns; bool one_bool_column; - static VBool only_one_column_value; Table2hash_value_type value_type; int columns_count; public: Table* empty; public: - Hash_sql_event_handlers(bool adistinct, HashStringValue& arows_hash, Table2hash_value_type avalue_type): + Hash_sql_event_handlers(bool adistinct, HashStringValue& aresult, Table2hash_value_type avalue_type): distinct(adistinct), - rows_hash(arows_hash), + result(aresult), row_value(0), column_index(0), columns(*new ArrayString), @@ -105,23 +104,23 @@ public: bool duplicate=false; if(one_bool_column) { - duplicate=rows_hash.put_dont_replace(cell, &only_one_column_value); // put. existed? + duplicate=result.put_dont_replace(cell, &VBool::get(true)); // put. existed? } else if(column_index==0) { switch(value_type){ case C_HASH: { VHash* row_vhash=new VHash; row_value=row_vhash; - duplicate=rows_hash.put_dont_replace(cell, row_vhash); // put. existed? + duplicate=result.put_dont_replace(cell, row_vhash); // put. existed? break; } case C_STRING: { VString* row_vstring=new VString(); row_value=row_vstring; - duplicate=rows_hash.put_dont_replace(cell, row_vstring); // put. existed? + duplicate=result.put_dont_replace(cell, row_vstring); // put. existed? break; } case C_TABLE: { - VTable* vtable=(VTable*)rows_hash.get(cell); + VTable* vtable=(VTable*)result.get(cell); Table* table; if(vtable) { // table with this key exist? @@ -135,7 +134,7 @@ public: Table::Action_options table_options(0, 0); table=new Table(*empty, table_options/*no rows, just structure*/); vtable=new VTable(table); - rows_hash.put(cell, vtable); // put + result.put(cell, vtable); // put } ArrayString* row=new ArrayString(columns_count); row_value=(Value*)row; @@ -177,7 +176,6 @@ public: } }; -VBool Hash_sql_event_handlers::only_one_column_value(true); #endif @@ -188,7 +186,7 @@ static void _create_or_add(Request& r, M HashStringValue* self_hash=&(self.hash()); HashStringValue* src_hash; - if(VHashBase* src=static_cast(vsrc.as(VHASH_TYPE))) { + if(VHashBase* src=dynamic_cast(&vsrc)) { src_hash=&(src->hash()); if(src_hash==self_hash) // same: doing nothing @@ -238,19 +236,46 @@ struct Copy_intersection_to_info { HashStringValue* dest; }; #endif -static void copy_intersection_to(HashStringValue::key_type key, HashStringValue::value_type value, Copy_intersection_to_info *info) { + +static void copy_intersection_by_arg(HashStringValue::key_type key, HashStringValue::value_type, Copy_intersection_to_info *info) { + if(HashStringValue::value_type value=info->b->get(key)) + info->dest->put_dont_replace(key, value); +} + +static void copy_intersection_by_self(HashStringValue::key_type key, HashStringValue::value_type value, Copy_intersection_to_info *info) { if(info->b->get(key)) info->dest->put_dont_replace(key, value); } + static void _intersection(Request& r, MethodParams& params) { Value& result=*new VHash; - // dest += b + + bool order_by_arg=false; + if(params.count()>1) + if(HashStringValue* options=params.as_hash(1, "options")) { + int valid_options=0; + if(Value* vorder=options->get("order")) { + const String &sorder=r.process(*vorder).as_string(); + if(sorder == "arg") + order_by_arg=true; + else if(sorder != "self") + throw Exception(PARSER_RUNTIME, &sorder, "'order' must be 'self' or 'arg'"); + valid_options++; + } + if(valid_options!=options->count()) + throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); + } + if(HashStringValue* b=params.as_hash(0, "param")) { - Copy_intersection_to_info info={b, result.get_hash()}; - GET_SELF(r, VHashBase).hash().for_each(copy_intersection_to, &info); + if(order_by_arg){ + Copy_intersection_to_info info={&GET_SELF(r, VHashBase).hash(), result.get_hash()}; + b->for_each(copy_intersection_by_arg, &info); + } else { + Copy_intersection_to_info info={b, result.get_hash()}; + GET_SELF(r, VHashBase).hash().for_each(copy_intersection_by_self, &info); + } } - // return result r.write(result); } @@ -761,8 +786,8 @@ MHash::MHash(): Methoded("hash") add_native_method("sub", Method::CT_DYNAMIC, _sub, 1, 1); // ^a.union[b] = hash add_native_method("union", Method::CT_DYNAMIC, _union, 1, 1); - // ^a.intersection[b] = hash - add_native_method("intersection", Method::CT_DYNAMIC, _intersection, 1, 1); + // ^a.intersection[b][options hash] = hash + add_native_method("intersection", Method::CT_DYNAMIC, _intersection, 1, 2); // ^a.intersects[b] = bool add_native_method("intersects", Method::CT_DYNAMIC, _intersects, 1, 1);