/* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include #include #include #include namespace facebook { namespace yoga { namespace detail { constexpr size_t log2ceil(size_t n) { return n < 1 ? 0 : (1 + log2ceil(n / 2)); } // The number of bits necessary to represent enums defined with YG_ENUM_SEQ_DECL template constexpr size_t bitWidth() { static_assert( enums::count() > 0, "Enums must have at least one entries"); return log2ceil(enums::count() - 1); } // Number of bits needed for a boolean template <> constexpr size_t bitWidth() { return 1; } template struct BitTraits {}; template struct BitTraits { // Base cases static constexpr size_t width(size_t) { return 0; } static constexpr size_t shift(size_t) { return 0; } }; template struct BitTraits { using Rest = BitTraits; static constexpr size_t width(size_t idx) { return idx == 0 ? bitWidth() : Rest::width(idx - 1); } static constexpr size_t shift(size_t idx) { return idx == 0 ? Rest::width(0) + Rest::shift(0) : Rest::shift(idx - 1); } static constexpr U mask(size_t idx) { return ((U{1} << width(idx)) - 1) << shift(idx); } }; template struct IndexedType { using Type = typename IndexedType::Type; }; template struct IndexedType<0, T, Ts...> { using Type = T; }; } // namespace detail template class Bitfield { static_assert( std::is_integral::value, "Bitfield needs an integral storage type"); static_assert( std::is_unsigned::value, "Bitfield needs an unsigned storage type"); static_assert(sizeof...(Fields) > 0, "Bitfield needs at least one member"); using BitTraits = detail::BitTraits; #if !defined(_MSC_VER) || _MSC_VER > 1914 static_assert( BitTraits::shift(0) + BitTraits::width(0) <= std::numeric_limits::digits, "Specified storage type is too narrow to hold all types"); #endif template using TypeAt = typename detail::IndexedType::Type; template static constexpr Storage initStorage(Value value, Values... values) { return ((value << BitTraits::shift(Idx)) & BitTraits::mask(Idx)) | initStorage(values...); } template static constexpr Storage initStorage() { return Storage{0}; } Storage storage_ = 0; public: template class Ref { Bitfield& bitfield_; public: Ref(Bitfield& bitfield) : bitfield_(bitfield) {} Ref& operator=(TypeAt value) { bitfield_.storage_ = (bitfield_.storage_ & ~BitTraits::mask(Idx)) | ((value << BitTraits::shift(Idx)) & BitTraits::mask(Idx)); return *this; } operator TypeAt() const { return const_cast(bitfield_).at(); } }; constexpr Bitfield() = default; constexpr Bitfield(Fields... values) : storage_{initStorage<0>(values...)} {} template constexpr TypeAt at() const { return static_cast>( (storage_ & BitTraits::mask(Idx)) >> BitTraits::shift(Idx)); } template Ref at() { return {*this}; } }; } // namespace yoga } // namespace facebook