Skip to content

Commit 2c31efd

Browse files
extremeandyclaude
andcommitted
Add SortedLinearMap
A fixed-capacity map that keeps entries sorted by key and performs lookups via binary search - the BTreeMap analogue of LinearMap. Includes BTreeMap-style APIs: first_key_value/last_key_value, pop_first/pop_last, range/range_mut, plus the usual entry API, retain, Serialize/Deserialize, and Zeroize support. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ca95c4b commit 2c31efd

5 files changed

Lines changed: 1805 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
- Added `SortedLinearMap`, a fixed-capacity map that keeps entries sorted by key and performs lookups via binary search (analogous to `BTreeMap` as `LinearMap` is to `HashMap`). Includes `first_key_value`/`last_key_value`, `pop_first`/`pop_last`, `range`/`range_mut`, `entry`, `retain`, serde, and zeroize support.
11+
1012
## [v0.9.3] 2025-04-15
1113

1214
- Fixed unsoundness in `Deque::clear`, `HistoryBuf::clear` and `IndexMap::clear` in the context

src/de.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
binary_heap::Kind as BinaryHeapKind, len_type::LenType, BinaryHeap, Deque, HistoryBuf,
3-
IndexMap, IndexSet, LinearMap, String, Vec,
3+
IndexMap, IndexSet, LinearMap, SortedLinearMap, String, Vec,
44
};
55
use core::{
66
fmt,
@@ -297,6 +297,47 @@ where
297297
}
298298
}
299299

300+
impl<'de, K, V, const N: usize> Deserialize<'de> for SortedLinearMap<K, V, N>
301+
where
302+
K: Ord + Deserialize<'de>,
303+
V: Deserialize<'de>,
304+
{
305+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
306+
where
307+
D: Deserializer<'de>,
308+
{
309+
struct ValueVisitor<'de, K, V, const N: usize>(PhantomData<(&'de (), K, V)>);
310+
311+
impl<'de, K, V, const N: usize> de::Visitor<'de> for ValueVisitor<'de, K, V, N>
312+
where
313+
K: Ord + Deserialize<'de>,
314+
V: Deserialize<'de>,
315+
{
316+
type Value = SortedLinearMap<K, V, N>;
317+
318+
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
319+
formatter.write_str("a map")
320+
}
321+
322+
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
323+
where
324+
A: MapAccess<'de>,
325+
{
326+
let mut values = SortedLinearMap::new();
327+
328+
while let Some((key, value)) = map.next_entry()? {
329+
if values.insert(key, value).is_err() {
330+
return Err(A::Error::invalid_length(values.capacity() + 1, &self))?;
331+
}
332+
}
333+
334+
Ok(values)
335+
}
336+
}
337+
deserializer.deserialize_map(ValueVisitor(PhantomData))
338+
}
339+
}
340+
300341
// String containers
301342

302343
impl<'de, LenT: LenType, const N: usize> Deserialize<'de> for String<N, LenT> {

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
//! - [`IndexMap`]: A hash table.
101101
//! - [`IndexSet`]: A hash set.
102102
//! - [`LinearMap`]: A linear map.
103+
//! - [`SortedLinearMap`]: A map with entries kept sorted by key.
103104
//! - [`SortedLinkedList`](sorted_linked_list::SortedLinkedList): A sorted linked list.
104105
//! - [`String`]: A string.
105106
//! - [`Vec`]: A vector.
@@ -157,6 +158,7 @@ pub use index_map::IndexMap;
157158
pub use index_set::IndexSet;
158159
pub use len_type::LenType;
159160
pub use linear_map::LinearMap;
161+
pub use sorted_linear_map::SortedLinearMap;
160162
pub use string::String;
161163

162164
pub use vec::{Vec, VecView};
@@ -173,6 +175,7 @@ pub mod index_set;
173175
mod len_type;
174176
pub mod linear_map;
175177
mod slice;
178+
pub mod sorted_linear_map;
176179
pub mod storage;
177180
pub mod string;
178181
pub mod vec;

src/ser.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
history_buf::{HistoryBufInner, HistoryBufStorage},
77
len_type::LenType,
88
linear_map::{LinearMapInner, LinearMapStorage},
9+
sorted_linear_map::{SortedLinearMapInner, SortedLinearMapStorage},
910
string::{StringInner, StringStorage},
1011
vec::{VecInner, VecStorage},
1112
IndexMap, IndexSet,
@@ -134,6 +135,23 @@ where
134135
}
135136
}
136137

138+
impl<K, V, S: SortedLinearMapStorage<K, V> + ?Sized> Serialize for SortedLinearMapInner<K, V, S>
139+
where
140+
K: Ord + Serialize,
141+
V: Serialize,
142+
{
143+
fn serialize<SER>(&self, serializer: SER) -> Result<SER::Ok, SER::Error>
144+
where
145+
SER: Serializer,
146+
{
147+
let mut map = serializer.serialize_map(Some(self.len()))?;
148+
for (k, v) in self {
149+
map.serialize_entry(k, v)?;
150+
}
151+
map.end()
152+
}
153+
}
154+
137155
// String containers
138156

139157
impl<LenT: LenType, S: StringStorage + ?Sized> Serialize for StringInner<LenT, S> {

0 commit comments

Comments
 (0)