Fabric: Introducing Better: For faster, clear and ideomatic codebase
Summary: `Better` is a trivial collection of basic tools borrowed from other low-level general purpose libraries (like Folly, Abseil or Boost). The main goals of Better: - Make the codebase more portable; - Make the dependency list explicit (by decoupling it as a dependency list of Better); - Make relying on modern C++ patterns and tools in code simple and easy. - Make executing experiments with different dependencies easier. As a first example usage, this diff replaces std::unordered_map with an efficient one from folly on the one of the hottest paths. Reviewed By: JoshuaGross Differential Revision: D13944565 fbshipit-source-id: 5fa2c4abe6c17f7361eddcc25f968b6440d5d9db
This commit is contained in:
parent
7ecf55fc9d
commit
fd3b8f2000
|
@ -0,0 +1,55 @@
|
|||
load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
|
||||
load(
|
||||
"//tools/build_defs/oss:rn_defs.bzl",
|
||||
"ANDROID",
|
||||
"APPLE",
|
||||
"get_apple_compiler_flags",
|
||||
"get_apple_inspector_flags",
|
||||
"rn_xplat_cxx_library",
|
||||
"subdir_glob",
|
||||
)
|
||||
|
||||
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
|
||||
|
||||
rn_xplat_cxx_library(
|
||||
name = "better",
|
||||
srcs = glob(
|
||||
["**/*.cpp"],
|
||||
exclude = glob(["tests/**/*.cpp"]),
|
||||
),
|
||||
headers = glob(
|
||||
["**/*.h"],
|
||||
exclude = glob(["tests/**/*.h"]),
|
||||
),
|
||||
header_namespace = "",
|
||||
exported_headers = subdir_glob(
|
||||
[
|
||||
("", "*.h"),
|
||||
],
|
||||
prefix = "better",
|
||||
),
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++14",
|
||||
"-Wall",
|
||||
],
|
||||
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
|
||||
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
|
||||
force_static = True,
|
||||
macosx_tests_override = [],
|
||||
platforms = (ANDROID, APPLE),
|
||||
preprocessor_flags = [
|
||||
"-DLOG_TAG=\"ReactNative\"",
|
||||
"-DWITH_FBSYSTRACE=1",
|
||||
],
|
||||
tests = [],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
"xplat//fbsystrace:fbsystrace",
|
||||
"xplat//folly:headers_only",
|
||||
"xplat//folly:memory",
|
||||
"xplat//folly:molly",
|
||||
"xplat//third-party/glog:glog",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace facebook {
|
||||
namespace better {
|
||||
|
||||
/*
|
||||
* `Better` is a trivial collection of basic tools borrowed from other low-level
|
||||
* general purpose libraries (like Folly, Abseil or Boost). The main goals of
|
||||
* Better:
|
||||
* - Make the codebase more portable;
|
||||
* - Make the dependency list explicit (by decoupling it as a dependency list of
|
||||
* Better);
|
||||
* - Make relying on modern C++ patterns and tools in code simple and easy.
|
||||
* - Make executing experiments with different dependencies easier.
|
||||
*
|
||||
* What should be part of Better and what should not? Should I add some piece of
|
||||
* functionality in the Better? Here is a quick checklist.
|
||||
*
|
||||
* If one of the following is true, yes, go for it:
|
||||
* - If some feature is already in some future C++ standard (possibly in draft
|
||||
* stage) and it's already implemented in some 3rd party library.
|
||||
* - If some standardized feature of C++ is implemented in the standard not in
|
||||
* the most efficient way (because the standard enforces some tricky constraints
|
||||
* (like always-valid iterators) which nobody uses and should use), but you have
|
||||
* a library that does it right providing exact same interface.
|
||||
*
|
||||
* If one of the following is true, please do *NOT* do it (at least as part of
|
||||
* the library):
|
||||
* - You want to use some very fancy pattern that your favorite library (but
|
||||
* nothing else) provides, and You want to make this pattern very command in the
|
||||
* code base. Your hope is that this pattern will conquer the world and be
|
||||
* a part of the C++ standard eventually.
|
||||
* - You favorite library provides some general purpose container that 10x times
|
||||
* faster than the standard one, so You want to use that in the code base. That
|
||||
* container does not have compatible API though (because it's a clear trade-off
|
||||
* with efficiency, of course).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enables using Folly containers instead of standard ones (such as map, vector,
|
||||
* string, optional and etc.)
|
||||
*/
|
||||
#define BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
} // namespace better
|
||||
} // namespace facebook
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <better/better.h>
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
#include <folly/container/F14Map.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace better {
|
||||
|
||||
/*
|
||||
* Note: In Better, `map` aliases to `unorderd_map` because everyone agrees that
|
||||
* an *ordered* map is nonsense and was a huge mistake for standardization. If
|
||||
* you need an *ordered* map, feel free to introduce that as
|
||||
* `better::ordered_map`.
|
||||
*/
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
template <typename... Ts>
|
||||
using map = folly::F14FastMap<Ts...>;
|
||||
|
||||
#else
|
||||
|
||||
template <typename... Ts>
|
||||
using map = std::unordered_map<Ts...>;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace better
|
||||
} // namespace facebook
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <folly/SharedMutex.h>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace facebook {
|
||||
namespace better {
|
||||
|
||||
template <typename T>
|
||||
using shared_lock = std::shared_lock<T>;
|
||||
|
||||
template <typename T>
|
||||
using shared_mutex = folly::SharedMutex<T>;
|
||||
|
||||
} // namespace better
|
||||
} // namespace facebook
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <better/better.h>
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
#include <folly/Optional.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <optional>
|
||||
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace better {
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
template <typename Value>
|
||||
using optional = folly::Optional<Value>;
|
||||
|
||||
#else
|
||||
|
||||
template <typename Value>
|
||||
using optional = std::optional<Value>;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace better
|
||||
} // namespace facebook
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <better/better.h>
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
#include <folly/container/F14Set.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace better {
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
template <typename... Ts>
|
||||
using set = folly::F14FastSet<Ts...>;
|
||||
|
||||
#else
|
||||
|
||||
template <typename... Ts>
|
||||
using set = std::unordered_set<Ts...>;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace better
|
||||
} // namespace facebook
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <better/better.h>
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
#include <folly/fbstring.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <string>
|
||||
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace better {
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
using string = folly::fbstring;
|
||||
|
||||
#else
|
||||
|
||||
using string = std::string;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace better
|
||||
} // namespace facebook
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <better/better.h>
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
#include <folly/fbvector.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <vector>
|
||||
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace better {
|
||||
|
||||
#ifdef BETTER_USE_FOLLY_CONTAINERS
|
||||
|
||||
template <typename... Ts>
|
||||
using vector = folly::fbvector<Ts...>;
|
||||
|
||||
#else
|
||||
|
||||
template <typename... Ts>
|
||||
using vector = std::vector<Ts...>;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace better
|
||||
} // namespace facebook
|
|
@ -56,6 +56,7 @@ rn_xplat_cxx_library(
|
|||
"xplat//folly:memory",
|
||||
"xplat//folly:molly",
|
||||
"xplat//third-party/glog:glog",
|
||||
react_native_xplat_target("better:better"),
|
||||
react_native_xplat_target("fabric/core:core"),
|
||||
react_native_xplat_target("fabric/debug:debug"),
|
||||
react_native_xplat_target("fabric/events:events"),
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "Differentiator.h"
|
||||
|
||||
#include <better/map.h>
|
||||
#include <react/core/LayoutableShadowNode.h>
|
||||
#include "ShadowView.h"
|
||||
|
||||
|
@ -65,7 +66,7 @@ static void calculateShadowViewMutations(
|
|||
return;
|
||||
}
|
||||
|
||||
std::unordered_map<Tag, ShadowViewNodePair> insertedPaires;
|
||||
better::map<Tag, ShadowViewNodePair> insertedPairs;
|
||||
int index = 0;
|
||||
|
||||
ShadowViewMutationList createMutations = {};
|
||||
|
@ -116,7 +117,7 @@ static void calculateShadowViewMutations(
|
|||
insertMutations.push_back(ShadowViewMutation::InsertMutation(
|
||||
parentShadowView, newChildPair.shadowView, index));
|
||||
|
||||
insertedPaires.insert({newChildPair.shadowView.tag, newChildPair});
|
||||
insertedPairs.insert({newChildPair.shadowView.tag, newChildPair});
|
||||
}
|
||||
|
||||
// Stage 3: Collecting `Delete` and `Remove` mutations
|
||||
|
@ -129,9 +130,9 @@ static void calculateShadowViewMutations(
|
|||
removeMutations.push_back(ShadowViewMutation::RemoveMutation(
|
||||
parentShadowView, oldChildPair.shadowView, index));
|
||||
|
||||
const auto &it = insertedPaires.find(oldChildPair.shadowView.tag);
|
||||
const auto &it = insertedPairs.find(oldChildPair.shadowView.tag);
|
||||
|
||||
if (it == insertedPaires.end()) {
|
||||
if (it == insertedPairs.end()) {
|
||||
// The old view was *not* (re)inserted.
|
||||
// We have to generate `delete` mutation and apply the algorithm
|
||||
// recursively.
|
||||
|
@ -163,11 +164,11 @@ static void calculateShadowViewMutations(
|
|||
newGrandChildPairs);
|
||||
}
|
||||
|
||||
// In any case we have to remove the view from `insertedPaires` as
|
||||
// In any case we have to remove the view from `insertedPairs` as
|
||||
// indication that the view was actually removed (which means that
|
||||
// the view existed before), hence we don't have to generate
|
||||
// `create` mutation.
|
||||
insertedPaires.erase(it);
|
||||
insertedPairs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,8 +177,8 @@ static void calculateShadowViewMutations(
|
|||
index++) {
|
||||
const auto &newChildPair = newChildPairs[index];
|
||||
|
||||
if (insertedPaires.find(newChildPair.shadowView.tag) ==
|
||||
insertedPaires.end()) {
|
||||
if (insertedPairs.find(newChildPair.shadowView.tag) ==
|
||||
insertedPairs.end()) {
|
||||
// The new view was (re)inserted, so there is no need to create it.
|
||||
continue;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue