Skip to content

Commit 2066fa6

Browse files
committed
Add experimental u64 version bitset
1 parent 4ac6c42 commit 2066fa6

File tree

5 files changed

+760
-0
lines changed

5 files changed

+760
-0
lines changed

src/experimental/helpers.rs

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

src/experimental/mod.rs

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

0 commit comments

Comments
 (0)