aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/memory/blob.h
blob: a14ac742b299c4b13074d8c455adc4096ebac142 (plain) (blame)
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
#pragma once

#include "ref.h"
#include "ref_counted.h"

#include <library/cpp/yt/misc/port.h>

namespace NYT {

////////////////////////////////////////////////////////////////////////////////

//! Default memory tag for TBlob.
struct TDefaultBlobTag
{ };

//! A home-grown optimized replacement for |std::vector<char>| suitable for carrying
//! large chunks of data.
/*!
 *  Compared to |std::vector<char>|, this class supports uninitialized allocations
 *  when explicitly requested to.
 */
class TBlob
{
public:
    //! Constructs a blob with a given size.
    explicit TBlob(
        TRefCountedTypeCookie tagCookie = GetRefCountedTypeCookie<TDefaultBlobTag>(),
        size_t size = 0,
        bool initializeStorage = true,
        bool pageAligned = false);

    //! Copies a chunk of memory into a new instance.
    TBlob(
        TRefCountedTypeCookie tagCookie,
        TRef data,
        bool pageAligned = false);

    //! Copies the data.
    TBlob(const TBlob& other);

    //! Moves the data (takes the ownership).
    TBlob(TBlob&& other) noexcept;

    //! Reclaims the memory.
    ~TBlob();

    //! Ensures that capacity is at least #capacity.
    void Reserve(size_t newCapacity);

    //! Changes the size to #newSize.
    /*!
     *  If #size exceeds the current capacity,
     *  we make sure the new capacity grows exponentially.
     *  Hence calling #Resize N times to increase the size by N only
     *  takes amortized O(1) time per call.
     */
    void Resize(size_t newSize, bool initializeStorage = true);

    //! Returns the start pointer.
    Y_FORCE_INLINE const char* Begin() const
    {
        return Begin_;
    }

    //! Returns the start pointer.
    Y_FORCE_INLINE char* Begin()
    {
        return Begin_;
    }

    //! Returns the end pointer.
    Y_FORCE_INLINE const char* End() const
    {
        return Begin_ + Size_;
    }

    //! Returns the end pointer.
    Y_FORCE_INLINE char* End()
    {
        return Begin_ + Size_;
    }

    //! Returns the size.
    Y_FORCE_INLINE size_t size() const
    {
        return Size_;
    }

    //! Returns the size.
    Y_FORCE_INLINE size_t Size() const
    {
        return Size_;
    }

    //! Returns the capacity.
    Y_FORCE_INLINE size_t Capacity() const
    {
        return Capacity_;
    }

    //! Returns the TStringBuf instance for the occupied part of the blob.
    Y_FORCE_INLINE TStringBuf ToStringBuf() const
    {
        return TStringBuf(Begin_, Size_);
    }

    //! Returns the TRef instance for the occupied part of the blob.
    Y_FORCE_INLINE TRef ToRef() const
    {
        return TRef(Begin_, Size_);
    }

    //! Provides by-value access to the underlying storage.
    Y_FORCE_INLINE char operator [] (size_t index) const
    {
        return Begin_[index];
    }

    //! Provides by-ref access to the underlying storage.
    Y_FORCE_INLINE char& operator [] (size_t index)
    {
        return Begin_[index];
    }

    //! Clears the instance but does not reclaim the memory.
    Y_FORCE_INLINE void Clear()
    {
        Size_ = 0;
    }

    //! Returns |true| if size is zero.
    Y_FORCE_INLINE bool IsEmpty() const
    {
        return Size_ == 0;
    }

    //! Overwrites the current instance.
    TBlob& operator = (const TBlob& rhs);

    //! Takes the ownership.
    TBlob& operator = (TBlob&& rhs) noexcept;

    //! Appends a chunk of memory to the end.
    void Append(const void* data, size_t size);

    //! Appends a chunk of memory to the end.
    void Append(TRef ref);

    //! Appends a single char to the end.
    void Append(char ch);

    //! Swaps the current and other instances
    void Swap(TBlob& other);

    friend void swap(TBlob& left, TBlob& right);

private:
    char* Begin_ = nullptr;
    size_t Size_ = 0;
    size_t Capacity_ = 0;
    bool PageAligned_ = false;

#ifdef YT_ENABLE_REF_COUNTED_TRACKING
    TRefCountedTypeCookie TagCookie_ = NullRefCountedTypeCookie;
#endif

    char* DoAllocate(size_t newCapacity);
    void Allocate(size_t newCapacity);
    void Reallocate(size_t newCapacity);
    void Free();

    void Reset();

    void SetTagCookie(TRefCountedTypeCookie tagCookie);
    void SetTagCookie(const TBlob& other);
};

void swap(TBlob& left, TBlob& right);

////////////////////////////////////////////////////////////////////////////////

} // namespace NYT