Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/dom/FakeString.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_dom_FakeString_h__
8
#define mozilla_dom_FakeString_h__
9
10
#include "nsString.h"
11
#include "nsStringBuffer.h"
12
#include "mozilla/RefPtr.h"
13
#include "mozilla/Span.h"
14
15
namespace mozilla {
16
namespace dom {
17
namespace binding_detail {
18
// A struct that has the same layout as an nsString but much faster
19
// constructor and destructor behavior. FakeString uses inline storage
20
// for small strings and a nsStringBuffer for longer strings.
21
struct FakeString {
22
  FakeString() :
23
    mDataFlags(nsString::DataFlags::TERMINATED),
24
    mClassFlags(nsString::ClassFlags(0))
25
14
  {
26
14
  }
27
28
14
  ~FakeString() {
29
14
    if (mDataFlags & nsString::DataFlags::REFCOUNTED) {
30
0
      nsStringBuffer::FromData(mData)->Release();
31
0
    }
32
14
  }
33
34
0
  void Rebind(const nsString::char_type* aData, nsString::size_type aLength) {
35
0
    MOZ_ASSERT(mDataFlags == nsString::DataFlags::TERMINATED);
36
0
    mData = const_cast<nsString::char_type*>(aData);
37
0
    mLength = aLength;
38
0
  }
39
40
  // Share aString's string buffer, if it has one; otherwise, make this string
41
  // depend upon aString's data.  aString should outlive this instance of
42
  // FakeString.
43
0
  void ShareOrDependUpon(const nsAString& aString) {
44
0
    RefPtr<nsStringBuffer> sharedBuffer = nsStringBuffer::FromString(aString);
45
0
    if (!sharedBuffer) {
46
0
      Rebind(aString.Data(), aString.Length());
47
0
    } else {
48
0
      AssignFromStringBuffer(sharedBuffer.forget());
49
0
      mLength = aString.Length();
50
0
    }
51
0
  }
52
53
0
  void Truncate() {
54
0
    MOZ_ASSERT(mDataFlags == nsString::DataFlags::TERMINATED);
55
0
    mData = nsString::char_traits::sEmptyBuffer;
56
0
    mLength = 0;
57
0
  }
58
59
0
  void SetIsVoid(bool aValue) {
60
0
    MOZ_ASSERT(aValue,
61
0
               "We don't support SetIsVoid(false) on FakeString!");
62
0
    Truncate();
63
0
    mDataFlags |= nsString::DataFlags::VOIDED;
64
0
  }
65
66
  const nsString::char_type* Data() const
67
0
  {
68
0
    return mData;
69
0
  }
70
71
  nsString::char_type* BeginWriting()
72
14
  {
73
14
    MOZ_ASSERT(!(mDataFlags & nsString::DataFlags::REFCOUNTED) ||
74
14
               !nsStringBuffer::FromData(mData)->IsReadonly());
75
14
    return mData;
76
14
  }
77
78
  nsString::size_type Length() const
79
0
  {
80
0
    return mLength;
81
0
  }
82
83
  operator mozilla::Span<const nsString::char_type>() const
84
0
  {
85
0
    return mozilla::MakeSpan(Data(), Length());
86
0
  }
87
88
  operator mozilla::Span<nsString::char_type>()
89
0
  {
90
0
    return mozilla::MakeSpan(BeginWriting(), Length());
91
0
  }
92
93
  // Reserve space to write aLength chars, not including null-terminator.
94
14
  bool SetLength(nsString::size_type aLength, mozilla::fallible_t const&) {
95
14
    // Use mInlineStorage for small strings.
96
14
    if (aLength < sInlineCapacity) {
97
14
      SetData(mInlineStorage);
98
14
    } else {
99
0
      RefPtr<nsStringBuffer> buf = nsStringBuffer::Alloc((aLength + 1) * sizeof(nsString::char_type));
100
0
      if (MOZ_UNLIKELY(!buf)) {
101
0
        return false;
102
0
      }
103
0
104
0
      AssignFromStringBuffer(buf.forget());
105
0
    }
106
14
    mLength = aLength;
107
14
    mData[mLength] = char16_t(0);
108
14
    return true;
109
14
  }
110
111
  // If this ever changes, change the corresponding code in the
112
  // Optional<nsAString> specialization as well.
113
0
  const nsAString* ToAStringPtr() const {
114
0
    return reinterpret_cast<const nsString*>(this);
115
0
  }
116
117
14
operator const nsAString& () const {
118
14
    return *reinterpret_cast<const nsString*>(this);
119
14
  }
120
121
private:
122
0
  nsAString* ToAStringPtr() {
123
0
    return reinterpret_cast<nsString*>(this);
124
0
  }
125
126
  // mData is left uninitialized for optimization purposes.
127
  MOZ_INIT_OUTSIDE_CTOR nsString::char_type* mData;
128
  // mLength is left uninitialized for optimization purposes.
129
  MOZ_INIT_OUTSIDE_CTOR nsString::size_type mLength;
130
  nsString::DataFlags mDataFlags;
131
  nsString::ClassFlags mClassFlags;
132
133
  static const size_t sInlineCapacity = 64;
134
  nsString::char_type mInlineStorage[sInlineCapacity];
135
136
  FakeString(const FakeString& other) = delete;
137
  void operator=(const FakeString& other) = delete;
138
139
14
  void SetData(nsString::char_type* aData) {
140
14
    MOZ_ASSERT(mDataFlags == nsString::DataFlags::TERMINATED);
141
14
    mData = const_cast<nsString::char_type*>(aData);
142
14
  }
143
0
  void AssignFromStringBuffer(already_AddRefed<nsStringBuffer> aBuffer) {
144
0
    SetData(static_cast<nsString::char_type*>(aBuffer.take()->Data()));
145
0
    mDataFlags = nsString::DataFlags::REFCOUNTED | nsString::DataFlags::TERMINATED;
146
0
  }
147
148
  friend class NonNull<nsAString>;
149
150
  // A class to use for our static asserts to ensure our object layout
151
  // matches that of nsString.
152
  class StringAsserter;
153
  friend class StringAsserter;
154
155
  class StringAsserter : public nsString {
156
  public:
157
0
    static void StaticAsserts() {
158
0
      static_assert(offsetof(FakeString, mInlineStorage) ==
159
0
                      sizeof(nsString),
160
0
                    "FakeString should include all nsString members");
161
0
      static_assert(offsetof(FakeString, mData) ==
162
0
                      offsetof(StringAsserter, mData),
163
0
                    "Offset of mData should match");
164
0
      static_assert(offsetof(FakeString, mLength) ==
165
0
                      offsetof(StringAsserter, mLength),
166
0
                    "Offset of mLength should match");
167
0
      static_assert(offsetof(FakeString, mDataFlags) ==
168
0
                      offsetof(StringAsserter, mDataFlags),
169
0
                    "Offset of mDataFlags should match");
170
0
      static_assert(offsetof(FakeString, mClassFlags) ==
171
0
                      offsetof(StringAsserter, mClassFlags),
172
0
                    "Offset of mClassFlags should match");
173
0
    }
174
  };
175
};
176
} // namespace binding_detail
177
} // namespace dom
178
} // namespace mozilla
179
180
#endif /* mozilla_dom_FakeString_h__ */