VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/rest/RTCRestArrayBase.cpp@ 74095

Last change on this file since 74095 was 74025, checked in by vboxsync, 6 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.3 KB
Line 
1/* $Id: RTCRestArrayBase.cpp 74025 2018-09-02 14:14:43Z vboxsync $ */
2/** @file
3 * IPRT - C++ REST, RTCRestArrayBase 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/restarray.h>
33
34#include <iprt/err.h>
35#include <iprt/string.h>
36
37
38
39/**
40 * Default destructor.
41 */
42RTCRestArrayBase::RTCRestArrayBase()
43 : RTCRestObjectBase()
44 , m_papElements(NULL)
45 , m_cElements(0)
46 , m_cCapacity(0)
47{
48}
49
50
51#if 0 /* should not be used */
52/**
53 * Copy constructor.
54 */
55RTCRestArrayBase::RTCRestArrayBase(RTCRestArrayBase const &a_rThat);
56#endif
57
58/**
59 * Destructor.
60 */
61RTCRestArrayBase::~RTCRestArrayBase()
62{
63 clear();
64
65 if (m_papElements)
66 {
67 RTMemFree(m_papElements);
68 m_papElements = NULL;
69 m_cCapacity = 0;
70 }
71}
72
73
74#if 0 /* should not be used */
75/**
76 * Copy assignment operator.
77 */
78RTCRestArrayBase &RTCRestArrayBase::operator=(RTCRestArrayBase const &a_rThat);
79#endif
80
81
82/*********************************************************************************************************************************
83* Overridden methods *
84*********************************************************************************************************************************/
85
86int RTCRestArrayBase::resetToDefault()
87{
88 /* The default state of an array is empty. At least for now. */
89 clear();
90 m_fNullIndicator = false;
91 return VINF_SUCCESS;
92}
93
94
95RTCRestOutputBase &RTCRestArrayBase::serializeAsJson(RTCRestOutputBase &a_rDst) const
96{
97 if (!m_fNullIndicator)
98 {
99 a_rDst.printf("[\n");
100 unsigned const uOldIndent = a_rDst.incrementIndent();
101
102 for (size_t i = 0; i < m_cElements; i++)
103 {
104 m_papElements[i]->serializeAsJson(a_rDst);
105 if (i < m_cElements)
106 a_rDst.printf(",\n");
107 else
108 a_rDst.printf("\n");
109 }
110
111 a_rDst.setIndent(uOldIndent);
112 a_rDst.printf("]");
113 }
114 else
115 a_rDst.printf("null");
116 return a_rDst;
117}
118
119
120int RTCRestArrayBase::deserializeFromJson(RTCRestJsonCursor const &a_rCursor)
121{
122 /*
123 * Make sure the object starts out with an empty map.
124 */
125 if (m_cElements > 0)
126 clear();
127 m_fNullIndicator = false;
128
129 /*
130 * Iterate the array values.
131 */
132 RTJSONIT hIterator;
133 int rcRet = RTJsonIteratorBeginArray(a_rCursor.m_hValue, &hIterator);
134 if (RT_SUCCESS(rcRet))
135 {
136 for (size_t idxName = 0;; idxName++)
137 {
138 RTCRestJsonCursor SubCursor(a_rCursor);
139 int rc = RTJsonIteratorQueryValue(hIterator, &SubCursor.m_hValue, &SubCursor.m_pszName);
140 if (RT_SUCCESS(rc))
141 {
142 RTCRestObjectBase *pObj = createValue();
143 if (pObj)
144 {
145 char szName[32];
146 RTStrPrintf(szName, sizeof(szName), "[%u]", idxName);
147 SubCursor.m_pszName = szName;
148
149 rc = pObj->deserializeFromJson(SubCursor);
150 if (RT_SUCCESS(rc))
151 { /* likely */ }
152 else if (RT_SUCCESS(rcRet))
153 rcRet = rc;
154
155 rc = insertWorker(~(size_t)0, pObj, false /*a_fReplace*/);
156 if (RT_SUCCESS(rc))
157 { /* likely */ }
158 else
159 {
160 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Array insert failed (index %zu): %Rrc",
161 idxName, rc);
162 delete pObj;
163 }
164 }
165 else
166 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "Failed to create new value object");
167 }
168 else
169 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorQueryValue failed: %Rrc", rc);
170
171 /*
172 * Advance.
173 */
174 rc = RTJsonIteratorNext(hIterator);
175 if (RT_SUCCESS(rc))
176 { /* likely */ }
177 else if (rc == VERR_JSON_ITERATOR_END)
178 break;
179 else
180 {
181 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rc, "RTJsonIteratorNext failed: %Rrc", rc);
182 break;
183 }
184 }
185
186 RTJsonIteratorFree(hIterator);
187 }
188 else if (rcRet == VERR_JSON_IS_EMPTY)
189 rcRet = VINF_SUCCESS;
190 else if ( rcRet == VERR_JSON_VALUE_INVALID_TYPE
191 && RTJsonValueGetType(a_rCursor.m_hValue) == RTJSONVALTYPE_NULL)
192 {
193 m_fNullIndicator = true;
194 rcRet = VINF_SUCCESS;
195 }
196 else
197 rcRet = a_rCursor.m_pPrimary->addError(a_rCursor, rcRet,
198 "RTJsonIteratorBeginrray failed: %Rrc (type %s)",
199 rcRet, RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue)));
200 return rcRet;
201
202}
203
204
205int RTCRestArrayBase::toString(RTCString *a_pDst, uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/) const
206{
207 int rc;
208 if (!m_fNullIndicator)
209 {
210 if (m_cElements)
211 {
212 static char const s_szSep[kCollectionFormat_Mask + 1] = ",, \t|,,";
213 char const chSep = s_szSep[a_fFlags & kCollectionFormat_Mask];
214
215 rc = m_papElements[0]->toString(a_pDst, a_fFlags);
216 for (size_t i = 1; RT_SUCCESS(rc) && i < m_cElements; i++)
217 {
218 rc = a_pDst->appendNoThrow(chSep);
219 if (RT_SUCCESS(rc))
220 rc = m_papElements[i]->toString(a_pDst, a_fFlags | kToString_Append);
221 }
222 }
223 else
224 {
225 if (!(a_fFlags & kToString_Append))
226 a_pDst->setNull();
227 rc = VINF_SUCCESS;
228 }
229 }
230 else if (a_fFlags & kToString_Append)
231 rc = a_pDst->appendNoThrow(RT_STR_TUPLE("null"));
232 else
233 rc = a_pDst->appendNoThrow(RT_STR_TUPLE("null"));
234
235 return rc;
236}
237
238
239int RTCRestArrayBase::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/,
240 uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/)
241{
242 /** @todo proper fromString implementation for arrays. */
243 return RTCRestObjectBase::fromString(a_rValue, a_pszName, a_pErrInfo, a_fFlags);
244}
245
246
247RTCRestObjectBase::kTypeClass RTCRestArrayBase::typeClass(void) const
248{
249 return kTypeClass_Array;
250}
251
252
253const char *RTCRestArrayBase::typeName(void) const
254{
255 return "RTCRestArray<ElementType>";
256}
257
258
259
260/*********************************************************************************************************************************
261* Array methods *
262*********************************************************************************************************************************/
263
264void RTCRestArrayBase::clear()
265{
266 size_t i = m_cElements;
267 while (i-- > 0)
268 {
269 delete m_papElements[i];
270 m_papElements[i] = NULL;
271 }
272 m_cElements = 0;
273 m_fNullIndicator = false;
274}
275
276
277bool RTCRestArrayBase::removeAt(size_t a_idx)
278{
279 if (a_idx == ~(size_t)0)
280 a_idx = m_cElements - 1;
281 if (a_idx < m_cElements)
282 {
283 delete m_papElements[a_idx];
284 m_papElements[a_idx] = NULL;
285
286 m_cElements--;
287 if (a_idx < m_cElements)
288 memmove(&m_papElements[a_idx], &m_papElements[a_idx + 1], (m_cElements - a_idx) * sizeof(m_papElements[0]));
289
290 m_cElements--;
291 }
292 return false;
293}
294
295
296int RTCRestArrayBase::ensureCapacity(size_t a_cEnsureCapacity)
297{
298 if (m_cCapacity < a_cEnsureCapacity)
299 {
300 if (a_cEnsureCapacity < 512)
301 a_cEnsureCapacity = RT_ALIGN_Z(a_cEnsureCapacity, 16);
302 else if (a_cEnsureCapacity < 16384)
303 a_cEnsureCapacity = RT_ALIGN_Z(a_cEnsureCapacity, 128);
304 else
305 a_cEnsureCapacity = RT_ALIGN_Z(a_cEnsureCapacity, 512);
306
307 void *pvNew = RTMemRealloc(m_papElements, sizeof(m_papElements[0]) * a_cEnsureCapacity);
308 if (pvNew)
309 {
310 m_papElements = (RTCRestObjectBase **)pvNew;
311 memset(&m_papElements[m_cCapacity], 0, (a_cEnsureCapacity - m_cCapacity) * sizeof(sizeof(m_papElements[0])));
312 m_cCapacity = a_cEnsureCapacity;
313 }
314 else
315 return VERR_NO_MEMORY;
316 }
317 return VINF_SUCCESS;
318}
319
320
321int RTCRestArrayBase::copyArrayWorker(RTCRestArrayBase const &a_rThat, bool a_fThrow)
322{
323 int rc;
324 clear();
325 if (a_rThat.m_cElements == 0)
326 {
327 m_fNullIndicator = a_rThat.m_fNullIndicator;
328 rc = VINF_SUCCESS;
329 }
330 else
331 {
332 Assert(!a_rThat.m_fNullIndicator);
333 rc = ensureCapacity(a_rThat.m_cElements);
334 if (RT_SUCCESS(rc))
335 {
336 for (size_t i = 0; i < a_rThat.m_cElements; i++)
337 {
338 AssertPtr(a_rThat.m_papElements[i]);
339 rc = insertCopyWorker(i, *a_rThat.m_papElements[i], false);
340 if (RT_SUCCESS(rc))
341 { /* likely */ }
342 else if (a_fThrow)
343 throw std::bad_alloc();
344 else
345 return rc;
346 }
347 }
348 }
349 return rc;
350}
351
352
353int RTCRestArrayBase::insertWorker(size_t a_idx, RTCRestObjectBase *a_pValue, bool a_fReplace)
354{
355 AssertPtrReturn(a_pValue, VERR_INVALID_POINTER);
356
357 if (a_idx == ~(size_t)0)
358 a_idx = m_cElements;
359
360 if (a_idx <= m_cElements)
361 {
362 if (a_idx == m_cElements || !a_fReplace)
363 {
364 /* Make sure we've got array space. */
365 if (m_cElements + 1 < m_cCapacity)
366 { /* kind of likely */ }
367 else
368 {
369 int rc = ensureCapacity(m_cElements + 1);
370 if (RT_SUCCESS(rc))
371 { /* likely */ }
372 else
373 return rc;
374 }
375
376 /* Shift following elements before inserting. */
377 if (a_idx < m_cElements)
378 memmove(&m_papElements[a_idx + 1], &m_papElements[a_idx], (m_cElements - a_idx) * sizeof(m_papElements[0]));
379 m_papElements[a_idx] = a_pValue;
380 m_cElements++;
381#ifdef RT_STRICT
382 for (size_t i = 0; i < m_cElements; i++)
383 AssertPtr(m_papElements[i]);
384#endif
385 m_fNullIndicator = false;
386 return VINF_SUCCESS;
387 }
388
389 /* Replace element. */
390 delete m_papElements[a_idx];
391 m_papElements[a_idx] = a_pValue;
392 m_fNullIndicator = false;
393 return VWRN_ALREADY_EXISTS;
394 }
395 return VERR_OUT_OF_RANGE;
396}
397
398
399int RTCRestArrayBase::insertCopyWorker(size_t a_idx, RTCRestObjectBase const &a_rValue, bool a_fReplace)
400{
401 int rc;
402 RTCRestObjectBase *pValueCopy = createValueCopy(&a_rValue);
403 if (pValueCopy)
404 {
405 rc = insertWorker(a_idx, pValueCopy, a_fReplace);
406 if (RT_SUCCESS(rc))
407 { /* likely */ }
408 else
409 delete pValueCopy;
410 }
411 else
412 rc = VERR_NO_MEMORY;
413 return rc;
414}
415
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