@@ -178,51 +178,42 @@ FOLLY_EXPORT FOLLY_ALWAYS_INLINE enum_find<U>& enum_find_instance() {
178178 return impl;
179179}
180180
181- template <typename E, typename = void >
182- inline constexpr bool eligible_for_dense_enum_optimization_v = false ;
183-
184- // Empty Thrift enums as well as empty Thrift union tag enums do NOT
185- // have TEnumtraits<E>::min()/max() static methods. Instead of failing
186- // the build, we will just exclude them from the dense enum optimization.
187- // It is reasonable to expect few would call `enum_find_name` on an
188- // empty enum. So it should not miss any major optimizations.
189- // Since C++ allows `static_cast<E>()` with any value representable
190- // by the underlying type, it's better to just fallback to the unoptimized
191- // path instead of failing to build.
192181template <typename E>
193- inline constexpr bool eligible_for_dense_enum_optimization_v<
194- E,
195- folly::void_t <decltype (TEnumTraits<E>::max())>> =
196- (((folly::to_underlying(TEnumTraits<E>::max()) -
197- folly::to_underlying (TEnumTraits<E>::min())) <
198- 2 * TEnumTraits<E>::size) ||
199- ((folly::to_underlying(TEnumTraits<E>::max()) -
200- folly::to_underlying(TEnumTraits<E>::min())) < 16)) &&
201- (TEnumTraits<E>::size < 10'000 );
182+ consteval auto enum_find_name_dense_array_make () {
183+ using T = TEnumTraits<E>;
184+ using D = TEnumDataStorage<E>;
185+ constexpr auto min = folly::to_underlying (T::min ());
186+ constexpr auto max = folly::to_underlying (T::max ());
187+ std::array<int16_t , max - min + 1 > ret;
188+ for (auto & e : ret) {
189+ e = -1 ;
190+ }
191+ for (size_t i = 0 ; i < T::size; ++i) {
192+ ret[folly::to_underlying (D::values[i]) - min] = i;
193+ }
194+ return ret;
195+ }
196+
197+ template <typename E>
198+ inline constexpr auto enum_find_name_dense =
199+ enum_find_name_dense_array_make<E>();
202200
203201template <typename E, typename U = std::underlying_type_t <E>>
204202FOLLY_ERASE bool enum_find_name (
205203 E const value, std::string_view* const out) noexcept {
206- if constexpr (eligible_for_dense_enum_optimization_v<E>) {
207- static constexpr auto index = []() consteval {
208- constexpr auto min = folly::to_underlying (TEnumTraits<E>::min ());
209- constexpr auto max = folly::to_underlying (TEnumTraits<E>::max ());
210- constexpr auto size = TEnumTraits<E>::size;
211- std::array<std::string_view, max - min + 1 > ret;
212- for (size_t i = 0 ; i < size; ++i) {
213- ret[folly::to_underlying (TEnumDataStorage<E>::values[i]) - min] =
214- TEnumDataStorage<E>::names[i];
215- }
216- return ret;
217- }();
204+ constexpr auto sz = TEnumTraits<E>::size;
205+ // excludes empty enums and empty union tag enums, but these are typically
206+ // unlikely to be searched anyway
207+ if constexpr (sz && sz <= 4096 ) {
218208 constexpr auto min = folly::to_underlying (TEnumTraits<E>::min ());
219209 constexpr auto max = folly::to_underlying (TEnumTraits<E>::max ());
220- const auto under = folly::to_underlying (value);
221- if (under < min || under > max) {
222- return false ;
210+ constexpr auto gap = max - min;
211+ if constexpr (gap < 2 * sz || gap < 16 ) {
212+ constexpr auto & index = enum_find_name_dense<E>;
213+ const auto under = folly::to_underlying (value);
214+ const auto idx = under < min || under > max ? -1 : index[under - min];
215+ return idx >= 0 && ((*out = TEnumDataStorage<E>::names[idx]), true );
223216 }
224- std::string_view name = index[under - min];
225- return !name.empty () && ((*out = name), true );
226217 }
227218 const auto r = enum_find<U>::find_name (U (value), enum_find_instance<E>());
228219 return r && ((*out = r.result ), true );
0 commit comments