GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/shortstring.h Lines: 89 104 85.6 %
Date: 2019-02-03 02:48:13 Branches: 51 76 67.1 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 *
4
 * Implements a string class that stores short strings on the stack and
5
 * malloc's a std::string on the heap on overflow.  Used for file names and
6
 * path names that are usually small.
7
 */
8
9
#ifndef CVMFS_SHORTSTRING_H_
10
#define CVMFS_SHORTSTRING_H_
11
12
#include <algorithm>
13
#include <cstring>
14
#include <string>
15
16
#include "atomic.h"
17
18
#ifdef CVMFS_NAMESPACE_GUARD
19
namespace CVMFS_NAMESPACE_GUARD {
20
#endif
21
22
const unsigned char kDefaultMaxName = 25;
23
const unsigned char kDefaultMaxLink = 25;
24
const unsigned char kDefaultMaxPath = 200;
25
26
template<unsigned char StackSize, char Type>
27
class ShortString {
28
 public:
29
4681567
  ShortString() : long_string_(NULL), length_(0) {
30
4681567
    atomic_inc64(&num_instances_);
31
4681567
  }
32
27833
  ShortString(const ShortString &other) : long_string_(NULL) {
33
27833
    atomic_inc64(&num_instances_);
34
27833
    Assign(other);
35
27833
  }
36
24296
  ShortString(const char *chars, const unsigned length) : long_string_(NULL) {
37
24296
    atomic_inc64(&num_instances_);
38
24296
    Assign(chars, length);
39
24296
  }
40
5572235
  explicit ShortString(const std::string &std_string) : long_string_(NULL) {
41
5572235
    atomic_inc64(&num_instances_);
42
5579255
    Assign(std_string.data(), std_string.length());
43
5570450
  }
44
45
5578954
  ShortString & operator= (const ShortString & other) {
46

5578954
    if (this != &other)
47
5579059
      Assign(other);
48
5568919
    return *this;
49
  }
50
51

10309936
  ~ShortString() { delete long_string_; }
52
53
11164078
  void Assign(const char *chars, const unsigned length) {
54

11164078
    delete long_string_;
55
11154808
    long_string_ = NULL;
56

11154808
    if (length > StackSize) {
57
      atomic_inc64(&num_overflows_);
58
      long_string_ = new std::string(chars, length);
59
    } else {
60

11154808
      if (length)
61
11158807
        memcpy(stack_, chars, length);
62
11154808
      this->length_ = length;
63
    }
64
11154808
  }
65
66
5606956
  void Assign(const ShortString &other) {
67
5606956
    Assign(other.GetChars(), other.GetLength());
68
5596756
  }
69
70
1627
  void Append(const char *chars, const unsigned length) {
71
1627
    if (long_string_) {
72
      long_string_->append(chars, length);
73
      return;
74
    }
75
76
1627
    const unsigned new_length = this->length_ + length;
77
1627
    if (new_length > StackSize) {
78
      atomic_inc64(&num_overflows_);
79
      long_string_ = new std::string();
80
      long_string_->reserve(new_length);
81
      long_string_->assign(stack_, length_);
82
      long_string_->append(chars, length);
83
      return;
84
    }
85
1627
    if (length > 0)
86
1604
      memcpy(&stack_[this->length_], chars, length);
87
1627
    this->length_ = new_length;
88
  }
89
90
  void Clear() {
91
    delete long_string_;
92
    long_string_ = NULL;
93
    length_ = 0;
94
  }
95
96
11209480
  const char *GetChars() const {
97

11209480
    if (long_string_)
98
      return long_string_->data();
99
    else
100
11209480
      return stack_;
101
  }
102
103
11217251
  unsigned GetLength() const {
104

11217251
    if (long_string_)
105
      return long_string_->length();
106
11217251
    return length_;
107
  }
108
109
1119
  bool IsEmpty() const {
110
1119
    return GetLength() == 0;
111
  }
112
113
5601129
  std::string ToString() const {
114
5601129
    return std::string(this->GetChars(), this->GetLength());
115
  }
116
117
541
  const char *c_str() const {
118

541
    if (long_string_)
119
      return long_string_->c_str();
120
121
541
    char *c = const_cast<char *>(stack_) + length_;
122
541
    *c = '\0';
123
541
    return stack_;
124
  }
125
126
513
  bool operator ==(const ShortString &other) const {
127
513
    const unsigned this_length = this->GetLength();
128
513
    const unsigned other_length = other.GetLength();
129

513
    if (this_length != other_length)
130
288
      return false;
131

225
    if (this_length == 0)
132
144
      return true;
133
134
81
    return memcmp(this->GetChars(), other.GetChars(), this_length) == 0;
135
  }
136
137
293
  bool operator !=(const ShortString &other) const {
138
293
    return !(*this == other);
139
  }
140
141
582
  bool operator <(const ShortString &other) const {
142
582
    const unsigned this_length = this->GetLength();
143
582
    const unsigned other_length = other.GetLength();
144
145
582
    if (this_length < other_length)
146
143
      return true;
147
439
    if (this_length > other_length)
148
57
      return false;
149
150
382
    const char *this_chars = this->GetChars();
151
382
    const char *other_chars = other.GetChars();
152
2348
    for (unsigned i = 0; i < this_length; ++i) {
153
1972
      if (this_chars[i] < other_chars[i])
154
5
        return true;
155
1967
      if (this_chars[i] > other_chars[i])
156
1
        return false;
157
    }
158
376
    return false;
159
  }
160
161
389
  bool StartsWith(const ShortString &other) const {
162
389
    const unsigned this_length = this->GetLength();
163
389
    const unsigned other_length = other.GetLength();
164
389
    if (this_length < other_length)
165
20
      return false;
166
167
369
    return memcmp(this->GetChars(), other.GetChars(), other_length) == 0;
168
  }
169
170
142
  ShortString Suffix(const unsigned start_at) const {
171
142
    const unsigned length = this->GetLength();
172
142
    if (start_at >= length)
173
4
      return ShortString("", 0);
174
175
138
    return ShortString(this->GetChars() + start_at, length-start_at);
176
  }
177
178
  static uint64_t num_instances() { return atomic_read64(&num_instances_); }
179
  static uint64_t num_overflows() { return atomic_read64(&num_overflows_); }
180
181
 private:
182
  std::string *long_string_;
183
  char stack_[StackSize+1];  // +1 to add a final '\0' if necessary
184
  unsigned char length_;
185
  static atomic_int64 num_overflows_;
186
  static atomic_int64 num_instances_;
187
};  // class ShortString
188
189
typedef ShortString<kDefaultMaxPath, 0> PathString;
190
typedef ShortString<kDefaultMaxName, 1> NameString;
191
typedef ShortString<kDefaultMaxLink, 2> LinkString;
192
193
template<unsigned char StackSize, char Type>
194
atomic_int64 ShortString<StackSize, Type>::num_overflows_ = 0;
195
template<unsigned char StackSize, char Type>
196
atomic_int64 ShortString<StackSize, Type>::num_instances_ = 0;
197
198
#ifdef CVMFS_NAMESPACE_GUARD
199
}  // namespace CVMFS_NAMESPACE_GUARD
200
#endif
201
202
#endif  // CVMFS_SHORTSTRING_H_