addressable.rs98.77%
1
// Copyright 2024 Google LLC2
//3
// Licensed under the Apache License, Version 2.0 (the "License");4
// you may not use this file except in compliance with the License.5
// You may obtain a copy of the License at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// distributed under the License is distributed on an "AS IS" BASIS,11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12
// See the License for the specific language governing permissions and13
// limitations under the License.14
15
use std::ops::RangeBounds;16
17
use crate::mem::{Result, error};18
19
pub trait SlotBackend {20
fn size(&self) -> u64;21
}22
23
#[derive(Debug)]24
struct Slot<B>25
where26
B: SlotBackend,27
{28
addr: u64,29
backend: B,30
}31
32
impl<B> Slot<B>33
where34
B: SlotBackend,35
{36
fn new(addr: u64, backend: B) -> Result<Self> {744x37
if backend.size() == 0 {744x38
return error::ZeroSizedSlot.fail();3x39
}741x40
match (backend.size() - 1).checked_add(addr) {741x41
None => error::ExceedsLimit {3x42
addr,3x43
size: backend.size(),3x44
}3x45
.fail(),3x46
Some(_) => Ok(Self { addr, backend }),738x47
}48
}744x49
50
fn max_addr(&self) -> u64 {2661x51
(self.backend.size() - 1) + self.addr2661x52
}2661x53
}54
55
#[derive(Debug)]56
pub struct Addressable<B>57
where58
B: SlotBackend,59
{60
slots: Vec<Slot<B>>,61
}62
63
impl<B> Default for Addressable<B>64
where65
B: SlotBackend,66
{67
fn default() -> Self {307x68
Addressable { slots: Vec::new() }307x69
}307x70
}71
72
impl<B> Addressable<B>73
where74
B: SlotBackend,75
{76
pub fn new() -> Self {226x77
Self::default()226x78
}226x79
80
pub fn iter(&self) -> impl DoubleEndedIterator<Item = (u64, &B)> {27x81
self.slots.iter().map(|slot| (slot.addr, &slot.backend))39x82
}27x83
84
pub fn drain(12x85
&mut self,12x86
range: impl RangeBounds<usize>,12x87
) -> impl DoubleEndedIterator<Item = (u64, B)> + '_ {12x88
self.slots.drain(range).map(|s| (s.addr, s.backend))12x89
}12x90
91
pub fn is_empty(&self) -> bool {92x92
self.slots.is_empty()92x93
}92x94
95
pub fn last(&self) -> Option<(u64, &B)> {3x96
self.slots.last().map(|slot| (slot.addr, &slot.backend))3x97
}3x98
}99
100
impl<B> Addressable<B>101
where102
B: SlotBackend,103
{104
pub fn add(&mut self, addr: u64, backend: B) -> Result<&mut B> {735x105
let slot = Slot::new(addr, backend)?;735x106
let result = match self.slots.binary_search_by_key(&addr, |s| s.addr) {735x107
Ok(index) => Err(&self.slots[index]),3x108
Err(index) => {732x109
if index < self.slots.len() && self.slots[index].addr <= slot.max_addr() {732x110
Err(&self.slots[index])9x111
} else if index > 0 && slot.addr <= self.slots[index - 1].max_addr() {723x112
Err(&self.slots[index - 1])9x113
} else {114
Ok(index)714x115
}116
}117
};118
match result {735x119
Err(curr_slot) => error::Overlap {21x120
new_item: [slot.addr, slot.max_addr()],21x121
exist_item: [curr_slot.addr, curr_slot.max_addr()],21x122
}21x123
.fail(),21x124
Ok(index) => {714x125
self.slots.insert(index, slot);714x126
// TODO add some compiler hint to eliminate bound check?127
Ok(&mut self.slots[index].backend)714x128
}129
}130
}735x131
132
pub fn remove(&mut self, addr: u64) -> Result<B> {51x133
match self.slots.binary_search_by_key(&addr, |s| s.addr) {51x134
Ok(index) => Ok(self.slots.remove(index).backend),48x135
Err(_) => error::NotMapped { addr }.fail(),3x136
}137
}51x138
139
pub fn search(&self, addr: u64) -> Option<(u64, &B)> {2586x140
match self.slots.binary_search_by_key(&addr, |s| s.addr) {2586x141
Ok(index) => Some((self.slots[index].addr, &self.slots[index].backend)),651x142
Err(0) => None,3x143
Err(index) => {1932x144
let candidate = &self.slots[index - 1];1932x145
if addr <= candidate.max_addr() {1932x146
Some((candidate.addr, &candidate.backend))1743x147
} else {148
None189x149
}150
}151
}152
}2586x153
154
pub fn search_next(&self, addr: u64) -> Option<(u64, &B)> {426x155
match self.slots.binary_search_by_key(&addr, |s| s.addr) {426x156
Ok(index) => Some((self.slots[index].addr, &self.slots[index].backend)),270x157
Err(0) => None,158
Err(index) => {156x159
let candidate = &self.slots[index - 1];156x160
if addr <= candidate.max_addr() {156x161
Some((candidate.addr, &candidate.backend))57x162
} else {163
self.slots.get(index).map(|slot| (slot.addr, &slot.backend))99x164
}165
}166
}167
}426x168
}169
170
#[cfg(test)]171
#[path = "addressable_test.rs"]172
mod tests;173