Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
Pointer.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include "Stroika/Foundation/Characters/String2Int.h"
7#include "Stroika/Foundation/DataExchange/BadFormatException.h"
8
9#include "Pointer.h"
10
11using namespace std;
12
13using namespace Stroika::Foundation;
17
19
20/*
21 ********************************************************************************
22 ************************ JSON::PointerType::MapElt *****************************
23 ********************************************************************************
24 */
25String JSON::PointerType::Context::MapElt::ToString () const
26{
28 sb << "{"sv;
29 sb << "orig: " << fOrigValue;
30 sb << ", eltName: " << fEltName;
31 sb << "}"sv;
32 return sb;
33}
34
35/*
36 ********************************************************************************
37 *********************** JSON::PointerType::SeqElt ******************************
38 ********************************************************************************
39 */
40String JSON::PointerType::Context::SeqElt::ToString () const
41{
43 sb << "{"sv;
44 sb << "orig: " << fOrigValue;
45 sb << ", index: " << this->fIndex;
46 sb << "}"sv;
47 return sb;
48}
49
50/*
51 ********************************************************************************
52 *********************** JSON::PointerType::Context *****************************
53 ********************************************************************************
54 */
55namespace {
56 using MapElt = JSON::PointerType::Context::MapElt;
57 using SeqElt = JSON::PointerType::Context::SeqElt;
58 auto PopOneAtAtATPopOneAtAtATime_ (Stack<variant<MapElt, SeqElt>> stack, const optional<VariantValue>& leafToUse) -> optional<VariantValue>
59 {
60 if (stack.empty ()) {
61 return leafToUse;
62 }
63 variant<MapElt, SeqElt> cur = stack.Pop ();
64 if (auto om = get_if<MapElt> (&cur)) {
65 Mapping<String, VariantValue> r = om->fOrigValue;
66 if (leafToUse) {
67 r.Add (om->fEltName, leafToUse);
68 }
69 return PopOneAtAtATPopOneAtAtATime_ (stack, VariantValue{r});
70 }
71 else if (auto os = get_if<SeqElt> (&cur)) {
72 Sequence<VariantValue> r = os->fOrigValue;
73 if (os->fIndex > r.size ()) {
74 static const auto kExcept_ = DataExchange::BadFormatException{"JSON Patch had array reference outside bounds of array"sv};
75 Execution::Throw (kExcept_);
76 }
77 if (leafToUse) {
78 r.SetAt (os->fIndex, *leafToUse);
79 }
80 return PopOneAtAtATPopOneAtAtATime_ (stack, VariantValue{r});
81 }
82 else {
83 AssertNotReached (); // always one kind of context or another
84 return nullopt;
85 }
86 }
87}
88
89optional<VariantValue> JSON::PointerType::Context::ConstructNewFrom (const optional<VariantValue>& leafToUse) const
90{
91 return PopOneAtAtATPopOneAtAtATime_ (fStack, leafToUse);
92}
93
94String JSON::PointerType::Context::ToString () const
95{
97 sb << "{"sv;
98 sb << "stack: " << fStack;
99 sb << "}"sv;
100 return sb;
101}
102
103/*
104 ********************************************************************************
105 ******************************** JSON::PointerType *****************************
106 ********************************************************************************
107 */
109 template <>
110 PointerType::PointerType (const String& s)
111 {
112 optional<Character> prevChar;
113 bool startedSection = false;
114 StringBuilder curSectionSB;
115 // return true if handled, and throw if bad character following
116 auto maybeHandleCharAfterTwiddle = [&] (Character c) -> bool {
117 if (prevChar == '~') {
118 switch (c.GetCharacterCode ()) {
119 case '0':
120 curSectionSB << '~';
121 break;
122 case '1':
123 curSectionSB << '/';
124 break;
125 default:
126 static const auto kExcept_ = DataExchange::BadFormatException{"Expected 0 or 1 after ~ in JSON Pointer"sv};
127 Execution::Throw (kExcept_);
128 break;
129 }
130 prevChar = c;
131 return true;
132 }
133 return false;
134 };
135 s.Apply ([&] (Character c) {
136 if (maybeHandleCharAfterTwiddle (c)) {
137 return;
138 }
139 if (c == '/') {
140 if (startedSection) {
141 fComponents_.Append (curSectionSB);
142 curSectionSB.clear ();
143 }
144 startedSection = true;
145 }
146 else if (startedSection) {
147 if (c != '~') {
148 curSectionSB << c;
149 }
150 }
151 else {
152 static const auto kExcept_ = DataExchange::BadFormatException{"Expected / to start section of JSON Pointer"sv};
153 Execution::Throw (kExcept_);
154 }
155 prevChar = c;
156 });
157 if (prevChar == '/' or not curSectionSB.empty ()) {
158 fComponents_.Append (curSectionSB);
159 }
160 }
161}
162
163auto JSON::PointerType::ApplyWithContext (const VariantValue& v, Context* contextOut) const -> optional<VariantValue>
164{
165 VariantValue curNode = v;
166 for (String component : this->fComponents_) {
167 switch (curNode.GetType ()) {
168 case VariantValue::eArray: {
170 size_t i = component == "-"sv ? sv.size () : Characters::String2Int<size_t> (component);
171 if (i > sv.size ()) {
172 return nullopt;
173 }
174 curNode = i == sv.size () ? VariantValue{} : sv[i];
175 if (contextOut != nullptr) {
176 contextOut->fStack.Push (Context::SeqElt{.fOrigValue = sv, .fIndex = i});
177 }
178 } break;
179 case VariantValue::eMap: {
181 if (auto o = mv.Lookup (component)) {
182 curNode = *o;
183 }
184 else {
185 return nullopt;
186 }
187 if (contextOut != nullptr) {
188 contextOut->fStack.Push (Context::MapElt{.fOrigValue = mv, .fEltName = component});
189 }
190 } break;
191 default: {
192 return nullopt;
193 } break;
194 }
195 }
196 // if we run out of components, return everything that is left
197 return curNode;
198}
199
200String JSON::PointerType::ToString () const
201{
202 return Characters::ToString (fComponents_);
203}
#define AssertNotReached()
Definition Assertions.h:355
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
Definition Mapping.inl:188
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
Definition Mapping.inl:142
A generalization of a vector: a container whose elements are keyed by the natural numbers.
nonvirtual void SetAt(size_t i, ArgByValueType< value_type > item)
Definition Sequence.inl:244
nonvirtual optional< tuple< Context, VariantValue > > ApplyWithContext(const VariantValue &v) const
Definition Pointer.inl:32
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
nonvirtual void Apply(const function< void(ArgByValueType< T > item)> &doToElement, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const
Run the argument function (or lambda) on each element of the container.
nonvirtual size_t size() const
Returns the number of items contained.
Definition Iterable.inl:302
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...
Definition ToString.inl:465
STL namespace.
optional< VariantValue > ConstructNewFrom(const optional< VariantValue > &leafToUse) const
Definition Pointer.cpp:89