Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [7.0.14]

[7.0.14]: https://github.com/microsoft/CCF/releases/tag/ccf-7.0.14

### Changed

- CCF and C++ applications built against it now require C++23. The supported minimum Clang version remains 18.1.2. (#8234)

## [7.0.13]

[7.0.13]: https://github.com/microsoft/CCF/releases/tag/ccf-7.0.13
Expand Down
3 changes: 2 additions & 1 deletion cmake/preproject.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,5 @@ function(add_warning_checks name)
)
endfunction()

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
3 changes: 3 additions & 0 deletions include/ccf/byte_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
#include <climits>
#include <fmt/format.h>
#include <fmt/ranges.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include <small_vector/SmallVector.h>
#pragma clang diagnostic pop

namespace ccf
{
Expand Down
4 changes: 2 additions & 2 deletions include/ccf/ds/enum_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#define FMT_HEADER_ONLY
#include <fmt/format.h>
#include <utility>

/**
* Generic formatter for scoped enums.
Expand All @@ -22,8 +23,7 @@ struct formatter<E, std::enable_if_t<std::is_enum_v<E>, char>>
template <typename FormatContext>
auto format(const E& value, FormatContext& ctx) const
{
return fmt::format_to(
ctx.out(), "{}", static_cast<std::underlying_type_t<E>>(value));
return fmt::format_to(ctx.out(), "{}", std::to_underlying(value));
}
};
FMT_END_NAMESPACE
Expand Down
3 changes: 3 additions & 0 deletions include/ccf/ds/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

#include <array>
#include <cstdint>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include <small_vector/SmallVector.h>
#pragma clang diagnostic pop
#include <string_view>
#include <vector>

Expand Down
3 changes: 2 additions & 1 deletion include/ccf/ds/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <optional>
#include <sstream>
#include <type_traits>
#include <utility>

namespace ccf::logger
{
Expand All @@ -25,7 +26,7 @@ namespace ccf::logger

static constexpr const char* to_string(LoggerLevel l)
{
return LevelNames[static_cast<int>(l)];
return LevelNames[std::to_underlying(l)];
}

static constexpr long int ns_per_s = 1'000'000'000;
Expand Down
3 changes: 1 addition & 2 deletions include/ccf/endpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,7 @@ struct formatter<ccf::endpoints::ForwardingRequired>
default:
{
throw std::logic_error(fmt::format(
"Unhandled value for ForwardingRequired: {}",
static_cast<uint8_t>(v)));
"Unhandled value for ForwardingRequired: {}", std::to_underlying(v)));
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions include/ccf/js/kv_access_permissions.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "ccf/js/core/context.h"

#include <utility>

namespace ccf::js
{
enum class KVAccessPermissions : uint8_t
Expand All @@ -17,9 +19,7 @@ namespace ccf::js
inline KVAccessPermissions intersect_access_permissions(
KVAccessPermissions l, KVAccessPermissions r)
{
/* This could use std::to_underlying from C++23 */
using T = std::underlying_type_t<KVAccessPermissions>;
const auto intersection = (T)l & (T)r;
return KVAccessPermissions(intersection);
const auto intersection = std::to_underlying(l) & std::to_underlying(r);
return static_cast<KVAccessPermissions>(intersection);
}
}
4 changes: 2 additions & 2 deletions include/ccf/service/node_info_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ namespace ccf
// rsplit_1 splits on the last ':'. When the address has no port it returns
// ("", addr), which would wrongly put the host in the port slot; handle the
// port-less case explicitly so the host stays in the first position.
if (addr.find(':') == std::string::npos)
if (!addr.contains(':'))
{
return std::make_pair(addr, std::string());
}
Expand All @@ -238,7 +238,7 @@ namespace ccf
inline static NodeInfoNetwork::NetAddress make_net_address(
const std::string& host, const std::string& port)
{
if (host.find(':') != std::string::npos && !host.starts_with('['))
if (host.contains(':') && !host.starts_with('['))
{
return fmt::format("[{}]:{}", host, port);
}
Expand Down
5 changes: 3 additions & 2 deletions include/ccf/service/tables/proposals.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "ccf/service/map.h"

#include <unordered_map>
#include <utility>
#include <vector>

namespace ccf
Expand Down Expand Up @@ -82,8 +83,8 @@ struct formatter<ccf::ProposalState>
}
default:
{
throw std::logic_error(fmt::format(
"Unknown proposal state {}", static_cast<uint8_t>(state)));
throw std::logic_error(
fmt::format("Unknown proposal state {}", std::to_underlying(state)));
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions include/ccf/tx_status.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "ccf/ds/json.h"
#include "ccf/tx_id.h"

#include <utility>

namespace ccf
{
/** Describes the status of a transaction, as seen by this node.
Expand Down Expand Up @@ -34,9 +36,8 @@ namespace ccf
// Contains only the terminal values of TxStatus
enum class FinalTxStatus : std::underlying_type_t<TxStatus>
{
Committed =
static_cast<std::underlying_type_t<TxStatus>>(TxStatus::Committed),
Invalid = static_cast<std::underlying_type_t<TxStatus>>(TxStatus::Invalid),
Committed = std::to_underlying(TxStatus::Committed),
Invalid = std::to_underlying(TxStatus::Invalid),
};

constexpr char const* tx_status_to_str(TxStatus status)
Expand Down
2 changes: 1 addition & 1 deletion python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "ccf"
version = "7.0.13"
version = "7.0.14"
authors = [
{ name="CCF Team", email="CCF-Sec@microsoft.com" },
]
Expand Down
4 changes: 1 addition & 3 deletions src/common/cli_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ namespace cli
// Unbracketed IPv6 literals are ambiguous with the host:port separator.
// Require bracketed "[host]:port" form for any address containing more
// than one ':' (e.g. "::1").
if (
addr.find(':') != std::string::npos &&
addr.find(':') != addr.find_last_of(':'))
if (addr.contains(':') && addr.find(':') != addr.find_last_of(':'))
{
throw std::logic_error(fmt::format(
"IPv6 address '{}' must be bracketed as '[host]:port'", addr));
Expand Down
3 changes: 2 additions & 1 deletion src/consensus/aft/test/committable_suffix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "test_common.h"

#define DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES
#include <algorithm>
#include <doctest/doctest.h>

void keep_messages_for_multiple(
Expand All @@ -16,7 +17,7 @@ void keep_messages_for_multiple(
while (it != messages.end())
{
if (
std::find(targets.begin(), targets.end(), it->first) == targets.end() ||
!std::ranges::contains(targets, it->first) ||
(max_to_keep.has_value() && kept[it->first] >= *max_to_keep))
{
it = messages.erase(it);
Expand Down
7 changes: 2 additions & 5 deletions src/cose/test/cose_ffi_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,7 @@ TEST_CASE("cose_sign_ledger fails with invalid key")
CoseKey::from_private(bad_key.data(), bad_key.size(), key_err);
CHECK(!cose_key.is_set());
CHECK(key_err.is_set());
CHECK(
key_err.to_string().find("d2i_AutoPrivateKey failed:") !=
std::string::npos);
CHECK(key_err.to_string().contains("d2i_AutoPrivateKey failed:"));
}

TEST_CASE("CoseKey error propagation")
Expand All @@ -169,8 +167,7 @@ TEST_CASE("CoseKey error propagation")
auto k = CoseKey::from_private(truncated.data(), truncated.size(), err);
CHECK(!k.is_set());
CHECK(err.is_set());
CHECK(
err.to_string().find("d2i_AutoPrivateKey failed:") != std::string::npos);
CHECK(err.to_string().contains("d2i_AutoPrivateKey failed:"));
}

SUBCASE("valid key succeeds without error")
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/pem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ccf::crypto
{
void Pem::check_pem_format()
{
if (s.find("-----BEGIN") == std::string::npos)
if (!s.contains("-----BEGIN"))
{
throw std::runtime_error(
fmt::format("PEM constructed with non-PEM data: {}", s));
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/test/crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,8 +628,8 @@ void run_csr(bool corrupt_csr = false)

std::string valid_from_, valid_to_;
std::tie(valid_from_, valid_to_) = v.validity_period();
REQUIRE(valid_from_.find(valid_from) != std::string::npos);
REQUIRE(valid_to_.find(valid_to) != std::string::npos);
REQUIRE(valid_from_.contains(valid_from));
REQUIRE(valid_to_.contains(valid_to));
}

TEST_CASE("2-digit years")
Expand Down
5 changes: 3 additions & 2 deletions src/ds/test/json_schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "ccf/ds/json.h"

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <algorithm>
#include <doctest/doctest.h>
#include <nlohmann/json.hpp>
#include <vector>
Expand Down Expand Up @@ -598,14 +599,14 @@ TEST_CASE("JSON with different field names")
for (const auto s : required_json_fields)
{
REQUIRE(properties.find(s) != properties.end());
REQUIRE(std::find(required.begin(), required.end(), s) != required.end());
REQUIRE(std::ranges::contains(required, s));
}

std::vector<char const*> optional_json_fields{"A", "OTHER_NAME", "c"};
for (const auto s : optional_json_fields)
{
REQUIRE(properties.find(s) != properties.end());
REQUIRE(std::find(required.begin(), required.end(), s) == required.end());
REQUIRE(!std::ranges::contains(required, s));
}

renamed::Foo foo;
Expand Down
57 changes: 28 additions & 29 deletions src/ds/test/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ TEST_CASE("Framework logging macros")
REQUIRE(logs.size() == 1);

const auto& log = logs[0];
REQUIRE(log.find("info") != std::string::npos);
REQUIRE(log.find("logger.cpp") != std::string::npos);
REQUIRE(log.find("Hello A") != std::string::npos);
REQUIRE(log.contains("info"));
REQUIRE(log.contains("logger.cpp"));
REQUIRE(log.contains("Hello A"));

logs.clear();
}
Expand All @@ -72,9 +72,9 @@ TEST_CASE("Framework logging macros")
REQUIRE(logs.size() == 1);

const auto& log = logs[0];
REQUIRE(log.find("fail") != std::string::npos);
REQUIRE(log.find("logger.cpp") != std::string::npos);
REQUIRE(log.find("Hello B") != std::string::npos);
REQUIRE(log.contains("fail"));
REQUIRE(log.contains("logger.cpp"));
REQUIRE(log.contains("Hello B"));

logs.clear();
}
Expand All @@ -85,9 +85,9 @@ TEST_CASE("Framework logging macros")
REQUIRE(logs.size() == 1);

const auto& log = logs[0];
REQUIRE(log.find("fatal") != std::string::npos);
REQUIRE(log.find("logger.cpp") != std::string::npos);
REQUIRE(log.find("Hello C") != std::string::npos);
REQUIRE(log.contains("fatal"));
REQUIRE(log.contains("logger.cpp"));
REQUIRE(log.contains("Hello C"));

logs.clear();
}
Expand All @@ -108,10 +108,10 @@ TEST_CASE("Application logging macros")
REQUIRE(logs.size() == 1);

const auto& log = logs[0];
REQUIRE(log.find("info") != std::string::npos);
REQUIRE(log.find("[app]") != std::string::npos);
REQUIRE(log.find("logger.cpp") != std::string::npos);
REQUIRE(log.find("Hello A") != std::string::npos);
REQUIRE(log.contains("info"));
REQUIRE(log.contains("[app]"));
REQUIRE(log.contains("logger.cpp"));
REQUIRE(log.contains("Hello A"));

logs.clear();
}
Expand All @@ -122,10 +122,10 @@ TEST_CASE("Application logging macros")
REQUIRE(logs.size() == 1);

const auto& log = logs[0];
REQUIRE(log.find("fail") != std::string::npos);
REQUIRE(log.find("[app]") != std::string::npos);
REQUIRE(log.find("logger.cpp") != std::string::npos);
REQUIRE(log.find("Hello B") != std::string::npos);
REQUIRE(log.contains("fail"));
REQUIRE(log.contains("[app]"));
REQUIRE(log.contains("logger.cpp"));
REQUIRE(log.contains("Hello B"));

logs.clear();
}
Expand All @@ -136,10 +136,10 @@ TEST_CASE("Application logging macros")
REQUIRE(logs.size() == 1);

const auto& log = logs[0];
REQUIRE(log.find("fatal") != std::string::npos);
REQUIRE(log.find("[app]") != std::string::npos);
REQUIRE(log.find("logger.cpp") != std::string::npos);
REQUIRE(log.find("Hello C") != std::string::npos);
REQUIRE(log.contains("fatal"));
REQUIRE(log.contains("[app]"));
REQUIRE(log.contains("logger.cpp"));
REQUIRE(log.contains("Hello C"));

logs.clear();
}
Expand Down Expand Up @@ -167,10 +167,10 @@ TEST_CASE("Custom logging macros")
REQUIRE(logs.size() == 1);

const auto& log = logs[0];
REQUIRE(log.find("info") != std::string::npos);
REQUIRE(log.find(custom_tag) != std::string::npos);
REQUIRE(log.find("logger.cpp") != std::string::npos);
REQUIRE(log.find("Some message") != std::string::npos);
REQUIRE(log.contains("info"));
REQUIRE(log.contains(custom_tag));
REQUIRE(log.contains("logger.cpp"));
REQUIRE(log.contains("Some message"));

logs.clear();
}
Expand All @@ -181,21 +181,20 @@ TEST_CASE("Custom logging macros")
REQUIRE(logs.size() == 1);

const auto& log = logs[0];
REQUIRE(log.find("info") != std::string::npos);
REQUIRE(log.contains("info"));
// Search for smaller prefixes of the long tag, expect that one is
// eventually present
std::string truncated_tag = custom_long_tag;
while (truncated_tag.size() > 0)
{
const auto search = log.find(truncated_tag);
if (search != std::string::npos)
if (log.contains(truncated_tag))
{
break;
}
truncated_tag.resize(truncated_tag.size() - 1);
}
REQUIRE(truncated_tag.size() > 0);
REQUIRE(log.find("Some other message") != std::string::npos);
REQUIRE(log.contains("Some other message"));

logs.clear();
}
Expand Down
Loading