Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2024 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 : #pragma once
19 :
20 : namespace chip {
21 :
22 : template <typename T>
23 : class ScopedChange;
24 :
25 : /// Allows a value to only be changed within a scope.
26 : ///
27 : /// Generally used to force determinism for unit test execution.
28 : ///
29 : /// When a variable of this type is used, it should
30 : /// only be changed via `ScopedChange`.
31 : template <typename T>
32 : class ScopedChangeOnly
33 : {
34 : public:
35 60 : explicit ScopedChangeOnly(T initial) : mValue(initial) {}
36 42 : operator T() const { return mValue; }
37 :
38 : private:
39 : T mValue;
40 :
41 : // Expected to be used only by ScopedChange<T> only
42 20 : T & InternalMutableValue() { return mValue; }
43 : friend class ScopedChange<T>;
44 : };
45 :
46 : /// Allows a scoped mutation to occur on a variable.
47 : ///
48 : /// When an instance of this class goes out of scope, the variable
49 : /// will be reset to the value id had before the scoped change came
50 : /// into effect.
51 : ///
52 : /// While the ScopedChange is in scope it can be used to make changes
53 : /// to the underlying value using the assignment operator.
54 : ///
55 : /// Example usage:
56 : ///
57 : /// int a = 123;
58 : /// ScopedChangeOnly<int> b(234);
59 : ///
60 : /// /* a == 123, b == 234 */
61 : /// {
62 : /// ScopedChange changeA(a, 321);
63 : /// /* a == 321, b == 234 */
64 : /// {
65 : /// ScopedChange changeB(b, 10);
66 : /// /* a == 321, b == 10 */
67 : /// }
68 : /// /* a == 321, b == 234 */
69 : /// changeA = 333; // assignments within the ScopedChange are allowed
70 : /// /* a == 333, b == 234 */
71 : /// }
72 : /// /* a == 123, b == 234 */
73 : ///
74 : template <typename T>
75 : class ScopedChange
76 : {
77 : public:
78 20 : ScopedChange(ScopedChangeOnly<T> & what) : mValue(what.InternalMutableValue()), mOriginal(what) {}
79 20 : ScopedChange(ScopedChangeOnly<T> & what, T value) : ScopedChange(what) { mValue = value; }
80 :
81 : ScopedChange(T & what) : mValue(what), mOriginal(what) {}
82 : ScopedChange(T & what, T value) : ScopedChange(what) { mValue = value; }
83 :
84 20 : ~ScopedChange() { mValue = mOriginal; }
85 :
86 : ScopedChange & operator=(T const & value)
87 : {
88 : mValue = value;
89 : return *this;
90 : }
91 :
92 : operator T() const { return mValue; }
93 :
94 : private:
95 : T & mValue;
96 : T mOriginal;
97 : };
98 :
99 : } // namespace chip
|