VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/rest/RTCRestStringMapBase.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.1 KB
Line 
1/* $Id: RTCRestStringMapBase.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - C++ REST, RTCRestStringMapBase implementation.
4 */
5
6/*
7 * Copyright (C) 2018-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_REST
42#include <iprt/cpp/reststringmap.h>
43
44#include <iprt/err.h>
45#include <iprt/string.h>
46#include <iprt/cpp/restoutput.h>
47
48
49/**
50 * Default destructor.
51 */
52RTCRestStringMapBase::RTCRestStringMapBase() RT_NOEXCEPT
53 : RTCRestObjectBase()
54 , m_Map(NULL)
55 , m_cEntries(0)
56{
57 RTListInit(&m_ListHead);
58}
59
60
61#if 0 /* trigger link error for now. */
62/** Copy constructor. */
63RTCRestStringMapBase::RTCRestStringMapBase(RTCRestStringMapBase const &a_rThat);
64#endif
65
66
67/**
68 * Destructor.
69 */
70RTCRestStringMapBase::~RTCRestStringMapBase()
71{
72 clear();
73}
74
75
76
77#if 0 /* trigger link error for now. */
78/** Copy assignment operator. */
79RTCRestStringMapBase &RTCRestStringMapBase::operator=(RTCRestStringMapBase const &a_rThat);
80#endif
81
82
83/*********************************************************************************************************************************
84* Overridden base object methods *
85*********************************************************************************************************************************/
86
87RTCRestObjectBase *RTCRestStringMapBase::baseClone() const RT_NOEXCEPT
88{
89 RTCRestStringMapBase *pClone = createClone();
90 if (pClone)
91 {
92 int rc = pClone->copyMapWorkerNoThrow(*this);
93 if (RT_SUCCESS(rc))
94 return pClone;
95 delete pClone;
96 }
97 return NULL;
98}
99
100
101int RTCRestStringMapBase::resetToDefault() RT_NOEXCEPT
102{
103 /* Default is an empty map. */
104 clear();
105 m_fNullIndicator = false;
106 return VINF_SUCCESS;
107}
108
109
110RTCRestOutputBase &RTCRestStringMapBase::serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT
111{
112 if (!m_fNullIndicator)
113 {
114 uint32_t const uOldState = a_rDst.beginObject();
115 MapEntry const *pCur;
116 RTListForEachCpp(&m_ListHead, pCur, MapEntry, ListEntry)
117 {
118 a_rDst.valueSeparatorAndName(pCur->strKey.c_str(), pCur->strKey.length());
119 pCur->pValue->serializeAsJson(a_rDst);
120 }
121 a_rDst.endObject(uOldState);
122 }
123 else
124 a_rDst.nullValue();
125 return a_rDst;
126}
127
128
129int RTCRestStringMapBase::deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT
130{
131 if (RTJsonValueGetType(a_rCursor.m_hValue) == RTJSONVALTYPE_NULL)
132 {
133 setNull();
134 return VINF_SUCCESS;
135 }
136
137 /*
138 * Make sure the object starts out with an empty map.
139 */
140 if (m_cEntries > 0)
141 clear();
142 m_fNullIndicator = false;
143
144 /*
145 * Iterate the object values.
146 */
147 RTJSONIT hIterator;
148 int rcRet = RTJsonIteratorBeginObject(a_rCursor.m_hValue, &hIterator);
149 if (RT_SUCCESS(rcRet))
150 {
151 for (;;)
152 {
153 /* Set up the sub-cursor. */
154 RTCRestJsonCursor SubCursor(a_rCursor);
155 int rc = RTJsonIteratorQueryValue(hIterator, &SubCursor.m_hValue, &SubCursor.m_pszName);
156 if (RT_SUCCESS(rc))
157 {
158 /* Call the static deserializeInstanceFromJson method of the value class. */
159 RTCRestObjectBase *pObj = NULL;
160 rc = deserializeValueInstanceFromJson(SubCursor, &pObj);
161 if (RT_SUCCESS(rc))
162 Assert(pObj);
163 else if (RT_SUCCESS(rcRet))
164 rcRet = rc;
165 if (pObj)
166 {
167 /* Insert the value. */
168 rc = putWorker(SubCursor.m_pszName, pObj, true /*a_fReplace*/);
169 if (rc == VINF_SUCCESS)
170 { /* likely */ }
171 else if (RT_SUCCESS(rc))
172 {
173 a_rCursor.m_pPrimary->addError(a_rCursor, rc, "warning %Rrc inserting '%s' into map",
174 rc, SubCursor.m_pszName);
175 if (rcRet == VINF_SUCCESS)
176 rcRet = rc;
177 }
178 else
179 {
180 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Failed to insert '%s' into map: %Rrc",
181 SubCursor.m_pszName, rc);
182 delete pObj;
183 }
184 }
185 }
186 else
187 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorQueryValue failed: %Rrc", rc);
188
189 /*
190 * Advance.
191 */
192 rc = RTJsonIteratorNext(hIterator);
193 if (RT_SUCCESS(rc))
194 { /* likely */ }
195 else if (rc == VERR_JSON_ITERATOR_END)
196 break;
197 else
198 {
199 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorNext failed: %Rrc", rc);
200 break;
201 }
202 }
203
204 RTJsonIteratorFree(hIterator);
205 }
206 else if (rcRet == VERR_JSON_IS_EMPTY)
207 rcRet = VINF_SUCCESS;
208 else if ( rcRet == VERR_JSON_VALUE_INVALID_TYPE
209 && RTJsonValueGetType(a_rCursor.m_hValue) == RTJSONVALTYPE_NULL)
210 {
211 m_fNullIndicator = true;
212 rcRet = VINF_SUCCESS;
213 }
214 else
215 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rcRet, "RTJsonIteratorBegin failed: %Rrc (type %s)",
216 rcRet, RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue)));
217 return rcRet;
218}
219
220// later?
221// virtual int RTCRestStringMapBase::toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const ;
222// virtual int RTCRestStringMapBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL,
223// uint32_t a_fFlags = kCollectionFormat_Unspecified) ;
224//
225
226
227RTCRestObjectBase::kTypeClass RTCRestStringMapBase::typeClass(void) const RT_NOEXCEPT
228{
229 return kTypeClass_StringMap;
230}
231
232
233const char *RTCRestStringMapBase::typeName(void) const RT_NOEXCEPT
234{
235 return "RTCRestStringMap<ValueType>";
236}
237
238
239/*********************************************************************************************************************************
240* Generic map methods *
241*********************************************************************************************************************************/
242
243/**
244 * @callback_method_impl{FNRTSTRSPACECALLBACK}
245 */
246/*static*/ DECLCALLBACK(int) RTCRestStringMapBase::stringSpaceDestructorCallback(PRTSTRSPACECORE pStr, void *pvUser) RT_NOEXCEPT
247{
248 MapEntry *pNode = (MapEntry *)pStr;
249 if (pNode->pValue)
250 {
251 delete pNode->pValue;
252 pNode->pValue = NULL;
253 }
254 pNode->strKey.setNull();
255 delete pNode;
256
257 RT_NOREF(pvUser);
258 return VINF_SUCCESS;
259}
260
261
262void RTCRestStringMapBase::clear() RT_NOEXCEPT
263{
264 RTStrSpaceDestroy(&m_Map, stringSpaceDestructorCallback, NULL);
265 RTListInit(&m_ListHead);
266 m_cEntries = 0;
267 m_fNullIndicator = false;
268}
269
270
271size_t RTCRestStringMapBase::size() const RT_NOEXCEPT
272{
273 return m_cEntries;
274}
275
276
277bool RTCRestStringMapBase::containsKey(const char *a_pszKey) const RT_NOEXCEPT
278{
279 if (isNull())
280 return false;
281
282 return RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey) != NULL;
283}
284
285
286bool RTCRestStringMapBase::containsKey(RTCString const &a_rStrKey) const RT_NOEXCEPT
287{
288 return containsKey(a_rStrKey.c_str());
289}
290
291
292bool RTCRestStringMapBase::remove(const char *a_pszKey) RT_NOEXCEPT
293{
294 if (isNull())
295 return false;
296
297 MapEntry *pRemoved = (MapEntry *)RTStrSpaceRemove(&m_Map, a_pszKey);
298 if (pRemoved)
299 {
300 m_cEntries--;
301 RTListNodeRemove(&pRemoved->ListEntry);
302 stringSpaceDestructorCallback(&pRemoved->Core, NULL);
303 return true;
304 }
305 return false;
306}
307
308
309bool RTCRestStringMapBase::remove(RTCString const &a_rStrKey) RT_NOEXCEPT
310{
311 return remove(a_rStrKey.c_str());
312}
313
314
315int RTCRestStringMapBase::putNewValue(RTCRestObjectBase **a_ppValue, const char *a_pszKey, size_t a_cchKey /*= RTSTR_MAX*/,
316 bool a_fReplace /*= false*/) RT_NOEXCEPT
317{
318 RTCRestObjectBase *pValue = createValue();
319 if (pValue)
320 {
321 int rc = putWorker(a_pszKey, pValue, a_fReplace, a_cchKey);
322 if (RT_SUCCESS(rc))
323 *a_ppValue = pValue;
324 else
325 {
326 delete pValue;
327 *a_ppValue = NULL;
328 }
329 return rc;
330 }
331 *a_ppValue = NULL;
332 return VERR_NO_MEMORY;
333}
334
335
336int RTCRestStringMapBase::putNewValue(RTCRestObjectBase **a_ppValue, RTCString const &a_rStrKey, bool a_fReplace /*= false*/) RT_NOEXCEPT
337{
338 return putNewValue(a_ppValue, a_rStrKey.c_str(), a_rStrKey.length(), a_fReplace);
339}
340
341
342/*********************************************************************************************************************************
343* Protected methods *
344*********************************************************************************************************************************/
345
346int RTCRestStringMapBase::copyMapWorkerNoThrow(RTCRestStringMapBase const &a_rThat) RT_NOEXCEPT
347{
348 Assert(this != &a_rThat);
349 clear();
350 m_fNullIndicator = a_rThat.m_fNullIndicator;
351
352 if (!a_rThat.m_fNullIndicator)
353 {
354 MapEntry const *pCur;
355 RTListForEachCpp(&a_rThat.m_ListHead, pCur, MapEntry, ListEntry)
356 {
357 int rc = putCopyWorker(pCur->strKey.c_str(), *pCur->pValue, true /*a_fReplace*/);
358 if (RT_SUCCESS(rc))
359 { /* likely */ }
360 else
361 return rc;
362 }
363 }
364
365 return VINF_SUCCESS;
366}
367
368
369void RTCRestStringMapBase::copyMapWorkerMayThrow(RTCRestStringMapBase const &a_rThat)
370{
371 int rc = copyMapWorkerNoThrow(a_rThat);
372 if (RT_SUCCESS(rc))
373 return;
374 throw std::bad_alloc();
375}
376
377
378int RTCRestStringMapBase::putWorker(const char *a_pszKey, RTCRestObjectBase *a_pValue, bool a_fReplace,
379 size_t a_cchKey /*= RTSTR_MAX*/) RT_NOEXCEPT
380{
381 int rc;
382 MapEntry *pEntry = new (std::nothrow) MapEntry;
383 if (pEntry)
384 {
385 rc = pEntry->strKey.assignNoThrow(a_pszKey, a_cchKey);
386 if (RT_SUCCESS(rc))
387 {
388 pEntry->Core.pszString = pEntry->strKey.c_str();
389 pEntry->Core.cchString = pEntry->strKey.length();
390 pEntry->pValue = a_pValue;
391 if (RTStrSpaceInsert(&m_Map, &pEntry->Core))
392 {
393 RTListAppend(&m_ListHead, &pEntry->ListEntry);
394 m_cEntries++;
395 m_fNullIndicator = false;
396 return VINF_SUCCESS;
397 }
398
399 Assert(!m_fNullIndicator);
400 if (!a_fReplace)
401 rc = VERR_ALREADY_EXISTS;
402 else
403 {
404 /* Just replace the pValue in the existing entry. */
405 MapEntry *pCollision = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
406 if (pCollision)
407 {
408 if (pCollision->pValue)
409 delete pCollision->pValue;
410 pCollision->pValue = a_pValue;
411 pEntry->pValue = NULL; /* paranoia */
412 rc = VWRN_ALREADY_EXISTS;
413 }
414 else
415 rc = VERR_INTERNAL_ERROR;
416 }
417 }
418 delete pEntry;
419 }
420 else
421 rc = VERR_NO_MEMORY;
422 return rc;
423}
424
425
426int RTCRestStringMapBase::putCopyWorker(const char *a_pszKey, RTCRestObjectBase const &a_rValue, bool a_fReplace,
427 size_t a_cchKey /*= RTSTR_MAX*/) RT_NOEXCEPT
428{
429 int rc;
430 RTCRestObjectBase *pValueCopy = a_rValue.baseClone();
431 if (pValueCopy)
432 {
433 rc = putWorker(a_pszKey, pValueCopy, a_fReplace, a_cchKey);
434 if (RT_SUCCESS(rc))
435 { /* likely */ }
436 else
437 delete pValueCopy;
438 }
439 else
440 rc = VERR_NO_MEMORY;
441 return rc;
442}
443
444
445RTCRestObjectBase *RTCRestStringMapBase::getWorker(const char *a_pszKey) RT_NOEXCEPT
446{
447 if (isNull())
448 return NULL;
449
450 MapEntry *pHit = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
451 if (pHit)
452 return pHit->pValue;
453 return NULL;
454}
455
456
457RTCRestObjectBase const *RTCRestStringMapBase::getWorker(const char *a_pszKey) const RT_NOEXCEPT
458{
459 if (isNull())
460 return NULL;
461
462 MapEntry const *pHit = (MapEntry const *)RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey);
463 if (pHit)
464 return pHit->pValue;
465 return NULL;
466}
467
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use