Skip to content
File

Blob: src/workerd/util/strong-bool.h

cpp69 lines
1// Copyright (c) 2025 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4#pragma once
5 
6#include <kj/string.h>
7 
8#include <compare>
9#include <cstdint>
10 
11namespace workerd {
12 
13// WD_STRONG_BOOL(StrongBool) defines a class type, `StrongBool`, which acts like a boolean flag,
14// but with greater type safety.
15//
16// `StrongBool` has the following restrictions:
17// - No default constructor: you must explicitly initialize values
18// - No possibility for uninitialized values
19// - No implicit conversion to or from boolean values
20//
21// `StrongBool` supports the following explicit and contextual boolean conversions:
22// - Explicit conversion from boolean values: `StrongBool(true)`, `StrongBool(false)`
23// - Explicit conversion to boolean values: `bool(StrongBool::YES)`, `StrongBool::NO.toBool()`
24// - Contextual boolean conversion: `if (strongBool)`, `while (strongBool)`, `!strongBool`
25//
26// The `.toBool()` function exists to make safe, explicit conversion to `bool` more convenient,
27// avoiding the verbosity of `static_cast` and the risk of C-style/functional casts.
28//
29// `StrongBool` supports the full suite of comparison and logical operators. Note that ! is
30// supported via contextual conversion (`explicit operator bool()`), rather than `operator!()`.
31//
32// Logical operators (&& and ||) preserve the type of their operands when the operands are the same
33// `StrongBool` type. Otherwise, contextual boolean conversion applies, and the operands will be
34// converted to `bool` before the operator is invoked.
35#define WD_STRONG_BOOL(Type) \
36 class Type final { \
37 public: \
38 static const Type NO; \
39 static const Type YES; \
40 constexpr explicit Type(bool booleanValue): value(booleanValue ? Value::YES : Value::NO) {} \
41 constexpr explicit operator bool() const { \
42 return toBool(); \
43 } \
44 constexpr bool toBool() const { \
45 return value == YES; \
46 } \
47 constexpr auto operator<=>(const Type&) const = default; \
48 constexpr Type operator&&(const Type& other) const { \
49 return Type(value == YES && other.value == YES); \
50 } \
51 constexpr Type operator||(const Type& other) const { \
52 return Type(value == YES || other.value == YES); \
53 } \
54 \
55 private: \
56 enum class Value : std::uint8_t { NO, YES }; \
57 constexpr Type(Value value): value(value) {} \
58 Value value; \
59 }; \
60 constexpr inline kj::LiteralStringConst KJ_STRINGIFY(Type value) { \
61 return value ? #Type "::YES"_kjc : #Type "::NO"_kjc; \
62 } \
63 inline constexpr Type Type::NO{Type::Value::NO}; \
64 inline constexpr Type Type::YES { \
65 Type::Value::YES \
66 }
67 
68} // namespace workerd