|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef mozilla_dom_DOMString_h |
|
7 #define mozilla_dom_DOMString_h |
|
8 |
|
9 #include "nsStringGlue.h" |
|
10 #include "nsStringBuffer.h" |
|
11 #include "mozilla/Assertions.h" |
|
12 #include "mozilla/Attributes.h" |
|
13 #include "mozilla/Maybe.h" |
|
14 #include "nsDOMString.h" |
|
15 #include "nsIAtom.h" |
|
16 |
|
17 namespace mozilla { |
|
18 namespace dom { |
|
19 |
|
20 /** |
|
21 * A class for representing string return values. This can be either passed to |
|
22 * callees that have an nsString or nsAString out param or passed to a callee |
|
23 * that actually knows about this class and can work with it. Such a callee may |
|
24 * call SetStringBuffer or SetOwnedString or SetOwnedAtom on this object, but |
|
25 * only if it plans to keep holding a strong ref to the internal stringbuffer! |
|
26 * |
|
27 * The proper way to store a value in this class is to either to do nothing |
|
28 * (which leaves this as an empty string), to call SetStringBuffer with a |
|
29 * non-null stringbuffer, to call SetOwnedString, to call SetOwnedAtom, to call |
|
30 * SetNull(), or to call AsAString() and set the value in the resulting |
|
31 * nsString. These options are mutually exclusive! Don't do more than one of |
|
32 * them. |
|
33 * |
|
34 * The proper way to extract a value is to check IsNull(). If not null, then |
|
35 * check HasStringBuffer(). If that's true, check for a zero length, and if the |
|
36 * length is nonzero call StringBuffer(). If the length is zero this is the |
|
37 * empty string. If HasStringBuffer() returns false, call AsAString() and get |
|
38 * the value from that. |
|
39 */ |
|
40 class MOZ_STACK_CLASS DOMString { |
|
41 public: |
|
42 DOMString() |
|
43 : mStringBuffer(nullptr) |
|
44 , mLength(0) |
|
45 , mIsNull(false) |
|
46 {} |
|
47 ~DOMString() |
|
48 { |
|
49 MOZ_ASSERT(mString.empty() || !mStringBuffer, |
|
50 "Shouldn't have both present!"); |
|
51 } |
|
52 |
|
53 operator nsString&() |
|
54 { |
|
55 return AsAString(); |
|
56 } |
|
57 |
|
58 nsString& AsAString() |
|
59 { |
|
60 MOZ_ASSERT(!mStringBuffer, "We already have a stringbuffer?"); |
|
61 MOZ_ASSERT(!mIsNull, "We're already set as null"); |
|
62 if (mString.empty()) { |
|
63 mString.construct(); |
|
64 } |
|
65 return mString.ref(); |
|
66 } |
|
67 |
|
68 bool HasStringBuffer() const |
|
69 { |
|
70 MOZ_ASSERT(mString.empty() || !mStringBuffer, |
|
71 "Shouldn't have both present!"); |
|
72 MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first"); |
|
73 return mString.empty(); |
|
74 } |
|
75 |
|
76 // Get the stringbuffer. This can only be called if HasStringBuffer() |
|
77 // returned true and StringBufferLength() is nonzero. If that's true, it will |
|
78 // never return null. |
|
79 nsStringBuffer* StringBuffer() const |
|
80 { |
|
81 MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first"); |
|
82 MOZ_ASSERT(HasStringBuffer(), |
|
83 "Don't ask for the stringbuffer if we don't have it"); |
|
84 MOZ_ASSERT(StringBufferLength() != 0, "Why are you asking for this?"); |
|
85 MOZ_ASSERT(mStringBuffer, |
|
86 "If our length is nonzero, we better have a stringbuffer."); |
|
87 return mStringBuffer; |
|
88 } |
|
89 |
|
90 // Get the length of the stringbuffer. Can only be called if |
|
91 // HasStringBuffer(). |
|
92 uint32_t StringBufferLength() const |
|
93 { |
|
94 MOZ_ASSERT(HasStringBuffer(), "Don't call this if there is no stringbuffer"); |
|
95 return mLength; |
|
96 } |
|
97 |
|
98 void SetStringBuffer(nsStringBuffer* aStringBuffer, uint32_t aLength) |
|
99 { |
|
100 MOZ_ASSERT(mString.empty(), "We already have a string?"); |
|
101 MOZ_ASSERT(!mIsNull, "We're already set as null"); |
|
102 MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?"); |
|
103 MOZ_ASSERT(aStringBuffer, "Why are we getting null?"); |
|
104 mStringBuffer = aStringBuffer; |
|
105 mLength = aLength; |
|
106 } |
|
107 |
|
108 void SetOwnedString(const nsAString& aString) |
|
109 { |
|
110 MOZ_ASSERT(mString.empty(), "We already have a string?"); |
|
111 MOZ_ASSERT(!mIsNull, "We're already set as null"); |
|
112 MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?"); |
|
113 nsStringBuffer* buf = nsStringBuffer::FromString(aString); |
|
114 if (buf) { |
|
115 SetStringBuffer(buf, aString.Length()); |
|
116 } else if (aString.IsVoid()) { |
|
117 SetNull(); |
|
118 } else if (!aString.IsEmpty()) { |
|
119 AsAString() = aString; |
|
120 } |
|
121 } |
|
122 |
|
123 enum NullHandling |
|
124 { |
|
125 eTreatNullAsNull, |
|
126 eTreatNullAsEmpty, |
|
127 eNullNotExpected |
|
128 }; |
|
129 |
|
130 void SetOwnedAtom(nsIAtom* aAtom, NullHandling aNullHandling) |
|
131 { |
|
132 MOZ_ASSERT(mString.empty(), "We already have a string?"); |
|
133 MOZ_ASSERT(!mIsNull, "We're already set as null"); |
|
134 MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?"); |
|
135 MOZ_ASSERT(aAtom || aNullHandling != eNullNotExpected); |
|
136 if (aNullHandling == eNullNotExpected || aAtom) { |
|
137 SetStringBuffer(aAtom->GetStringBuffer(), aAtom->GetLength()); |
|
138 } else if (aNullHandling == eTreatNullAsNull) { |
|
139 SetNull(); |
|
140 } |
|
141 } |
|
142 |
|
143 void SetNull() |
|
144 { |
|
145 MOZ_ASSERT(!mStringBuffer, "Should have no stringbuffer if null"); |
|
146 MOZ_ASSERT(mString.empty(), "Should have no string if null"); |
|
147 mIsNull = true; |
|
148 } |
|
149 |
|
150 bool IsNull() const |
|
151 { |
|
152 MOZ_ASSERT(!mStringBuffer || mString.empty(), |
|
153 "How could we have a stringbuffer and a nonempty string?"); |
|
154 return mIsNull || (!mString.empty() && mString.ref().IsVoid()); |
|
155 } |
|
156 |
|
157 void ToString(nsAString& aString) |
|
158 { |
|
159 if (IsNull()) { |
|
160 SetDOMStringToNull(aString); |
|
161 } else if (HasStringBuffer()) { |
|
162 if (StringBufferLength() == 0) { |
|
163 aString.Truncate(); |
|
164 } else { |
|
165 StringBuffer()->ToString(StringBufferLength(), aString); |
|
166 } |
|
167 } else { |
|
168 aString = AsAString(); |
|
169 } |
|
170 } |
|
171 |
|
172 private: |
|
173 // We need to be able to act like a string as needed |
|
174 Maybe<nsAutoString> mString; |
|
175 |
|
176 // For callees that know we exist, we can be a stringbuffer/length/null-flag |
|
177 // triple. |
|
178 nsStringBuffer* mStringBuffer; |
|
179 uint32_t mLength; |
|
180 bool mIsNull; |
|
181 }; |
|
182 |
|
183 } // namespace dom |
|
184 } // namespace mozilla |
|
185 |
|
186 #endif // mozilla_dom_DOMString_h |