VirtualBox

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

Last change on this file since 74402 was 74402, checked in by vboxsync, 6 years ago

IPRT/rest: Implemented array and string-map support for deserializating polymorphic objects. bugref:9167

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette