Skip to main content

oxilean_codegen/pipeline/types/
impls2.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::defs::*;
6use super::impls1::*;
7use crate::c_backend::{self, CEmitConfig, COutput};
8use crate::closure_convert::{ClosureConvertConfig, ClosureConverter};
9use crate::lcnf::*;
10use crate::native_backend::{self, NativeEmitConfig, NativeModule};
11use crate::opt_dce::{self, DceConfig};
12use crate::to_lcnf::{self, ToLcnfConfig};
13use crate::CodegenTarget;
14use oxilean_kernel::expr::Expr;
15use oxilean_kernel::Name;
16
17use super::super::functions::LcnfDeclInput;
18
19use super::super::functions::*;
20use std::collections::{HashMap, HashSet, VecDeque};
21
22/// The result of running the complete compilation pipeline.
23#[derive(Debug, Clone)]
24pub struct PipelineResult {
25    /// C output (if target was C).
26    pub c_output: Option<COutput>,
27    /// Native module (if target was Native/LlvmIr).
28    pub native_output: Option<NativeModule>,
29    /// The final LCNF module (always available).
30    pub lcnf_module: LcnfModule,
31    /// Pipeline statistics.
32    pub stats: PipelineStats,
33}
34/// Worklist for PipeExt.
35#[allow(dead_code)]
36#[derive(Debug, Clone)]
37pub struct PipeExtWorklist {
38    pub(crate) items: std::collections::VecDeque<usize>,
39    pub(crate) present: Vec<bool>,
40}
41impl PipeExtWorklist {
42    #[allow(dead_code)]
43    pub fn new(capacity: usize) -> Self {
44        Self {
45            items: std::collections::VecDeque::new(),
46            present: vec![false; capacity],
47        }
48    }
49    #[allow(dead_code)]
50    pub fn push(&mut self, id: usize) {
51        if id < self.present.len() && !self.present[id] {
52            self.present[id] = true;
53            self.items.push_back(id);
54        }
55    }
56    #[allow(dead_code)]
57    pub fn push_front(&mut self, id: usize) {
58        if id < self.present.len() && !self.present[id] {
59            self.present[id] = true;
60            self.items.push_front(id);
61        }
62    }
63    #[allow(dead_code)]
64    pub fn pop(&mut self) -> Option<usize> {
65        let id = self.items.pop_front()?;
66        if id < self.present.len() {
67            self.present[id] = false;
68        }
69        Some(id)
70    }
71    #[allow(dead_code)]
72    pub fn is_empty(&self) -> bool {
73        self.items.is_empty()
74    }
75    #[allow(dead_code)]
76    pub fn len(&self) -> usize {
77        self.items.len()
78    }
79    #[allow(dead_code)]
80    pub fn contains(&self, id: usize) -> bool {
81        id < self.present.len() && self.present[id]
82    }
83    #[allow(dead_code)]
84    pub fn drain_all(&mut self) -> Vec<usize> {
85        let v: Vec<usize> = self.items.drain(..).collect();
86        for &id in &v {
87            if id < self.present.len() {
88                self.present[id] = false;
89            }
90        }
91        v
92    }
93}
94/// Liveness analysis for PipeExt.
95#[allow(dead_code)]
96#[derive(Debug, Clone, Default)]
97pub struct PipeExtLiveness {
98    pub live_in: Vec<Vec<usize>>,
99    pub live_out: Vec<Vec<usize>>,
100    pub defs: Vec<Vec<usize>>,
101    pub uses: Vec<Vec<usize>>,
102}
103impl PipeExtLiveness {
104    #[allow(dead_code)]
105    pub fn new(n: usize) -> Self {
106        Self {
107            live_in: vec![Vec::new(); n],
108            live_out: vec![Vec::new(); n],
109            defs: vec![Vec::new(); n],
110            uses: vec![Vec::new(); n],
111        }
112    }
113    #[allow(dead_code)]
114    pub fn live_in(&self, b: usize, v: usize) -> bool {
115        self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
116    }
117    #[allow(dead_code)]
118    pub fn live_out(&self, b: usize, v: usize) -> bool {
119        self.live_out
120            .get(b)
121            .map(|s| s.contains(&v))
122            .unwrap_or(false)
123    }
124    #[allow(dead_code)]
125    pub fn add_def(&mut self, b: usize, v: usize) {
126        if let Some(s) = self.defs.get_mut(b) {
127            if !s.contains(&v) {
128                s.push(v);
129            }
130        }
131    }
132    #[allow(dead_code)]
133    pub fn add_use(&mut self, b: usize, v: usize) {
134        if let Some(s) = self.uses.get_mut(b) {
135            if !s.contains(&v) {
136                s.push(v);
137            }
138        }
139    }
140    #[allow(dead_code)]
141    pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
142        self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
143    }
144    #[allow(dead_code)]
145    pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
146        self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
147    }
148}
149/// Analysis cache for PipeX2.
150#[allow(dead_code)]
151#[derive(Debug)]
152pub struct PipeX2Cache {
153    pub(crate) entries: Vec<(u64, Vec<u8>, bool, u32)>,
154    pub(crate) cap: usize,
155    pub(crate) total_hits: u64,
156    pub(crate) total_misses: u64,
157}
158impl PipeX2Cache {
159    #[allow(dead_code)]
160    pub fn new(cap: usize) -> Self {
161        Self {
162            entries: Vec::new(),
163            cap,
164            total_hits: 0,
165            total_misses: 0,
166        }
167    }
168    #[allow(dead_code)]
169    pub fn get(&mut self, key: u64) -> Option<&[u8]> {
170        for e in self.entries.iter_mut() {
171            if e.0 == key && e.2 {
172                e.3 += 1;
173                self.total_hits += 1;
174                return Some(&e.1);
175            }
176        }
177        self.total_misses += 1;
178        None
179    }
180    #[allow(dead_code)]
181    pub fn put(&mut self, key: u64, data: Vec<u8>) {
182        if self.entries.len() >= self.cap {
183            self.entries.retain(|e| e.2);
184            if self.entries.len() >= self.cap {
185                self.entries.remove(0);
186            }
187        }
188        self.entries.push((key, data, true, 0));
189    }
190    #[allow(dead_code)]
191    pub fn invalidate(&mut self) {
192        for e in self.entries.iter_mut() {
193            e.2 = false;
194        }
195    }
196    #[allow(dead_code)]
197    pub fn hit_rate(&self) -> f64 {
198        let t = self.total_hits + self.total_misses;
199        if t == 0 {
200            0.0
201        } else {
202            self.total_hits as f64 / t as f64
203        }
204    }
205    #[allow(dead_code)]
206    pub fn live_count(&self) -> usize {
207        self.entries.iter().filter(|e| e.2).count()
208    }
209}
210#[allow(dead_code)]
211#[derive(Debug, Clone)]
212pub struct PipeLivenessInfo {
213    pub live_in: Vec<std::collections::HashSet<u32>>,
214    pub live_out: Vec<std::collections::HashSet<u32>>,
215    pub defs: Vec<std::collections::HashSet<u32>>,
216    pub uses: Vec<std::collections::HashSet<u32>>,
217}
218impl PipeLivenessInfo {
219    #[allow(dead_code)]
220    pub fn new(block_count: usize) -> Self {
221        PipeLivenessInfo {
222            live_in: vec![std::collections::HashSet::new(); block_count],
223            live_out: vec![std::collections::HashSet::new(); block_count],
224            defs: vec![std::collections::HashSet::new(); block_count],
225            uses: vec![std::collections::HashSet::new(); block_count],
226        }
227    }
228    #[allow(dead_code)]
229    pub fn add_def(&mut self, block: usize, var: u32) {
230        if block < self.defs.len() {
231            self.defs[block].insert(var);
232        }
233    }
234    #[allow(dead_code)]
235    pub fn add_use(&mut self, block: usize, var: u32) {
236        if block < self.uses.len() {
237            self.uses[block].insert(var);
238        }
239    }
240    #[allow(dead_code)]
241    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
242        self.live_in
243            .get(block)
244            .map(|s| s.contains(&var))
245            .unwrap_or(false)
246    }
247    #[allow(dead_code)]
248    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
249        self.live_out
250            .get(block)
251            .map(|s| s.contains(&var))
252            .unwrap_or(false)
253    }
254}
255#[allow(dead_code)]
256#[derive(Debug, Clone, PartialEq)]
257pub enum PipePassPhase {
258    Analysis,
259    Transformation,
260    Verification,
261    Cleanup,
262}
263impl PipePassPhase {
264    #[allow(dead_code)]
265    pub fn name(&self) -> &str {
266        match self {
267            PipePassPhase::Analysis => "analysis",
268            PipePassPhase::Transformation => "transformation",
269            PipePassPhase::Verification => "verification",
270            PipePassPhase::Cleanup => "cleanup",
271        }
272    }
273    #[allow(dead_code)]
274    pub fn is_modifying(&self) -> bool {
275        matches!(self, PipePassPhase::Transformation | PipePassPhase::Cleanup)
276    }
277}
278/// Aggregate statistics for the entire pipeline.
279#[derive(Debug, Clone, Default)]
280pub struct PipelineStats {
281    /// Per-pass statistics.
282    pub per_pass: Vec<(PassId, PassStats)>,
283    /// Total time for the pipeline in microseconds.
284    pub total_time_us: u64,
285    /// Number of fixed-point iterations executed.
286    pub iterations: usize,
287    /// Total number of LCNF declarations at input.
288    pub input_decls: usize,
289    /// Total number of LCNF declarations at output.
290    pub output_decls: usize,
291}
292/// Identifier for an optimization pass.
293#[derive(Debug, Clone, PartialEq, Eq, Hash)]
294pub enum PassId {
295    /// Join point optimization.
296    JoinPoints,
297    /// Specialization.
298    Specialize,
299    /// Reset-reuse optimization.
300    Reuse,
301    /// Dead code elimination + constant/copy propagation.
302    Dce,
303    /// Closure conversion.
304    ClosureConvert,
305    /// A custom (user-defined) pass.
306    Custom(String),
307}
308/// Statistics for a single pass.
309#[derive(Debug, Clone, Default)]
310pub struct PassStats {
311    /// Number of declarations processed.
312    pub decls_processed: usize,
313    /// Number of transformations applied.
314    pub transformations: usize,
315    /// Time taken in microseconds.
316    pub time_us: u64,
317}
318/// Pass execution phase for PipeExt.
319#[allow(dead_code)]
320#[derive(Debug, Clone, PartialEq, Eq, Hash)]
321pub enum PipeExtPassPhase {
322    Early,
323    Middle,
324    Late,
325    Finalize,
326}
327impl PipeExtPassPhase {
328    #[allow(dead_code)]
329    pub fn is_early(&self) -> bool {
330        matches!(self, Self::Early)
331    }
332    #[allow(dead_code)]
333    pub fn is_middle(&self) -> bool {
334        matches!(self, Self::Middle)
335    }
336    #[allow(dead_code)]
337    pub fn is_late(&self) -> bool {
338        matches!(self, Self::Late)
339    }
340    #[allow(dead_code)]
341    pub fn is_finalize(&self) -> bool {
342        matches!(self, Self::Finalize)
343    }
344    #[allow(dead_code)]
345    pub fn order(&self) -> u32 {
346        match self {
347            Self::Early => 0,
348            Self::Middle => 1,
349            Self::Late => 2,
350            Self::Finalize => 3,
351        }
352    }
353    #[allow(dead_code)]
354    pub fn from_order(n: u32) -> Option<Self> {
355        match n {
356            0 => Some(Self::Early),
357            1 => Some(Self::Middle),
358            2 => Some(Self::Late),
359            3 => Some(Self::Finalize),
360            _ => None,
361        }
362    }
363}
364/// Dependency graph for PipeExt.
365#[allow(dead_code)]
366#[derive(Debug, Clone)]
367pub struct PipeExtDepGraph {
368    pub(crate) n: usize,
369    pub(crate) adj: Vec<Vec<usize>>,
370    pub(crate) rev: Vec<Vec<usize>>,
371    pub(crate) edge_count: usize,
372}
373impl PipeExtDepGraph {
374    #[allow(dead_code)]
375    pub fn new(n: usize) -> Self {
376        Self {
377            n,
378            adj: vec![Vec::new(); n],
379            rev: vec![Vec::new(); n],
380            edge_count: 0,
381        }
382    }
383    #[allow(dead_code)]
384    pub fn add_edge(&mut self, from: usize, to: usize) {
385        if from < self.n && to < self.n {
386            if !self.adj[from].contains(&to) {
387                self.adj[from].push(to);
388                self.rev[to].push(from);
389                self.edge_count += 1;
390            }
391        }
392    }
393    #[allow(dead_code)]
394    pub fn succs(&self, n: usize) -> &[usize] {
395        self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
396    }
397    #[allow(dead_code)]
398    pub fn preds(&self, n: usize) -> &[usize] {
399        self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
400    }
401    #[allow(dead_code)]
402    pub fn topo_sort(&self) -> Option<Vec<usize>> {
403        let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
404        let mut q: std::collections::VecDeque<usize> =
405            (0..self.n).filter(|&i| deg[i] == 0).collect();
406        let mut out = Vec::with_capacity(self.n);
407        while let Some(u) = q.pop_front() {
408            out.push(u);
409            for &v in &self.adj[u] {
410                deg[v] -= 1;
411                if deg[v] == 0 {
412                    q.push_back(v);
413                }
414            }
415        }
416        if out.len() == self.n {
417            Some(out)
418        } else {
419            None
420        }
421    }
422    #[allow(dead_code)]
423    pub fn has_cycle(&self) -> bool {
424        self.topo_sort().is_none()
425    }
426    #[allow(dead_code)]
427    pub fn reachable(&self, start: usize) -> Vec<usize> {
428        let mut vis = vec![false; self.n];
429        let mut stk = vec![start];
430        let mut out = Vec::new();
431        while let Some(u) = stk.pop() {
432            if u < self.n && !vis[u] {
433                vis[u] = true;
434                out.push(u);
435                for &v in &self.adj[u] {
436                    if !vis[v] {
437                        stk.push(v);
438                    }
439                }
440            }
441        }
442        out
443    }
444    #[allow(dead_code)]
445    pub fn scc(&self) -> Vec<Vec<usize>> {
446        let mut visited = vec![false; self.n];
447        let mut order = Vec::new();
448        for i in 0..self.n {
449            if !visited[i] {
450                let mut stk = vec![(i, 0usize)];
451                while let Some((u, idx)) = stk.last_mut() {
452                    if !visited[*u] {
453                        visited[*u] = true;
454                    }
455                    if *idx < self.adj[*u].len() {
456                        let v = self.adj[*u][*idx];
457                        *idx += 1;
458                        if !visited[v] {
459                            stk.push((v, 0));
460                        }
461                    } else {
462                        order.push(*u);
463                        stk.pop();
464                    }
465                }
466            }
467        }
468        let mut comp = vec![usize::MAX; self.n];
469        let mut components: Vec<Vec<usize>> = Vec::new();
470        for &start in order.iter().rev() {
471            if comp[start] == usize::MAX {
472                let cid = components.len();
473                let mut component = Vec::new();
474                let mut stk = vec![start];
475                while let Some(u) = stk.pop() {
476                    if comp[u] == usize::MAX {
477                        comp[u] = cid;
478                        component.push(u);
479                        for &v in &self.rev[u] {
480                            if comp[v] == usize::MAX {
481                                stk.push(v);
482                            }
483                        }
484                    }
485                }
486                components.push(component);
487            }
488        }
489        components
490    }
491    #[allow(dead_code)]
492    pub fn node_count(&self) -> usize {
493        self.n
494    }
495    #[allow(dead_code)]
496    pub fn edge_count(&self) -> usize {
497        self.edge_count
498    }
499}
500/// Configuration for the compiler pipeline.
501#[derive(Debug, Clone)]
502pub struct PipelineConfig {
503    /// Optimization level.
504    pub opt_level: OptLevel,
505    /// Code generation target.
506    pub target: CodegenTarget,
507    /// Whether to emit debug info.
508    pub debug: bool,
509    /// Whether to emit intermediate IR for inspection.
510    pub emit_ir: bool,
511    /// Explicit list of passes to run (overrides opt_level if non-empty).
512    pub passes: Vec<PassId>,
513    /// Maximum iterations for fixed-point optimization.
514    pub max_iterations: usize,
515    /// Whether to emit comments in generated code.
516    pub emit_comments: bool,
517}
518impl PipelineConfig {
519    /// Get the effective list of passes to run.
520    pub fn effective_passes(&self) -> Vec<PassId> {
521        if self.passes.is_empty() {
522            self.opt_level.default_passes()
523        } else {
524            self.passes.clone()
525        }
526    }
527    /// Get the effective max iterations.
528    pub fn effective_max_iterations(&self) -> usize {
529        if self.max_iterations > 0 {
530            self.max_iterations
531        } else {
532            self.opt_level.max_iterations()
533        }
534    }
535}
536/// Configuration for PipeX2 passes.
537#[allow(dead_code)]
538#[derive(Debug, Clone)]
539pub struct PipeX2PassConfig {
540    pub name: String,
541    pub phase: PipeX2PassPhase,
542    pub enabled: bool,
543    pub max_iterations: usize,
544    pub debug: u32,
545    pub timeout_ms: Option<u64>,
546}
547impl PipeX2PassConfig {
548    #[allow(dead_code)]
549    pub fn new(name: impl Into<String>) -> Self {
550        Self {
551            name: name.into(),
552            phase: PipeX2PassPhase::Middle,
553            enabled: true,
554            max_iterations: 100,
555            debug: 0,
556            timeout_ms: None,
557        }
558    }
559    #[allow(dead_code)]
560    pub fn with_phase(mut self, phase: PipeX2PassPhase) -> Self {
561        self.phase = phase;
562        self
563    }
564    #[allow(dead_code)]
565    pub fn with_max_iter(mut self, n: usize) -> Self {
566        self.max_iterations = n;
567        self
568    }
569    #[allow(dead_code)]
570    pub fn with_debug(mut self, d: u32) -> Self {
571        self.debug = d;
572        self
573    }
574    #[allow(dead_code)]
575    pub fn disabled(mut self) -> Self {
576        self.enabled = false;
577        self
578    }
579    #[allow(dead_code)]
580    pub fn with_timeout(mut self, ms: u64) -> Self {
581        self.timeout_ms = Some(ms);
582        self
583    }
584    #[allow(dead_code)]
585    pub fn is_debug_enabled(&self) -> bool {
586        self.debug > 0
587    }
588}
589/// Statistics for PipeX2 passes.
590#[allow(dead_code)]
591#[derive(Debug, Clone, Default)]
592pub struct PipeX2PassStats {
593    pub iterations: usize,
594    pub changed: bool,
595    pub nodes_visited: usize,
596    pub nodes_modified: usize,
597    pub time_ms: u64,
598    pub memory_bytes: usize,
599    pub errors: usize,
600}
601impl PipeX2PassStats {
602    #[allow(dead_code)]
603    pub fn new() -> Self {
604        Self::default()
605    }
606    #[allow(dead_code)]
607    pub fn visit(&mut self) {
608        self.nodes_visited += 1;
609    }
610    #[allow(dead_code)]
611    pub fn modify(&mut self) {
612        self.nodes_modified += 1;
613        self.changed = true;
614    }
615    #[allow(dead_code)]
616    pub fn iterate(&mut self) {
617        self.iterations += 1;
618    }
619    #[allow(dead_code)]
620    pub fn error(&mut self) {
621        self.errors += 1;
622    }
623    #[allow(dead_code)]
624    pub fn efficiency(&self) -> f64 {
625        if self.nodes_visited == 0 {
626            0.0
627        } else {
628            self.nodes_modified as f64 / self.nodes_visited as f64
629        }
630    }
631    #[allow(dead_code)]
632    pub fn merge(&mut self, o: &PipeX2PassStats) {
633        self.iterations += o.iterations;
634        self.changed |= o.changed;
635        self.nodes_visited += o.nodes_visited;
636        self.nodes_modified += o.nodes_modified;
637        self.time_ms += o.time_ms;
638        self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
639        self.errors += o.errors;
640    }
641}
642#[allow(dead_code)]
643pub struct PipePassRegistry {
644    pub(crate) configs: Vec<PipePassConfig>,
645    pub(crate) stats: std::collections::HashMap<String, PipePassStats>,
646}
647impl PipePassRegistry {
648    #[allow(dead_code)]
649    pub fn new() -> Self {
650        PipePassRegistry {
651            configs: Vec::new(),
652            stats: std::collections::HashMap::new(),
653        }
654    }
655    #[allow(dead_code)]
656    pub fn register(&mut self, config: PipePassConfig) {
657        self.stats
658            .insert(config.pass_name.clone(), PipePassStats::new());
659        self.configs.push(config);
660    }
661    #[allow(dead_code)]
662    pub fn enabled_passes(&self) -> Vec<&PipePassConfig> {
663        self.configs.iter().filter(|c| c.enabled).collect()
664    }
665    #[allow(dead_code)]
666    pub fn get_stats(&self, name: &str) -> Option<&PipePassStats> {
667        self.stats.get(name)
668    }
669    #[allow(dead_code)]
670    pub fn total_passes(&self) -> usize {
671        self.configs.len()
672    }
673    #[allow(dead_code)]
674    pub fn enabled_count(&self) -> usize {
675        self.enabled_passes().len()
676    }
677    #[allow(dead_code)]
678    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
679        if let Some(stats) = self.stats.get_mut(name) {
680            stats.record_run(changes, time_ms, iter);
681        }
682    }
683}
684/// Pass registry for PipeX2.
685#[allow(dead_code)]
686#[derive(Debug, Default)]
687pub struct PipeX2PassRegistry {
688    pub(crate) configs: Vec<PipeX2PassConfig>,
689    pub(crate) stats: Vec<PipeX2PassStats>,
690}
691impl PipeX2PassRegistry {
692    #[allow(dead_code)]
693    pub fn new() -> Self {
694        Self::default()
695    }
696    #[allow(dead_code)]
697    pub fn register(&mut self, c: PipeX2PassConfig) {
698        self.stats.push(PipeX2PassStats::new());
699        self.configs.push(c);
700    }
701    #[allow(dead_code)]
702    pub fn len(&self) -> usize {
703        self.configs.len()
704    }
705    #[allow(dead_code)]
706    pub fn is_empty(&self) -> bool {
707        self.configs.is_empty()
708    }
709    #[allow(dead_code)]
710    pub fn get(&self, i: usize) -> Option<&PipeX2PassConfig> {
711        self.configs.get(i)
712    }
713    #[allow(dead_code)]
714    pub fn get_stats(&self, i: usize) -> Option<&PipeX2PassStats> {
715        self.stats.get(i)
716    }
717    #[allow(dead_code)]
718    pub fn enabled_passes(&self) -> Vec<&PipeX2PassConfig> {
719        self.configs.iter().filter(|c| c.enabled).collect()
720    }
721    #[allow(dead_code)]
722    pub fn passes_in_phase(&self, ph: &PipeX2PassPhase) -> Vec<&PipeX2PassConfig> {
723        self.configs
724            .iter()
725            .filter(|c| c.enabled && &c.phase == ph)
726            .collect()
727    }
728    #[allow(dead_code)]
729    pub fn total_nodes_visited(&self) -> usize {
730        self.stats.iter().map(|s| s.nodes_visited).sum()
731    }
732    #[allow(dead_code)]
733    pub fn any_changed(&self) -> bool {
734        self.stats.iter().any(|s| s.changed)
735    }
736}
737/// Worklist for PipeX2.
738#[allow(dead_code)]
739#[derive(Debug, Clone)]
740pub struct PipeX2Worklist {
741    pub(crate) items: std::collections::VecDeque<usize>,
742    pub(crate) present: Vec<bool>,
743}
744impl PipeX2Worklist {
745    #[allow(dead_code)]
746    pub fn new(capacity: usize) -> Self {
747        Self {
748            items: std::collections::VecDeque::new(),
749            present: vec![false; capacity],
750        }
751    }
752    #[allow(dead_code)]
753    pub fn push(&mut self, id: usize) {
754        if id < self.present.len() && !self.present[id] {
755            self.present[id] = true;
756            self.items.push_back(id);
757        }
758    }
759    #[allow(dead_code)]
760    pub fn push_front(&mut self, id: usize) {
761        if id < self.present.len() && !self.present[id] {
762            self.present[id] = true;
763            self.items.push_front(id);
764        }
765    }
766    #[allow(dead_code)]
767    pub fn pop(&mut self) -> Option<usize> {
768        let id = self.items.pop_front()?;
769        if id < self.present.len() {
770            self.present[id] = false;
771        }
772        Some(id)
773    }
774    #[allow(dead_code)]
775    pub fn is_empty(&self) -> bool {
776        self.items.is_empty()
777    }
778    #[allow(dead_code)]
779    pub fn len(&self) -> usize {
780        self.items.len()
781    }
782    #[allow(dead_code)]
783    pub fn contains(&self, id: usize) -> bool {
784        id < self.present.len() && self.present[id]
785    }
786    #[allow(dead_code)]
787    pub fn drain_all(&mut self) -> Vec<usize> {
788        let v: Vec<usize> = self.items.drain(..).collect();
789        for &id in &v {
790            if id < self.present.len() {
791                self.present[id] = false;
792            }
793        }
794        v
795    }
796}