diff options
Diffstat (limited to 'Source/WebCore/contentextensions/DFA.cpp')
-rw-r--r-- | Source/WebCore/contentextensions/DFA.cpp | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/Source/WebCore/contentextensions/DFA.cpp b/Source/WebCore/contentextensions/DFA.cpp new file mode 100644 index 000000000..40dee4a32 --- /dev/null +++ b/Source/WebCore/contentextensions/DFA.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DFA.h" + +#if ENABLE(CONTENT_EXTENSIONS) + +#include "DFAMinimizer.h" +#include <wtf/DataLog.h> + +namespace WebCore { + +namespace ContentExtensions { + +DFA DFA::empty() +{ + DFA newDFA; + newDFA.nodes.append(DFANode()); + return newDFA; +} + +size_t DFA::memoryUsed() const +{ + return sizeof(DFA) + + actions.capacity() * sizeof(uint64_t) + + transitionRanges.capacity() * sizeof(CharRange) + + transitionDestinations.capacity() * sizeof(uint32_t) + + nodes.capacity() * sizeof(DFANode); +} + +void DFA::shrinkToFit() +{ + nodes.shrinkToFit(); + actions.shrinkToFit(); + transitionRanges.shrinkToFit(); + transitionDestinations.shrinkToFit(); +} + +void DFA::minimize() +{ + DFAMinimizer::minimize(*this); +} + +unsigned DFA::graphSize() const +{ + unsigned count = 0; + for (const DFANode& node : nodes) { + if (!node.isKilled()) + ++count; + } + return count; +} + +#if CONTENT_EXTENSIONS_STATE_MACHINE_DEBUGGING +static void printRange(bool firstRange, char rangeStart, char rangeEnd) +{ + if (!firstRange) + dataLogF(", "); + if (rangeStart == rangeEnd) { + if (rangeStart == '"' || rangeStart == '\\') + dataLogF("\\%c", rangeStart); + else if (rangeStart >= '!' && rangeStart <= '~') + dataLogF("%c", rangeStart); + else + dataLogF("\\\\%d", rangeStart); + } else + dataLogF("\\\\%d-\\\\%d", rangeStart, rangeEnd); +} + +static void printTransitions(const DFA& dfa, unsigned sourceNodeId) +{ + const DFANode& sourceNode = dfa.nodes[sourceNodeId]; + auto transitions = sourceNode.transitions(dfa); + + if (transitions.begin() == transitions.end()) + return; + + HashMap<unsigned, Vector<uint16_t>, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> transitionsPerTarget; + + // First, we build the list of transitions coming to each target node. + for (const auto& transition : transitions) { + unsigned target = transition.target(); + transitionsPerTarget.add(target, Vector<uint16_t>()); + + for (unsigned offset = 0; offset < transition.range().size(); ++offset) + transitionsPerTarget.find(target)->value.append(transition.first() + offset); + } + + // Then we go over each one an display the ranges one by one. + for (const auto& transitionPerTarget : transitionsPerTarget) { + dataLogF(" %d -> %d [label=\"", sourceNodeId, transitionPerTarget.key); + + Vector<uint16_t> incommingCharacters = transitionPerTarget.value; + std::sort(incommingCharacters.begin(), incommingCharacters.end()); + + char rangeStart = incommingCharacters.first(); + char rangeEnd = rangeStart; + bool first = true; + for (unsigned sortedTransitionIndex = 1; sortedTransitionIndex < incommingCharacters.size(); ++sortedTransitionIndex) { + char nextChar = incommingCharacters[sortedTransitionIndex]; + if (nextChar == rangeEnd+1) { + rangeEnd = nextChar; + continue; + } + printRange(first, rangeStart, rangeEnd); + rangeStart = rangeEnd = nextChar; + first = false; + } + printRange(first, rangeStart, rangeEnd); + + dataLogF("\"];\n"); + } +} + +void DFA::debugPrintDot() const +{ + dataLogF("digraph DFA_Transitions {\n"); + dataLogF(" rankdir=LR;\n"); + dataLogF(" node [shape=circle];\n"); + dataLogF(" {\n"); + for (unsigned i = 0; i < nodes.size(); ++i) { + if (nodes[i].isKilled()) + continue; + + dataLogF(" %d [label=<Node %d", i, i); + const Vector<uint64_t>& actions = nodes[i].actions(*this); + if (!actions.isEmpty()) { + dataLogF("<BR/>Actions: "); + for (unsigned actionIndex = 0; actionIndex < actions.size(); ++actionIndex) { + if (actionIndex) + dataLogF(", "); + dataLogF("%llu", actions[actionIndex]); + } + } + dataLogF(">]"); + + if (!actions.isEmpty()) + dataLogF(" [shape=doublecircle]"); + + dataLogF(";\n"); + } + dataLogF(" }\n"); + + dataLogF(" {\n"); + for (unsigned i = 0; i < nodes.size(); ++i) + printTransitions(*this, i); + + dataLogF(" }\n"); + dataLogF("}\n"); +} +#endif + +} // namespace ContentExtensions + +} // namespace WebCore + +#endif // ENABLE(CONTENT_EXTENSIONS) |