return found[0]
+def findIndex(list, pred):
+ """Finds the index of the first element satisfying 'pred' in a list, or
+ 'len(list)' if there is no such element."""
+ index = 0
+ for x in list:
+ if pred(x):
+ break
+ else:
+ index += 1
+ return index
+
+
class TestHasCompileFlag(SetupConfigs):
"""
Tests for libcxx.test.dsl.hasCompileFlag
args = ["first-argument", "second-argument"]
self.assertEqual(dsl.programOutput(self.config, source, args=args), "")
+ def test_caching_is_not_too_aggressive(self):
+ # Run a program, then change the substitutions and run it again.
+ # Make sure the program is run the second time and the right result
+ # is given, to ensure we're not incorrectly caching the result of the
+ # first program run.
+ source = """
+ #include <cstdio>
+ int main(int, char**) {
+ std::printf("MACRO=%u\\n", MACRO);
+ }
+ """
+ compileFlagsIndex = findIndex(self.config.substitutions, lambda x: x[0] == '%{compile_flags}')
+ compileFlags = self.config.substitutions[compileFlagsIndex][1]
+
+ self.config.substitutions[compileFlagsIndex] = ('%{compile_flags}', compileFlags + ' -DMACRO=1')
+ output1 = dsl.programOutput(self.config, source)
+ self.assertEqual(output1, "MACRO=1\n")
+
+ self.config.substitutions[compileFlagsIndex] = ('%{compile_flags}', compileFlags + ' -DMACRO=2')
+ output2 = dsl.programOutput(self.config, source)
+ self.assertEqual(output2, "MACRO=2\n")
+
+
class TestHasLocale(SetupConfigs):
"""
Tests for libcxx.test.dsl.hasLocale
#===----------------------------------------------------------------------===##
import os
+import pickle
import pipes
import platform
import re
"""
Allows memoizing a very expensive operation.
- The caching is implemented as a list, and we search linearly for existing
- entries. This is incredibly naive, however this allows the cache keys to
- contain lists and other non-hashable objects. Assuming the operation we're
- memoizing is very expensive, this is still a win anyway.
+ We pickle the cache key to make sure we store an immutable representation
+ of it. If we stored an object and the object was referenced elsewhere, it
+ could be changed from under our feet, which would break the cache.
"""
def decorator(function):
- cache = []
+ cache = {}
def f(*args, **kwargs):
- cacheKey = extractCacheKey(*args, **kwargs)
- try:
- result = next(res for (key, res) in cache if key == cacheKey)
- except StopIteration: # This wasn't in the cache
- result = function(*args, **kwargs)
- cache.append((cacheKey, result))
- return result
+ cacheKey = pickle.dumps(extractCacheKey(*args, **kwargs))
+ if cacheKey not in cache:
+ cache[cacheKey] = function(*args, **kwargs)
+ return cache[cacheKey]
return f
return decorator