#include <cstddef>
+#include <folly/Portability.h>
#include <folly/concurrency/CacheLocality.h>
namespace folly {
template <typename T>
class CachelinePadded {
static_assert(
- alignof(T) < CacheLocality::kFalseSharingRange,
- "CachelinePadded does not support types aligned >= a cache-line.");
+ alignof(T) <= folly::max_align_v,
+ "CachelinePadded does not support over-aligned types.");
public:
template <typename... Args>
"Invalid size of PaddedSpinLock");
// Check if T can theoretically cross a cache line.
- static_assert(alignof(std::max_align_t) > 0 &&
- FOLLY_CACHE_LINE_SIZE % alignof(std::max_align_t) == 0 &&
- sizeof(T) <= alignof(std::max_align_t),
- "T can cross cache line boundaries");
+ static_assert(
+ folly::max_align_v > 0 &&
+ FOLLY_CACHE_LINE_SIZE % folly::max_align_v == 0 &&
+ sizeof(T) <= folly::max_align_v,
+ "T can cross cache line boundaries");
char padding_[FOLLY_CACHE_LINE_SIZE];
std::array<PaddedSpinLock, N> data_;
#include <string.h>
#include <cstddef>
+#include <type_traits>
#include <folly/portability/Config.h>
#else
constexpr bool kHasUnalignedAccess = false;
#endif
-}
+
+namespace detail {
+
+template <typename I, I A, I... Bs>
+struct integral_max
+ : std::integral_constant<
+ I,
+ (A > integral_max<I, Bs...>::value) ? A
+ : integral_max<I, Bs...>::value> {
+};
+
+template <typename I, size_t A>
+struct integral_max<I, A> : std::integral_constant<I, A> {};
+
+template <typename... Ts>
+using max_alignment = integral_max<size_t, alignof(Ts)...>;
+
+using max_basic_alignment = max_alignment<
+ std::max_align_t,
+ long double,
+ double,
+ float,
+ long long int,
+ long int,
+ int,
+ short int,
+ bool,
+ char,
+ char16_t,
+ char32_t,
+ wchar_t,
+ std::nullptr_t>;
+} // namespace detail
+
+constexpr size_t max_align_v = detail::max_basic_alignment::value;
+
+// max_align_t is a type which is aligned at least as strictly as the
+// most-aligned basic type (see the specification of std::max_align_t). This
+// implementation exists because 32-bit iOS platforms have a broken
+// std::max_align_t (see below).
+//
+// You should refer to this as `::folly::max_align_t` in portable code, even if
+// you have `using namespace folly;` because C11 defines a global namespace
+// `max_align_t` type.
+//
+// To be certain, we consider every non-void fundamental type specified by the
+// standard. On most platforms `long double` would be enough, but iOS 32-bit
+// has an 8-byte aligned `double` and `long long int` and a 4-byte aligned
+// `long double`.
+//
+// So far we've covered locals and other non-allocated storage, but we also need
+// confidence that allocated storage from `malloc`, `new`, etc will also be
+// suitable for objects with this alignment reuirement.
+//
+// Apple document that their implementation of malloc will issue 16-byte
+// granularity chunks for small allocations (large allocations are page-size
+// granularity and page-aligned). We think that allocated storage will be
+// suitable for these objects based on the following assumptions:
+//
+// 1. 16-byte granularity also means 16-byte aligned.
+// 2. `new` and other allocators follow the `malloc` rules.
+//
+// We also have some anecdotal evidence: we don't see lots of misaligned-storage
+// crashes on 32-bit iOS apps that use `double`.
+//
+// Apple's allocation reference: http://bit.ly/malloc-small
+struct alignas(max_align_v) max_align_t {};
+
+} // namespace folly
// compiler specific attribute translation
// msvc should come first, so if clang is in msvc mode it gets the right defines
#else
# error Cannot define FOLLY_ALIGNED on this platform
#endif
-#define FOLLY_ALIGNED_MAX FOLLY_ALIGNED(alignof(std::max_align_t))
+#define FOLLY_ALIGNED_MAX FOLLY_ALIGNED(::folly::max_align_v)
// NOTE: this will only do checking in msvc with versions that support /analyze
#if _MSC_VER
// Install a pointer to ourselves as the allocator.
*reinterpret_cast<SimpleAllocator**>(mem_) = this;
static_assert(
- alignof(std::max_align_t) >= sizeof(SimpleAllocator*),
- "alignment too small");
- mem_ += std::min(sz_, alignof(std::max_align_t));
+ folly::max_align_v >= sizeof(SimpleAllocator*), "alignment too small");
+ mem_ += std::min(sz_, folly::max_align_v);
// New allocation.
auto mem = mem_;
if (intptr_t(mem_) % 128 == 0) {
// Avoid allocating pointers that may look like malloc
// pointers.
- mem_ += std::min(sz_, alignof(std::max_align_t));
+ mem_ += std::min(sz_, folly::max_align_v);
}
if (mem_ && (mem_ + sz_ <= end_)) {
auto mem = mem_;
/// std::pmr::memory_resource (C++17) as needed for developing a
/// hazptr prototype.
////////////////////////////////////////////////////////////////////////////////
-#include <cstddef>
+#include <folly/Portability.h>
#include <memory>
namespace folly {
virtual ~memory_resource() = default;
virtual void* allocate(
const size_t bytes,
- const size_t alignment = alignof(std::max_align_t)) = 0;
+ const size_t alignment = folly::max_align_v) = 0;
virtual void deallocate(
void* p,
const size_t bytes,
- const size_t alignment = alignof(std::max_align_t)) = 0;
+ const size_t alignment = folly::max_align_v) = 0;
};
memory_resource* get_default_resource();
public:
void* allocate(
const size_t bytes,
- const size_t alignment = alignof(std::max_align_t)) override {
+ const size_t alignment = folly::max_align_v) override {
(void)alignment;
void* p = static_cast<void*>(new char[bytes]);
DEBUG_PRINT(this << " " << p << " " << bytes);
void deallocate(
void* p,
const size_t bytes,
- const size_t alignment = alignof(std::max_align_t)) override {
+ const size_t alignment = folly::max_align_v) override {
(void)alignment;
(void)bytes;
DEBUG_PRINT(p << " " << bytes);
HeapStorage hs;
SharedInfo shared;
- std::max_align_t align;
+ folly::max_align_t align;
};
IOBuf::SharedInfo::SharedInfo()
SizedData<kCachelineSize / 2>,
SizedData<kCachelineSize + kCachelineSize / 2>,
// Mimic single basic types:
- SizedDataMimic<std::max_align_t>,
+ SizedDataMimic<folly::max_align_t>,
SizedDataMimic<void*>,
SizedDataMimic<long double>,
SizedDataMimic<double>,
SizedDataMimic<short>,
SizedDataMimic<char>,
// Mimic small arrays of basic types:
- SizedDataMimic<std::max_align_t, 3>,
+ SizedDataMimic<folly::max_align_t, 3>,
SizedDataMimic<void*, 3>,
SizedDataMimic<long double, 3>,
SizedDataMimic<double, 3>,
SizedDataMimic<short, 3>,
SizedDataMimic<char, 3>,
// Mimic large arrays of basic types:
- SizedDataMimic<std::max_align_t, kCachelineSize + 3>,
+ SizedDataMimic<folly::max_align_t, kCachelineSize + 3>,
SizedDataMimic<void*, kCachelineSize + 3>,
SizedDataMimic<long double, kCachelineSize + 3>,
SizedDataMimic<double, kCachelineSize + 3>,
} // namespace
TEST(ThreadCachedArena, BlockSize) {
- static const size_t alignment = alignof(std::max_align_t);
+ static const size_t alignment = folly::max_align_v;
static const size_t requestedBlockSize = 64;
ThreadCachedArena arena(requestedBlockSize);