aboutsummaryrefslogtreecommitdiff
path: root/src/gfxstream/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/algo.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/gfxstream/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/algo.py')
-rw-r--r--src/gfxstream/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/algo.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/gfxstream/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/algo.py b/src/gfxstream/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/algo.py
new file mode 100644
index 00000000000..e9dff4a13ad
--- /dev/null
+++ b/src/gfxstream/codegen/vulkan/vulkan-docs-next/scripts/spec_tools/algo.py
@@ -0,0 +1,145 @@
+#!/usr/bin/python3 -i
+#
+# Copyright (c) 2019 Collabora, Ltd.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Author(s): Ryan Pavlik <ryan.pavlik@collabora.com>
+"""RecursiveMemoize serves as a base class for a function modeled
+as a dictionary computed on-the-fly."""
+
+
+class RecursiveMemoize:
+ """Base class for functions that are recursive.
+
+ Derive and implement `def compute(self, key):` to perform the computation:
+ you may use __getitem__ (aka self[otherkey]) to access the results for
+ another key. Each value will be computed at most once. Your
+ function should never return None, since it is used as a sentinel here.
+
+ """
+
+ def __init__(self, func, key_iterable=None, permit_cycles=False):
+ """Initialize data structures, and optionally compute/cache the answer
+ for all elements of an iterable.
+
+ If permit_cycles is False, then __getitem__ on something that's
+ currently being computed raises an exception.
+ If permit_cycles is True, then __getitem__ on something that's
+ currently being computed returns None.
+ """
+ self._compute = func
+ self.permit_cycles = permit_cycles
+ self.d = {}
+ if key_iterable:
+ # If we were given an iterable, let's populate those.
+ for key in key_iterable:
+ _ = self[key]
+
+ def __getitem__(self, key):
+ """Access the result of computing the function on the input.
+
+ Performed lazily and cached.
+ Implement `def compute(self, key):` with the actual function,
+ which will be called on demand."""
+ if key in self.d:
+ ret = self.d[key]
+ # Detect "we're computing this" sentinel and
+ # fail if cycles not permitted
+ if ret is None and not self.permit_cycles:
+ raise RuntimeError("Cycle detected when computing function: " +
+ "f({}) depends on itself".format(key))
+ # return the memoized value
+ # (which might be None if we're in a cycle that's permitted)
+ return ret
+
+ # Set sentinel for "we're computing this"
+ self.d[key] = None
+ # Delegate to function to actually compute
+ ret = self._compute(key)
+ # Memoize
+ self.d[key] = ret
+
+ return ret
+
+ def get_dict(self):
+ """Return the dictionary where memoized results are stored.
+
+ DO NOT MODIFY!"""
+ return self.d
+
+
+def longest_common_prefix(strings):
+ """
+ Find the longest common prefix of a list of 2 or more strings.
+
+ Args:
+ strings (collection): at least 2 strings.
+
+ Returns:
+ string: The longest string that all submitted strings start with.
+
+ >>> longest_common_prefix(["abcd", "abce"])
+ 'abc'
+
+ """
+ assert(len(strings) > 1)
+ a = min(strings)
+ b = max(strings)
+ prefix = []
+ for a_char, b_char in zip(a, b):
+ if a_char == b_char:
+ prefix.append(a_char)
+ else:
+ break
+ return "".join(prefix)
+
+
+def longest_common_token_prefix(strings, delimiter='_'):
+ """
+ Find the longest common token-wise prefix of a list of 2 or more strings.
+
+ Args:
+ strings (collection): at least 2 strings.
+ delimiter (character): the character to split on.
+
+ Returns:
+ string: The longest string that all submitted strings start with.
+
+ >>> longest_common_token_prefix(["xr_abc_123", "xr_abc_567"])
+ 'xr_abc_'
+
+ "1" is in the per-character longest common prefix, but 123 != 135,
+ so it's not in the per-token prefix.
+
+ >>> longest_common_token_prefix(["xr_abc_123", "xr_abc_135"])
+ 'xr_abc_'
+
+ Here, the prefix is actually the entirety of one string, so no trailing delimiter.
+
+ >>> longest_common_token_prefix(["xr_abc_123", "xr_abc"])
+ 'xr_abc'
+
+
+ No common prefix here, because it's per-token:
+
+ >>> longest_common_token_prefix(["abc_123", "ab_123"])
+ ''
+
+ """
+ assert(len(strings) > 1)
+ a = min(strings).split(delimiter)
+ b = max(strings).split(delimiter)
+ prefix_tokens = []
+ for a_token, b_token in zip(a, b):
+ if a_token == b_token:
+ prefix_tokens.append(a_token)
+ else:
+ break
+ if prefix_tokens:
+ prefix = delimiter.join(prefix_tokens)
+ if len(prefix_tokens) < min(len(a), len(b)):
+ # This is truly a prefix, not just one of the strings.
+ prefix += delimiter
+ return prefix
+ return ''