aboutsummaryrefslogtreecommitdiff
path: root/src/unstable/blobbuilder.h
blob: fd368fa371d43153145512b69231b6b4717ebe1c (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
/*
 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
 *
 * This file is part of the libbu++ library and is released under the
 * terms of the license contained in the file LICENSE.
 */

#ifndef BU_BLOB_BUILDER_H
#define BU_BLOB_BUILDER_H

#include "bu/config.h"
#include "bu/sharedcore.h"

namespace Bu
{
    class Blob;
    class BlobBuilder;

    /** @cond DEVEL */
    class BlobBuilderCore
    {
    friend class BlobBuilder;
    friend class SharedCore<BlobBuilder, BlobBuilderCore>;
    private:
        class Chunk
        {
        public:
            Chunk( const char *pSrc, int32_t iLength );
            ~Chunk();

            void append( const char *&pSrc, int32_t &iLength );

            /**
             * Splits this chunk into two chunks, and fixes the links.
             *@param iIndex The first byte to be in the new chunk, if this is
             * zero or less then it has no effect.
             *@returns A pointer to the new chunk, or null if no work was
             * done.
             */
            Chunk *split( int32_t iIndex );

            int32_t iLength;
            char *pData;
            Chunk *pNext;
        };

        BlobBuilderCore();
        BlobBuilderCore( const Bu::Blob &rSrc );
        BlobBuilderCore( const BlobBuilderCore &rSrc );
        virtual ~BlobBuilderCore();

        void clear();
        void append( const char *pSrc, int32_t iLength );
        void prepend( const char *pSrc, int32_t iLength );
        void insert( int32_t iBefore, const char *pSrc, int32_t iLength );
        void set( const char *pSrc, int32_t iLength );
        void copyTo( void *pDestRaw, int32_t iLength ) const;
        char getAt( int32_t iIndex ) const;

        Chunk *pFirst;
        Chunk *pLast;
        int32_t iLength;
    };
    /** @endcond */

    /**
     * This makes creating a Blob piece at a time easy and fast.  You can
     * append, prepend, or insert with reasonable efficiency. The underlying
     * data structure is currently a linked list, and the individual links are
     * actually block allocated memory. If an amount of data is appended that
     * is less than the minimum page size then the minimum page size is
     * allocated. Subsequent appends will share that allocated buffer until it
     * is full, at which point a new buffer will be created.  If an amount
     * greater than the minimum page size is appended then any extra space in
     * the last buffer is used, and then the rest is placed in a single buffer.
     * At most one buffer will be allocated for any given append or prepend
     * operation.  Due to the nature of insert, up to two buffers could be
     * allocated.
     *
     * Insert operations will take O(N) time to find the location to insert to
     * in the linked list, at that point the foud chunk will be split into two
     * and the new data will be added at the new location. This will also
     * attempt to share the existing buffers, but if there's extra it will
     * allocate a new buffer for the remaining data.
     */
    class BlobBuilder : public Bu::SharedCore<BlobBuilder, BlobBuilderCore>
    {
    protected:
        using SharedCore<BlobBuilder, BlobBuilderCore>::core;
        using SharedCore<BlobBuilder, BlobBuilderCore>::_hardCopy;

    public:
        BlobBuilder();
        BlobBuilder( const Blob &rSrc );
        BlobBuilder( const BlobBuilder &rSrc );
        virtual ~BlobBuilder();

        void set( const Blob &rSrc );
        void set( const char *pSrc, int32_t iLength );
        void set( const char *pSrc );
        void append( const Blob &rSrc );
        void append( const char *pSrc, int32_t iLength );
        void append( const char *pSrc );
        void prepend( const Blob &rSrc );
        void prepend( const char *pSrc, int32_t iLength );
        void prepend( const char *pSrc );
        void insert( int32_t iBefore, const Blob &rSrc );
        void insert( int32_t iBefore, const char *pSrc, int32_t iLength );
        void insert( int32_t iBefore, const char *pSrc );
        void clear();

        int32_t getSize() const;
        Blob getBlob() const;
        void copyTo( void *pDestRaw, int32_t iDestSize ) const;
        char operator[]( int32_t iIndex ) const;

        BlobBuilder &operator=( const Blob &rSrc );
        BlobBuilder &operator=( const char *pSrc );
        BlobBuilder &operator=( const char chr );
        BlobBuilder &operator+=( const Blob &rSrc );
        BlobBuilder &operator+=( const char *pSrc );
        BlobBuilder &operator+=( const char chr );
        BlobBuilder &operator<<( const Blob &rSrc );
        BlobBuilder &operator<<( const char *pSrc );
        BlobBuilder &operator<<( const char chr );
    private:
    };
};

#endif