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_CFX_STRING_C_TEMPLATE_H_
8#define CORE_FXCRT_CFX_STRING_C_TEMPLATE_H_
9
10#include <algorithm>
11#include <type_traits>
12
13#include "core/fxcrt/fx_system.h"
14
15// An immutable string with caller-provided storage which must outlive the
16// string itself. These are not necessarily nul-terminated, so that substring
17// extraction (via the Mid(), Left(), and Right() methods) is copy-free.
18template <typename T>
19class CFX_StringCTemplate {
20 public:
21  using CharType = T;
22  using UnsignedType = typename std::make_unsigned<CharType>::type;
23
24  CFX_StringCTemplate() : m_Ptr(nullptr), m_Length(0) {}
25
26  // Deliberately implicit to avoid calling on every string literal.
27  // NOLINTNEXTLINE(runtime/explicit)
28  CFX_StringCTemplate(const CharType* ptr)
29      : m_Ptr(reinterpret_cast<const UnsignedType*>(ptr)),
30        m_Length(ptr ? FXSYS_len(ptr) : 0) {}
31
32  CFX_StringCTemplate(const CharType* ptr, FX_STRSIZE len)
33      : m_Ptr(reinterpret_cast<const UnsignedType*>(ptr)),
34        m_Length(len == -1 ? FXSYS_len(ptr) : len) {}
35
36  template <typename U = UnsignedType>
37  CFX_StringCTemplate(
38      const UnsignedType* ptr,
39      FX_STRSIZE size,
40      typename std::enable_if<!std::is_same<U, CharType>::value>::type* = 0)
41      : m_Ptr(ptr), m_Length(size) {}
42
43  // Deliberately implicit to avoid calling on every string literal.
44  // |ch| must be an lvalue that outlives the the CFX_StringCTemplate.
45  // NOLINTNEXTLINE(runtime/explicit)
46  CFX_StringCTemplate(CharType& ch) {
47    m_Ptr = reinterpret_cast<const UnsignedType*>(&ch);
48    m_Length = 1;
49  }
50
51  CFX_StringCTemplate(const CFX_StringCTemplate& src) {
52    m_Ptr = src.m_Ptr;
53    m_Length = src.m_Length;
54  }
55
56  CFX_StringCTemplate& operator=(const CharType* src) {
57    m_Ptr = reinterpret_cast<const UnsignedType*>(src);
58    m_Length = src ? FXSYS_len(src) : 0;
59    return *this;
60  }
61
62  CFX_StringCTemplate& operator=(const CFX_StringCTemplate& src) {
63    m_Ptr = src.m_Ptr;
64    m_Length = src.m_Length;
65    return *this;
66  }
67
68  bool operator==(const CharType* ptr) const {
69    return FXSYS_len(ptr) == m_Length &&
70           FXSYS_cmp(ptr, reinterpret_cast<const CharType*>(m_Ptr), m_Length) ==
71               0;
72  }
73  bool operator==(const CFX_StringCTemplate& other) const {
74    return other.m_Length == m_Length &&
75           FXSYS_cmp(reinterpret_cast<const CharType*>(other.m_Ptr),
76                     reinterpret_cast<const CharType*>(m_Ptr), m_Length) == 0;
77  }
78  bool operator!=(const CharType* ptr) const { return !(*this == ptr); }
79  bool operator!=(const CFX_StringCTemplate& other) const {
80    return !(*this == other);
81  }
82
83  uint32_t GetID(FX_STRSIZE start_pos = 0) const {
84    if (m_Length == 0 || start_pos < 0 || start_pos >= m_Length)
85      return 0;
86
87    uint32_t strid = 0;
88    FX_STRSIZE size = std::min(4, m_Length - start_pos);
89    for (FX_STRSIZE i = 0; i < size; i++)
90      strid = strid * 256 + m_Ptr[start_pos + i];
91
92    return strid << ((4 - size) * 8);
93  }
94
95  const UnsignedType* raw_str() const { return m_Ptr; }
96  const CharType* c_str() const {
97    return reinterpret_cast<const CharType*>(m_Ptr);
98  }
99
100  FX_STRSIZE GetLength() const { return m_Length; }
101  bool IsEmpty() const { return m_Length == 0; }
102
103  UnsignedType GetAt(FX_STRSIZE index) const { return m_Ptr[index]; }
104  CharType CharAt(FX_STRSIZE index) const {
105    return static_cast<CharType>(m_Ptr[index]);
106  }
107
108  FX_STRSIZE Find(CharType ch) const {
109    const UnsignedType* found = reinterpret_cast<const UnsignedType*>(
110        FXSYS_chr(reinterpret_cast<const CharType*>(m_Ptr), ch, m_Length));
111    return found ? found - m_Ptr : -1;
112  }
113
114  CFX_StringCTemplate Mid(FX_STRSIZE index, FX_STRSIZE count = -1) const {
115    index = std::max(0, index);
116    if (index > m_Length)
117      return CFX_StringCTemplate();
118
119    if (count < 0 || count > m_Length - index)
120      count = m_Length - index;
121
122    return CFX_StringCTemplate(m_Ptr + index, count);
123  }
124
125  CFX_StringCTemplate Left(FX_STRSIZE count) const {
126    if (count <= 0)
127      return CFX_StringCTemplate();
128
129    return CFX_StringCTemplate(m_Ptr, std::min(count, m_Length));
130  }
131
132  CFX_StringCTemplate Right(FX_STRSIZE count) const {
133    if (count <= 0)
134      return CFX_StringCTemplate();
135
136    count = std::min(count, m_Length);
137    return CFX_StringCTemplate(m_Ptr + m_Length - count, count);
138  }
139
140  const UnsignedType& operator[](size_t index) const { return m_Ptr[index]; }
141
142  bool operator<(const CFX_StringCTemplate& that) const {
143    int result = FXSYS_cmp(reinterpret_cast<const CharType*>(m_Ptr),
144                           reinterpret_cast<const CharType*>(that.m_Ptr),
145                           std::min(m_Length, that.m_Length));
146    return result < 0 || (result == 0 && m_Length < that.m_Length);
147  }
148
149 protected:
150  const UnsignedType* m_Ptr;
151  FX_STRSIZE m_Length;
152
153 private:
154  void* operator new(size_t) throw() { return nullptr; }
155};
156
157template <typename T>
158inline bool operator==(const T* lhs, const CFX_StringCTemplate<T>& rhs) {
159  return rhs == lhs;
160}
161
162template <typename T>
163inline bool operator!=(const T* lhs, const CFX_StringCTemplate<T>& rhs) {
164  return rhs != lhs;
165}
166
167extern template class CFX_StringCTemplate<FX_CHAR>;
168extern template class CFX_StringCTemplate<FX_WCHAR>;
169
170#endif  // CORE_FXCRT_CFX_STRING_C_TEMPLATE_H_
171