File: BDF.py

package info (click to toggle)
amdsmi 6.1.2%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 4,744 kB
  • sloc: cpp: 30,276; python: 15,627; ansic: 6,319; sh: 586; makefile: 21
file content (130 lines) | stat: -rw-r--r-- 4,772 bytes parent folder | download
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#
# Copyright (C) 2023 Advanced Micro Devices. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

import logging
import re


class BDF():
    """ BDF Class to cast and compare BDF objects using built-in python comparators

    Useful for validating a BDF string and converting it to a BDF object
    This allows us to handle BDF objects in a pythonic way

    Attributes:
        __eq__: The equals comparator
        __: An integer count of the eggs we have laid.
    """
    def __init__(self, bdf):
        """Init a BDF object"""
        if isinstance(bdf, BDF):
            self.segment, self.bus, self.device, self.function = tuple(bdf)
        else:
            if bdf.startswith("BDF("):
                bdf = bdf.replace('BDF(', '').replace(')', '')

            try:
                bdf_components = [int(x, 16) for x in re.split('[:.]', bdf)]
            except self.BDFError as e:
                logging.error(f"Invalid string passed: {bdf}")
                raise e

            self.segment = bdf_components[0] if len(bdf_components) == 4 else 0
            self.bus, self.device, self.function = bdf_components[-3:]
            if self.segment > 65535:
                raise self.BDFError("Segment can't be greater than 65535")
            if self.bus > 255:
                raise self.BDFError("Bus can't be greater than 255")
            if self.device > 31:
                raise self.BDFError("Device can't be greater than 31")
            if self.function > 7:
                raise self.BDFError("Function can't be greater than 7")


    class BDFError(Exception):
        """BDF Class Error"""


    def __eq__(self, passed_bdf):
        """Overrides the == operator and allows for BDF objects to be compared to BDF strings"""

        # Only accept strings and BDF objects
        if isinstance(passed_bdf, str):
            if passed_bdf == '':
                return False
            passed_bdf = BDF(passed_bdf)
        elif not isinstance(passed_bdf, BDF):
            return False

        if self.segment   == passed_bdf.segment and \
            self.bus      == passed_bdf.bus and \
            self.device   == passed_bdf.device and \
            self.function == passed_bdf.function:
            return True
        else:
            return False


    def __ne__(self, passed_bdf):
        """Overrides the != operator and allows for BDF objects to be compared to BDF strings"""
        # Since we overrided the == operator we can use that to make this simple
        return not self == passed_bdf


    def __add__(self, passed_bdf):
        """Overrides the + operator and allows for string concatenation"""
        return str(self) + passed_bdf


    def __radd__(self, passed_bdf):
        """Overrides the + operator and allows for string concatenation"""
        return passed_bdf + str(self)


    def __str__(self):
        """Cast BDF object to a string"""
        return "{:04X}:{:02X}:{:02X}:{}".format(self.segment, self.bus, self.device, self.function)


    def __repr__(self):
        """How the BDF object is represented"""
        return f"BDF({self})"


    def __hash__(self):
        """Allow the BDF object to be hashable"""
        return hash(str(self))


    def __iter__(self):
        """Make the BDF object iterable over its 4 values"""
        yield from (self.segment, self.bus, self.device, self.function)


    def __contains__(self, passed_bdf):
        """Overrided the 'in' comparator in python"""
        passed_bdf = str(BDF(passed_bdf))

        bdf_regex = "(?:[0-6]?[0-9a-fA-F]{1,4}:)?[0-2]?[0-9a-fA-F]{1,2}:[0-9a-fA-F]{1,2}\\.[0-7]"
        for match in re.findall(bdf_regex, passed_bdf):
            if self == match:
                return True
        return False