diff options
Diffstat (limited to 'vendor/object/src/write/string.rs')
-rw-r--r-- | vendor/object/src/write/string.rs | 159 |
1 files changed, 0 insertions, 159 deletions
diff --git a/vendor/object/src/write/string.rs b/vendor/object/src/write/string.rs deleted file mode 100644 index b23274a..0000000 --- a/vendor/object/src/write/string.rs +++ /dev/null @@ -1,159 +0,0 @@ -use alloc::vec::Vec; - -#[cfg(feature = "std")] -type IndexSet<K> = indexmap::IndexSet<K>; -#[cfg(not(feature = "std"))] -type IndexSet<K> = indexmap::IndexSet<K, hashbrown::hash_map::DefaultHashBuilder>; - -/// An identifier for an entry in a string table. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct StringId(usize); - -#[derive(Debug, Default)] -pub(crate) struct StringTable<'a> { - strings: IndexSet<&'a [u8]>, - offsets: Vec<usize>, -} - -impl<'a> StringTable<'a> { - /// Add a string to the string table. - /// - /// Panics if the string table has already been written, or - /// if the string contains a null byte. - pub fn add(&mut self, string: &'a [u8]) -> StringId { - assert!(self.offsets.is_empty()); - assert!(!string.contains(&0)); - let id = self.strings.insert_full(string).0; - StringId(id) - } - - /// Return the id of the given string. - /// - /// Panics if the string is not in the string table. - pub fn get_id(&self, string: &[u8]) -> StringId { - let id = self.strings.get_index_of(string).unwrap(); - StringId(id) - } - - /// Return the string for the given id. - /// - /// Panics if the string is not in the string table. - pub fn get_string(&self, id: StringId) -> &'a [u8] { - self.strings.get_index(id.0).unwrap() - } - - /// Return the offset of the given string. - /// - /// Panics if the string table has not been written, or - /// if the string is not in the string table. - pub fn get_offset(&self, id: StringId) -> usize { - self.offsets[id.0] - } - - /// Append the string table to the given `Vec`, and - /// calculate the list of string offsets. - /// - /// `base` is the initial string table offset. For example, - /// this should be 1 for ELF, to account for the initial - /// null byte (which must have been written by the caller). - pub fn write(&mut self, base: usize, w: &mut Vec<u8>) { - assert!(self.offsets.is_empty()); - - let mut ids: Vec<_> = (0..self.strings.len()).collect(); - sort(&mut ids, 1, &self.strings); - - self.offsets = vec![0; ids.len()]; - let mut offset = base; - let mut previous = &[][..]; - for id in ids { - let string = self.strings.get_index(id).unwrap(); - if previous.ends_with(string) { - self.offsets[id] = offset - string.len() - 1; - } else { - self.offsets[id] = offset; - w.extend_from_slice(string); - w.push(0); - offset += string.len() + 1; - previous = string; - } - } - } -} - -// Multi-key quicksort. -// -// Ordering is such that if a string is a suffix of at least one other string, -// then it is placed immediately after one of those strings. That is: -// - comparison starts at the end of the string -// - shorter strings come later -// -// Based on the implementation in LLVM. -fn sort(mut ids: &mut [usize], mut pos: usize, strings: &IndexSet<&[u8]>) { - loop { - if ids.len() <= 1 { - return; - } - - let pivot = byte(ids[0], pos, strings); - let mut lower = 0; - let mut upper = ids.len(); - let mut i = 1; - while i < upper { - let b = byte(ids[i], pos, strings); - if b > pivot { - ids.swap(lower, i); - lower += 1; - i += 1; - } else if b < pivot { - upper -= 1; - ids.swap(upper, i); - } else { - i += 1; - } - } - - sort(&mut ids[..lower], pos, strings); - sort(&mut ids[upper..], pos, strings); - - if pivot == 0 { - return; - } - ids = &mut ids[lower..upper]; - pos += 1; - } -} - -fn byte(id: usize, pos: usize, strings: &IndexSet<&[u8]>) -> u8 { - let string = strings.get_index(id).unwrap(); - let len = string.len(); - if len >= pos { - string[len - pos] - } else { - // We know the strings don't contain null bytes. - 0 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn string_table() { - let mut table = StringTable::default(); - let id0 = table.add(b""); - let id1 = table.add(b"foo"); - let id2 = table.add(b"bar"); - let id3 = table.add(b"foobar"); - - let mut data = Vec::new(); - data.push(0); - table.write(1, &mut data); - assert_eq!(data, b"\0foobar\0foo\0"); - - assert_eq!(table.get_offset(id0), 11); - assert_eq!(table.get_offset(id1), 8); - assert_eq!(table.get_offset(id2), 4); - assert_eq!(table.get_offset(id3), 1); - } -} |