• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Abseil Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef ABSL_STRINGS_INTERNAL_CORD_REP_TEST_UTIL_H_
16 #define ABSL_STRINGS_INTERNAL_CORD_REP_TEST_UTIL_H_
17 
18 #include <cassert>
19 #include <memory>
20 #include <random>
21 #include <string>
22 #include <vector>
23 
24 #include "absl/base/config.h"
25 #include "absl/base/internal/raw_logging.h"
26 #include "absl/strings/internal/cord_internal.h"
27 #include "absl/strings/internal/cord_rep_btree.h"
28 #include "absl/strings/internal/cord_rep_flat.h"
29 #include "absl/strings/string_view.h"
30 
31 namespace absl {
32 ABSL_NAMESPACE_BEGIN
33 namespace cordrep_testing {
34 
MakeSubstring(size_t start,size_t len,cord_internal::CordRep * rep)35 inline cord_internal::CordRepSubstring* MakeSubstring(
36     size_t start, size_t len, cord_internal::CordRep* rep) {
37   auto* sub = new cord_internal::CordRepSubstring;
38   sub->tag = cord_internal::SUBSTRING;
39   sub->start = start;
40   sub->length = len <= 0 ? rep->length - start + len : len;
41   sub->child = rep;
42   return sub;
43 }
44 
45 inline cord_internal::CordRepConcat* MakeConcat(cord_internal::CordRep* left,
46                                                 cord_internal::CordRep* right,
47                                                 int depth = 0) {
48   auto* concat = new cord_internal::CordRepConcat;
49   concat->tag = cord_internal::CONCAT;
50   concat->length = left->length + right->length;
51   concat->left = left;
52   concat->right = right;
53   concat->set_depth(depth);
54   return concat;
55 }
56 
MakeFlat(absl::string_view value)57 inline cord_internal::CordRepFlat* MakeFlat(absl::string_view value) {
58   assert(value.length() <= cord_internal::kMaxFlatLength);
59   auto* flat = cord_internal::CordRepFlat::New(value.length());
60   flat->length = value.length();
61   memcpy(flat->Data(), value.data(), value.length());
62   return flat;
63 }
64 
65 // Creates an external node for testing
MakeExternal(absl::string_view s)66 inline cord_internal::CordRepExternal* MakeExternal(absl::string_view s) {
67   struct Rep : public cord_internal::CordRepExternal {
68     std::string s;
69     explicit Rep(absl::string_view sv) : s(sv) {
70       this->tag = cord_internal::EXTERNAL;
71       this->base = s.data();
72       this->length = s.length();
73       this->releaser_invoker = [](cord_internal::CordRepExternal* self) {
74         delete static_cast<Rep*>(self);
75       };
76     }
77   };
78   return new Rep(s);
79 }
80 
CreateRandomString(size_t n)81 inline std::string CreateRandomString(size_t n) {
82   absl::string_view data =
83       "abcdefghijklmnopqrstuvwxyz"
84       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
85       "0123456789~!@#$%^&*()_+=-<>?:\"{}[]|";
86   std::minstd_rand rnd;
87   std::uniform_int_distribution<size_t> dist(0, data.size() - 1);
88   std::string s(n, ' ');
89   for (size_t i = 0; i < n; ++i) {
90     s[i] = data[dist(rnd)];
91   }
92   return s;
93 }
94 
95 // Creates an array of flats from the provided string, chopping
96 // the provided string up into flats of size `chunk_size` characters
97 // resulting in roughly `data.size() / chunk_size` total flats.
CreateFlatsFromString(absl::string_view data,size_t chunk_size)98 inline std::vector<cord_internal::CordRep*> CreateFlatsFromString(
99     absl::string_view data, size_t chunk_size) {
100   assert(chunk_size > 0);
101   std::vector<cord_internal::CordRep*> flats;
102   for (absl::string_view s = data; !s.empty(); s.remove_prefix(chunk_size)) {
103     flats.push_back(MakeFlat(s.substr(0, chunk_size)));
104   }
105   return flats;
106 }
107 
CordRepBtreeFromFlats(absl::Span<cord_internal::CordRep * const> flats)108 inline cord_internal::CordRepBtree* CordRepBtreeFromFlats(
109     absl::Span<cord_internal::CordRep* const> flats) {
110   assert(!flats.empty());
111   auto* node = cord_internal::CordRepBtree::Create(flats[0]);
112   for (size_t i = 1; i < flats.size(); ++i) {
113     node = cord_internal::CordRepBtree::Append(node, flats[i]);
114   }
115   return node;
116 }
117 
CordToString(cord_internal::CordRep * rep,std::string & s)118 inline void CordToString(cord_internal::CordRep* rep, std::string& s) {
119   size_t offset = 0;
120   size_t length = rep->length;
121   while (rep->tag == cord_internal::SUBSTRING) {
122     offset += rep->substring()->start;
123     rep = rep->substring()->child;
124   }
125   if (rep->tag == cord_internal::BTREE) {
126     for (cord_internal::CordRep* edge : rep->btree()->Edges()) {
127       CordToString(edge, s);
128     }
129   } else if (rep->tag >= cord_internal::FLAT) {
130     s.append(rep->flat()->Data() + offset, length);
131   } else if (rep->tag == cord_internal::EXTERNAL) {
132     s.append(rep->external()->base + offset, length);
133   } else {
134     ABSL_RAW_LOG(FATAL, "Unsupported tag %d", rep->tag);
135   }
136 }
137 
CordToString(cord_internal::CordRep * rep)138 inline std::string CordToString(cord_internal::CordRep* rep) {
139   std::string s;
140   s.reserve(rep->length);
141   CordToString(rep, s);
142   return s;
143 }
144 
145 // RAII Helper class to automatically unref reps on destruction.
146 class AutoUnref {
147  public:
~AutoUnref()148   ~AutoUnref() {
149     for (CordRep* rep : unrefs_) CordRep::Unref(rep);
150   }
151 
152   // Adds `rep` to the list of reps to be unreffed at destruction.
153   template <typename CordRepType>
Add(CordRepType * rep)154   CordRepType* Add(CordRepType* rep) {
155     unrefs_.push_back(rep);
156     return rep;
157   }
158 
159   // Increments the reference count of `rep` by one, and adds it to
160   // the list of reps to be unreffed at destruction.
161   template <typename CordRepType>
Ref(CordRepType * rep)162   CordRepType* Ref(CordRepType* rep) {
163     unrefs_.push_back(CordRep::Ref(rep));
164     return rep;
165   }
166 
167   // Increments the reference count of `rep` by one if `condition` is true,
168   // and adds it to the list of reps to be unreffed at destruction.
169   template <typename CordRepType>
RefIf(bool condition,CordRepType * rep)170   CordRepType* RefIf(bool condition, CordRepType* rep) {
171     if (condition) unrefs_.push_back(CordRep::Ref(rep));
172     return rep;
173   }
174 
175  private:
176   using CordRep = absl::cord_internal::CordRep;
177 
178   std::vector<CordRep*> unrefs_;
179 };
180 
181 }  // namespace cordrep_testing
182 ABSL_NAMESPACE_END
183 }  // namespace absl
184 
185 #endif  // ABSL_STRINGS_INTERNAL_CORD_REP_TEST_UTIL_H_
186