open_vaf/
span.rs

1/*
2 * ******************************************************************************************
3 * Copyright (c) 2019 Pascal Kuthe. This file is part of the OpenVAF project.
4 * It is subject to the license terms in the LICENSE file found in the top-level directory
5 *  of this distribution and at  https://gitlab.com/DSPOM/OpenVAF/blob/master/LICENSE.
6 *  No part of OpenVAF, including this file, may be copied, modified, propagated, or
7 *  distributed except according to the terms contained in the LICENSE file.
8 * *****************************************************************************************
9 */
10use core::fmt::Display;
11use core::num::NonZeroU16;
12use std::fmt::{Debug, Formatter};
13use std::sync::Mutex;
14
15pub type Index = u32;
16pub type IndexOffset = i64;
17pub type Range = std::ops::Range<Index>;
18pub type LineNumber = u16;
19
20#[derive(Copy, Clone, Debug)]
21enum SpanData {
22    ///This Span is too large to fit its length or zero
23    LargeSpan,
24    Length(NonZeroU16),
25}
26lazy_static! {
27    static ref INTERNER: Mutex<SpanInterner> = Mutex::new(SpanInterner::new());
28}
29struct SpanInterner {
30    data: Vec<(u32, u32)>,
31}
32impl SpanInterner {
33    fn new() -> Self {
34        Self {
35            data: Vec::with_capacity(64),
36        }
37    }
38    fn add(&mut self, start: u32, end: u32) -> usize {
39        let idx = self.data.len();
40        self.data.push((start, end));
41        idx
42    }
43    fn get(&self, idx: usize) -> (u32, u32) {
44        unsafe { *self.data.get_unchecked(idx) }
45    }
46}
47
48#[derive(Copy, Clone, Debug)]
49pub struct Span {
50    start_or_idx: Index,
51    data: SpanData,
52}
53impl Span {
54    #[inline]
55    pub fn new(start: Index, end: Index) -> Self {
56        Self::new_with_length(start, end - start)
57    }
58
59    const U16_MAX_U32: u32 = std::u16::MAX as u32;
60    #[inline]
61    pub fn new_with_length(start: Index, len: Index) -> Self {
62        match len {
63            0 if start < (1 << 31) => Self {
64                start_or_idx: (start << 1) | 1,
65                data: SpanData::LargeSpan,
66            },
67            len @ 1..=Self::U16_MAX_U32 => Self {
68                start_or_idx: start,
69                data: SpanData::Length(unsafe { NonZeroU16::new_unchecked(len as u16) }),
70            },
71            len => {
72                debug_assert!(len == 0 || len > std::u16::MAX as u32);
73                Self {
74                    start_or_idx: (INTERNER.lock().unwrap().add(start, start + len) as u32) << 1,
75                    data: SpanData::LargeSpan,
76                }
77            }
78        }
79    }
80
81    #[inline]
82    pub const fn new_short_span(start: Index, len: NonZeroU16) -> Self {
83        Self {
84            start_or_idx: start,
85            data: SpanData::Length(len),
86        }
87    }
88    #[inline]
89    pub fn new_empty_span(start: Index) -> Self {
90        if start < 1 << 31 {
91            Self {
92                start_or_idx: (start << 1) | 1,
93                data: SpanData::LargeSpan,
94            }
95        } else {
96            Self {
97                start_or_idx: (INTERNER.lock().unwrap().add(start, start) as u32) << 1,
98                data: SpanData::LargeSpan,
99            }
100        }
101    }
102    #[inline]
103    pub const fn new_short_empty_span(start: u16) -> Self {
104        Self {
105            start_or_idx: ((start as u32) << 1) | 1,
106            data: SpanData::LargeSpan,
107        }
108    }
109
110    #[inline]
111    pub fn get_start(self) -> Index {
112        match self.data {
113            SpanData::Length(_) => self.start_or_idx,
114            SpanData::LargeSpan if self.start_or_idx & 1 == 1 => self.start_or_idx >> 1,
115            SpanData::LargeSpan => {
116                INTERNER
117                    .lock()
118                    .unwrap()
119                    .get((self.start_or_idx >> 1) as usize)
120                    .0
121            }
122        }
123    }
124
125    #[inline]
126    pub fn get_end(self) -> Index {
127        match self.data {
128            SpanData::Length(length) => self.start_or_idx + (length.get() as u32),
129            SpanData::LargeSpan if self.start_or_idx & 1 == 1 => self.start_or_idx >> 1,
130            SpanData::LargeSpan => {
131                INTERNER
132                    .lock()
133                    .unwrap()
134                    .get((self.start_or_idx >> 1) as usize)
135                    .1
136            }
137        }
138    }
139
140    pub fn get_len(self) -> Index {
141        match self.data {
142            SpanData::Length(length) => length.get() as Index,
143            SpanData::LargeSpan if self.start_or_idx & 1 == 1 => 0,
144            SpanData::LargeSpan => {
145                let (start, end) = INTERNER
146                    .lock()
147                    .unwrap()
148                    .get((self.start_or_idx >> 1) as usize);
149                end - start
150            }
151        }
152    }
153    pub fn offset(mut self, offset: Index) -> Self {
154        match self.data {
155            SpanData::Length(_) => self.start_or_idx += offset,
156            SpanData::LargeSpan if (self.start_or_idx & 1) == 1 => {
157                let new_start = (self.start_or_idx >> 1) + offset;
158                if new_start + offset <= (1 << 31) - 1 {
159                    self.start_or_idx = new_start
160                } else {
161                    self.start_or_idx =
162                        (INTERNER.lock().unwrap().add(new_start, new_start) as u32) << 1
163                }
164            }
165            SpanData::LargeSpan => {
166                let mut inter = INTERNER.lock().unwrap();
167                let (start, end) = inter.get((self.start_or_idx >> 1) as usize);
168                self.start_or_idx = inter.add(start + offset, end + offset) as u32;
169            }
170        }
171        self
172    }
173    pub fn signed_offset(self, offset: IndexOffset) -> Self {
174        if offset < 0 {
175            self.negative_offset(-offset as Index)
176        } else {
177            self.offset(offset as Index)
178        }
179    }
180    pub fn negative_offset(mut self, offset: Index) -> Self {
181        match self.data {
182            SpanData::LargeSpan if self.start_or_idx & 1 == 1 => {
183                let new_start = (self.start_or_idx >> 1) - offset;
184                if new_start + offset <= (1 << 31) - 1 {
185                    self.start_or_idx = new_start
186                } else {
187                    self.start_or_idx =
188                        (INTERNER.lock().unwrap().add(new_start, new_start) as u32) << 1
189                }
190            }
191            SpanData::LargeSpan => {
192                let mut inter = INTERNER.lock().unwrap();
193                let (start, end) = inter.get((self.start_or_idx >> 1) as usize);
194                self.start_or_idx = inter.add(start - offset, end - offset) as u32;
195            }
196            SpanData::Length(_) => self.start_or_idx -= offset,
197        }
198        self
199    }
200    pub fn extend(self, to: Self) -> Self {
201        if to.get_end() > self.get_start() {
202            Self::new(self.get_start(), to.get_end())
203        } else {
204            self
205        }
206    }
207}
208impl From<Range> for Span {
209    fn from(range: Range) -> Self {
210        Self::new(range.start, range.end)
211    }
212}
213impl Into<Range> for Span {
214    fn into(self) -> Range {
215        Range {
216            start: self.get_start(),
217            end: self.get_end(),
218        }
219    }
220}
221impl Into<std::ops::Range<usize>> for Span {
222    fn into(self) -> std::ops::Range<usize> {
223        std::ops::Range {
224            start: self.get_start() as usize,
225            end: self.get_end() as usize,
226        }
227    }
228}
229impl Display for Span {
230    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
231        f.write_fmt(format_args!(" [{},{}]", self.get_start(), self.get_end()))
232    }
233}
234impl Eq for Span {}
235impl PartialEq for Span {
236    fn eq(&self, other: &Self) -> bool {
237        self.get_start() == other.get_start() && self.get_end() == other.get_end()
238    }
239}