jpayne@69: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors jpayne@69: // Licensed under the MIT License: jpayne@69: // jpayne@69: // Permission is hereby granted, free of charge, to any person obtaining a copy jpayne@69: // of this software and associated documentation files (the "Software"), to deal jpayne@69: // in the Software without restriction, including without limitation the rights jpayne@69: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell jpayne@69: // copies of the Software, and to permit persons to whom the Software is jpayne@69: // furnished to do so, subject to the following conditions: jpayne@69: // jpayne@69: // The above copyright notice and this permission notice shall be included in jpayne@69: // all copies or substantial portions of the Software. jpayne@69: // jpayne@69: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR jpayne@69: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, jpayne@69: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE jpayne@69: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER jpayne@69: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, jpayne@69: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN jpayne@69: // THE SOFTWARE. jpayne@69: jpayne@69: // Header that should be #included by everyone. jpayne@69: // jpayne@69: // This defines very simple utilities that are widely applicable. jpayne@69: jpayne@69: #pragma once jpayne@69: jpayne@69: #if defined(__GNUC__) || defined(__clang__) jpayne@69: #define KJ_BEGIN_SYSTEM_HEADER _Pragma("GCC system_header") jpayne@69: #elif defined(_MSC_VER) jpayne@69: #define KJ_BEGIN_SYSTEM_HEADER __pragma(warning(push, 0)) jpayne@69: #define KJ_END_SYSTEM_HEADER __pragma(warning(pop)) jpayne@69: #endif jpayne@69: jpayne@69: #ifndef KJ_BEGIN_SYSTEM_HEADER jpayne@69: #define KJ_BEGIN_SYSTEM_HEADER jpayne@69: #endif jpayne@69: jpayne@69: #ifndef KJ_END_SYSTEM_HEADER jpayne@69: #define KJ_END_SYSTEM_HEADER jpayne@69: #endif jpayne@69: jpayne@69: #if !defined(KJ_HEADER_WARNINGS) || !KJ_HEADER_WARNINGS jpayne@69: #define KJ_BEGIN_HEADER KJ_BEGIN_SYSTEM_HEADER jpayne@69: #define KJ_END_HEADER KJ_END_SYSTEM_HEADER jpayne@69: #else jpayne@69: #define KJ_BEGIN_HEADER jpayne@69: #define KJ_END_HEADER jpayne@69: #endif jpayne@69: jpayne@69: #ifdef __has_cpp_attribute jpayne@69: #define KJ_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) jpayne@69: #else jpayne@69: #define KJ_HAS_CPP_ATTRIBUTE(x) 0 jpayne@69: #endif jpayne@69: jpayne@69: #ifdef __has_feature jpayne@69: #define KJ_HAS_COMPILER_FEATURE(x) __has_feature(x) jpayne@69: #else jpayne@69: #define KJ_HAS_COMPILER_FEATURE(x) 0 jpayne@69: #endif jpayne@69: jpayne@69: #if defined(_MSVC_LANG) && !defined(__clang__) jpayne@69: #define KJ_CPP_STD _MSVC_LANG jpayne@69: #else jpayne@69: #define KJ_CPP_STD __cplusplus jpayne@69: #endif jpayne@69: jpayne@69: KJ_BEGIN_HEADER jpayne@69: jpayne@69: #ifndef KJ_NO_COMPILER_CHECK jpayne@69: // Technically, __cplusplus should be 201402L for C++14, but GCC 4.9 -- which is supported -- still jpayne@69: // had it defined to 201300L even with -std=c++14. jpayne@69: #if KJ_CPP_STD < 201300L && !__CDT_PARSER__ jpayne@69: #error "This code requires C++14. Either your compiler does not support it or it is not enabled." jpayne@69: #ifdef __GNUC__ jpayne@69: // Compiler claims compatibility with GCC, so presumably supports -std. jpayne@69: #error "Pass -std=c++14 on the compiler command line to enable C++14." jpayne@69: #endif jpayne@69: #endif jpayne@69: jpayne@69: #ifdef __GNUC__ jpayne@69: #if __clang__ jpayne@69: #if __clang_major__ < 5 jpayne@69: #warning "This library requires at least Clang 5.0." jpayne@69: #elif KJ_CPP_STD >= 201402L && !__has_include() jpayne@69: #warning "Your compiler supports C++14 but your C++ standard library does not. If your "\ jpayne@69: "system has libc++ installed (as should be the case on e.g. Mac OSX), try adding "\ jpayne@69: "-stdlib=libc++ to your CXXFLAGS." jpayne@69: #endif jpayne@69: #else jpayne@69: #if __GNUC__ < 5 jpayne@69: #warning "This library requires at least GCC 5.0." jpayne@69: #endif jpayne@69: #endif jpayne@69: #elif defined(_MSC_VER) jpayne@69: #if _MSC_VER < 1910 && !defined(__clang__) jpayne@69: #error "You need Visual Studio 2017 or better to compile this code." jpayne@69: #endif jpayne@69: #else jpayne@69: #warning "I don't recognize your compiler. As of this writing, Clang, GCC, and Visual Studio "\ jpayne@69: "are the only known compilers with enough C++14 support for this library. "\ jpayne@69: "#define KJ_NO_COMPILER_CHECK to make this warning go away." jpayne@69: #endif jpayne@69: #endif jpayne@69: jpayne@69: #include jpayne@69: #include jpayne@69: #include jpayne@69: #include jpayne@69: jpayne@69: #if __linux__ && KJ_CPP_STD > 201200L jpayne@69: // Hack around stdlib bug with C++14 that exists on some Linux systems. jpayne@69: // Apparently in this mode the C library decides not to define gets() but the C++ library still jpayne@69: // tries to import it into the std namespace. This bug has been fixed at the source but is still jpayne@69: // widely present in the wild e.g. on Ubuntu 14.04. jpayne@69: #undef _GLIBCXX_HAVE_GETS jpayne@69: #endif jpayne@69: jpayne@69: #if _WIN32 jpayne@69: // Windows likes to define macros for min() and max(). We just can't deal with this. jpayne@69: // If windows.h was included already, undef these. jpayne@69: #undef min jpayne@69: #undef max jpayne@69: // If windows.h was not included yet, define the macro that prevents min() and max() from being jpayne@69: // defined. jpayne@69: #ifndef NOMINMAX jpayne@69: #define NOMINMAX 1 jpayne@69: #endif jpayne@69: #endif jpayne@69: jpayne@69: #if defined(_MSC_VER) jpayne@69: #include // __popcnt jpayne@69: #endif jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: jpayne@69: namespace kj { jpayne@69: jpayne@69: typedef unsigned int uint; jpayne@69: typedef unsigned char byte; jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Common macros, especially for common yet compiler-specific features. jpayne@69: jpayne@69: // Detect whether RTTI and exceptions are enabled, assuming they are unless we have specific jpayne@69: // evidence to the contrary. Clients can always define KJ_NO_RTTI or KJ_NO_EXCEPTIONS explicitly jpayne@69: // to override these checks. jpayne@69: jpayne@69: // TODO: Ideally we'd use __cpp_exceptions/__cpp_rtti not being defined as the first pass since jpayne@69: // that is the standard compliant way. However, it's unclear how to use those macros (or any jpayne@69: // others) to distinguish between the compiler supporting feature detection and the feature being jpayne@69: // disabled vs the compiler not supporting feature detection at all. jpayne@69: #if defined(__has_feature) jpayne@69: #if !defined(KJ_NO_RTTI) && !__has_feature(cxx_rtti) jpayne@69: #define KJ_NO_RTTI 1 jpayne@69: #endif jpayne@69: #if !defined(KJ_NO_EXCEPTIONS) && !__has_feature(cxx_exceptions) jpayne@69: #define KJ_NO_EXCEPTIONS 1 jpayne@69: #endif jpayne@69: #elif defined(__GNUC__) jpayne@69: #if !defined(KJ_NO_RTTI) && !__GXX_RTTI jpayne@69: #define KJ_NO_RTTI 1 jpayne@69: #endif jpayne@69: #if !defined(KJ_NO_EXCEPTIONS) && !__EXCEPTIONS jpayne@69: #define KJ_NO_EXCEPTIONS 1 jpayne@69: #endif jpayne@69: #elif defined(_MSC_VER) jpayne@69: #if !defined(KJ_NO_RTTI) && !defined(_CPPRTTI) jpayne@69: #define KJ_NO_RTTI 1 jpayne@69: #endif jpayne@69: #if !defined(KJ_NO_EXCEPTIONS) && !defined(_CPPUNWIND) jpayne@69: #define KJ_NO_EXCEPTIONS 1 jpayne@69: #endif jpayne@69: #endif jpayne@69: jpayne@69: #if !defined(KJ_DEBUG) && !defined(KJ_NDEBUG) jpayne@69: // Heuristically decide whether to enable debug mode. If DEBUG or NDEBUG is defined, use that. jpayne@69: // Otherwise, fall back to checking whether optimization is enabled. jpayne@69: #if defined(DEBUG) || defined(_DEBUG) jpayne@69: #define KJ_DEBUG jpayne@69: #elif defined(NDEBUG) jpayne@69: #define KJ_NDEBUG jpayne@69: #elif __OPTIMIZE__ jpayne@69: #define KJ_NDEBUG jpayne@69: #else jpayne@69: #define KJ_DEBUG jpayne@69: #endif jpayne@69: #endif jpayne@69: jpayne@69: #define KJ_DISALLOW_COPY(classname) \ jpayne@69: classname(const classname&) = delete; \ jpayne@69: classname& operator=(const classname&) = delete jpayne@69: // Deletes the implicit copy constructor and assignment operator. This inhibits the compiler from jpayne@69: // generating the implicit move constructor and assignment operator for this class, but allows the jpayne@69: // code author to supply them, if they make sense to implement. jpayne@69: // jpayne@69: // This macro should not be your first choice. Instead, prefer using KJ_DISALLOW_COPY_AND_MOVE, and only use jpayne@69: // this macro when you have determined that you must implement move semantics for your type. jpayne@69: jpayne@69: #define KJ_DISALLOW_COPY_AND_MOVE(classname) \ jpayne@69: classname(const classname&) = delete; \ jpayne@69: classname& operator=(const classname&) = delete; \ jpayne@69: classname(classname&&) = delete; \ jpayne@69: classname& operator=(classname&&) = delete jpayne@69: // Deletes the implicit copy and move constructors and assignment operators. This is useful in cases jpayne@69: // where the code author wants to provide an additional compile-time guard against subsequent jpayne@69: // maintainers casually adding move operations. This is particularly useful when implementing RAII jpayne@69: // classes that are intended to be completely immobile. jpayne@69: jpayne@69: #ifdef __GNUC__ jpayne@69: #define KJ_LIKELY(condition) __builtin_expect(condition, true) jpayne@69: #define KJ_UNLIKELY(condition) __builtin_expect(condition, false) jpayne@69: // Branch prediction macros. Evaluates to the condition given, but also tells the compiler that we jpayne@69: // expect the condition to be true/false enough of the time that it's worth hard-coding branch jpayne@69: // prediction. jpayne@69: #else jpayne@69: #define KJ_LIKELY(condition) (condition) jpayne@69: #define KJ_UNLIKELY(condition) (condition) jpayne@69: #endif jpayne@69: jpayne@69: #if defined(KJ_DEBUG) || __NO_INLINE__ jpayne@69: #define KJ_ALWAYS_INLINE(...) inline __VA_ARGS__ jpayne@69: // Don't force inline in debug mode. jpayne@69: #else jpayne@69: #if defined(_MSC_VER) && !defined(__clang__) jpayne@69: #define KJ_ALWAYS_INLINE(...) __forceinline __VA_ARGS__ jpayne@69: #else jpayne@69: #define KJ_ALWAYS_INLINE(...) inline __VA_ARGS__ __attribute__((always_inline)) jpayne@69: #endif jpayne@69: // Force a function to always be inlined. Apply only to the prototype, not to the definition. jpayne@69: #endif jpayne@69: jpayne@69: #if defined(_MSC_VER) && !defined(__clang__) jpayne@69: #define KJ_NOINLINE __declspec(noinline) jpayne@69: #else jpayne@69: #define KJ_NOINLINE __attribute__((noinline)) jpayne@69: #endif jpayne@69: jpayne@69: #if defined(_MSC_VER) && !__clang__ jpayne@69: #define KJ_NORETURN(prototype) __declspec(noreturn) prototype jpayne@69: #define KJ_UNUSED jpayne@69: #define KJ_WARN_UNUSED_RESULT jpayne@69: // TODO(msvc): KJ_WARN_UNUSED_RESULT can use _Check_return_ on MSVC, but it's a prefix, so jpayne@69: // wrapping the whole prototype is needed. http://msdn.microsoft.com/en-us/library/jj159529.aspx jpayne@69: // Similarly, KJ_UNUSED could use __pragma(warning(suppress:...)), but again that's a prefix. jpayne@69: #else jpayne@69: #define KJ_NORETURN(prototype) prototype __attribute__((noreturn)) jpayne@69: #define KJ_UNUSED __attribute__((unused)) jpayne@69: #define KJ_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) jpayne@69: #endif jpayne@69: jpayne@69: #if KJ_HAS_CPP_ATTRIBUTE(clang::lifetimebound) jpayne@69: // If this is generating too many false-positives, the user is responsible for disabling the jpayne@69: // problematic warning at the compiler switch level or by suppressing the place where the jpayne@69: // false-positive is reported through compiler-specific pragmas if available. jpayne@69: #define KJ_LIFETIMEBOUND [[clang::lifetimebound]] jpayne@69: #else jpayne@69: #define KJ_LIFETIMEBOUND jpayne@69: #endif jpayne@69: // Annotation that indicates the returned value is referencing a resource owned by this type (e.g. jpayne@69: // cStr() on a std::string). Unfortunately this lifetime can only be superficial currently & cannot jpayne@69: // track further. For example, there's no way to get `array.asPtr().slice(5, 6))` to warn if the jpayne@69: // last slice exceeds the lifetime of `array`. That's because in the general case `ArrayPtr::slice` jpayne@69: // can't have the lifetime bound annotation since it's not wrong to do something like: jpayne@69: // ArrayPtr doSomething(ArrayPtr foo) { jpayne@69: // ... jpayne@69: // return foo.slice(5, 6); jpayne@69: // } jpayne@69: // If `ArrayPtr::slice` had a lifetime bound then the compiler would warn about this perfectly jpayne@69: // legitimate method. Really there needs to be 2 more annotations. One to inherit the lifetime bound jpayne@69: // and another to inherit the lifetime bound from a parameter (which really could be the same thing jpayne@69: // by allowing a syntax like `[[clang::lifetimebound(*this)]]`. jpayne@69: // https://clang.llvm.org/docs/AttributeReference.html#lifetimebound jpayne@69: jpayne@69: #if __clang__ jpayne@69: #define KJ_UNUSED_MEMBER __attribute__((unused)) jpayne@69: // Inhibits "unused" warning for member variables. Only Clang produces such a warning, while GCC jpayne@69: // complains if the attribute is set on members. jpayne@69: #else jpayne@69: #define KJ_UNUSED_MEMBER jpayne@69: #endif jpayne@69: jpayne@69: #if KJ_CPP_STD > 201703L || (__clang__ && __clang_major__ >= 9 && KJ_CPP_STD >= 201103L) jpayne@69: // Technically this was only added to C++20 but Clang allows it for >= C++11 and spelunking the jpayne@69: // attributes manual indicates it first came in with Clang 9. jpayne@69: #define KJ_NO_UNIQUE_ADDRESS [[no_unique_address]] jpayne@69: #else jpayne@69: #define KJ_NO_UNIQUE_ADDRESS jpayne@69: #endif jpayne@69: jpayne@69: #if KJ_HAS_COMPILER_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) jpayne@69: #define KJ_DISABLE_TSAN __attribute__((no_sanitize("thread"), noinline)) jpayne@69: #else jpayne@69: #define KJ_DISABLE_TSAN jpayne@69: #endif jpayne@69: jpayne@69: #if __clang__ jpayne@69: #define KJ_DEPRECATED(reason) \ jpayne@69: __attribute__((deprecated(reason))) jpayne@69: #define KJ_UNAVAILABLE(reason) \ jpayne@69: __attribute__((unavailable(reason))) jpayne@69: #elif __GNUC__ jpayne@69: #define KJ_DEPRECATED(reason) \ jpayne@69: __attribute__((deprecated)) jpayne@69: #define KJ_UNAVAILABLE(reason) = delete jpayne@69: // If the `unavailable` attribute is not supproted, just mark the method deleted, which at least jpayne@69: // makes it a compile-time error to try to call it. Note that on Clang, marking a method deleted jpayne@69: // *and* unavailable unfortunately defeats the purpose of the unavailable annotation, as the jpayne@69: // generic "deleted" error is reported instead. jpayne@69: #else jpayne@69: #define KJ_DEPRECATED(reason) jpayne@69: #define KJ_UNAVAILABLE(reason) = delete jpayne@69: // TODO(msvc): Again, here, MSVC prefers a prefix, __declspec(deprecated). jpayne@69: #endif jpayne@69: jpayne@69: #if KJ_TESTING_KJ // defined in KJ's own unit tests; others should not define this jpayne@69: #undef KJ_DEPRECATED jpayne@69: #define KJ_DEPRECATED(reason) jpayne@69: #endif jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: KJ_NORETURN(void inlineRequireFailure( jpayne@69: const char* file, int line, const char* expectation, const char* macroArgs, jpayne@69: const char* message = nullptr)); jpayne@69: jpayne@69: KJ_NORETURN(void unreachable()); jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: jpayne@69: #if _MSC_VER && !defined(__clang__) && (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL) jpayne@69: #define KJ_MSVC_TRADITIONAL_CPP 1 jpayne@69: #endif jpayne@69: jpayne@69: #ifdef KJ_DEBUG jpayne@69: #if KJ_MSVC_TRADITIONAL_CPP jpayne@69: #define KJ_IREQUIRE(condition, ...) \ jpayne@69: if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \ jpayne@69: __FILE__, __LINE__, #condition, "" #__VA_ARGS__, __VA_ARGS__) jpayne@69: // Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to jpayne@69: // check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that jpayne@69: // it will be enabled depending on whether the application is compiled in debug mode rather than jpayne@69: // whether libkj is. jpayne@69: #else jpayne@69: #define KJ_IREQUIRE(condition, ...) \ jpayne@69: if (KJ_LIKELY(condition)); else ::kj::_::inlineRequireFailure( \ jpayne@69: __FILE__, __LINE__, #condition, #__VA_ARGS__, ##__VA_ARGS__) jpayne@69: // Version of KJ_DREQUIRE() which is safe to use in headers that are #included by users. Used to jpayne@69: // check preconditions inside inline methods. KJ_IREQUIRE is particularly useful in that jpayne@69: // it will be enabled depending on whether the application is compiled in debug mode rather than jpayne@69: // whether libkj is. jpayne@69: #endif jpayne@69: #else jpayne@69: #define KJ_IREQUIRE(condition, ...) jpayne@69: #endif jpayne@69: jpayne@69: #define KJ_IASSERT KJ_IREQUIRE jpayne@69: jpayne@69: #define KJ_UNREACHABLE ::kj::_::unreachable(); jpayne@69: // Put this on code paths that cannot be reached to suppress compiler warnings about missing jpayne@69: // returns. jpayne@69: jpayne@69: #if __clang__ jpayne@69: #define KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT jpayne@69: #else jpayne@69: #define KJ_CLANG_KNOWS_THIS_IS_UNREACHABLE_BUT_GCC_DOESNT KJ_UNREACHABLE jpayne@69: #endif jpayne@69: jpayne@69: #if __clang__ jpayne@69: #define KJ_KNOWN_UNREACHABLE(code) \ jpayne@69: do { \ jpayne@69: _Pragma("clang diagnostic push") \ jpayne@69: _Pragma("clang diagnostic ignored \"-Wunreachable-code\"") \ jpayne@69: code; \ jpayne@69: _Pragma("clang diagnostic pop") \ jpayne@69: } while (false) jpayne@69: // Suppress "unreachable code" warnings on intentionally unreachable code. jpayne@69: #else jpayne@69: // TODO(someday): Add support for non-clang compilers. jpayne@69: #define KJ_KNOWN_UNREACHABLE(code) do {code;} while(false) jpayne@69: #endif jpayne@69: jpayne@69: #if KJ_HAS_CPP_ATTRIBUTE(fallthrough) jpayne@69: #define KJ_FALLTHROUGH [[fallthrough]] jpayne@69: #else jpayne@69: #define KJ_FALLTHROUGH jpayne@69: #endif jpayne@69: jpayne@69: // #define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) jpayne@69: // jpayne@69: // Allocate an array, preferably on the stack, unless it is too big. On GCC this will use jpayne@69: // variable-sized arrays. For other compilers we could just use a fixed-size array. `minStack` jpayne@69: // is the stack array size to use if variable-width arrays are not supported. `maxStack` is the jpayne@69: // maximum stack array size if variable-width arrays *are* supported. jpayne@69: #if __GNUC__ && !__clang__ jpayne@69: #define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ jpayne@69: size_t name##_size = (size); \ jpayne@69: bool name##_isOnStack = name##_size <= (maxStack); \ jpayne@69: type name##_stack[kj::max(1, name##_isOnStack ? name##_size : 0)]; \ jpayne@69: ::kj::Array name##_heap = name##_isOnStack ? \ jpayne@69: nullptr : kj::heapArray(name##_size); \ jpayne@69: ::kj::ArrayPtr name = name##_isOnStack ? \ jpayne@69: kj::arrayPtr(name##_stack, name##_size) : name##_heap jpayne@69: #else jpayne@69: #define KJ_STACK_ARRAY(type, name, size, minStack, maxStack) \ jpayne@69: size_t name##_size = (size); \ jpayne@69: bool name##_isOnStack = name##_size <= (minStack); \ jpayne@69: type name##_stack[minStack]; \ jpayne@69: ::kj::Array name##_heap = name##_isOnStack ? \ jpayne@69: nullptr : kj::heapArray(name##_size); \ jpayne@69: ::kj::ArrayPtr name = name##_isOnStack ? \ jpayne@69: kj::arrayPtr(name##_stack, name##_size) : name##_heap jpayne@69: #endif jpayne@69: jpayne@69: #define KJ_CONCAT_(x, y) x##y jpayne@69: #define KJ_CONCAT(x, y) KJ_CONCAT_(x, y) jpayne@69: #define KJ_UNIQUE_NAME(prefix) KJ_CONCAT(prefix, __LINE__) jpayne@69: // Create a unique identifier name. We use concatenate __LINE__ rather than __COUNTER__ so that jpayne@69: // the name can be used multiple times in the same macro. jpayne@69: jpayne@69: #if _MSC_VER && !defined(__clang__) jpayne@69: jpayne@69: #define KJ_CONSTEXPR(...) __VA_ARGS__ jpayne@69: // Use in cases where MSVC barfs on constexpr. A replacement keyword (e.g. "const") can be jpayne@69: // provided, or just leave blank to remove the keyword entirely. jpayne@69: // jpayne@69: // TODO(msvc): Remove this hack once MSVC fully supports constexpr. jpayne@69: jpayne@69: #ifndef __restrict__ jpayne@69: #define __restrict__ __restrict jpayne@69: // TODO(msvc): Would it be better to define a KJ_RESTRICT macro? jpayne@69: #endif jpayne@69: jpayne@69: #pragma warning(disable: 4521 4522) jpayne@69: // This warning complains when there are two copy constructors, one for a const reference and jpayne@69: // one for a non-const reference. It is often quite necessary to do this in wrapper templates, jpayne@69: // therefore this warning is dumb and we disable it. jpayne@69: jpayne@69: #pragma warning(disable: 4458) jpayne@69: // Warns when a parameter name shadows a class member. Unfortunately my code does this a lot, jpayne@69: // since I don't use a special name format for members. jpayne@69: jpayne@69: #else // _MSC_VER jpayne@69: #define KJ_CONSTEXPR(...) constexpr jpayne@69: #endif jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Template metaprogramming helpers. jpayne@69: jpayne@69: #define KJ_HAS_TRIVIAL_CONSTRUCTOR __is_trivially_constructible jpayne@69: #if __GNUC__ && !__clang__ jpayne@69: #define KJ_HAS_NOTHROW_CONSTRUCTOR __has_nothrow_constructor jpayne@69: #define KJ_HAS_TRIVIAL_DESTRUCTOR __has_trivial_destructor jpayne@69: #else jpayne@69: #define KJ_HAS_NOTHROW_CONSTRUCTOR __is_nothrow_constructible jpayne@69: #define KJ_HAS_TRIVIAL_DESTRUCTOR __is_trivially_destructible jpayne@69: #endif jpayne@69: jpayne@69: template struct NoInfer_ { typedef T Type; }; jpayne@69: template using NoInfer = typename NoInfer_::Type; jpayne@69: // Use NoInfer::Type in place of T for a template function parameter to prevent inference of jpayne@69: // the type based on the parameter value. jpayne@69: jpayne@69: template struct RemoveConst_ { typedef T Type; }; jpayne@69: template struct RemoveConst_ { typedef T Type; }; jpayne@69: template using RemoveConst = typename RemoveConst_::Type; jpayne@69: jpayne@69: template struct IsLvalueReference_ { static constexpr bool value = false; }; jpayne@69: template struct IsLvalueReference_ { static constexpr bool value = true; }; jpayne@69: template jpayne@69: inline constexpr bool isLvalueReference() { return IsLvalueReference_::value; } jpayne@69: jpayne@69: template struct Decay_ { typedef T Type; }; jpayne@69: template struct Decay_ { typedef typename Decay_::Type Type; }; jpayne@69: template struct Decay_ { typedef typename Decay_::Type Type; }; jpayne@69: template struct Decay_ { typedef typename Decay_::Type Type; }; jpayne@69: template struct Decay_ { typedef typename Decay_::Type Type; }; jpayne@69: template struct Decay_ { typedef typename Decay_::Type Type; }; jpayne@69: template struct Decay_ { typedef typename Decay_::Type Type; }; jpayne@69: template struct Decay_ { typedef typename Decay_::Type Type; }; jpayne@69: template struct Decay_ { typedef typename Decay_::Type Type; }; jpayne@69: template using Decay = typename Decay_::Type; jpayne@69: jpayne@69: template struct EnableIf_; jpayne@69: template <> struct EnableIf_ { typedef void Type; }; jpayne@69: template using EnableIf = typename EnableIf_::Type; jpayne@69: // Use like: jpayne@69: // jpayne@69: // template ()>> jpayne@69: // void func(T&& t); jpayne@69: jpayne@69: template struct VoidSfinae_ { using Type = void; }; jpayne@69: template using VoidSfinae = typename VoidSfinae_::Type; jpayne@69: // Note: VoidSfinae is std::void_t from C++17. jpayne@69: jpayne@69: template jpayne@69: T instance() noexcept; jpayne@69: // Like std::declval, but doesn't transform T into an rvalue reference. If you want that, specify jpayne@69: // instance(). jpayne@69: jpayne@69: struct DisallowConstCopy { jpayne@69: // Inherit from this, or declare a member variable of this type, to prevent the class from being jpayne@69: // copyable from a const reference -- instead, it will only be copyable from non-const references. jpayne@69: // This is useful for enforcing transitive constness of contained pointers. jpayne@69: // jpayne@69: // For example, say you have a type T which contains a pointer. T has non-const methods which jpayne@69: // modify the value at that pointer, but T's const methods are designed to allow reading only. jpayne@69: // Unfortunately, if T has a regular copy constructor, someone can simply make a copy of T and jpayne@69: // then use it to modify the pointed-to value. However, if T inherits DisallowConstCopy, then jpayne@69: // callers will only be able to copy non-const instances of T. Ideally, there is some jpayne@69: // parallel type ImmutableT which is like a version of T that only has const methods, and can jpayne@69: // be copied from a const T. jpayne@69: // jpayne@69: // Note that due to C++ rules about implicit copy constructors and assignment operators, any jpayne@69: // type that contains or inherits from a type that disallows const copies will also automatically jpayne@69: // disallow const copies. Hey, cool, that's exactly what we want. jpayne@69: jpayne@69: #if CAPNP_DEBUG_TYPES jpayne@69: // Alas! Declaring a defaulted non-const copy constructor tickles a bug which causes GCC and jpayne@69: // Clang to disagree on ABI, using different calling conventions to pass this type, leading to jpayne@69: // immediate segfaults. See: jpayne@69: // https://bugs.llvm.org/show_bug.cgi?id=23764 jpayne@69: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58074 jpayne@69: // jpayne@69: // Because of this, we can't use this technique. We guard it by CAPNP_DEBUG_TYPES so that it jpayne@69: // still applies to the Cap'n Proto developers during internal testing. jpayne@69: jpayne@69: DisallowConstCopy() = default; jpayne@69: DisallowConstCopy(DisallowConstCopy&) = default; jpayne@69: DisallowConstCopy(DisallowConstCopy&&) = default; jpayne@69: DisallowConstCopy& operator=(DisallowConstCopy&) = default; jpayne@69: DisallowConstCopy& operator=(DisallowConstCopy&&) = default; jpayne@69: #endif jpayne@69: }; jpayne@69: jpayne@69: #if _MSC_VER && !defined(__clang__) jpayne@69: jpayne@69: #define KJ_CPCAP(obj) obj=::kj::cp(obj) jpayne@69: // TODO(msvc): MSVC refuses to invoke non-const versions of copy constructors in by-value lambda jpayne@69: // captures. Wrap your captured object in this macro to force the compiler to perform a copy. jpayne@69: // Example: jpayne@69: // jpayne@69: // struct Foo: DisallowConstCopy {}; jpayne@69: // Foo foo; jpayne@69: // auto lambda = [KJ_CPCAP(foo)] {}; jpayne@69: jpayne@69: #else jpayne@69: jpayne@69: #define KJ_CPCAP(obj) obj jpayne@69: // Clang and gcc both already perform copy capturing correctly with non-const copy constructors. jpayne@69: jpayne@69: #endif jpayne@69: jpayne@69: template jpayne@69: struct DisallowConstCopyIfNotConst: public DisallowConstCopy { jpayne@69: // Inherit from this when implementing a template that contains a pointer to T and which should jpayne@69: // enforce transitive constness. If T is a const type, this has no effect. Otherwise, it is jpayne@69: // an alias for DisallowConstCopy. jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: struct DisallowConstCopyIfNotConst {}; jpayne@69: jpayne@69: template struct IsConst_ { static constexpr bool value = false; }; jpayne@69: template struct IsConst_ { static constexpr bool value = true; }; jpayne@69: template constexpr bool isConst() { return IsConst_::value; } jpayne@69: jpayne@69: template struct EnableIfNotConst_ { typedef T Type; }; jpayne@69: template struct EnableIfNotConst_; jpayne@69: template using EnableIfNotConst = typename EnableIfNotConst_::Type; jpayne@69: jpayne@69: template struct EnableIfConst_; jpayne@69: template struct EnableIfConst_ { typedef T Type; }; jpayne@69: template using EnableIfConst = typename EnableIfConst_::Type; jpayne@69: jpayne@69: template struct RemoveConstOrDisable_ { struct Type; }; jpayne@69: template struct RemoveConstOrDisable_ { typedef T Type; }; jpayne@69: template using RemoveConstOrDisable = typename RemoveConstOrDisable_::Type; jpayne@69: jpayne@69: template struct IsReference_ { static constexpr bool value = false; }; jpayne@69: template struct IsReference_ { static constexpr bool value = true; }; jpayne@69: template constexpr bool isReference() { return IsReference_::value; } jpayne@69: jpayne@69: template jpayne@69: struct PropagateConst_ { typedef To Type; }; jpayne@69: template jpayne@69: struct PropagateConst_ { typedef const To Type; }; jpayne@69: template jpayne@69: using PropagateConst = typename PropagateConst_::Type; jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: template jpayne@69: T refIfLvalue(T&&); jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: jpayne@69: #define KJ_DECLTYPE_REF(exp) decltype(::kj::_::refIfLvalue(exp)) jpayne@69: // Like decltype(exp), but if exp is an lvalue, produces a reference type. jpayne@69: // jpayne@69: // int i; jpayne@69: // decltype(i) i1(i); // i1 has type int. jpayne@69: // KJ_DECLTYPE_REF(i + 1) i2(i + 1); // i2 has type int. jpayne@69: // KJ_DECLTYPE_REF(i) i3(i); // i3 has type int&. jpayne@69: // KJ_DECLTYPE_REF(kj::mv(i)) i4(kj::mv(i)); // i4 has type int. jpayne@69: jpayne@69: template struct IsSameType_ { static constexpr bool value = false; }; jpayne@69: template struct IsSameType_ { static constexpr bool value = true; }; jpayne@69: template constexpr bool isSameType() { return IsSameType_::value; } jpayne@69: jpayne@69: template constexpr bool isIntegral() { return false; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: template <> constexpr bool isIntegral() { return true; } jpayne@69: jpayne@69: template jpayne@69: struct CanConvert_ { jpayne@69: static int sfinae(T); jpayne@69: static bool sfinae(...); jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: constexpr bool canConvert() { jpayne@69: return sizeof(CanConvert_::sfinae(instance())) == sizeof(int); jpayne@69: } jpayne@69: jpayne@69: #if __GNUC__ && !__clang__ && __GNUC__ < 5 jpayne@69: template jpayne@69: constexpr bool canMemcpy() { jpayne@69: // Returns true if T can be copied using memcpy instead of using the copy constructor or jpayne@69: // assignment operator. jpayne@69: jpayne@69: // GCC 4 does not have __is_trivially_constructible and friends, and there doesn't seem to be jpayne@69: // any reliable alternative. __has_trivial_copy() and __has_trivial_assign() return the right jpayne@69: // thing at one point but later on they changed such that a deleted copy constructor was jpayne@69: // considered "trivial" (apparently technically correct, though useless). So, on GCC 4 we give up jpayne@69: // and assume we can't memcpy() at all, and must explicitly copy-construct everything. jpayne@69: return false; jpayne@69: } jpayne@69: #define KJ_ASSERT_CAN_MEMCPY(T) jpayne@69: #else jpayne@69: template jpayne@69: constexpr bool canMemcpy() { jpayne@69: // Returns true if T can be copied using memcpy instead of using the copy constructor or jpayne@69: // assignment operator. jpayne@69: jpayne@69: return __is_trivially_constructible(T, const T&) && __is_trivially_assignable(T, const T&); jpayne@69: } jpayne@69: #define KJ_ASSERT_CAN_MEMCPY(T) \ jpayne@69: static_assert(kj::canMemcpy(), "this code expects this type to be memcpy()-able"); jpayne@69: #endif jpayne@69: jpayne@69: template jpayne@69: class Badge { jpayne@69: // A pattern for marking individual methods such that they can only be called from a specific jpayne@69: // caller class: Make the method public but give it a parameter of type `Badge`. Only jpayne@69: // `Caller` can construct one, so only `Caller` can call the method. jpayne@69: // jpayne@69: // // We only allow calls from the class `Bar`. jpayne@69: // void foo(Badge) jpayne@69: // jpayne@69: // The call site looks like: jpayne@69: // jpayne@69: // foo({}); jpayne@69: // jpayne@69: // This pattern also works well for declaring private constructors, but still being able to use jpayne@69: // them with `kj::heap()`, etc. jpayne@69: // jpayne@69: // Idea from: https://awesomekling.github.io/Serenity-C++-patterns-The-Badge/ jpayne@69: // jpayne@69: // Note that some forms of this idea make the copy constructor private as well, in order to jpayne@69: // prohibit `Badge(*(Badge*)nullptr)`. However, that would prevent badges from jpayne@69: // being passed through forwarding functions like `kj::heap()`, which would ruin one of the main jpayne@69: // use cases for this pattern in KJ. In any case, dereferencing a null pointer is UB; there are jpayne@69: // plenty of other ways to get access to private members if you're willing to go UB. For one-off jpayne@69: // debugging purposes, you might as well use `#define private public` at the top of the file. jpayne@69: private: jpayne@69: Badge() {} jpayne@69: friend T; jpayne@69: }; jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Equivalents to std::move() and std::forward(), since these are very commonly needed and the jpayne@69: // std header pulls in lots of other stuff. jpayne@69: // jpayne@69: // We use abbreviated names mv and fwd because these helpers (especially mv) are so commonly used jpayne@69: // that the cost of typing more letters outweighs the cost of being slightly harder to understand jpayne@69: // when first encountered. jpayne@69: jpayne@69: template constexpr T&& mv(T& t) noexcept { return static_cast(t); } jpayne@69: template constexpr T&& fwd(NoInfer& t) noexcept { return static_cast(t); } jpayne@69: jpayne@69: template constexpr T cp(T& t) noexcept { return t; } jpayne@69: template constexpr T cp(const T& t) noexcept { return t; } jpayne@69: // Useful to force a copy, particularly to pass into a function that expects T&&. jpayne@69: jpayne@69: template struct ChooseType_; jpayne@69: template struct ChooseType_ { typedef T Type; }; jpayne@69: template struct ChooseType_ { typedef T Type; }; jpayne@69: template struct ChooseType_ { typedef U Type; }; jpayne@69: jpayne@69: template jpayne@69: using WiderType = typename ChooseType_= sizeof(U)>::Type; jpayne@69: jpayne@69: template jpayne@69: inline constexpr auto min(T&& a, U&& b) -> WiderType, Decay> { jpayne@69: return a < b ? WiderType, Decay>(a) : WiderType, Decay>(b); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: inline constexpr auto max(T&& a, U&& b) -> WiderType, Decay> { jpayne@69: return a > b ? WiderType, Decay>(a) : WiderType, Decay>(b); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: inline constexpr size_t size(T (&arr)[s]) { return s; } jpayne@69: template jpayne@69: inline constexpr size_t size(T&& arr) { return arr.size(); } jpayne@69: // Returns the size of the parameter, whether the parameter is a regular C array or a container jpayne@69: // with a `.size()` method. jpayne@69: jpayne@69: class MaxValue_ { jpayne@69: private: jpayne@69: template jpayne@69: inline constexpr T maxSigned() const { jpayne@69: return (1ull << (sizeof(T) * 8 - 1)) - 1; jpayne@69: } jpayne@69: template jpayne@69: inline constexpr T maxUnsigned() const { jpayne@69: return ~static_cast(0u); jpayne@69: } jpayne@69: jpayne@69: public: jpayne@69: #define _kJ_HANDLE_TYPE(T) \ jpayne@69: inline constexpr operator signed T() const { return MaxValue_::maxSigned < signed T>(); } \ jpayne@69: inline constexpr operator unsigned T() const { return MaxValue_::maxUnsigned(); } jpayne@69: _kJ_HANDLE_TYPE(char) jpayne@69: _kJ_HANDLE_TYPE(short) jpayne@69: _kJ_HANDLE_TYPE(int) jpayne@69: _kJ_HANDLE_TYPE(long) jpayne@69: _kJ_HANDLE_TYPE(long long) jpayne@69: #undef _kJ_HANDLE_TYPE jpayne@69: jpayne@69: inline constexpr operator char() const { jpayne@69: // `char` is different from both `signed char` and `unsigned char`, and may be signed or jpayne@69: // unsigned on different platforms. Ugh. jpayne@69: return char(-1) < 0 ? MaxValue_::maxSigned() jpayne@69: : MaxValue_::maxUnsigned(); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: class MinValue_ { jpayne@69: private: jpayne@69: template jpayne@69: inline constexpr T minSigned() const { jpayne@69: return 1ull << (sizeof(T) * 8 - 1); jpayne@69: } jpayne@69: template jpayne@69: inline constexpr T minUnsigned() const { jpayne@69: return 0u; jpayne@69: } jpayne@69: jpayne@69: public: jpayne@69: #define _kJ_HANDLE_TYPE(T) \ jpayne@69: inline constexpr operator signed T() const { return MinValue_::minSigned < signed T>(); } \ jpayne@69: inline constexpr operator unsigned T() const { return MinValue_::minUnsigned(); } jpayne@69: _kJ_HANDLE_TYPE(char) jpayne@69: _kJ_HANDLE_TYPE(short) jpayne@69: _kJ_HANDLE_TYPE(int) jpayne@69: _kJ_HANDLE_TYPE(long) jpayne@69: _kJ_HANDLE_TYPE(long long) jpayne@69: #undef _kJ_HANDLE_TYPE jpayne@69: jpayne@69: inline constexpr operator char() const { jpayne@69: // `char` is different from both `signed char` and `unsigned char`, and may be signed or jpayne@69: // unsigned on different platforms. Ugh. jpayne@69: return char(-1) < 0 ? MinValue_::minSigned() jpayne@69: : MinValue_::minUnsigned(); jpayne@69: } jpayne@69: }; jpayne@69: jpayne@69: static KJ_CONSTEXPR(const) MaxValue_ maxValue = MaxValue_(); jpayne@69: // A special constant which, when cast to an integer type, takes on the maximum possible value of jpayne@69: // that type. This is useful to use as e.g. a parameter to a function because it will be robust jpayne@69: // in the face of changes to the parameter's type. jpayne@69: // jpayne@69: // `char` is not supported, but `signed char` and `unsigned char` are. jpayne@69: jpayne@69: static KJ_CONSTEXPR(const) MinValue_ minValue = MinValue_(); jpayne@69: // A special constant which, when cast to an integer type, takes on the minimum possible value jpayne@69: // of that type. This is useful to use as e.g. a parameter to a function because it will be robust jpayne@69: // in the face of changes to the parameter's type. jpayne@69: // jpayne@69: // `char` is not supported, but `signed char` and `unsigned char` are. jpayne@69: jpayne@69: template jpayne@69: inline bool operator==(T t, MaxValue_) { return t == Decay(maxValue); } jpayne@69: template jpayne@69: inline bool operator==(T t, MinValue_) { return t == Decay(minValue); } jpayne@69: jpayne@69: template jpayne@69: inline constexpr unsigned long long maxValueForBits() { jpayne@69: // Get the maximum integer representable in the given number of bits. jpayne@69: jpayne@69: // 1ull << 64 is unfortunately undefined. jpayne@69: return (bits == 64 ? 0 : (1ull << bits)) - 1; jpayne@69: } jpayne@69: jpayne@69: struct ThrowOverflow { jpayne@69: // Functor which throws an exception complaining about integer overflow. Usually this is used jpayne@69: // with the interfaces in units.h, but is defined here because Cap'n Proto wants to avoid jpayne@69: // including units.h when not using CAPNP_DEBUG_TYPES. jpayne@69: [[noreturn]] void operator()() const; jpayne@69: }; jpayne@69: jpayne@69: #if __GNUC__ || __clang__ || _MSC_VER jpayne@69: inline constexpr float inf() { return __builtin_huge_valf(); } jpayne@69: inline constexpr float nan() { return __builtin_nanf(""); } jpayne@69: jpayne@69: #else jpayne@69: #error "Not sure how to support your compiler." jpayne@69: #endif jpayne@69: jpayne@69: inline constexpr bool isNaN(float f) { return f != f; } jpayne@69: inline constexpr bool isNaN(double f) { return f != f; } jpayne@69: jpayne@69: inline int popCount(unsigned int x) { jpayne@69: #if defined(_MSC_VER) && !defined(__clang__) jpayne@69: return __popcnt(x); jpayne@69: // Note: __popcnt returns unsigned int, but the value is clearly guaranteed to fit into an int jpayne@69: #else jpayne@69: return __builtin_popcount(x); jpayne@69: #endif jpayne@69: } jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Useful fake containers jpayne@69: jpayne@69: template jpayne@69: class Range { jpayne@69: public: jpayne@69: inline constexpr Range(const T& begin, const T& end): begin_(begin), end_(end) {} jpayne@69: inline explicit constexpr Range(const T& end): begin_(0), end_(end) {} jpayne@69: jpayne@69: class Iterator { jpayne@69: public: jpayne@69: Iterator() = default; jpayne@69: inline Iterator(const T& value): value(value) {} jpayne@69: jpayne@69: inline const T& operator* () const { return value; } jpayne@69: inline const T& operator[](size_t index) const { return value + index; } jpayne@69: inline Iterator& operator++() { ++value; return *this; } jpayne@69: inline Iterator operator++(int) { return Iterator(value++); } jpayne@69: inline Iterator& operator--() { --value; return *this; } jpayne@69: inline Iterator operator--(int) { return Iterator(value--); } jpayne@69: inline Iterator& operator+=(ptrdiff_t amount) { value += amount; return *this; } jpayne@69: inline Iterator& operator-=(ptrdiff_t amount) { value -= amount; return *this; } jpayne@69: inline Iterator operator+ (ptrdiff_t amount) const { return Iterator(value + amount); } jpayne@69: inline Iterator operator- (ptrdiff_t amount) const { return Iterator(value - amount); } jpayne@69: inline ptrdiff_t operator- (const Iterator& other) const { return value - other.value; } jpayne@69: jpayne@69: inline bool operator==(const Iterator& other) const { return value == other.value; } jpayne@69: inline bool operator!=(const Iterator& other) const { return value != other.value; } jpayne@69: inline bool operator<=(const Iterator& other) const { return value <= other.value; } jpayne@69: inline bool operator>=(const Iterator& other) const { return value >= other.value; } jpayne@69: inline bool operator< (const Iterator& other) const { return value < other.value; } jpayne@69: inline bool operator> (const Iterator& other) const { return value > other.value; } jpayne@69: jpayne@69: private: jpayne@69: T value; jpayne@69: }; jpayne@69: jpayne@69: inline Iterator begin() const { return Iterator(begin_); } jpayne@69: inline Iterator end() const { return Iterator(end_); } jpayne@69: jpayne@69: inline auto size() const -> decltype(instance() - instance()) { return end_ - begin_; } jpayne@69: jpayne@69: private: jpayne@69: T begin_; jpayne@69: T end_; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: inline constexpr Range, Decay>> range(T begin, U end) { jpayne@69: return Range, Decay>>(begin, end); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: inline constexpr Range> range(T begin, T end) { return Range>(begin, end); } jpayne@69: // Returns a fake iterable container containing all values of T from `begin` (inclusive) to `end` jpayne@69: // (exclusive). Example: jpayne@69: // jpayne@69: // // Prints 1, 2, 3, 4, 5, 6, 7, 8, 9. jpayne@69: // for (int i: kj::range(1, 10)) { print(i); } jpayne@69: jpayne@69: template jpayne@69: inline constexpr Range> zeroTo(T end) { return Range>(end); } jpayne@69: // Returns a fake iterable container containing all values of T from zero (inclusive) to `end` jpayne@69: // (exclusive). Example: jpayne@69: // jpayne@69: // // Prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. jpayne@69: // for (int i: kj::zeroTo(10)) { print(i); } jpayne@69: jpayne@69: template jpayne@69: inline constexpr Range indices(T&& container) { jpayne@69: // Shortcut for iterating over the indices of a container: jpayne@69: // jpayne@69: // for (size_t i: kj::indices(myArray)) { handle(myArray[i]); } jpayne@69: jpayne@69: return range(0, kj::size(container)); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: class Repeat { jpayne@69: public: jpayne@69: inline constexpr Repeat(const T& value, size_t count): value(value), count(count) {} jpayne@69: jpayne@69: class Iterator { jpayne@69: public: jpayne@69: Iterator() = default; jpayne@69: inline Iterator(const T& value, size_t index): value(value), index(index) {} jpayne@69: jpayne@69: inline const T& operator* () const { return value; } jpayne@69: inline const T& operator[](ptrdiff_t index) const { return value; } jpayne@69: inline Iterator& operator++() { ++index; return *this; } jpayne@69: inline Iterator operator++(int) { return Iterator(value, index++); } jpayne@69: inline Iterator& operator--() { --index; return *this; } jpayne@69: inline Iterator operator--(int) { return Iterator(value, index--); } jpayne@69: inline Iterator& operator+=(ptrdiff_t amount) { index += amount; return *this; } jpayne@69: inline Iterator& operator-=(ptrdiff_t amount) { index -= amount; return *this; } jpayne@69: inline Iterator operator+ (ptrdiff_t amount) const { return Iterator(value, index + amount); } jpayne@69: inline Iterator operator- (ptrdiff_t amount) const { return Iterator(value, index - amount); } jpayne@69: inline ptrdiff_t operator- (const Iterator& other) const { return index - other.index; } jpayne@69: jpayne@69: inline bool operator==(const Iterator& other) const { return index == other.index; } jpayne@69: inline bool operator!=(const Iterator& other) const { return index != other.index; } jpayne@69: inline bool operator<=(const Iterator& other) const { return index <= other.index; } jpayne@69: inline bool operator>=(const Iterator& other) const { return index >= other.index; } jpayne@69: inline bool operator< (const Iterator& other) const { return index < other.index; } jpayne@69: inline bool operator> (const Iterator& other) const { return index > other.index; } jpayne@69: jpayne@69: private: jpayne@69: T value; jpayne@69: size_t index; jpayne@69: }; jpayne@69: jpayne@69: inline Iterator begin() const { return Iterator(value, 0); } jpayne@69: inline Iterator end() const { return Iterator(value, count); } jpayne@69: jpayne@69: inline size_t size() const { return count; } jpayne@69: inline const T& operator[](ptrdiff_t) const { return value; } jpayne@69: jpayne@69: private: jpayne@69: T value; jpayne@69: size_t count; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: inline constexpr Repeat> repeat(T&& value, size_t count) { jpayne@69: // Returns a fake iterable which contains `count` repeats of `value`. Useful for e.g. creating jpayne@69: // a bunch of spaces: `kj::repeat(' ', indent * 2)` jpayne@69: jpayne@69: return Repeat>(value, count); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: class MappedIterator: private Mapping { jpayne@69: // An iterator that wraps some other iterator and maps the values through a mapping function. jpayne@69: // The type `Mapping` must define a method `map()` which performs this mapping. jpayne@69: jpayne@69: public: jpayne@69: template jpayne@69: MappedIterator(Inner inner, Params&&... params) jpayne@69: : Mapping(kj::fwd(params)...), inner(inner) {} jpayne@69: jpayne@69: inline auto operator->() const { return &Mapping::map(*inner); } jpayne@69: inline decltype(auto) operator* () const { return Mapping::map(*inner); } jpayne@69: inline decltype(auto) operator[](size_t index) const { return Mapping::map(inner[index]); } jpayne@69: inline MappedIterator& operator++() { ++inner; return *this; } jpayne@69: inline MappedIterator operator++(int) { return MappedIterator(inner++, *this); } jpayne@69: inline MappedIterator& operator--() { --inner; return *this; } jpayne@69: inline MappedIterator operator--(int) { return MappedIterator(inner--, *this); } jpayne@69: inline MappedIterator& operator+=(ptrdiff_t amount) { inner += amount; return *this; } jpayne@69: inline MappedIterator& operator-=(ptrdiff_t amount) { inner -= amount; return *this; } jpayne@69: inline MappedIterator operator+ (ptrdiff_t amount) const { jpayne@69: return MappedIterator(inner + amount, *this); jpayne@69: } jpayne@69: inline MappedIterator operator- (ptrdiff_t amount) const { jpayne@69: return MappedIterator(inner - amount, *this); jpayne@69: } jpayne@69: inline ptrdiff_t operator- (const MappedIterator& other) const { return inner - other.inner; } jpayne@69: jpayne@69: inline bool operator==(const MappedIterator& other) const { return inner == other.inner; } jpayne@69: inline bool operator!=(const MappedIterator& other) const { return inner != other.inner; } jpayne@69: inline bool operator<=(const MappedIterator& other) const { return inner <= other.inner; } jpayne@69: inline bool operator>=(const MappedIterator& other) const { return inner >= other.inner; } jpayne@69: inline bool operator< (const MappedIterator& other) const { return inner < other.inner; } jpayne@69: inline bool operator> (const MappedIterator& other) const { return inner > other.inner; } jpayne@69: jpayne@69: private: jpayne@69: Inner inner; jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: class MappedIterable: private Mapping { jpayne@69: // An iterable that wraps some other iterable and maps the values through a mapping function. jpayne@69: // The type `Mapping` must define a method `map()` which performs this mapping. jpayne@69: jpayne@69: public: jpayne@69: template jpayne@69: MappedIterable(Inner inner, Params&&... params) jpayne@69: : Mapping(kj::fwd(params)...), inner(inner) {} jpayne@69: jpayne@69: typedef Decay().begin())> InnerIterator; jpayne@69: typedef MappedIterator Iterator; jpayne@69: typedef Decay().begin())> InnerConstIterator; jpayne@69: typedef MappedIterator ConstIterator; jpayne@69: jpayne@69: inline Iterator begin() { return { inner.begin(), (Mapping&)*this }; } jpayne@69: inline Iterator end() { return { inner.end(), (Mapping&)*this }; } jpayne@69: inline ConstIterator begin() const { return { inner.begin(), (const Mapping&)*this }; } jpayne@69: inline ConstIterator end() const { return { inner.end(), (const Mapping&)*this }; } jpayne@69: jpayne@69: private: jpayne@69: Inner inner; jpayne@69: }; jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Manually invoking constructors and destructors jpayne@69: // jpayne@69: // ctor(x, ...) and dtor(x) invoke x's constructor or destructor, respectively. jpayne@69: jpayne@69: // We want placement new, but we don't want to #include . operator new cannot be defined in jpayne@69: // a namespace, and defining it globally conflicts with the definition in . So we have to jpayne@69: // define a dummy type and an operator new that uses it. jpayne@69: jpayne@69: namespace _ { // private jpayne@69: struct PlacementNew {}; jpayne@69: } // namespace _ (private) jpayne@69: } // namespace kj jpayne@69: jpayne@69: inline void* operator new(size_t, kj::_::PlacementNew, void* __p) noexcept { jpayne@69: return __p; jpayne@69: } jpayne@69: jpayne@69: inline void operator delete(void*, kj::_::PlacementNew, void* __p) noexcept {} jpayne@69: jpayne@69: namespace kj { jpayne@69: jpayne@69: template jpayne@69: inline void ctor(T& location, Params&&... params) { jpayne@69: new (_::PlacementNew(), &location) T(kj::fwd(params)...); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: inline void dtor(T& location) { jpayne@69: location.~T(); jpayne@69: } jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Maybe jpayne@69: // jpayne@69: // Use in cases where you want to indicate that a value may be null. Using Maybe instead of T* jpayne@69: // forces the caller to handle the null case in order to satisfy the compiler, thus reliably jpayne@69: // preventing null pointer dereferences at runtime. jpayne@69: // jpayne@69: // Maybe can be implicitly constructed from T and from nullptr. jpayne@69: // To read the value of a Maybe, do: jpayne@69: // jpayne@69: // KJ_IF_MAYBE(value, someFuncReturningMaybe()) { jpayne@69: // doSomething(*value); jpayne@69: // } else { jpayne@69: // maybeWasNull(); jpayne@69: // } jpayne@69: // jpayne@69: // KJ_IF_MAYBE's first parameter is a variable name which will be defined within the following jpayne@69: // block. The variable will behave like a (guaranteed non-null) pointer to the Maybe's value, jpayne@69: // though it may or may not actually be a pointer. jpayne@69: // jpayne@69: // Note that Maybe actually just wraps a pointer, whereas Maybe wraps a T and a boolean jpayne@69: // indicating nullness. jpayne@69: jpayne@69: template jpayne@69: class Maybe; jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: template jpayne@69: class NullableValue { jpayne@69: // Class whose interface behaves much like T*, but actually contains an instance of T and a jpayne@69: // boolean flag indicating nullness. jpayne@69: jpayne@69: public: jpayne@69: inline NullableValue(NullableValue&& other) jpayne@69: : isSet(other.isSet) { jpayne@69: if (isSet) { jpayne@69: ctor(value, kj::mv(other.value)); jpayne@69: } jpayne@69: } jpayne@69: inline NullableValue(const NullableValue& other) jpayne@69: : isSet(other.isSet) { jpayne@69: if (isSet) { jpayne@69: ctor(value, other.value); jpayne@69: } jpayne@69: } jpayne@69: inline NullableValue(NullableValue& other) jpayne@69: : isSet(other.isSet) { jpayne@69: if (isSet) { jpayne@69: ctor(value, other.value); jpayne@69: } jpayne@69: } jpayne@69: inline ~NullableValue() jpayne@69: #if _MSC_VER && !defined(__clang__) jpayne@69: // TODO(msvc): MSVC has a hard time with noexcept specifier expressions that are more complex jpayne@69: // than `true` or `false`. We had a workaround for VS2015, but VS2017 regressed. jpayne@69: noexcept(false) jpayne@69: #else jpayne@69: noexcept(noexcept(instance().~T())) jpayne@69: #endif jpayne@69: { jpayne@69: if (isSet) { jpayne@69: dtor(value); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: inline T& operator*() & { return value; } jpayne@69: inline const T& operator*() const & { return value; } jpayne@69: inline T&& operator*() && { return kj::mv(value); } jpayne@69: inline const T&& operator*() const && { return kj::mv(value); } jpayne@69: inline T* operator->() { return &value; } jpayne@69: inline const T* operator->() const { return &value; } jpayne@69: inline operator T*() { return isSet ? &value : nullptr; } jpayne@69: inline operator const T*() const { return isSet ? &value : nullptr; } jpayne@69: jpayne@69: template jpayne@69: inline T& emplace(Params&&... params) { jpayne@69: if (isSet) { jpayne@69: isSet = false; jpayne@69: dtor(value); jpayne@69: } jpayne@69: ctor(value, kj::fwd(params)...); jpayne@69: isSet = true; jpayne@69: return value; jpayne@69: } jpayne@69: jpayne@69: inline NullableValue(): isSet(false) {} jpayne@69: inline NullableValue(T&& t) jpayne@69: : isSet(true) { jpayne@69: ctor(value, kj::mv(t)); jpayne@69: } jpayne@69: inline NullableValue(T& t) jpayne@69: : isSet(true) { jpayne@69: ctor(value, t); jpayne@69: } jpayne@69: inline NullableValue(const T& t) jpayne@69: : isSet(true) { jpayne@69: ctor(value, t); jpayne@69: } jpayne@69: template jpayne@69: inline NullableValue(NullableValue&& other) jpayne@69: : isSet(other.isSet) { jpayne@69: if (isSet) { jpayne@69: ctor(value, kj::mv(other.value)); jpayne@69: } jpayne@69: } jpayne@69: template jpayne@69: inline NullableValue(const NullableValue& other) jpayne@69: : isSet(other.isSet) { jpayne@69: if (isSet) { jpayne@69: ctor(value, other.value); jpayne@69: } jpayne@69: } jpayne@69: template jpayne@69: inline NullableValue(const NullableValue& other) jpayne@69: : isSet(other.isSet) { jpayne@69: if (isSet) { jpayne@69: ctor(value, *other.ptr); jpayne@69: } jpayne@69: } jpayne@69: inline NullableValue(decltype(nullptr)): isSet(false) {} jpayne@69: jpayne@69: inline NullableValue& operator=(NullableValue&& other) { jpayne@69: if (&other != this) { jpayne@69: // Careful about throwing destructors/constructors here. jpayne@69: if (isSet) { jpayne@69: isSet = false; jpayne@69: dtor(value); jpayne@69: } jpayne@69: if (other.isSet) { jpayne@69: ctor(value, kj::mv(other.value)); jpayne@69: isSet = true; jpayne@69: } jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: inline NullableValue& operator=(NullableValue& other) { jpayne@69: if (&other != this) { jpayne@69: // Careful about throwing destructors/constructors here. jpayne@69: if (isSet) { jpayne@69: isSet = false; jpayne@69: dtor(value); jpayne@69: } jpayne@69: if (other.isSet) { jpayne@69: ctor(value, other.value); jpayne@69: isSet = true; jpayne@69: } jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: inline NullableValue& operator=(const NullableValue& other) { jpayne@69: if (&other != this) { jpayne@69: // Careful about throwing destructors/constructors here. jpayne@69: if (isSet) { jpayne@69: isSet = false; jpayne@69: dtor(value); jpayne@69: } jpayne@69: if (other.isSet) { jpayne@69: ctor(value, other.value); jpayne@69: isSet = true; jpayne@69: } jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: inline NullableValue& operator=(T&& other) { emplace(kj::mv(other)); return *this; } jpayne@69: inline NullableValue& operator=(T& other) { emplace(other); return *this; } jpayne@69: inline NullableValue& operator=(const T& other) { emplace(other); return *this; } jpayne@69: template jpayne@69: inline NullableValue& operator=(NullableValue&& other) { jpayne@69: if (other.isSet) { jpayne@69: emplace(kj::mv(other.value)); jpayne@69: } else { jpayne@69: *this = nullptr; jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: template jpayne@69: inline NullableValue& operator=(const NullableValue& other) { jpayne@69: if (other.isSet) { jpayne@69: emplace(other.value); jpayne@69: } else { jpayne@69: *this = nullptr; jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: template jpayne@69: inline NullableValue& operator=(const NullableValue& other) { jpayne@69: if (other.isSet) { jpayne@69: emplace(other.value); jpayne@69: } else { jpayne@69: *this = nullptr; jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: inline NullableValue& operator=(decltype(nullptr)) { jpayne@69: if (isSet) { jpayne@69: isSet = false; jpayne@69: dtor(value); jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: inline bool operator==(decltype(nullptr)) const { return !isSet; } jpayne@69: inline bool operator!=(decltype(nullptr)) const { return isSet; } jpayne@69: jpayne@69: NullableValue(const T* t) = delete; jpayne@69: NullableValue& operator=(const T* other) = delete; jpayne@69: // We used to permit assigning a Maybe directly from a T*, and the assignment would check for jpayne@69: // nullness. This turned out never to be useful, and sometimes to be dangerous. jpayne@69: jpayne@69: private: jpayne@69: bool isSet; jpayne@69: jpayne@69: #if _MSC_VER && !defined(__clang__) jpayne@69: #pragma warning(push) jpayne@69: #pragma warning(disable: 4624) jpayne@69: // Warns that the anonymous union has a deleted destructor when T is non-trivial. This warning jpayne@69: // seems broken. jpayne@69: #endif jpayne@69: jpayne@69: union { jpayne@69: T value; jpayne@69: }; jpayne@69: jpayne@69: #if _MSC_VER && !defined(__clang__) jpayne@69: #pragma warning(pop) jpayne@69: #endif jpayne@69: jpayne@69: friend class kj::Maybe; jpayne@69: template jpayne@69: friend NullableValue&& readMaybe(Maybe&& maybe); jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: inline NullableValue&& readMaybe(Maybe&& maybe) { return kj::mv(maybe.ptr); } jpayne@69: template jpayne@69: inline T* readMaybe(Maybe& maybe) { return maybe.ptr; } jpayne@69: template jpayne@69: inline const T* readMaybe(const Maybe& maybe) { return maybe.ptr; } jpayne@69: template jpayne@69: inline T* readMaybe(Maybe&& maybe) { return maybe.ptr; } jpayne@69: template jpayne@69: inline T* readMaybe(const Maybe& maybe) { return maybe.ptr; } jpayne@69: jpayne@69: template jpayne@69: inline T* readMaybe(T* ptr) { return ptr; } jpayne@69: // Allow KJ_IF_MAYBE to work on regular pointers. jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: jpayne@69: #define KJ_IF_MAYBE(name, exp) if (auto name = ::kj::_::readMaybe(exp)) jpayne@69: jpayne@69: #if __GNUC__ || __clang__ jpayne@69: // These two macros provide a friendly syntax to extract the value of a Maybe or return early. jpayne@69: // jpayne@69: // Use KJ_UNWRAP_OR_RETURN if you just want to return a simple value when the Maybe is null: jpayne@69: // jpayne@69: // int foo(Maybe maybe) { jpayne@69: // int value = KJ_UNWRAP_OR_RETURN(maybe, -1); jpayne@69: // // ... use value ... jpayne@69: // } jpayne@69: // jpayne@69: // For functions returning void, omit the second parameter to KJ_UNWRAP_OR_RETURN: jpayne@69: // jpayne@69: // void foo(Maybe maybe) { jpayne@69: // int value = KJ_UNWRAP_OR_RETURN(maybe); jpayne@69: // // ... use value ... jpayne@69: // } jpayne@69: // jpayne@69: // Use KJ_UNWRAP_OR if you want to execute a block with multiple statements. jpayne@69: // jpayne@69: // int foo(Maybe maybe) { jpayne@69: // int value = KJ_UNWRAP_OR(maybe, { jpayne@69: // KJ_LOG(ERROR, "problem!!!"); jpayne@69: // return -1; jpayne@69: // }); jpayne@69: // // ... use value ... jpayne@69: // } jpayne@69: // jpayne@69: // The block MUST return at the end or you will get a compiler error jpayne@69: // jpayne@69: // Unfortunately, these macros seem impossible to express without using GCC's non-standard jpayne@69: // "statement expressions" extension. IIFEs don't do the trick here because a lambda cannot jpayne@69: // return out of the parent scope. These macros should therefore only be used in projects that jpayne@69: // target GCC or GCC-compatible compilers. jpayne@69: // jpayne@69: // `__GNUC__` is not defined when using LLVM's MSVC-compatible compiler driver `clang-cl` (even jpayne@69: // though clang supports the required extension), hence the additional `|| __clang__`. jpayne@69: jpayne@69: #define KJ_UNWRAP_OR_RETURN(value, ...) \ jpayne@69: (*({ \ jpayne@69: auto _kj_result = ::kj::_::readMaybe(value); \ jpayne@69: if (!_kj_result) { \ jpayne@69: return __VA_ARGS__; \ jpayne@69: } \ jpayne@69: kj::mv(_kj_result); \ jpayne@69: })) jpayne@69: jpayne@69: #define KJ_UNWRAP_OR(value, block) \ jpayne@69: (*({ \ jpayne@69: auto _kj_result = ::kj::_::readMaybe(value); \ jpayne@69: if (!_kj_result) { \ jpayne@69: block; \ jpayne@69: asm("KJ_UNWRAP_OR_block_is_missing_return_statement\n"); \ jpayne@69: } \ jpayne@69: kj::mv(_kj_result); \ jpayne@69: })) jpayne@69: #endif jpayne@69: jpayne@69: template jpayne@69: class Maybe { jpayne@69: // A T, or nullptr. jpayne@69: jpayne@69: // IF YOU CHANGE THIS CLASS: Note that there is a specialization of it in memory.h. jpayne@69: jpayne@69: public: jpayne@69: Maybe(): ptr(nullptr) {} jpayne@69: Maybe(T&& t): ptr(kj::mv(t)) {} jpayne@69: Maybe(T& t): ptr(t) {} jpayne@69: Maybe(const T& t): ptr(t) {} jpayne@69: Maybe(Maybe&& other): ptr(kj::mv(other.ptr)) { other = nullptr; } jpayne@69: Maybe(const Maybe& other): ptr(other.ptr) {} jpayne@69: Maybe(Maybe& other): ptr(other.ptr) {} jpayne@69: jpayne@69: template jpayne@69: Maybe(Maybe&& other) { jpayne@69: KJ_IF_MAYBE(val, kj::mv(other)) { jpayne@69: ptr.emplace(kj::mv(*val)); jpayne@69: other = nullptr; jpayne@69: } jpayne@69: } jpayne@69: template jpayne@69: Maybe(Maybe&& other) { jpayne@69: KJ_IF_MAYBE(val, other) { jpayne@69: ptr.emplace(*val); jpayne@69: other = nullptr; jpayne@69: } jpayne@69: } jpayne@69: template jpayne@69: Maybe(const Maybe& other) { jpayne@69: KJ_IF_MAYBE(val, other) { jpayne@69: ptr.emplace(*val); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: Maybe(decltype(nullptr)): ptr(nullptr) {} jpayne@69: jpayne@69: template jpayne@69: inline T& emplace(Params&&... params) { jpayne@69: // Replace this Maybe's content with a new value constructed by passing the given parameters to jpayne@69: // T's constructor. This can be used to initialize a Maybe without copying or even moving a T. jpayne@69: // Returns a reference to the newly-constructed value. jpayne@69: jpayne@69: return ptr.emplace(kj::fwd(params)...); jpayne@69: } jpayne@69: jpayne@69: inline Maybe& operator=(T&& other) { ptr = kj::mv(other); return *this; } jpayne@69: inline Maybe& operator=(T& other) { ptr = other; return *this; } jpayne@69: inline Maybe& operator=(const T& other) { ptr = other; return *this; } jpayne@69: jpayne@69: inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); other = nullptr; return *this; } jpayne@69: inline Maybe& operator=(Maybe& other) { ptr = other.ptr; return *this; } jpayne@69: inline Maybe& operator=(const Maybe& other) { ptr = other.ptr; return *this; } jpayne@69: jpayne@69: template jpayne@69: Maybe& operator=(Maybe&& other) { jpayne@69: KJ_IF_MAYBE(val, kj::mv(other)) { jpayne@69: ptr.emplace(kj::mv(*val)); jpayne@69: other = nullptr; jpayne@69: } else { jpayne@69: ptr = nullptr; jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: template jpayne@69: Maybe& operator=(const Maybe& other) { jpayne@69: KJ_IF_MAYBE(val, other) { jpayne@69: ptr.emplace(*val); jpayne@69: } else { jpayne@69: ptr = nullptr; jpayne@69: } jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: inline Maybe& operator=(decltype(nullptr)) { ptr = nullptr; return *this; } jpayne@69: jpayne@69: inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } jpayne@69: inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } jpayne@69: jpayne@69: inline bool operator==(const Maybe& other) const { jpayne@69: if (ptr == nullptr) { jpayne@69: return other == nullptr; jpayne@69: } else { jpayne@69: return other.ptr != nullptr && *ptr == *other.ptr; jpayne@69: } jpayne@69: } jpayne@69: inline bool operator!=(const Maybe& other) const { return !(*this == other); } jpayne@69: jpayne@69: Maybe(const T* t) = delete; jpayne@69: Maybe& operator=(const T* other) = delete; jpayne@69: // We used to permit assigning a Maybe directly from a T*, and the assignment would check for jpayne@69: // nullness. This turned out never to be useful, and sometimes to be dangerous. jpayne@69: jpayne@69: T& orDefault(T& defaultValue) & { jpayne@69: if (ptr == nullptr) { jpayne@69: return defaultValue; jpayne@69: } else { jpayne@69: return *ptr; jpayne@69: } jpayne@69: } jpayne@69: const T& orDefault(const T& defaultValue) const & { jpayne@69: if (ptr == nullptr) { jpayne@69: return defaultValue; jpayne@69: } else { jpayne@69: return *ptr; jpayne@69: } jpayne@69: } jpayne@69: T&& orDefault(T&& defaultValue) && { jpayne@69: if (ptr == nullptr) { jpayne@69: return kj::mv(defaultValue); jpayne@69: } else { jpayne@69: return kj::mv(*ptr); jpayne@69: } jpayne@69: } jpayne@69: const T&& orDefault(const T&& defaultValue) const && { jpayne@69: if (ptr == nullptr) { jpayne@69: return kj::mv(defaultValue); jpayne@69: } else { jpayne@69: return kj::mv(*ptr); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template () ? instance() : instance()())> jpayne@69: Result orDefault(F&& lazyDefaultValue) & { jpayne@69: if (ptr == nullptr) { jpayne@69: return lazyDefaultValue(); jpayne@69: } else { jpayne@69: return *ptr; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template () ? instance() : instance()())> jpayne@69: Result orDefault(F&& lazyDefaultValue) const & { jpayne@69: if (ptr == nullptr) { jpayne@69: return lazyDefaultValue(); jpayne@69: } else { jpayne@69: return *ptr; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template () ? instance() : instance()())> jpayne@69: Result orDefault(F&& lazyDefaultValue) && { jpayne@69: if (ptr == nullptr) { jpayne@69: return lazyDefaultValue(); jpayne@69: } else { jpayne@69: return kj::mv(*ptr); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template () ? instance() : instance()())> jpayne@69: Result orDefault(F&& lazyDefaultValue) const && { jpayne@69: if (ptr == nullptr) { jpayne@69: return lazyDefaultValue(); jpayne@69: } else { jpayne@69: return kj::mv(*ptr); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) & -> Maybe()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return f(*ptr); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) const & -> Maybe()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return f(*ptr); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) && -> Maybe()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return f(kj::mv(*ptr)); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) const && -> Maybe()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return f(kj::mv(*ptr)); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: _::NullableValue ptr; jpayne@69: jpayne@69: template jpayne@69: friend class Maybe; jpayne@69: template jpayne@69: friend _::NullableValue&& _::readMaybe(Maybe&& maybe); jpayne@69: template jpayne@69: friend U* _::readMaybe(Maybe& maybe); jpayne@69: template jpayne@69: friend const U* _::readMaybe(const Maybe& maybe); jpayne@69: }; jpayne@69: jpayne@69: template jpayne@69: class Maybe { jpayne@69: public: jpayne@69: constexpr Maybe(): ptr(nullptr) {} jpayne@69: constexpr Maybe(T& t): ptr(&t) {} jpayne@69: constexpr Maybe(T* t): ptr(t) {} jpayne@69: jpayne@69: inline constexpr Maybe(PropagateConst& other): ptr(other.ptr) {} jpayne@69: // Allow const copy only if `T` itself is const. Otherwise allow only non-const copy, to jpayne@69: // protect transitive constness. Clang is happy for this constructor to be declared `= default` jpayne@69: // since, after evaluation of `PropagateConst`, it does end up being a default-able constructor. jpayne@69: // But, GCC and MSVC both complain about that, claiming this constructor cannot be declared jpayne@69: // default. I don't know who is correct, but whatever, we'll write out an implementation, fine. jpayne@69: // jpayne@69: // Note that we can't solve this by inheriting DisallowConstCopyIfNotConst because we want jpayne@69: // to override the move constructor, and if we override the move constructor then we must define jpayne@69: // the copy constructor here. jpayne@69: jpayne@69: inline constexpr Maybe(Maybe&& other): ptr(other.ptr) { other.ptr = nullptr; } jpayne@69: jpayne@69: template jpayne@69: inline constexpr Maybe(Maybe& other): ptr(other.ptr) {} jpayne@69: template jpayne@69: inline constexpr Maybe(const Maybe& other): ptr(const_cast(other.ptr)) {} jpayne@69: template jpayne@69: inline constexpr Maybe(Maybe&& other): ptr(other.ptr) { other.ptr = nullptr; } jpayne@69: template jpayne@69: inline constexpr Maybe(const Maybe&& other) = delete; jpayne@69: template ()>> jpayne@69: constexpr Maybe(Maybe& other): ptr(other.ptr.operator U*()) {} jpayne@69: template ()>> jpayne@69: constexpr Maybe(const Maybe& other): ptr(other.ptr.operator const U*()) {} jpayne@69: inline constexpr Maybe(decltype(nullptr)): ptr(nullptr) {} jpayne@69: jpayne@69: inline Maybe& operator=(T& other) { ptr = &other; return *this; } jpayne@69: inline Maybe& operator=(T* other) { ptr = other; return *this; } jpayne@69: inline Maybe& operator=(PropagateConst& other) { ptr = other.ptr; return *this; } jpayne@69: inline Maybe& operator=(Maybe&& other) { ptr = other.ptr; other.ptr = nullptr; return *this; } jpayne@69: template jpayne@69: inline Maybe& operator=(Maybe& other) { ptr = other.ptr; return *this; } jpayne@69: template jpayne@69: inline Maybe& operator=(const Maybe& other) { ptr = other.ptr; return *this; } jpayne@69: template jpayne@69: inline Maybe& operator=(Maybe&& other) { ptr = other.ptr; other.ptr = nullptr; return *this; } jpayne@69: template jpayne@69: inline Maybe& operator=(const Maybe&& other) = delete; jpayne@69: jpayne@69: inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; } jpayne@69: inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; } jpayne@69: jpayne@69: T& orDefault(T& defaultValue) { jpayne@69: if (ptr == nullptr) { jpayne@69: return defaultValue; jpayne@69: } else { jpayne@69: return *ptr; jpayne@69: } jpayne@69: } jpayne@69: const T& orDefault(const T& defaultValue) const { jpayne@69: if (ptr == nullptr) { jpayne@69: return defaultValue; jpayne@69: } else { jpayne@69: return *ptr; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) -> Maybe()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return f(*ptr); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: auto map(Func&& f) const -> Maybe()))> { jpayne@69: if (ptr == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: const T& ref = *ptr; jpayne@69: return f(ref); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: T* ptr; jpayne@69: jpayne@69: template jpayne@69: friend class Maybe; jpayne@69: template jpayne@69: friend U* _::readMaybe(Maybe&& maybe); jpayne@69: template jpayne@69: friend U* _::readMaybe(const Maybe& maybe); jpayne@69: }; jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // ArrayPtr jpayne@69: // jpayne@69: // So common that we put it in common.h rather than array.h. jpayne@69: jpayne@69: template jpayne@69: class Array; jpayne@69: jpayne@69: template jpayne@69: class ArrayPtr: public DisallowConstCopyIfNotConst { jpayne@69: // A pointer to an array. Includes a size. Like any pointer, it doesn't own the target data, jpayne@69: // and passing by value only copies the pointer, not the target. jpayne@69: jpayne@69: public: jpayne@69: inline constexpr ArrayPtr(): ptr(nullptr), size_(0) {} jpayne@69: inline constexpr ArrayPtr(decltype(nullptr)): ptr(nullptr), size_(0) {} jpayne@69: inline constexpr ArrayPtr(T* ptr KJ_LIFETIMEBOUND, size_t size): ptr(ptr), size_(size) {} jpayne@69: inline constexpr ArrayPtr(T* begin KJ_LIFETIMEBOUND, T* end KJ_LIFETIMEBOUND) jpayne@69: : ptr(begin), size_(end - begin) {} jpayne@69: ArrayPtr& operator=(Array&&) = delete; jpayne@69: ArrayPtr& operator=(decltype(nullptr)) { jpayne@69: ptr = nullptr; jpayne@69: size_ = 0; jpayne@69: return *this; jpayne@69: } jpayne@69: jpayne@69: #if __GNUC__ && !__clang__ && __GNUC__ >= 9 jpayne@69: // GCC 9 added a warning when we take an initializer_list as a constructor parameter and save a jpayne@69: // pointer to its content in a class member. GCC apparently imagines we're going to do something jpayne@69: // dumb like this: jpayne@69: // ArrayPtr ptr = { 1, 2, 3 }; jpayne@69: // foo(ptr[1]); // undefined behavior! jpayne@69: // Any KJ programmer should be able to recognize that this is UB, because an ArrayPtr does not own jpayne@69: // its content. That's not what this constructor is for, tohugh. This constructor is meant to allow jpayne@69: // code like this: jpayne@69: // int foo(ArrayPtr p); jpayne@69: // // ... later ... jpayne@69: // foo({1, 2, 3}); jpayne@69: // In this case, the initializer_list's backing array, like any temporary, lives until the end of jpayne@69: // the statement `foo({1, 2, 3});`. Therefore, it lives at least until the call to foo() has jpayne@69: // returned, which is exactly what we care about. This usage is fine! GCC is wrong to warn. jpayne@69: // jpayne@69: // Amusingly, Clang's implementation has a similar type that they call ArrayRef which apparently jpayne@69: // triggers this same GCC warning. My guess is that Clang will not introduce a similar warning jpayne@69: // given that it triggers on their own, legitimate code. jpayne@69: #pragma GCC diagnostic push jpayne@69: #pragma GCC diagnostic ignored "-Winit-list-lifetime" jpayne@69: #endif jpayne@69: inline KJ_CONSTEXPR() ArrayPtr( jpayne@69: ::std::initializer_list> init KJ_LIFETIMEBOUND) jpayne@69: : ptr(init.begin()), size_(init.size()) {} jpayne@69: #if __GNUC__ && !__clang__ && __GNUC__ >= 9 jpayne@69: #pragma GCC diagnostic pop jpayne@69: #endif jpayne@69: jpayne@69: template jpayne@69: inline constexpr ArrayPtr(KJ_LIFETIMEBOUND T (&native)[size]): ptr(native), size_(size) { jpayne@69: // Construct an ArrayPtr from a native C-style array. jpayne@69: // jpayne@69: // We disable this constructor for const char arrays because otherwise you would be able to jpayne@69: // implicitly convert a character literal to ArrayPtr, which sounds really great, jpayne@69: // except that the NUL terminator would be included, which probably isn't what you intended. jpayne@69: // jpayne@69: // TODO(someday): Maybe we should support character literals but explicitly chop off the NUL jpayne@69: // terminator. This could do the wrong thing if someone tries to construct an jpayne@69: // ArrayPtr from a non-NUL-terminated char array, but evidence suggests that all jpayne@69: // real use cases are in fact intending to remove the NUL terminator. It's convenient to be jpayne@69: // able to specify ArrayPtr as a parameter type and be able to accept strings jpayne@69: // as input in addition to arrays. Currently, you'll need overloading to support string jpayne@69: // literals in this case, but if you overload StringPtr, then you'll find that several jpayne@69: // conversions (e.g. from String and from a literal char array) become ambiguous! You end up jpayne@69: // having to overload for literal char arrays specifically which is cumbersome. jpayne@69: jpayne@69: static_assert(!isSameType(), jpayne@69: "Can't implicitly convert literal char array to ArrayPtr because we don't know if " jpayne@69: "you meant to include the NUL terminator. We may change this in the future to " jpayne@69: "automatically drop the NUL terminator. For now, try explicitly converting to StringPtr, " jpayne@69: "which can in turn implicitly convert to ArrayPtr."); jpayne@69: static_assert(!isSameType(), "see above"); jpayne@69: static_assert(!isSameType(), "see above"); jpayne@69: } jpayne@69: jpayne@69: inline operator ArrayPtr() const { jpayne@69: return ArrayPtr(ptr, size_); jpayne@69: } jpayne@69: inline ArrayPtr asConst() const { jpayne@69: return ArrayPtr(ptr, size_); jpayne@69: } jpayne@69: jpayne@69: inline constexpr size_t size() const { return size_; } jpayne@69: inline const T& operator[](size_t index) const { jpayne@69: KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access."); jpayne@69: return ptr[index]; jpayne@69: } jpayne@69: inline T& operator[](size_t index) { jpayne@69: KJ_IREQUIRE(index < size_, "Out-of-bounds ArrayPtr access."); jpayne@69: return ptr[index]; jpayne@69: } jpayne@69: jpayne@69: inline T* begin() { return ptr; } jpayne@69: inline T* end() { return ptr + size_; } jpayne@69: inline T& front() { return *ptr; } jpayne@69: inline T& back() { return *(ptr + size_ - 1); } jpayne@69: inline constexpr const T* begin() const { return ptr; } jpayne@69: inline constexpr const T* end() const { return ptr + size_; } jpayne@69: inline const T& front() const { return *ptr; } jpayne@69: inline const T& back() const { return *(ptr + size_ - 1); } jpayne@69: jpayne@69: inline ArrayPtr slice(size_t start, size_t end) const { jpayne@69: KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice()."); jpayne@69: return ArrayPtr(ptr + start, end - start); jpayne@69: } jpayne@69: inline ArrayPtr slice(size_t start, size_t end) { jpayne@69: KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice()."); jpayne@69: return ArrayPtr(ptr + start, end - start); jpayne@69: } jpayne@69: inline bool startsWith(const ArrayPtr& other) const { jpayne@69: return other.size() <= size_ && slice(0, other.size()) == other; jpayne@69: } jpayne@69: inline bool endsWith(const ArrayPtr& other) const { jpayne@69: return other.size() <= size_ && slice(size_ - other.size(), size_) == other; jpayne@69: } jpayne@69: jpayne@69: inline Maybe findFirst(const T& match) const { jpayne@69: for (size_t i = 0; i < size_; i++) { jpayne@69: if (ptr[i] == match) { jpayne@69: return i; jpayne@69: } jpayne@69: } jpayne@69: return nullptr; jpayne@69: } jpayne@69: inline Maybe findLast(const T& match) const { jpayne@69: for (size_t i = size_; i--;) { jpayne@69: if (ptr[i] == match) { jpayne@69: return i; jpayne@69: } jpayne@69: } jpayne@69: return nullptr; jpayne@69: } jpayne@69: jpayne@69: inline ArrayPtr> asBytes() const { jpayne@69: // Reinterpret the array as a byte array. This is explicitly legal under C++ aliasing jpayne@69: // rules. jpayne@69: return { reinterpret_cast*>(ptr), size_ * sizeof(T) }; jpayne@69: } jpayne@69: inline ArrayPtr> asChars() const { jpayne@69: // Reinterpret the array as a char array. This is explicitly legal under C++ aliasing jpayne@69: // rules. jpayne@69: return { reinterpret_cast*>(ptr), size_ * sizeof(T) }; jpayne@69: } jpayne@69: jpayne@69: inline bool operator==(decltype(nullptr)) const { return size_ == 0; } jpayne@69: inline bool operator!=(decltype(nullptr)) const { return size_ != 0; } jpayne@69: jpayne@69: inline bool operator==(const ArrayPtr& other) const { jpayne@69: if (size_ != other.size_) return false; jpayne@69: if (isIntegral>()) { jpayne@69: if (size_ == 0) return true; jpayne@69: return memcmp(ptr, other.ptr, size_ * sizeof(T)) == 0; jpayne@69: } jpayne@69: for (size_t i = 0; i < size_; i++) { jpayne@69: if (ptr[i] != other[i]) return false; jpayne@69: } jpayne@69: return true; jpayne@69: } jpayne@69: #if !__cpp_impl_three_way_comparison jpayne@69: inline bool operator!=(const ArrayPtr& other) const { return !(*this == other); } jpayne@69: #endif jpayne@69: jpayne@69: template jpayne@69: inline bool operator==(const ArrayPtr& other) const { jpayne@69: if (size_ != other.size()) return false; jpayne@69: for (size_t i = 0; i < size_; i++) { jpayne@69: if (ptr[i] != other[i]) return false; jpayne@69: } jpayne@69: return true; jpayne@69: } jpayne@69: #if !__cpp_impl_three_way_comparison jpayne@69: template jpayne@69: inline bool operator!=(const ArrayPtr& other) const { return !(*this == other); } jpayne@69: #endif jpayne@69: jpayne@69: template jpayne@69: Array attach(Attachments&&... attachments) const KJ_WARN_UNUSED_RESULT; jpayne@69: // Like Array::attach(), but also promotes an ArrayPtr to an Array. Generally the attachment jpayne@69: // should be an object that actually owns the array that the ArrayPtr is pointing at. jpayne@69: // jpayne@69: // You must include kj/array.h to call this. jpayne@69: jpayne@69: private: jpayne@69: T* ptr; jpayne@69: size_t size_; jpayne@69: }; jpayne@69: jpayne@69: template <> jpayne@69: inline Maybe ArrayPtr::findFirst(const char& c) const { jpayne@69: const char* pos = reinterpret_cast(memchr(ptr, c, size_)); jpayne@69: if (pos == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return pos - ptr; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template <> jpayne@69: inline Maybe ArrayPtr::findFirst(const char& c) const { jpayne@69: char* pos = reinterpret_cast(memchr(ptr, c, size_)); jpayne@69: if (pos == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return pos - ptr; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template <> jpayne@69: inline Maybe ArrayPtr::findFirst(const byte& c) const { jpayne@69: const byte* pos = reinterpret_cast(memchr(ptr, c, size_)); jpayne@69: if (pos == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return pos - ptr; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: template <> jpayne@69: inline Maybe ArrayPtr::findFirst(const byte& c) const { jpayne@69: byte* pos = reinterpret_cast(memchr(ptr, c, size_)); jpayne@69: if (pos == nullptr) { jpayne@69: return nullptr; jpayne@69: } else { jpayne@69: return pos - ptr; jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: // glibc has a memrchr() for reverse search but it's non-standard, so we don't bother optimizing jpayne@69: // findLast(), which isn't used much anyway. jpayne@69: jpayne@69: template jpayne@69: inline constexpr ArrayPtr arrayPtr(T* ptr KJ_LIFETIMEBOUND, size_t size) { jpayne@69: // Use this function to construct ArrayPtrs without writing out the type name. jpayne@69: return ArrayPtr(ptr, size); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: inline constexpr ArrayPtr arrayPtr(T* begin KJ_LIFETIMEBOUND, T* end KJ_LIFETIMEBOUND) { jpayne@69: // Use this function to construct ArrayPtrs without writing out the type name. jpayne@69: return ArrayPtr(begin, end); jpayne@69: } jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Casts jpayne@69: jpayne@69: template jpayne@69: To implicitCast(From&& from) { jpayne@69: // `implicitCast(value)` casts `value` to type `T` only if the conversion is implicit. Useful jpayne@69: // for e.g. resolving ambiguous overloads without sacrificing type-safety. jpayne@69: return kj::fwd(from); jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: Maybe dynamicDowncastIfAvailable(From& from) { jpayne@69: // If RTTI is disabled, always returns nullptr. Otherwise, works like dynamic_cast. Useful jpayne@69: // in situations where dynamic_cast could allow an optimization, but isn't strictly necessary jpayne@69: // for correctness. It is highly recommended that you try to arrange all your dynamic_casts jpayne@69: // this way, as a dynamic_cast that is necessary for correctness implies a flaw in the interface jpayne@69: // design. jpayne@69: jpayne@69: // Force a compile error if To is not a subtype of From. Cross-casting is rare; if it is needed jpayne@69: // we should have a separate cast function like dynamicCrosscastIfAvailable(). jpayne@69: if (false) { jpayne@69: kj::implicitCast(kj::implicitCast(nullptr)); jpayne@69: } jpayne@69: jpayne@69: #if KJ_NO_RTTI jpayne@69: return nullptr; jpayne@69: #else jpayne@69: return dynamic_cast(&from); jpayne@69: #endif jpayne@69: } jpayne@69: jpayne@69: template jpayne@69: To& downcast(From& from) { jpayne@69: // Down-cast a value to a sub-type, asserting that the cast is valid. In opt mode this is a jpayne@69: // static_cast, but in debug mode (when RTTI is enabled) a dynamic_cast will be used to verify jpayne@69: // that the value really has the requested type. jpayne@69: jpayne@69: // Force a compile error if To is not a subtype of From. jpayne@69: if (false) { jpayne@69: kj::implicitCast(kj::implicitCast(nullptr)); jpayne@69: } jpayne@69: jpayne@69: #if !KJ_NO_RTTI jpayne@69: KJ_IREQUIRE(dynamic_cast(&from) != nullptr, "Value cannot be downcast() to requested type."); jpayne@69: #endif jpayne@69: jpayne@69: return static_cast(from); jpayne@69: } jpayne@69: jpayne@69: // ======================================================================================= jpayne@69: // Defer jpayne@69: jpayne@69: namespace _ { // private jpayne@69: jpayne@69: template jpayne@69: class Deferred { jpayne@69: public: jpayne@69: Deferred(Func&& func): maybeFunc(kj::fwd(func)) {} jpayne@69: ~Deferred() noexcept(false) { jpayne@69: run(); jpayne@69: } jpayne@69: KJ_DISALLOW_COPY(Deferred); jpayne@69: jpayne@69: Deferred(Deferred&&) = default; jpayne@69: // Since we use a kj::Maybe, the default move constructor does exactly what we want it to do. jpayne@69: jpayne@69: void run() { jpayne@69: // Move `maybeFunc` to the local scope so that even if we throw, we destroy the functor we had. jpayne@69: auto maybeLocalFunc = kj::mv(maybeFunc); jpayne@69: KJ_IF_MAYBE(func, maybeLocalFunc) { jpayne@69: (*func)(); jpayne@69: } jpayne@69: } jpayne@69: jpayne@69: void cancel() { jpayne@69: maybeFunc = nullptr; jpayne@69: } jpayne@69: jpayne@69: private: jpayne@69: kj::Maybe maybeFunc; jpayne@69: // Note that `Func` may actually be an lvalue reference because `kj::defer` takes its argument via jpayne@69: // universal reference. `kj::Maybe` has specializations for lvalue reference types, so this works jpayne@69: // out. jpayne@69: }; jpayne@69: jpayne@69: } // namespace _ (private) jpayne@69: jpayne@69: template jpayne@69: _::Deferred defer(Func&& func) { jpayne@69: // Returns an object which will invoke the given functor in its destructor. The object is not jpayne@69: // copyable but is move-constructable with the semantics you'd expect. Since the return type is jpayne@69: // private, you need to assign to an `auto` variable. jpayne@69: // jpayne@69: // The KJ_DEFER macro provides slightly more convenient syntax for the common case where you jpayne@69: // want some code to run at current scope exit. jpayne@69: // jpayne@69: // KJ_DEFER does not support move-assignment for its returned objects. If you need to reuse the jpayne@69: // variable for your deferred function object, then you will want to write your own class for that jpayne@69: // purpose. jpayne@69: jpayne@69: return _::Deferred(kj::fwd(func)); jpayne@69: } jpayne@69: jpayne@69: #define KJ_DEFER(code) auto KJ_UNIQUE_NAME(_kjDefer) = ::kj::defer([&](){code;}) jpayne@69: // Run the given code when the function exits, whether by return or exception. jpayne@69: jpayne@69: } // namespace kj jpayne@69: jpayne@69: KJ_END_HEADER