Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
452c84b2
Commit
452c84b2
authored
Jun 17, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More parsers.
parent
37ee4819
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
357 additions
and
27 deletions
+357
-27
parse-test.c++
c++/src/kj/parse-test.c++
+200
-0
parse.h
c++/src/kj/parse.h
+157
-27
No files found.
c++/src/kj/parse-test.c++
View file @
452c84b2
...
...
@@ -55,6 +55,61 @@ TEST(Parsers, ExactElementParser) {
EXPECT_TRUE
(
input
.
atEnd
());
}
TEST
(
Parsers
,
ExactlyConstParser
)
{
StringPtr
text
=
"foo"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
Tuple
<>>
result
=
exactlyConst
<
char
,
'f'
>
()(
input
);
EXPECT_TRUE
(
result
!=
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
result
=
exactlyConst
<
char
,
'o'
>
()(
input
);
EXPECT_TRUE
(
result
!=
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
result
=
exactlyConst
<
char
,
'x'
>
()(
input
);
EXPECT_TRUE
(
result
==
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
auto
parser
=
exactlyConst
<
char
,
'o'
>
();
ParserRef
<
Input
,
Tuple
<>>
wrapped
=
ref
<
Input
>
(
parser
);
result
=
wrapped
(
input
);
EXPECT_TRUE
(
result
!=
nullptr
);
EXPECT_TRUE
(
input
.
atEnd
());
}
TEST
(
Parsers
,
ExactChar
)
{
constexpr
auto
parser
=
exactChar
<
'a'
>
();
{
StringPtr
text
=
"a"
;
Input
input
(
text
.
begin
(),
text
.
end
());
EXPECT_TRUE
(
parser
(
input
)
!=
nullptr
);
EXPECT_TRUE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"b"
;
Input
input
(
text
.
begin
(),
text
.
end
());
EXPECT_TRUE
(
parser
(
input
)
==
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
}
}
TEST
(
Parsers
,
ConstResultParser
)
{
auto
parser
=
constResult
(
exactly
(
'o'
),
123
);
StringPtr
text
=
"o"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
int
>
result
=
parser
(
input
);
KJ_IF_MAYBE
(
i
,
result
)
{
EXPECT_EQ
(
123
,
*
i
);
}
else
{
ADD_FAILURE
()
<<
"Expected 123, got null."
;
}
EXPECT_TRUE
(
input
.
atEnd
());
}
TEST
(
Parsers
,
SequenceParser
)
{
StringPtr
text
=
"foo"
;
...
...
@@ -328,6 +383,151 @@ TEST(Parsers, AcceptIfParser) {
}
}
TEST
(
Parsers
,
CharRange
)
{
constexpr
auto
parser
=
charRange
(
'a'
,
'z'
);
{
StringPtr
text
=
"a"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
KJ_IF_MAYBE
(
value
,
result
)
{
EXPECT_EQ
(
'a'
,
*
value
);
}
else
{
ADD_FAILURE
()
<<
"Expected parse result, got null."
;
}
EXPECT_TRUE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"n"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
KJ_IF_MAYBE
(
value
,
result
)
{
EXPECT_EQ
(
'n'
,
*
value
);
}
else
{
ADD_FAILURE
()
<<
"Expected parse result, got null."
;
}
EXPECT_TRUE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"z"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
KJ_IF_MAYBE
(
value
,
result
)
{
EXPECT_EQ
(
'z'
,
*
value
);
}
else
{
ADD_FAILURE
()
<<
"Expected parse result, got null."
;
}
EXPECT_TRUE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"`"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
EXPECT_TRUE
(
result
==
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"{"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
EXPECT_TRUE
(
result
==
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"A"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
EXPECT_TRUE
(
result
==
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
}
}
TEST
(
Parsers
,
AnyChar
)
{
constexpr
auto
parser
=
anyChar
(
"axn2B"
);
{
StringPtr
text
=
"a"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
KJ_IF_MAYBE
(
value
,
result
)
{
EXPECT_EQ
(
'a'
,
*
value
);
}
else
{
ADD_FAILURE
()
<<
"Expected parse result, got null."
;
}
EXPECT_TRUE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"n"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
KJ_IF_MAYBE
(
value
,
result
)
{
EXPECT_EQ
(
'n'
,
*
value
);
}
else
{
ADD_FAILURE
()
<<
"Expected parse result, got null."
;
}
EXPECT_TRUE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"B"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
KJ_IF_MAYBE
(
value
,
result
)
{
EXPECT_EQ
(
'B'
,
*
value
);
}
else
{
ADD_FAILURE
()
<<
"Expected parse result, got null."
;
}
EXPECT_TRUE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"b"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
EXPECT_TRUE
(
result
==
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"j"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
EXPECT_TRUE
(
result
==
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
}
{
StringPtr
text
=
"A"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
char
>
result
=
parser
(
input
);
EXPECT_TRUE
(
result
==
nullptr
);
EXPECT_FALSE
(
input
.
atEnd
());
}
}
TEST
(
Parsers
,
CharGroupCombo
)
{
constexpr
auto
parser
=
many
(
charRange
(
'0'
,
'9'
).
orRange
(
'a'
,
'z'
).
orRange
(
'A'
,
'Z'
).
orAny
(
"-_"
));
{
StringPtr
text
=
"foo1-bar2_baz3@qux"
;
Input
input
(
text
.
begin
(),
text
.
end
());
Maybe
<
Array
<
char
>>
result
=
parser
(
input
);
KJ_IF_MAYBE
(
value
,
result
)
{
EXPECT_EQ
(
"foo1-bar2_baz3"
,
str
(
*
value
));
}
else
{
ADD_FAILURE
()
<<
"Expected parse result, got null."
;
}
EXPECT_FALSE
(
input
.
atEnd
());
}
}
}
// namespace
}
// namespace parse
}
// namespace kj
c++/src/kj/parse.h
View file @
452c84b2
...
...
@@ -114,7 +114,8 @@ class ParserRef {
public
:
template
<
typename
Other
>
ParserRef
(
Other
&
other
)
:
parser
(
&
other
),
wrapper
(
WrapperImpl
<
Other
>::
instance
())
{}
constexpr
ParserRef
(
Other
&
other
)
:
parser
(
&
other
),
wrapper
(
WrapperImplInstance
<
Other
>::
instance
)
{}
KJ_ALWAYS_INLINE
(
Maybe
<
Output
>
operator
()(
Input
&
input
)
const
)
{
// Always inline in the hopes that this allows branch prediction to kick in so the virtual call
...
...
@@ -131,20 +132,23 @@ private:
Maybe
<
Output
>
parse
(
const
void
*
parser
,
Input
&
input
)
const
override
{
return
(
*
reinterpret_cast
<
const
ParserImpl
*>
(
parser
))(
input
);
}
static
WrapperImpl
&
instance
()
{
static
WrapperImpl
obj
;
return
obj
;
}
};
template
<
typename
ParserImpl
>
struct
WrapperImplInstance
{
static
constexpr
WrapperImpl
<
ParserImpl
>
instance
=
WrapperImpl
<
ParserImpl
>
();
};
const
void
*
parser
;
Wrapper
&
wrapper
;
const
Wrapper
&
wrapper
;
};
template
<
typename
Input
,
typename
Output
>
template
<
typename
ParserImpl
>
constexpr
ParserRef
<
Input
,
Output
>::
WrapperImpl
<
ParserImpl
>
ParserRef
<
Input
,
Output
>::
WrapperImplInstance
<
ParserImpl
>::
instance
;
template
<
typename
Input
,
typename
ParserImpl
>
ParserRef
<
Input
,
OutputType
<
ParserImpl
,
Input
>>
ref
(
ParserImpl
&
impl
)
{
constexpr
ParserRef
<
Input
,
OutputType
<
ParserImpl
,
Input
>>
ref
(
ParserImpl
&
impl
)
{
// Constructs a ParserRef. You must specify the input type explicitly, e.g.
// `ref<MyInput>(myParser)`.
...
...
@@ -158,7 +162,7 @@ ref(ParserImpl& impl) {
template
<
typename
T
>
class
Exactly_
{
public
:
explicit
Exactly_
(
T
&&
expected
)
:
expected
(
expected
)
{}
explicit
constexpr
Exactly_
(
T
&&
expected
)
:
expected
(
expected
)
{}
template
<
typename
Input
>
Maybe
<
Tuple
<>>
operator
()(
Input
&
input
)
const
{
...
...
@@ -175,13 +179,77 @@ private:
};
template
<
typename
T
>
Exactly_
<
T
>
exactly
(
T
&&
expected
)
{
constexpr
Exactly_
<
T
>
exactly
(
T
&&
expected
)
{
// Constructs a parser which succeeds when the input is exactly the token specified. The
// result is always the empty tuple.
return
Exactly_
<
T
>
(
kj
::
fwd
<
T
>
(
expected
));
}
// -------------------------------------------------------------------
// exactlyConst()
// Output = Tuple<>
template
<
typename
T
,
T
expected
>
class
ExactlyConst_
{
public
:
explicit
constexpr
ExactlyConst_
()
{}
template
<
typename
Input
>
Maybe
<
Tuple
<>>
operator
()(
Input
&
input
)
const
{
if
(
input
.
atEnd
()
||
input
.
current
()
!=
expected
)
{
return
nullptr
;
}
else
{
input
.
next
();
return
Tuple
<>
();
}
}
};
template
<
typename
T
,
T
expected
>
constexpr
ExactlyConst_
<
T
,
expected
>
exactlyConst
()
{
// Constructs a parser which succeeds when the input is exactly the token specified. The
// result is always the empty tuple. This parser is templated on the token value which may cause
// it to perform better -- or worse. Be sure to measure.
return
ExactlyConst_
<
T
,
expected
>
();
}
template
<
char
c
>
constexpr
ExactlyConst_
<
char
,
c
>
exactChar
()
{
return
ExactlyConst_
<
char
,
c
>
();
}
// -------------------------------------------------------------------
// constResult()
template
<
typename
SubParser
,
typename
Result
>
class
ConstResult_
{
public
:
explicit
constexpr
ConstResult_
(
SubParser
&&
subParser
,
Result
&&
result
)
:
subParser
(
kj
::
fwd
<
SubParser
>
(
subParser
)),
result
(
kj
::
fwd
<
Result
>
(
result
))
{}
template
<
typename
Input
>
Maybe
<
Result
>
operator
()(
Input
&
input
)
const
{
if
(
subParser
(
input
)
==
nullptr
)
{
return
nullptr
;
}
else
{
return
result
;
}
}
private
:
SubParser
subParser
;
Result
result
;
};
template
<
typename
SubParser
,
typename
Result
>
constexpr
ConstResult_
<
SubParser
,
Result
>
constResult
(
SubParser
&&
subParser
,
Result
&&
result
)
{
// Constructs a parser which returns exactly `result` if `subParser` is successful.
return
ConstResult_
<
SubParser
,
Result
>
(
kj
::
fwd
<
SubParser
>
(
subParser
),
kj
::
fwd
<
Result
>
(
result
));
}
// -------------------------------------------------------------------
// sequence()
// Output = Flattened Tuple of outputs of sub-parsers.
...
...
@@ -192,7 +260,7 @@ template <typename FirstSubParser, typename... SubParsers>
class
Sequence_
<
FirstSubParser
,
SubParsers
...
>
{
public
:
template
<
typename
T
,
typename
...
U
>
explicit
Sequence_
(
T
&&
firstSubParser
,
U
&&
...
rest
)
explicit
constexpr
Sequence_
(
T
&&
firstSubParser
,
U
&&
...
rest
)
:
first
(
kj
::
fwd
<
T
>
(
firstSubParser
)),
rest
(
kj
::
fwd
<
U
>
(
rest
)...)
{}
template
<
typename
Input
>
...
...
@@ -238,7 +306,7 @@ public:
};
template
<
typename
...
SubParsers
>
Sequence_
<
SubParsers
...
>
sequence
(
SubParsers
&&
...
subParsers
)
{
constexpr
Sequence_
<
SubParsers
...
>
sequence
(
SubParsers
&&
...
subParsers
)
{
// Constructs a parser that executes each of the parameter parsers in sequence and returns a
// tuple of their results.
...
...
@@ -252,7 +320,7 @@ Sequence_<SubParsers...> sequence(SubParsers&&... subParsers) {
template
<
typename
SubParser
,
bool
atLeastOne
>
class
Many_
{
public
:
explicit
Many_
(
SubParser
&&
subParser
)
explicit
constexpr
Many_
(
SubParser
&&
subParser
)
:
subParser
(
kj
::
mv
(
subParser
))
{}
template
<
typename
Input
>
...
...
@@ -283,14 +351,14 @@ private:
};
template
<
typename
SubParser
>
Many_
<
SubParser
,
false
>
many
(
SubParser
&&
subParser
)
{
constexpr
Many_
<
SubParser
,
false
>
many
(
SubParser
&&
subParser
)
{
// Constructs a parser that repeatedly executes the given parser until it fails, returning an
// Array of the results.
return
Many_
<
SubParser
,
false
>
(
kj
::
fwd
<
SubParser
>
(
subParser
));
}
template
<
typename
SubParser
>
Many_
<
SubParser
,
true
>
oneOrMore
(
SubParser
&&
subParser
)
{
constexpr
Many_
<
SubParser
,
true
>
oneOrMore
(
SubParser
&&
subParser
)
{
// Like `many()` but the parser must parse at least one item to be successful.
return
Many_
<
SubParser
,
true
>
(
kj
::
fwd
<
SubParser
>
(
subParser
));
}
...
...
@@ -302,7 +370,7 @@ Many_<SubParser, true> oneOrMore(SubParser&& subParser) {
template
<
typename
SubParser
>
class
Optional_
{
public
:
explicit
Optional_
(
SubParser
&&
subParser
)
explicit
constexpr
Optional_
(
SubParser
&&
subParser
)
:
subParser
(
kj
::
mv
(
subParser
))
{}
template
<
typename
Input
>
...
...
@@ -323,7 +391,7 @@ private:
};
template
<
typename
SubParser
>
Optional_
<
SubParser
>
optional
(
SubParser
&&
subParser
)
{
constexpr
Optional_
<
SubParser
>
optional
(
SubParser
&&
subParser
)
{
// Constructs a parser that accepts zero or one of the given sub-parser, returning a Maybe
// of the sub-parser's result.
return
Optional_
<
SubParser
>
(
kj
::
fwd
<
SubParser
>
(
subParser
));
...
...
@@ -341,7 +409,7 @@ template <typename FirstSubParser, typename... SubParsers>
class
OneOf_
<
FirstSubParser
,
SubParsers
...
>
{
public
:
template
<
typename
T
,
typename
...
U
>
explicit
OneOf_
(
T
&&
firstSubParser
,
U
&&
...
rest
)
explicit
constexpr
OneOf_
(
T
&&
firstSubParser
,
U
&&
...
rest
)
:
first
(
kj
::
fwd
<
T
>
(
firstSubParser
)),
rest
(
kj
::
fwd
<
U
>
(
rest
)...)
{}
template
<
typename
Input
>
...
...
@@ -375,7 +443,7 @@ public:
};
template
<
typename
...
SubParsers
>
OneOf_
<
SubParsers
...
>
oneOf
(
SubParsers
&&
...
parsers
)
{
constexpr
OneOf_
<
SubParsers
...
>
oneOf
(
SubParsers
&&
...
parsers
)
{
// Constructs a parser that accepts one of a set of options. The parser behaves as the first
// sub-parser in the list which returns successfully. All of the sub-parsers must return the
// same type.
...
...
@@ -394,7 +462,7 @@ public:
inline
const
Position
&
end
()
{
return
end_
;
}
Span
()
=
default
;
inline
Span
(
Position
&&
begin
,
Position
&&
end
)
:
begin_
(
mv
(
begin
)),
end_
(
mv
(
end
))
{}
inline
constexpr
Span
(
Position
&&
begin
,
Position
&&
end
)
:
begin_
(
mv
(
begin
)),
end_
(
mv
(
end
))
{}
private
:
Position
begin_
;
...
...
@@ -402,14 +470,14 @@ private:
};
template
<
typename
Position
>
Span
<
Decay
<
Position
>>
span
(
Position
&&
start
,
Position
&&
end
)
{
constexpr
Span
<
Decay
<
Position
>>
span
(
Position
&&
start
,
Position
&&
end
)
{
return
Span
<
Decay
<
Position
>>
(
kj
::
fwd
<
Position
>
(
start
),
kj
::
fwd
<
Position
>
(
end
));
}
template
<
typename
SubParser
,
typename
TransformFunc
>
class
Transform_
{
public
:
explicit
Transform_
(
SubParser
&&
subParser
,
TransformFunc
&&
transform
)
explicit
constexpr
Transform_
(
SubParser
&&
subParser
,
TransformFunc
&&
transform
)
:
subParser
(
kj
::
fwd
<
SubParser
>
(
subParser
)),
transform
(
kj
::
fwd
<
TransformFunc
>
(
transform
))
{}
template
<
typename
Input
>
...
...
@@ -432,7 +500,8 @@ private:
};
template
<
typename
SubParser
,
typename
TransformFunc
>
Transform_
<
SubParser
,
TransformFunc
>
transform
(
SubParser
&&
subParser
,
TransformFunc
&&
functor
)
{
constexpr
Transform_
<
SubParser
,
TransformFunc
>
transform
(
SubParser
&&
subParser
,
TransformFunc
&&
functor
)
{
// Constructs a parser which executes some other parser and then transforms the result by invoking
// `functor` on it. Typically `functor` is a lambda. It is invoked using `kj::apply`,
// meaning tuples will be unpacked as arguments.
...
...
@@ -447,7 +516,7 @@ Transform_<SubParser, TransformFunc> transform(SubParser&& subParser, TransformF
template
<
typename
SubParser
,
typename
Condition
>
class
AcceptIf_
{
public
:
explicit
AcceptIf_
(
SubParser
&&
subParser
,
Condition
&&
condition
)
explicit
constexpr
AcceptIf_
(
SubParser
&&
subParser
,
Condition
&&
condition
)
:
subParser
(
kj
::
mv
(
subParser
)),
condition
(
kj
::
mv
(
condition
))
{}
template
<
typename
Input
>
...
...
@@ -469,7 +538,7 @@ private:
};
template
<
typename
SubParser
,
typename
Condition
>
AcceptIf_
<
SubParser
,
Condition
>
acceptIf
(
SubParser
&&
subParser
,
Condition
&&
condition
)
{
constexpr
AcceptIf_
<
SubParser
,
Condition
>
acceptIf
(
SubParser
&&
subParser
,
Condition
&&
condition
)
{
// Constructs a parser which executes some other parser and then invokes the functor
// `condition` on the result to check if it is valid. Typically, `condition` is a lambda
// returning true or false. Like with `transform()`, `condition` is invoked using `kj::apply`
...
...
@@ -494,11 +563,72 @@ public:
}
};
EndOfInput_
endOfInput
()
{
constexpr
EndOfInput_
endOfInput
()
{
// Constructs a parser that succeeds only if it is called with no input.
return
EndOfInput_
();
}
// -------------------------------------------------------------------
// CharGroup
class
CharGroup_
{
public
:
constexpr
CharGroup_
()
:
bits
{
0
,
0
,
0
,
0
}
{}
constexpr
CharGroup_
orRange
(
unsigned
char
first
,
unsigned
char
last
)
const
{
return
CharGroup_
(
bits
[
0
]
|
(
oneBits
(
last
+
1
)
&
~
oneBits
(
first
)),
bits
[
1
]
|
(
oneBits
(
last
-
63
)
&
~
oneBits
(
first
-
64
)),
bits
[
2
]
|
(
oneBits
(
last
-
127
)
&
~
oneBits
(
first
-
128
)),
bits
[
3
]
|
(
oneBits
(
last
-
191
)
&
~
oneBits
(
first
-
192
)));
}
constexpr
CharGroup_
orAny
(
const
char
*
chars
)
const
{
return
*
chars
==
0
?
*
this
:
orChar
(
*
chars
).
orAny
(
chars
+
1
);
}
constexpr
CharGroup_
orChar
(
unsigned
char
c
)
const
{
return
CharGroup_
(
bits
[
0
]
|
bit
(
c
),
bits
[
1
]
|
bit
(
c
-
64
),
bits
[
2
]
|
bit
(
c
-
128
),
bits
[
3
]
|
bit
(
c
-
256
));
}
constexpr
CharGroup_
invert
()
const
{
return
CharGroup_
(
~
bits
[
0
],
~
bits
[
1
],
~
bits
[
2
],
~
bits
[
3
]);
}
template
<
typename
Input
>
Maybe
<
char
>
operator
()(
Input
&
input
)
const
{
unsigned
char
c
=
input
.
current
();
if
((
bits
[
c
/
64
]
&
(
1ll
<<
(
c
%
64
)))
!=
0
)
{
input
.
next
();
return
c
;
}
else
{
return
nullptr
;
}
}
private
:
typedef
unsigned
long
long
Bits64
;
constexpr
CharGroup_
(
Bits64
a
,
Bits64
b
,
Bits64
c
,
Bits64
d
)
:
bits
{
a
,
b
,
c
,
d
}
{}
Bits64
bits
[
4
];
static
constexpr
Bits64
oneBits
(
int
count
)
{
return
count
<=
0
?
0ll
:
count
>=
64
?
-
1ll
:
((
1ll
<<
count
)
-
1
);
}
static
constexpr
Bits64
bit
(
int
index
)
{
return
index
<
0
?
0
:
index
>=
64
?
0
:
(
1ll
<<
index
);
}
};
constexpr
CharGroup_
charRange
(
char
first
,
char
last
)
{
return
CharGroup_
().
orRange
(
first
,
last
);
}
constexpr
CharGroup_
anyChar
(
const
char
*
chars
)
{
return
CharGroup_
().
orAny
(
chars
);
}
}
// namespace parse
}
// namespace kj
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment