1extern crate free_ranges;
31
32use free_ranges::FreeRanges;
33use free_ranges::Range;
34
35use std::error::Error;
36use std::fmt;
37use std::usize;
38
39pub mod iter;
40
41#[derive(Debug)]
44pub struct IndexPool {
45 next_id: usize,
46 in_use: usize,
47 free_list: FreeRanges,
48}
49
50impl IndexPool {
51 #[inline]
53 pub fn new() -> Self {
54 Self::with_initial_index(0)
55 }
56
57 pub fn with_initial_index(index: usize) -> Self {
65 IndexPool {
66 next_id: index,
67 in_use: 0,
68 free_list: FreeRanges::new(),
69 }
70 }
71
72 #[inline]
76 pub fn new_id(&mut self) -> usize {
77 self.in_use += 1;
78
79 if let Some(id) = self.free_list.set_first_used() {
80 return id;
81 }
82
83 let id = self.next_id;
84 self.next_id += 1;
85 return id;
86 }
87
88 #[inline]
89 pub fn request_id(&mut self, id: usize) -> Result<(), AlreadyInUse> {
91 assert!(id < usize::MAX);
92 if id == self.next_id {
93 self.next_id += 1;
94 self.in_use += 1;
95 Ok(())
96 } else if id > self.next_id {
97 self.free_list.set_range_free(Range {
98 min: self.next_id,
99 max: id - 1,
100 });
101 self.next_id = id + 1;
102 self.in_use += 1;
103
104 Ok(())
105 } else if self.free_list.set_used(id) {
106 self.in_use += 1;
107 Ok(())
108 } else {
109 Err(AlreadyInUse)
110 }
111 }
112
113 #[inline]
117 pub fn return_id(&mut self, id: usize) -> Result<(), AlreadyReturned> {
118 if id >= self.next_id {
119 return Err(AlreadyReturned);
120 }
121
122 if id + 1 == self.next_id {
123 self.next_id -= 1;
124 } else {
125 if !self.free_list.set_free(id) {
126 return Err(AlreadyReturned);
127 }
128 assert!(self.free_list.is_free(id));
129 }
130
131 self.in_use -= 1;
132
133 while self.collapse_next() {}
134
135 Ok(())
136 }
137
138 #[inline]
143 pub fn maximum(&self) -> usize {
144 self.next_id
145 }
146
147 #[inline]
149 pub fn in_use(&self) -> usize {
150 self.in_use
151 }
152
153 #[inline]
154 pub fn is_free(&self, id: usize) -> bool {
156 id >= self.next_id || self.free_list.is_free(id)
157 }
158
159 #[inline]
161 pub fn all_indices(&self) -> iter::IndexIter {
162 iter::IndexIter::new(self.free_list.free_ranges(), self.next_id)
163 }
164
165 #[inline]
166 pub fn all_indices_after(&self, after: usize) -> iter::IndexAfterIter {
167 iter::IndexAfterIter::new(self.free_list.free_ranges_after(after), after, self.next_id)
168 }
169
170 #[inline]
171 fn collapse_next(&mut self) -> bool {
172 if let Some(last_range) = self.free_list.free_ranges().rev().nth(0).cloned() {
173 if last_range.max + 1 == self.next_id {
174 self.free_list.remove_last_contiguous();
175 self.next_id = last_range.min;
176 return true;
177 }
178 }
179
180 false
181 }
182
183 #[inline]
184 pub fn clear(&mut self) {
185 self.free_list.clear();
186 self.in_use = 0;
187 self.next_id = 0;
188 }
189}
190
191impl Default for IndexPool {
192 #[inline]
194 fn default() -> Self {
195 IndexPool::new()
196 }
197}
198
199#[derive(Debug, PartialEq, Eq)]
200pub struct AlreadyReturned;
201
202impl fmt::Display for AlreadyReturned {
203 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
204 fmt.write_str(self.description())
205 }
206}
207
208impl Error for AlreadyReturned {
209 fn description(&self) -> &str {
210 "An index was tried to be returned to the pool, but it was already marked as free."
211 }
212}
213
214#[derive(Debug, PartialEq, Eq)]
215pub struct AlreadyInUse;
216
217impl fmt::Display for AlreadyInUse {
218 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
219 fmt.write_str(self.description())
220 }
221}
222
223impl Error for AlreadyInUse {
224 fn description(&self) -> &str {
225 "An index was requested which was already marked as in use."
226 }
227}