Skip to content

Commit 7638eca

Browse files
committed
Add experimental u64 version bitset
1 parent 4c6cdde commit 7638eca

File tree

5 files changed

+764
-0
lines changed

5 files changed

+764
-0
lines changed

src/experimental/helpers.rs

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
//! Helpers structs.
2+
3+
use std::fmt::{self, Display};
4+
use std::iter::repeat_n;
5+
use std::num::NonZeroU64;
6+
use std::rc::Rc;
7+
8+
use crate::experimental::{VersionIndex, VersionSet};
9+
10+
/// Package allowing more than 63 versions
11+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
12+
pub struct Pkg<P> {
13+
pkg: P,
14+
quotient: u64,
15+
count: u64,
16+
}
17+
18+
impl<P> Pkg<P> {
19+
/// Get the inner package.
20+
pub fn pkg(&self) -> &P {
21+
&self.pkg
22+
}
23+
}
24+
25+
impl<P: Display> Display for Pkg<P> {
26+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27+
write!(f, "{} (q={})", self.pkg, self.quotient)
28+
}
29+
}
30+
31+
/// Virtual package ensuring package unicity
32+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
33+
pub struct VirtualPkg<P> {
34+
pkg: P,
35+
quotient: u64,
36+
count: u64,
37+
}
38+
39+
impl<P> VirtualPkg<P> {
40+
/// Get the inner package.
41+
pub fn pkg(&self) -> &P {
42+
&self.pkg
43+
}
44+
}
45+
46+
impl<P: Display> Display for VirtualPkg<P> {
47+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48+
write!(
49+
f,
50+
"VirtualPkg({}, q={}, c={})",
51+
self.pkg, self.quotient, self.count
52+
)
53+
}
54+
}
55+
56+
/// Virtual package dependency allowing more than 63 versions
57+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
58+
pub struct VirtualDep<P> {
59+
pkg: P,
60+
version_indices: Rc<[VersionSet]>,
61+
offset: u64,
62+
quotient: u64,
63+
}
64+
65+
impl<P> VirtualDep<P> {
66+
/// Get the inner package.
67+
pub fn pkg(&self) -> &P {
68+
&self.pkg
69+
}
70+
}
71+
72+
impl<P: Display> Display for VirtualDep<P> {
73+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74+
let vc = self
75+
.version_indices
76+
.iter()
77+
.map(|vs| vs.count())
78+
.sum::<usize>();
79+
80+
write!(
81+
f,
82+
"VirtualDep({}, vc={vc}, o={}, q={})",
83+
self.pkg, self.offset, self.quotient
84+
)
85+
}
86+
}
87+
88+
/// Package wrapper used to allow more than 63 versions per package.
89+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
90+
pub enum PackageVersionWrapper<P: Clone + Display> {
91+
/// Package allowing more than 63 versions
92+
Pkg(Pkg<P>),
93+
/// Virtual package ensuring package unicity
94+
VirtualPkg(VirtualPkg<P>),
95+
/// Virtual package dependency allowing more than 63 versions
96+
VirtualDep(VirtualDep<P>),
97+
}
98+
99+
impl<P: Clone + Display> Display for PackageVersionWrapper<P> {
100+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101+
match self {
102+
Self::Pkg(p) => p.fmt(f),
103+
Self::VirtualPkg(vp) => vp.fmt(f),
104+
Self::VirtualDep(vd) => vd.fmt(f),
105+
}
106+
}
107+
}
108+
109+
impl<P: Clone + Display> PackageVersionWrapper<P> {
110+
/// Create a new package.
111+
pub fn new_pkg(
112+
pkg: P,
113+
true_version_index: u64,
114+
version_count: NonZeroU64,
115+
) -> (Self, VersionIndex) {
116+
(
117+
Self::Pkg(Pkg {
118+
pkg,
119+
quotient: true_version_index / VersionIndex::MAX,
120+
count: (version_count.get() - 1) / VersionIndex::MAX,
121+
}),
122+
VersionIndex::new((true_version_index % VersionIndex::MAX) as u8).unwrap(),
123+
)
124+
}
125+
126+
/// Create a new package dependency with no versions.
127+
pub fn new_empty_dep(pkg: P) -> (Self, VersionSet) {
128+
(
129+
Self::Pkg(Pkg {
130+
pkg,
131+
quotient: 0,
132+
count: 0,
133+
}),
134+
VersionSet::empty(),
135+
)
136+
}
137+
138+
/// Create a new package dependency at the specified version.
139+
pub fn new_singleton_dep(
140+
pkg: P,
141+
true_version_index: u64,
142+
version_count: u64,
143+
) -> (Self, VersionSet) {
144+
match NonZeroU64::new(version_count) {
145+
Some(version_count) => {
146+
assert!(true_version_index < version_count.get());
147+
let (this, v) = Self::new_pkg(pkg, true_version_index, version_count);
148+
(this, VersionSet::singleton(v))
149+
}
150+
None => Self::new_empty_dep(pkg),
151+
}
152+
}
153+
154+
/// Create a new package dependency at the specified versions.
155+
pub fn new_dep(
156+
pkg: P,
157+
true_version_indices: impl IntoIterator<Item = u64>,
158+
version_count: u64,
159+
) -> (Self, VersionSet) {
160+
let Some(nz_version_count) = NonZeroU64::new(version_count) else {
161+
return Self::new_empty_dep(pkg);
162+
};
163+
if version_count <= VersionIndex::MAX {
164+
let mut set = VersionSet::empty();
165+
for true_version_index in true_version_indices {
166+
assert!(true_version_index < version_count);
167+
let v = VersionIndex::new(true_version_index as u8).unwrap();
168+
set = set.union(VersionSet::singleton(v));
169+
}
170+
return (
171+
Self::Pkg(Pkg {
172+
pkg,
173+
quotient: 0,
174+
count: (version_count - 1) / VersionIndex::MAX,
175+
}),
176+
set,
177+
);
178+
}
179+
180+
let mut true_version_indices = true_version_indices.into_iter();
181+
182+
let Some(first) = true_version_indices.next() else {
183+
return Self::new_empty_dep(pkg);
184+
};
185+
assert!(first < version_count);
186+
187+
let Some(second) = true_version_indices.next() else {
188+
let (d, vs) = Self::new_pkg(pkg, first, nz_version_count);
189+
return (d, VersionSet::singleton(vs));
190+
};
191+
assert!(second < version_count);
192+
193+
let mut version_indices = Rc::from_iter(repeat_n(
194+
VersionSet::empty(),
195+
(1 + (version_count - 1) / VersionIndex::MAX) as usize,
196+
));
197+
let versions_slice = Rc::make_mut(&mut version_indices);
198+
199+
for true_version_index in [first, second].into_iter().chain(true_version_indices) {
200+
assert!(true_version_index < version_count);
201+
let index = (true_version_index / VersionIndex::MAX) as usize;
202+
let v = VersionIndex::new((true_version_index % VersionIndex::MAX) as u8).unwrap();
203+
let set = versions_slice.get_mut(index).unwrap();
204+
*set = set.union(VersionSet::singleton(v));
205+
}
206+
207+
let offset = 0;
208+
let quotient = VersionIndex::MAX.pow(version_count.ilog(VersionIndex::MAX) - 1);
209+
let version_set = Self::dep_version_set(&version_indices, offset, quotient);
210+
211+
let this = Self::VirtualDep(VirtualDep {
212+
pkg,
213+
version_indices,
214+
offset,
215+
quotient,
216+
});
217+
218+
(this, version_set)
219+
}
220+
221+
/// Clone and replace the package of this wrapper.
222+
pub fn replace_pkg<T: Clone + Display>(&self, new_pkg: T) -> PackageVersionWrapper<T> {
223+
match *self {
224+
Self::Pkg(Pkg {
225+
pkg: _,
226+
quotient,
227+
count,
228+
}) => PackageVersionWrapper::Pkg(Pkg {
229+
pkg: new_pkg,
230+
quotient,
231+
count,
232+
}),
233+
Self::VirtualPkg(VirtualPkg {
234+
pkg: _,
235+
quotient,
236+
count,
237+
}) => PackageVersionWrapper::VirtualPkg(VirtualPkg {
238+
pkg: new_pkg,
239+
quotient,
240+
count,
241+
}),
242+
Self::VirtualDep(VirtualDep {
243+
pkg: _,
244+
ref version_indices,
245+
offset,
246+
quotient,
247+
}) => PackageVersionWrapper::VirtualDep(VirtualDep {
248+
pkg: new_pkg,
249+
version_indices: version_indices.clone(),
250+
offset,
251+
quotient,
252+
}),
253+
}
254+
}
255+
256+
/// Get the inner package if existing.
257+
pub fn inner_pkg(&self) -> Option<&P> {
258+
match self {
259+
Self::Pkg(Pkg { pkg, .. }) => Some(pkg),
260+
_ => None,
261+
}
262+
}
263+
264+
/// Get the inner package if existing.
265+
pub fn inner(&self, version_index: VersionIndex) -> Option<(&P, u64)> {
266+
match self {
267+
Self::Pkg(Pkg { pkg, quotient, .. }) => Some((
268+
pkg,
269+
quotient * VersionIndex::MAX + version_index.get() as u64,
270+
)),
271+
_ => None,
272+
}
273+
}
274+
275+
/// Get the inner package if existing.
276+
pub fn into_inner(self, version_index: VersionIndex) -> Option<(P, u64)> {
277+
match self {
278+
Self::Pkg(Pkg { pkg, quotient, .. }) => Some((
279+
pkg,
280+
quotient * VersionIndex::MAX + version_index.get() as u64,
281+
)),
282+
_ => None,
283+
}
284+
}
285+
286+
/// Get the wrapper virtual dependency if existing.
287+
pub fn dependency(&self, version_index: VersionIndex) -> Option<(Self, VersionSet)> {
288+
match *self {
289+
Self::Pkg(Pkg {
290+
ref pkg,
291+
quotient,
292+
count,
293+
})
294+
| Self::VirtualPkg(VirtualPkg {
295+
ref pkg,
296+
quotient,
297+
count,
298+
}) => {
299+
if count == 0 {
300+
None
301+
} else {
302+
Some((
303+
Self::VirtualPkg(VirtualPkg {
304+
pkg: pkg.clone(),
305+
quotient: quotient / VersionIndex::MAX,
306+
count: count / VersionIndex::MAX,
307+
}),
308+
VersionSet::singleton(
309+
VersionIndex::new((quotient % VersionIndex::MAX) as u8).unwrap(),
310+
),
311+
))
312+
}
313+
}
314+
Self::VirtualDep(VirtualDep {
315+
ref pkg,
316+
ref version_indices,
317+
offset,
318+
quotient,
319+
}) => {
320+
let offset = offset + version_index.get() as u64 * quotient;
321+
if quotient == 1 {
322+
return Some((
323+
Self::Pkg(Pkg {
324+
pkg: pkg.clone(),
325+
quotient: offset,
326+
count: (version_indices.len() - 1) as u64,
327+
}),
328+
version_indices[offset as usize],
329+
));
330+
}
331+
let quotient = quotient / VersionIndex::MAX;
332+
let version_set = Self::dep_version_set(version_indices, offset, quotient);
333+
334+
let this = Self::VirtualDep(VirtualDep {
335+
pkg: pkg.clone(),
336+
version_indices: version_indices.clone(),
337+
offset,
338+
quotient,
339+
});
340+
341+
Some((this, version_set))
342+
}
343+
}
344+
}
345+
346+
fn dep_version_set(sets: &[VersionSet], offset: u64, quotient: u64) -> VersionSet {
347+
sets[offset as usize..]
348+
.chunks(quotient as usize)
349+
.take(VersionIndex::MAX as usize)
350+
.enumerate()
351+
.filter(|&(_, sets)| sets.iter().any(|&vs| vs != VersionSet::empty()))
352+
.map(|(i, _)| VersionSet::singleton(VersionIndex::new(i as u8).unwrap()))
353+
.fold(VersionSet::empty(), |acc, vs| acc.union(vs))
354+
}
355+
}

src/experimental/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pub mod helpers;
2+
mod term;
3+
mod version;
4+
5+
pub use term::Term;
6+
pub use version::{VersionIndex, VersionSet};

0 commit comments

Comments
 (0)