xref: /petsc/config/BuildSystem/config/util.py (revision 7b5fd022a6ba26727040df7457b27566b4c6742d)
1# Stateless utilities
2#
3# This entire module is exported into the config.* namespace (see
4# __init__.py), so be careful to avoid namespace conflicts.  Do not
5# import config.util directly.  Instead, import config and access only
6# the exported objects.
7
8def classify(items, functional, args=(), kwargs=dict()):
9    '''Classify items as True or False using boolean functional on sets.
10
11    An item can only be identified as False if functional([item]) is
12    false, but an item is True if functional(List) is True and item in
13    List.
14
15    Functional may return True (all items are True), False (at least one
16    item is False) or a list of suggestions for items that may have been
17    False (implies that at least one item is False).  The list of
18    suggestions does not have to be accurate, but classification will be
19    faster if it is accurate.
20    '''
21    items = list(items)         # In case a set or other iterable was passed in
22
23    result = functional(items, *args, **kwargs)
24    if result is True:
25        return items, []        # All succeeded
26    if len(items) == 1:
27        return [], items        # Sole failure
28    if result is False:
29        suggested = []
30    else:
31        suggested = list(result)
32    items = [i for i in items if i not in suggested]
33    good = []
34    bad = []
35    if len(items) < 5:          # linear check
36        groups = [[i] for i in items]
37    else:                       # bisect
38        groups = [items[:len(items)//2], items[len(items)//2:]]
39    groups += [[i] for i in suggested]
40    for grp in groups:
41        g, b = classify(grp, functional, args, kwargs)
42        good += g
43        bad += b
44    return good, bad
45
46class NamedInStderr:
47    '''Hepler class to log the (string) items that are written to stderr on failure.
48
49    In the common case, all the missing items are named in the linker
50    error and the rest can be confirmed True in a single batch.
51    '''
52    def __init__(self, items):
53        self.named = []
54        self.items = items
55
56    def examineStderr(self, ret, out, err):
57        if ret:
58            self.named += [i for i in self.items if i in err]
59
60class memoize(dict):
61    '''Memoizing decorator.  No support for keyword arguments.'''
62    def __init__(self, func):
63        self.func = func
64
65    def __call__(self, *args):
66        try:
67            return self[args]
68        except KeyError:
69            ret = self[args] = self.func(*args)
70            return ret
71