未验证 提交 3b71d3b0 编写于 作者: S Stephen Toub 提交者: GitHub

Enable SymbolicRegexNode.IsNullableFor fast path to inline (#61605)

上级 2e97ac49
......@@ -173,101 +173,106 @@ static void AppendToList(SymbolicRegexNode<S> concat, List<SymbolicRegexNode<S>>
/// <param name="context">kind info for previous and next characters</param>
internal bool IsNullableFor(uint context)
{
if (_nullabilityCache is null)
// if _nullabilityCache is null then IsNullable==CanBeNullable
// Observe that if IsNullable==true then CanBeNullable==true.
// but when the node does not start with an anchor
// and IsNullable==false then CanBeNullable==false.
return _nullabilityCache is null ?
_info.IsNullable :
WithCache(context);
// Separated out to enable the common case (no nullability cache) to be inlined
// and to avoid zero-init costs for generally unused state.
bool WithCache(uint context)
{
// if _nullabilityCache is null then IsNullable==CanBeNullable
// Observe that if IsNullable==true then CanBeNullable==true.
// but when the node does not start with an anchor
// and IsNullable==false then CanBeNullable==false.
return _info.IsNullable;
}
if (!StackHelper.TryEnsureSufficientExecutionStack())
{
return StackHelper.CallOnEmptyStack(IsNullableFor, context);
}
if (!StackHelper.TryEnsureSufficientExecutionStack())
{
return StackHelper.CallOnEmptyStack(IsNullableFor, context);
}
Debug.Assert(context < CharKind.ContextLimit);
Debug.Assert(context < CharKind.ContextLimit);
// If nullablity has been computed for the given context then return it
byte b = Volatile.Read(ref _nullabilityCache[context]);
if (b != UndefinedByte)
{
return b == TrueByte;
}
// If nullablity has been computed for the given context then return it
byte b = Volatile.Read(ref _nullabilityCache[context]);
if (b != UndefinedByte)
{
return b == TrueByte;
}
// Otherwise compute the nullability recursively for the given context
bool is_nullable;
switch (_kind)
{
case SymbolicRegexKind.Loop:
Debug.Assert(_left is not null);
is_nullable = _lower == 0 || _left.IsNullableFor(context);
break;
// Otherwise compute the nullability recursively for the given context
bool is_nullable;
switch (_kind)
{
case SymbolicRegexKind.Loop:
Debug.Assert(_left is not null);
is_nullable = _lower == 0 || _left.IsNullableFor(context);
break;
case SymbolicRegexKind.Concat:
Debug.Assert(_left is not null && _right is not null);
is_nullable = _left.IsNullableFor(context) && _right.IsNullableFor(context);
break;
case SymbolicRegexKind.Concat:
Debug.Assert(_left is not null && _right is not null);
is_nullable = _left.IsNullableFor(context) && _right.IsNullableFor(context);
break;
case SymbolicRegexKind.Or:
case SymbolicRegexKind.And:
Debug.Assert(_alts is not null);
is_nullable = _alts.IsNullableFor(context);
break;
case SymbolicRegexKind.Or:
case SymbolicRegexKind.And:
Debug.Assert(_alts is not null);
is_nullable = _alts.IsNullableFor(context);
break;
case SymbolicRegexKind.Not:
Debug.Assert(_left is not null);
is_nullable = !_left.IsNullableFor(context);
break;
case SymbolicRegexKind.Not:
Debug.Assert(_left is not null);
is_nullable = !_left.IsNullableFor(context);
break;
case SymbolicRegexKind.StartAnchor:
is_nullable = CharKind.Prev(context) == CharKind.StartStop;
break;
case SymbolicRegexKind.StartAnchor:
is_nullable = CharKind.Prev(context) == CharKind.StartStop;
break;
case SymbolicRegexKind.EndAnchor:
is_nullable = CharKind.Next(context) == CharKind.StartStop;
break;
case SymbolicRegexKind.EndAnchor:
is_nullable = CharKind.Next(context) == CharKind.StartStop;
break;
case SymbolicRegexKind.BOLAnchor:
// Beg-Of-Line anchor is nullable when the previous character is Newline or Start
// note: at least one of the bits must be 1, but both could also be 1 in case of very first newline
is_nullable = (CharKind.Prev(context) & CharKind.NewLineS) != 0;
break;
case SymbolicRegexKind.BOLAnchor:
// Beg-Of-Line anchor is nullable when the previous character is Newline or Start
// note: at least one of the bits must be 1, but both could also be 1 in case of very first newline
is_nullable = (CharKind.Prev(context) & CharKind.NewLineS) != 0;
break;
case SymbolicRegexKind.EOLAnchor:
// End-Of-Line anchor is nullable when the next character is Newline or Stop
// note: at least one of the bits must be 1, but both could also be 1 in case of \Z
is_nullable = (CharKind.Next(context) & CharKind.NewLineS) != 0;
break;
case SymbolicRegexKind.EOLAnchor:
// End-Of-Line anchor is nullable when the next character is Newline or Stop
// note: at least one of the bits must be 1, but both could also be 1 in case of \Z
is_nullable = (CharKind.Next(context) & CharKind.NewLineS) != 0;
break;
case SymbolicRegexKind.WBAnchor:
// test that prev char is word letter iff next is not not word letter
is_nullable = ((CharKind.Prev(context) & CharKind.WordLetter) ^ (CharKind.Next(context) & CharKind.WordLetter)) != 0;
break;
case SymbolicRegexKind.WBAnchor:
// test that prev char is word letter iff next is not not word letter
is_nullable = ((CharKind.Prev(context) & CharKind.WordLetter) ^ (CharKind.Next(context) & CharKind.WordLetter)) != 0;
break;
case SymbolicRegexKind.NWBAnchor:
// test that prev char is word letter iff next is word letter
is_nullable = ((CharKind.Prev(context) & CharKind.WordLetter) ^ (CharKind.Next(context) & CharKind.WordLetter)) == 0;
break;
case SymbolicRegexKind.NWBAnchor:
// test that prev char is word letter iff next is word letter
is_nullable = ((CharKind.Prev(context) & CharKind.WordLetter) ^ (CharKind.Next(context) & CharKind.WordLetter)) == 0;
break;
case SymbolicRegexKind.EndAnchorZ:
// \Z anchor is nullable when the next character is either the last Newline or Stop
// note: CharKind.NewLineS == CharKind.Newline|CharKind.StartStop
is_nullable = (CharKind.Next(context) & CharKind.StartStop) != 0;
break;
case SymbolicRegexKind.EndAnchorZ:
// \Z anchor is nullable when the next character is either the last Newline or Stop
// note: CharKind.NewLineS == CharKind.Newline|CharKind.StartStop
is_nullable = (CharKind.Next(context) & CharKind.StartStop) != 0;
break;
default: // SymbolicRegexKind.EndAnchorZRev:
// EndAnchorZRev (rev(\Z)) anchor is nullable when the prev character is either the first Newline or Start
// note: CharKind.NewLineS == CharKind.Newline|CharKind.StartStop
Debug.Assert(_kind == SymbolicRegexKind.EndAnchorZRev);
is_nullable = (CharKind.Prev(context) & CharKind.StartStop) != 0;
break;
}
default: // SymbolicRegexKind.EndAnchorZRev:
// EndAnchorZRev (rev(\Z)) anchor is nullable when the prev character is either the first Newline or Start
// note: CharKind.NewLineS == CharKind.Newline|CharKind.StartStop
Debug.Assert(_kind == SymbolicRegexKind.EndAnchorZRev);
is_nullable = (CharKind.Prev(context) & CharKind.StartStop) != 0;
break;
}
Volatile.Write(ref _nullabilityCache[context], is_nullable ? TrueByte : FalseByte);
Volatile.Write(ref _nullabilityCache[context], is_nullable ? TrueByte : FalseByte);
return is_nullable;
return is_nullable;
}
}
/// <summary>Returns true if this is equivalent to .* (the node must be eager also)</summary>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册