//------------------------------------------------------------------------------------------------------- // 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("")); 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 }