Skip to content

Commit

Permalink
[style] simplify checking conditional enum values (openthread#10843)
Browse files Browse the repository at this point in the history
This commit adds a compile time utility to check that enum values are in
order, which eliminates calculating the actual value of conditional enum
values in source code.
  • Loading branch information
bukepo authored Oct 18, 2024
1 parent deb35b0 commit a147485
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 104 deletions.
1 change: 1 addition & 0 deletions src/core/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ openthread_core_files = [
"utils/slaac_address.hpp",
"utils/srp_client_buffers.cpp",
"utils/srp_client_buffers.hpp",
"utils/static_counter.hpp",
"utils/verhoeff_checksum.cpp",
"utils/verhoeff_checksum.hpp",
]
Expand Down
24 changes: 15 additions & 9 deletions src/core/mac/mac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "crypto/aes_ccm.hpp"
#include "crypto/sha256.hpp"
#include "instance/instance.hpp"
#include "utils/static_counter.hpp"

namespace ot {
namespace Mac {
Expand Down Expand Up @@ -2210,19 +2211,24 @@ const char *Mac::OperationToString(Operation aOperation)
#endif
};

static_assert(kOperationIdle == 0, "kOperationIdle value is incorrect");
static_assert(kOperationActiveScan == 1, "kOperationActiveScan value is incorrect");
static_assert(kOperationEnergyScan == 2, "kOperationEnergyScan value is incorrect");
static_assert(kOperationTransmitBeacon == 3, "kOperationTransmitBeacon value is incorrect");
static_assert(kOperationTransmitDataDirect == 4, "kOperationTransmitDataDirect value is incorrect");
static_assert(kOperationTransmitPoll == 5, "kOperationTransmitPoll value is incorrect");
static_assert(kOperationWaitingForData == 6, "kOperationWaitingForData value is incorrect");
struct OperationChecker
{
InitEnumValidatorCounter();

ValidateNextEnum(kOperationIdle);
ValidateNextEnum(kOperationActiveScan);
ValidateNextEnum(kOperationEnergyScan);
ValidateNextEnum(kOperationTransmitBeacon);
ValidateNextEnum(kOperationTransmitDataDirect);
ValidateNextEnum(kOperationTransmitPoll);
ValidateNextEnum(kOperationWaitingForData);
#if OPENTHREAD_FTD
static_assert(kOperationTransmitDataIndirect == 7, "kOperationTransmitDataIndirect value is incorrect");
ValidateNextEnum(kOperationTransmitDataIndirect);
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
static_assert(kOperationTransmitDataCsl == 8, "TransmitDataCsl value is incorrect");
ValidateNextEnum(kOperationTransmitDataCsl);
#endif
#endif
};

return kOperationStrings[aOperation];
}
Expand Down
37 changes: 16 additions & 21 deletions src/core/mac/sub_mac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

#include "common/code_utils.hpp"
#include "instance/instance.hpp"
#include "utils/static_counter.hpp"

namespace ot {
namespace Mac {
Expand Down Expand Up @@ -1010,32 +1011,26 @@ const char *SubMac::StateToString(State aState)
#endif
};

static_assert(kStateDisabled == 0, "kStateDisabled value is not correct");
static_assert(kStateSleep == 1, "kStateSleep value is not correct");
static_assert(kStateReceive == 2, "kStateReceive value is not correct");
static_assert(kStateCsmaBackoff == 3, "kStateCsmaBackoff value is not correct");
static_assert(kStateTransmit == 4, "kStateTransmit value is not correct");
static_assert(kStateEnergyScan == 5, "kStateEnergyScan value is not correct");

struct StateValueChecker
{
InitEnumValidatorCounter();

ValidateNextEnum(kStateDisabled);
ValidateNextEnum(kStateSleep);
ValidateNextEnum(kStateReceive);
ValidateNextEnum(kStateCsmaBackoff);
ValidateNextEnum(kStateTransmit);
ValidateNextEnum(kStateEnergyScan);
#if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
static_assert(kStateDelayBeforeRetx == 6, "kStateDelayBeforeRetx value is not correct");
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
static_assert(kStateCslTransmit == 7, "kStateCslTransmit value is not correct");
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
static_assert(kStateCslSample == 8, "kStateCslSample value is not correct");
ValidateNextEnum(kStateDelayBeforeRetx);
#endif
#elif OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
static_assert(kStateCslSample == 7, "kStateCslSample value is not correct");
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
ValidateNextEnum(kStateCslTransmit);
#endif

#elif !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
static_assert(kStateCslTransmit == 6, "kStateCslTransmit value is not correct");
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
static_assert(kStateCslSample == 7, "kStateCslSample value is not correct");
#endif
#elif OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
static_assert(kStateCslSample == 6, "kStateCslSample value is not correct");
ValidateNextEnum(kStateCslSample);
#endif
};

return kStateStrings[aState];
}
Expand Down
26 changes: 14 additions & 12 deletions src/core/net/dns_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE

#include "instance/instance.hpp"
#include "utils/static_counter.hpp"

/**
* @file
Expand Down Expand Up @@ -738,21 +739,22 @@ Client::Client(Instance &aInstance)
, mUserDidSetDefaultAddress(false)
#endif
{
static_assert(kIp6AddressQuery == 0, "kIp6AddressQuery value is not correct");
struct QueryTypeChecker
{
InitEnumValidatorCounter();

ValidateNextEnum(kIp6AddressQuery);
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
static_assert(kIp4AddressQuery == 1, "kIp4AddressQuery value is not correct");
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
static_assert(kBrowseQuery == 2, "kBrowseQuery value is not correct");
static_assert(kServiceQuerySrvTxt == 3, "kServiceQuerySrvTxt value is not correct");
static_assert(kServiceQuerySrv == 4, "kServiceQuerySrv value is not correct");
static_assert(kServiceQueryTxt == 5, "kServiceQueryTxt value is not correct");
ValidateNextEnum(kIp4AddressQuery);
#endif
#elif OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
static_assert(kBrowseQuery == 1, "kBrowseQuery value is not correct");
static_assert(kServiceQuerySrvTxt == 2, "kServiceQuerySrvTxt value is not correct");
static_assert(kServiceQuerySrv == 3, "kServiceQuerySrv value is not correct");
static_assert(kServiceQueryTxt == 4, "kServiceQuerySrv value is not correct");
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
ValidateNextEnum(kBrowseQuery);
ValidateNextEnum(kServiceQuerySrvTxt);
ValidateNextEnum(kServiceQuerySrv);
ValidateNextEnum(kServiceQueryTxt);
#endif
};

#if OPENTHREAD_CONFIG_DNS_CLIENT_OVER_TCP_ENABLE
ClearAllBytes(mSendLink);
#endif
Expand Down
28 changes: 15 additions & 13 deletions src/core/thread/mesh_forwarder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "mesh_forwarder.hpp"

#include "instance/instance.hpp"
#include "utils/static_counter.hpp"

namespace ot {

Expand Down Expand Up @@ -1770,23 +1771,24 @@ const char *MeshForwarder::MessageActionToString(MessageAction aAction, Error aE

const char *string = kMessageActionStrings[aAction];

static_assert(kMessageReceive == 0, "kMessageReceive value is incorrect");
static_assert(kMessageTransmit == 1, "kMessageTransmit value is incorrect");
static_assert(kMessagePrepareIndirect == 2, "kMessagePrepareIndirect value is incorrect");
static_assert(kMessageDrop == 3, "kMessageDrop value is incorrect");
static_assert(kMessageReassemblyDrop == 4, "kMessageReassemblyDrop value is incorrect");
static_assert(kMessageEvict == 5, "kMessageEvict value is incorrect");
struct MessageActionChecker
{
InitEnumValidatorCounter();

ValidateNextEnum(kMessageReceive);
ValidateNextEnum(kMessageTransmit);
ValidateNextEnum(kMessagePrepareIndirect);
ValidateNextEnum(kMessageDrop);
ValidateNextEnum(kMessageReassemblyDrop);
ValidateNextEnum(kMessageEvict);
#if OPENTHREAD_CONFIG_DELAY_AWARE_QUEUE_MANAGEMENT_ENABLE
static_assert(kMessageMarkEcn == 6, "kMessageMarkEcn is incorrect");
static_assert(kMessageQueueMgmtDrop == 7, "kMessageQueueMgmtDrop is incorrect");
#if (OPENTHREAD_CONFIG_MAX_FRAMES_IN_DIRECT_TX_QUEUE > 0)
static_assert(kMessageFullQueueDrop == 8, "kMessageFullQueueDrop is incorrect");
ValidateNextEnum(kMessageMarkEcn);
ValidateNextEnum(kMessageQueueMgmtDrop);
#endif
#else
#if (OPENTHREAD_CONFIG_MAX_FRAMES_IN_DIRECT_TX_QUEUE > 0)
static_assert(kMessageFullQueueDrop == 6, "kMessageFullQueueDrop is incorrect");
#endif
ValidateNextEnum(kMessageFullQueueDrop);
#endif
};

if ((aAction == kMessageTransmit) && (aError != kErrorNone))
{
Expand Down
87 changes: 38 additions & 49 deletions src/core/thread/mle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "mle.hpp"

#include "instance/instance.hpp"
#include "utils/static_counter.hpp"

namespace ot {
namespace Mle {
Expand Down Expand Up @@ -4029,61 +4030,49 @@ const char *Mle::MessageTypeToString(MessageType aType)
#endif
};

static_assert(kTypeAdvertisement == 0, "kTypeAdvertisement value is incorrect");
static_assert(kTypeAnnounce == 1, "kTypeAnnounce value is incorrect");
static_assert(kTypeChildIdRequest == 2, "kTypeChildIdRequest value is incorrect");
static_assert(kTypeChildIdRequestShort == 3, "kTypeChildIdRequestShort value is incorrect");
static_assert(kTypeChildIdResponse == 4, "kTypeChildIdResponse value is incorrect");
static_assert(kTypeChildUpdateRequestAsChild == 5, "kTypeChildUpdateRequestAsChild value is incorrect");
static_assert(kTypeChildUpdateResponseAsChild == 6, "kTypeChildUpdateResponseAsChild value is incorrect");
static_assert(kTypeDataRequest == 7, "kTypeDataRequest value is incorrect");
static_assert(kTypeDataResponse == 8, "kTypeDataResponse value is incorrect");
static_assert(kTypeDiscoveryRequest == 9, "kTypeDiscoveryRequest value is incorrect");
static_assert(kTypeDiscoveryResponse == 10, "kTypeDiscoveryResponse value is incorrect");
static_assert(kTypeGenericDelayed == 11, "kTypeGenericDelayed value is incorrect");
static_assert(kTypeGenericUdp == 12, "kTypeGenericUdp value is incorrect");
static_assert(kTypeParentRequestToRouters == 13, "kTypeParentRequestToRouters value is incorrect");
static_assert(kTypeParentRequestToRoutersReeds == 14, "kTypeParentRequestToRoutersReeds value is incorrect");
static_assert(kTypeParentResponse == 15, "kTypeParentResponse value is incorrect");
struct MessageTypeChecker
{
InitEnumValidatorCounter();

ValidateNextEnum(kTypeAdvertisement);
ValidateNextEnum(kTypeAnnounce);
ValidateNextEnum(kTypeChildIdRequest);
ValidateNextEnum(kTypeChildIdRequestShort);
ValidateNextEnum(kTypeChildIdResponse);
ValidateNextEnum(kTypeChildUpdateRequestAsChild);
ValidateNextEnum(kTypeChildUpdateResponseAsChild);
ValidateNextEnum(kTypeDataRequest);
ValidateNextEnum(kTypeDataResponse);
ValidateNextEnum(kTypeDiscoveryRequest);
ValidateNextEnum(kTypeDiscoveryResponse);
ValidateNextEnum(kTypeGenericDelayed);
ValidateNextEnum(kTypeGenericUdp);
ValidateNextEnum(kTypeParentRequestToRouters);
ValidateNextEnum(kTypeParentRequestToRoutersReeds);
ValidateNextEnum(kTypeParentResponse);
#if OPENTHREAD_FTD
static_assert(kTypeAddressRelease == 16, "kTypeAddressRelease value is incorrect");
static_assert(kTypeAddressReleaseReply == 17, "kTypeAddressReleaseReply value is incorrect");
static_assert(kTypeAddressReply == 18, "kTypeAddressReply value is incorrect");
static_assert(kTypeAddressSolicit == 19, "kTypeAddressSolicit value is incorrect");
static_assert(kTypeChildUpdateRequestOfChild == 20, "kTypeChildUpdateRequestOfChild value is incorrect");
static_assert(kTypeChildUpdateResponseOfChild == 21, "kTypeChildUpdateResponseOfChild value is incorrect");
static_assert(kTypeChildUpdateResponseOfUnknownChild == 22, "kTypeChildUpdateResponseOfUnknownChild is incorrect");
static_assert(kTypeLinkAccept == 23, "kTypeLinkAccept value is incorrect");
static_assert(kTypeLinkAcceptAndRequest == 24, "kTypeLinkAcceptAndRequest value is incorrect");
static_assert(kTypeLinkReject == 25, "kTypeLinkReject value is incorrect");
static_assert(kTypeLinkRequest == 26, "kTypeLinkRequest value is incorrect");
static_assert(kTypeParentRequest == 27, "kTypeParentRequest value is incorrect");
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
static_assert(kTypeLinkMetricsManagementRequest == 28, "kTypeLinkMetricsManagementRequest value is incorrect)");
static_assert(kTypeLinkMetricsManagementResponse == 29, "kTypeLinkMetricsManagementResponse value is incorrect)");
static_assert(kTypeLinkProbe == 30, "kTypeLinkProbe value is incorrect)");
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
static_assert(kTypeTimeSync == 31, "kTypeTimeSync value is incorrect");
#endif
#else
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
static_assert(kTypeTimeSync == 28, "kTypeTimeSync value is incorrect");
#endif
ValidateNextEnum(kTypeAddressRelease);
ValidateNextEnum(kTypeAddressReleaseReply);
ValidateNextEnum(kTypeAddressReply);
ValidateNextEnum(kTypeAddressSolicit);
ValidateNextEnum(kTypeChildUpdateRequestOfChild);
ValidateNextEnum(kTypeChildUpdateResponseOfChild);
ValidateNextEnum(kTypeChildUpdateResponseOfUnknownChild);
ValidateNextEnum(kTypeLinkAccept);
ValidateNextEnum(kTypeLinkAcceptAndRequest);
ValidateNextEnum(kTypeLinkReject);
ValidateNextEnum(kTypeLinkRequest);
ValidateNextEnum(kTypeParentRequest);
#endif
#else // OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
static_assert(kTypeLinkMetricsManagementRequest == 16, "kTypeLinkMetricsManagementRequest value is incorrect)");
static_assert(kTypeLinkMetricsManagementResponse == 17, "kTypeLinkMetricsManagementResponse value is incorrect)");
static_assert(kTypeLinkProbe == 18, "kTypeLinkProbe value is incorrect)");
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
static_assert(kTypeTimeSync == 19, "kTypeTimeSync value is incorrect");
ValidateNextEnum(kTypeLinkMetricsManagementRequest);
ValidateNextEnum(kTypeLinkMetricsManagementResponse);
ValidateNextEnum(kTypeLinkProbe);
#endif
#else
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
static_assert(kTypeTimeSync == 16, "kTypeTimeSync value is incorrect");
#endif
ValidateNextEnum(kTypeTimeSync);
#endif
#endif // OPENTHREAD_FTD
};

return kMessageTypeStrings[aType];
}
Expand Down
66 changes: 66 additions & 0 deletions src/core/utils/static_counter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

/**
* @file
* This file provides a compile time counter and utilities based on it.
*/

#ifndef OT_UTILS_STATIC_COUNTER_HPP_
#define OT_UTILS_STATIC_COUNTER_HPP_

namespace ot {

template <int N> struct StaticInt : public StaticInt<N - 1>
{
public:
static constexpr int kValue = N;
};

template <> struct StaticInt<0>
{
public:
static constexpr int kValue = 0;
};

#define StaticCounterInit(N) static constexpr StaticInt<N> StaticCounter(StaticInt<N>)

#define StaticCounterValue() decltype(StaticCounter(StaticInt<255>{}))::kValue

#define StaticCounterIncr() \
static constexpr StaticInt<StaticCounterValue() + 1> StaticCounter(StaticInt<StaticCounterValue() + 1>)

#define InitEnumValidatorCounter() StaticCounterInit(0)

#define ValidateNextEnum(kEnumartor) \
static_assert(kEnumartor == StaticCounterValue(), #kEnumartor " value is incorrect"); \
StaticCounterIncr()

} // namespace ot

#endif // OT_UTILS_STATIC_COUNTER_HPP_

0 comments on commit a147485

Please sign in to comment.