pw_kvs: Make kvs compile with C++14
A series of small changes to ensure KVS compiles with C++14.
Change-Id: Idd514c20583b9f3ed192baa38cc5824e3c1ac1a3
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/27141
Commit-Queue: Rob Oliver <rgoliver@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
diff --git a/pw_checksum/BUILD.gn b/pw_checksum/BUILD.gn
index 59f85db..048964c 100644
--- a/pw_checksum/BUILD.gn
+++ b/pw_checksum/BUILD.gn
@@ -32,7 +32,10 @@
"crc16_ccitt.cc",
"crc32.cc",
]
- public_deps = [ dir_pw_span ]
+ public_deps = [
+ dir_pw_bytes,
+ dir_pw_span,
+ ]
}
pw_test_group("tests") {
diff --git a/pw_checksum/public/pw_checksum/crc16_ccitt.h b/pw_checksum/public/pw_checksum/crc16_ccitt.h
index 0f7785c..0a9daff 100644
--- a/pw_checksum/public/pw_checksum/crc16_ccitt.h
+++ b/pw_checksum/public/pw_checksum/crc16_ccitt.h
@@ -37,6 +37,8 @@
#include <span>
+#include "pw_bytes/span.h"
+
namespace pw::checksum {
// Calculates the CRC-16-CCITT for all data passed to Update.
@@ -55,7 +57,7 @@
static uint16_t Calculate(std::byte data,
uint16_t initial_value = kInitialValue) {
- return Calculate(std::span(&data, 1), initial_value);
+ return Calculate(ConstByteSpan(&data, 1), initial_value);
}
constexpr Crc16Ccitt() : value_(kInitialValue) {}
@@ -64,7 +66,7 @@
value_ = Calculate(data, value_);
}
- void Update(std::byte data) { Update(std::span(&data, 1)); }
+ void Update(std::byte data) { Update(ByteSpan(&data, 1)); }
// Returns the value of the CRC-16-CCITT for all data passed to Update.
uint16_t value() const { return value_; }
diff --git a/pw_containers/public/pw_containers/vector.h b/pw_containers/public/pw_containers/vector.h
index 7d734d3..f6b7331 100644
--- a/pw_containers/public/pw_containers/vector.h
+++ b/pw_containers/public/pw_containers/vector.h
@@ -23,6 +23,8 @@
#include <type_traits>
#include <utility>
+#include "pw_polyfill/language_feature_macros.h"
+
namespace pw {
namespace vector_impl {
@@ -31,7 +33,7 @@
std::is_same<typename std::iterator_traits<I>::value_type, void>>;
// Used as kMaxSize in the generic-size Vector<T> interface.
-inline constexpr size_t kGeneric = size_t(-1);
+PW_INLINE_VARIABLE constexpr size_t kGeneric = size_t(-1);
} // namespace vector_impl
@@ -128,10 +130,15 @@
static_assert(kMaxSize <= std::numeric_limits<size_type>::max());
// Provides access to the underlying array as an array of T.
+#ifdef __cpp_lib_launder
pointer array() { return std::launder(reinterpret_cast<T*>(&array_)); }
const_pointer array() const {
return std::launder(reinterpret_cast<const T*>(&array_));
}
+#else
+ pointer array() { return reinterpret_cast<T*>(&array_); }
+ const_pointer array() const { return reinterpret_cast<const T*>(&array_); }
+#endif // __cpp_lib_launder
// Vector entries are stored as uninitialized memory blocks aligned correctly
// for the type. Elements are initialized on demand with placement new.
diff --git a/pw_kvs/BUILD.gn b/pw_kvs/BUILD.gn
index 407c2fa..6015a8b 100644
--- a/pw_kvs/BUILD.gn
+++ b/pw_kvs/BUILD.gn
@@ -61,9 +61,11 @@
]
public_deps = [
dir_pw_assert,
+ dir_pw_bytes,
dir_pw_containers,
dir_pw_span,
dir_pw_status,
+ dir_pw_string,
]
deps = [
":config",
diff --git a/pw_kvs/public/pw_kvs/alignment.h b/pw_kvs/public/pw_kvs/alignment.h
index 56d0c08..e86ec73 100644
--- a/pw_kvs/public/pw_kvs/alignment.h
+++ b/pw_kvs/public/pw_kvs/alignment.h
@@ -20,6 +20,7 @@
#include <span>
#include <utility>
+#include "pw_bytes/span.h"
#include "pw_kvs/io.h"
#include "pw_status/status_with_size.h"
@@ -71,7 +72,8 @@
StatusWithSize Write(std::span<const std::byte> data);
StatusWithSize Write(const void* data, size_t size) {
- return Write(std::span(static_cast<const std::byte*>(data), size));
+ return Write(
+ std::span<const std::byte>(static_cast<const std::byte*>(data), size));
}
// Reads size bytes from the input and writes them to the output.
@@ -83,7 +85,7 @@
StatusWithSize Flush();
private:
- static constexpr std::byte kPadByte = std::byte{0};
+ static constexpr std::byte kPadByte = static_cast<std::byte>(0);
StatusWithSize AddBytesToBuffer(size_t bytes_added);
@@ -122,7 +124,8 @@
AlignedWriterBuffer<kBufferSize> buffer(alignment_bytes, output);
for (const std::span<const std::byte>& chunk : data) {
- if (StatusWithSize result = buffer.Write(chunk); !result.ok()) {
+ StatusWithSize result = buffer.Write(chunk);
+ if (!result.ok()) {
return result;
}
}
@@ -137,7 +140,9 @@
size_t alignment_bytes,
std::initializer_list<std::span<const std::byte>> data) {
return AlignedWrite<kBufferSize>(
- output, alignment_bytes, std::span(data.begin(), data.size()));
+ output,
+ alignment_bytes,
+ std::span<const ConstByteSpan>(data.begin(), data.size()));
}
} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/checksum.h b/pw_kvs/public/pw_kvs/checksum.h
index 5899566..6a42e00 100644
--- a/pw_kvs/public/pw_kvs/checksum.h
+++ b/pw_kvs/public/pw_kvs/checksum.h
@@ -19,7 +19,8 @@
#include "pw_kvs/alignment.h"
#include "pw_status/status.h"
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
class ChecksumAlgorithm {
public:
@@ -31,7 +32,8 @@
// Updates the checksum from a pointer and size.
void Update(const void* data, size_t size_bytes) {
- return Update(std::span(static_cast<const std::byte*>(data), size_bytes));
+ return Update(std::span<const std::byte>(
+ static_cast<const std::byte*>(data), size_bytes));
}
// Returns the final result of the checksum. Update() can no longer be called
@@ -110,8 +112,12 @@
virtual void FinalizeAligned() = 0;
- OutputToMethod<&AlignedChecksum::UpdateAligned> output_;
+ OutputToMethod<void (AlignedChecksum<kAlignmentBytes, kBufferSize>::*)(
+ std::span<const std::byte>),
+ &AlignedChecksum::UpdateAligned>
+ output_;
AlignedWriterBuffer<kBufferSize> writer_;
};
-} // namespace pw::kvs
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/crc16_checksum.h b/pw_kvs/public/pw_kvs/crc16_checksum.h
index 1cbff63..852e192 100644
--- a/pw_kvs/public/pw_kvs/crc16_checksum.h
+++ b/pw_kvs/public/pw_kvs/crc16_checksum.h
@@ -22,7 +22,8 @@
class ChecksumCrc16 final : public ChecksumAlgorithm {
public:
- ChecksumCrc16() : ChecksumAlgorithm(std::as_bytes(std::span(&crc_, 1))) {}
+ ChecksumCrc16()
+ : ChecksumAlgorithm(std::as_bytes(std::span<uint16_t>(&crc_, 1))) {}
void Reset() override { crc_ = checksum::Crc16Ccitt::kInitialValue; }
diff --git a/pw_kvs/public/pw_kvs/flash_memory.h b/pw_kvs/public/pw_kvs/flash_memory.h
index d1864b4..3b25d88 100644
--- a/pw_kvs/public/pw_kvs/flash_memory.h
+++ b/pw_kvs/public/pw_kvs/flash_memory.h
@@ -23,7 +23,8 @@
#include "pw_status/status.h"
#include "pw_status/status_with_size.h"
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
enum class PartitionPermission : bool {
kReadOnly,
@@ -41,7 +42,7 @@
size_t alignment,
uint32_t start_address = 0,
uint32_t sector_start = 0,
- std::byte erased_memory_content = std::byte{0xFF})
+ std::byte erased_memory_content = std::byte(0xFF))
: sector_size_(sector_size),
flash_sector_count_(sector_count),
alignment_(alignment),
@@ -78,7 +79,8 @@
virtual StatusWithSize Read(Address address, std::span<std::byte> output) = 0;
StatusWithSize Read(Address address, void* buffer, size_t len) {
- return Read(address, std::span(static_cast<std::byte*>(buffer), len));
+ return Read(address,
+ std::span<std::byte>(static_cast<std::byte*>(buffer), len));
}
// Writes bytes to flash. Blocking call. Returns:
@@ -93,8 +95,9 @@
StatusWithSize Write(Address destination_flash_address,
const void* data,
size_t len) {
- return Write(destination_flash_address,
- std::span(static_cast<const std::byte*>(data), len));
+ return Write(
+ destination_flash_address,
+ std::span<const std::byte>(static_cast<const std::byte*>(data), len));
}
// Convert an Address to an MCU pointer, this can be used for memory
@@ -207,7 +210,8 @@
virtual StatusWithSize Read(Address address, std::span<std::byte> output);
StatusWithSize Read(Address address, size_t length, void* output) {
- return Read(address, std::span(static_cast<std::byte*>(output), length));
+ return Read(address,
+ std::span<std::byte>(static_cast<std::byte*>(output), length));
}
// Writes bytes to flash. Address and data.size_bytes() must both be a
@@ -296,4 +300,5 @@
const PartitionPermission permission_;
};
-} // namespace pw::kvs
+} // namespace kvs
+} // namespace pw
\ No newline at end of file
diff --git a/pw_kvs/public/pw_kvs/format.h b/pw_kvs/public/pw_kvs/format.h
index 19cd174..309f786 100644
--- a/pw_kvs/public/pw_kvs/format.h
+++ b/pw_kvs/public/pw_kvs/format.h
@@ -18,7 +18,8 @@
#include "pw_kvs/checksum.h"
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
struct EntryFormat;
@@ -104,4 +105,5 @@
ChecksumAlgorithm* checksum;
};
-} // namespace pw::kvs
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/entry.h b/pw_kvs/public/pw_kvs/internal/entry.h
index 56ad721..aa94cbb 100644
--- a/pw_kvs/public/pw_kvs/internal/entry.h
+++ b/pw_kvs/public/pw_kvs/internal/entry.h
@@ -29,7 +29,9 @@
#include "pw_kvs/internal/key_descriptor.h"
#include "pw_kvs/key.h"
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
// Entry represents a key-value entry in a flash partition.
class Entry {
@@ -198,7 +200,7 @@
}
std::span<const std::byte> checksum_bytes() const {
- return std::as_bytes(std::span(&header_.checksum, 1));
+ return std::as_bytes(std::span<const uint32_t>(&header_.checksum, 1));
}
std::span<const std::byte> CalculateChecksum(
@@ -219,4 +221,6 @@
EntryHeader header_;
};
-} // namespace pw::kvs::internal
+} // namespace internal
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/entry_cache.h b/pw_kvs/public/pw_kvs/internal/entry_cache.h
index 8016b53..18e3484 100644
--- a/pw_kvs/public/pw_kvs/internal/entry_cache.h
+++ b/pw_kvs/public/pw_kvs/internal/entry_cache.h
@@ -25,7 +25,9 @@
#include "pw_kvs/internal/sectors.h"
#include "pw_kvs/key.h"
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
// Caches information about a key-value entry. Facilitates quickly finding
// entries without having to read flash.
@@ -57,7 +59,7 @@
// than allowed by the redundancy.
void AddNewAddress(Address address) {
addresses_[addresses_.size()] = address;
- addresses_ = std::span(addresses_.begin(), addresses_.size() + 1);
+ addresses_ = std::span<Address>(addresses_.begin(), addresses_.size() + 1);
}
// Remove an address from the entry metadata.
@@ -230,4 +232,6 @@
const size_t redundancy_;
};
-} // namespace pw::kvs::internal
+} // namespace internal
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/hash.h b/pw_kvs/public/pw_kvs/internal/hash.h
index b0e60d4..e56fe88 100644
--- a/pw_kvs/public/pw_kvs/internal/hash.h
+++ b/pw_kvs/public/pw_kvs/internal/hash.h
@@ -17,7 +17,9 @@
#include "pw_kvs/key.h"
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
// The hash function used to hash keys.
constexpr uint32_t Hash(Key string) {
@@ -32,4 +34,6 @@
return hash;
}
-} // namespace pw::kvs::internal
+} // namespace internal
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/key_descriptor.h b/pw_kvs/public/pw_kvs/internal/key_descriptor.h
index a7c7183..8e05b3f 100644
--- a/pw_kvs/public/pw_kvs/internal/key_descriptor.h
+++ b/pw_kvs/public/pw_kvs/internal/key_descriptor.h
@@ -15,7 +15,9 @@
#include <cstdint>
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
// Whether an entry is present or deleted.
enum class EntryState : bool { kValid, kDeleted };
@@ -28,4 +30,6 @@
EntryState state; // TODO: Pack into transaction ID? or something?
};
-} // namespace pw::kvs::internal
+} // namespace internal
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/sectors.h b/pw_kvs/public/pw_kvs/internal/sectors.h
index d2f4565..50fda8d 100644
--- a/pw_kvs/public/pw_kvs/internal/sectors.h
+++ b/pw_kvs/public/pw_kvs/internal/sectors.h
@@ -21,7 +21,9 @@
#include "pw_containers/vector.h"
#include "pw_kvs/flash_memory.h"
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
// Tracks the available and used space in each sector used by the KVS.
class SectorDescriptor {
@@ -225,4 +227,6 @@
const SectorDescriptor** const temp_sectors_to_skip_;
};
-} // namespace pw::kvs::internal
+} // namespace internal
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/span_traits.h b/pw_kvs/public/pw_kvs/internal/span_traits.h
index 89966a9..f85f0d6 100644
--- a/pw_kvs/public/pw_kvs/internal/span_traits.h
+++ b/pw_kvs/public/pw_kvs/internal/span_traits.h
@@ -16,7 +16,8 @@
#include <iterator>
#include <type_traits>
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
namespace internal {
// This borrows the `make_span` function from Chromium and uses to see if a type
@@ -90,4 +91,5 @@
: public std::bool_constant<
internal::ConvertsToSpan<std::remove_reference_t<T>>(0)> {};
-} // namespace pw::kvs
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/io.h b/pw_kvs/public/pw_kvs/io.h
index 80a0ef0..341b80a 100644
--- a/pw_kvs/public/pw_kvs/io.h
+++ b/pw_kvs/public/pw_kvs/io.h
@@ -43,7 +43,8 @@
// Convenience wrapper for writing data from a pointer and length.
StatusWithSize Write(const void* data, size_t size_bytes) {
- return Write(std::span(static_cast<const std::byte*>(data), size_bytes));
+ return Write(std::span<const std::byte>(static_cast<const std::byte*>(data),
+ size_bytes));
}
protected:
@@ -59,7 +60,8 @@
// Convenience wrapper for reading data from a pointer and length.
StatusWithSize Read(void* data, size_t size_bytes) {
- return Read(std::span(static_cast<std::byte*>(data), size_bytes));
+ return Read(
+ std::span<std::byte>(static_cast<std::byte*>(data), size_bytes));
}
protected:
@@ -72,7 +74,7 @@
// Output adapter that calls a method on a class with a std::span of bytes. If
// the method returns void instead of the expected Status, Write always returns
// Status::Ok().
-template <auto kMethod>
+template <typename T, T kMethod>
class OutputToMethod final : public Output {
using Class = typename internal::FunctionTraits<decltype(kMethod)>::Class;
@@ -80,15 +82,26 @@
constexpr OutputToMethod(Class* object) : object_(*object) {}
private:
- StatusWithSize DoWrite(std::span<const std::byte> data) override {
- using Return = typename internal::FunctionTraits<decltype(kMethod)>::Return;
+ using Return = typename internal::FunctionTraits<decltype(kMethod)>::Return;
+ template <T kMethodImpl = kMethod>
+ typename std::enable_if<std::is_void<typename internal::FunctionTraits<
+ decltype(kMethodImpl)>::Return>::value,
+ StatusWithSize>::type
+ DoWriteImpl(std::span<const std::byte> data) {
+ (object_.*kMethod)(data);
+ return StatusWithSize(data.size());
+ }
- if constexpr (std::is_void_v<Return>) {
- (object_.*kMethod)(data);
- return StatusWithSize(data.size());
- } else {
- return (object_.*kMethod)(data);
- }
+ template <T kMethodImpl = kMethod>
+ typename std::enable_if<!std::is_void<typename internal::FunctionTraits<
+ decltype(kMethodImpl)>::Return>::value,
+ StatusWithSize>::type
+ DoWriteImpl(std::span<const std::byte> data) {
+ return (object_.*kMethod)(data);
+ }
+
+ StatusWithSize DoWrite(std::span<const std::byte> data) override {
+ return DoWriteImpl(data);
}
private:
diff --git a/pw_kvs/public/pw_kvs/key.h b/pw_kvs/public/pw_kvs/key.h
index df86571..62b8532 100644
--- a/pw_kvs/public/pw_kvs/key.h
+++ b/pw_kvs/public/pw_kvs/key.h
@@ -14,13 +14,17 @@
#pragma once
#include <cstring>
+#include <limits>
#include <string>
#if __cplusplus >= 201703L
#include <string_view>
#endif // __cplusplus >= 201703L
-namespace pw::kvs {
+#include "pw_string/util.h"
+
+namespace pw {
+namespace kvs {
// Key is a simplified string_view used for KVS. This helps KVS work on
// platforms without C++17.
@@ -30,7 +34,8 @@
constexpr Key() : str_{nullptr}, length_{0} {}
constexpr Key(const Key&) = default;
constexpr Key(const char* str)
- : str_{str}, length_{std::char_traits<char>::length(str)} {}
+ : str_{str},
+ length_{string::Length(str, std::numeric_limits<size_t>::max())} {}
constexpr Key(const char* str, size_t len) : str_{str}, length_{len} {}
Key(const std::string& str) : str_{str.data()}, length_{str.length()} {}
@@ -73,4 +78,5 @@
size_t length_;
};
-} // namespace pw::kvs
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/key_value_store.h b/pw_kvs/public/pw_kvs/key_value_store.h
index a63c5fd..f5d4695 100644
--- a/pw_kvs/public/pw_kvs/key_value_store.h
+++ b/pw_kvs/public/pw_kvs/key_value_store.h
@@ -32,7 +32,8 @@
#include "pw_status/status.h"
#include "pw_status/status_with_size.h"
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
enum class GargbageCollectOnWrite {
// Disable all automatic garbage collection on write.
@@ -124,7 +125,7 @@
// std::as_writable_bytes(std::span(array)), or pass a pointer to the array
// instead of the array itself.
template <typename Pointer,
- typename = std::enable_if_t<std::is_pointer_v<Pointer>>>
+ typename = std::enable_if_t<std::is_pointer<Pointer>::value>>
Status Get(const Key& key, const Pointer& pointer) const {
using T = std::remove_reference_t<std::remove_pointer_t<Pointer>>;
CheckThatObjectCanBePutOrGet<T>();
@@ -148,14 +149,17 @@
// FAILED_PRECONDITION: the KVS is not initialized
// INVALID_ARGUMENT: key is empty or too long or value is too large
//
- template <typename T>
+ template <typename T,
+ typename std::enable_if_t<ConvertsToSpan<T>::value>* = nullptr>
Status Put(const Key& key, const T& value) {
- if constexpr (ConvertsToSpan<T>::value) {
- return PutBytes(key, std::as_bytes(std::span(value)));
- } else {
- CheckThatObjectCanBePutOrGet<T>();
- return PutBytes(key, std::as_bytes(std::span(&value, 1)));
- }
+ return PutBytes(key, std::as_bytes(internal::make_span(value)));
+ }
+
+ template <typename T,
+ typename std::enable_if_t<!ConvertsToSpan<T>::value>* = nullptr>
+ Status Put(const Key& key, const T& value) {
+ CheckThatObjectCanBePutOrGet<T>();
+ return PutBytes(key, std::as_bytes(std::span<const T>(&value, 1)));
}
// Removes a key-value entry from the KVS.
@@ -225,7 +229,7 @@
}
template <typename Pointer,
- typename = std::enable_if_t<std::is_pointer_v<Pointer>>>
+ typename = std::enable_if_t<std::is_pointer<Pointer>::value>>
Status Get(const Pointer& pointer) const {
using T = std::remove_reference_t<std::remove_pointer_t<Pointer>>;
CheckThatObjectCanBePutOrGet<T>();
@@ -360,7 +364,7 @@
template <typename T>
static constexpr void CheckThatObjectCanBePutOrGet() {
static_assert(
- std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>,
+ std::is_trivially_copyable<T>::value && !std::is_pointer<T>::value,
"Only trivially copyable, non-pointer objects may be Put and Get by "
"value. Any value may be stored by converting it to a byte std::span "
"with std::as_bytes(std::span(&value, 1)) or "
@@ -571,7 +575,8 @@
const Options& options = {})
: KeyValueStoreBuffer(
partition,
- std::span(reinterpret_cast<const EntryFormat (&)[1]>(format)),
+ std::span<const EntryFormat, kEntryFormats>(
+ reinterpret_cast<const EntryFormat (&)[1]>(format)),
options) {
static_assert(kEntryFormats == 1,
"kEntryFormats EntryFormats must be specified");
@@ -622,4 +627,5 @@
std::array<EntryFormat, kEntryFormats> formats_;
};
-} // namespace pw::kvs
+} // namespace kvs
+} // namespace pw
diff --git a/pw_kvs/public/pw_kvs/test_key_value_store.h b/pw_kvs/public/pw_kvs/test_key_value_store.h
index 73aa609..e57e74f 100644
--- a/pw_kvs/public/pw_kvs/test_key_value_store.h
+++ b/pw_kvs/public/pw_kvs/test_key_value_store.h
@@ -15,8 +15,10 @@
#include "pw_kvs/key_value_store.h"
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
KeyValueStore& TestKvs();
-} // namespace pw::kvs
+} // namespace kvs
+} // namespace pw
diff --git a/pw_minimal_cpp_stdlib/public/internal/type_traits.h b/pw_minimal_cpp_stdlib/public/internal/type_traits.h
index 6630e3b..bb6ccb5 100644
--- a/pw_minimal_cpp_stdlib/public/internal/type_traits.h
+++ b/pw_minimal_cpp_stdlib/public/internal/type_traits.h
@@ -19,6 +19,7 @@
#define __cpp_lib_transformation_trait_aliases 201304L
#define __cpp_lib_type_trait_variable_templates 201510L
+#define __cpp_lib_logical_traits 201510L
template <decltype(sizeof(0)) kLength,
decltype(sizeof(0)) kAlignment> // no default
diff --git a/pw_polyfill/standard_library_public/pw_polyfill/standard_library/type_traits.h b/pw_polyfill/standard_library_public/pw_polyfill/standard_library/type_traits.h
index 33ea9d1..1d9b9b2 100644
--- a/pw_polyfill/standard_library_public/pw_polyfill/standard_library/type_traits.h
+++ b/pw_polyfill/standard_library_public/pw_polyfill/standard_library/type_traits.h
@@ -65,4 +65,33 @@
#endif // __cpp_lib_is_null_pointer
+#ifndef __cpp_lib_bool_constant
+#define __cpp_lib_bool_constant 201505L
+template <bool value>
+using bool_constant = integral_constant<bool, value>;
+#endif // __cpp_lib_bool_constant
+
+#ifndef __cpp_lib_logical_traits
+#define __cpp_lib_logical_traits 201510L
+template <typename value>
+struct negation : bool_constant<!bool(value::value)> {};
+
+template <typename...>
+struct conjunction : std::true_type {};
+template <typename B1>
+struct conjunction<B1> : B1 {};
+template <typename B1, typename... Bn>
+struct conjunction<B1, Bn...>
+ : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
+
+template <typename...>
+struct disjunction : std::false_type {};
+template <typename B1>
+struct disjunction<B1> : B1 {};
+template <typename B1, typename... Bn>
+struct disjunction<B1, Bn...>
+ : std::conditional_t<bool(B1::value), B1, disjunction<Bn...>> {};
+
+#endif // __cpp_lib_logical_traits
+
_PW_POLYFILL_END_NAMESPACE_STD
diff --git a/pw_polyfill/test.cc b/pw_polyfill/test.cc
index 27d2a19..497bd3b 100644
--- a/pw_polyfill/test.cc
+++ b/pw_polyfill/test.cc
@@ -188,6 +188,19 @@
static_assert(std::make_index_sequence<123>::size() == 123);
}
+TEST(Utility, LogicalTraits) {
+ static_assert(std::conjunction<std::true_type, std::true_type>::value);
+ static_assert(!std::conjunction<std::true_type, std::false_type>::value);
+ static_assert(!std::conjunction<std::false_type, std::false_type>::value);
+
+ static_assert(std::disjunction<std::true_type, std::true_type>::value);
+ static_assert(std::disjunction<std::true_type, std::false_type>::value);
+ static_assert(!std::disjunction<std::false_type, std::false_type>::value);
+
+ static_assert(!std::negation<std::true_type>::value);
+ static_assert(std::negation<std::false_type>::value);
+}
+
} // namespace
} // namespace polyfill
} // namespace pw
diff --git a/pw_status/public/pw_status/status_with_size.h b/pw_status/public/pw_status/status_with_size.h
index 751ace8..895ab99 100644
--- a/pw_status/public/pw_status/status_with_size.h
+++ b/pw_status/public/pw_status/status_with_size.h
@@ -158,7 +158,7 @@
// Creates a StatusWithSize with Status::Ok() and the provided size.
// std::enable_if is used to prevent enum types (e.g. Status) from being used.
// TODO(hepler): Add debug-only assert that size <= max_size().
- template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+ template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
explicit constexpr StatusWithSize(T size) : size_(size) {}
// Creates a StatusWithSize with the provided status and size.
diff --git a/pw_string/public/pw_string/util.h b/pw_string/public/pw_string/util.h
index ddf6a36..37c6c0b 100644
--- a/pw_string/public/pw_string/util.h
+++ b/pw_string/public/pw_string/util.h
@@ -15,7 +15,8 @@
#include <cstddef>
-namespace pw::string {
+namespace pw {
+namespace string {
// Calculates the length of a null-terminated string up to the specified maximum
// length. If str is nullptr, returns 0.
@@ -35,4 +36,5 @@
return length;
}
-} // namespace pw::string
+} // namespace string
+} // namespace pw