--- parser3/src/classes/hash.C 2020/12/29 13:56:18 1.147 +++ parser3/src/classes/hash.C 2024/09/13 04:01:22 1.158 @@ -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.147 2020/12/29 13:56:18 moko Exp $"; +volatile const char * IDENT_HASH_C="$Id: hash.C,v 1.158 2024/09/13 04:01:22 moko Exp $"; // class @@ -188,7 +188,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 +238,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); } @@ -622,6 +649,7 @@ static void _at(Request& r, MethodParams extern String table_reverse_name; static void _select(Request& r, MethodParams& params) { + InCycle temp(r); 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"); Value& vcondition=params.as_expression(2, "condition must be number, bool or expression"); @@ -634,6 +662,7 @@ static void _select(Request& r, MethodPa int limit=source_hash.count(); bool reverse=false; + bool copy_default=false; if(params.count()>3) if(HashStringValue* options=params.as_hash(3)) { @@ -646,6 +675,10 @@ static void _select(Request& r, MethodPa valid_options++; reverse=r.process(*vreverse).as_bool(); } + if(Value* vcopy_default=options->get(sql_default_name)) { + valid_options++; + copy_default=r.process(*vcopy_default).as_bool(); + } if(valid_options!=options->count()) throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); } @@ -653,6 +686,7 @@ static void _select(Request& r, MethodPa HashStringValue& result_hash=*new HashStringValue(); if(limit>0){ + #ifdef HASH_ORDER if(reverse){ for(HashStringValue::ReverseIterator i(source_hash); i; i.prev()){ @@ -661,7 +695,12 @@ static void _select(Request& r, MethodPa if(value_var_name) r.put_element(caller, *value_var_name, i.value()); - if(r.process(vcondition).as_bool()){ + bool condition=r.process(vcondition).as_bool(); + + if(r.check_skip_break()) + break; + + if(condition){ result_hash.put(i.key(), i.value()); if(!--limit) break; @@ -677,7 +716,12 @@ static void _select(Request& r, MethodPa if(value_var_name) r.put_element(caller, *value_var_name, i.value()); - if(r.process(vcondition).as_bool()){ + bool condition=r.process(vcondition).as_bool(); + + if(r.check_skip_break()) + break; + + if(condition){ result_hash.put(i.key(), i.value()); if(!--limit) break; @@ -686,11 +730,17 @@ static void _select(Request& r, MethodPa } } - r.write(*new VHash(result_hash)); + VHash *result=new VHash(result_hash); + if(copy_default){ + result->set_default(GET_SELF(r, VHashBase).get_default()); + } + + r.write(*result); } static void _reverse(Request& r, MethodParams& params) { - HashStringValue& source_hash=GET_SELF(r, VHashBase).hash(); + VHashBase& self=GET_SELF(r, VHashBase); + HashStringValue& source_hash=self.hash(); HashStringValue& result_hash=*new HashStringValue(); #ifdef HASH_ORDER @@ -700,9 +750,32 @@ static void _reverse(Request& r, MethodP for(HashStringValue::Iterator i(source_hash); i; i.next() ) result_hash.put(i.key(), i.value()); #endif - r.write(*new VHash(result_hash)); + + VHashBase& result=*new VHash(result_hash); + if(Value* vdefault=self.get_default()) + result.set_default(vdefault); + + r.write(result); } + +static void _rename(Request& r, MethodParams& params) { + HashStringValue& hash=GET_SELF(r, VHashBase).hash(); + + if(params.count()>1){ + const String& key_from=params.as_string(0, "from key must be string"); + const String& key_to=params.as_string(1, "to key must be string"); + + hash.rename(key_from, key_to); + } else { + HashStringValue* names=params.as_hash(0,"single parameter"); + + for(HashStringValue::Iterator i(*names); i; i.next()) + hash.rename(i.key(), i.value()->as_string()); + } +} + + // constructor MHash::MHash(): Methoded("hash") @@ -715,8 +788,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); @@ -754,6 +827,10 @@ MHash::MHash(): Methoded("hash") // ^hash._at([-+]offset)[['key'|'value'|'hash']] add_native_method("_at", Method::CT_DYNAMIC, _at, 1, 2); + // ^hash.rename[from;to] + // ^hash.rename[ $.from[to] ... ] + add_native_method("rename", Method::CT_DYNAMIC, _rename, 1, 2); + #ifdef FEATURE_GET_ELEMENT4CALL // aliases without "_" add_native_method("keys", Method::CT_DYNAMIC, _keys, 0, 1);