Clean up, remove compat with py < 3.6
[pyi2ncommon] / src / v4_addr_range.py
CommitLineData
11cbb815
PD
1# The software in this package is distributed under the GNU General
2# Public License version 2 (with a special exception described below).
3#
4# A copy of GNU General Public License (GPL) is included in this distribution,
5# in the file COPYING.GPL.
6#
7# As a special exception, if other files instantiate templates or use macros
8# or inline functions from this file, or you compile this file and link it
9# with other works to produce a work based on this file, this file
10# does not by itself cause the resulting work to be covered
11# by the GNU General Public License.
12#
13# However the source code for this file must still be made available
14# in accordance with section (3) of the GNU General Public License.
15#
16# This exception does not invalidate any other reasons why a work based
17# on this file might be covered by the GNU General Public License.
18#
19# Copyright (c) 2016-2018 Intra2net AG <info@intra2net.com>
20
f49f6323
PD
21"""
22
23SUMMARY
24------------------------------------------------------
25V4_addr_range class
26
27Copyright: Intra2net AG
28
29
30INTERFACE
31------------------------------------------------------
32
33"""
34
35default_addr_lo = 42
36default_addr_range = 42
37uint32_max = 0xffffffff
38
39
40class V4_addr_range:
41
42 def __init__(self, lo=None, addr_range=None):
43 self.val_lo = default_addr_lo # : int, initial offset for allocation
44 self.val_range = default_addr_range # : int, allocation block size
45 self.val_hi = 0 # : int, lo + range
46 self.var_alloc = {} # : mutable int, bool allocated values
47
48 if lo is not None:
49 if isinstance(lo, int) is False:
50 raise TypeError("Expected value of integer type, got \"%s\" : %s."
51 % (lo, type(lo)))
52 self.val_lo = lo
53 if addr_range is not None:
54 if isinstance(addr_range, int) is False:
55 raise TypeError("Expected value of integer type, got \"%s\" : %s."
56 % (lo, type(lo)))
57 self.val_range = addr_range
58 self.fix_range()
59 for val in range(self.val_lo, self.val_hi):
60 # we use ints as keys since the types are checked elsewhere
61 self.var_alloc[val] = False
62
63 def __len__(self):
64 length = 0
65 for v in self.var_alloc.values():
66 length += 1 if v is True else 0
67 return length
68
69 def __eq__(self, other):
70 if isinstance(other, int):
71 return other == len(self)
72 if isinstance(other, self.__class__):
73 return len(self) == len(other)
74 raise TypeError("Equality comparison of %s with type %s is undefined."
75 % (self.__class__.__name__, type(other)))
76
77 def __getitem__(self, k):
78 try:
79 return self.var_alloc[k]
80 except KeyError:
81 return False
82
83 def fix_range(self):
84 if self.val_range <= 0:
7628bc48 85 raise TypeError("IP address ranges need to be natural numbers > 0.")
f49f6323
PD
86 hi = self.val_lo + self.val_range
87 if hi <= self.val_lo or hi > uint32_max:
88 raise ValueError("Invalid IP address range: %d+%d."
89 % (self.val_lo, self.val_range))
90 self.val_hi = hi
91
92 def lo(self):
93 return self.val_lo
94
95 def range(self):
96 return self.val_range
97
98 def hi(self):
99 return self.val_hi
100
101 def get(self):
102 """
103 .get -- Return lowest unallocated number in range and insert as a
104 Python integer.
105 """
106 curlen = len(self)
107
108 if curlen == self.val_range:
109 raise IndexError("Address range (%d) exhausted."
110 % self.val_range)
111 for val in range(self.val_lo, self.val_hi):
112 if self.var_alloc[val] is False:
113 self.var_alloc[val] = True
114 return val
115
116 def rm(self, val):
117 """
118 Remove allocated number from range.
119 """
120 if isinstance(val, int) is False:
121 raise TypeError("Expected int or short, got %s." % type(val))
122 val = val
123 vali = val
124 if val < self.val_lo or self.val_hi < val:
125 raise IndexError("Address %d out of bounds ([%d, %d])."
126 % (vali, self.val_lo, self.val_hi))
127 if self.var_alloc[vali] is False:
128 raise ValueError("Address %d was never allocated." % vali)
129 self.var_alloc[vali] = True
130
131 def __str__(self):
132 return "v4 address range: [%d, %d] = %d+%d, at %d (%.2f%%)" \
133 % (self.val_lo,
134 self.val_hi,
135 self.val_lo,
136 self.val_range,
137 len(self.var_alloc),
138 (100.0 * (float(len(self.var_alloc)) / float(self.val_range))))
139
140 def __repr__(self):
141 return "(%d, %d, %s)" \
142 % (self.val_lo,
143 self.val_range,
144 self.var_alloc.__repr__())