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. pubfn add(&mutself, 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. #[allow(dead_code)] pubfn 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. #[allow(dead_code)] pubfn 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. pubfn 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). /// /// Panics if the string table has already been written. pubfn write(&mutself, base: usize, w: &mut Vec<u8>) {
assert!(self.offsets.is_empty());
self.offsets = vec![0; ids.len()]; letmut offset = base; letmut 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;
}
}
}
/// Calculate the size in bytes of the string table. /// /// `base` is the initial string table offset. For example, /// this should be 1 for ELF, to account for the initial /// null byte. #[allow(dead_code)] pubfn size(&self, base: usize) -> usize { // TODO: cache this result? letmut ids: Vec<_> = (0..self.strings.len()).collect();
sort(&mut ids, 1, &self.strings);
letmut size = base; letmut previous = &[][..]; for id in ids { let string = self.strings.get_index(id).unwrap(); if !previous.ends_with(string) {
size += string.len() + 1;
previous = string;
}
}
size
}
}
// 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); letmut lower = 0; letmut upper = ids.len(); letmut i = 1; while i < upper { let b = byte(ids[i], pos, strings); if b > pivot {
ids.swap(lower, i);
lower += 1;
i += 1;
} elseif b < pivot {
upper -= 1;
ids.swap(upper, i);
} else {
i += 1;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.