summaryrefslogtreecommitdiff
path: root/Source/WebCore/contentextensions/DFA.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/contentextensions/DFA.cpp')
-rw-r--r--Source/WebCore/contentextensions/DFA.cpp180
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)