WebKit Bugzilla
Attachment 348845 Details for
Bug 189272
: [WTF] Add support for compactly storing multiple optional members in a class
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
Proof of concept
Optionals.cpp (text/x-csrc), 9.08 KB, created by
Sam Weinig
on 2018-09-04 13:54:03 PDT
(
hide
)
Description:
Proof of concept
Filename:
MIME Type:
Creator:
Sam Weinig
Created:
2018-09-04 13:54:03 PDT
Size:
9.08 KB
patch
obsolete
>// c++ --std=c++14 Optionals.cpp > >#include <cassert> >#include <cstdio> >#include <type_traits> > >template<typename T> >class OptionalsBitSet { > static_assert(std::is_enum<T>::value, "T is not an enum type"); > typedef typename std::make_unsigned<typename std::underlying_type<T>::type>::type StorageType; > >public: > constexpr OptionalsBitSet() = default; > > constexpr StorageType toRaw() const { return m_storage; } > > constexpr bool has(T option) const { return m_storage & (1 << option); } > constexpr void set(T option) { m_storage |= (1 << option); } > constexpr void clear(T option) { m_storage &= ~(1 << option); } > >private: > StorageType m_storage { 0 }; >}; > >// From StdLibExtras.h >#define OBJECT_OFFSETOF(class, field) (reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<class*>(0x4000)->field)) - 0x4000) > >// Adapted from https://codecraft.co/2014/11/25/variadic-macros-tricks/ >#define _OPTIONALS_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N >#define _OPTIONALS_fe_0(_call, o, ...) >#define _OPTIONALS_fe_1(_call, o, x) _call(o, x) >#define _OPTIONALS_fe_2(_call, o, x, ...) _call(o, x) _OPTIONALS_fe_1(_call, o, __VA_ARGS__) >#define _OPTIONALS_fe_3(_call, o, x, ...) _call(o, x) _OPTIONALS_fe_2(_call, o, __VA_ARGS__) >#define _OPTIONALS_fe_4(_call, o, x, ...) _call(o, x) _OPTIONALS_fe_3(_call, o, __VA_ARGS__) >#define _OPTIONALS_fe_5(_call, o, x, ...) _call(o, x) _OPTIONALS_fe_4(_call, o, __VA_ARGS__) >#define _OPTIONALS_fe_6(_call, o, x, ...) _call(o, x) _OPTIONALS_fe_5(_call, o, __VA_ARGS__) >#define _OPTIONALS_fe_7(_call, o, x, ...) _call(o, x) _OPTIONALS_fe_6(_call, o, __VA_ARGS__) >#define _OPTIONALS_fe_8(_call, o, x, ...) _call(o, x) _OPTIONALS_fe_7(_call, o, __VA_ARGS__) >#define _OPTIONALS_fe_9(_call, o, x, ...) _call(o, x) _OPTIONALS_fe_8(_call, o, __VA_ARGS__) >#define _OPTIONALS_CALL_MACRO_X_FOR_EACH(x, o, ...) \ > _OPTIONALS_GET_NTH_ARG("ignored", ##__VA_ARGS__, _OPTIONALS_fe_9, _OPTIONALS_fe_8, _OPTIONALS_fe_7, _OPTIONALS_fe_6, _OPTIONALS_fe_5, _OPTIONALS_fe_4, _OPTIONALS_fe_3, _OPTIONALS_fe_2, _OPTIONALS_fe_1, _OPTIONALS_fe_0)(x, o, ##__VA_ARGS__) > >#define _OPTIONALS_VALUE_OFFSET_CASE(OwnerClass, EnumValue) \ > case EnumValue: return OBJECT_OFFSETOF(OwnerClass, m_##EnumValue); >#define OPTIONALS_DEFINITION(OwnerClass, ...) \ > enum OptionalsValueEnum { \ > __VA_ARGS__ \ > }; \ > OptionalsBitSet<OptionalsValueEnum> m_bits; \ > template<typename, typename Owner, typename Owner::OptionalsValueEnum> friend class OptionalsValue; \ > static ptrdiff_t bitsOffset() \ > { \ > return OBJECT_OFFSETOF(OwnerClass, m_bits); \ > } \ > static ptrdiff_t valueOffset(OptionalsValueEnum enumValue) \ > { \ > switch (enumValue) { \ > _OPTIONALS_CALL_MACRO_X_FOR_EACH(_OPTIONALS_VALUE_OFFSET_CASE, OwnerClass, __VA_ARGS__) \ > } \ > } > >template<typename T, typename Owner, typename Owner::OptionalsValueEnum enumValue> >class OptionalsValue { >public: > typedef T ValueType; > typedef Owner OwnerType; > typedef OptionalsBitSet<typename OwnerType::OptionalsValueEnum> BitSetType; > > > // Debugging > void printSizeOfValueType() const { printf("SizeOfValueType: %lu\n", sizeof(ValueType)); } > void printEnumValue() const { printf("EnumValue: %d\n", enumValue); } > void printValueOffset() const { printf("ValueOffset: %td\n", OwnerType::valueOffset(enumValue)); } > void printBitsOffset() const { printf("BitsOffset: %td\n", OwnerType::bitsOffset()); } > void printBitsDistance() const { printf("BitsDistance: %d\n", bitsDistanceFromThis()); } > void printThis() const { printf("This: %p\n", this); } > void printBitsLocation() const { printf("BitsLocation: %p\n", bits()); } > void printBitsValue() const { printf("BitsValue: %x\n", bits()->toRaw()); } > > > // API > OptionalsValue(ValueType value) > : m_value(value) > { > bits()->set(enumValue); > } > > OptionalsValue() = default; > > void set(ValueType value) { m_value = value; bits()->set(enumValue); } > bool has() const { return bits()->has(enumValue); } > ValueType value() const { assert(bits()->has(enumValue)); return m_value; } > void clear() { bits()->clear(enumValue); } > ValueType valueOr(ValueType&& other) { return has() ? value() : other; } > >private: > // Bitset access > unsigned bitsDistanceFromThis() const { return OwnerType::valueOffset(enumValue) - OwnerType::bitsOffset(); } > BitSetType* bits() const { return (BitSetType*)((size_t)this - bitsDistanceFromThis()); } > > ValueType m_value; >}; > >class TestDummy { >public: > virtual void dummyVirtualFunction() > { > } > > TestDummy() > : m_value1(75.4) > { > } > > auto& getValue1() { return m_value1; } > auto& getValue2() { return m_value2; } > auto& bits() const { return m_bits; } > >private: > // enum OptionalsValueEnum { > // value1, > // value2 > // }; > // > // OptionalsBitSet<OptionalsValueEnum> m_bits; > // > // template<typename, typename Owner, typename Owner::OptionalsValueEnum> friend class OptionalsValue > // > // static unsigned bitsOffset() > // { > // return OBJECT_OFFSETOF(TestDummy, m_bits); > // } > // > // static unsigned valueOffset(OptionalsValueEnum value) > // { > // switch (value) { > // case value1: > // return OBJECT_OFFSETOF(TestDummy, m_value1); > // case value2: > // return OBJECT_OFFSETOF(TestDummy, m_value2); > // } > // } > > OPTIONALS_DEFINITION(TestDummy, value1, value2); > OptionalsValue<double, TestDummy, value1> m_value1; > OptionalsValue<unsigned, TestDummy, value2> m_value2; >}; > > >int main(int argc, char const *argv[]) >{ > TestDummy dummy; > > dummy.getValue1().printSizeOfValueType(); > dummy.getValue1().printEnumValue(); > dummy.getValue1().printValueOffset(); > dummy.getValue1().printBitsOffset(); > dummy.getValue1().printBitsDistance(); > dummy.getValue1().printThis(); > dummy.getValue1().printBitsLocation(); > dummy.getValue1().printBitsValue(); > dummy.getValue2().printSizeOfValueType(); > dummy.getValue2().printEnumValue(); > dummy.getValue2().printValueOffset(); > dummy.getValue2().printBitsOffset(); > dummy.getValue2().printBitsDistance(); > dummy.getValue2().printThis(); > dummy.getValue2().printBitsLocation(); > dummy.getValue2().printBitsValue(); > > > printf("\nInitial conditions\n"); > printf("m_value1.has(): %s\n", dummy.getValue1().has() ? "YES" : "NO"); > printf("m_value2.has(): %s\n", dummy.getValue2().has() ? "YES" : "NO"); > printf("m_value1.value(): %f\n", dummy.getValue1().value()); > printf("m_bits: %x\n", dummy.bits().toRaw()); > > > printf("\nSetting m_value1 to %f\n", 2.5); > dummy.getValue1().set(2.5); > printf("m_value1.has(): %s\n", dummy.getValue1().has() ? "YES" : "NO"); > printf("m_value2.has(): %s\n", dummy.getValue2().has() ? "YES" : "NO"); > printf("m_value1.value(): %f\n", dummy.getValue1().value()); > printf("m_bits: %x\n", dummy.bits().toRaw()); > > > printf("\nClearing m_value1\n"); > dummy.getValue1().clear(); > printf("m_value1.has(): %s\n", dummy.getValue1().has() ? "YES" : "NO"); > printf("m_value2.has(): %s\n", dummy.getValue2().has() ? "YES" : "NO"); > printf("m_bits: %x\n", dummy.bits().toRaw()); > > > printf("\nSetting m_value2 to %d\n", 10); > dummy.getValue2().set(10); > printf("m_value1.has(): %s\n", dummy.getValue1().has() ? "YES" : "NO"); > printf("m_value2.has(): %s\n", dummy.getValue2().has() ? "YES" : "NO"); > printf("m_value2.value(): %d\n", dummy.getValue2().value()); > printf("m_bits: %x\n", dummy.bits().toRaw()); > > > printf("\nClearing m_value2\n"); > dummy.getValue2().clear(); > printf("m_value1.has(): %s\n", dummy.getValue1().has() ? "YES" : "NO"); > printf("m_value2.has(): %s\n", dummy.getValue2().has() ? "YES" : "NO"); > printf("m_value2.valueOr(100): %d\n", dummy.getValue2().valueOr(100)); > printf("m_bits: %x\n", dummy.bits().toRaw()); > > > printf("\nSetting both m_value1 and m_value2\n"); > dummy.getValue1().set(0); > dummy.getValue2().set(0); > printf("m_value1.has(): %s\n", dummy.getValue1().has() ? "YES" : "NO"); > printf("m_value2.has(): %s\n", dummy.getValue2().has() ? "YES" : "NO"); > printf("m_bits: %x\n", dummy.bits().toRaw()); > > return 0; >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 189272
: 348845