refactor: use constexpr lookup tables in gin helper (#38818)

* feat: add gin_helper::FromV8WithLookup()

feat: add gin_helper::FromV8WithLowerLookup()

* refactor: use constexpr lookup table in gin Converters
This commit is contained in:
Charles Kerr 2023-06-19 03:33:09 -05:00 committed by GitHub
parent 41ab5f327f
commit 97132ece33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 255 additions and 400 deletions

View file

@ -8,12 +8,14 @@
#include <string>
#include <vector>
#include "base/containers/fixed_flat_map.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "gin/converter.h"
#include "gin/data_object_builder.h"
#include "shell/common/gin_converters/gfx_converter.h"
#include "shell/common/gin_converters/gurl_converter.h"
#include "shell/common/gin_converters/std_converter.h"
#include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/keyboard_util.h"
@ -130,86 +132,77 @@ struct Converter<blink::WebMouseEvent::Button> {
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
blink::WebMouseEvent::Button* out) {
std::string button = base::ToLowerASCII(gin::V8ToString(isolate, val));
if (button == "left")
*out = blink::WebMouseEvent::Button::kLeft;
else if (button == "middle")
*out = blink::WebMouseEvent::Button::kMiddle;
else if (button == "right")
*out = blink::WebMouseEvent::Button::kRight;
else
return false;
return true;
using Val = blink::WebMouseEvent::Button;
static constexpr auto Lookup =
base::MakeFixedFlatMapSorted<base::StringPiece, Val>({
{"left", Val::kLeft},
{"middle", Val::kMiddle},
{"right", Val::kRight},
});
return FromV8WithLowerLookup(isolate, val, Lookup, out);
}
};
// clang-format off
// these are the modifier names we both accept and return
static constexpr auto Modifiers =
base::MakeFixedFlatMapSorted<base::StringPiece, blink::WebInputEvent::Modifiers>({
{"alt", blink::WebInputEvent::Modifiers::kAltKey},
{"capslock", blink::WebInputEvent::Modifiers::kCapsLockOn},
{"control", blink::WebInputEvent::Modifiers::kControlKey},
{"isautorepeat", blink::WebInputEvent::Modifiers::kIsAutoRepeat},
{"iskeypad", blink::WebInputEvent::Modifiers::kIsKeyPad},
{"left", blink::WebInputEvent::Modifiers::kIsLeft},
{"leftbuttondown", blink::WebInputEvent::Modifiers::kLeftButtonDown},
{"meta", blink::WebInputEvent::Modifiers::kMetaKey},
{"middlebuttondown", blink::WebInputEvent::Modifiers::kMiddleButtonDown},
{"numlock", blink::WebInputEvent::Modifiers::kNumLockOn},
{"right", blink::WebInputEvent::Modifiers::kIsRight},
{"rightbuttondown", blink::WebInputEvent::Modifiers::kRightButtonDown},
{"shift", blink::WebInputEvent::Modifiers::kShiftKey},
// TODO(nornagon): the rest of the modifiers
});
// these are the modifier names we accept but do not return
static constexpr auto ModifierAliases =
base::MakeFixedFlatMapSorted<base::StringPiece, blink::WebInputEvent::Modifiers>({
{"cmd", blink::WebInputEvent::Modifiers::kMetaKey},
{"command", blink::WebInputEvent::Modifiers::kMetaKey},
{"ctrl", blink::WebInputEvent::Modifiers::kControlKey},
});
static constexpr auto ReferrerPolicies =
base::MakeFixedFlatMapSorted<base::StringPiece, network::mojom::ReferrerPolicy>({
{"default", network::mojom::ReferrerPolicy::kDefault},
{"no-referrer", network::mojom::ReferrerPolicy::kNever},
{"no-referrer-when-downgrade", network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade},
{"origin", network::mojom::ReferrerPolicy::kOrigin},
{"same-origin", network::mojom::ReferrerPolicy::kSameOrigin},
{"strict-origin", network::mojom::ReferrerPolicy::kStrictOrigin},
{"strict-origin-when-cross-origin", network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin},
{"unsafe-url", network::mojom::ReferrerPolicy::kAlways},
});
// clang-format on
template <>
struct Converter<blink::WebInputEvent::Modifiers> {
static bool FromV8(v8::Isolate* isolate,
v8::Handle<v8::Value> val,
blink::WebInputEvent::Modifiers* out) {
std::string modifier = base::ToLowerASCII(gin::V8ToString(isolate, val));
if (modifier == "shift")
*out = blink::WebInputEvent::Modifiers::kShiftKey;
else if (modifier == "control" || modifier == "ctrl")
*out = blink::WebInputEvent::Modifiers::kControlKey;
else if (modifier == "alt")
*out = blink::WebInputEvent::Modifiers::kAltKey;
else if (modifier == "meta" || modifier == "command" || modifier == "cmd")
*out = blink::WebInputEvent::Modifiers::kMetaKey;
else if (modifier == "iskeypad")
*out = blink::WebInputEvent::Modifiers::kIsKeyPad;
else if (modifier == "isautorepeat")
*out = blink::WebInputEvent::Modifiers::kIsAutoRepeat;
else if (modifier == "leftbuttondown")
*out = blink::WebInputEvent::Modifiers::kLeftButtonDown;
else if (modifier == "middlebuttondown")
*out = blink::WebInputEvent::Modifiers::kMiddleButtonDown;
else if (modifier == "rightbuttondown")
*out = blink::WebInputEvent::Modifiers::kRightButtonDown;
else if (modifier == "capslock")
*out = blink::WebInputEvent::Modifiers::kCapsLockOn;
else if (modifier == "numlock")
*out = blink::WebInputEvent::Modifiers::kNumLockOn;
else if (modifier == "left")
*out = blink::WebInputEvent::Modifiers::kIsLeft;
else if (modifier == "right")
*out = blink::WebInputEvent::Modifiers::kIsRight;
// TODO(nornagon): the rest of the modifiers
return true;
return FromV8WithLowerLookup(isolate, val, Modifiers, out) ||
FromV8WithLowerLookup(isolate, val, ModifierAliases, out);
}
};
std::vector<base::StringPiece> ModifiersToArray(int modifiers) {
using Modifiers = blink::WebInputEvent::Modifiers;
std::vector<base::StringPiece> modifier_strings;
if (modifiers & Modifiers::kShiftKey)
modifier_strings.push_back("shift");
if (modifiers & Modifiers::kControlKey)
modifier_strings.push_back("control");
if (modifiers & Modifiers::kAltKey)
modifier_strings.push_back("alt");
if (modifiers & Modifiers::kMetaKey)
modifier_strings.push_back("meta");
if (modifiers & Modifiers::kIsKeyPad)
modifier_strings.push_back("iskeypad");
if (modifiers & Modifiers::kIsAutoRepeat)
modifier_strings.push_back("isautorepeat");
if (modifiers & Modifiers::kLeftButtonDown)
modifier_strings.push_back("leftbuttondown");
if (modifiers & Modifiers::kMiddleButtonDown)
modifier_strings.push_back("middlebuttondown");
if (modifiers & Modifiers::kRightButtonDown)
modifier_strings.push_back("rightbuttondown");
if (modifiers & Modifiers::kCapsLockOn)
modifier_strings.push_back("capslock");
if (modifiers & Modifiers::kNumLockOn)
modifier_strings.push_back("numlock");
if (modifiers & Modifiers::kIsLeft)
modifier_strings.push_back("left");
if (modifiers & Modifiers::kIsRight)
modifier_strings.push_back("right");
// TODO(nornagon): the rest of the modifiers
for (const auto& [name, mask] : Modifiers)
if (mask & modifiers)
modifier_strings.emplace_back(name);
return modifier_strings;
}
@ -553,26 +546,11 @@ v8::Local<v8::Value> Converter<blink::WebCacheResourceTypeStats>::ToV8(
v8::Local<v8::Value> Converter<network::mojom::ReferrerPolicy>::ToV8(
v8::Isolate* isolate,
const network::mojom::ReferrerPolicy& in) {
switch (in) {
case network::mojom::ReferrerPolicy::kDefault:
return StringToV8(isolate, "default");
case network::mojom::ReferrerPolicy::kAlways:
return StringToV8(isolate, "unsafe-url");
case network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade:
return StringToV8(isolate, "no-referrer-when-downgrade");
case network::mojom::ReferrerPolicy::kNever:
return StringToV8(isolate, "no-referrer");
case network::mojom::ReferrerPolicy::kOrigin:
return StringToV8(isolate, "origin");
case network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin:
return StringToV8(isolate, "strict-origin-when-cross-origin");
case network::mojom::ReferrerPolicy::kSameOrigin:
return StringToV8(isolate, "same-origin");
case network::mojom::ReferrerPolicy::kStrictOrigin:
return StringToV8(isolate, "strict-origin");
default:
return StringToV8(isolate, "no-referrer");
}
for (const auto& [name, val] : ReferrerPolicies)
if (val == in)
return StringToV8(isolate, name);
return StringToV8(isolate, "no-referrer");
}
// static
@ -580,26 +558,7 @@ bool Converter<network::mojom::ReferrerPolicy>::FromV8(
v8::Isolate* isolate,
v8::Handle<v8::Value> val,
network::mojom::ReferrerPolicy* out) {
std::string policy = base::ToLowerASCII(gin::V8ToString(isolate, val));
if (policy == "default")
*out = network::mojom::ReferrerPolicy::kDefault;
else if (policy == "unsafe-url")
*out = network::mojom::ReferrerPolicy::kAlways;
else if (policy == "no-referrer-when-downgrade")
*out = network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade;
else if (policy == "no-referrer")
*out = network::mojom::ReferrerPolicy::kNever;
else if (policy == "origin")
*out = network::mojom::ReferrerPolicy::kOrigin;
else if (policy == "strict-origin-when-cross-origin")
*out = network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin;
else if (policy == "same-origin")
*out = network::mojom::ReferrerPolicy::kSameOrigin;
else if (policy == "strict-origin")
*out = network::mojom::ReferrerPolicy::kStrictOrigin;
else
return false;
return true;
return FromV8WithLowerLookup(isolate, val, ReferrerPolicies, out);
}
// static

View file

@ -689,57 +689,28 @@ v8::Local<v8::Value> Converter<net::IPEndPoint>::ToV8(
bool Converter<net::DnsQueryType>::FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
net::DnsQueryType* out) {
std::string query_type;
if (!ConvertFromV8(isolate, val, &query_type))
return false;
if (query_type == "A") {
*out = net::DnsQueryType::A;
return true;
}
if (query_type == "AAAA") {
*out = net::DnsQueryType::AAAA;
return true;
}
return false;
static constexpr auto Lookup =
base::MakeFixedFlatMapSorted<base::StringPiece, net::DnsQueryType>({
{"A", net::DnsQueryType::A},
{"AAAA", net::DnsQueryType::AAAA},
});
return FromV8WithLookup(isolate, val, Lookup, out);
}
// static
bool Converter<net::HostResolverSource>::FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
net::HostResolverSource* out) {
std::string query_type;
if (!ConvertFromV8(isolate, val, &query_type))
return false;
if (query_type == "any") {
*out = net::HostResolverSource::ANY;
return true;
}
if (query_type == "system") {
*out = net::HostResolverSource::SYSTEM;
return true;
}
if (query_type == "dns") {
*out = net::HostResolverSource::DNS;
return true;
}
if (query_type == "mdns") {
*out = net::HostResolverSource::MULTICAST_DNS;
return true;
}
if (query_type == "localOnly") {
*out = net::HostResolverSource::LOCAL_ONLY;
return true;
}
return false;
using Val = net::HostResolverSource;
static constexpr auto Lookup =
base::MakeFixedFlatMapSorted<base::StringPiece, Val>({
{"any", Val::ANY},
{"dns", Val::DNS},
{"localOnly", Val::LOCAL_ONLY},
{"mdns", Val::MULTICAST_DNS},
{"system", Val::SYSTEM},
});
return FromV8WithLookup(isolate, val, Lookup, out);
}
// static
@ -747,26 +718,14 @@ bool Converter<network::mojom::ResolveHostParameters::CacheUsage>::FromV8(
v8::Isolate* isolate,
v8::Local<v8::Value> val,
network::mojom::ResolveHostParameters::CacheUsage* out) {
std::string query_type;
if (!ConvertFromV8(isolate, val, &query_type))
return false;
if (query_type == "allowed") {
*out = network::mojom::ResolveHostParameters::CacheUsage::ALLOWED;
return true;
}
if (query_type == "staleAllowed") {
*out = network::mojom::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
return true;
}
if (query_type == "disallowed") {
*out = network::mojom::ResolveHostParameters::CacheUsage::DISALLOWED;
return true;
}
return false;
using Val = network::mojom::ResolveHostParameters::CacheUsage;
static constexpr auto Lookup =
base::MakeFixedFlatMapSorted<base::StringPiece, Val>({
{"allowed", Val::ALLOWED},
{"disallowed", Val::DISALLOWED},
{"staleAllowed", Val::STALE_ALLOWED},
});
return FromV8WithLookup(isolate, val, Lookup, out);
}
// static
@ -774,21 +733,13 @@ bool Converter<network::mojom::SecureDnsPolicy>::FromV8(
v8::Isolate* isolate,
v8::Local<v8::Value> val,
network::mojom::SecureDnsPolicy* out) {
std::string query_type;
if (!ConvertFromV8(isolate, val, &query_type))
return false;
if (query_type == "allow") {
*out = network::mojom::SecureDnsPolicy::ALLOW;
return true;
}
if (query_type == "disable") {
*out = network::mojom::SecureDnsPolicy::DISABLE;
return true;
}
return false;
using Val = network::mojom::SecureDnsPolicy;
static constexpr auto Lookup =
base::MakeFixedFlatMapSorted<base::StringPiece, Val>({
{"allow", Val::ALLOW},
{"disable", Val::DISABLE},
});
return FromV8WithLookup(isolate, val, Lookup, out);
}
// static

View file

@ -5,12 +5,16 @@
#ifndef ELECTRON_SHELL_COMMON_GIN_CONVERTERS_STD_CONVERTER_H_
#define ELECTRON_SHELL_COMMON_GIN_CONVERTERS_STD_CONVERTER_H_
#include <cstddef>
#include <functional>
#include <map>
#include <set>
#include <type_traits>
#include <utility>
#include "gin/converter.h"
#include "base/strings/string_util.h"
#if BUILDFLAG(IS_WIN)
#include "base/strings/string_util_win.h"
#endif
@ -210,6 +214,61 @@ struct Converter<std::wstring> {
};
#endif
namespace detail {
// Get a key from `key_val` and check `lookup` for a matching entry.
// Return true iff a match is found, and set `*out` to the entry's value.
template <typename KeyType, typename Out, typename Map>
bool FromV8WithLookup(v8::Isolate* isolate,
v8::Local<v8::Value> key_val,
const Map& table,
Out* out,
std::function<void(KeyType&)> key_transform = {}) {
static_assert(std::is_same_v<typename Map::mapped_type, Out>);
auto key = KeyType{};
if (!ConvertFromV8(isolate, key_val, &key))
return false;
if (key_transform)
key_transform(key);
if (const auto* iter = table.find(key); iter != table.end()) {
*out = iter->second;
return true;
}
return false;
}
} // namespace detail
// Convert `key_val to a string key and check `lookup` for a matching entry.
// Return true iff a match is found, and set `*out` to the entry's value.
template <typename Out, typename Map>
bool FromV8WithLookup(v8::Isolate* isolate,
v8::Local<v8::Value> key_val,
const Map& table,
Out* out) {
return detail::FromV8WithLookup<std::string>(isolate, key_val, table, out);
}
// Convert `key_val` to a lowercase string key and check `lookup` for a matching
// entry. Return true iff a match is found, and set `*out` to the entry's value.
template <typename Out, typename Map>
bool FromV8WithLowerLookup(v8::Isolate* isolate,
v8::Local<v8::Value> key_val,
const Map& table,
Out* out) {
static constexpr auto to_lower_ascii_inplace = [](std::string& str) {
for (auto& ch : str)
ch = base::ToLowerASCII(ch);
};
return detail::FromV8WithLookup<std::string>(isolate, key_val, table, out,
to_lower_ascii_inplace);
}
} // namespace gin
#endif // ELECTRON_SHELL_COMMON_GIN_CONVERTERS_STD_CONVERTER_H_