• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #ifndef CORE_FXCRT_STRING_DATA_TEMPLATE_H_
8 #define CORE_FXCRT_STRING_DATA_TEMPLATE_H_
9 
10 #include "core/fxcrt/fx_memory.h"
11 #include "core/fxcrt/fx_system.h"
12 #include "third_party/base/numerics/safe_math.h"
13 
14 namespace fxcrt {
15 
16 template <typename CharType>
17 class StringDataTemplate {
18  public:
Create(size_t nLen)19   static StringDataTemplate* Create(size_t nLen) {
20     ASSERT(nLen > 0);
21 
22     // Calculate space needed for the fixed portion of the struct plus the
23     // NUL char that is not included in |m_nAllocLength|.
24     int overhead = offsetof(StringDataTemplate, m_String) + sizeof(CharType);
25     pdfium::base::CheckedNumeric<size_t> nSize = nLen;
26     nSize *= sizeof(CharType);
27     nSize += overhead;
28 
29     // Now round to an 8-byte boundary. We'd expect that this is the minimum
30     // granularity of any of the underlying allocators, so there may be cases
31     // where we can save a re-alloc when adding a few characters to a string
32     // by using this otherwise wasted space.
33     nSize += 7;
34     nSize &= ~7;
35     size_t totalSize = nSize.ValueOrDie();
36     size_t usableLen = (totalSize - overhead) / sizeof(CharType);
37     ASSERT(usableLen >= nLen);
38 
39     void* pData = GetStringPartitionAllocator().root()->Alloc(
40         totalSize, "StringDataTemplate");
41     return new (pData) StringDataTemplate(nLen, usableLen);
42   }
43 
Create(const CharType * pStr,size_t nLen)44   static StringDataTemplate* Create(const CharType* pStr, size_t nLen) {
45     StringDataTemplate* result = Create(nLen);
46     result->CopyContents(pStr, nLen);
47     return result;
48   }
49 
Retain()50   void Retain() { ++m_nRefs; }
Release()51   void Release() {
52     if (--m_nRefs <= 0)
53       GetStringPartitionAllocator().root()->Free(this);
54   }
55 
CanOperateInPlace(size_t nTotalLen)56   bool CanOperateInPlace(size_t nTotalLen) const {
57     return m_nRefs <= 1 && nTotalLen <= m_nAllocLength;
58   }
59 
CopyContents(const StringDataTemplate & other)60   void CopyContents(const StringDataTemplate& other) {
61     ASSERT(other.m_nDataLength <= m_nAllocLength);
62     memcpy(m_String, other.m_String,
63            (other.m_nDataLength + 1) * sizeof(CharType));
64   }
65 
CopyContents(const CharType * pStr,size_t nLen)66   void CopyContents(const CharType* pStr, size_t nLen) {
67     ASSERT(nLen >= 0);
68     ASSERT(nLen <= m_nAllocLength);
69 
70     memcpy(m_String, pStr, nLen * sizeof(CharType));
71     m_String[nLen] = 0;
72   }
73 
CopyContentsAt(size_t offset,const CharType * pStr,size_t nLen)74   void CopyContentsAt(size_t offset, const CharType* pStr, size_t nLen) {
75     ASSERT(offset >= 0);
76     ASSERT(nLen >= 0);
77     ASSERT(offset + nLen <= m_nAllocLength);
78 
79     memcpy(m_String + offset, pStr, nLen * sizeof(CharType));
80     m_String[offset + nLen] = 0;
81   }
82 
83   // To ensure ref counts do not overflow, consider the worst possible case:
84   // the entire address space contains nothing but pointers to this object.
85   // Since the count increments with each new pointer, the largest value is
86   // the number of pointers that can fit into the address space. The size of
87   // the address space itself is a good upper bound on it.
88   intptr_t m_nRefs;
89 
90   // These lengths are in terms of number of characters, not bytes, and do not
91   // include the terminating NUL character, but the underlying buffer is sized
92   // to be capable of holding it.
93   size_t m_nDataLength;
94   size_t m_nAllocLength;
95 
96   // Not really 1, variable size.
97   CharType m_String[1];
98 
99  private:
StringDataTemplate(size_t dataLen,size_t allocLen)100   StringDataTemplate(size_t dataLen, size_t allocLen)
101       : m_nRefs(0), m_nDataLength(dataLen), m_nAllocLength(allocLen) {
102     ASSERT(dataLen >= 0);
103     ASSERT(dataLen <= allocLen);
104     m_String[dataLen] = 0;
105   }
106 
107   ~StringDataTemplate() = delete;
108 };
109 
110 extern template class StringDataTemplate<char>;
111 extern template class StringDataTemplate<wchar_t>;
112 
113 }  // namespace fxcrt
114 
115 using fxcrt::StringDataTemplate;
116 
117 #endif  // CORE_FXCRT_STRING_DATA_TEMPLATE_H_
118