aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/scheme/scimpl_private.h
blob: b92badabde14c9d8c8f9aa53e8c00e52d241e631 (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
#pragma once

#include "scheme.h"

#include <util/thread/singleton.h>

namespace NSc {
    namespace NImpl {
        template <typename TContext>
        static inline TContext& GetTlsInstance() {
            return *FastTlsSingleton<TContext>();
        }

        template <typename TContext>
        class TContextGuard : TNonCopyable {
            using TElement = typename TContext::TElement;
            using TTarget = typename TContext::TTarget;
            using TVectorType = TVector<TElement>;

        public:
            TContextGuard(TContext& ctx, TTarget& target)
                : Ctx(ctx)
                , Active(TContext::Needed(target))
            {
                if (Active) {
                    Begin = Ctx.Vector.size();
                    Ok = Ctx.Process(target);
                    End = Ctx.Vector.size();
                }
            }

            ~TContextGuard() noexcept {
                if (Active) {
                    Ctx.Vector.resize(Begin);
                }
            }

            const TVectorType& GetVector() const {
                return Ctx.Vector;
            }

            using const_iterator = size_t;

            size_t begin() const {
                return Begin;
            }

            size_t end() const {
                return End;
            }

            bool Ok = true;

        private:
            TContext& Ctx;
            size_t Begin = 0;
            size_t End = 0;
            bool Active = false;
        };

        template <typename TElem, typename TTgt>
        class TBasicContext {
        public:
            using TElement = TElem;
            using TTarget = TTgt;

            TBasicContext() {
                Vector.reserve(64);
            }

            TVector<TElement> Vector;
        };

        class TKeySortContext: public TBasicContext<TStringBuf, const TDict> {
        public:
            using TGuard = TContextGuard<TKeySortContext>;

            bool Process(const TDict& self);

            static bool Needed(const TDict& self) {
                return self.size();
            }
        };

        class TSelfOverrideContext: public TBasicContext<TValue, TValue::TScCore> {
        public:
            using TGuard = TContextGuard<TSelfOverrideContext>;

            bool Process(TValue::TScCore& self);

            static bool Needed(const TValue::TScCore& self) {
                return self.HasChildren();
            }
        };

        class TSelfLoopContext: public TBasicContext<const void*, const TValue::TScCore> {
        public:
            enum class EMode {
                Assert, Throw, Abort, Stderr
            };

            using TGuard = TContextGuard<TSelfLoopContext>;

            bool Process(const TValue::TScCore& self);

            static bool Needed(const TValue::TScCore& self) {
                return self.HasChildren();
            }

        public:
            EMode ReportingMode = EMode::Assert;
        };
    }
}