aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/minikql/computation/mkql_optional_usage_mask.h
blob: dab8bb257cb378ad31e9d1c48554ba8506a5a1f8 (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
#pragma once

#include "mkql_computation_node_pack_impl.h"

#include <util/generic/bitmap.h>
#include <util/generic/buffer.h>

#include <cstring>

namespace NKikimr {
namespace NMiniKQL {

namespace NDetails {

class TOptionalUsageMask {
public:
    TOptionalUsageMask() = default;

    void Reset() {
        CountOfOptional = 0U;
        Mask.Clear();
    }

    void Reset(TChunkedInputBuffer& buf) {
        Reset();
        ui64 bytes = UnpackUInt64(buf);
        if (bytes) {
            Mask.Reserve(bytes << 3ULL);
            buf.CopyTo(reinterpret_cast<char*>(const_cast<ui8*>(Mask.GetChunks())), bytes);
        }
    }

    void SetNextEmptyOptional(bool empty) {
        if (empty) {
            Mask.Set(CountOfOptional);
        }
        ++CountOfOptional;
    }

    bool IsNextEmptyOptional() {
        return Mask.Test(CountOfOptional++);
    }

    bool IsEmptyMask() const {
        return Mask.Empty();
    }

    size_t CalcSerializedSize() {
        if (!CountOfOptional || Mask.Empty()) {
            return 1ULL; // One byte for size=0
        }

        const size_t usedBits = Mask.ValueBitCount();
        const size_t usedBytes = (usedBits + 7ULL) >> 3ULL;
        return GetPack64Length(usedBytes) + usedBytes;
    }

    template<typename TBuf>
    void Serialize(TBuf& buf) const {
        if (!CountOfOptional || Mask.Empty()) {
            return buf.Append(0);
        }

        const size_t usedBits = Mask.ValueBitCount();
        const size_t usedBytes = (usedBits + 7ULL) >> 3ULL;
        buf.Advance(MAX_PACKED64_SIZE);
        // Note: usage of Pack64() is safe here - it won't overwrite useful data for small values of usedBytes
        buf.EraseBack(MAX_PACKED64_SIZE - Pack64(usedBytes, buf.Pos() - MAX_PACKED64_SIZE));
        buf.Append(reinterpret_cast<const char*>(Mask.GetChunks()), usedBytes);
    }

private:
    ui32 CountOfOptional = 0U;
    TBitMapOps<TDynamicBitMapTraits<ui8>> Mask;
};

} // NDetails
}
}