1/*
2 * Copyright (C) 2016 The Qt Company Ltd.
3 * Copyright (c) Meta Platforms, Inc. and affiliates.
4 *
5 * SPDX-License-Identifier: MIT
6 */
7
8#pragma once
9
10#include <cmath>
11#include <cstdint>
12#include <limits>
13
14#include <yoga/YGMacros.h>
15#include <yoga/YGValue.h>
16
17#if defined(__has_include) && __has_include(<version>)
18// needed to be able to evaluate defined(__cpp_lib_bit_cast)
19#include <version>
20#else
21// needed to be able to evaluate defined(__cpp_lib_bit_cast)
22#include <ciso646>
23#endif
24
25#ifdef __cpp_lib_bit_cast
26#include <bit>
27#else
28#include <cstring>
29#endif
30
31static_assert(
32 std::numeric_limits<float>::is_iec559,
33 "QtYoga::facebook::yoga::detail::CompactValue only works with IEEE754 floats");
34
35#ifdef YOGA_COMPACT_VALUE_TEST
36#define VISIBLE_FOR_TESTING public:
37#else
38#define VISIBLE_FOR_TESTING private:
39#endif
40
41QT_YOGA_NAMESPACE_BEGIN
42
43namespace facebook {
44namespace yoga {
45namespace detail {
46
47// This class stores YGValue in 32 bits.
48// - The value does not matter for Undefined and Auto. NaNs are used for their
49// representation.
50// - To differentiate between Point and Percent, one exponent bit is used.
51// Supported the range [0x40, 0xbf] (0xbf is inclusive for point, but
52// exclusive for percent).
53// - Value ranges:
54// points: 1.08420217e-19f to 36893485948395847680
55// 0x00000000 0x3fffffff
56// percent: 1.08420217e-19f to 18446742974197923840
57// 0x40000000 0x7f7fffff
58// - Zero is supported, negative zero is not
59// - values outside of the representable range are clamped
60class YOGA_EXPORT CompactValue {
61 friend constexpr bool operator==(CompactValue, CompactValue) noexcept;
62
63public:
64 static constexpr auto LOWER_BOUND = 1.08420217e-19f;
65 static constexpr auto UPPER_BOUND_POINT = 36893485948395847680.0f;
66 static constexpr auto UPPER_BOUND_PERCENT = 18446742974197923840.0f;
67
68 template <YGUnit Unit>
69 static CompactValue of(float value) noexcept {
70 if (value == 0.0f || (value < LOWER_BOUND && value > -LOWER_BOUND)) {
71 constexpr auto zero =
72 Unit == YGUnitPercent ? ZERO_BITS_PERCENT : ZERO_BITS_POINT;
73 return {zero};
74 }
75
76 constexpr auto upperBound =
77 Unit == YGUnitPercent ? UPPER_BOUND_PERCENT : UPPER_BOUND_POINT;
78 if (value > upperBound || value < -upperBound) {
79 value = copysignf(x: upperBound, y: value);
80 }
81
82 uint32_t unitBit = Unit == YGUnitPercent ? PERCENT_BIT : 0;
83 auto data = asU32(f: value);
84 data -= BIAS;
85 data |= unitBit;
86 return {data};
87 }
88
89 template <YGUnit Unit>
90 static CompactValue ofMaybe(float value) noexcept {
91 return std::isnan(x: value) || std::isinf(x: value) ? ofUndefined()
92 : of<Unit>(value);
93 }
94
95 static constexpr CompactValue ofZero() noexcept {
96 return CompactValue{ZERO_BITS_POINT};
97 }
98
99 static constexpr CompactValue ofUndefined() noexcept {
100 return CompactValue{};
101 }
102
103 static constexpr CompactValue ofAuto() noexcept {
104 return CompactValue{AUTO_BITS};
105 }
106
107 constexpr CompactValue() noexcept : repr_(0x7FC00000) {}
108
109 CompactValue(const YGValue& x) noexcept : repr_(uint32_t{0}) {
110 switch (x.unit) {
111 case YGUnitUndefined:
112 *this = ofUndefined();
113 break;
114 case YGUnitAuto:
115 *this = ofAuto();
116 break;
117 case YGUnitPoint:
118 *this = of<YGUnitPoint>(value: x.value);
119 break;
120 case YGUnitPercent:
121 *this = of<YGUnitPercent>(value: x.value);
122 break;
123 }
124 }
125
126 operator YGValue() const noexcept {
127 switch (repr_) {
128 case AUTO_BITS:
129 return YGValueAuto;
130 case ZERO_BITS_POINT:
131 return YGValue{.value: 0.0f, .unit: YGUnitPoint};
132 case ZERO_BITS_PERCENT:
133 return YGValue{.value: 0.0f, .unit: YGUnitPercent};
134 }
135
136 if (std::isnan(x: asFloat(u: repr_))) {
137 return YGValueUndefined;
138 }
139
140 auto data = repr_;
141 data &= ~PERCENT_BIT;
142 data += BIAS;
143
144 return YGValue{
145 .value: asFloat(u: data), .unit: repr_ & 0x40000000 ? YGUnitPercent : YGUnitPoint};
146 }
147
148 bool isUndefined() const noexcept {
149 return (
150 repr_ != AUTO_BITS && repr_ != ZERO_BITS_POINT &&
151 repr_ != ZERO_BITS_PERCENT && std::isnan(x: asFloat(u: repr_)));
152 }
153
154 bool isAuto() const noexcept { return repr_ == AUTO_BITS; }
155
156private:
157 uint32_t repr_;
158
159 static constexpr uint32_t BIAS = 0x20000000;
160 static constexpr uint32_t PERCENT_BIT = 0x40000000;
161
162 // these are signaling NaNs with specific bit pattern as payload they will be
163 // silenced whenever going through an FPU operation on ARM + x86
164 static constexpr uint32_t AUTO_BITS = 0x7faaaaaa;
165 static constexpr uint32_t ZERO_BITS_POINT = 0x7f8f0f0f;
166 static constexpr uint32_t ZERO_BITS_PERCENT = 0x7f80f0f0;
167
168 constexpr CompactValue(uint32_t data) noexcept : repr_(data) {}
169
170 VISIBLE_FOR_TESTING uint32_t repr() { return repr_; }
171
172 static uint32_t asU32(float f) {
173#ifdef __cpp_lib_bit_cast
174 return std::bit_cast<uint32_t>(f);
175#else
176 uint32_t u;
177 static_assert(
178 sizeof(u) == sizeof(f), "uint32_t and float must have the same size");
179 std::memcpy(dest: &u, src: &f, n: sizeof(f));
180 return u;
181#endif
182 }
183
184 static float asFloat(uint32_t u) {
185#ifdef __cpp_lib_bit_cast
186 return std::bit_cast<float>(u);
187#else
188 float f;
189 static_assert(
190 sizeof(f) == sizeof(u), "uint32_t and float must have the same size");
191 std::memcpy(dest: &f, src: &u, n: sizeof(u));
192 return f;
193#endif
194 }
195};
196
197template <>
198CompactValue CompactValue::of<YGUnitUndefined>(float) noexcept = delete;
199template <>
200CompactValue CompactValue::of<YGUnitAuto>(float) noexcept = delete;
201template <>
202CompactValue CompactValue::ofMaybe<YGUnitUndefined>(float) noexcept = delete;
203template <>
204CompactValue CompactValue::ofMaybe<YGUnitAuto>(float) noexcept = delete;
205
206constexpr bool operator==(CompactValue a, CompactValue b) noexcept {
207 return a.repr_ == b.repr_;
208}
209
210constexpr bool operator!=(CompactValue a, CompactValue b) noexcept {
211 return !(a == b);
212}
213
214} // namespace detail
215} // namespace yoga
216} // namespace facebook
217
218QT_YOGA_NAMESPACE_END
219
220

source code of qtdeclarative/src/3rdparty/yoga/CompactValue.h