Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use std::optional for chip::Nullable #33080

Merged
merged 25 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
963d89a
make nullable depend on std::optional instead of chip::optional
andreilitvin Apr 19, 2024
86ab8f1
Fix equality operator
andreilitvin Apr 19, 2024
39c351f
Fix inequality operator as well
andreilitvin Apr 19, 2024
93e5331
Fix test: previous code was enforcing chip::optional behavior on in-p…
andreilitvin Apr 19, 2024
773136d
Restyle
andreilitvin Apr 19, 2024
fc7b2bd
Fix some compile errors ... std::optional now detects unused variables
andreilitvin Apr 19, 2024
4af74df
Restyle
andreilitvin Apr 19, 2024
0879c6c
Remove unused variable
andreilitvin Apr 19, 2024
48635c4
Restyle
andreilitvin Apr 19, 2024
bc029ad
Review updates
andreilitvin Apr 19, 2024
4b0e5d9
Review fix
andreilitvin Apr 19, 2024
810758c
Typo fixes
andreilitvin Apr 19, 2024
f113924
Ugly forward of Value and ValueOr .... however at least hopefully it …
andreilitvin Apr 19, 2024
e0d00a0
Do not expose value/value_or at this time and keep Value/ValueOr as t…
andreilitvin Apr 23, 2024
aef95c1
Fix copy and paste typo
andreilitvin Apr 23, 2024
589cf12
Make more changes to make things compile and work like the old nullable
andreilitvin Apr 23, 2024
569f7ca
Use value again instead of operator** ... I was looking at the wrong …
andreilitvin Apr 23, 2024
736d9e6
Undo unrelated change
andreilitvin Apr 23, 2024
b3cc106
Make clang-tidy be abel to compile ... apparently it really does not …
andreilitvin Apr 23, 2024
f8d8b3b
Restyle
andreilitvin Apr 23, 2024
4796bf6
Another update to make clang-tidy happy for the other equality operator
andreilitvin Apr 23, 2024
e846720
Merge branch 'master' into nullable_is_std_optional
andy31415 Apr 25, 2024
9bb289e
Update src/app/data-model/Nullable.h
andy31415 Apr 29, 2024
90508ee
Merge branch 'master' into nullable_is_std_optional
andy31415 Apr 29, 2024
25055dd
Undo odd whitespace change
andy31415 Apr 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/app/clusters/ota-requestor/ota-requestor-server.cpp
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ Status OtaRequestorServerGetUpdateState(chip::EndpointId endpointId, OTAUpdateSt
Status OtaRequestorServerSetUpdateStateProgress(app::DataModel::Nullable<uint8_t> value)
{
Status status = Status::Success;

// Find all endpoints that have OtaSoftwareUpdateRequestor implemented
for (auto endpoint : EnabledEndpointsWithServerCluster(OtaSoftwareUpdateRequestor::Id))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,7 @@ Delegate * GetDefaultDelegate(EndpointId endpoint)

CHIP_ERROR CloseValve(EndpointId ep)
{
Delegate * delegate = GetDelegate(ep);
DataModel::Nullable<uint32_t> rDuration;
Delegate * delegate = GetDelegate(ep);
CHIP_ERROR attribute_error = CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);

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

CHIP_ERROR SetValveLevel(EndpointId ep, DataModel::Nullable<Percent> level, DataModel::Nullable<uint32_t> openDuration)
{
Delegate * delegate = GetDelegate(ep);
Optional<Status> status = Optional<Status>::Missing();
DataModel::Nullable<Percent> openLevel;
DataModel::Nullable<uint64_t> autoCloseTime;
Delegate * delegate = GetDelegate(ep);
Optional<Status> status = Optional<Status>::Missing();
CHIP_ERROR attribute_error = CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute);

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

uint64_t time = openDuration.Value() * chip::kMicrosecondsPerSecond;
DataModel::Nullable<uint64_t> autoCloseTime;
autoCloseTime.SetNonNull(chipEpochTime + time);
VerifyOrReturnError(Status::Success == AutoCloseTime::Set(ep, autoCloseTime), attribute_error);
}
Expand Down
47 changes: 30 additions & 17 deletions src/app/data-model/Nullable.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
#pragma once

#include <app/util/attribute-storage-null-handling.h>
#include <lib/core/Optional.h>

#include <optional>
#include <type_traits>
#include <utility>

namespace chip {
namespace app {
Expand All @@ -37,31 +37,40 @@ inline constexpr auto NullNullable = NullOptional;
* things.
*/
template <typename T>
struct Nullable : protected Optional<T>
struct Nullable : protected std::optional<T>
{

//
// The following 'using' statement is needed to make visible
// all constructors of the base class within this derived class.
//
using Optional<T>::Optional;
using std::optional<T>::optional;
using std::optional<T>::operator*;
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
using std::optional<T>::operator->;

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

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

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

template <class... Args>
constexpr T & SetNonNull(Args &&... args)
{
return Optional<T>::Emplace(std::forward<Args>(args)...);
return std::optional<T>::emplace(std::forward<Args>(args)...);
}

template <typename Arg>
constexpr auto ValueOr(Arg && arg) const
{
return std::optional<T>::value_or(std::forward<Arg>(arg));
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
}

inline constexpr const T & Value() const { return std::optional<T>::value(); }
inline T & Value() { return std::optional<T>::value(); }

// For integer types, being nullable involves a range restriction.
template <
typename U = std::decay_t<T>,
Expand Down Expand Up @@ -96,22 +105,26 @@ struct Nullable : protected Optional<T>
// 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<T>::operator==(other); }
bool operator!=(const Nullable & other) const { return Optional<T>::operator!=(other); }
bool operator==(const T & other) const { return Optional<T>::operator==(other); }
bool operator!=(const T & other) const { return Optional<T>::operator!=(other); }
inline bool operator==(const T & other) const { return static_cast<const std::optional<T> &>(*this) == other; }
inline bool operator!=(const T & other) const { return !(*this == other); }

inline bool operator==(const Nullable<T> & other) const
{
return static_cast<const std::optional<T> &>(*this) == static_cast<const std::optional<T> &>(other);
}
inline bool operator!=(const Nullable<T> & other) const { return !(*this == other); }
};

template <class T>
constexpr Nullable<std::decay_t<T>> MakeNullable(T && value)
{
return Nullable<std::decay_t<T>>(InPlace, std::forward<T>(value));
return Nullable<std::decay_t<T>>(std::in_place, std::forward<T>(value));
}

template <class T, class... Args>
constexpr Nullable<T> MakeNullable(Args &&... args)
{
return Nullable<T>(InPlace, std::forward<Args>(args)...);
return Nullable<T>(std::in_place, std::forward<Args>(args)...);
}

} // namespace DataModel
Expand Down
24 changes: 15 additions & 9 deletions src/app/tests/TestNullable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -165,24 +169,26 @@ static void TestMove(nlTestSuite * inSuite, void * inContext)
CtorDtorCounter::ResetCounter();

{
auto testSrc = MakeNullable<MovableCtorDtorCounter>(400);
Nullable<MovableCtorDtorCounter> testDst(std::move(testSrc));
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 1);
auto testSrc = MakeNullable<MovableCtorDtorCounter>(400); // construct
Nullable<MovableCtorDtorCounter> testDst(std::move(testSrc)); // move construct
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 0);
Damian-Nordic marked this conversation as resolved.
Show resolved Hide resolved
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<MovableCtorDtorCounter> testDst;
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 2 && CtorDtorCounter::destroyed == 2);
Nullable<MovableCtorDtorCounter> testDst; // no object construction
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 0 && CtorDtorCounter::destroyed == 0);
NL_TEST_ASSERT(inSuite, !!testDst.IsNull());

auto testSrc = MakeNullable<MovableCtorDtorCounter>(401);
testDst = std::move(testSrc);
NL_TEST_ASSERT(inSuite, CtorDtorCounter::created == 4 && CtorDtorCounter::destroyed == 3);
auto testSrc = MakeNullable<MovableCtorDtorCounter>(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)
Expand Down
Loading