aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/monlib/metrics/labels.h
blob: 63dc997c28067749294971fcf8c8827067b5d36a (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
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
#pragma once

#include <util/digest/multi.h>
#include <util/digest/sequence.h>
#include <util/generic/algorithm.h>
#include <util/generic/maybe.h>
#include <util/generic/string.h>
#include <util/generic/vector.h>
#include <util/stream/output.h>
#include <util/string/builder.h>
#include <util/string/strip.h>

#include <optional>
#include <type_traits>

namespace NMonitoring {
    struct ILabel {
        virtual ~ILabel() = default;

        virtual TStringBuf Name() const noexcept = 0;
        virtual TStringBuf Value() const noexcept = 0;
    };

    ///////////////////////////////////////////////////////////////////////////
    // TLabel
    ///////////////////////////////////////////////////////////////////////////
    template <typename TStringBackend>
    class TLabelImpl: public ILabel {
    public:
        using TStringType = TStringBackend;

        TLabelImpl() = default;

        inline TLabelImpl(TStringBuf name, TStringBuf value)
            : Name_{name}
            , Value_{value}
        {
        }

        inline bool operator==(const TLabelImpl& rhs) const noexcept {
            return Name_ == rhs.Name_ && Value_ == rhs.Value_;
        }

        inline bool operator!=(const TLabelImpl& rhs) const noexcept {
            return !(*this == rhs);
        }

        inline TStringBuf Name() const noexcept {
            return Name_;
        }

        inline TStringBuf Value() const noexcept {
            return Value_;
        }

        inline const TStringBackend& NameStr() const {
            return Name_;
        }

        inline const TStringBackend& ValueStr() const {
            return Value_;
        }

        inline size_t Hash() const noexcept {
            return MultiHash(Name_, Value_);
        }

        TStringBackend ToString() const {
            TStringBackend buf = Name_;
            buf += '=';
            buf += Value_;

            return buf;
        }

        static TLabelImpl FromString(TStringBuf str) {
            TStringBuf name, value;
            Y_ENSURE(str.TrySplit('=', name, value),
                     "invalid label string format: '" << str << '\'');

            TStringBuf nameStripped = StripString(name);
            Y_ENSURE(!nameStripped.empty(), "label name cannot be empty");

            TStringBuf valueStripped = StripString(value);
            Y_ENSURE(!valueStripped.empty(), "label value cannot be empty");

            return {nameStripped, valueStripped};
        }

        static bool TryFromString(TStringBuf str, TLabelImpl& label) {
            TStringBuf name, value;
            if (!str.TrySplit('=', name, value)) {
                return false;
            }

            TStringBuf nameStripped = StripString(name);
            if (nameStripped.empty()) {
                return false;
            }

            TStringBuf valueStripped = StripString(value);
            if (valueStripped.empty()) {
                return false;
            }

            label = {nameStripped, valueStripped};
            return true;
        }

    private:
        TStringBackend Name_;
        TStringBackend Value_;
    };

    using TLabel = TLabelImpl<TString>;

    struct ILabels {
        struct TIterator {
            TIterator() = default;
            TIterator(const ILabels* labels, size_t idx = 0)
                : Labels_{labels}
                , Idx_{idx}
            {
            }

            TIterator& operator++() noexcept {
                Idx_++;
                return *this;
            }

            void operator+=(size_t i) noexcept {
                Idx_ += i;
            }

            bool operator==(const TIterator& other) const noexcept {
                return Idx_ == other.Idx_;
            }

            bool operator!=(const TIterator& other) const noexcept {
                return !(*this == other);
            }

            const ILabel* operator->() const noexcept {
                Y_VERIFY_DEBUG(Labels_);
                return Labels_->Get(Idx_);
            }

            const ILabel& operator*() const noexcept {
                Y_VERIFY_DEBUG(Labels_);
                return *Labels_->Get(Idx_);
            }


        private:
            const ILabels* Labels_{nullptr};
            size_t Idx_{0};
        };

        virtual ~ILabels() = default;

        virtual bool Add(TStringBuf name, TStringBuf value) noexcept = 0;
        virtual bool Add(const ILabel& label) noexcept {
            return Add(label.Name(), label.Value());
        }

        virtual bool Has(TStringBuf name) const noexcept = 0;

        virtual size_t Size() const noexcept = 0;
        virtual bool Empty() const noexcept = 0;
        virtual void Clear() noexcept = 0;

        virtual size_t Hash() const noexcept = 0;

        virtual std::optional<const ILabel*> Get(TStringBuf name) const = 0;

        // NB: there's no guarantee that indices are preserved after any object modification
        virtual const ILabel* Get(size_t idx) const = 0;

        TIterator begin() const {
            return TIterator{this};
        }

        TIterator end() const {
            return TIterator{this, Size()};
        }
    };

    bool TryLoadLabelsFromString(TStringBuf sb, ILabels& labels);
    bool TryLoadLabelsFromString(IInputStream& is, ILabels& labels);

    ///////////////////////////////////////////////////////////////////////////
    // TLabels
    ///////////////////////////////////////////////////////////////////////////
    template <typename TStringBackend>
    class TLabelsImpl: public ILabels {
    public:
        using value_type = TLabelImpl<TStringBackend>;

        TLabelsImpl() = default;

        explicit TLabelsImpl(::NDetail::TReserveTag rt)
            : Labels_(std::move(rt))
        {}

        explicit TLabelsImpl(size_t count)
            : Labels_(count)
        {}

        explicit TLabelsImpl(size_t count, const value_type& label)
            : Labels_(count, label)
        {}

        TLabelsImpl(std::initializer_list<value_type> il)
            : Labels_(std::move(il))
        {}

        TLabelsImpl(const TLabelsImpl&) = default;
        TLabelsImpl& operator=(const TLabelsImpl&) = default;

        TLabelsImpl(TLabelsImpl&&) noexcept = default;
        TLabelsImpl& operator=(TLabelsImpl&&) noexcept = default;

        inline bool operator==(const TLabelsImpl& rhs) const {
            return Labels_ == rhs.Labels_;
        }

        inline bool operator!=(const TLabelsImpl& rhs) const {
            return Labels_ != rhs.Labels_;
        }

        bool Add(TStringBuf name, TStringBuf value) noexcept override {
            if (Has(name)) {
                return false;
            }

            Labels_.emplace_back(name, value);
            return true;
        }

        using ILabels::Add;

        bool Has(TStringBuf name) const noexcept override {
            auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) {
                return name == TStringBuf{label.Name()};
            });
            return it != Labels_.end();
        }

        bool Has(const TString& name) const noexcept {
            auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) {
                return name == TStringBuf{label.Name()};
            });
            return it != Labels_.end();
        }

        // XXX for backward compatibility
        TMaybe<TLabelImpl<TStringBackend>> Find(TStringBuf name) const {
            auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) {
                return name == TStringBuf{label.Name()};
            });
            if (it == Labels_.end()) {
                return Nothing();
            }
            return *it;
        }

        std::optional<const ILabel*> Get(TStringBuf name) const override {
            auto it = FindIf(Labels_, [name] (auto&& l) {
                return name == l.Name();
            });

            if (it == Labels_.end()) {
                return {};
            }

            return &*it;
        }

        const ILabel* Get(size_t idx) const noexcept override {
            return &(*this)[idx];
        }

        TMaybe<TLabelImpl<TStringBackend>> Extract(TStringBuf name) {
            auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) {
                return name == TStringBuf{label.Name()};
            });
            if (it == Labels_.end()) {
                return Nothing();
            }
            TLabel tmp = *it;
            Labels_.erase(it);
            return tmp;
        }

        void SortByName() {
            std::sort(Labels_.begin(), Labels_.end(), [](const auto& lhs, const auto& rhs) {
                return lhs.Name() < rhs.Name();
            });
        }

        inline size_t Hash() const noexcept override {
            return TSimpleRangeHash()(Labels_);
        }

        inline TLabel* Data() const noexcept {
            return const_cast<TLabel*>(Labels_.data());
        }

        inline size_t Size() const noexcept override {
            return Labels_.size();
        }

        inline bool Empty() const noexcept override {
            return Labels_.empty();
        }

        inline void Clear() noexcept override {
            Labels_.clear();
        };

        TLabelImpl<TStringBackend>& front() {
            return Labels_.front();
        }

        const TLabelImpl<TStringBackend>& front() const {
            return Labels_.front();
        }

        TLabelImpl<TStringBackend>& back() {
            return Labels_.back();
        }

        const TLabelImpl<TStringBackend>& back() const {
            return Labels_.back();
        }

        TLabelImpl<TStringBackend>& operator[](size_t index) {
            return Labels_[index];
        }

        const TLabelImpl<TStringBackend>& operator[](size_t index) const {
            return Labels_[index];
        }

        TLabelImpl<TStringBackend>& at(size_t index) {
            return Labels_.at(index);
        }

        const TLabelImpl<TStringBackend>& at(size_t index) const {
            return Labels_.at(index);
        }

        size_t capacity() const {
            return Labels_.capacity();
        }

        TLabelImpl<TStringBackend>* data() {
            return Labels_.data();
        }

        const TLabelImpl<TStringBackend>* data() const {
            return Labels_.data();
        }

        size_t size() const {
            return Labels_.size();
        }

        bool empty() const {
            return Labels_.empty();
        }

        void clear() {
            Labels_.clear();
        }

        using ILabels::begin;
        using ILabels::end;

        using iterator = ILabels::TIterator;
        using const_iterator = iterator;

    protected:
        TVector<TLabelImpl<TStringBackend>>& AsVector() {
            return Labels_;
        }

        const TVector<TLabelImpl<TStringBackend>>& AsVector() const {
            return Labels_;
        }

    private:
        TVector<TLabelImpl<TStringBackend>> Labels_;
    };

    using TLabels = TLabelsImpl<TString>;
    using ILabelsPtr = THolder<ILabels>;

    template <typename T>
    ILabelsPtr MakeLabels() {
        return MakeHolder<TLabelsImpl<T>>();
    }

    template <typename T>
    ILabelsPtr MakeLabels(std::initializer_list<TLabelImpl<T>> labels) {
        return MakeHolder<TLabelsImpl<T>>(labels);
    }

    inline ILabelsPtr MakeLabels(TLabels&& labels) {
        return MakeHolder<TLabels>(std::move(labels));
    }
}

template<>
struct THash<NMonitoring::ILabelsPtr> {
    size_t operator()(const NMonitoring::ILabelsPtr& labels) const noexcept {
        return labels->Hash();
    }

    size_t operator()(const NMonitoring::ILabels& labels) const noexcept {
        return labels.Hash();
    }
};

template<typename TStringBackend>
struct THash<NMonitoring::TLabelsImpl<TStringBackend>> {
    size_t operator()(const NMonitoring::TLabelsImpl<TStringBackend>& labels) const noexcept {
        return labels.Hash();
    }
};

template <typename TStringBackend>
struct THash<NMonitoring::TLabelImpl<TStringBackend>> {
    inline size_t operator()(const NMonitoring::TLabelImpl<TStringBackend>& label) const noexcept {
        return label.Hash();
    }
};

inline bool operator==(const NMonitoring::ILabels& lhs, const NMonitoring::ILabels& rhs) {
    if (lhs.Size() != rhs.Size()) {
        return false;
    }

    for (auto&& l : lhs) {
        auto rl = rhs.Get(l.Name());
        if (!rl || (*rl)->Value() != l.Value()) {
            return false;
        }
    }

    return true;
}

bool operator==(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabelsPtr& rhs) = delete;
bool operator==(const NMonitoring::ILabels& lhs, const NMonitoring::ILabelsPtr& rhs) = delete;
bool operator==(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabels& rhs) = delete;

template<>
struct TEqualTo<NMonitoring::ILabelsPtr> {
    bool operator()(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabelsPtr& rhs) {
        return *lhs == *rhs;
    }

    bool operator()(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabels& rhs) {
        return *lhs == rhs;
    }

    bool operator()(const NMonitoring::ILabels& lhs, const NMonitoring::ILabelsPtr& rhs) {
        return lhs == *rhs;
    }
};

#define Y_MONLIB_DEFINE_LABELS_OUT(T) \
template <> \
void Out<T>(IOutputStream& out, const T& labels) { \
    Out<NMonitoring::ILabels>(out, labels); \
}

#define Y_MONLIB_DEFINE_LABEL_OUT(T) \
template <> \
void Out<T>(IOutputStream& out, const T& label) { \
    Out<NMonitoring::ILabel>(out, label); \
}