mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: This diff reimplements the prop parsing infrastructure in a part where it interacts with RawProps value. Local synthetic tests show that the new way is 3x faster but the actual production result is quite unpredictable. MobileLab tests show some improvements about 10-20 ms on iPhone 6. In short, the new way is faster because it inverts the lookup order and heavily relies on actual data types (and their properties) that we use. The old approach required about 130 hash-map lookups (where the key is `std::string`) to parse a single *Props object. The new approach prepares concrete-props-specific tables with indexes of coming values ahead of time, iterates over raw data and puts it into those tables, and then performs a lookup in a very efficient manner. Reviewed By: JoshuaGross Differential Revision: D15752968 fbshipit-source-id: 847106e652eb7fc7ef7b99884a6f819ea3b9fd06
89 lines
2.2 KiB
C++
89 lines
2.2 KiB
C++
/**
|
|
* 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.
|
|
*/
|
|
|
|
#include "RawPropsKeyMap.h"
|
|
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
int RawPropsKeyMap::comparator(void const *lhs, void const *rhs) {
|
|
auto a = static_cast<RawPropsKeyMap::Item const *>(lhs);
|
|
auto b = static_cast<RawPropsKeyMap::Item const *>(rhs);
|
|
|
|
if (a->length != b->length) {
|
|
return a->length - b->length;
|
|
}
|
|
|
|
return std::memcmp(a->name, b->name, a->length);
|
|
}
|
|
|
|
void RawPropsKeyMap::insert(RawPropsKey const &key, RawPropsValueIndex value) {
|
|
auto item = Item{};
|
|
item.value = value;
|
|
key.render(item.name, &item.length);
|
|
items_.push_back(item);
|
|
}
|
|
|
|
void RawPropsKeyMap::reindex() {
|
|
// Sorting `items_` by property names length and then lexicographically.
|
|
std::qsort(
|
|
items_.data(),
|
|
items_.size(),
|
|
sizeof(decltype(items_)::value_type),
|
|
&RawPropsKeyMap::comparator);
|
|
|
|
buckets_.resize(kPropNameLengthHardCap);
|
|
|
|
auto length = RawPropsPropNameLength{0};
|
|
for (auto i = 0; i < items_.size(); i++) {
|
|
auto &item = items_[i];
|
|
if (item.length != length) {
|
|
for (auto j = length; j < item.length; j++) {
|
|
buckets_[j] = i;
|
|
}
|
|
length = item.length;
|
|
}
|
|
}
|
|
|
|
for (auto j = length; j < buckets_.size(); j++) {
|
|
buckets_[j] = items_.size();
|
|
}
|
|
}
|
|
|
|
RawPropsValueIndex RawPropsKeyMap::at(
|
|
char const *name,
|
|
RawPropsPropNameLength length) {
|
|
assert(length > 0);
|
|
assert(length < kPropNameLengthHardCap);
|
|
// 1. Find the bucket.
|
|
auto lower = int{buckets_[length - 1]};
|
|
auto upper = int{buckets_[length]} - 1;
|
|
assert(lower - 1 <= upper);
|
|
|
|
// 2. Binary search in the bucket.
|
|
while (lower <= upper) {
|
|
auto median = (lower + upper) / 2;
|
|
auto condition = std::memcmp(items_[median].name, name, length);
|
|
if (condition < 0) {
|
|
lower = median + 1;
|
|
} else if (condition == 0) {
|
|
return items_[median].value;
|
|
} else /* if (condition > 0) */ {
|
|
upper = median - 1;
|
|
}
|
|
}
|
|
|
|
return kRawPropsValueIndexEmpty;
|
|
}
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|