Skip to content

Commit dfe64ee

Browse files
andy31415andreilitvinbzbarsky-apple
authored
Use std::optional for chip::Nullable (#33080)
* make nullable depend on std::optional instead of chip::optional * Fix equality operator * Fix inequality operator as well * Fix test: previous code was enforcing chip::optional behavior on in-place construction * Restyle * Fix some compile errors ... std::optional now detects unused variables * Restyle * Remove unused variable * Restyle * Review updates * Review fix * Typo fixes * Ugly forward of Value and ValueOr .... however at least hopefully it is complete * Do not expose value/value_or at this time and keep Value/ValueOr as the public API for nullable * Fix copy and paste typo * Make more changes to make things compile and work like the old nullable * Use value again instead of operator** ... I was looking at the wrong compiler errors * Undo unrelated change * Make clang-tidy be abel to compile ... apparently it really does not like using has_value in equality operators * Restyle * Another update to make clang-tidy happy for the other equality operator * Update src/app/data-model/Nullable.h Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Undo odd whitespace change --------- Co-authored-by: Andrei Litvin <andreilitvin@google.com> Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent 9eb2e29 commit dfe64ee

File tree

3 files changed

+49
-32
lines changed

3 files changed

+49
-32
lines changed

src/app/clusters/valve-configuration-and-control-server/valve-configuration-and-control-server.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,7 @@ Delegate * GetDefaultDelegate(EndpointId endpoint)
277277

278278
CHIP_ERROR CloseValve(EndpointId ep)
279279
{
280-
Delegate * delegate = GetDelegate(ep);
281-
DataModel::Nullable<uint32_t> rDuration;
280+
Delegate * delegate = GetDelegate(ep);
282281
CHIP_ERROR attribute_error = CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);
283282

284283
VerifyOrReturnError(Status::Success == TargetState::Set(ep, ValveConfigurationAndControl::ValveStateEnum::kClosed),
@@ -309,10 +308,8 @@ CHIP_ERROR CloseValve(EndpointId ep)
309308

310309
CHIP_ERROR SetValveLevel(EndpointId ep, DataModel::Nullable<Percent> level, DataModel::Nullable<uint32_t> openDuration)
311310
{
312-
Delegate * delegate = GetDelegate(ep);
313-
Optional<Status> status = Optional<Status>::Missing();
314-
DataModel::Nullable<Percent> openLevel;
315-
DataModel::Nullable<uint64_t> autoCloseTime;
311+
Delegate * delegate = GetDelegate(ep);
312+
Optional<Status> status = Optional<Status>::Missing();
316313
CHIP_ERROR attribute_error = CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);
317314

318315
if (HasFeature(ep, ValveConfigurationAndControl::Feature::kTimeSync))
@@ -328,6 +325,7 @@ CHIP_ERROR SetValveLevel(EndpointId ep, DataModel::Nullable<Percent> level, Data
328325
VerifyOrReturnError(UnixEpochToChipEpochMicros(utcTime.count(), chipEpochTime), CHIP_ERROR_INVALID_TIME);
329326

330327
uint64_t time = openDuration.Value() * chip::kMicrosecondsPerSecond;
328+
DataModel::Nullable<uint64_t> autoCloseTime;
331329
autoCloseTime.SetNonNull(chipEpochTime + time);
332330
VerifyOrReturnError(Status::Success == AutoCloseTime::Set(ep, autoCloseTime), attribute_error);
333331
}

src/app/data-model/Nullable.h

+30-17
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
#pragma once
2020

2121
#include <app/util/attribute-storage-null-handling.h>
22-
#include <lib/core/Optional.h>
23-
22+
#include <optional>
2423
#include <type_traits>
24+
#include <utility>
2525

2626
namespace chip {
2727
namespace app {
@@ -37,31 +37,40 @@ inline constexpr auto NullNullable = NullOptional;
3737
* things.
3838
*/
3939
template <typename T>
40-
struct Nullable : protected Optional<T>
40+
struct Nullable : protected std::optional<T>
4141
{
42+
4243
//
4344
// The following 'using' statement is needed to make visible
4445
// all constructors of the base class within this derived class.
4546
//
46-
using Optional<T>::Optional;
47+
using std::optional<T>::optional;
48+
using std::optional<T>::operator*;
49+
using std::optional<T>::operator->;
4750

48-
// Pull in APIs that make sense on Nullable with the same names as on
49-
// Optional.
50-
using Optional<T>::Value;
51-
using Optional<T>::ValueOr;
51+
Nullable(NullOptionalType) : std::optional<T>(std::nullopt) {}
5252

5353
// Some consumers need an easy way to determine our underlying type.
5454
using UnderlyingType = T;
5555

56-
constexpr void SetNull() { Optional<T>::ClearValue(); }
57-
constexpr bool IsNull() const { return !Optional<T>::HasValue(); }
56+
constexpr void SetNull() { std::optional<T>::reset(); }
57+
constexpr bool IsNull() const { return !std::optional<T>::has_value(); }
5858

5959
template <class... Args>
6060
constexpr T & SetNonNull(Args &&... args)
6161
{
62-
return Optional<T>::Emplace(std::forward<Args>(args)...);
62+
return std::optional<T>::emplace(std::forward<Args>(args)...);
63+
}
64+
65+
template <typename... Args>
66+
constexpr auto ValueOr(Args &&... args) const
67+
{
68+
return std::optional<T>::value_or(std::forward<Args>(args)...);
6369
}
6470

71+
inline constexpr const T & Value() const { return std::optional<T>::value(); }
72+
inline T & Value() { return std::optional<T>::value(); }
73+
6574
// For integer types, being nullable involves a range restriction.
6675
template <
6776
typename U = std::decay_t<T>,
@@ -96,22 +105,26 @@ struct Nullable : protected Optional<T>
96105
// The only fabric-scoped objects in the spec are commands, events and structs inside lists, and none of those can be nullable.
97106
static constexpr bool kIsFabricScoped = false;
98107

99-
bool operator==(const Nullable & other) const { return Optional<T>::operator==(other); }
100-
bool operator!=(const Nullable & other) const { return Optional<T>::operator!=(other); }
101-
bool operator==(const T & other) const { return Optional<T>::operator==(other); }
102-
bool operator!=(const T & other) const { return Optional<T>::operator!=(other); }
108+
inline bool operator==(const T & other) const { return static_cast<const std::optional<T> &>(*this) == other; }
109+
inline bool operator!=(const T & other) const { return !(*this == other); }
110+
111+
inline bool operator==(const Nullable<T> & other) const
112+
{
113+
return static_cast<const std::optional<T> &>(*this) == static_cast<const std::optional<T> &>(other);
114+
}
115+
inline bool operator!=(const Nullable<T> & other) const { return !(*this == other); }
103116
};
104117

105118
template <class T>
106119
constexpr Nullable<std::decay_t<T>> MakeNullable(T && value)
107120
{
108-
return Nullable<std::decay_t<T>>(InPlace, std::forward<T>(value));
121+
return Nullable<std::decay_t<T>>(std::in_place, std::forward<T>(value));
109122
}
110123

111124
template <class T, class... Args>
112125
constexpr Nullable<T> MakeNullable(Args &&... args)
113126
{
114-
return Nullable<T>(InPlace, std::forward<Args>(args)...);
127+
return Nullable<T>(std::in_place, std::forward<Args>(args)...);
115128
}
116129

117130
} // namespace DataModel

src/app/tests/TestNullable.cpp

+15-9
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct CtorDtorCounter
4545
CtorDtorCounter & operator=(CtorDtorCounter &&) = default;
4646

4747
bool operator==(const CtorDtorCounter & o) const { return m == o.m; }
48+
bool operator!=(const CtorDtorCounter & o) const { return m != o.m; }
4849

4950
int m;
5051

@@ -68,6 +69,9 @@ struct MovableCtorDtorCounter : public CtorDtorCounter
6869

6970
MovableCtorDtorCounter(MovableCtorDtorCounter && o) = default;
7071
MovableCtorDtorCounter & operator=(MovableCtorDtorCounter &&) = default;
72+
73+
using CtorDtorCounter::operator==;
74+
using CtorDtorCounter::operator!=;
7175
};
7276

7377
int CtorDtorCounter::created = 0;
@@ -165,24 +169,26 @@ static void TestMove(nlTestSuite * inSuite, void * inContext)
165169
CtorDtorCounter::ResetCounter();
166170

167171
{
168-
auto testSrc = MakeNullable<MovableCtorDtorCounter>(400);
169-
Nullable<MovableCtorDtorCounter> testDst(std::move(testSrc));
170-
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 1);
172+
auto testSrc = MakeNullable<MovableCtorDtorCounter>(400); // construct
173+
Nullable<MovableCtorDtorCounter> testDst(std::move(testSrc)); // move construct
174+
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 0);
171175
NL_TEST_ASSERT(inSuite, !testDst.IsNull() && testDst.Value().m == 400);
176+
// destroy both testsSrc and testDst
172177
}
173178
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 2);
174179

180+
CtorDtorCounter::ResetCounter();
175181
{
176-
Nullable<MovableCtorDtorCounter> testDst;
177-
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 2);
182+
Nullable<MovableCtorDtorCounter> testDst; // no object construction
183+
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 0 && CtorDtorCounter::destroyed == 0);
178184
NL_TEST_ASSERT(inSuite, !!testDst.IsNull());
179185

180-
auto testSrc = MakeNullable<MovableCtorDtorCounter>(401);
181-
testDst = std::move(testSrc);
182-
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 4 && CtorDtorCounter::destroyed == 3);
186+
auto testSrc = MakeNullable<MovableCtorDtorCounter>(401); // construct object
187+
testDst = std::move(testSrc); // construct a copy
188+
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 0);
183189
NL_TEST_ASSERT(inSuite, !testDst.IsNull() && testDst.Value().m == 401);
184190
}
185-
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 4 && CtorDtorCounter::destroyed == 4);
191+
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 2);
186192
}
187193

188194
static void TestUpdate(nlTestSuite * inSuite, void * inContext)

0 commit comments

Comments
 (0)