aboutsummaryrefslogtreecommitdiff
path: root/bestflags/flags_util.py
blob: c4a490e2027f71fd5de091fd30f4b01268526fc3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# Copyright 2013 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Utility functions to explore the neighbor flags.

Part of the Chrome build flags optimization.
"""

__author__ = "yuhenglong@google.com (Yuheng Long)"

import flags
from flags import Flag


def ClimbNext(flags_dict, climb_spec):
    """Get the flags that are different from |flags_dict| by |climb_spec|.

    Given a set of flags, |flags_dict|, return a new set of flags that are
    adjacent along the flag spec |climb_spec|.

    An example flags_dict is {foo=[1-9]:foo=5, bar=[1-5]:bar=2} and climb_spec is
    bar=[1-5]. This method changes the flag that contains the spec bar=[1-5]. The
    results are its neighbors dictionaries, i.e., {foo=[1-9]:foo=5,
    bar=[1-5]:bar=1} and {foo=[1-9]:foo=5, bar=[1-5]:bar=3}.

    Args:
      flags_dict: The dictionary containing the original flags whose neighbors are
        to be explored.
      climb_spec: The spec in the flags_dict is to be changed. The spec is a
        definition in the little language, a string with escaped sequences of the
        form [<start>-<end>] where start and end is an positive integer for a
        fillable value. An example of a spec is "foo[0-9]".

    Returns:
      List of dictionaries of neighbor flags.
    """

    # This method searches for a pattern [start-end] in the spec. If the spec
    # contains this pattern, it is a numeric flag. Otherwise it is a boolean flag.
    # For example, -finline-limit=[1-1000] is a numeric flag and -falign-jumps is
    # a boolean flag.
    numeric_flag_match = flags.Search(climb_spec)

    # If the flags do not contain the spec.
    if climb_spec not in flags_dict:
        results = flags_dict.copy()

        if numeric_flag_match:
            # Numeric flags.
            results[climb_spec] = Flag(
                climb_spec, int(numeric_flag_match.group("start"))
            )
        else:
            # Boolean flags.
            results[climb_spec] = Flag(climb_spec)

        return [results]

    # The flags contain the spec.
    if not numeric_flag_match:
        # Boolean flags.
        results = flags_dict.copy()

        # Turn off the flag. A flag is turned off if it is not presented in the
        # flags_dict.
        del results[climb_spec]
        return [results]

    # Numeric flags.
    flag = flags_dict[climb_spec]

    # The value of the flag having spec.
    value = flag.GetValue()
    results = []

    if value + 1 < int(numeric_flag_match.group("end")):
        # If the value is not the end value, explore the value that is 1 larger than
        # the current value.
        neighbor = flags_dict.copy()
        neighbor[climb_spec] = Flag(climb_spec, value + 1)
        results.append(neighbor)

    if value > int(numeric_flag_match.group("start")):
        # If the value is not the start value, explore the value that is 1 lesser
        # than the current value.
        neighbor = flags_dict.copy()
        neighbor[climb_spec] = Flag(climb_spec, value - 1)
        results.append(neighbor)
    else:
        # Delete the value, i.e., turn off the flag. A flag is turned off if it is
        # not presented in the flags_dict.
        neighbor = flags_dict.copy()
        del neighbor[climb_spec]
        results.append(neighbor)

    return results