summaryrefslogtreecommitdiff
path: root/src/engine/SCons/Scanner/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/SCons/Scanner/__init__.py')
-rw-r--r--src/engine/SCons/Scanner/__init__.py104
1 files changed, 57 insertions, 47 deletions
diff --git a/src/engine/SCons/Scanner/__init__.py b/src/engine/SCons/Scanner/__init__.py
index cbab50c3..1968a9e3 100644
--- a/src/engine/SCons/Scanner/__init__.py
+++ b/src/engine/SCons/Scanner/__init__.py
@@ -34,7 +34,6 @@ import string
import SCons.Node.FS
import SCons.Sig
-import SCons.UserTuple
import SCons.Util
@@ -54,51 +53,51 @@ def Scanner(function, *args, **kw):
else:
return apply(Base, (function,) + args, kw)
-# Important, important, important performance optimization:
-#
-# The paths of Nodes returned from a FindPathDirs will be used to index
-# a dictionary that caches the values, so we don't have to look up the
-# same path over and over and over. If FindPathDir returns just a tuple,
-# though, then the time it takes to compute the hash of the tuple grows
-# proportionally to the length of the tuple itself--and some people can
-# have very, very long strings of include directories...
-#
-# The solution is to wrap the tuple in an object, a UserTuple class
-# whose *id()* our caller can use to cache the appropriate value.
-# This means we have to guarantee that these ids genuinely represent
-# unique values, which we do by maintaining our own cache that maps the
-# expensive-to-hash tuple values to the easy-to-hash UniqueUserTuple
-# values that our caller uses.
-#
-# *Major* kudos to Eric Frias and his colleagues for finding this.
-class UniqueUserTuple(SCons.UserTuple.UserTuple):
- def __hash__(self):
- return id(self)
-
-PathCache = {}
+class Binder:
+ __metaclass__ = SCons.Memoize.Memoized_Metaclass
+ def __init__(self, bindval):
+ self._val = bindval
+ def __call__(self):
+ return self._val
+ def __str__(self):
+ return str(self._val)
+ #debug: return 'B<%s>'%str(self._val)
+
class FindPathDirs:
"""A class to bind a specific *PATH variable name and the fs object
to a function that will return all of the *path directories."""
+ __metaclass__ = SCons.Memoize.Memoized_Metaclass
def __init__(self, variable, fs):
self.variable = variable
self.fs = fs
def __call__(self, env, dir, argument=None):
+ "__cacheable__"
try:
path = env[self.variable]
except KeyError:
return ()
path_tuple = tuple(self.fs.Rsearchall(env.subst_path(path),
- must_exist = 0,
+ must_exist = 0, #kwq!
clazz = SCons.Node.FS.Dir,
cwd = dir))
- try:
- return PathCache[path_tuple]
- except KeyError:
- path_UserTuple = UniqueUserTuple(path_tuple)
- PathCache[path_tuple] = path_UserTuple
- return path_UserTuple
+ return Binder(path_tuple)
+
+if not SCons.Memoize.has_metaclass:
+ _FPD_Base = FindPathDirs
+ class FindPathDirs(SCons.Memoize.Memoizer, _FPD_Base):
+ "Cache-backed version of FindPathDirs"
+ def __init__(self, *args, **kw):
+ apply(_FPD_Base.__init__, (self,)+args, kw)
+ SCons.Memoize.Memoizer.__init__(self)
+ _BinderBase = Binder
+ class Binder(SCons.Memoize.Memoizer, _BinderBase):
+ "Cache-backed version of Binder"
+ def __init__(self, *args, **kw):
+ apply(_BinderBase.__init__, (self,)+args, kw)
+ SCons.Memoize.Memoizer.__init__(self)
+
class Base:
"""
@@ -106,6 +105,8 @@ class Base:
straightforward, single-pass scanning of a single file.
"""
+ __metaclass__ = SCons.Memoize.Memoized_Metaclass
+
def __init__(self,
function,
name = "NONE",
@@ -135,6 +136,8 @@ class Base:
(a construction environment, optional directory, and optional
argument for this instance) and returns a tuple of the
directories that can be searched for implicit dependency files.
+ May also return a callable() which is called with no args and
+ returns the tuple (supporting Bindable class).
'node_class' - the class of Nodes which this scan will return.
If node_class is None, then this scanner will not enforce any
@@ -186,6 +189,7 @@ class Base:
self.recursive = recursive
def path(self, env, dir = None):
+ "__cacheable__"
if not self.path_function:
return ()
if not self.argument is _null:
@@ -242,6 +246,14 @@ class Base:
def select(self, node):
return self
+if not SCons.Memoize.has_metaclass:
+ _Base = Base
+ class Base(SCons.Memoize.Memoizer, _Base):
+ "Cache-backed version of Scanner Base"
+ def __init__(self, *args, **kw):
+ apply(_Base.__init__, (self,)+args, kw)
+ SCons.Memoize.Memoizer.__init__(self)
+
class Selector(Base):
"""
@@ -296,22 +308,12 @@ class Classic(Current):
self.cre = re.compile(regex, re.M)
self.fs = fs
- self._cached = {}
def _scan(node, env, path=(), self=self):
node = node.rfile()
-
if not node.exists():
return []
-
- key = str(id(node)) + '|' + string.join(map(str, path), ':')
- try:
- return self._cached[key]
- except KeyError:
- pass
-
- self._cached[key] = scan_result = self.scan(node, path)
- return scan_result
+ return self.scan(node, path)
kw['function'] = _scan
kw['path_function'] = FindPathDirs(path_variable, fs)
@@ -322,6 +324,8 @@ class Classic(Current):
apply(Current.__init__, (self,) + args, kw)
def find_include(self, include, source_dir, path):
+ "__cacheable__"
+ if callable(path): path = path()
n = SCons.Node.FS.find_file(include,
(source_dir,) + tuple(path),
self.fs.File)
@@ -331,6 +335,7 @@ class Classic(Current):
return SCons.Node.FS._my_normcase(include)
def scan(self, node, path=()):
+ "__cacheable__"
# cache the includes list in node so we only scan it once:
if node.includes != None:
@@ -372,14 +377,19 @@ class ClassicCPP(Classic):
the contained filename in group 1.
"""
def find_include(self, include, source_dir, path):
+ "__cacheable__"
+ if callable(path):
+ path = path() #kwq: extend callable to find_file...
+
if include[0] == '"':
- n = SCons.Node.FS.find_file(include[1],
- (source_dir,) + tuple(path),
- self.fs.File)
+ paths = Binder( (source_dir,) + tuple(path) )
else:
- n = SCons.Node.FS.find_file(include[1],
- tuple(path) + (source_dir,),
- self.fs.File)
+ paths = Binder( tuple(path) + (source_dir,) )
+
+ n = SCons.Node.FS.find_file(include[1],
+ paths,
+ self.fs.File)
+
return n, include[1]
def sort_key(self, include):