C/C++ API Reference
Loading...
Searching...
No Matches
persistent.h
1// Copyright 2021 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstdint>
17#include <cstring>
18#include <new>
19#include <type_traits>
20#include <utility>
21
22#include "pw_assert/assert.h"
23#include "pw_checksum/crc16_ccitt.h"
24#include "pw_preprocessor/compiler.h"
25#include "pw_span/span.h"
26
29
31
32// Behavior to use when attempting to get a handle to the underlying data stored
33// in persistent memory.
34enum class GetterAction {
35 // Default-construct the object before returning a handle.
36 kReset,
37 // Assert that the object is valid before returning a handle.
38 kAssertValid,
39};
40
41// The Persistent class intentionally uses uninitialized memory, which triggers
42// compiler warnings. Disable those warnings for this file.
44PW_MODIFY_DIAGNOSTIC(ignored, "-Wuninitialized");
45PW_MODIFY_DIAGNOSTIC_GCC(ignored, "-Wmaybe-uninitialized");
46
57template <typename T>
59 public:
60 // This object provides mutable access to the underlying object of a
61 // Persistent<T>.
62 //
63 // WARNING: This object must remain in scope for any modifications of the
64 // Underlying object. If the object is modified after the Mutator goes out
65 // of scope, the CRC will not be updated to reflect changes, invalidating the
66 // contents of the Persistent<T>!
67 //
68 // WARNING: Persistent<T>::has_value() will return false if there are
69 // in-flight modifications by a Mutator that have not yet been flushed.
70 class Mutator {
71 public:
72 explicit constexpr Mutator(Persistent<T>& persistent)
73 : persistent_(persistent) {}
74 ~Mutator() { persistent_.crc_ = persistent_.CalculateCrc(); }
75
76 Mutator(const Mutator&) = delete; // Copy constructor is disabled.
77
78 T* operator->() { return const_cast<T*>(&persistent_.contents_); }
79
80 // Be careful when sharing a reference or pointer to the underlying object.
81 // Once the Mutator goes out of scope, any changes to the object will
82 // invalidate the checksum. Avoid directly using the underlying object
83 // unless you need to pass it to a function.
84 T& value() { return persistent_.contents_; }
85 T& operator*() { return *const_cast<T*>(&persistent_.contents_); }
86
87 private:
88 Persistent<T>& persistent_;
89 };
90
91 // Constructor which does nothing, meaning it never sets the value.
92 constexpr Persistent() {}
93
94 Persistent(const Persistent&) = delete; // Copy constructor is disabled.
95 Persistent(Persistent&&) = delete; // Move constructor is disabled.
96 ~Persistent() {} // The destructor does nothing.
97
98 // Construct the value in-place.
99 template <class... Args>
100 const T& emplace(Args&&... args) {
101 new (const_cast<T*>(&contents_)) T(std::forward<Args>(args)...);
102 crc_ = CalculateCrc();
103 return const_cast<T&>(contents_);
104 }
105
106 // Assignment operator.
107 template <typename U = T>
108 Persistent& operator=(U&& value) {
109 contents_ = std::forward<U>(value);
110 crc_ = CalculateCrc();
111 return *this;
112 }
113
114 // Destroys any contained value.
115 void Invalidate() {
116 // The trivial destructor is skipped as it's trivial.
117 std::memset(const_cast<T*>(&contents_), 0, sizeof(contents_));
118 crc_ = 0;
119 }
120
121 // This is deprecated, use Invalidate() instead.
122 [[deprecated]] void reset() { Invalidate(); }
123
124 // Returns true if a value is held by the Persistent.
125 bool has_value() const {
126 return crc_ == CalculateCrc(); // There's a value if its CRC matches.
127 }
128
129 // Access the value.
130 //
131 // Precondition: has_value() must be true.
132 const T& value() const {
133 PW_ASSERT(has_value());
134 return const_cast<T&>(contents_);
135 }
136
137 // Get a mutable handle to the underlying data.
138 //
139 // Args:
140 // action: Whether to default-construct the underlying value before
141 // providing a mutator, or to assert that the object is valid
142 // without modifying the underlying data.
143 // Precondition: has_value() must be true.
144 Mutator mutator(GetterAction action = GetterAction::kAssertValid) {
145 if (action == GetterAction::kReset) {
146 emplace();
147 } else {
148 PW_ASSERT(has_value());
149 }
150 return Mutator(*this);
151 }
152
153 private:
154 friend class Mutator;
155
156 static_assert(std::is_trivially_copy_constructible<T>::value,
157 "If a Persistent persists across reboots, it is effectively "
158 "loaded through a trivial copy constructor.");
159
160 static_assert(std::is_trivially_destructible<T>::value,
161 "A Persistent's destructor does not invoke the value's "
162 "destructor, ergo only trivially destructible types are "
163 "supported.");
164
165 uint16_t CalculateCrc() const {
166 return checksum::Crc16Ccitt::Calculate(
167 as_bytes(span(const_cast<const T*>(&contents_), 1)));
168 }
169
170 // Use unions to denote that these members are never initialized by design and
171 // on purpose. Volatile is used to ensure that the compiler cannot optimize
172 // out operations where it seems like there is no further usage of a
173 // Persistent as this may be on the next boot.
174 union {
175 volatile T contents_;
176 };
177 union {
178 volatile uint16_t crc_;
179 };
180};
181
183
184} // namespace pw::persistent_ram
Definition: persistent.h:70
Definition: persistent.h:58
#define PW_MODIFY_DIAGNOSTICS_POP()
Definition: compiler.h:194
#define PW_MODIFY_DIAGNOSTIC(kind, option)
Definition: compiler.h:203
#define PW_MODIFY_DIAGNOSTIC_GCC(kind, option)
Definition: compiler.h:211
#define PW_MODIFY_DIAGNOSTICS_PUSH()
Definition: compiler.h:189
Persistent RAM utilities and containers.
Definition: persistent.h:28