VirtualBox

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

Last change on this file since 74161 was 74025, checked in by vboxsync, 7 years ago

IPRT/rest: split up restbase.h into several files to make it more managable. bugref:9167

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: RTCRestStringMapBase.cpp 74025 2018-09-02 14:14:43Z 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
76int RTCRestStringMapBase::resetToDefault()
77{
78 /* Default is an empty map. */
79 clear();
80 m_fNullIndicator = false;
81 return VINF_SUCCESS;
82}
83
84
85RTCRestOutputBase &RTCRestStringMapBase::serializeAsJson(RTCRestOutputBase &a_rDst) const
86{
87 if (!m_fNullIndicator)
88 {
89 a_rDst.printf("{\n");
90 unsigned const uOldIndent = a_rDst.incrementIndent();
91
92 MapEntry const * const pLast = RTListGetLastCpp(&m_ListHead, MapEntry, ListEntry);
93 MapEntry const * pCur;
94 RTListForEachCpp(&m_ListHead, pCur, MapEntry, ListEntry)
95 {
96 a_rDst.printf("%RJs: ", pCur->strKey.c_str());
97 pCur->pValue->serializeAsJson(a_rDst);
98
99 if (pCur != pLast)
100 a_rDst.printf(",\n");
101 else
102 a_rDst.printf("\n");
103 }
104
105 a_rDst.setIndent(uOldIndent);
106 a_rDst.printf("}");
107 }
108 else
109 a_rDst.printf("null");
110 return a_rDst;
111}
112
113
114int RTCRestStringMapBase::deserializeFromJson(RTCRestJsonCursor const &a_rCursor)
115{
116 /*
117 * Make sure the object starts out with an empty map.
118 */
119 if (m_cEntries > 0)
120 clear();
121 m_fNullIndicator = false;
122
123 /*
124 * Iterate the object values.
125 */
126 RTJSONIT hIterator;
127 int rcRet = RTJsonIteratorBeginObject(a_rCursor.m_hValue, &hIterator);
128 if (RT_SUCCESS(rcRet))
129 {
130 for (;;)
131 {
132 RTCRestJsonCursor SubCursor(a_rCursor);
133 int rc = RTJsonIteratorQueryValue(hIterator, &SubCursor.m_hValue, &SubCursor.m_pszName);
134 if (RT_SUCCESS(rc))
135 {
136 RTCRestObjectBase *pObj = createValue();
137 if (pObj)
138 {
139 rc = pObj->deserializeFromJson(SubCursor);
140 if (RT_SUCCESS(rc))
141 { /* likely */ }
142 else if (RT_SUCCESS(rcRet))
143 rcRet = rc;
144
145 rc = putWorker(SubCursor.m_pszName, pObj, true /*a_fReplace*/);
146 if (rc == VINF_SUCCESS)
147 { /* likely */ }
148 else if (RT_SUCCESS(rc))
149 {
150 a_rCursor.m_pPrimary->addError(a_rCursor, rc, "warning %Rrc inserting '%s' into map",
151 rc, SubCursor.m_pszName);
152 if (rcRet == VINF_SUCCESS)
153 rcRet = rc;
154 }
155 else
156 {
157 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Failed to insert '%s' into map: %Rrc",
158 SubCursor.m_pszName, rc);
159 delete pObj;
160 }
161 }
162 else
163 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Failed to create new value object");
164 }
165 else
166 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorQueryValue failed: %Rrc", rc);
167
168 /*
169 * Advance.
170 */
171 rc = RTJsonIteratorNext(hIterator);
172 if (RT_SUCCESS(rc))
173 { /* likely */ }
174 else if (rc == VERR_JSON_ITERATOR_END)
175 break;
176 else
177 {
178 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorNext failed: %Rrc", rc);
179 break;
180 }
181 }
182
183 RTJsonIteratorFree(hIterator);
184 }
185 else if (rcRet == VERR_JSON_IS_EMPTY)
186 rcRet = VINF_SUCCESS;
187 else if ( rcRet == VERR_JSON_VALUE_INVALID_TYPE
188 && RTJsonValueGetType(a_rCursor.m_hValue) == RTJSONVALTYPE_NULL)
189 {
190 m_fNullIndicator = true;
191 rcRet = VINF_SUCCESS;
192 }
193 else
194 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rcRet, "RTJsonIteratorBegin failed: %Rrc (type %s)",
195 rcRet, RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue)));
196 return rcRet;
197}
198
199// later?
200// virtual int RTCRestStringMapBase::toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const ;
201// virtual int RTCRestStringMapBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL,
202// uint32_t a_fFlags = kCollectionFormat_Unspecified) ;
203//
204
205
206RTCRestObjectBase::kTypeClass RTCRestStringMapBase::typeClass(void) const
207{
208 return kTypeClass_StringMap;
209}
210
211
212const char *RTCRestStringMapBase::typeName(void) const
213{
214 return "RTCRestStringMap<ValueType>";
215}
216
217
218/*********************************************************************************************************************************
219* Generic map methods *
220*********************************************************************************************************************************/
221
222/**
223 * @callback_method_impl{FNRTSTRSPACECALLBACK}
224 */
225/*static*/ DECLCALLBACK(int) RTCRestStringMapBase::stringSpaceDestructorCallback(PRTSTRSPACECORE pStr, void *pvUser)
226{
227 MapEntry *pNode = (MapEntry *)pStr;
228 if (pNode->pValue)
229 {
230 delete pNode->pValue;
231 pNode->pValue = NULL;
232 }
233 pNode->strKey.setNull();
234 delete pNode;
235
236 RT_NOREF(pvUser);
237 return VINF_SUCCESS;
238}
239
240
241void RTCRestStringMapBase::clear()
242{
243 RTStrSpaceDestroy(&m_Map, stringSpaceDestructorCallback, NULL);
244 RTListInit(&m_ListHead);
245 m_cEntries = 0;
246 m_fNullIndicator = false;
247}
248
249
250size_t RTCRestStringMapBase::size() const
251{
252 return m_cEntries;
253}
254
255
256bool RTCRestStringMapBase::constainsKey(const char *a_pszKey) const
257{
258 return RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey) != NULL;
259}
260
261
262bool RTCRestStringMapBase::constainsKey(RTCString const &a_rStrKey) const
263{
264 return constainsKey(a_rStrKey.c_str());
265}
266
267
268bool RTCRestStringMapBase::remove(const char *a_pszKey)
269{
270 PRTSTRSPACECORE pRemoved = RTStrSpaceRemove(&m_Map, a_pszKey);
271 if (pRemoved)
272 {
273 stringSpaceDestructorCallback(pRemoved, NULL);
274 return true;
275 }
276 return false;
277}
278
279
280bool RTCRestStringMapBase::remove(RTCString const &a_rStrKey)
281{
282 return remove(a_rStrKey.c_str());
283}
284
285
286int RTCRestStringMapBase::putNewValue(RTCRestObjectBase **a_ppValue, const char *a_pszKey, size_t a_cchKey /*= RTSTR_MAX*/,
287 bool a_fReplace /*= false*/)
288{
289 RTCRestObjectBase *pValue = createValue();
290 if (pValue)
291 {
292 int rc = putWorker(a_pszKey, pValue, a_fReplace, a_cchKey);
293 if (RT_SUCCESS(rc))
294 *a_ppValue = pValue;
295 else
296 {
297 delete pValue;
298 *a_ppValue = NULL;
299 }
300 return rc;
301 }
302 *a_ppValue = NULL;
303 return VERR_NO_MEMORY;
304}
305
306
307int RTCRestStringMapBase::putNewValue(RTCRestObjectBase **a_ppValue, RTCString const &a_rStrKey, bool a_fReplace /*= false*/)
308{
309 return putNewValue(a_ppValue, a_rStrKey.c_str(), a_rStrKey.length(), a_fReplace);
310}
311
312
313/*********************************************************************************************************************************
314* Protected methods *
315*********************************************************************************************************************************/
316
317int RTCRestStringMapBase::copyMapWorker(RTCRestStringMapBase const &a_rThat, bool a_fThrow)
318{
319 Assert(this != &a_rThat);
320 clear();
321 m_fNullIndicator = a_rThat.m_fNullIndicator;
322
323 if (!a_rThat.m_fNullIndicator)
324 {
325 MapEntry const *pCur;
326 RTListForEachCpp(&a_rThat.m_ListHead, pCur, MapEntry, ListEntry)
327 {
328 int rc = putCopyWorker(pCur->strKey.c_str(), *pCur->pValue, true /*a_fReplace*/);
329 if (RT_SUCCESS(rc))
330 { /* likely */ }
331 else if (a_fThrow)
332 throw std::bad_alloc();
333 else
334 return rc;
335 }
336 }
337
338 return VINF_SUCCESS;
339}
340
341
342int RTCRestStringMapBase::putWorker(const char *a_pszKey, RTCRestObjectBase *a_pValue, bool a_fReplace,
343 size_t a_cchKey /*= RTSTR_MAX*/)
344{
345 int rc;
346 MapEntry *pEntry = new (std::nothrow) MapEntry;
347 if (pEntry)
348 {
349 rc = pEntry->strKey.assignNoThrow(a_pszKey, a_cchKey);
350 if (RT_SUCCESS(rc))
351 {
352 pEntry->Core.pszString = pEntry->strKey.c_str();
353 pEntry->Core.cchString = pEntry->strKey.length();
354 pEntry->pValue = a_pValue;
355 if (RTStrSpaceInsert(&m_Map, &pEntry->Core))
356 {
357 m_cEntries++;
358 m_fNullIndicator = false;
359 return VINF_SUCCESS;
360 }
361
362 Assert(!m_fNullIndicator);
363 if (!a_fReplace)
364 rc = VERR_ALREADY_EXISTS;
365 else
366 {
367 /* Just replace the pValue in the existing entry. */
368 MapEntry *pCollision = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
369 if (pCollision)
370 {
371 if (pCollision->pValue)
372 delete pCollision->pValue;
373 pCollision->pValue = a_pValue;
374 pEntry->pValue = NULL; /* paranoia */
375 rc = VWRN_ALREADY_EXISTS;
376 }
377 else
378 rc = VERR_INTERNAL_ERROR;
379 }
380 }
381 delete pEntry;
382 }
383 else
384 rc = VERR_NO_MEMORY;
385 return rc;
386}
387
388
389int RTCRestStringMapBase::putCopyWorker(const char *a_pszKey, RTCRestObjectBase const &a_rValue, bool a_fReplace,
390 size_t a_cchKey /*= RTSTR_MAX*/)
391{
392 int rc;
393 RTCRestObjectBase *pValueCopy = createValueCopy(&a_rValue);
394 if (pValueCopy)
395 {
396 rc = putWorker(a_pszKey, pValueCopy, a_fReplace, a_cchKey);
397 if (RT_SUCCESS(rc))
398 { /* likely */ }
399 else
400 delete pValueCopy;
401 }
402 else
403 rc = VERR_NO_MEMORY;
404 return rc;
405}
406
407
408RTCRestObjectBase *RTCRestStringMapBase::getWorker(const char *a_pszKey)
409{
410 MapEntry *pHit = (MapEntry *)RTStrSpaceGet(&m_Map, a_pszKey);
411 if (pHit)
412 return pHit->pValue;
413 return NULL;
414}
415
416
417RTCRestObjectBase const *RTCRestStringMapBase::getWorker(const char *a_pszKey) const
418{
419 MapEntry const *pHit = (MapEntry const *)RTStrSpaceGet((PRTSTRSPACE)&m_Map, a_pszKey);
420 if (pHit)
421 return pHit->pValue;
422 return NULL;
423}
424
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