blob: 10dc686ee3e364acc49ce34352b8351998b4ebe4 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "ParserPch.h"
namespace UnifiedRegex
{
// The VS2013 linker treats this as a redefinition of an already
// defined constant and complains. So skip the declaration if we're compiling
// with VS2013 or below.
#if !defined(_MSC_VER) || _MSC_VER >= 1900
const int CharTrie::initCapacity;
#endif
// ----------------------------------------------------------------------
// CharTrie
// ----------------------------------------------------------------------
inline bool CharTrie::Find(Char c, int& outi)
{
if (count == 0)
{
outi = 0;
return false;
}
int l = 0;
int h = count - 1;
while (true)
{
int m = (l + h) / 2;
if (children[m].c == c)
{
outi = m;
return true;
}
else if (CTU(children[m].c) < CTU(c))
{
l = m + 1;
if (l > h)
{
outi = l;
return false;
}
}
else
{
h = m - 1;
if (h < l)
{
outi = m;
return false;
}
}
}
return false;
}
void CharTrie::FreeBody(ArenaAllocator* allocator)
{
for (int i = 0; i < count; i++)
children[i].node.FreeBody(allocator);
if (capacity > 0)
AdeleteArray(allocator, capacity, children);
#if DBG
count = 0;
capacity = 0;
children = 0;
#endif
}
CharTrie* CharTrie::Add(ArenaAllocator* allocator, Char c)
{
int i;
if (!Find(c, i))
{
if (capacity <= count)
{
int newCapacity = max(capacity * 2, initCapacity);
children = (CharTrieEntry*)allocator->Realloc(children, capacity * sizeof(CharTrieEntry), newCapacity * sizeof(CharTrieEntry));
capacity = newCapacity;
}
for (int j = count; j > i; j--)
{
children[j].c = children[j - 1].c;
children[j].node = children[j - 1].node;
}
children[i].c = c;
children[i].node.Reset();
count++;
}
return &children[i].node;
}
bool CharTrie::IsDepthZero() const
{
return isAccepting && count == 0;
}
bool CharTrie::IsDepthOne() const
{
if (isAccepting)
return 0;
for (int i = 0; i < count; i++)
{
if (!children[i].node.IsDepthZero())
return false;
}
return true;
}
#if ENABLE_REGEX_CONFIG_OPTIONS
void CharTrie::Print(DebugWriter* w) const
{
w->Indent();
if (isAccepting)
w->PrintEOL(_u("<accept>"));
for (int i = 0; i < count; i++)
{
w->PrintQuotedChar(children[i].c);
w->EOL();
children[i].node.Print(w);
}
w->Unindent();
}
#endif
// ----------------------------------------------------------------------
// RuntimeCharTrie
// ----------------------------------------------------------------------
bool RuntimeCharTrie::Match
(const Char* const input
, const CharCount inputLength
, CharCount& inputOffset
#if ENABLE_REGEX_CONFIG_OPTIONS
, RegexStats* stats
#endif
) const
{
const RuntimeCharTrie* curr = this;
while (true)
{
if (curr->count == 0)
return true;
if (inputOffset >= inputLength)
return false;
#if ENABLE_REGEX_CONFIG_OPTIONS
if (stats != 0)
stats->numCompares++;
#endif
#if 0
int l = 0;
int h = curr->count - 1;
while (true)
{
if (l > h)
return false;
int m = (l + h) / 2;
if (curr->children[m].c == input[inputOffset])
{
inputOffset++;
curr = &curr->children[m].node;
break;
}
else if (CTU(curr->children[m].c) < CTU(input[inputOffset]))
l = m + 1;
else
h = m - 1;
}
#else
int i = 0;
while (true)
{
if (curr->children[i].c == input[inputOffset])
{
inputOffset++;
curr = &curr->children[i].node;
break;
}
else if (curr->children[i].c > input[inputOffset])
return false;
else if (++i >= curr->count)
return false;
}
#endif
}
}
void RuntimeCharTrie::FreeBody(ArenaAllocator* allocator)
{
for (int i = 0; i < count; i++)
children[i].node.FreeBody(allocator);
if (count > 0)
AdeleteArray(allocator, count, children);
#if DBG
count = 0;
children = 0;
#endif
}
void RuntimeCharTrie::CloneFrom(ArenaAllocator* allocator, const CharTrie& other)
{
count = other.count;
if (count > 0)
{
children = AnewArray(allocator, RuntimeCharTrieEntry, count);
for (int i = 0; i < count; i++)
{
children[i].c = other.children[i].c;
children[i].node.CloneFrom(allocator, other.children[i].node);
}
}
else
children = 0;
}
#if ENABLE_REGEX_CONFIG_OPTIONS
void RuntimeCharTrie::Print(DebugWriter* w) const
{
w->Indent();
for (int i = 0; i < count; i++)
{
w->PrintQuotedChar(children[i].c);
w->EOL();
children[i].node.Print(w);
}
w->Unindent();
}
#endif
}