summaryrefslogtreecommitdiffstats
path: root/include/iprt/cpp/reststringmap.h
blob: cff201bb4f1cae61a9288bccd05586496e74e4ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
/** @file
 * IPRT - C++ Representational State Transfer (REST) String Map Template.
 */

/*
 * Copyright (C) 2008-2022 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
 * in the VirtualBox distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 *
 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
 */

#ifndef IPRT_INCLUDED_cpp_reststringmap_h
#define IPRT_INCLUDED_cpp_reststringmap_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <iprt/list.h>
#include <iprt/string.h>
#include <iprt/cpp/restbase.h>


/** @defgroup grp_rt_cpp_reststingmap   C++ Representational State Transfer (REST) String Map Template
 * @ingroup grp_rt_cpp
 * @{
 */

/**
 * Abstract base class for the RTCRestStringMap template.
 */
class RT_DECL_CLASS RTCRestStringMapBase : public RTCRestObjectBase
{
public:
    /** Default destructor. */
    RTCRestStringMapBase() RT_NOEXCEPT;
    /** Copy constructor. */
    RTCRestStringMapBase(RTCRestStringMapBase const &a_rThat);
    /** Destructor. */
    virtual ~RTCRestStringMapBase();
    /** Copy assignment operator. */
    RTCRestStringMapBase &operator=(RTCRestStringMapBase const &a_rThat);

    /* Overridden methods: */
    virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE;
    virtual int resetToDefault() RT_NOEXCEPT RT_OVERRIDE;
    virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_NOEXCEPT RT_OVERRIDE;
    virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_NOEXCEPT RT_OVERRIDE;
    // later?
    //virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = kCollectionFormat_Unspecified) const RT_NOEXCEPT RT_OVERRIDE;
    //virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL,
    //                       uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_NOEXCEPT RT_OVERRIDE;
    virtual kTypeClass typeClass(void) const RT_NOEXCEPT RT_OVERRIDE;
    virtual const char *typeName(void) const RT_NOEXCEPT RT_OVERRIDE;

    /**
     * Clear the content of the map.
     */
    void clear() RT_NOEXCEPT;

    /**
     * Checks if the map is empty.
     */
    inline bool isEmpty() const RT_NOEXCEPT { return m_cEntries == 0; }

    /**
     * Gets the number of entries in the map.
     */
    size_t size() const RT_NOEXCEPT;

    /**
     * Checks if the map contains the given key.
     * @returns true if key found, false if not.
     * @param   a_pszKey   The key to check fo.
     */
    bool containsKey(const char *a_pszKey) const RT_NOEXCEPT;

    /**
     * Checks if the map contains the given key.
     * @returns true if key found, false if not.
     * @param   a_rStrKey   The key to check fo.
     */
    bool containsKey(RTCString const &a_rStrKey) const RT_NOEXCEPT;

    /**
     * Remove any key-value pair with the given key.
     * @returns true if anything was removed, false if not found.
     * @param   a_pszKey    The key to remove.
     */
    bool remove(const char *a_pszKey) RT_NOEXCEPT;

    /**
     * Remove any key-value pair with the given key.
     * @returns true if anything was removed, false if not found.
     * @param   a_rStrKey   The key to remove.
     */
    bool remove(RTCString const &a_rStrKey) RT_NOEXCEPT;

    /**
     * Creates a new value and inserts it under the given key, returning the new value.
     *
     * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success.
     *          VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure.
     * @param   a_ppValue   Where to return the pointer to the value.
     * @param   a_pszKey    The key to put it under.
     * @param   a_cchKey    The length of the key.  Default is the entire string.
     * @param   a_fReplace  Whether to replace or fail on key collision.
     */
    int putNewValue(RTCRestObjectBase **a_ppValue, const char *a_pszKey, size_t a_cchKey = RTSTR_MAX, bool a_fReplace = false) RT_NOEXCEPT;

    /**
     * Creates a new value and inserts it under the given key, returning the new value.
     *
     * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success.
     *          VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure.
     * @param   a_ppValue   Where to return the pointer to the value.
     * @param   a_rStrKey   The key to put it under.
     * @param   a_fReplace  Whether to replace or fail on key collision.
     */
    int putNewValue(RTCRestObjectBase **a_ppValue, RTCString const &a_rStrKey, bool a_fReplace = false) RT_NOEXCEPT;

protected:
    /** Map entry. */
    typedef struct MapEntry
    {
        /** String space core. */
        RTSTRSPACECORE      Core;
        /** List node for enumeration. */
        RTLISTNODE          ListEntry;
        /** The key.
         * @remarks Core.pszString points to the value of this object.  So, consider it const. */
        RTCString           strKey;
        /** The value. */
        RTCRestObjectBase  *pValue;
    } MapEntry;
    /** The map tree. */
    RTSTRSPACE          m_Map;
    /** The enumeration list head (MapEntry). */
    RTLISTANCHOR        m_ListHead;
    /** Number of map entries. */
    size_t              m_cEntries;

public:
    /** @name Map Iteration
     * @{  */
    /** Const iterator. */
    class ConstIterator
    {
    private:
        MapEntry            *m_pCur;
        ConstIterator() RT_NOEXCEPT;
    protected:
        ConstIterator(MapEntry *a_pEntry) RT_NOEXCEPT : m_pCur(a_pEntry) { }
    public:
        ConstIterator(ConstIterator const &a_rThat) RT_NOEXCEPT : m_pCur(a_rThat.m_pCur) { }

        /** Gets the key string. */
        inline RTCString const         &getKey() RT_NOEXCEPT   { return m_pCur->strKey; }
        /** Gets poitner to the value object. */
        inline RTCRestObjectBase const *getValue() RT_NOEXCEPT { return m_pCur->pValue; }

        /** Advance to the next map entry. */
        inline ConstIterator &operator++() RT_NOEXCEPT
        {
            m_pCur = RTListNodeGetNextCpp(&m_pCur->ListEntry, MapEntry, ListEntry);
            return *this;
        }

        /** Advance to the previous map entry. */
        inline ConstIterator &operator--() RT_NOEXCEPT
        {
            m_pCur = RTListNodeGetPrevCpp(&m_pCur->ListEntry, MapEntry, ListEntry);
            return *this;
        }

        /** Compare equal. */
        inline bool operator==(ConstIterator const &a_rThat) RT_NOEXCEPT { return m_pCur == a_rThat.m_pCur; }
        /** Compare not equal. */
        inline bool operator!=(ConstIterator const &a_rThat) RT_NOEXCEPT { return m_pCur != a_rThat.m_pCur; }

        /* Map class must be friend so it can use the MapEntry constructor. */
        friend class RTCRestStringMapBase;
    };

    /** Returns iterator for the first map entry (unless it's empty and it's also the end). */
    inline ConstIterator begin() const RT_NOEXCEPT
    {
        if (!RTListIsEmpty(&m_ListHead))
            return ConstIterator(RTListNodeGetNextCpp(&m_ListHead, MapEntry, ListEntry));
        return end();
    }
    /** Returns iterator for the last map entry (unless it's empty and it's also the end). */
    inline ConstIterator last() const RT_NOEXCEPT
    {
        if (!RTListIsEmpty(&m_ListHead))
            return ConstIterator(RTListNodeGetPrevCpp(&m_ListHead, MapEntry, ListEntry));
        return end();
    }
    /** Returns the end iterator.  This does not ever refer to an actual map entry. */
    inline ConstIterator end() const RT_NOEXCEPT
    {
        return ConstIterator(RT_FROM_CPP_MEMBER(&m_ListHead, MapEntry, ListEntry));
    }
    /** @} */


protected:
    /**
     * Helper for creating a clone.
     *
     * @returns Pointer to new map object on success, NULL if out of memory.
     */
    virtual RTCRestStringMapBase *createClone(void) const RT_NOEXCEPT = 0;

    /**
     * Wrapper around the value constructor.
     *
     * @returns Pointer to new value object on success, NULL if out of memory.
     */
    virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT = 0;

    /**
     * For accessing the static deserializeInstanceFromJson() method of the value.
     */
    virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT = 0;

    /**
     * Worker for the copy assignment method and copyMapWorkerMayThrow.
     *
     * This will use createEntryCopy to do the copying.
     *
     * @returns VINF_SUCCESS on success, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure.
     * @param   a_rThat     The map to copy.  Caller makes 100% sure the it has
     *                      the same type as the destination.
     */
    int copyMapWorkerNoThrow(RTCRestStringMapBase const &a_rThat) RT_NOEXCEPT;

    /**
     * Wrapper around copyMapWorkerNoThrow() that throws allocation errors, making
     * it suitable for copy constructors and assignment operators.
     */
    void copyMapWorkerMayThrow(RTCRestStringMapBase const &a_rThat);

    /**
     * Worker for performing inserts.
     *
     * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success.
     *          VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure.
     * @param   a_pszKey        The key.
     * @param   a_pValue        The value to insert.  Ownership is transferred to the map on success.
     * @param   a_fReplace      Whether to replace existing key-value pair with matching key.
     * @param   a_cchKey        The key length, the whole string by default.
     */
    int putWorker(const char *a_pszKey, RTCRestObjectBase *a_pValue, bool a_fReplace, size_t a_cchKey = RTSTR_MAX) RT_NOEXCEPT;

    /**
     * Worker for performing inserts.
     *
     * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success.
     *          VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure.
     * @param   a_pszKey        The key.
     * @param   a_rValue        The value to copy into the map.
     * @param   a_fReplace      Whether to replace existing key-value pair with matching key.
     * @param   a_cchKey        The key length, the whole string by default.
     */
    int putCopyWorker(const char *a_pszKey, RTCRestObjectBase const &a_rValue, bool a_fReplace, size_t a_cchKey = RTSTR_MAX) RT_NOEXCEPT;

    /**
     * Worker for getting the value corresponding to the given key.
     *
     * @returns Pointer to the value object if found, NULL if key not in the map.
     * @param   a_pszKey        The key which value to look up.
     */
    RTCRestObjectBase *getWorker(const char *a_pszKey) RT_NOEXCEPT;

    /**
     * Worker for getting the value corresponding to the given key, const variant.
     *
     * @returns Pointer to the value object if found, NULL if key not in the map.
     * @param   a_pszKey        The key which value to look up.
     */
    RTCRestObjectBase const *getWorker(const char *a_pszKey) const RT_NOEXCEPT;

private:
    static DECLCALLBACK(int) stringSpaceDestructorCallback(PRTSTRSPACECORE pStr, void *pvUser) RT_NOEXCEPT;
};


/**
 * Limited map class.
 */
template<class ValueType> class RTCRestStringMap : public RTCRestStringMapBase
{
public:
    /** Default constructor, creates emtpy map. */
    RTCRestStringMap() RT_NOEXCEPT
        : RTCRestStringMapBase()
    {}

    /** Copy constructor. */
    RTCRestStringMap(RTCRestStringMap const &a_rThat)
        : RTCRestStringMapBase()
    {
        copyMapWorkerMayThrow(a_rThat);
    }

    /** Destructor. */
    virtual ~RTCRestStringMap()
    {
       /* nothing to do here. */
    }

    /** Copy assignment operator. */
    RTCRestStringMap &operator=(RTCRestStringMap const &a_rThat)
    {
        copyMapWorkerMayThrow(a_rThat);
        return *this;
    }

    /** Safe copy assignment method. */
    int assignCopy(RTCRestStringMap const &a_rThat) RT_NOEXCEPT
    {
        return copyMapWorkerNoThrow(a_rThat);
    }

    /** Make a clone of this object. */
    inline RTCRestStringMap *clone() const RT_NOEXCEPT
    {
        return (RTCRestStringMap *)baseClone();
    }

    /** Factory method. */
    static DECLCALLBACK(RTCRestObjectBase *) createInstance(void) RT_NOEXCEPT
    {
        return new (std::nothrow) RTCRestStringMap<ValueType>();
    }

    /** Factory method for values. */
    static DECLCALLBACK(RTCRestObjectBase *) createValueInstance(void) RT_NOEXCEPT
    {
        return new (std::nothrow) ValueType();
    }

    /** @copydoc RTCRestObjectBase::FNDESERIALIZEINSTANCEFROMJSON */
    static DECLCALLBACK(int) deserializeInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT
    {
        *a_ppInstance = new (std::nothrow) RTCRestStringMap<ValueType>();
        if (*a_ppInstance)
            return (*a_ppInstance)->deserializeFromJson(a_rCursor);
        return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_NO_MEMORY, "Out of memory");
    }

    /**
     * Inserts the given object into the map.
     *
     * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success.
     *          VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure.
     * @param   a_pszKey        The key.
     * @param   a_pValue        The value to insert.  Ownership is transferred to the map on success.
     * @param   a_fReplace      Whether to replace existing key-value pair with matching key.
     */
    inline int put(const char *a_pszKey, ValueType *a_pValue, bool a_fReplace = false) RT_NOEXCEPT
    {
        return putWorker(a_pszKey, a_pValue, a_fReplace);
    }

    /**
     * Inserts the given object into the map.
     *
     * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success.
     *          VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure.
     * @param   a_rStrKey       The key.
     * @param   a_pValue        The value to insert.  Ownership is transferred to the map on success.
     * @param   a_fReplace      Whether to replace existing key-value pair with matching key.
     */
    inline int put(RTCString const &a_rStrKey, ValueType *a_pValue, bool a_fReplace = false) RT_NOEXCEPT
    {
        return putWorker(a_rStrKey.c_str(), a_pValue, a_fReplace, a_rStrKey.length());
    }

    /**
     * Inserts a copy of the given object into the map.
     *
     * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success.
     *          VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure.
     * @param   a_pszKey        The key.
     * @param   a_rValue        The value to insert a copy of.
     * @param   a_fReplace      Whether to replace existing key-value pair with matching key.
     */
    inline int putCopy(const char *a_pszKey, const ValueType &a_rValue, bool a_fReplace = false) RT_NOEXCEPT
    {
        return putCopyWorker(a_pszKey, a_rValue, a_fReplace);
    }

    /**
     * Inserts a copy of the given object into the map.
     *
     * @returns VINF_SUCCESS or VWRN_ALREADY_EXISTS on success.
     *          VERR_ALREADY_EXISTS, VERR_NO_MEMORY or VERR_NO_STR_MEMORY on failure.
     * @param   a_rStrKey       The key.
     * @param   a_rValue        The value to insert a copy of.
     * @param   a_fReplace      Whether to replace existing key-value pair with matching key.
     */
    inline int putCopy(RTCString const &a_rStrKey, const ValueType &a_rValue, bool a_fReplace = false) RT_NOEXCEPT
    {
        return putCopyWorker(a_rStrKey.c_str(), a_rValue, a_fReplace, a_rStrKey.length());
    }

    /**
     * Gets the value corresponding to the given key.
     *
     * @returns Pointer to the value object if found, NULL if key not in the map.
     * @param   a_pszKey        The key which value to look up.
     */
    inline ValueType *get(const char *a_pszKey) RT_NOEXCEPT
    {
        return (ValueType *)getWorker(a_pszKey);
    }

    /**
     * Gets the value corresponding to the given key.
     *
     * @returns Pointer to the value object if found, NULL if key not in the map.
     * @param   a_rStrKey       The key which value to look up.
     */
    inline ValueType *get(RTCString const &a_rStrKey) RT_NOEXCEPT
    {
        return (ValueType *)getWorker(a_rStrKey.c_str());
    }

    /**
     * Gets the const value corresponding to the given key.
     *
     * @returns Pointer to the value object if found, NULL if key not in the map.
     * @param   a_pszKey        The key which value to look up.
     */
    inline ValueType const *get(const char *a_pszKey) const RT_NOEXCEPT
    {
        return (ValueType const *)getWorker(a_pszKey);
    }

    /**
     * Gets the const value corresponding to the given key.
     *
     * @returns Pointer to the value object if found, NULL if key not in the map.
     * @param   a_rStrKey       The key which value to look up.
     */
    inline ValueType const *get(RTCString const &a_rStrKey) const RT_NOEXCEPT
    {
        return (ValueType const *)getWorker(a_rStrKey.c_str());
    }

    /** @todo enumerator*/

protected:
    virtual RTCRestStringMapBase *createClone(void) const RT_NOEXCEPT RT_OVERRIDE
    {
        return new (std::nothrow) RTCRestStringMap();
    }

    virtual RTCRestObjectBase *createValue(void) RT_NOEXCEPT RT_OVERRIDE
    {
        return new (std::nothrow) ValueType();
    }

    virtual int deserializeValueInstanceFromJson(RTCRestJsonCursor const &a_rCursor, RTCRestObjectBase **a_ppInstance) RT_NOEXCEPT RT_OVERRIDE
    {
        return ValueType::deserializeInstanceFromJson(a_rCursor, a_ppInstance);
    }
};


/** @} */

#endif /* !IPRT_INCLUDED_cpp_reststringmap_h */