mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-14 04:03:47 +00:00
Bug 1403506 - Remove nsTFixedString<T>. r=erahm.
(patch is actually r=erahm,mystor) nsTFixedString<T> is only used as a base class for nsTAutoStringN<T, N>, so this patch merges the former into the latter, cutting some code and simplifying the string class hierarchy. Because the "Fixed" name is now gone, the patch also renames StringDataFlags::FIXED as INLINE and ClassDataFlags::FIXED as INLINE. The patch also removes nsFixed[C]String and ns_auto_[c]string! from Rust code because nsAutoString can't be implemented directly in Rust due to its move semantics. There were only two uses of ns_auto_string! outside of tests so this seems like a minor loss. MozReview-Commit-ID: 8ntximghiut --HG-- extra : rebase_source : f36edbae0553adcfee356fb8b311097ff7424786
This commit is contained in:
parent
32f449da79
commit
9e0714dd26
@ -506,7 +506,6 @@ function ignoreContents(entry)
|
||||
/(nsTSubstring<T>|nsAC?String)::StripTaggedASCII/,
|
||||
/(nsTSubstring<T>|nsAC?String)::operator=/,
|
||||
/nsTAutoStringN<T, N>::nsTAutoStringN/,
|
||||
/nsTFixedString<T>::nsTFixedString/,
|
||||
|
||||
// Similar for some other data structures
|
||||
/nsCOMArray_base::SetCapacity/,
|
||||
|
@ -21,8 +21,6 @@ extern "C" {
|
||||
|
||||
SIZE_ALIGN_CHECK(nsString)
|
||||
SIZE_ALIGN_CHECK(nsCString)
|
||||
SIZE_ALIGN_CHECK(nsFixedString)
|
||||
SIZE_ALIGN_CHECK(nsFixedCString)
|
||||
|
||||
#define MEMBER_CHECK(Clazz, Member) \
|
||||
extern "C" void Rust_Test_Member_##Clazz##_##Member(size_t* size, \
|
||||
@ -35,7 +33,7 @@ SIZE_ALIGN_CHECK(nsFixedCString)
|
||||
size_t size, align, offset; \
|
||||
Rust_Test_Member_##Clazz##_##Member(&size, &align, &offset); \
|
||||
EXPECT_EQ(size, sizeof(mozilla::DeclVal<Hack>().Member)); \
|
||||
EXPECT_EQ(size, alignof(decltype(mozilla::DeclVal<Hack>().Member))); \
|
||||
EXPECT_EQ(align, alignof(decltype(mozilla::DeclVal<Hack>().Member))); \
|
||||
EXPECT_EQ(offset, offsetof(Hack, Member)); \
|
||||
} \
|
||||
}; \
|
||||
@ -51,26 +49,22 @@ MEMBER_CHECK(nsCString, mData)
|
||||
MEMBER_CHECK(nsCString, mLength)
|
||||
MEMBER_CHECK(nsCString, mDataFlags)
|
||||
MEMBER_CHECK(nsCString, mClassFlags)
|
||||
MEMBER_CHECK(nsFixedString, mFixedCapacity)
|
||||
MEMBER_CHECK(nsFixedString, mFixedBuf)
|
||||
MEMBER_CHECK(nsFixedCString, mFixedCapacity)
|
||||
MEMBER_CHECK(nsFixedCString, mFixedBuf)
|
||||
|
||||
extern "C" void Rust_Test_NsStringFlags(uint16_t* f_terminated,
|
||||
uint16_t* f_voided,
|
||||
uint16_t* f_shared,
|
||||
uint16_t* f_owned,
|
||||
uint16_t* f_fixed,
|
||||
uint16_t* f_inline,
|
||||
uint16_t* f_literal,
|
||||
uint16_t* f_class_fixed,
|
||||
uint16_t* f_class_inline,
|
||||
uint16_t* f_class_null_terminated);
|
||||
TEST(RustNsString, NsStringFlags) {
|
||||
uint16_t f_terminated, f_voided, f_shared, f_owned, f_fixed, f_literal,
|
||||
f_class_fixed, f_class_null_terminated;
|
||||
uint16_t f_terminated, f_voided, f_shared, f_owned, f_inline, f_literal,
|
||||
f_class_inline, f_class_null_terminated;
|
||||
Rust_Test_NsStringFlags(&f_terminated,
|
||||
&f_voided, &f_shared,
|
||||
&f_owned, &f_fixed,
|
||||
&f_literal, &f_class_fixed, &f_class_null_terminated);
|
||||
&f_owned, &f_inline,
|
||||
&f_literal, &f_class_inline, &f_class_null_terminated);
|
||||
EXPECT_EQ(f_terminated, uint16_t(nsAString::DataFlags::TERMINATED));
|
||||
EXPECT_EQ(f_terminated, uint16_t(nsACString::DataFlags::TERMINATED));
|
||||
EXPECT_EQ(f_voided, uint16_t(nsAString::DataFlags::VOIDED));
|
||||
@ -79,12 +73,12 @@ TEST(RustNsString, NsStringFlags) {
|
||||
EXPECT_EQ(f_shared, uint16_t(nsACString::DataFlags::SHARED));
|
||||
EXPECT_EQ(f_owned, uint16_t(nsAString::DataFlags::OWNED));
|
||||
EXPECT_EQ(f_owned, uint16_t(nsACString::DataFlags::OWNED));
|
||||
EXPECT_EQ(f_fixed, uint16_t(nsAString::DataFlags::FIXED));
|
||||
EXPECT_EQ(f_fixed, uint16_t(nsACString::DataFlags::FIXED));
|
||||
EXPECT_EQ(f_inline, uint16_t(nsAString::DataFlags::INLINE));
|
||||
EXPECT_EQ(f_inline, uint16_t(nsACString::DataFlags::INLINE));
|
||||
EXPECT_EQ(f_literal, uint16_t(nsAString::DataFlags::LITERAL));
|
||||
EXPECT_EQ(f_literal, uint16_t(nsACString::DataFlags::LITERAL));
|
||||
EXPECT_EQ(f_class_fixed, uint16_t(nsAString::ClassFlags::FIXED));
|
||||
EXPECT_EQ(f_class_fixed, uint16_t(nsACString::ClassFlags::FIXED));
|
||||
EXPECT_EQ(f_class_inline, uint16_t(nsAString::ClassFlags::INLINE));
|
||||
EXPECT_EQ(f_class_inline, uint16_t(nsACString::ClassFlags::INLINE));
|
||||
EXPECT_EQ(f_class_null_terminated, uint16_t(nsAString::ClassFlags::NULL_TERMINATED));
|
||||
EXPECT_EQ(f_class_null_terminated, uint16_t(nsACString::ClassFlags::NULL_TERMINATED));
|
||||
}
|
||||
@ -119,14 +113,6 @@ extern "C" void Rust_AssignFromCpp();
|
||||
TEST(RustNsString, AssignFromCpp) {
|
||||
Rust_AssignFromCpp();
|
||||
}
|
||||
extern "C" void Rust_FixedAssignFromCpp();
|
||||
TEST(RustNsString, FixedAssignFromCpp) {
|
||||
Rust_FixedAssignFromCpp();
|
||||
}
|
||||
extern "C" void Rust_AutoAssignFromCpp();
|
||||
TEST(RustNsString, AutoAssignFromCpp) {
|
||||
Rust_AutoAssignFromCpp();
|
||||
}
|
||||
|
||||
extern "C" void Rust_StringWrite();
|
||||
TEST(RustNsString, StringWrite) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate nsstring;
|
||||
|
||||
use std::fmt::Write;
|
||||
@ -63,38 +62,10 @@ pub extern fn Rust_AssignFromCpp() {
|
||||
expect_eq!(s, "Hello, World!");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn Rust_FixedAssignFromCpp() {
|
||||
let mut cs_buf: [u8; 64] = [0; 64];
|
||||
let cs_buf_ptr = &cs_buf as *const _ as usize;
|
||||
let mut s_buf: [u16; 64] = [0; 64];
|
||||
let s_buf_ptr = &s_buf as *const _ as usize;
|
||||
let mut cs = nsFixedCString::new(&mut cs_buf);
|
||||
let mut s = nsFixedString::new(&mut s_buf);
|
||||
unsafe {
|
||||
Cpp_AssignFromCpp(&mut *cs, &mut *s);
|
||||
}
|
||||
expect_eq!(cs, "Hello, World!");
|
||||
expect_eq!(s, "Hello, World!");
|
||||
expect_eq!(cs.as_ptr() as usize, cs_buf_ptr);
|
||||
expect_eq!(s.as_ptr() as usize, s_buf_ptr);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn Rust_AutoAssignFromCpp() {
|
||||
ns_auto_cstring!(cs);
|
||||
ns_auto_string!(s);
|
||||
unsafe {
|
||||
Cpp_AssignFromCpp(&mut *cs, &mut *s);
|
||||
}
|
||||
expect_eq!(cs, "Hello, World!");
|
||||
expect_eq!(s, "Hello, World!");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn Rust_StringWrite() {
|
||||
ns_auto_cstring!(cs);
|
||||
ns_auto_string!(s);
|
||||
let mut cs = nsCString::new();
|
||||
let mut s = nsString::new();
|
||||
|
||||
write!(s, "a").unwrap();
|
||||
write!(cs, "a").unwrap();
|
||||
|
@ -18,12 +18,16 @@
|
||||
//! struct field, but passing the borrowed `&{mut,} nsA[C]String` over FFI is
|
||||
//! safe.
|
||||
//!
|
||||
//! Use `nsFixed[C]String` or `ns_auto_[c]string!` for dynamic stack allocated
|
||||
//! strings which are expected to hold short string values.
|
||||
//!
|
||||
//! Use `*{const,mut} nsA[C]String` (`{const,} nsA[C]String*` in C++) for
|
||||
//! function arguments passed across the rust/C++ language boundary.
|
||||
//!
|
||||
//! There is currently no Rust equivalent to nsAuto[C]String. Implementing a
|
||||
//! type that contains a pointer to an inline buffer is difficult in Rust due
|
||||
//! to its move semantics, which require that it be safe to move a value by
|
||||
//! copying its bits. If such a type is genuinely needed at some point,
|
||||
//! https://bugzilla.mozilla.org/show_bug.cgi?id=1403506#c6 has a sketch of how
|
||||
//! to emulate it via macros.
|
||||
//!
|
||||
//! # String Types
|
||||
//!
|
||||
//! ## `nsA[C]String`
|
||||
@ -94,36 +98,6 @@
|
||||
//! mutable reference. This struct may also be included in `#[repr(C)]` structs
|
||||
//! shared with C++.
|
||||
//!
|
||||
//! ## `nsFixed[C]String<'a>`
|
||||
//!
|
||||
//! This type is a string type with fixed backing storage. It is created with
|
||||
//! `nsFixed[C]String::new(buffer)`, passing a mutable reference to a buffer as
|
||||
//! the argument. This buffer will be used as backing storage whenever the
|
||||
//! resulting string will fit within it, falling back to heap allocations only
|
||||
//! when the string size exceeds that of the backing buffer.
|
||||
//!
|
||||
//! Like `ns[C]String`, this type dereferences to `nsA[C]String` which provides
|
||||
//! the methods for manipulating the type, and is not `#[repr(C)]`.
|
||||
//!
|
||||
//! When passing this type by reference, prefer passing a `&nsA[C]String` or
|
||||
//! `&mut nsA[C]String`. to passing this type.
|
||||
//!
|
||||
//! When passing this type across the language boundary, pass it as `*const
|
||||
//! nsA[C]String` for an immutable reference, or `*mut nsA[C]String` for a
|
||||
//! mutable reference. This struct may also be included in `#[repr(C)]`
|
||||
//! structs shared with C++, although `nsFixed[C]String` objects are uncommon
|
||||
//! as struct members.
|
||||
//!
|
||||
//! ## `ns_auto_[c]string!($name)`
|
||||
//!
|
||||
//! This is a helper macro which defines a fixed size, (currently 64 character),
|
||||
//! backing array on the stack, and defines a local variable with name `$name`
|
||||
//! which is a `nsFixed[C]String` using this buffer as its backing storage.
|
||||
//!
|
||||
//! Usage of this macro is similar to the C++ type `nsAuto[C]String`, but could
|
||||
//! not be implemented as a basic type due to the differences between rust and
|
||||
//! C++'s move semantics.
|
||||
//!
|
||||
//! ## `ns[C]StringRepr`
|
||||
//!
|
||||
//! This crate also provides the type `ns[C]StringRepr` which acts conceptually
|
||||
@ -151,9 +125,9 @@ use std::str;
|
||||
use std::u32;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
//////////////////////////////////
|
||||
// Internal Implemenation Flags //
|
||||
//////////////////////////////////
|
||||
///////////////////////////////////
|
||||
// Internal Implementation Flags //
|
||||
///////////////////////////////////
|
||||
|
||||
mod data_flags {
|
||||
bitflags! {
|
||||
@ -165,7 +139,7 @@ mod data_flags {
|
||||
const VOIDED = 1 << 1, // IsVoid returns true
|
||||
const SHARED = 1 << 2, // mData points to a heap-allocated, shared buffer
|
||||
const OWNED = 1 << 3, // mData points to a heap-allocated, raw buffer
|
||||
const FIXED = 1 << 4, // mData points to a fixed-size writable, dependent buffer
|
||||
const INLINE = 1 << 4, // mData points to a writable, inline buffer
|
||||
const LITERAL = 1 << 5, // mData points to a string literal; TERMINATED will also be set
|
||||
}
|
||||
}
|
||||
@ -177,7 +151,7 @@ mod class_flags {
|
||||
// over FFI safely as a u16.
|
||||
#[repr(C)]
|
||||
pub flags ClassFlags : u16 {
|
||||
const FIXED = 1 << 0, // |this| is of type nsTFixedString
|
||||
const INLINE = 1 << 0, // |this|'s buffer is inline
|
||||
const NULL_TERMINATED = 1 << 1, // |this| requires its buffer is null-terminated
|
||||
}
|
||||
}
|
||||
@ -197,7 +171,6 @@ macro_rules! define_string_types {
|
||||
AString = $AString: ident;
|
||||
String = $String: ident;
|
||||
Str = $Str: ident;
|
||||
FixedString = $FixedString: ident;
|
||||
|
||||
StringLike = $StringLike: ident;
|
||||
StringAdapter = $StringAdapter: ident;
|
||||
@ -431,12 +404,6 @@ macro_rules! define_string_types {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> cmp::PartialEq<$FixedString<'a>> for $AString {
|
||||
fn eq(&self, other: &$FixedString<'a>) -> bool {
|
||||
self.eq(&**other)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct $Str<'a> {
|
||||
hdr: $StringRepr,
|
||||
@ -702,100 +669,6 @@ macro_rules! define_string_types {
|
||||
}
|
||||
}
|
||||
|
||||
/// A nsFixed[C]String is a string which uses a fixed size mutable
|
||||
/// backing buffer for storing strings which will fit within that
|
||||
/// buffer, rather than using heap allocations.
|
||||
#[repr(C)]
|
||||
pub struct $FixedString<'a> {
|
||||
base: $String,
|
||||
capacity: u32,
|
||||
buffer: *mut $char_t,
|
||||
_marker: PhantomData<&'a mut [$char_t]>,
|
||||
}
|
||||
|
||||
impl<'a> $FixedString<'a> {
|
||||
pub fn new(buf: &'a mut [$char_t]) -> $FixedString<'a> {
|
||||
let len = buf.len();
|
||||
assert!(len < (u32::MAX as usize));
|
||||
let buf_ptr = buf.as_mut_ptr();
|
||||
$FixedString {
|
||||
base: $String {
|
||||
hdr: $StringRepr::new(class_flags::FIXED | class_flags::NULL_TERMINATED),
|
||||
},
|
||||
capacity: len as u32,
|
||||
buffer: buf_ptr,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for $FixedString<'a> {
|
||||
type Target = $AString;
|
||||
fn deref(&self) -> &$AString {
|
||||
&self.base
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for $FixedString<'a> {
|
||||
fn deref_mut(&mut self) -> &mut $AString {
|
||||
&mut self.base
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRef<[$char_t]> for $FixedString<'a> {
|
||||
fn as_ref(&self) -> &[$char_t] {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Write for $FixedString<'a> {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||
$AString::write_str(self, s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for $FixedString<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
<$AString as fmt::Display>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for $FixedString<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
<$AString as fmt::Debug>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> cmp::PartialEq for $FixedString<'a> {
|
||||
fn eq(&self, other: &$FixedString<'a>) -> bool {
|
||||
$AString::eq(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> cmp::PartialEq<[$char_t]> for $FixedString<'a> {
|
||||
fn eq(&self, other: &[$char_t]) -> bool {
|
||||
$AString::eq(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> cmp::PartialEq<&'b [$char_t]> for $FixedString<'a> {
|
||||
fn eq(&self, other: &&'b [$char_t]) -> bool {
|
||||
$AString::eq(self, *other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> cmp::PartialEq<str> for $FixedString<'a> {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
$AString::eq(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> cmp::PartialEq<&'b str> for $FixedString<'a> {
|
||||
fn eq(&self, other: &&'b str) -> bool {
|
||||
$AString::eq(self, *other)
|
||||
}
|
||||
}
|
||||
|
||||
/// An adapter type to allow for passing both types which coerce to
|
||||
/// &[$char_type], and &$AString to a function, while still performing
|
||||
/// optimized operations when passed the $AString.
|
||||
@ -865,12 +738,6 @@ macro_rules! define_string_types {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $StringLike for $FixedString<'a> {
|
||||
fn adapt(&self) -> $StringAdapter {
|
||||
$StringAdapter::Abstract(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl $StringLike for [$char_t] {
|
||||
fn adapt(&self) -> $StringAdapter {
|
||||
$StringAdapter::Borrowed($Str::from(self))
|
||||
@ -901,7 +768,6 @@ define_string_types! {
|
||||
AString = nsACString;
|
||||
String = nsCString;
|
||||
Str = nsCStr;
|
||||
FixedString = nsFixedCString;
|
||||
|
||||
StringLike = nsCStringLike;
|
||||
StringAdapter = nsCStringAdapter;
|
||||
@ -1025,14 +891,6 @@ impl nsCStringLike for Box<str> {
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ns_auto_cstring {
|
||||
($name:ident) => {
|
||||
let mut buf: [u8; 64] = [0; 64];
|
||||
let mut $name = $crate::nsFixedCString::new(&mut buf);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Bindings for nsString (u16 char type) //
|
||||
///////////////////////////////////////////
|
||||
@ -1043,7 +901,6 @@ define_string_types! {
|
||||
AString = nsAString;
|
||||
String = nsString;
|
||||
Str = nsStr;
|
||||
FixedString = nsFixedString;
|
||||
|
||||
StringLike = nsStringLike;
|
||||
StringAdapter = nsStringAdapter;
|
||||
@ -1125,14 +982,6 @@ impl cmp::PartialEq<str> for nsAString {
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ns_auto_string {
|
||||
($name:ident) => {
|
||||
let mut buf: [u16; 64] = [0; 64];
|
||||
let mut $name = $crate::nsFixedString::new(&mut buf);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn Gecko_IncrementStringAdoptCount(_: *mut c_void) {}
|
||||
@ -1183,8 +1032,6 @@ pub mod test_helpers {
|
||||
//! gtest code.
|
||||
|
||||
use super::{
|
||||
nsFixedCString,
|
||||
nsFixedString,
|
||||
nsCString,
|
||||
nsString,
|
||||
nsCStr,
|
||||
@ -1230,8 +1077,6 @@ pub mod test_helpers {
|
||||
Rust_Test_ReprSizeAlign_nsString);
|
||||
size_align_check!(nsCStringRepr, nsCString, nsCStr<'static>,
|
||||
Rust_Test_ReprSizeAlign_nsCString);
|
||||
size_align_check!(nsFixedString<'static>, Rust_Test_ReprSizeAlign_nsFixedString);
|
||||
size_align_check!(nsFixedCString<'static>, Rust_Test_ReprSizeAlign_nsFixedCString);
|
||||
|
||||
/// Generates a $[no_mangle] extern "C" function which returns the size,
|
||||
/// alignment and offset in the parent struct of a given member, with the
|
||||
@ -1312,10 +1157,6 @@ pub mod test_helpers {
|
||||
dataflags, Rust_Test_Member_nsCString_mDataFlags);
|
||||
member_check!(nsCStringRepr, nsCString, nsCStr<'static>,
|
||||
classflags, Rust_Test_Member_nsCString_mClassFlags);
|
||||
member_check!(nsFixedString<'static>, capacity, Rust_Test_Member_nsFixedString_mFixedCapacity);
|
||||
member_check!(nsFixedString<'static>, buffer, Rust_Test_Member_nsFixedString_mFixedBuf);
|
||||
member_check!(nsFixedCString<'static>, capacity, Rust_Test_Member_nsFixedCString_mFixedCapacity);
|
||||
member_check!(nsFixedCString<'static>, buffer, Rust_Test_Member_nsFixedCString_mFixedBuf);
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
@ -1323,18 +1164,18 @@ pub mod test_helpers {
|
||||
f_voided: *mut u16,
|
||||
f_shared: *mut u16,
|
||||
f_owned: *mut u16,
|
||||
f_fixed: *mut u16,
|
||||
f_inline: *mut u16,
|
||||
f_literal: *mut u16,
|
||||
f_class_fixed: *mut u16,
|
||||
f_class_inline: *mut u16,
|
||||
f_class_null_terminated: *mut u16) {
|
||||
unsafe {
|
||||
*f_terminated = data_flags::TERMINATED.bits();
|
||||
*f_voided = data_flags::VOIDED.bits();
|
||||
*f_shared = data_flags::SHARED.bits();
|
||||
*f_owned = data_flags::OWNED.bits();
|
||||
*f_fixed = data_flags::FIXED.bits();
|
||||
*f_inline = data_flags::INLINE.bits();
|
||||
*f_literal = data_flags::LITERAL.bits();
|
||||
*f_class_fixed = class_flags::FIXED.bits();
|
||||
*f_class_inline = class_flags::INLINE.bits();
|
||||
*f_class_null_terminated = class_flags::NULL_TERMINATED.bits();
|
||||
}
|
||||
}
|
||||
|
@ -40,30 +40,30 @@ enum class StringDataFlags : uint16_t
|
||||
//
|
||||
// Some comments about the string data flags:
|
||||
//
|
||||
// SHARED, OWNED, and FIXED are all mutually exlusive. They
|
||||
// SHARED, OWNED, and INLINE are all mutually exlusive. They
|
||||
// indicate the allocation type of mData. If none of these flags
|
||||
// are set, then the string buffer is dependent.
|
||||
//
|
||||
// SHARED, OWNED, or FIXED imply TERMINATED. This is because
|
||||
// SHARED, OWNED, or INLINE imply TERMINATED. This is because
|
||||
// the string classes always allocate null-terminated buffers, and
|
||||
// non-terminated substrings are always dependent.
|
||||
//
|
||||
// VOIDED implies TERMINATED, and moreover it implies that mData
|
||||
// points to char_traits::sEmptyBuffer. Therefore, VOIDED is
|
||||
// mutually exclusive with SHARED, OWNED, and FIXED.
|
||||
// mutually exclusive with SHARED, OWNED, and INLINE.
|
||||
|
||||
TERMINATED = 1 << 0, // IsTerminated returns true
|
||||
VOIDED = 1 << 1, // IsVoid returns true
|
||||
SHARED = 1 << 2, // mData points to a heap-allocated, shared buffer
|
||||
OWNED = 1 << 3, // mData points to a heap-allocated, raw buffer
|
||||
FIXED = 1 << 4, // mData points to a fixed-size writable, dependent buffer
|
||||
INLINE = 1 << 4, // mData points to a writable, inline buffer
|
||||
LITERAL = 1 << 5 // mData points to a string literal; DataFlags::TERMINATED will also be set
|
||||
};
|
||||
|
||||
// bits for mClassFlags
|
||||
enum class StringClassFlags : uint16_t
|
||||
{
|
||||
FIXED = 1 << 0, // |this| is of type nsTFixedString
|
||||
INLINE = 1 << 0, // |this|'s buffer is inline
|
||||
NULL_TERMINATED = 1 << 1 // |this| requires its buffer is null-terminated
|
||||
};
|
||||
|
||||
|
@ -34,7 +34,6 @@ template <typename T> class nsTPromiseFlatString;
|
||||
template <typename T> class nsTStringComparator;
|
||||
template <typename T> class nsTDefaultStringComparator;
|
||||
template <typename T> class nsTLiteralString;
|
||||
template <typename T> class nsTFixedString;
|
||||
|
||||
// We define this version without a size param instead of providing a
|
||||
// default value for N so that so there is a default typename that doesn't
|
||||
@ -55,7 +54,6 @@ using nsPromiseFlatString = nsTPromiseFlatString<char16_t>;
|
||||
using nsStringComparator = nsTStringComparator<char16_t>;
|
||||
using nsDefaultStringComparator = nsTDefaultStringComparator<char16_t>;
|
||||
using nsLiteralString = nsTLiteralString<char16_t>;
|
||||
using nsFixedString = nsTFixedString<char16_t>;
|
||||
|
||||
// Single-byte (char) string types.
|
||||
|
||||
@ -70,6 +68,5 @@ using nsPromiseFlatCString = nsTPromiseFlatString<char>;
|
||||
using nsCStringComparator = nsTStringComparator<char>;
|
||||
using nsDefaultCStringComparator = nsTDefaultStringComparator<char>;
|
||||
using nsLiteralCString = nsTLiteralString<char>;
|
||||
using nsFixedCString = nsTFixedString<char>;
|
||||
|
||||
#endif /* !defined(nsStringFwd_h) */
|
||||
|
@ -525,13 +525,24 @@ protected:
|
||||
//extern template class nsTString<char>;
|
||||
//extern template class nsTString<char16_t>;
|
||||
|
||||
template <typename T>
|
||||
class nsTFixedString : public nsTString<T>
|
||||
/**
|
||||
* nsTAutoStringN
|
||||
*
|
||||
* Subclass of nsTString that adds support for stack-based string
|
||||
* allocation. It is normally not a good idea to use this class on the
|
||||
* heap, because it will allocate space which may be wasted if the string
|
||||
* it contains is significantly smaller or any larger than 64 characters.
|
||||
*
|
||||
* NAMES:
|
||||
* nsAutoStringN / nsTAutoString for wide characters
|
||||
* nsAutoCStringN / nsTAutoCString for narrow characters
|
||||
*/
|
||||
template<typename T, size_t N>
|
||||
class MOZ_NON_MEMMOVABLE nsTAutoStringN : public nsTString<T>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef nsTFixedString<T> self_type;
|
||||
typedef nsTFixedString<T> fixed_string_type;
|
||||
typedef nsTAutoStringN<T, N> self_type;
|
||||
|
||||
typedef nsTString<T> base_string_type;
|
||||
typedef typename base_string_type::string_type string_type;
|
||||
@ -548,108 +559,6 @@ public:
|
||||
using typename base_string_type::IsChar;
|
||||
using typename base_string_type::IsChar16;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @param aData
|
||||
* fixed-size buffer to be used by the string (the contents of
|
||||
* this buffer may be modified by the string)
|
||||
* @param aStorageSize
|
||||
* the size of the fixed buffer
|
||||
* @param aLength (optional)
|
||||
* the length of the string already contained in the buffer
|
||||
*/
|
||||
|
||||
nsTFixedString(char_type* aData, size_type aStorageSize)
|
||||
: string_type(aData, uint32_t(char_traits::length(aData)),
|
||||
DataFlags::TERMINATED | DataFlags::FIXED,
|
||||
ClassFlags::FIXED)
|
||||
, mFixedCapacity(aStorageSize - 1)
|
||||
, mFixedBuf(aData)
|
||||
{
|
||||
}
|
||||
|
||||
nsTFixedString(char_type* aData, size_type aStorageSize,
|
||||
size_type aLength)
|
||||
: string_type(aData, aLength, DataFlags::TERMINATED | DataFlags::FIXED,
|
||||
ClassFlags::FIXED)
|
||||
, mFixedCapacity(aStorageSize - 1)
|
||||
, mFixedBuf(aData)
|
||||
{
|
||||
// null-terminate
|
||||
mFixedBuf[aLength] = char_type(0);
|
||||
}
|
||||
|
||||
// |operator=| does not inherit, so we must define our own
|
||||
self_type& operator=(char_type aChar)
|
||||
{
|
||||
this->Assign(aChar);
|
||||
return *this;
|
||||
}
|
||||
self_type& operator=(const char_type* aData)
|
||||
{
|
||||
this->Assign(aData);
|
||||
return *this;
|
||||
}
|
||||
self_type& operator=(const substring_type& aStr)
|
||||
{
|
||||
this->Assign(aStr);
|
||||
return *this;
|
||||
}
|
||||
self_type& operator=(const substring_tuple_type& aTuple)
|
||||
{
|
||||
this->Assign(aTuple);
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
friend class nsTSubstring<T>;
|
||||
|
||||
size_type mFixedCapacity;
|
||||
char_type* mFixedBuf;
|
||||
};
|
||||
|
||||
extern template class nsTFixedString<char>;
|
||||
extern template class nsTFixedString<char>;
|
||||
|
||||
/**
|
||||
* nsTAutoStringN
|
||||
*
|
||||
* Subclass of nsTString that adds support for stack-based string
|
||||
* allocation. It is normally not a good idea to use this class on the
|
||||
* heap, because it will allocate space which may be wasted if the string
|
||||
* it contains is significantly smaller or any larger than 64 characters.
|
||||
*
|
||||
* NAMES:
|
||||
* nsAutoStringN / nsTAutoString for wide characters
|
||||
* nsAutoCStringN / nsTAutoCString for narrow characters
|
||||
*/
|
||||
template<typename T, size_t N>
|
||||
class MOZ_NON_MEMMOVABLE nsTAutoStringN : public nsTFixedString<T>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef nsTAutoStringN<T, N> self_type;
|
||||
|
||||
#ifdef __clang__
|
||||
// bindgen w/ clang 3.9 at least chokes on a typedef, but using is okay.
|
||||
using typename nsTFixedString<T>::fixed_string_type;
|
||||
#else
|
||||
// On the other hand msvc chokes on the using statement. It seems others
|
||||
// don't care either way so we lump them in here.
|
||||
typedef typename nsTFixedString<T>::fixed_string_type fixed_string_type;
|
||||
#endif
|
||||
|
||||
typedef typename fixed_string_type::char_type char_type;
|
||||
typedef typename fixed_string_type::char_traits char_traits;
|
||||
typedef typename fixed_string_type::substring_type substring_type;
|
||||
typedef typename fixed_string_type::size_type size_type;
|
||||
typedef typename fixed_string_type::substring_tuple_type substring_tuple_type;
|
||||
|
||||
using typename fixed_string_type::IsChar;
|
||||
using typename fixed_string_type::IsChar16;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -657,20 +566,24 @@ public:
|
||||
*/
|
||||
|
||||
nsTAutoStringN()
|
||||
: fixed_string_type(mStorage, N, 0)
|
||||
: string_type(mStorage, 0, DataFlags::TERMINATED | DataFlags::INLINE,
|
||||
ClassFlags::INLINE)
|
||||
, mInlineCapacity(N - 1)
|
||||
{
|
||||
// null-terminate
|
||||
mStorage[0] = char_type(0);
|
||||
}
|
||||
|
||||
explicit
|
||||
nsTAutoStringN(char_type aChar)
|
||||
: fixed_string_type(mStorage, N, 0)
|
||||
: self_type()
|
||||
{
|
||||
this->Assign(aChar);
|
||||
}
|
||||
|
||||
explicit
|
||||
nsTAutoStringN(const char_type* aData, size_type aLength = size_type(-1))
|
||||
: fixed_string_type(mStorage, N, 0)
|
||||
: self_type()
|
||||
{
|
||||
this->Assign(aData, aLength);
|
||||
}
|
||||
@ -679,26 +592,26 @@ public:
|
||||
template <typename EnableIfChar16 = IsChar16>
|
||||
explicit
|
||||
nsTAutoStringN(char16ptr_t aData, size_type aLength = size_type(-1))
|
||||
: nsTAutoStringN(static_cast<const char16_t*>(aData), aLength)
|
||||
: self_type(static_cast<const char16_t*>(aData), aLength)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
nsTAutoStringN(const self_type& aStr)
|
||||
: fixed_string_type(mStorage, N, 0)
|
||||
: self_type()
|
||||
{
|
||||
this->Assign(aStr);
|
||||
}
|
||||
|
||||
explicit
|
||||
nsTAutoStringN(const substring_type& aStr)
|
||||
: fixed_string_type(mStorage, N, 0)
|
||||
: self_type()
|
||||
{
|
||||
this->Assign(aStr);
|
||||
}
|
||||
|
||||
MOZ_IMPLICIT nsTAutoStringN(const substring_tuple_type& aTuple)
|
||||
: fixed_string_type(mStorage, N, 0)
|
||||
: self_type()
|
||||
{
|
||||
this->Assign(aTuple);
|
||||
}
|
||||
@ -740,8 +653,12 @@ public:
|
||||
|
||||
static const size_t kStorageSize = N;
|
||||
|
||||
private:
|
||||
protected:
|
||||
friend class nsTSubstring<T>;
|
||||
|
||||
size_type mInlineCapacity;
|
||||
|
||||
private:
|
||||
char_type mStorage[N];
|
||||
};
|
||||
|
||||
|
@ -37,13 +37,13 @@ nsTSubstring<T>::nsTSubstring(char_type* aData, size_type aLength,
|
||||
#endif /* XPCOM_STRING_CONSTRUCTOR_OUT_OF_LINE */
|
||||
|
||||
/**
|
||||
* helper function for down-casting a nsTSubstring to a nsTFixedString.
|
||||
* helper function for down-casting a nsTSubstring to an nsTAutoString.
|
||||
*/
|
||||
template <typename T>
|
||||
inline const nsTFixedString<T>*
|
||||
AsFixedString(const nsTSubstring<T>* aStr)
|
||||
inline const nsTAutoString<T>*
|
||||
AsAutoString(const nsTSubstring<T>* aStr)
|
||||
{
|
||||
return static_cast<const nsTFixedString<T>*>(aStr);
|
||||
return static_cast<const nsTAutoString<T>*>(aStr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,7 +122,7 @@ nsTSubstring<T>::MutatePrep(size_type aCapacity, char_type** aOldData,
|
||||
//
|
||||
// (1) we have a shared buffer (this->mDataFlags & DataFlags::SHARED)
|
||||
// (2) we have an owned buffer (this->mDataFlags & DataFlags::OWNED)
|
||||
// (3) we have a fixed buffer (this->mDataFlags & DataFlags::FIXED)
|
||||
// (3) we have an inline buffer (this->mDataFlags & DataFlags::INLINE)
|
||||
// (4) we have a readonly buffer
|
||||
//
|
||||
// requiring that we in some cases preserve the data before creating
|
||||
@ -150,16 +150,16 @@ nsTSubstring<T>::MutatePrep(size_type aCapacity, char_type** aOldData,
|
||||
char_type* newData;
|
||||
DataFlags newDataFlags;
|
||||
|
||||
// if we have a fixed buffer of sufficient size, then use it. this helps
|
||||
// avoid heap allocations.
|
||||
if ((this->mClassFlags & ClassFlags::FIXED) &&
|
||||
(aCapacity < AsFixedString(this)->mFixedCapacity)) {
|
||||
newData = AsFixedString(this)->mFixedBuf;
|
||||
newDataFlags = DataFlags::TERMINATED | DataFlags::FIXED;
|
||||
// If this is an nsTAutoStringN whose inline buffer is sufficiently large,
|
||||
// then use it. This helps avoid heap allocations.
|
||||
if ((this->mClassFlags & ClassFlags::INLINE) &&
|
||||
(aCapacity < AsAutoString(this)->mInlineCapacity)) {
|
||||
newData = (char_type*)AsAutoString(this)->mStorage;
|
||||
newDataFlags = DataFlags::TERMINATED | DataFlags::INLINE;
|
||||
} else {
|
||||
// if we reach here then, we must allocate a new buffer. we cannot
|
||||
// make use of our DataFlags::OWNED or DataFlags::FIXED buffers because they are not
|
||||
// large enough.
|
||||
// make use of our DataFlags::OWNED or DataFlags::INLINE buffers because
|
||||
// they are not large enough.
|
||||
|
||||
nsStringBuffer* newHdr =
|
||||
nsStringBuffer::Alloc(storageSize).take();
|
||||
@ -283,8 +283,8 @@ nsTSubstring<T>::Capacity() const
|
||||
} else {
|
||||
capacity = (hdr->StorageSize() / sizeof(char_type)) - 1;
|
||||
}
|
||||
} else if (this->mDataFlags & DataFlags::FIXED) {
|
||||
capacity = AsFixedString(this)->mFixedCapacity;
|
||||
} else if (this->mDataFlags & DataFlags::INLINE) {
|
||||
capacity = AsAutoString(this)->mInlineCapacity;
|
||||
} else if (this->mDataFlags & DataFlags::OWNED) {
|
||||
// we don't store the capacity of an adopted buffer because that would
|
||||
// require an additional member field. the best we can do is base the
|
||||
@ -303,7 +303,7 @@ bool
|
||||
nsTSubstring<T>::EnsureMutable(size_type aNewLen)
|
||||
{
|
||||
if (aNewLen == size_type(-1) || aNewLen == this->mLength) {
|
||||
if (this->mDataFlags & (DataFlags::FIXED | DataFlags::OWNED)) {
|
||||
if (this->mDataFlags & (DataFlags::INLINE | DataFlags::OWNED)) {
|
||||
return true;
|
||||
}
|
||||
if ((this->mDataFlags & DataFlags::SHARED) &&
|
||||
@ -1177,10 +1177,10 @@ nsTSubstring<T>::SizeOfExcludingThisIfUnshared(
|
||||
|
||||
// If we reach here, exactly one of the following must be true:
|
||||
// - DataFlags::VOIDED is set, and this->mData points to sEmptyBuffer;
|
||||
// - DataFlags::FIXED is set, and this->mData points to a buffer within a string
|
||||
// object (e.g. nsAutoString);
|
||||
// - None of DataFlags::SHARED, DataFlags::OWNED, DataFlags::FIXED is set, and this->mData points to a buffer
|
||||
// owned by something else.
|
||||
// - DataFlags::INLINE is set, and this->mData points to a buffer within a
|
||||
// string object (e.g. nsAutoString);
|
||||
// - None of DataFlags::SHARED, DataFlags::OWNED, DataFlags::INLINE is set,
|
||||
// and this->mData points to a buffer owned by something else.
|
||||
//
|
||||
// In all three cases, we don't measure it.
|
||||
return 0;
|
||||
|
@ -27,8 +27,6 @@ template class nsTDependentSubstring<char16_t>;
|
||||
// Note: nsTString is skipped as it's implicitly instantiated by derived
|
||||
// classes.
|
||||
|
||||
template class nsTFixedString<char>;
|
||||
template class nsTFixedString<char16_t>;
|
||||
template class nsTAutoStringN<char, 64>;
|
||||
template class nsTAutoStringN<char16_t, 64>;
|
||||
|
||||
|
@ -426,20 +426,6 @@ TEST(Strings, equals_ic)
|
||||
EXPECT_FALSE(s.LowerCaseEqualsLiteral("view-source"));
|
||||
}
|
||||
|
||||
TEST(Strings, fixed_string)
|
||||
{
|
||||
char buf[256] = "hello world";
|
||||
|
||||
nsFixedCString s(buf, sizeof(buf));
|
||||
|
||||
EXPECT_EQ(s.Length(), strlen(buf));
|
||||
|
||||
EXPECT_STREQ(s.get(), buf);
|
||||
|
||||
s.Assign("foopy doopy doo");
|
||||
EXPECT_EQ(s.get(), buf);
|
||||
}
|
||||
|
||||
TEST(Strings, concat)
|
||||
{
|
||||
nsCString bar("bar");
|
||||
|
Loading…
x
Reference in New Issue
Block a user