Skip to content

Instantly share code, notes, and snippets.

@danlark1
danlark1 / optional.h
Last active January 11, 2020 19:24
Brief absl::optional description
#if __cplusplus >= 201703 && __has_include(<optional>)
#include <optional>
namespace absl {
using std::bad_optional_access;
using std::optional;
using std::make_optional;
using std::nullopt_t;
using std::nullopt;
@danlark1
danlark1 / singleton.h
Created January 11, 2020 20:48
Singletons
// Very bad because the destruction order is not specified.
// From experience, these are one of the hardest to debug bugs.
template <class T>
T BadSingleton() {
static T t;
return t;
}
// Better. It is NOT a leak because the compiler will clear it after the shutdown.
// Downside -- destuctors are not called. But you should never do complicated
@danlark1
danlark1 / flags.h
Last active January 11, 2020 21:04
// ABSL_CONST_INIT
//
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
// not compile (on supported platforms) unless the variable has a constant
// initializer. This is useful for variables with static and thread storage
// duration, because it guarantees that they will not suffer from the so-called
// "static init order fiasco". Prefer to put this attribute on the most visible
// declaration of the variable, if there's more than one, because code that
// accesses the variable can then use the attribute for optimization.
// Note that this attribute is redundant if the variable is declared constexpr.
// This is reserved space for an absl::Mutex to guard flag data. It will be
// initialized in FlagImpl::Init via placement new.
// We can't use "absl::Mutex data_guard_", since this class is not literal.
// We do not want to use "absl::Mutex* data_guard_", since this would require
// heap allocation during initialization, which is both slows program startup
// and can fail. Using reserved space + placement new allows us to avoid both
// problems.
alignas(absl::Mutex) mutable char data_guard_[sizeof(absl::Mutex)];
#include <type_traits>
#include "testing/benchmark.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/flags/flag.h"
#include "absl/time/time.h"
// Updater threads + reverse frequency 1/128.
#define BENCHMARK_FLAG(func) BENCHMARK(func)->ThreadRange(1, 32)
template <class T, class Flag>
movq (%rdi), %rax # load from the input
xorl %ecx, %ecx
movabsq $-6076574518398440533, %rdx # imm = 0xABABABABABABABAB
cmpq %rdx, %rax # Check with a garbage value
cmovel %ecx, %eax # return it in %rax
retq
// This macro is the "source of truth" for the list of supported flag types we
// expect to perform lock free operations on. Specifically it generates code,
// a one argument macro operating on a type, supplied as a macro argument, for
// each type in the list.
#define ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(A) \
A(bool) \
A(short) \
A(unsigned short) \
A(int) \
A(unsigned int) \
// The minimum atomic size we believe to generate lock free code, i.e. all
// trivially copyable types not bigger this size generate lock free code.
static constexpr int kMinLockFreeAtomicSize = 8;
template <typename T>
struct IsAtomicFlagTypeTrait {
static constexpr bool value = (sizeof(T) <= kMinLockFreeAtomicSize
&& std::is_trivially_copyable<T>::value);
}
struct empty_struct {};
struct dummy_type {
static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
// Use an array to avoid GCC 6 placement-new warning.
empty_struct data[sizeof(T) / sizeof(empty_struct)];
};
// Data storage
union {
// The minimum atomic size we believe to generate lock free code, i.e. all
// trivially copyable types not bigger this size generate lock free code.
static constexpr int kMinLockFreeAtomicSize = 8;
template <typename T>
struct IsAtomicFlagTypeTrait {
static constexpr bool value = (sizeof(T) <= kMinLockFreeAtomicSize
&& std::is_trivially_copyable<T>::value);
}