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

#include "new.h"
#include "range.h"
#include "shared_range.h"

#include <library/cpp/yt/string/format.h>

#include <type_traits>

namespace NYT {

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

// Forward declaration.
class TBlob;

//! A non-owning reference to a range of memory.
class TRef
    : public TRange<char>
{
public:
    //! Creates a null TRef.
    TRef() = default;

    //! Creates a TRef for a given block of memory.
    TRef(const void* data, size_t size);

    //! Creates a TRef for a given range of memory.
    TRef(const void* begin, const void* end);

    //! Creates an empty TRef.
    static TRef MakeEmpty();

    //! Creates a non-owning TRef for a given blob.
    static TRef FromBlob(const TBlob& blob);

    //! Creates a non-owning TRef for a given string.
    static TRef FromString(const TString& str);

    //! Creates a non-owning TRef for a given std::string.
    static TRef FromString(const std::string& str);

    //! Creates a non-owning TRef for a given stringbuf.
    static TRef FromStringBuf(TStringBuf strBuf);

    //! Creates a non-owning TRef for a given pod structure.
    template <class T>
    static TRef FromPod(const T& data);

    //! Converts to TStringBuf.
    TStringBuf ToStringBuf() const;

    //! Creates a TRef for a part of existing range.
    TRef Slice(size_t startOffset, size_t endOffset) const;

    //! Compares the content for bitwise equality.
    static bool AreBitwiseEqual(TRef lhs, TRef rhs);
};

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

//! A non-owning reference to a mutable range of memory.
//! Use with caution :)
class TMutableRef
    : public TMutableRange<char>
{
public:
    //! Creates a null TMutableRef.
    //! Note empty TMutableRef is not the same as null TMutableRef.
    //! `operator bool` can be used to check if ref is nonnull.
    TMutableRef() = default;

    //! Creates a TMutableRef for a given block of memory.
    TMutableRef(void* data, size_t size);

    //! Creates a TMutableRef for a given range of memory.
    TMutableRef(void* begin, void* end);

    //! Creates an empty TMutableRef.
    static TMutableRef MakeEmpty();

    //! Converts a TMutableRef to TRef.
    operator TRef() const;

    //! Creates a non-owning TMutableRef for a given blob.
    static TMutableRef FromBlob(TBlob& blob);

    //! Creates a non-owning TMutableRef for a given pod structure.
    template <class T>
    static TMutableRef FromPod(T& data);

    //! Creates a non-owning TMutableRef for a given TString.
    //! Ensures that the string is not shared.
    static TMutableRef FromString(TString& str);

    //! Creates a non-owning TMutableRef for a given std::string.
    static TMutableRef FromString(std::string& str);

    //! Creates a TMutableRef for a part of existing range.
    TMutableRef Slice(size_t startOffset, size_t endOffset) const;
};

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

//! Default tag type for memory blocks allocated via TSharedRef.
/*!
 *  Each newly allocated TSharedRef blob is associated with a tag type
 *  that appears in ref-counted statistics.
 */
struct TDefaultSharedBlobTag { };

//! A reference to a range of memory with shared ownership.
class TSharedRef
    : public TSharedRange<char>
{
public:
    //! Creates a null TSharedRef.
    TSharedRef() = default;

    //! Creates a TSharedRef with a given holder.
    TSharedRef(TRef ref, TSharedRangeHolderPtr holder);

    //! Creates a TSharedRef from a pointer and length.
    TSharedRef(const void* data, size_t length, TSharedRangeHolderPtr holder);

    //! Creates a TSharedRef from a range.
    TSharedRef(const void* begin, const void* end, TSharedRangeHolderPtr holder);

    //! Creates an empty TSharedRef.
    static TSharedRef MakeEmpty();

    //! Converts a TSharedRef to TRef.
    operator TRef() const;


    //! Creates a TSharedRef from TString.
    //! Since strings are ref-counted, no data is being copied.
    //! The memory is marked with a given tag.
    template <class TTag>
    static TSharedRef FromString(TString str);

    //! Same as above but the memory is marked with TDefaultSharedBlobTag.
    static TSharedRef FromString(TString str);

    //! Same as above but the memory tag is specified in #tagCookie.
    static TSharedRef FromString(TString str, TRefCountedTypeCookie tagCookie);

    //! Creates a TSharedRef from std::string.
    //! No data is being copied in #FromString itself but since #str is passed by value
    //! a copy may occur at caller's side.
    //! The memory is marked with a given tag.
    template <class TTag>
    static TSharedRef FromString(std::string str);

    //! Same as above but the memory is marked with TDefaultSharedBlobTag.
    static TSharedRef FromString(std::string str);

    //! Same as above but the memory tag is specified in #tagCookie.
    static TSharedRef FromString(std::string str, TRefCountedTypeCookie tagCookie);

    //! Creates a TSharedRef from a zero-terminated C string.
    static TSharedRef FromString(const char* str);

    //! Creates a TSharedRef for a given blob taking ownership of its content.
    static TSharedRef FromBlob(TBlob&& blob);

    //! Converts to TStringBuf.
    TStringBuf ToStringBuf() const;

    //! Creates a copy of a given TRef.
    //! The memory is marked with a given tag.
    static TSharedRef MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie);

    //! Creates a copy of a given TRef.
    //! The memory is marked with a given tag.
    template <class TTag>
    static TSharedRef MakeCopy(TRef ref);

    //! Creates a TSharedRef for a part of existing range.
    TSharedRef Slice(size_t startOffset, size_t endOffset) const;

    //! Creates a TSharedRef for a part of existing range.
    TSharedRef Slice(const void* begin, const void* end) const;

    //! Creates a vector of slices with specified size.
    std::vector<TSharedRef> Split(size_t partSize) const;

private:
    friend class TSharedRefArrayImpl;

    template <class TString>
    static TSharedRef FromStringImpl(TString str, TRefCountedTypeCookie tagCookie);
};

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

//! Various options for allocating TSharedMutableRef.
struct TSharedMutableRefAllocateOptions
{
    bool InitializeStorage = true;
    bool ExtendToUsableSize = false;
};

//! A reference to a mutable range of memory with shared ownership.
//! Use with caution :)
class TSharedMutableRef
    : public TSharedMutableRange<char>
{
public:
    //! Creates a null TSharedMutableRef.
    TSharedMutableRef() = default;

    //! Creates a TSharedMutableRef with a given holder.
    TSharedMutableRef(const TMutableRef& ref, TSharedRangeHolderPtr holder);

    //! Creates a TSharedMutableRef from a pointer and length.
    TSharedMutableRef(void* data, size_t length, TSharedRangeHolderPtr holder);

    //! Creates a TSharedMutableRef from a range.
    TSharedMutableRef(void* begin, void* end, TSharedRangeHolderPtr holder);

    //! Creates an empty TSharedMutableRef.
    static TSharedMutableRef MakeEmpty();

    //! Converts a TSharedMutableRef to TMutableRef.
    operator TMutableRef() const;

    //! Converts a TSharedMutableRef to TSharedRef.
    operator TSharedRef() const;

    //! Converts a TSharedMutableRef to TRef.
    operator TRef() const;


    //! Allocates a new shared block of memory.
    //! The memory is marked with a given tag.
    template <class TTag>
    static TSharedMutableRef Allocate(size_t size, TSharedMutableRefAllocateOptions options = {});

    //! Allocates a new shared block of memory.
    //! The memory is marked with TDefaultSharedBlobTag.
    static TSharedMutableRef Allocate(size_t size, TSharedMutableRefAllocateOptions options = {});

    //! Allocates a new shared block of memory.
    //! The memory is marked with a given tag.
    static TSharedMutableRef Allocate(size_t size, TSharedMutableRefAllocateOptions options, TRefCountedTypeCookie tagCookie);

    //! Allocates a new page aligned shared block of memory.
    //! #size must be divisible by page size.
    //! The memory is marked with a given tag.
    template <class TTag>
    static TSharedMutableRef AllocatePageAligned(size_t size, TSharedMutableRefAllocateOptions options = {});

    //! Allocates a new page aligned shared block of memory.
    //! #size must be divisible by page size.
    //! The memory is marked with TDefaultSharedBlobTag.
    static TSharedMutableRef AllocatePageAligned(size_t size, TSharedMutableRefAllocateOptions options = {});

    //! Allocates a new page aligned shared block of memory.
    //! #size must be divisible by page size.
    //! The memory is marked with a given tag.
    static TSharedMutableRef AllocatePageAligned(size_t size, TSharedMutableRefAllocateOptions options, TRefCountedTypeCookie tagCookie);

    //! Creates a TSharedMutableRef for the whole blob taking ownership of its content.
    static TSharedMutableRef FromBlob(TBlob&& blob);

    //! Creates a copy of a given TRef.
    //! The memory is marked with a given tag.
    static TSharedMutableRef MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie);

    //! Creates a copy of a given TRef.
    //! The memory is marked with a given tag.
    template <class TTag>
    static TSharedMutableRef MakeCopy(TRef ref);

    //! Creates a reference for a part of existing range.
    TSharedMutableRef Slice(size_t startOffset, size_t endOffset) const;

    //! Creates a reference for a part of existing range.
    TSharedMutableRef Slice(void* begin, void* end) const;
};

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

DECLARE_REFCOUNTED_CLASS(TSharedRefArrayImpl)

//! A smart-pointer to a ref-counted immutable sequence of TSharedRef-s.
class TSharedRefArray
{
public:
    TSharedRefArray() = default;
    TSharedRefArray(const TSharedRefArray& other);
    TSharedRefArray(TSharedRefArray&& other) noexcept;

    explicit TSharedRefArray(const TSharedRef& part);
    explicit TSharedRefArray(TSharedRef&& part);

    struct TCopyParts
    { };
    struct TMoveParts
    { };

    template <class TParts>
    TSharedRefArray(const TParts& parts, TCopyParts);
    template <class TParts>
    TSharedRefArray(TParts&& parts, TMoveParts);

    TSharedRefArray& operator = (const TSharedRefArray& other);
    TSharedRefArray& operator = (TSharedRefArray&& other);

    explicit operator bool() const;

    void Reset();

    size_t Size() const;
    size_t size() const;
    i64 ByteSize() const;
    bool Empty() const;
    const TSharedRef& operator [] (size_t index) const;

    const TSharedRef* Begin() const;
    const TSharedRef* End() const;

    std::vector<TSharedRef> ToVector() const;
    TString ToString() const;

    //! Creates a copy of a given TSharedRefArray.
    //! The memory is marked with a given tag.
    static TSharedRefArray MakeCopy(const TSharedRefArray& array, TRefCountedTypeCookie tagCookie);

private:
    friend class TSharedRefArrayBuilder;

    TSharedRefArrayImplPtr Impl_;

    explicit TSharedRefArray(TSharedRefArrayImplPtr impl);

    template <class... As>
    static TSharedRefArrayImplPtr NewImpl(
        size_t size,
        size_t poolCapacity,
        TRefCountedTypeCookie cookie,
        As&&... args);
};

// STL interop.
const TSharedRef* begin(const TSharedRefArray& array);
const TSharedRef* end(const TSharedRefArray& array);

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

struct TDefaultSharedRefArrayBuilderTag { };

//! A helper for creating TSharedRefArray.
class TSharedRefArrayBuilder
{
public:
    //! Creates a builder instance.
    /*
     *  The user must provide the total (resulting) part count in #size.
     *
     *  Additionally, the user may request a certain memory pool of size #poolCapacity
     *  to be created. Parts occupiying space in the above pool are created with #AllocateAndAdd
     *  calls.
     *
     *  The pool (if any) and the array are created within a single memory allocation tagged with
     *  #tagCookie.
     *
     *  If less than #size parts are added, the trailing ones are null.
     */
    explicit TSharedRefArrayBuilder(
        size_t size,
        size_t poolCapacity = 0,
        TRefCountedTypeCookie tagCookie = GetRefCountedTypeCookie<TDefaultSharedRefArrayBuilderTag>());

    //! Adds an existing TSharedRef part to the constructed array.
    void Add(TSharedRef part);

    //! Allocates #size memory from the pool and adds a part to the constuctured array.
    /*!
     *  The resulting TMutableRef enables the user to fill the just-created part appropriately.
     *  The total sum of #size during all #AllocateAndAll calls must now exceed #allocationCapacity
     *  passed to the ctor.
     *
     *  The memory is being claimed from the pool contiguously; the user must
     *  take care of the alignment issues on its own.
     */
    TMutableRef AllocateAndAdd(size_t size);

    //! Finalizes the construction; returns the constructed TSharedRefArray.
    TSharedRefArray Finish();

private:
    const size_t AllocationCapacity_;
    TSharedRefArrayImplPtr Impl_;
    char* CurrentAllocationPtr_;
    size_t CurrentPartIndex_ = 0;
};


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

void FormatValue(TStringBuilderBase* builder, const TRef& ref, TStringBuf spec);
void FormatValue(TStringBuilderBase* builder, const TMutableRef& ref, TStringBuf spec);
void FormatValue(TStringBuilderBase* builder, const TSharedRef& ref, TStringBuf spec);
void FormatValue(TStringBuilderBase* builder, const TSharedMutableRef& ref, TStringBuf);

size_t GetPageSize();
size_t RoundUpToPage(size_t bytes);

size_t GetByteSize(TRef ref);
size_t GetByteSize(const TSharedRefArray& array);
template <class T>
size_t GetByteSize(TRange<T> parts);
template <class T>
size_t GetByteSize(const std::vector<T>& parts);

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

} // namespace NYT

#define REF_INL_H_
#include "ref-inl.h"
#undef REF_INL_H_

//! Serialize TSharedRef like vector<char>. Useful for ::Save, ::Load serialization/deserialization. See util/ysaveload.h.
template <>
class TSerializer<NYT::TSharedRef>: public TVectorSerializer<NYT::TSharedRange<char>> {};