parent
122fa2f689
commit
c38a234691
@ -0,0 +1,3 @@ |
||||
#![feature(btree_cursors)] |
||||
|
||||
pub mod ranged_number_allocator; |
@ -0,0 +1,88 @@ |
||||
use std::{collections::BTreeMap, ops::Bound}; |
||||
|
||||
pub struct RangedNumberAllocator { |
||||
pub tree: BTreeMap<u32, u32>, |
||||
} |
||||
|
||||
impl RangedNumberAllocator { |
||||
pub fn new() -> Self { |
||||
RangedNumberAllocator { |
||||
tree: BTreeMap::new() |
||||
} |
||||
} |
||||
|
||||
pub fn remove(&mut self, value: u32) { |
||||
let mut cursor = self.tree.upper_bound_mut(Bound::Included(&value)); |
||||
if let Some((&range_start, &range_end)) = cursor.key_value() { |
||||
if range_end >= value { |
||||
// The found range covers the requested value, meaning this value was previously used. Now there are four scenarios:
|
||||
// 1. It's [value, value]; we should remove it;
|
||||
// 2. It's [value, x] where x > value; we should replace it with [value+1, x];
|
||||
// 3. It's [x, value] where value > x; we should change it to [x, value-1];
|
||||
// 4. It's [x, y] where x < value < y; we should replace it with [x, value-1] and [value+1, y].
|
||||
if range_start == value && range_end == value { |
||||
// Scenario 1
|
||||
cursor.remove_current().unwrap(); |
||||
} else if range_start == value { |
||||
// Scenario 2
|
||||
cursor.insert_after(value + 1, range_end); |
||||
cursor.remove_current().unwrap(); |
||||
} else if range_end == value { |
||||
// Scenario 3
|
||||
*cursor.value_mut().unwrap() = value - 1; |
||||
} else { |
||||
// Scenario 4
|
||||
cursor.insert_after(value + 1, range_end); |
||||
*cursor.value_mut().unwrap() = value - 1; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
pub fn allocate(&mut self) -> u32 { |
||||
let mut cursor = self.tree.lower_bound_mut(Bound::Unbounded); |
||||
// Six scenarios:
|
||||
// 1. Tree is empty; we should add [1, 1] range and return 1;
|
||||
// 2. Tree has only one range [1, x]; we should change it to [1, x+1] and return x+1;
|
||||
// 3. Tree has at least first two ranges, [1, x] and [x+2, y]; we should replace them with [1, y] and return x+1;
|
||||
// 4. Tree has at least first two ranges, [1, x] and [y, z] where y > x+2; we should change the first range to [1, x+1] and return x+1;
|
||||
// 5. Tree has at least first range [2, x]; we should replace it with [1, x] and return 1;
|
||||
// 6. Tree has at least first range [x, y] where x > 2; we should add [1, 1] and return 1.
|
||||
if let Some((&range_start, &range_end)) = cursor.key_value() { |
||||
// There is at least one range; eliminated scenario 1, left with 2-6.
|
||||
if range_start == 1 { |
||||
// First range starts with 1; eliminated scenarios 5-6, left with 2-4.
|
||||
if let Some((&next_range_start, &mut next_range_end)) = cursor.peek_next() { |
||||
// There is another range; eliminated scenario 2, left with 3-4
|
||||
if next_range_start == range_end + 2 { |
||||
// Scenario 3
|
||||
*cursor.value_mut().unwrap() = next_range_end; |
||||
cursor.move_next(); |
||||
cursor.remove_current_and_move_back().unwrap(); |
||||
return range_end + 1; |
||||
} else { |
||||
// Scenario 4
|
||||
*cursor.value_mut().unwrap() = range_end + 1; |
||||
return range_end + 1; |
||||
} |
||||
} else { |
||||
// Scenario 2
|
||||
*cursor.value_mut().unwrap() = range_end + 1; |
||||
return range_end + 1; |
||||
} |
||||
} else if range_start == 2 { |
||||
// Scenario 5
|
||||
cursor.insert_before(1, range_end); |
||||
cursor.remove_current().unwrap(); |
||||
return 1; |
||||
} else { |
||||
// Scenario 6
|
||||
cursor.insert_before(1, 1); |
||||
return 1; |
||||
} |
||||
} else { |
||||
cursor.insert_after(1, 1); |
||||
return 1; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,111 @@ |
||||
extern crate hostnames_allocator; |
||||
|
||||
use hostnames_allocator::ranged_number_allocator::RangedNumberAllocator; |
||||
|
||||
fn create_allocator(data: &[(u32, u32)]) -> RangedNumberAllocator { |
||||
RangedNumberAllocator { |
||||
tree: data.to_owned().into_iter().collect() |
||||
} |
||||
} |
||||
|
||||
fn check_allocator(allocator: RangedNumberAllocator, expected: &[(u32, u32)]) { |
||||
itertools::assert_equal(allocator.tree, expected.to_owned()); |
||||
} |
||||
|
||||
#[test] |
||||
fn remove_preserves_tree_when_empty() { |
||||
let mut allocator = create_allocator(&[]); |
||||
allocator.remove(5); |
||||
check_allocator(allocator, &[]); |
||||
} |
||||
|
||||
#[test] |
||||
fn remove_preserves_tree_when_not_found() { |
||||
let mut allocator = create_allocator(&[(1, 3), (11, 13)]); |
||||
allocator.remove(5); |
||||
check_allocator(allocator, &[(1, 3), (11, 13)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn remove_removes_range_with_single_value() { |
||||
let mut allocator = create_allocator(&[(1, 3), (5, 5), (11, 13)]); |
||||
allocator.remove(5); |
||||
check_allocator(allocator, &[(1, 3), (11, 13)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn remove_replaces_range_starting_with_value() { |
||||
let mut allocator = create_allocator(&[(1, 3), (5, 7), (11, 13)]); |
||||
allocator.remove(5); |
||||
check_allocator(allocator, &[(1, 3), (6, 7), (11, 13)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn remove_changes_range_ending_with_value() { |
||||
let mut allocator = create_allocator(&[(1, 3), (5, 7), (11, 13)]); |
||||
allocator.remove(7); |
||||
check_allocator(allocator, &[(1, 3), (5, 6), (11, 13)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn remove_splits_range_containing_value() { |
||||
let mut allocator = create_allocator(&[(1, 3), (5, 9), (11, 13)]); |
||||
allocator.remove(7); |
||||
check_allocator(allocator, &[(1, 3), (5, 6), (8, 9), (11, 13)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn remove_removes_last_value() { |
||||
let mut allocator = create_allocator(&[(5, 5)]); |
||||
allocator.remove(5); |
||||
check_allocator(allocator, &[]); |
||||
} |
||||
|
||||
#[test] |
||||
fn allocate_initializes_empty() { |
||||
let mut allocator = create_allocator(&[]); |
||||
assert_eq!(allocator.allocate(), 1); |
||||
check_allocator(allocator, &[(1, 1)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn allocate_adds_second_value() { |
||||
let mut allocator = create_allocator(&[(1, 1)]); |
||||
assert_eq!(allocator.allocate(), 2); |
||||
check_allocator(allocator, &[(1, 2)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn allocate_adds_tenth_value() { |
||||
let mut allocator = create_allocator(&[(1, 9)]); |
||||
assert_eq!(allocator.allocate(), 10); |
||||
check_allocator(allocator, &[(1, 10)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn allocate_adds_value_for_two_ranges_starting_with_one() { |
||||
let mut allocator = create_allocator(&[(1, 5), (10, 15)]); |
||||
assert_eq!(allocator.allocate(), 6); |
||||
check_allocator(allocator, &[(1, 6), (10, 15)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn allocate_combines_two_adjacent_ranges_starting_with_one() { |
||||
let mut allocator = create_allocator(&[(1, 5), (7, 15)]); |
||||
assert_eq!(allocator.allocate(), 6); |
||||
check_allocator(allocator, &[(1, 15)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn allocate_adds_value_for_range_starting_with_two() { |
||||
let mut allocator = create_allocator(&[(2, 10)]); |
||||
assert_eq!(allocator.allocate(), 1); |
||||
check_allocator(allocator, &[(1, 10)]); |
||||
} |
||||
|
||||
#[test] |
||||
fn allocate_adds_value_for_range_starting_with_ten() { |
||||
let mut allocator = create_allocator(&[(10, 20)]); |
||||
assert_eq!(allocator.allocate(), 1); |
||||
check_allocator(allocator, &[(1, 1), (10, 20)]); |
||||
} |
Loading…
Reference in new issue