diff --git a/src/app/clusters/valve-configuration-and-control-server/valve-configuration-and-control-server.cpp b/src/app/clusters/valve-configuration-and-control-server/valve-configuration-and-control-server.cpp index 82dd45464cfde4..02486beea315a4 100644 --- a/src/app/clusters/valve-configuration-and-control-server/valve-configuration-and-control-server.cpp +++ b/src/app/clusters/valve-configuration-and-control-server/valve-configuration-and-control-server.cpp @@ -277,8 +277,7 @@ Delegate * GetDefaultDelegate(EndpointId endpoint) CHIP_ERROR CloseValve(EndpointId ep) { - Delegate * delegate = GetDelegate(ep); - DataModel::Nullable rDuration; + Delegate * delegate = GetDelegate(ep); CHIP_ERROR attribute_error = CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute); VerifyOrReturnError(Status::Success == TargetState::Set(ep, ValveConfigurationAndControl::ValveStateEnum::kClosed), @@ -309,10 +308,8 @@ CHIP_ERROR CloseValve(EndpointId ep) CHIP_ERROR SetValveLevel(EndpointId ep, DataModel::Nullable level, DataModel::Nullable openDuration) { - Delegate * delegate = GetDelegate(ep); - Optional status = Optional::Missing(); - DataModel::Nullable openLevel; - DataModel::Nullable autoCloseTime; + Delegate * delegate = GetDelegate(ep); + Optional status = Optional::Missing(); CHIP_ERROR attribute_error = CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute); if (HasFeature(ep, ValveConfigurationAndControl::Feature::kTimeSync)) @@ -328,6 +325,7 @@ CHIP_ERROR SetValveLevel(EndpointId ep, DataModel::Nullable level, Data VerifyOrReturnError(UnixEpochToChipEpochMicros(utcTime.count(), chipEpochTime), CHIP_ERROR_INVALID_TIME); uint64_t time = openDuration.Value() * chip::kMicrosecondsPerSecond; + DataModel::Nullable autoCloseTime; autoCloseTime.SetNonNull(chipEpochTime + time); VerifyOrReturnError(Status::Success == AutoCloseTime::Set(ep, autoCloseTime), attribute_error); } diff --git a/src/app/data-model/Nullable.h b/src/app/data-model/Nullable.h index cea3dea5b5361b..f56e67ced19113 100644 --- a/src/app/data-model/Nullable.h +++ b/src/app/data-model/Nullable.h @@ -19,9 +19,9 @@ #pragma once #include -#include - +#include #include +#include namespace chip { namespace app { @@ -37,31 +37,40 @@ inline constexpr auto NullNullable = NullOptional; * things. */ template -struct Nullable : protected Optional +struct Nullable : protected std::optional { + // // The following 'using' statement is needed to make visible // all constructors of the base class within this derived class. // - using Optional::Optional; + using std::optional::optional; + using std::optional::operator*; + using std::optional::operator->; - // Pull in APIs that make sense on Nullable with the same names as on - // Optional. - using Optional::Value; - using Optional::ValueOr; + Nullable(NullOptionalType) : std::optional(std::nullopt) {} // Some consumers need an easy way to determine our underlying type. using UnderlyingType = T; - constexpr void SetNull() { Optional::ClearValue(); } - constexpr bool IsNull() const { return !Optional::HasValue(); } + constexpr void SetNull() { std::optional::reset(); } + constexpr bool IsNull() const { return !std::optional::has_value(); } template constexpr T & SetNonNull(Args &&... args) { - return Optional::Emplace(std::forward(args)...); + return std::optional::emplace(std::forward(args)...); + } + + template + constexpr auto ValueOr(Args &&... args) const + { + return std::optional::value_or(std::forward(args)...); } + inline constexpr const T & Value() const { return std::optional::value(); } + inline T & Value() { return std::optional::value(); } + // For integer types, being nullable involves a range restriction. template < typename U = std::decay_t, @@ -96,22 +105,26 @@ struct Nullable : protected Optional // The only fabric-scoped objects in the spec are commands, events and structs inside lists, and none of those can be nullable. static constexpr bool kIsFabricScoped = false; - bool operator==(const Nullable & other) const { return Optional::operator==(other); } - bool operator!=(const Nullable & other) const { return Optional::operator!=(other); } - bool operator==(const T & other) const { return Optional::operator==(other); } - bool operator!=(const T & other) const { return Optional::operator!=(other); } + inline bool operator==(const T & other) const { return static_cast &>(*this) == other; } + inline bool operator!=(const T & other) const { return !(*this == other); } + + inline bool operator==(const Nullable & other) const + { + return static_cast &>(*this) == static_cast &>(other); + } + inline bool operator!=(const Nullable & other) const { return !(*this == other); } }; template constexpr Nullable> MakeNullable(T && value) { - return Nullable>(InPlace, std::forward(value)); + return Nullable>(std::in_place, std::forward(value)); } template constexpr Nullable MakeNullable(Args &&... args) { - return Nullable(InPlace, std::forward(args)...); + return Nullable(std::in_place, std::forward(args)...); } } // namespace DataModel diff --git a/src/app/tests/TestNullable.cpp b/src/app/tests/TestNullable.cpp index c1290c1a0cef66..660037339d44e1 100644 --- a/src/app/tests/TestNullable.cpp +++ b/src/app/tests/TestNullable.cpp @@ -45,6 +45,7 @@ struct CtorDtorCounter CtorDtorCounter & operator=(CtorDtorCounter &&) = default; bool operator==(const CtorDtorCounter & o) const { return m == o.m; } + bool operator!=(const CtorDtorCounter & o) const { return m != o.m; } int m; @@ -68,6 +69,9 @@ struct MovableCtorDtorCounter : public CtorDtorCounter MovableCtorDtorCounter(MovableCtorDtorCounter && o) = default; MovableCtorDtorCounter & operator=(MovableCtorDtorCounter &&) = default; + + using CtorDtorCounter::operator==; + using CtorDtorCounter::operator!=; }; int CtorDtorCounter::created = 0; @@ -165,24 +169,26 @@ static void TestMove(nlTestSuite * inSuite, void * inContext) CtorDtorCounter::ResetCounter(); { - auto testSrc = MakeNullable(400); - Nullable testDst(std::move(testSrc)); - NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 1); + auto testSrc = MakeNullable(400); // construct + Nullable testDst(std::move(testSrc)); // move construct + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 0); NL_TEST_ASSERT(inSuite, !testDst.IsNull() && testDst.Value().m == 400); + // destroy both testsSrc and testDst } NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 2); + CtorDtorCounter::ResetCounter(); { - Nullable testDst; - NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 2); + Nullable testDst; // no object construction + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 0 && CtorDtorCounter::destroyed == 0); NL_TEST_ASSERT(inSuite, !!testDst.IsNull()); - auto testSrc = MakeNullable(401); - testDst = std::move(testSrc); - NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 4 && CtorDtorCounter::destroyed == 3); + auto testSrc = MakeNullable(401); // construct object + testDst = std::move(testSrc); // construct a copy + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 0); NL_TEST_ASSERT(inSuite, !testDst.IsNull() && testDst.Value().m == 401); } - NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 4 && CtorDtorCounter::destroyed == 4); + NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 2); } static void TestUpdate(nlTestSuite * inSuite, void * inContext)