diff --git a/change/react-native-windows-0fb7974b-3432-4444-9e4e-74d40818b302.json b/change/react-native-windows-0fb7974b-3432-4444-9e4e-74d40818b302.json
new file mode 100644
index 00000000000..f288a1dab87
--- /dev/null
+++ b/change/react-native-windows-0fb7974b-3432-4444-9e4e-74d40818b302.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "folly update",
+ "packageName": "react-native-windows",
+ "email": "agnel@microsoft.com",
+ "dependentChangeType": "patch"
+}
diff --git a/vnext/Desktop.DLL/react-native-win32.x64.def b/vnext/Desktop.DLL/react-native-win32.x64.def
index 98f64546b56..0ad602317ef 100644
--- a/vnext/Desktop.DLL/react-native-win32.x64.def
+++ b/vnext/Desktop.DLL/react-native-win32.x64.def
@@ -33,6 +33,8 @@ EXPORTS
?createIUIManager@react@facebook@@YA?AV?$shared_ptr@VIUIManager@react@facebook@@@std@@$$QEAV?$vector@V?$unique_ptr@VIViewManager@react@facebook@@U?$default_delete@VIViewManager@react@facebook@@@std@@@std@@V?$allocator@V?$unique_ptr@VIViewManager@react@facebook@@U?$default_delete@VIViewManager@react@facebook@@@std@@@std@@@2@@4@PEAUINativeUIManager@12@@Z
?createUIManagerModule@react@facebook@@YA?AV?$unique_ptr@VCxxModule@module@xplat@facebook@@U?$default_delete@VCxxModule@module@xplat@facebook@@@std@@@std@@V?$shared_ptr@VIUIManager@react@facebook@@@4@@Z
?createUIManagerModule@react@facebook@@YA?AV?$unique_ptr@VCxxModule@module@xplat@facebook@@U?$default_delete@VCxxModule@module@xplat@facebook@@@std@@@std@@$$QEAV?$shared_ptr@VIUIManager@react@facebook@@@4@$$QEAV?$shared_ptr@VMessageQueueThread@react@facebook@@@4@@Z
+?data@?$to_ascii_powers@$09_K@detail@folly@@2U?$c_array@_K$0BE@@3@B
+?data@?$to_ascii_table@$09U?$to_ascii_alphabet@$0A@@folly@@@detail@folly@@2U?$c_array@G$0GE@@3@B
?destroy@dynamic@folly@@AEAAXXZ
?dispatchCommand@ShadowNode@react@facebook@@UEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBUdynamic@folly@@@Z
?getModuleRegistry@Instance@react@facebook@@QEAAAEAVModuleRegistry@23@XZ
diff --git a/vnext/Desktop.DLL/react-native-win32.x86.def b/vnext/Desktop.DLL/react-native-win32.x86.def
index 11e76f67153..29efc8b3080 100644
--- a/vnext/Desktop.DLL/react-native-win32.x86.def
+++ b/vnext/Desktop.DLL/react-native-win32.x86.def
@@ -34,6 +34,8 @@ EXPORTS
?createIUIManager@react@facebook@@YG?AV?$shared_ptr@VIUIManager@react@facebook@@@std@@$$QAV?$vector@V?$unique_ptr@VIViewManager@react@facebook@@U?$default_delete@VIViewManager@react@facebook@@@std@@@std@@V?$allocator@V?$unique_ptr@VIViewManager@react@facebook@@U?$default_delete@VIViewManager@react@facebook@@@std@@@std@@@2@@4@PAUINativeUIManager@12@@Z
?createUIManagerModule@react@facebook@@YG?AV?$unique_ptr@VCxxModule@module@xplat@facebook@@U?$default_delete@VCxxModule@module@xplat@facebook@@@std@@@std@@V?$shared_ptr@VIUIManager@react@facebook@@@4@@Z
?createUIManagerModule@react@facebook@@YG?AV?$unique_ptr@VCxxModule@module@xplat@facebook@@U?$default_delete@VCxxModule@module@xplat@facebook@@@std@@@std@@$$QAV?$shared_ptr@VIUIManager@react@facebook@@@4@$$QAV?$shared_ptr@VMessageQueueThread@react@facebook@@@4@@Z
+?data@?$to_ascii_powers@$09_K@detail@folly@@2U?$c_array@_K$0BE@@3@B
+?data@?$to_ascii_table@$09U?$to_ascii_alphabet@$0A@@folly@@@detail@folly@@2U?$c_array@G$0GE@@3@B
?destroy@dynamic@folly@@AAEXXZ
?dispatchCommand@ShadowNode@react@facebook@@UAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABUdynamic@folly@@@Z
?getModuleRegistry@Instance@react@facebook@@QAEAAVModuleRegistry@23@XZ
diff --git a/vnext/Directory.Build.props b/vnext/Directory.Build.props
index 51b8d2ad916..96ff3e8029d 100644
--- a/vnext/Directory.Build.props
+++ b/vnext/Directory.Build.props
@@ -18,7 +18,7 @@
The PR (windows-vs-pr.yml) and CI (publish.yml() turn it back on.
-->
false
- 2021.03.29.00
+ 2021.05.10.00
7.1.3
diff --git a/vnext/Folly/Folly.vcxproj b/vnext/Folly/Folly.vcxproj
index 263a65d5bdd..75c84f1be2b 100644
--- a/vnext/Folly/Folly.vcxproj
+++ b/vnext/Folly/Folly.vcxproj
@@ -52,6 +52,7 @@
+
diff --git a/vnext/Folly/Folly.vcxproj.filters b/vnext/Folly/Folly.vcxproj.filters
index 18eabd827d8..0c1f54abdbf 100644
--- a/vnext/Folly/Folly.vcxproj.filters
+++ b/vnext/Folly/Folly.vcxproj.filters
@@ -30,6 +30,9 @@
+
+ Source Files\lang
+
Source Files\lang
diff --git a/vnext/Folly/TEMP_UntilFollyUpdate/dynamic.cpp b/vnext/Folly/TEMP_UntilFollyUpdate/dynamic.cpp
deleted file mode 100644
index f145e2a4600..00000000000
--- a/vnext/Folly/TEMP_UntilFollyUpdate/dynamic.cpp
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include
-
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-namespace folly {
-
-//////////////////////////////////////////////////////////////////////
-
-#define FOLLY_DYNAMIC_DEF_TYPEINFO(T, str) \
- const char* const dynamic::TypeInfo::name = str; \
- //
-
-FOLLY_DYNAMIC_DEF_TYPEINFO(std::nullptr_t, "null")
-FOLLY_DYNAMIC_DEF_TYPEINFO(bool, "boolean")
-FOLLY_DYNAMIC_DEF_TYPEINFO(std::string, "string")
-FOLLY_DYNAMIC_DEF_TYPEINFO(dynamic::Array, "array")
-FOLLY_DYNAMIC_DEF_TYPEINFO(double, "double")
-FOLLY_DYNAMIC_DEF_TYPEINFO(int64_t, "int64")
-FOLLY_DYNAMIC_DEF_TYPEINFO(dynamic::ObjectImpl, "object")
-
-#undef FOLLY_DYNAMIC_DEF_TYPEINFO
-
-const char* dynamic::typeName() const {
- return typeName(type_);
-}
-
-TypeError::TypeError(const std::string& expected, dynamic::Type actual)
- : std::runtime_error(sformat(
- "TypeError: expected dynamic type `{}', but had type `{}'",
- expected,
- dynamic::typeName(actual))) {}
-
-TypeError::TypeError(
- const std::string& expected, dynamic::Type actual1, dynamic::Type actual2)
- : std::runtime_error(sformat(
- "TypeError: expected dynamic types `{}, but had types `{}' and `{}'",
- expected,
- dynamic::typeName(actual1),
- dynamic::typeName(actual2))) {}
-
-// This is a higher-order preprocessor macro to aid going from runtime
-// types to the compile time type system.
-#define FB_DYNAMIC_APPLY(type, apply) \
- do { \
- switch ((type)) { \
- case NULLT: \
- apply(std::nullptr_t); \
- break; \
- case ARRAY: \
- apply(Array); \
- break; \
- case BOOL: \
- apply(bool); \
- break; \
- case DOUBLE: \
- apply(double); \
- break; \
- case INT64: \
- apply(int64_t); \
- break; \
- case OBJECT: \
- apply(ObjectImpl); \
- break; \
- case STRING: \
- apply(std::string); \
- break; \
- default: \
- CHECK(0); \
- abort(); \
- } \
- } while (0)
-
-bool dynamic::operator<(dynamic const& o) const {
- if (UNLIKELY(type_ == OBJECT || o.type_ == OBJECT)) {
- throw_exception("object", type_);
- }
- if (type_ != o.type_) {
- return type_ < o.type_;
- }
-
-#define FB_X(T) return CompareOp::comp(*getAddress(), *o.getAddress())
- FB_DYNAMIC_APPLY(type_, FB_X);
-#undef FB_X
-}
-
-bool dynamic::operator==(dynamic const& o) const {
- if (type() != o.type()) {
- if (isNumber() && o.isNumber()) {
- auto& integ = isInt() ? *this : o;
- auto& doubl = isInt() ? o : *this;
- return integ.asInt() == doubl.asDouble();
- }
- return false;
- }
-
-#define FB_X(T) return *getAddress() == *o.getAddress();
- FB_DYNAMIC_APPLY(type_, FB_X);
-#undef FB_X
-}
-
-dynamic& dynamic::operator=(dynamic const& o) {
- if (&o != this) {
- if (type_ == o.type_) {
-#define FB_X(T) *getAddress() = *o.getAddress()
- FB_DYNAMIC_APPLY(type_, FB_X);
-#undef FB_X
- } else {
- destroy();
-#define FB_X(T) new (getAddress()) T(*o.getAddress())
- FB_DYNAMIC_APPLY(o.type_, FB_X);
-#undef FB_X
- type_ = o.type_;
- }
- }
- return *this;
-}
-
-dynamic& dynamic::operator=(dynamic&& o) noexcept {
- if (&o != this) {
- if (type_ == o.type_) {
-#define FB_X(T) *getAddress() = std::move(*o.getAddress())
- FB_DYNAMIC_APPLY(type_, FB_X);
-#undef FB_X
- } else {
- destroy();
-#define FB_X(T) new (getAddress()) T(std::move(*o.getAddress()))
- FB_DYNAMIC_APPLY(o.type_, FB_X);
-#undef FB_X
- type_ = o.type_;
- }
- }
- return *this;
-}
-
-dynamic const& dynamic::atImpl(dynamic const& idx) const& {
- if (auto* parray = get_nothrow()) {
- if (!idx.isInt()) {
- throw_exception("int64", idx.type());
- }
- if (idx < 0 || idx >= parray->size()) {
- throw_exception("out of range in dynamic array");
- }
- return (*parray)[size_t(idx.asInt())];
- } else if (auto* pobject = get_nothrow()) {
- auto it = pobject->find(idx);
- if (it == pobject->end()) {
- throw_exception(
- sformat("couldn't find key {} in dynamic object", idx.asString()));
- }
- return it->second;
- } else {
- throw_exception("object/array", type());
- }
-}
-
-dynamic const& dynamic::at(StringPiece idx) const& {
- auto* pobject = get_nothrow();
- if (!pobject) {
- throw_exception("object", type());
- }
- auto it = pobject->find(idx);
- if (it == pobject->end()) {
- throw_exception(
- sformat("couldn't find key {} in dynamic object", idx));
- }
- return it->second;
-}
-
-dynamic& dynamic::operator[](StringPiece k) & {
- auto& obj = get();
- auto ret = obj.emplace(k, nullptr);
- return ret.first->second;
-}
-
-dynamic dynamic::getDefault(StringPiece k, const dynamic& v) const& {
- auto& obj = get();
- auto it = obj.find(k);
- return it == obj.end() ? v : it->second;
-}
-
-dynamic dynamic::getDefault(StringPiece k, dynamic&& v) const& {
- auto& obj = get();
- auto it = obj.find(k);
- // Avoid clang bug with ternary
- if (it == obj.end()) {
- return std::move(v);
- } else {
- return it->second;
- }
-}
-
-dynamic dynamic::getDefault(StringPiece k, const dynamic& v) && {
- auto& obj = get();
- auto it = obj.find(k);
- // Avoid clang bug with ternary
- if (it == obj.end()) {
- return v;
- } else {
- return std::move(it->second);
- }
-}
-
-dynamic dynamic::getDefault(StringPiece k, dynamic&& v) && {
- auto& obj = get();
- auto it = obj.find(k);
- return std::move(it == obj.end() ? v : it->second);
-}
-
-const dynamic* dynamic::get_ptrImpl(dynamic const& idx) const& {
- if (auto* parray = get_nothrow()) {
- if (!idx.isInt()) {
- throw_exception("int64", idx.type());
- }
- if (idx < 0 || idx >= parray->size()) {
- return nullptr;
- }
- return &(*parray)[size_t(idx.asInt())];
- } else if (auto* pobject = get_nothrow()) {
- auto it = pobject->find(idx);
- if (it == pobject->end()) {
- return nullptr;
- }
- return &it->second;
- } else {
- throw_exception("object/array", type());
- }
-}
-
-const dynamic* dynamic::get_ptr(StringPiece idx) const& {
- auto* pobject = get_nothrow();
- if (!pobject) {
- throw_exception("object", type());
- }
- auto it = pobject->find(idx);
- if (it == pobject->end()) {
- return nullptr;
- }
- return &it->second;
-}
-
-std::size_t dynamic::size() const {
- if (auto* ar = get_nothrow()) {
- return ar->size();
- }
- if (auto* obj = get_nothrow()) {
- return obj->size();
- }
- if (auto* str = get_nothrow()) {
- return str->size();
- }
- throw_exception("array/object/string", type());
-}
-
-dynamic::iterator dynamic::erase(const_iterator first, const_iterator last) {
- auto& arr = get();
- return get().erase(
- arr.begin() + (first - arr.begin()), arr.begin() + (last - arr.begin()));
-}
-
-std::size_t dynamic::hash() const {
- switch (type()) {
- case NULLT:
- return 0xBAAAAAAD;
- case OBJECT: {
- // Accumulate using addition instead of using hash_range (as in the ARRAY
- // case), as we need a commutative hash operation since unordered_map's
- // iteration order is unspecified.
- auto h = std::hash>{};
- return std::accumulate(
- items().begin(),
- items().end(),
- size_t{0x0B1EC7},
- [&](auto acc, auto const& item) { return acc + h(item); });
- }
- case ARRAY:
- return static_cast(folly::hash::hash_range(begin(), end()));
- case INT64:
- return std::hash()(getInt());
- case DOUBLE:
- return std::hash()(getDouble());
- case BOOL:
- return std::hash()(getBool());
- case STRING:
- // keep consistent with detail::DynamicHasher
- return Hash()(getString());
- }
- assume_unreachable();
-}
-
-char const* dynamic::typeName(Type t) {
-#define FB_X(T) return TypeInfo::name
- FB_DYNAMIC_APPLY(t, FB_X);
-#undef FB_X
-}
-
-void dynamic::destroy() noexcept {
- // This short-circuit speeds up some microbenchmarks.
- if (type_ == NULLT) {
- return;
- }
-
-#define FB_X(T) detail::Destroy::destroy(getAddress())
- FB_DYNAMIC_APPLY(type_, FB_X);
-#undef FB_X
- type_ = NULLT;
- u_.nul = nullptr;
-}
-
-dynamic dynamic::merge_diff(const dynamic& source, const dynamic& target) {
- if (!source.isObject() || !target.isObject()) {
- return target;
- }
-
- dynamic diff = object;
-
- // added/modified keys
- for (const auto& pair : target.items()) {
- auto it = source.find(pair.first);
- if (it == source.items().end()) {
- diff[pair.first] = pair.second;
- } else {
- const auto& ssource = it->second;
- const auto& starget = pair.second;
- if (ssource.isObject() && starget.isObject()) {
- auto sdiff = merge_diff(ssource, starget);
- if (!sdiff.empty()) {
- diff[pair.first] = std::move(sdiff);
- }
- } else if (ssource != starget) {
- diff[pair.first] = merge_diff(ssource, starget);
- }
- }
- }
-
- // removed keys
- for (const auto& pair : source.items()) {
- auto it = target.find(pair.first);
- if (it == target.items().end()) {
- diff[pair.first] = nullptr;
- }
- }
-
- return diff;
-}
-
-// clang-format off
-dynamic::resolved_json_pointer
-// clang-format on
-dynamic::try_get_ptr(json_pointer const& jsonPtr) const& {
- using err_code = json_pointer_resolution_error_code;
- using error = json_pointer_resolution_error;
-
- auto const& tokens = jsonPtr.tokens();
- if (tokens.empty()) {
- return json_pointer_resolved_value{
- nullptr, this, {nullptr, nullptr}, 0};
- }
-
- dynamic const* curr = this;
- dynamic const* prev = nullptr;
-
- size_t curr_idx{0};
- StringPiece curr_key{};
-
- for (auto it : enumerate(tokens)) {
- // hit bottom but pointer not exhausted yet
- if (!curr) {
- return makeUnexpected(
- error{err_code::json_pointer_out_of_bounds, it.index, prev});
- }
- prev = curr;
- // handle lookup in array
- if (auto const* parray = curr->get_nothrow()) {
- if (it->size() > 1 && it->at(0) == '0') {
- return makeUnexpected(
- error{err_code::index_has_leading_zero, it.index, prev});
- }
- // if last element of pointer is '-', this is an append operation
- if (it->size() == 1 && it->at(0) == '-') {
- // was '-' the last token in pointer?
- if (it.index == tokens.size() - 1) {
- return makeUnexpected(
- error{err_code::append_requested, it.index, prev});
- }
- // Cannot resolve past '-' in an array
- curr = nullptr;
- continue;
- }
- auto const idx = tryTo(*it);
- if (!idx.hasValue()) {
- return makeUnexpected(
- error{err_code::index_not_numeric, it.index, prev});
- }
- if (idx.value() < parray->size()) {
- curr = &(*parray)[idx.value()];
- curr_idx = idx.value();
- } else {
- return makeUnexpected(
- error{err_code::index_out_of_bounds, it.index, prev});
- }
- continue;
- }
- // handle lookup in object
- if (auto const* pobject = curr->get_nothrow()) {
- auto const sub_it = pobject->find(*it);
- if (sub_it == pobject->end()) {
- return makeUnexpected(error{err_code::key_not_found, it.index, prev});
- }
- curr = &sub_it->second;
- curr_key = *it;
- continue;
- }
- return makeUnexpected(
- error{err_code::element_not_object_or_array, it.index, prev});
- }
- return json_pointer_resolved_value{
- prev, curr, curr_key, curr_idx};
-}
-
-const dynamic* dynamic::get_ptr(json_pointer const& jsonPtr) const& {
- using err_code = json_pointer_resolution_error_code;
-
- auto ret = try_get_ptr(jsonPtr);
- if (ret.hasValue()) {
- return ret.value().value;
- }
-
- auto const ctx = ret.error().context;
- auto const objType = ctx ? ctx->type() : Type::NULLT;
-
- switch (ret.error().error_code) {
- case err_code::key_not_found:
- return nullptr;
- case err_code::index_out_of_bounds:
- return nullptr;
- case err_code::append_requested:
- return nullptr;
- case err_code::index_not_numeric:
- throw std::invalid_argument("array index is not numeric");
- case err_code::index_has_leading_zero:
- throw std::invalid_argument(
- "leading zero not allowed when indexing arrays");
- case err_code::element_not_object_or_array:
- throw_exception("object/array", objType);
- case err_code::json_pointer_out_of_bounds:
- return nullptr;
- case err_code::other:
- default:
- return nullptr;
- }
- assume_unreachable();
-}
-
-//////////////////////////////////////////////////////////////////////
-
-} // namespace folly
diff --git a/vnext/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.h b/vnext/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.h
deleted file mode 100644
index 1239feb9420..00000000000
--- a/vnext/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.h
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#if _MSC_VER
-#include
-#endif
-
-namespace folly {
-
-// to_ascii_alphabet
-//
-// Used implicity by to_ascii_lower and to_ascii_upper below.
-//
-// This alphabet translates digits to 0-9,a-z or 0-9,A-Z. The largest supported
-// base is 36; operator() presumes an argument less than that.
-//
-// Alternative alphabets may be used with to_ascii_with provided they match
-// the constructibility/destructibility and the interface of this one.
-template
-struct to_ascii_alphabet {
- // operator()
- //
- // Translates a single digit to 0-9,a-z or 0-9,A-Z.
- //
- // async-signal-safe
- constexpr char operator()(uint8_t b) const {
- return b < 10 ? '0' + b : (Upper ? 'A' : 'a') + (b - 10);
- }
-};
-using to_ascii_alphabet_lower = to_ascii_alphabet;
-using to_ascii_alphabet_upper = to_ascii_alphabet;
-
-namespace detail {
-
-#if defined(_M_IX86)
-FOLLY_ERASE auto to_ascii_port_clzll(uint64_t v) {
- return __builtin_clzll(v);
-}
-#else
-FOLLY_ERASE auto to_ascii_port_clzll(uint64_t v) {
-#if _MSC_VER
-#if FOLLY_X64
- return __lzcnt64(v);
-#else
- return __assume(0), 0;
-#endif
-#else
- return __builtin_clzll(v);
-#endif
-}
-#endif
-
-template
-struct to_ascii_array {
- using data_type_ = c_array;
- static constexpr data_type_ data_() {
- data_type_ result{};
- Alphabet alpha;
- for (size_t i = 0; i < Base; ++i) {
- result.data[i] = alpha(static_cast(i));
- }
- return result;
- }
- // @lint-ignore CLANGTIDY
- static data_type_ const data;
- constexpr char operator()(uint8_t index) const { // also an alphabet
- return data.data[index];
- }
-};
-template
-alignas(hardware_constructive_interference_size)
- typename to_ascii_array::data_type_ const
- to_ascii_array::data =
- to_ascii_array::data_();
-
-extern template to_ascii_array<8, to_ascii_alphabet_lower>::data_type_ const
- to_ascii_array<8, to_ascii_alphabet_lower>::data;
-extern template to_ascii_array<10, to_ascii_alphabet_lower>::data_type_ const
- to_ascii_array<10, to_ascii_alphabet_lower>::data;
-extern template to_ascii_array<16, to_ascii_alphabet_lower>::data_type_ const
- to_ascii_array<16, to_ascii_alphabet_lower>::data;
-extern template to_ascii_array<8, to_ascii_alphabet_upper>::data_type_ const
- to_ascii_array<8, to_ascii_alphabet_upper>::data;
-extern template to_ascii_array<10, to_ascii_alphabet_upper>::data_type_ const
- to_ascii_array<10, to_ascii_alphabet_upper>::data;
-extern template to_ascii_array<16, to_ascii_alphabet_upper>::data_type_ const
- to_ascii_array<16, to_ascii_alphabet_upper>::data;
-
-template
-struct to_ascii_table {
- using data_type_ = c_array;
- static constexpr data_type_ data_() {
- data_type_ result{};
- Alphabet alpha;
- for (size_t i = 0; i < Base * Base; ++i) {
- result.data[i] = //
- (alpha(uint8_t(i / Base)) << (kIsLittleEndian ? 0 : 8)) |
- (alpha(uint8_t(i % Base)) << (kIsLittleEndian ? 8 : 0));
- }
- return result;
- }
- // @lint-ignore CLANGTIDY
- static data_type_ const data;
-};
-template
-alignas(hardware_constructive_interference_size)
- typename to_ascii_table::data_type_ const
- to_ascii_table::data =
- to_ascii_table::data_();
-
-extern template to_ascii_table<8, to_ascii_alphabet_lower>::data_type_ const
- to_ascii_table<8, to_ascii_alphabet_lower>::data;
-extern template to_ascii_table<10, to_ascii_alphabet_lower>::data_type_ const
- to_ascii_table<10, to_ascii_alphabet_lower>::data;
-extern template to_ascii_table<16, to_ascii_alphabet_lower>::data_type_ const
- to_ascii_table<16, to_ascii_alphabet_lower>::data;
-extern template to_ascii_table<8, to_ascii_alphabet_upper>::data_type_ const
- to_ascii_table<8, to_ascii_alphabet_upper>::data;
-extern template to_ascii_table<10, to_ascii_alphabet_upper>::data_type_ const
- to_ascii_table<10, to_ascii_alphabet_upper>::data;
-extern template to_ascii_table<16, to_ascii_alphabet_upper>::data_type_ const
- to_ascii_table<16, to_ascii_alphabet_upper>::data;
-
-template
-struct to_ascii_powers {
- static constexpr size_t size_(I v) {
- return 1 + (v < Base ? 0 : size_(v / Base));
- }
- static constexpr size_t const size = size_(~I(0));
- using data_type_ = c_array;
- static constexpr data_type_ data_() {
- data_type_ result{};
- for (size_t i = 0; i < size; ++i) {
- result.data[i] = constexpr_pow(Base, i);
- }
- return result;
- }
- // @lint-ignore CLANGTIDY
- static data_type_ const data;
-};
-template
-constexpr size_t const to_ascii_powers::size;
-template
-alignas(hardware_constructive_interference_size)
- typename to_ascii_powers::data_type_ const
- to_ascii_powers::data = to_ascii_powers::data_();
-
-extern template to_ascii_powers<8, uint64_t>::data_type_ const
- to_ascii_powers<8, uint64_t>::data;
-extern template to_ascii_powers<10, uint64_t>::data_type_ const
- to_ascii_powers<10, uint64_t>::data;
-extern template to_ascii_powers<16, uint64_t>::data_type_ const
- to_ascii_powers<16, uint64_t>::data;
-
-template
-FOLLY_ALWAYS_INLINE size_t to_ascii_size_imuls(uint64_t v) {
- using powers = to_ascii_powers;
- uint64_t p = 1;
- for (size_t i = 0u; i < powers::size; ++i, p *= Base) {
- if (FOLLY_UNLIKELY(v < p)) {
- return i + size_t(i == 0);
- }
- }
- return powers::size;
-}
-
-template
-FOLLY_ALWAYS_INLINE size_t to_ascii_size_idivs(uint64_t v) {
- size_t i = 1;
- while (v >= Base) {
- i += 1;
- v /= Base;
- }
- return i;
-}
-
-template
-FOLLY_ALWAYS_INLINE size_t to_ascii_size_array(uint64_t v) {
- using powers = to_ascii_powers;
- for (size_t i = 0u; i < powers::size; ++i) {
- if (FOLLY_LIKELY(v < powers::data.data[i])) {
- return i + size_t(i == 0);
- }
- }
- return powers::size;
-}
-
-// For some architectures, we can get a little help from clzll, the "count
-// leading zeros" builtin, which is backed by a single performant instruction.
-//
-// Note that the compiler implements __builtin_clzll on all architectures, but
-// only emits a single clzll instruction when the architecture has one.
-//
-// This implementation may be faster than the basic ones in the general case
-// because the time taken to compute this one is constant for non-zero v,
-// whereas the basic ones take time proportional to log<2>(v). Whether this one
-// is actually faster depends on the emitted code for this implementation and
-// on whether the loops in the basic implementations are unrolled.
-template
-FOLLY_ALWAYS_INLINE size_t to_ascii_size_clzll(uint64_t v) {
- using powers = to_ascii_powers;
-
- // clzll is undefined for 0; must special case this
- if (FOLLY_UNLIKELY(!v)) {
- return 1;
- }
-
- // log2 is approx log<2>(v)
- size_t const vlog2 = 64 - static_cast(to_ascii_port_clzll(v));
-
- // handle directly when Base is power-of-two
- if (!(Base & (Base - 1))) {
- constexpr auto const blog2 = constexpr_log2(Base);
- return vlog2 / blog2 + size_t(vlog2 % blog2 != 0);
- }
-
- // blog2r is approx 1 / log<2>(Base), used in log change-of-base just below
- constexpr auto const blog2r = 8. / constexpr_log2(constexpr_pow(Base, 8));
-
- // vlogb is approx log(v) = log<2>(v) / log<2>(Base)
- auto const vlogb = vlog2 * size_t(blog2r * 256) / 256;
-
- // return vlogb, adjusted if necessary
- return vlogb + size_t(vlogb < powers::size && v >= powers::data.data[vlogb]);
-}
-
-template
-FOLLY_ALWAYS_INLINE size_t to_ascii_size(uint64_t v) {
- return kIsArchAmd64 && !(Base & (Base - 1)) //
- ? to_ascii_size_clzll(v)
- : to_ascii_size_array(v);
-}
-
-// The straightforward implementation, assuming the size known in advance.
-//
-// The straightforward implementation without the size known in advance would
-// entail emitting the bytes backward and then reversing them at the end, once
-// the size is known.
-template
-FOLLY_ALWAYS_INLINE void to_ascii_with_basic(
- char* out, size_t size, uint64_t v) {
- Alphabet const xlate;
- for (auto pos = size - 1; pos; --pos) {
- // keep /, % together so a peephole optimization computes them together
- auto const q = v / Base;
- auto const r = v % Base;
- out[pos] = xlate(r);
- v = q;
- }
- out[0] = xlate(v);
-}
-template
-FOLLY_ALWAYS_INLINE size_t to_ascii_with_basic(char* out, uint64_t v) {
- auto const size = to_ascii_size(v);
- to_ascii_with_basic(out, size, v);
- return size;
-}
-
-// A variant of the straightforward implementation, but using a lookup table.
-template
-FOLLY_ALWAYS_INLINE void to_ascii_with_array(
- char* out, size_t size, uint64_t v) {
- using array = to_ascii_array; // also an alphabet
- to_ascii_with_basic(out, size, v);
-}
-template
-FOLLY_ALWAYS_INLINE size_t to_ascii_with_array(char* out, uint64_t v) {
- auto const size = to_ascii_size(v);
- to_ascii_with_array(out, size, v);
- return size;
-}
-
-// A trickier implementation which performs half as many divides as the other,
-// more straightforward, implementation. On modern hardware, the divides are
-// the bottleneck (even when the compiler emits a complicated sequence of add,
-// sub, and mul instructions with special constants to simulate a divide by a
-// fixed denominator).
-//
-// The downside of this implementation is that the emitted code is larger,
-// especially when the divide is simulated, which affects inlining decisions.
-template
-FOLLY_ALWAYS_INLINE void to_ascii_with_table(
- char* out, size_t size, uint64_t v) {
- using table = to_ascii_table;
- auto pos = size - 2;
- while (FOLLY_UNLIKELY(v >= Base * Base)) {
- // keep /, % together so a peephole optimization computes them together
- auto const q = v / (Base * Base);
- auto const r = v % (Base * Base);
- auto const val = table::data.data[size_t(r)];
- std::memcpy(out + pos, &val, 2);
- pos -= 2;
- v = q;
- }
- auto const val = table::data.data[size_t(v)];
- if (FOLLY_UNLIKELY(size % 2 == 0)) {
- std::memcpy(out, &val, 2);
- } else {
- *out = val >> (kIsLittleEndian ? 8 : 0);
- }
-}
-template
-FOLLY_ALWAYS_INLINE size_t to_ascii_with_table(char* out, uint64_t v) {
- auto const size = to_ascii_size(v);
- to_ascii_with_table(out, size, v);
- return size;
-}
-
-} // namespace detail
-
-// to_ascii_size_max
-//
-// The maximum size buffer that might be required to hold the ascii-encoded
-// representation of any value of unsigned type I in base Base.
-//
-// In base 10, u64 requires at most 20 bytes, u32 at most 10, u16 at most 5,
-// and u8 at most 3.
-//
-// async-signal-safe
-template
-constexpr size_t to_ascii_size_max() {
- return detail::to_ascii_powers::size;
-}
-
-// to_ascii_size_max_decimal
-//
-// An alias to to_ascii_size_max<10>.
-//
-// async-signal-safe
-template
-constexpr size_t to_ascii_size_max_decimal() {
- return to_ascii_size_max<10, I>();
-}
-
-// to_ascii_size
-//
-// Returns the number of digits in the base Base representation of a uint64_t.
-// Useful for preallocating buffers, etc.
-//
-// async-signal-safe
-template
-size_t to_ascii_size(uint64_t v) {
- return detail::to_ascii_size(v);
-}
-
-// to_ascii_size_decimal
-//
-// An alias to to_ascii_size<10>.
-//
-// async-signal-safe
-inline size_t to_ascii_size_decimal(uint64_t v) {
- return to_ascii_size<10>(v);
-}
-
-// to_ascii_with
-//
-// Copies the digits of v, in base Base, translated with Alphabet, into buffer
-// and returns the number of bytes written.
-//
-// Does *not* append a null terminator. It is the caller's responsibility to
-// append a null terminator if one is required.
-//
-// Assumes buffer points to at least to_ascii_size(v) bytes of writable
-// memory. It is the caller's responsibility to provide a writable buffer with
-// the required min size.
-//
-// async-signal-safe
-template
-size_t to_ascii_with(char* out, uint64_t v) {
- return detail::to_ascii_with_table(out, v);
-}
-
-// to_ascii_lower
-//
-// Composes to_ascii_with with to_ascii_alphabet_lower.
-//
-// async-signal-safe
-template
-size_t to_ascii_lower(char* out, uint64_t v) {
- return to_ascii_with(out, v);
-}
-
-// to_ascii_upper
-//
-// Composes to_ascii_with with to_ascii_alphabet_upper.
-//
-// async-signal-safe
-template
-size_t to_ascii_upper(char* out, uint64_t v) {
- return to_ascii_with(out, v);
-}
-
-// to_ascii_decimal
-//
-// An alias to to_ascii<10, false>.
-//
-// async-signals-afe
-inline size_t to_ascii_decimal(char* out, uint64_t v) {
- return to_ascii_lower<10>(out, v);
-}
-
-} // namespace folly