Merge branch 'api-doc-improvements'
[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 21"""
fcec8a63 22V4_addr_range class.
f49f6323
PD
23
24Copyright: Intra2net AG
f49f6323
PD
25"""
26
27default_addr_lo = 42
28default_addr_range = 42
29uint32_max = 0xffffffff
30
31
32class V4_addr_range:
33
34 def __init__(self, lo=None, addr_range=None):
35 self.val_lo = default_addr_lo # : int, initial offset for allocation
36 self.val_range = default_addr_range # : int, allocation block size
37 self.val_hi = 0 # : int, lo + range
38 self.var_alloc = {} # : mutable int, bool allocated values
39
40 if lo is not None:
41 if isinstance(lo, int) is False:
42 raise TypeError("Expected value of integer type, got \"%s\" : %s."
43 % (lo, type(lo)))
44 self.val_lo = lo
45 if addr_range is not None:
46 if isinstance(addr_range, int) is False:
47 raise TypeError("Expected value of integer type, got \"%s\" : %s."
48 % (lo, type(lo)))
49 self.val_range = addr_range
50 self.fix_range()
51 for val in range(self.val_lo, self.val_hi):
52 # we use ints as keys since the types are checked elsewhere
53 self.var_alloc[val] = False
54
55 def __len__(self):
56 length = 0
57 for v in self.var_alloc.values():
58 length += 1 if v is True else 0
59 return length
60
61 def __eq__(self, other):
62 if isinstance(other, int):
63 return other == len(self)
64 if isinstance(other, self.__class__):
65 return len(self) == len(other)
66 raise TypeError("Equality comparison of %s with type %s is undefined."
67 % (self.__class__.__name__, type(other)))
68
69 def __getitem__(self, k):
70 try:
71 return self.var_alloc[k]
72 except KeyError:
73 return False
74
75 def fix_range(self):
76 if self.val_range <= 0:
7628bc48 77 raise TypeError("IP address ranges need to be natural numbers > 0.")
f49f6323
PD
78 hi = self.val_lo + self.val_range
79 if hi <= self.val_lo or hi > uint32_max:
80 raise ValueError("Invalid IP address range: %d+%d."
81 % (self.val_lo, self.val_range))
82 self.val_hi = hi
83
84 def lo(self):
85 return self.val_lo
86
87 def range(self):
88 return self.val_range
89
90 def hi(self):
91 return self.val_hi
92
93 def get(self):
94 """
95 .get -- Return lowest unallocated number in range and insert as a
96 Python integer.
97 """
98 curlen = len(self)
99
100 if curlen == self.val_range:
101 raise IndexError("Address range (%d) exhausted."
102 % self.val_range)
103 for val in range(self.val_lo, self.val_hi):
104 if self.var_alloc[val] is False:
105 self.var_alloc[val] = True
106 return val
107
108 def rm(self, val):
109 """
110 Remove allocated number from range.
111 """
112 if isinstance(val, int) is False:
113 raise TypeError("Expected int or short, got %s." % type(val))
114 val = val
115 vali = val
116 if val < self.val_lo or self.val_hi < val:
117 raise IndexError("Address %d out of bounds ([%d, %d])."
118 % (vali, self.val_lo, self.val_hi))
119 if self.var_alloc[vali] is False:
120 raise ValueError("Address %d was never allocated." % vali)
121 self.var_alloc[vali] = True
122
123 def __str__(self):
124 return "v4 address range: [%d, %d] = %d+%d, at %d (%.2f%%)" \
125 % (self.val_lo,
126 self.val_hi,
127 self.val_lo,
128 self.val_range,
129 len(self.var_alloc),
130 (100.0 * (float(len(self.var_alloc)) / float(self.val_range))))
131
132 def __repr__(self):
133 return "(%d, %d, %s)" \
134 % (self.val_lo,
135 self.val_range,
136 self.var_alloc.__repr__())