mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add CSSValueVariant and parseCSSValue()
Summary: This adds: 1. `CSSValueVariant`: A union-y type, mapping to a collection of CSS basic data types, and a set of allowed keywords. The aim here is to more closely model the data types after the CSS spec, to allow RN to store them correctly, while not taking up too much space. These types will form the foundation of Yoga prop storage (and probably some other props down the line), so compactness is a priority. 2. `parseCSSValue()`: This uses the previously added Tokenizer, along with parsing rules, to be able to parse a single component value, into a literal keyword, `<length>`, `<length-percentage>`, `<percentage>`, or `<number>`. This will be wired to the props parsing infrastructure. See D53461299 for an example of what this will look like in props storage. Changelog: [Internal] Reviewed By: rozele Differential Revision: D53342595 fbshipit-source-id: 3f00dfd7c0ead3dbef4605a61e9859cf69945fe5
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f63efaf920
commit
7e47df0a41
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and 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 <cstdint>
|
||||
#include <locale>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include <react/utils/fnv1a.h>
|
||||
#include <react/utils/to_underlying.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/**
|
||||
* One of any predefined CSS keywords.
|
||||
* https://www.w3.org/TR/css-values-3/#keywords
|
||||
*/
|
||||
enum class CSSKeyword : uint8_t {
|
||||
Absolute,
|
||||
Auto,
|
||||
Baseline,
|
||||
Center,
|
||||
Column,
|
||||
ColumnReverse,
|
||||
Flex,
|
||||
FlexEnd,
|
||||
FlexStart,
|
||||
Hidden,
|
||||
Inherit,
|
||||
Initial,
|
||||
Inline,
|
||||
Ltr,
|
||||
None,
|
||||
NoWrap,
|
||||
Relative,
|
||||
Row,
|
||||
RowReverse,
|
||||
Rtl,
|
||||
Scroll,
|
||||
SpaceAround,
|
||||
SpaceBetween,
|
||||
SpaceEvenly,
|
||||
Static,
|
||||
Stretch,
|
||||
Unset,
|
||||
Visible,
|
||||
Wrap,
|
||||
WrapReverse,
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a set of CSS keywords, including CSS-wide keywords.
|
||||
*/
|
||||
template <typename T>
|
||||
concept CSSKeywordSet = std::is_enum_v<T> && requires {
|
||||
{ T::Inherit } -> std::same_as<T>;
|
||||
{ T::Initial } -> std::same_as<T>;
|
||||
{ T::Unset } -> std::same_as<T>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines a new set of CSS keywords
|
||||
*/
|
||||
#define CSS_DEFINE_KEYWORD_SET(name, ...) \
|
||||
enum class name : uint8_t { \
|
||||
Inherit = to_underlying(CSSKeyword::Inherit), \
|
||||
Initial = to_underlying(CSSKeyword::Initial), \
|
||||
Unset = to_underlying(CSSKeyword::Unset), \
|
||||
__VA_ARGS__ \
|
||||
};
|
||||
|
||||
/**
|
||||
* CSS-wide keywords.
|
||||
* https://www.w3.org/TR/css-values-4/#common-keywords
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(CSSWideKeyword)
|
||||
|
||||
/**
|
||||
* CSS-wide keywords along with a context-dependent "auto" keyword.
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(CSSAutoKeyword, Auto = to_underlying(CSSKeyword::Auto))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "align-content" property.
|
||||
* https://www.w3.org/TR/css-flexbox-1/#align-content-property
|
||||
* https://www.w3.org/TR/css-align-3/#align-justify-content
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSAlignContent,
|
||||
Center = to_underlying(CSSKeyword::Center),
|
||||
FlexEnd = to_underlying(CSSKeyword::FlexEnd),
|
||||
FlexStart = to_underlying(CSSKeyword::FlexStart),
|
||||
SpaceAround = to_underlying(CSSKeyword::SpaceAround),
|
||||
SpaceBetween = to_underlying(CSSKeyword::SpaceBetween),
|
||||
SpaceEvenly = to_underlying(CSSKeyword::SpaceEvenly),
|
||||
Stretch = to_underlying(CSSKeyword::Stretch))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "align-items" property.
|
||||
* https://www.w3.org/TR/css-flexbox-1/#align-items-property
|
||||
* https://www.w3.org/TR/css-align-3/#align-items-property
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSAlignItems,
|
||||
Baseline = to_underlying(CSSKeyword::Baseline),
|
||||
Center = to_underlying(CSSKeyword::Center),
|
||||
FlexEnd = to_underlying(CSSKeyword::FlexEnd),
|
||||
FlexStart = to_underlying(CSSKeyword::FlexStart),
|
||||
Stretch = to_underlying(CSSKeyword::Stretch))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "align-items" property.
|
||||
* https://www.w3.org/TR/css-flexbox-1/#align-self-property
|
||||
* https://www.w3.org/TR/css-align-3/#align-self-property
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSAlignSelf,
|
||||
Auto = to_underlying(CSSKeyword::Auto),
|
||||
Baseline = to_underlying(CSSKeyword::Baseline),
|
||||
Center = to_underlying(CSSKeyword::Center),
|
||||
FlexEnd = to_underlying(CSSKeyword::FlexEnd),
|
||||
FlexStart = to_underlying(CSSKeyword::FlexStart),
|
||||
Stretch = to_underlying(CSSKeyword::Stretch))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "direction" property.
|
||||
* https://www.w3.org/TR/css-writing-modes-3/#direction
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSDirection,
|
||||
Ltr = to_underlying(CSSKeyword::Ltr),
|
||||
Rtl = to_underlying(CSSKeyword::Rtl))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "display" property.
|
||||
* https://www.w3.org/TR/css-display-3/#display-type
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSDisplay,
|
||||
Flex = to_underlying(CSSKeyword::Flex),
|
||||
Inline = to_underlying(CSSKeyword::Inline),
|
||||
None = to_underlying(CSSKeyword::None))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "flex-direction" property.
|
||||
* https://www.w3.org/TR/css-flexbox-1/#flex-direction-property
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSFlexDirection,
|
||||
Column = to_underlying(CSSKeyword::Column),
|
||||
ColumnReverse = to_underlying(CSSKeyword::ColumnReverse),
|
||||
Row = to_underlying(CSSKeyword::Row),
|
||||
RowReverse = to_underlying(CSSKeyword::RowReverse))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "flex-wrap" property.
|
||||
* https://www.w3.org/TR/css-flexbox-1/#flex-wrap-property
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSFlexWrap,
|
||||
NoWrap = to_underlying(CSSKeyword::NoWrap),
|
||||
Wrap = to_underlying(CSSKeyword::Wrap),
|
||||
WrapReverse = to_underlying(CSSKeyword::WrapReverse))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "justify-content" property.
|
||||
* https://www.w3.org/TR/css-flexbox-1/#justify-content-property
|
||||
* https://www.w3.org/TR/css-align-3/#align-justify-content
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSJustifyContent,
|
||||
Center = to_underlying(CSSKeyword::Center),
|
||||
FlexEnd = to_underlying(CSSKeyword::FlexEnd),
|
||||
FlexStart = to_underlying(CSSKeyword::FlexStart),
|
||||
SpaceAround = to_underlying(CSSKeyword::SpaceAround),
|
||||
SpaceBetween = to_underlying(CSSKeyword::SpaceBetween),
|
||||
SpaceEvenly = to_underlying(CSSKeyword::SpaceEvenly))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "overflow" property.
|
||||
* https://www.w3.org/TR/css-overflow-3/#overflow-control
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSOverflow,
|
||||
Hidden = to_underlying(CSSKeyword::Hidden),
|
||||
Scroll = to_underlying(CSSKeyword::Scroll),
|
||||
Visible = to_underlying(CSSKeyword::Visible))
|
||||
|
||||
/**
|
||||
* Keywords for the CSS "position" property.
|
||||
* https://www.w3.org/TR/css-position-3/#position-property
|
||||
*/
|
||||
CSS_DEFINE_KEYWORD_SET(
|
||||
CSSPosition,
|
||||
Absolute = to_underlying(CSSKeyword::Absolute),
|
||||
Relative = to_underlying(CSSKeyword::Relative),
|
||||
Static = to_underlying(CSSKeyword::Static))
|
||||
|
||||
/**
|
||||
* Compare two keywords of any representation
|
||||
*/
|
||||
constexpr bool operator==(CSSKeywordSet auto lhs, CSSKeywordSet auto rhs) {
|
||||
return to_underlying(lhs) == to_underlying(rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a concept for whether an enum has a given member.
|
||||
*/
|
||||
#define CSS_DEFINE_KEYWORD_CONEPTS(name) \
|
||||
namespace detail { \
|
||||
template <typename T> \
|
||||
concept has##name = (CSSKeywordSet<T> && requires() { T::name; }); \
|
||||
}
|
||||
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Absolute)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Auto)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Baseline)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Center)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Column)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(ColumnReverse)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Flex)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(FlexEnd)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(FlexStart)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Hidden)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Inherit)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Initial)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Inline)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Ltr)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(None)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(NoWrap)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Relative)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Row)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(RowReverse)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Rtl)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Scroll)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(SpaceAround)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(SpaceBetween)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(SpaceEvenly)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Static)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Stretch)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Unset)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Visible)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(Wrap)
|
||||
CSS_DEFINE_KEYWORD_CONEPTS(WrapReverse)
|
||||
|
||||
/**
|
||||
* Parses an ident token, case-insensitive, into a keyword.
|
||||
*
|
||||
* Returns KeywordT::Unset if the ident does not match any entries
|
||||
* in the keyword-set, or CSS-wide keywords.
|
||||
*/
|
||||
template <CSSKeywordSet KeywordT>
|
||||
constexpr std::optional<KeywordT> parseCSSKeyword(std::string_view ident) {
|
||||
struct LowerCaseTransform {
|
||||
char operator()(char c) const {
|
||||
return static_cast<char>(tolower(c));
|
||||
}
|
||||
};
|
||||
|
||||
switch (fnv1a<LowerCaseTransform>(ident)) {
|
||||
case fnv1a("absolute"):
|
||||
if constexpr (detail::hasAbsolute<KeywordT>) {
|
||||
return KeywordT::Absolute;
|
||||
}
|
||||
break;
|
||||
case fnv1a("auto"):
|
||||
if constexpr (detail::hasAuto<KeywordT>) {
|
||||
return KeywordT::Auto;
|
||||
}
|
||||
break;
|
||||
case fnv1a("baseline"):
|
||||
if constexpr (detail::hasBaseline<KeywordT>) {
|
||||
return KeywordT::Baseline;
|
||||
}
|
||||
break;
|
||||
case fnv1a("center"):
|
||||
if constexpr (detail::hasCenter<KeywordT>) {
|
||||
return KeywordT::Center;
|
||||
}
|
||||
break;
|
||||
case fnv1a("column"):
|
||||
if constexpr (detail::hasColumn<KeywordT>) {
|
||||
return KeywordT::Column;
|
||||
}
|
||||
break;
|
||||
case fnv1a("column-reverse"):
|
||||
if constexpr (detail::hasColumnReverse<KeywordT>) {
|
||||
return KeywordT::ColumnReverse;
|
||||
}
|
||||
break;
|
||||
case fnv1a("flex"):
|
||||
if constexpr (detail::hasFlex<KeywordT>) {
|
||||
return KeywordT::Flex;
|
||||
}
|
||||
break;
|
||||
case fnv1a("flex-end"):
|
||||
if constexpr (detail::hasFlexEnd<KeywordT>) {
|
||||
return KeywordT::FlexEnd;
|
||||
}
|
||||
break;
|
||||
case fnv1a("flex-start"):
|
||||
if constexpr (detail::hasFlexStart<KeywordT>) {
|
||||
return KeywordT::FlexStart;
|
||||
}
|
||||
break;
|
||||
case fnv1a("hidden"):
|
||||
if constexpr (detail::hasHidden<KeywordT>) {
|
||||
return KeywordT::Hidden;
|
||||
}
|
||||
break;
|
||||
case fnv1a("inherit"):
|
||||
if constexpr (detail::hasInherit<KeywordT>) {
|
||||
return KeywordT::Inherit;
|
||||
}
|
||||
break;
|
||||
case fnv1a("inline"):
|
||||
if constexpr (detail::hasInline<KeywordT>) {
|
||||
return KeywordT::Inline;
|
||||
}
|
||||
break;
|
||||
case fnv1a("ltr"):
|
||||
if constexpr (detail::hasLtr<KeywordT>) {
|
||||
return KeywordT::Ltr;
|
||||
}
|
||||
break;
|
||||
case fnv1a("none"):
|
||||
if constexpr (detail::hasNone<KeywordT>) {
|
||||
return KeywordT::None;
|
||||
}
|
||||
break;
|
||||
case fnv1a("no-wrap"):
|
||||
if constexpr (detail::hasNoWrap<KeywordT>) {
|
||||
return KeywordT::NoWrap;
|
||||
}
|
||||
break;
|
||||
case fnv1a("relative"):
|
||||
if constexpr (detail::hasRelative<KeywordT>) {
|
||||
return KeywordT::Relative;
|
||||
}
|
||||
break;
|
||||
case fnv1a("row"):
|
||||
if constexpr (detail::hasRow<KeywordT>) {
|
||||
return KeywordT::Row;
|
||||
}
|
||||
break;
|
||||
case fnv1a("row-reverse"):
|
||||
if constexpr (detail::hasRowReverse<KeywordT>) {
|
||||
return KeywordT::RowReverse;
|
||||
}
|
||||
break;
|
||||
case fnv1a("rtl"):
|
||||
if constexpr (detail::hasRtl<KeywordT>) {
|
||||
return KeywordT::Rtl;
|
||||
}
|
||||
break;
|
||||
case fnv1a("space-between"):
|
||||
if constexpr (detail::hasSpaceBetween<KeywordT>) {
|
||||
return KeywordT::SpaceBetween;
|
||||
}
|
||||
break;
|
||||
case fnv1a("space-around"):
|
||||
if constexpr (detail::hasSpaceAround<KeywordT>) {
|
||||
return KeywordT::SpaceAround;
|
||||
}
|
||||
break;
|
||||
case fnv1a("space-evenly"):
|
||||
if constexpr (detail::hasSpaceEvenly<KeywordT>) {
|
||||
return KeywordT::SpaceEvenly;
|
||||
}
|
||||
break;
|
||||
case fnv1a("scroll"):
|
||||
if constexpr (detail::hasScroll<KeywordT>) {
|
||||
return KeywordT::Scroll;
|
||||
}
|
||||
break;
|
||||
case fnv1a("static"):
|
||||
if constexpr (detail::hasStatic<KeywordT>) {
|
||||
return KeywordT::Static;
|
||||
}
|
||||
break;
|
||||
case fnv1a("stretch"):
|
||||
if constexpr (detail::hasStretch<KeywordT>) {
|
||||
return KeywordT::Stretch;
|
||||
}
|
||||
break;
|
||||
case fnv1a("unset"):
|
||||
if constexpr (detail::hasUnset<KeywordT>) {
|
||||
return KeywordT::Unset;
|
||||
}
|
||||
break;
|
||||
case fnv1a("visible"):
|
||||
if constexpr (detail::hasVisible<KeywordT>) {
|
||||
return KeywordT::Visible;
|
||||
}
|
||||
break;
|
||||
case fnv1a("wrap"):
|
||||
if constexpr (detail::hasWrap<KeywordT>) {
|
||||
return KeywordT::Wrap;
|
||||
}
|
||||
break;
|
||||
case fnv1a("wrap-reverse"):
|
||||
if constexpr (detail::hasWrapReverse<KeywordT>) {
|
||||
return KeywordT::WrapReverse;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and 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 <cstdint>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include <react/utils/fnv1a.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/**
|
||||
* Unit for the CSS <length> type.
|
||||
* https://www.w3.org/TR/css-values-4/#lengths
|
||||
*/
|
||||
enum class CSSLengthUnit : uint8_t {
|
||||
Cap,
|
||||
Ch,
|
||||
Cm,
|
||||
Dvb,
|
||||
Dvh,
|
||||
Dvi,
|
||||
Dvmax,
|
||||
Dvmin,
|
||||
Dvw,
|
||||
Em,
|
||||
Ex,
|
||||
Ic,
|
||||
In,
|
||||
Lh,
|
||||
Lvb,
|
||||
Lvh,
|
||||
Lvi,
|
||||
Lvmax,
|
||||
Lvmin,
|
||||
Lvw,
|
||||
Mm,
|
||||
Pc,
|
||||
Pt,
|
||||
Px,
|
||||
Q,
|
||||
Rcap,
|
||||
Rch,
|
||||
Rem,
|
||||
Rex,
|
||||
Ric,
|
||||
Rlh,
|
||||
Svb,
|
||||
Svh,
|
||||
Svi,
|
||||
Svmax,
|
||||
Svmin,
|
||||
Svw,
|
||||
Vb,
|
||||
Vh,
|
||||
Vi,
|
||||
Vmax,
|
||||
Vmin,
|
||||
Vw,
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses a unit from a dimension token into a CSS length unit.
|
||||
*/
|
||||
constexpr std::optional<CSSLengthUnit> parseCSSLengthUnit(
|
||||
std::string_view unit) {
|
||||
switch (fnv1a(unit)) {
|
||||
case fnv1a("cap"):
|
||||
return CSSLengthUnit::Cap;
|
||||
case fnv1a("ch"):
|
||||
return CSSLengthUnit::Ch;
|
||||
case fnv1a("cm"):
|
||||
return CSSLengthUnit::Cm;
|
||||
case fnv1a("dvb"):
|
||||
return CSSLengthUnit::Dvb;
|
||||
case fnv1a("dvh"):
|
||||
return CSSLengthUnit::Dvh;
|
||||
case fnv1a("dvi"):
|
||||
return CSSLengthUnit::Dvi;
|
||||
case fnv1a("dvmax"):
|
||||
return CSSLengthUnit::Dvmax;
|
||||
case fnv1a("dvmin"):
|
||||
return CSSLengthUnit::Dvmin;
|
||||
case fnv1a("dvw"):
|
||||
return CSSLengthUnit::Dvw;
|
||||
case fnv1a("em"):
|
||||
return CSSLengthUnit::Em;
|
||||
case fnv1a("ex"):
|
||||
return CSSLengthUnit::Ex;
|
||||
case fnv1a("ic"):
|
||||
return CSSLengthUnit::Ic;
|
||||
case fnv1a("in"):
|
||||
return CSSLengthUnit::In;
|
||||
case fnv1a("lh"):
|
||||
return CSSLengthUnit::Lh;
|
||||
case fnv1a("lvb"):
|
||||
return CSSLengthUnit::Lvb;
|
||||
case fnv1a("lvh"):
|
||||
return CSSLengthUnit::Lvh;
|
||||
case fnv1a("lvi"):
|
||||
return CSSLengthUnit::Lvi;
|
||||
case fnv1a("lvmax"):
|
||||
return CSSLengthUnit::Lvmax;
|
||||
case fnv1a("lvmin"):
|
||||
return CSSLengthUnit::Lvmin;
|
||||
case fnv1a("lvw"):
|
||||
return CSSLengthUnit::Lvw;
|
||||
case fnv1a("mm"):
|
||||
return CSSLengthUnit::Mm;
|
||||
case fnv1a("pc"):
|
||||
return CSSLengthUnit::Pc;
|
||||
case fnv1a("pt"):
|
||||
return CSSLengthUnit::Pt;
|
||||
case fnv1a("px"):
|
||||
return CSSLengthUnit::Px;
|
||||
case fnv1a("q"):
|
||||
return CSSLengthUnit::Q;
|
||||
case fnv1a("rcap"):
|
||||
return CSSLengthUnit::Rcap;
|
||||
case fnv1a("rch"):
|
||||
return CSSLengthUnit::Rch;
|
||||
case fnv1a("rem"):
|
||||
return CSSLengthUnit::Rem;
|
||||
case fnv1a("rex"):
|
||||
return CSSLengthUnit::Rex;
|
||||
case fnv1a("ric"):
|
||||
return CSSLengthUnit::Ric;
|
||||
case fnv1a("rlh"):
|
||||
return CSSLengthUnit::Rlh;
|
||||
case fnv1a("svb"):
|
||||
return CSSLengthUnit::Svb;
|
||||
case fnv1a("svh"):
|
||||
return CSSLengthUnit::Svh;
|
||||
case fnv1a("svi"):
|
||||
return CSSLengthUnit::Svi;
|
||||
case fnv1a("svmax"):
|
||||
return CSSLengthUnit::Svmax;
|
||||
case fnv1a("svmin"):
|
||||
return CSSLengthUnit::Svmin;
|
||||
case fnv1a("svw"):
|
||||
return CSSLengthUnit::Svw;
|
||||
case fnv1a("vb"):
|
||||
return CSSLengthUnit::Vb;
|
||||
case fnv1a("vh"):
|
||||
return CSSLengthUnit::Vh;
|
||||
case fnv1a("vi"):
|
||||
return CSSLengthUnit::Vi;
|
||||
case fnv1a("vmax"):
|
||||
return CSSLengthUnit::Vmax;
|
||||
case fnv1a("vmin"):
|
||||
return CSSLengthUnit::Vmin;
|
||||
case fnv1a("vw"):
|
||||
return CSSLengthUnit::Vw;
|
||||
default:
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and 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 <optional>
|
||||
|
||||
#include <react/renderer/css/CSSKeywords.h>
|
||||
#include <react/renderer/css/CSSLengthUnit.h>
|
||||
#include <react/renderer/css/CSSTokenizer.h>
|
||||
#include <react/renderer/css/CSSValue.h>
|
||||
#include <react/utils/PackTraits.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
namespace detail {
|
||||
template <CSSKeywordSet KeywordT, CSSBasicDataType... Rest>
|
||||
CSSValueVariant<KeywordT, Rest...> consumeComponentValue(
|
||||
const CSSToken& token) {
|
||||
using CSSValueT = CSSValueVariant<KeywordT, Rest...>;
|
||||
switch (token.type()) {
|
||||
case CSSTokenType::Ident:
|
||||
if (auto keyword = parseCSSKeyword<KeywordT>(token.stringValue())) {
|
||||
return CSSValueT::keyword(*keyword);
|
||||
}
|
||||
break;
|
||||
case CSSTokenType::Dimension:
|
||||
if constexpr (traits::containsType<CSSLength, Rest...>()) {
|
||||
if (auto unit = parseCSSLengthUnit(token.unit())) {
|
||||
return CSSValueT::length(token.numericValue(), *unit);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CSSTokenType::Percentage:
|
||||
if constexpr (traits::containsType<CSSPercentage, Rest...>()) {
|
||||
return CSSValueT::percentage(token.numericValue());
|
||||
}
|
||||
break;
|
||||
case CSSTokenType::Number:
|
||||
// For zero lengths the unit identifier is optional (i.e. can be
|
||||
// syntactically represented as the <number> 0). However, if a 0 could
|
||||
// be parsed as either a <number> or a <length> in a property (such as
|
||||
// line-height), it must parse as a <number>.
|
||||
// https://www.w3.org/TR/css-values-4/#lengths
|
||||
if constexpr (traits::containsType<CSSNumber, Rest...>()) {
|
||||
return CSSValueT::number(token.numericValue());
|
||||
} else if constexpr (traits::containsType<CSSLength, Rest...>()) {
|
||||
if (token.numericValue() == 0) {
|
||||
return CSSValueT::length(0, CSSLengthUnit::Px);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return CSSValueT{};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/*
|
||||
* Parse a single CSS component value as a keyword constrained to those
|
||||
* allowable by KeywordRepresentationT.
|
||||
* https://www.w3.org/TR/css-syntax-3/#parse-component-value
|
||||
*/
|
||||
template <CSSKeywordSet KeywordT, CSSBasicDataType... Rest>
|
||||
CSSValueVariant<KeywordT, Rest...> parseCSSValue(std::string_view css) {
|
||||
CSSTokenizer tokenizer(css);
|
||||
|
||||
auto token = tokenizer.next();
|
||||
while (token.type() == CSSTokenType::WhiteSpace) {
|
||||
token = tokenizer.next();
|
||||
}
|
||||
|
||||
auto value = detail::consumeComponentValue<KeywordT, Rest...>(token);
|
||||
|
||||
token = tokenizer.next();
|
||||
while (token.type() == CSSTokenType::WhiteSpace) {
|
||||
token = tokenizer.next();
|
||||
}
|
||||
if (token.type() == CSSTokenType::EndOfFile) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -141,7 +141,7 @@ CSSToken CSSTokenizer::consumeNumeric() {
|
||||
} else if (peek() == '%') {
|
||||
advance();
|
||||
consumeRunningValue();
|
||||
return {CSSTokenType::Percent, numberToken.numericValue()};
|
||||
return {CSSTokenType::Percentage, numberToken.numericValue()};
|
||||
} else {
|
||||
return numberToken;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ enum class CSSTokenType {
|
||||
EndOfFile,
|
||||
Ident,
|
||||
Number,
|
||||
Percent,
|
||||
Percentage,
|
||||
WhiteSpace,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and 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 <array>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include <react/renderer/css/CSSKeywords.h>
|
||||
#include <react/renderer/css/CSSLengthUnit.h>
|
||||
#include <react/utils/PackTraits.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/**
|
||||
* Represents a CSS component value type.
|
||||
* https://www.w3.org/TR/css-values-3/#component-types
|
||||
*/
|
||||
enum class CSSValueType : uint8_t {
|
||||
Keyword,
|
||||
Length,
|
||||
Number,
|
||||
Percentage,
|
||||
};
|
||||
|
||||
/**
|
||||
* Concrete representation for a CSS basic data type.
|
||||
* https://www.w3.org/TR/css-values-3/#component-types
|
||||
*/
|
||||
template <typename T>
|
||||
concept CSSBasicDataType = std::is_trivially_destructible_v<T> &&
|
||||
std::is_default_constructible_v<T> && requires() {
|
||||
sizeof(T);
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
/**
|
||||
* Representation of CSS <length> data type
|
||||
* https://www.w3.org/TR/css-values-3/#lengths
|
||||
*/
|
||||
struct CSSLength {
|
||||
float value{};
|
||||
CSSLengthUnit unit{CSSLengthUnit::Px};
|
||||
constexpr bool operator==(const CSSLength& rhs) const = default;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* Representation of CSS <percentage> data type
|
||||
* https://www.w3.org/TR/css-values-3/#percentages
|
||||
*/
|
||||
struct CSSPercentage {
|
||||
float value{};
|
||||
constexpr bool operator==(const CSSPercentage& rhs) const = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* Representation of CSS <number> data type
|
||||
* https://www.w3.org/TR/css-values-3/#numbers
|
||||
*/
|
||||
struct CSSNumber {
|
||||
float value{};
|
||||
constexpr bool operator==(const CSSNumber& rhs) const = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* CSSValueVariant represents a CSS component value:
|
||||
* https://www.w3.org/TR/css-values-3/#component-types
|
||||
*
|
||||
* A CSSValueVariant must be constrained to the set of possible CSS types it may
|
||||
* encounter. E.g. a dimension which accepts a CSS-wide keywords, "auto" or a
|
||||
* <length-percentage> would be modeled as
|
||||
* `CSSValueVariant<CSSAutoKeyord, CSSLength, CSSPercentage>`. This
|
||||
* allows for efficient storage, and customizing parsing based on the allowed
|
||||
* set of values.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
template <typename KeywordT, CSSBasicDataType... Rest>
|
||||
class CSSValueVariant {
|
||||
template <CSSValueType Type, CSSBasicDataType ValueT>
|
||||
constexpr ValueT getIf() const {
|
||||
if (type_ == Type) {
|
||||
return *std::launder(reinterpret_cast<const ValueT*>(data_.data()));
|
||||
} else {
|
||||
return ValueT{};
|
||||
}
|
||||
}
|
||||
|
||||
template <CSSBasicDataType ValueT>
|
||||
static constexpr bool canRepresent() {
|
||||
return traits::containsType<ValueT, KeywordT, Rest...>();
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr CSSValueVariant()
|
||||
: CSSValueVariant(CSSValueType::Keyword, KeywordT::Unset) {}
|
||||
|
||||
static constexpr CSSValueVariant keyword(KeywordT keyword) {
|
||||
return CSSValueVariant(CSSValueType::Keyword, KeywordT{keyword});
|
||||
}
|
||||
|
||||
static constexpr CSSValueVariant length(
|
||||
float value,
|
||||
CSSLengthUnit unit) requires(canRepresent<CSSLength>()) {
|
||||
return CSSValueVariant(CSSValueType::Length, CSSLength{value, unit});
|
||||
}
|
||||
|
||||
static constexpr CSSValueVariant number(float value) requires(
|
||||
canRepresent<CSSNumber>()) {
|
||||
return CSSValueVariant(CSSValueType::Number, CSSNumber{value});
|
||||
}
|
||||
|
||||
static constexpr CSSValueVariant percentage(float value) requires(
|
||||
canRepresent<CSSPercentage>()) {
|
||||
return CSSValueVariant(CSSValueType::Percentage, CSSPercentage{value});
|
||||
}
|
||||
|
||||
constexpr CSSValueType type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
constexpr KeywordT getKeyword() const {
|
||||
return getIf<CSSValueType::Keyword, KeywordT>();
|
||||
}
|
||||
|
||||
constexpr CSSLength getLength() const requires(canRepresent<CSSLength>()) {
|
||||
return getIf<CSSValueType::Length, CSSLength>();
|
||||
}
|
||||
|
||||
constexpr CSSNumber getNumber() const requires(canRepresent<CSSNumber>()) {
|
||||
return getIf<CSSValueType::Number, CSSNumber>();
|
||||
}
|
||||
|
||||
constexpr CSSPercentage getPercentage() const
|
||||
requires(canRepresent<CSSPercentage>()) {
|
||||
return getIf<CSSValueType::Percentage, CSSPercentage>();
|
||||
}
|
||||
|
||||
constexpr operator bool() const {
|
||||
return *this != CSSValueVariant{};
|
||||
}
|
||||
|
||||
constexpr bool operator==(const CSSValueVariant& rhs) const = default;
|
||||
|
||||
private:
|
||||
constexpr CSSValueVariant(CSSValueType type, CSSBasicDataType auto&& value)
|
||||
: type_(type) {
|
||||
new (data_.data()) std::remove_cvref_t<decltype(value)>{
|
||||
std::forward<decltype(value)>(value)};
|
||||
}
|
||||
|
||||
CSSValueType type_;
|
||||
std::array<std::byte, traits::maxSizeof<KeywordT, Rest...>()> data_;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(CSSValueVariant<CSSFlexDirection>) == 2);
|
||||
static_assert(sizeof(CSSValueVariant<CSSAutoKeyword, CSSLength>) == 6);
|
||||
static_assert(
|
||||
sizeof(CSSValueVariant<CSSAutoKeyword, CSSLength, CSSPercentage>) == 6);
|
||||
static_assert(sizeof(CSSValueVariant<CSSKeyword, CSSNumber>) == 5);
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <react/renderer/css/CSSParser.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
TEST(CSSParser, keyword_values) {
|
||||
auto emptyValue = parseCSSValue<CSSKeyword>("");
|
||||
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
|
||||
|
||||
auto autoValue = parseCSSValue<CSSKeyword>("auto");
|
||||
EXPECT_EQ(autoValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto);
|
||||
|
||||
auto autoCapsValue = parseCSSValue<CSSKeyword>("AuTO");
|
||||
EXPECT_EQ(autoCapsValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(autoCapsValue.getKeyword(), CSSKeyword::Auto);
|
||||
|
||||
auto autoDisallowedValue = parseCSSValue<CSSFlexDirection>("auto");
|
||||
EXPECT_EQ(autoDisallowedValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(autoDisallowedValue.getKeyword(), CSSKeyword::Unset);
|
||||
|
||||
auto whitespaceValue = parseCSSValue<CSSAlignItems>(" flex-start ");
|
||||
EXPECT_EQ(whitespaceValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(whitespaceValue.getKeyword(), CSSAlignItems::FlexStart);
|
||||
|
||||
auto badIdentValue = parseCSSValue<CSSWideKeyword>("bad");
|
||||
EXPECT_EQ(badIdentValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(badIdentValue.getKeyword(), CSSKeyword::Unset);
|
||||
|
||||
auto pxValue = parseCSSValue<CSSKeyword>("20px");
|
||||
EXPECT_EQ(pxValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(pxValue.getKeyword(), CSSKeyword::Unset);
|
||||
|
||||
auto multiValue = parseCSSValue<CSSKeyword>("auto flex-start");
|
||||
EXPECT_EQ(multiValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(multiValue.getKeyword(), CSSKeyword::Unset);
|
||||
}
|
||||
|
||||
TEST(CSSParser, length_values) {
|
||||
auto emptyValue = parseCSSValue<CSSAutoKeyword, CSSLength>("");
|
||||
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
|
||||
|
||||
auto autoValue = parseCSSValue<CSSAutoKeyword, CSSLength>("auto");
|
||||
EXPECT_EQ(autoValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto);
|
||||
|
||||
auto pxValue = parseCSSValue<CSSAutoKeyword, CSSLength>("20px");
|
||||
EXPECT_EQ(pxValue.type(), CSSValueType::Length);
|
||||
EXPECT_EQ(pxValue.getLength().value, 20.0f);
|
||||
EXPECT_EQ(pxValue.getLength().unit, CSSLengthUnit::Px);
|
||||
|
||||
auto cmValue = parseCSSValue<CSSAutoKeyword, CSSLength>("453cm");
|
||||
EXPECT_EQ(cmValue.type(), CSSValueType::Length);
|
||||
EXPECT_EQ(cmValue.getLength().value, 453.0f);
|
||||
EXPECT_EQ(cmValue.getLength().unit, CSSLengthUnit::Cm);
|
||||
|
||||
auto unitlessZeroValue = parseCSSValue<CSSAutoKeyword, CSSLength>("0");
|
||||
EXPECT_EQ(unitlessZeroValue.type(), CSSValueType::Length);
|
||||
EXPECT_EQ(unitlessZeroValue.getLength().value, 0.0f);
|
||||
EXPECT_EQ(unitlessZeroValue.getLength().unit, CSSLengthUnit::Px);
|
||||
|
||||
auto unitlessNonzeroValue = parseCSSValue<CSSAutoKeyword, CSSLength>("123");
|
||||
EXPECT_EQ(unitlessNonzeroValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(unitlessNonzeroValue.getKeyword(), CSSKeyword::Unset);
|
||||
|
||||
auto pctValue = parseCSSValue<CSSAutoKeyword, CSSLength>("-40%");
|
||||
EXPECT_EQ(pctValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(pctValue.getKeyword(), CSSKeyword::Unset);
|
||||
}
|
||||
|
||||
TEST(CSSParser, length_percentage_values) {
|
||||
auto emptyValue = parseCSSValue<CSSAutoKeyword, CSSLength, CSSPercentage>("");
|
||||
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
|
||||
|
||||
auto autoValue =
|
||||
parseCSSValue<CSSAutoKeyword, CSSLength, CSSPercentage>("auto");
|
||||
EXPECT_EQ(autoValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(autoValue.getKeyword(), CSSKeyword::Auto);
|
||||
|
||||
auto pxValue =
|
||||
parseCSSValue<CSSAutoKeyword, CSSLength, CSSPercentage>("20px");
|
||||
EXPECT_EQ(pxValue.type(), CSSValueType::Length);
|
||||
EXPECT_EQ(pxValue.getLength().value, 20.0f);
|
||||
EXPECT_EQ(pxValue.getLength().unit, CSSLengthUnit::Px);
|
||||
|
||||
auto pctValue =
|
||||
parseCSSValue<CSSAutoKeyword, CSSLength, CSSPercentage>("-40%");
|
||||
EXPECT_EQ(pctValue.type(), CSSValueType::Percentage);
|
||||
EXPECT_EQ(pctValue.getPercentage().value, -40.0f);
|
||||
}
|
||||
|
||||
TEST(CSSParser, number_values) {
|
||||
auto emptyValue = parseCSSValue<CSSKeyword, CSSNumber>("");
|
||||
EXPECT_EQ(emptyValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(emptyValue.getKeyword(), CSSKeyword::Unset);
|
||||
|
||||
auto inheritValue = parseCSSValue<CSSKeyword, CSSNumber>("inherit");
|
||||
EXPECT_EQ(inheritValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(inheritValue.getKeyword(), CSSKeyword::Inherit);
|
||||
|
||||
auto pxValue = parseCSSValue<CSSKeyword, CSSNumber>("20px");
|
||||
EXPECT_EQ(pxValue.type(), CSSValueType::Keyword);
|
||||
EXPECT_EQ(pxValue.getKeyword(), CSSKeyword::Unset);
|
||||
|
||||
auto numberValue = parseCSSValue<CSSKeyword, CSSNumber>("123.456");
|
||||
EXPECT_EQ(numberValue.type(), CSSValueType::Number);
|
||||
EXPECT_EQ(numberValue.getNumber().value, 123.456f);
|
||||
|
||||
auto unitlessZeroValue =
|
||||
parseCSSValue<CSSAutoKeyword, CSSLength, CSSNumber>("0");
|
||||
EXPECT_EQ(unitlessZeroValue.type(), CSSValueType::Number);
|
||||
EXPECT_EQ(unitlessZeroValue.getNumber().value, 0.0f);
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
@@ -104,12 +104,12 @@ TEST(CSSTokenizer, dimension_values) {
|
||||
TEST(CSSTokenizer, percent_values) {
|
||||
expectTokens(
|
||||
"12%",
|
||||
{CSSToken{CSSTokenType::Percent, 12.0f},
|
||||
{CSSToken{CSSTokenType::Percentage, 12.0f},
|
||||
CSSToken{CSSTokenType::EndOfFile}});
|
||||
|
||||
expectTokens(
|
||||
"-28.5%",
|
||||
{CSSToken{CSSTokenType::Percent, -28.5f},
|
||||
{CSSToken{CSSTokenType::Percentage, -28.5f},
|
||||
CSSToken{CSSTokenType::EndOfFile}});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and 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 <algorithm>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace facebook::react::traits {
|
||||
|
||||
template <typename T, typename... RestT>
|
||||
static constexpr size_t maxSizeof() {
|
||||
if constexpr (sizeof...(RestT) > 0) {
|
||||
return std::max(sizeof(T), maxSizeof<RestT...>());
|
||||
} else {
|
||||
return sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ExpectedT>
|
||||
static constexpr bool containsType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ExpectedT, typename FirstT, typename... RestT>
|
||||
static constexpr bool containsType() {
|
||||
if constexpr (sizeof...(RestT) > 0) {
|
||||
return std::is_same_v<ExpectedT, FirstT> ||
|
||||
containsType<ExpectedT, RestT...>();
|
||||
} else {
|
||||
return std::is_same_v<ExpectedT, FirstT>;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace facebook::react::traits
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/**
|
||||
@@ -17,13 +21,14 @@ namespace facebook::react {
|
||||
* when std::hash does not provide the needed functionality. For example,
|
||||
* constexpr.
|
||||
*/
|
||||
template <typename CharTransformT = std::identity>
|
||||
constexpr uint32_t fnv1a(std::string_view string) noexcept {
|
||||
constexpr uint32_t offset_basis = 2166136261;
|
||||
|
||||
uint32_t hash = offset_basis;
|
||||
|
||||
for (auto const& c : string) {
|
||||
hash ^= static_cast<int8_t>(c);
|
||||
hash ^= static_cast<int8_t>(CharTransformT{}(c));
|
||||
// Using shifts and adds instead of multiplication with a prime number.
|
||||
// This is faster when compiled with optimizations.
|
||||
hash +=
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and 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 <type_traits>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/**
|
||||
* Polyfill of C++ 23 to_underlying()
|
||||
* https://en.cppreference.com/w/cpp/utility/to_underlying
|
||||
*/
|
||||
constexpr auto to_underlying(auto e) noexcept {
|
||||
return static_cast<std::underlying_type_t<decltype(e)>>(e);
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
Reference in New Issue
Block a user