diff --git a/uppsrc/Core/Value.cpp b/uppsrc/Core/Value.cpp index 840b1a6a1..8afbf6868 100644 --- a/uppsrc/Core/Value.cpp +++ b/uppsrc/Core/Value.cpp @@ -651,7 +651,11 @@ Value& Value::GetAdd(const Value& key) { if(IsNull()) *this = ValueMap(); - ASSERT(IsRef() && ptr()->GetType() == VALUEMAP_V); + if(GetType() == VALUEARRAY_V) { + ValueMap m = *this; + *this = m; + } + ASSERT(GetType() == VALUEMAP_V); return ValueMap::Clone((ValueMap::Data*&)ptr()).GetAdd(key); } diff --git a/uppsrc/Core/Value.h b/uppsrc/Core/Value.h index 52aefc46a..ce9d8e2ad 100644 --- a/uppsrc/Core/Value.h +++ b/uppsrc/Core/Value.h @@ -255,10 +255,10 @@ public: const Value& operator[](const Id& key) const; Value& At(int i); + Value& operator()(int i) { return At(i); } void Add(const Value& src); template Value& operator<<(const T& src) { Add(src); return *this; } - Value& operator()(int i) { return At(i); } Value& GetAdd(const Value& key); Value& operator()(const String& key); diff --git a/uppsrc/Core/ValueUtil.h b/uppsrc/Core/ValueUtil.h index b2bf8b5df..455913080 100644 --- a/uppsrc/Core/ValueUtil.h +++ b/uppsrc/Core/ValueUtil.h @@ -373,12 +373,12 @@ public: const Value& operator[](const Id& key) const { return operator[](Value(key.ToString())); } Value& GetAdd(const Value& key); - Value& At(int i); Value& operator()(const Value& key) { return GetAdd(key); } Value& operator()(const String& key) { return operator()(Value(key)); } Value& operator()(const char *key) { return operator()(Value(key)); } Value& operator()(const int key) { return operator()(Value(key)); } Value& operator()(const Id& key) { return operator()(Value(key.ToString())); } + Value& At(int i); Value GetAndClear(const Value& key); diff --git a/uppsrc/Core/src.tpp/Value$en-us.tpp b/uppsrc/Core/src.tpp/Value$en-us.tpp index 4cc446225..262fb5b3d 100644 --- a/uppsrc/Core/src.tpp/Value$en-us.tpp +++ b/uppsrc/Core/src.tpp/Value$en-us.tpp @@ -161,6 +161,35 @@ through any contained ValueMaps and ValueArrays too, for other Value types it uses the normal operator`=`=.&] [s3; &] [s4;%- &] +[s5;:Value`:`:Compare`(const Value`&`)const:%- [@(0.0.255) int]_[* Compare]([@(0.0.255) con +st]_[_^Value^ Value][@(0.0.255) `&]_[*@3 v])_[@(0.0.255) const]&] +[s2; Compares value with another value [%-*@3 v]. Types of values must +be comparable (e.g. it is possible to compare texts with texts, +numbers with numbers etc...). If types are not comparable, returns +0. If values are equal, returns 0, `-1 if Value is lesser than +[%-*@3 v], 1 if Value if it is greater.&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:operator`<`=`(const Value`&`)const:%- [@(0.0.255) bool]_[* operator<`=]([@(0.0.255) c +onst]_[_^Value^ Value][@(0.0.255) `&]_[*@3 x])_[@(0.0.255) const]&] +[s2;%- [%% Same as Compare(][*@3 x]) <`= 0.&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:operator`>`=`(const Value`&`)const:%- [@(0.0.255) bool]_[* operator>`=]([@(0.0.255) c +onst]_[_^Value^ Value][@(0.0.255) `&]_[*@3 x])_[@(0.0.255) const]&] +[s2;%- [%% Same as Compare(][*@3 x]) >`= 0.&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:operator`<`(const Value`&`)const:%- [@(0.0.255) bool]_[* operator<]([@(0.0.255) c +onst]_[_^Value^ Value][@(0.0.255) `&]_[*@3 x])_[@(0.0.255) const]&] +[s2;%- [%% Same as Compare(][*@3 x]) < 0.&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:operator`>`(const Value`&`)const:%- [@(0.0.255) bool]_[* operator>]([@(0.0.255) c +onst]_[_^Value^ Value][@(0.0.255) `&]_[*@3 x])_[@(0.0.255) const]&] +[s2;%- [%% Same as Compare(][*@3 x]) > 0.&] +[s3; &] +[s4;%- &] [s5;:Value`:`:ToString`(`)const:%- [_^String^ String]_[* ToString]()_[@(0.0.255) const]&] [s2; Conversion to text for supporting rich types.&] [s3;%- &] @@ -213,6 +242,64 @@ onst]&] [%-*@3 key], returns its value. If not, returns void Value.&] [s3;%- &] [s4;%- &] +[s5;:Value`:`:At`(int`):%- [_^Value^ Value][@(0.0.255) `&]_[* At]([@(0.0.255) int]_[*@3 i])&] +[s2; If Value is Null, sets it to ValueArray. If Value is ValueArray +or was Null, returns a reference of element at [%-*@3 i] , if there +is none, adds as much Void Values to array as necessarry to have +it. If Value is ValueMap, returns a reference to map value at +[%-*@3 i] , if there is none, behaviour is undefined (ASSERT in +debug mode fails). [^topic`:`/`/Core`/srcdoc`/ValueReference`$en`-us^ The +reference returned is invalidated by any further use of originating +Value]. If Value is neither ValueArray, Null or ValueMap, behaviour +is undefined (ASSERT in debug mode fails).&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:operator`(`)`(int`):%- [_^Value^ Value][@(0.0.255) `&]_[* operator()]([@(0.0.255) i +nt]_[*@3 i])&] +[s2; Same as At([%-*@3 i]).&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:Add`(const Value`&`):%- [@(0.0.255) void]_[* Add]([@(0.0.255) const]_[_^Value^ V +alue][@(0.0.255) `&]_[*@3 src])&] +[s2; If Value is Null, sets it to ValueArray. If Value is ValueArray +or was Null, appends [%-*@3 src] at the end of ArrayValue. If Value +is neither ValueArray or Null, behaviour is undefined (ASSERT +in debug mode fails).&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:operator`<`<`(const T`&`):%- [@(0.0.255) template]_<[@(0.0.255) typename]_[*@4 T +]>_[_^Value^ Value][@(0.0.255) `&]_[* operator<<]([@(0.0.255) const]_[*@4 T][@(0.0.255) `&]_[*@3 s +rc])&] +[s2; Same as Add([%-*@3 src]).&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:GetAdd`(const Value`&`):%- [_^Value^ Value][@(0.0.255) `&]_[* GetAdd]([@(0.0.255) c +onst]_[_^Value^ Value][@(0.0.255) `&]_[*@3 key])&] +[s2; If Value is Null, sets it to ValueMap. If Value is ValueArray, +sets it to standard conversion of ValueMap to ValueArray (indicies +become keys). If Value is ValueMap or was Null, returns a reference +of element at key [%-*@3 key], if there is none, it is created +as Void Value. [^topic`:`/`/Core`/srcdoc`/ValueReference`$en`-us^ The +reference returned is invalidated by any further use of originating +Value]. If Value is neither ValueArray, Null or ValueMap, behaviour +is undefined (ASSERT in debug mode fails).&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:operator`(`)`(const String`&`):%- [_^Value^ Value][@(0.0.255) `&]_[* operator +()]([@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_[*@3 key])&] +[s2; Same as GetAdd([%-*@3 key]).&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:operator`(`)`(const char`*`):%- [_^Value^ Value][@(0.0.255) `&]_[* operator() +]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 key])&] +[s2; Save as GetAdd([%-*@3 key]).&] +[s3; &] +[s4;%- &] +[s5;:Value`:`:operator`(`)`(const Id`&`):%- [_^Value^ Value][@(0.0.255) `&]_[* operator()]( +[@(0.0.255) const]_[_^Id^ Id][@(0.0.255) `&]_[*@3 key])&] +[s2; Save as GetAdd([%-*@3 key]).&] +[s3; &] +[s4;%- &] [s5;:Value`:`:operator`=`(const Value`&`):%- [_^Value^ Value][@(0.0.255) `&]_[* operator`=]( [@(0.0.255) const]_[_^Value^ Value][@(0.0.255) `&]_[*@3 v])&] [s2; Assignment.&] @@ -222,7 +309,6 @@ onst]&] [*@3 v])&] [s2; Copy constructor.&] [s3; &] -[s3; &] [s4;%- &] [s5;:Value`:`:Value`(`):%- [* Value]()&] [s2; Default constructor, creates void Value.&] @@ -290,6 +376,17 @@ onst]_[*@4 T][@(0.0.255) `&])_[@(0.0.255) const]&] [s2; Conversion to text. ValueType returns empty String.&] [s3;%- &] [s4;%- &] +[s5;:ValueType`:`:Compare`(const T`&`)const:%- [@(0.0.255) int]_[* Compare]([@(0.0.255) con +st]_[*@4 T][@(0.0.255) `&])_[@(0.0.255) const]&] +[s2; Comparison with another value of the same type. Returns should +return `-1, 0, 1.&] +[s3;%- &] +[s4;%- &] +[s5;:ValueType`:`:PolyCompare`(const Value`&`)const:%- [@(0.0.255) int]_[* PolyCompare]([@(0.0.255) c +onst]_[_^Value^ Value][@(0.0.255) `&])_[@(0.0.255) const]&] +[s2; Polymorphic comparison with different type.&] +[s3;%- &] +[s4;%- &] [s5;:ValueType`:`:operator Ref`(`):%- [* operator_Ref]()&] [s2; Returns a Ref (generic reference) to the instance of T.&] [s0;%- &] diff --git a/uppsrc/Core/src.tpp/ValueArray$en-us.tpp b/uppsrc/Core/src.tpp/ValueArray$en-us.tpp index 54ef5426e..bf37cf66f 100644 --- a/uppsrc/Core/src.tpp/ValueArray$en-us.tpp +++ b/uppsrc/Core/src.tpp/ValueArray$en-us.tpp @@ -172,6 +172,13 @@ onst]_[_^ValueArray^ ValueArray][@(0.0.255) `&]_[*@3 va])&] [s2;%% Returns element at [%-*@3 i].&] [s3;%% &] [s4; &] +[s5;:ValueArray`:`:At`(int`): [_^Value^ Value][@(0.0.255) `&]_[* At]([@(0.0.255) int]_[*@3 i])&] +[s2;%% Returns a reference of element at [%-*@3 i] , if there is none, +adds as much Void Values to array as necessarry to have it. [^topic`:`/`/Core`/srcdoc`/ValueReference`$en`-us^ T +he reference returned is invalidated by any further use of originating +Value]. &] +[s3;%% &] +[s4; &] [s5;:ValueArray`:`:GetHashValue`(`)const: [@(0.0.255) unsigned]_[* GetHashValue]()_[@(0.0.255) c onst]&] [s2;%% Returns hashing value.&] diff --git a/uppsrc/Core/src.tpp/ValueMap$en-us.tpp b/uppsrc/Core/src.tpp/ValueMap$en-us.tpp index 620997381..0c47cc4c1 100644 --- a/uppsrc/Core/src.tpp/ValueMap$en-us.tpp +++ b/uppsrc/Core/src.tpp/ValueMap$en-us.tpp @@ -258,6 +258,33 @@ multiple overloads are required to make Id and SqlId work with ValueMap.&] [s3; &] [s4;%- &] +[s5;:ValueMap`:`:GetAdd`(const Value`&`):%- [_^Value^ Value][@(0.0.255) `&]_[* GetAdd]([@(0.0.255) c +onst]_[_^Value^ Value][@(0.0.255) `&]_[*@3 key])&] +[s2; Returns a reference of element at key [%-*@3 key], if there is +none, it is created as Void Value. [^topic`:`/`/Core`/srcdoc`/ValueReference`$en`-us^ T +he reference returned is invalidated by any further use of originating +Value].&] +[s3; &] +[s4;%- &] +[s5;:ValueMap`:`:operator`(`)`(const Value`&`):%- [_^Value^ Value][@(0.0.255) `&]_[* operat +or()]([@(0.0.255) const]_[_^Value^ Value][@(0.0.255) `&]_[*@3 key])&] +[s5;:ValueMap`:`:operator`(`)`(const String`&`):%- [_^Value^ Value][@(0.0.255) `&]_[* opera +tor()]([@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_[*@3 key])&] +[s5;:ValueMap`:`:operator`(`)`(const char`*`):%- [_^Value^ Value][@(0.0.255) `&]_[* operato +r()]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 key])&] +[s5;:ValueMap`:`:operator`(`)`(const int`):%- [_^Value^ Value][@(0.0.255) `&]_[* operator() +]([@(0.0.255) const]_[@(0.0.255) int]_[*@3 key])&] +[s5;:ValueMap`:`:operator`(`)`(const Id`&`):%- [_^Value^ Value][@(0.0.255) `&]_[* operator( +)]([@(0.0.255) const]_[_^Id^ Id][@(0.0.255) `&]_[*@3 key])&] +[s2; Same as GetAdd([%-*@3 key]).&] +[s3; &] +[s4;%- &] +[s5;:ValueMap`:`:At`(int`):%- [_^Value^ Value][@(0.0.255) `&]_[* At]([@(0.0.255) int]_[*@3 i])&] +[s2; Returns a reference of value at index [%-*@3 i]. [^topic`:`/`/Core`/srcdoc`/ValueReference`$en`-us^ T +he reference returned is invalidated by any further use of originating +Value].&] +[s3; &] +[s4;%- &] [s5;:ValueMap`:`:GetAndClear`(const Value`&`):%- [_^Value^ Value]_[* GetAndClear]([@(0.0.255) c onst]_[_^Value^ Value][@(0.0.255) `&]_[*@3 key])&] [s2; If [%-*@3 key] is not present, returns ErrorValue (which is Void diff --git a/uppsrc/Core/srcdoc.tpp/ValueReference$en-us.tpp b/uppsrc/Core/srcdoc.tpp/ValueReference$en-us.tpp new file mode 100644 index 000000000..e3b7d3d1d --- /dev/null +++ b/uppsrc/Core/srcdoc.tpp/ValueReference$en-us.tpp @@ -0,0 +1,45 @@ +topic "Rules for references to Value internal maps elements"; +[2 $$0,0#00000000000000000000000000000000:Default] +[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class] +[l288;2 $$2,2#27521748481378242620020725143825:desc] +[0 $$3,0#96390100711032703541132217272105:end] +[H6;0 $$4,0#05600065144404261032431302351956:begin] +[i448;a25;kKO9;2 $$5,0#37138531426314131252341829483370:item] +[l288;a4;*@5;1 $$6,6#70004532496200323422659154056402:requirement] +[l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param] +[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam] +[b42;2 $$9,9#13035079074754324216151401829390:normal] +[a83;*R6 $$10,12#31310162474203024125188417583966:caption] +[b83;*2 $$11,12#07864147445237544204411237157677:title] +[b42;a42;2 $$12,12#45413000475342174754091244180557:text] +[{_}%EN-US +[s10; Rules for references to Value internal maps elements&] +[s0; Value is originally designed as nonmutable concrete Value of +different concrete types.&] +[s0; &] +[s0; However, as Value is commonly used to store complex hierarchies +(using ValueArray/ValueMap types), it is in the end very useful +to be able to reference ValueArray/ValueMap elements directly. +Validity of such references is restricted by following rule:&] +[s0; &] +[s0; Reference obtained from Value (by Value`::At, Value`::GetAdd, +ValueArray`::At, ValueMap`::GetAdd and derivative methods) are +[* only valid until the next operation on originating Value `- +including just reading it.]&] +[s0; &] +[s0; Examples of invalid code:&] +[s0; &] +[s0; [*C@5 Value m;]&] +[s0; [*C@5 Value`& x `= m(`"key`");]&] +[s0; [*C@5 x `= m; // using m as source invalidates x]&] +[s0;*C@5 &] +[s0; [*C@5 Value m;]&] +[s0; [*C@5 Value`& x `= m(`"key`");]&] +[s0; [*C@5 Value`& y `= m(`"key2`"); // Invalidates x]&] +[s0; [*C@5 x `= 123; // undefined]&] +[s0;*C@5 &] +[s0; [*C@5 Value m;]&] +[s0; [*C@5 Value`& x `= m.At(1);]&] +[s0; [*C@5 Value m2 `= m; // Invalidates x]&] +[s0; [*C@5 x `= `"fail`"; // undefined]&] +[s0; ]] \ No newline at end of file