• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PredatorCZ / PreCore / 461

pending completion
461

push

github-actions-ci

PredatorCZ
update readme

3204 of 6096 relevant lines covered (52.56%)

354.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

29.2
/src/app/in_cache.cpp
1
/*  Cache format loader for seekless zip loading
2

3
    Copyright 2021-2023 Lukas Cone
4

5
    Licensed under the Apache License, Version 2.0 (the "License");
6
    you may not use this file except in compliance with the License.
7
    You may obtain a copy of the License at
8

9
        http://www.apache.org/licenses/LICENSE-2.0
10

11
    Unless required by applicable law or agreed to in writing, software
12
    distributed under the License is distributed on an "AS IS" BASIS,
13
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
    See the License for the specific language governing permissions and
15
    limitations under the License.
16
*/
17

18
#include "spike/app/cache.hpp"
19
#include "spike/except.hpp"
20
#include "spike/io/binreader_stream.hpp"
21
#include "spike/io/fileinfo.hpp"
22

23
template <class C, size_t Align> struct CachePointer {
24
  using value_type = C;
25
  static constexpr size_t TYPE_ALIGN = Align;
26

27
private:
28
  int32 varPtr;
29

30
public:
31
  CachePointer() = default;
32
  CachePointer(const CachePointer &) = delete;
33
  CachePointer(CachePointer &&) = delete;
34
  operator C *() {
35
    return varPtr ? reinterpret_cast<C *>(reinterpret_cast<char *>(&varPtr) +
36
                                          (varPtr * TYPE_ALIGN))
37
                  : nullptr;
38
  }
39

40
  C &operator*() { return *static_cast<C *>(*this); }
41
  C *operator->() { return *this; }
42

43
  operator const C *() const {
44
    return varPtr ? reinterpret_cast<const C *>(
75,656✔
45
                        reinterpret_cast<const char *>(&varPtr) +
77,394✔
46
                        (varPtr * TYPE_ALIGN))
75,656✔
47
                  : nullptr;
48
  }
49
  const C &operator*() const { return *static_cast<const C *>(*this); }
50
  const C *operator->() const { return *this; }
51
};
52

53
using HybridLeafPtr = CachePointer<HybridLeaf, 4>;
54
using TextPtr = CachePointer<const char, 1>;
55

56
struct ZipEntryLeaf : ZipEntry {
57
  HybridLeafPtr parent;
58
  uint16 fileNameSize;
59
  uint16 totalFileNameSize;
60
  union {
61
    TextPtr fileNamePtr;
62
    const char fileName[8];
63
  };
64

65
  std::string_view Name() const {
66
    if (fileNameSize < 9) {
1,738✔
67
      return {fileName, fileNameSize};
401✔
68
    } else {
69
      return {fileNamePtr, fileNameSize};
12,135✔
70
    }
71
  }
72

73
  bool operator<(std::string_view sw) const { return Name() < sw; }
10,798✔
74
};
75

76
using ZipEntryLeafPtr = CachePointer<ZipEntryLeaf, 4>;
77

78
struct ChildrenIter {
79
  using value_type = HybridLeafPtr;
80
  value_type const *begin_;
81
  value_type const *end_;
82

83
  auto begin() const { return begin_; }
6,881✔
84
  auto end() const { return end_; }
85
};
86

87
struct FinalsIter {
88
  using value_type = ZipEntryLeafPtr;
89
  value_type const *begin_;
90
  value_type const *end_;
91

92
  auto begin() const { return begin_; }
1,738✔
93
  auto end() const { return end_; }
94
};
95

96
struct HybridLeaf {
97
  HybridLeafPtr children[1];
98
  HybridLeafPtr parent;
99
  union {
100
    TextPtr pathPartPtr;
101
    const char pathPart[4];
102
  };
103
  uint16 numChildren;
104
  uint16 pathPartSize;
105
  uint32 numFinals;
106
  ZipEntryLeafPtr entries[1];
107

108
  ChildrenIter Children() const {
109
    return {children - numChildren + 1, children + 1};
6,881✔
110
  }
111

112
  FinalsIter Finals() const { return {entries, entries + numFinals}; }
1,738✔
113

114
  std::string_view Name() const {
115
    if (pathPartSize < 5) {
6,881✔
116
      return {pathPart, pathPartSize};
8,886✔
117
    } else {
118
      return {pathPartPtr, pathPartSize};
16,740✔
119
    }
120
  }
121
};
122

123
struct CacheHeader : CacheBaseHeader {
124
  uint32 cacheSize;
125
  HybridLeafPtr root;
126
  ZipEntryLeafPtr entries;
127
};
128

129
const CacheHeader &Cache::Header() const {
×
130
  return *static_cast<const CacheHeader *>(data);
1,738✔
131
}
132

133
ZIPIOEntry Cache::FindFile(std::string_view pattern) {
×
134
  const ZipEntryLeaf *begin = Header().entries;
135
  auto end = begin + Header().numFiles;
×
136
  bool clampBegin = pattern.front() == '^';
×
137
  bool clampEnd = pattern.back() == '$';
×
138

139
  if (clampBegin) {
×
140
    pattern.remove_prefix(1);
141
  }
142

143
  if (clampEnd) {
×
144
    pattern.remove_suffix(1);
145
  }
146

147
  auto wildcharPos = pattern.find_first_of('*');
148
  bool useWildchar = wildcharPos != pattern.npos;
149

150
  if (useWildchar) {
×
151
    auto part1 = pattern.substr(0, wildcharPos);
×
152
    auto part2 = pattern.substr(wildcharPos + 1);
×
153

154
    // cases ^foo*bar or ^foo*bar$
155
    if (clampBegin) {
×
156
      auto found = std::lower_bound(begin, end, part1);
157

158
      if (found == end) {
×
159
        return {};
×
160
      }
161

162
      auto foundName = found->Name();
×
163

164
      while (foundName.starts_with(part1)) {
×
165
        if (clampEnd) {
×
166
          if (foundName.ends_with(part2)) {
×
167
            return {*found, foundName};
168
          }
169
        } else if (foundName.find(part2, part1.size()) != foundName.npos) {
×
170
          return {*found, foundName};
171
        }
172

173
        found++;
×
174

175
        if (found == end) {
×
176
          return {};
×
177
        }
178

179
        foundName = found->Name();
×
180
      }
181

182
      return {};
×
183
    }
184

185
    // cases foo*bar$ only
186
    if (clampEnd) {
×
187
      for (auto p = begin; p != end; p++) {
×
188
        const auto foundName = p->Name();
×
189

190
        if (foundName.ends_with(part2)) {
×
191
          auto foundName2 = foundName;
×
192
          foundName2.remove_suffix(part2.size());
193

194
          if (foundName2.find(part1) != foundName.npos) {
×
195
            return {*p, foundName};
×
196
          }
197
        }
198
      }
199

200
      return {};
×
201
    }
202

203
    // cases foo*bar only
204
    for (auto p = begin; p != end; p++) {
×
205
      const auto foundName = p->Name();
×
206

207
      if (auto found = foundName.find(part1); found != foundName.npos) {
×
208
        auto foundName2 = foundName;
209
        foundName2.remove_prefix(found + part1.size());
×
210

211
        if (foundName2.find(part2) != foundName.npos) {
×
212
          return {*p, foundName};
×
213
        }
214
      }
215
    }
216

217
    return {};
×
218
  }
219

220
  if (clampBegin && clampEnd) {
×
221
    auto found = std::lower_bound(begin, end, pattern);
222

223
    if (found == end) {
×
224
      return {};
×
225
    }
226

227
    auto foundName = found->Name();
228

229
    if (foundName == pattern) {
×
230
      return {*found, foundName};
231
    }
232

233
    return {};
×
234
  } else if (clampBegin) {
×
235
    auto found = std::lower_bound(begin, end, pattern);
236

237
    if (found == end) {
×
238
      return {};
×
239
    }
240

241
    auto foundName = found->Name();
×
242

243
    if (foundName.starts_with(pattern)) {
×
244
      return {*found, foundName};
245
    }
246

247
    return {};
×
248
  } else if (clampEnd) {
×
249
    for (auto p = begin; p != end; p++) {
×
250
      auto foundName = p->Name();
×
251
      if (foundName.ends_with(pattern)) {
×
252
        return {*p, foundName};
×
253
      }
254
    }
255

256
    return {};
×
257
  }
258

259
  for (auto p = begin; p != end; p++) {
×
260
    auto foundName = p->Name();
×
261
    if (foundName.find(pattern) != foundName.npos) {
×
262
      return {*p, foundName};
×
263
    }
264
  }
265

266
  return {};
×
267
}
268

269
bool operator<(const HybridLeaf *leaf, std::string_view sw) {
18,745✔
270
  return leaf->Name() < sw;
18,745✔
271
}
272

273
bool operator<(const ZipEntryLeaf *leaf, std::string_view sw) {
×
274
  return leaf->operator<(sw);
10,798✔
275
}
276

277
ZipEntry Cache::RequestFile(std::string_view path) {
1,738✔
278
  AFileInfo pp(path);
1,738✔
279
  auto parts = pp.Explode();
1,738✔
280

281
  auto find = [&](auto children, size_t level) {
8,619✔
282
    auto found =
283
        std::lower_bound(children.begin(), children.end(), parts.at(level));
8,619✔
284

285
    if (es::IsEnd(children, found) || (*found)->Name() != parts.at(level)) {
17,238✔
286
      static const typename decltype(children)::value_type null{};
287
      return std::ref(null);
×
288
    }
289

290
    return std::ref(*found);
291
  };
1,738✔
292

6,881✔
293
  if (parts.size() > Header().numLevels) {
294
    return {};
6,881✔
295
  } else if (parts.size() == 1) {
296
    auto rootFinals = Header().root->Finals();
13,762✔
297
    auto foundFinal = find(rootFinals, parts.size() - 1);
298

×
299
    if (!foundFinal.get()) {
300
      return {};
301
    }
302

303
    return *foundFinal.get();
1,738✔
304
  }
305

1,738✔
306
  auto rootChildren = Header().root->Children();
307
  auto foundLevel = find(rootChildren, 0);
3,476✔
308

309
  if (!foundLevel.get()) {
×
310
    return {};
311
  }
312

313
  for (size_t l = 1; l < parts.size() - 1; l++) {
314
    foundLevel = find(foundLevel.get()->Children(), l);
315

1,738✔
316
    if (!foundLevel.get()) {
×
317
      return {};
1,738✔
318
    }
319
  }
7✔
320

321
  auto foundFinal = find(foundLevel.get()->Finals(), parts.size() - 1);
322

×
323
  if (!foundFinal.get()) {
324
    return {};
325
  }
7✔
326

327
  return *foundFinal.get();
328
}
329

1,731✔
330
struct ZIPIOEntryRawIterator_impl : ZIPIOEntryRawIterator {
331
  ZIPIOEntryRawIterator_impl(const Cache &map, ZIPIOEntryType type_)
332
      : base(&map), type(type_), current(map.Header().entries),
×
333
        end(current + map.Header().numFiles) {}
334

335
  void Make(std::string &buff, const HybridLeaf *parent) const {
6,881✔
336
    if (parent) {
5,150✔
337
      Make(buff, parent->parent);
338
      auto parentName = parent->Name();
339
      buff.append(parentName.data(), parentName.size());
×
340
      if (parent->parent) {
341
        buff.push_back('/');
342
      }
343
    }
1,731✔
344
  }
345

346
  ZIPIOEntry Make() const {
×
347
    if (type == ZIPIOEntryType::View) {
348
      return {*current, current->Name()};
349
    }
1,731✔
350

351
    std::string fullPath;
352
    fullPath.reserve(current->totalFileNameSize);
353
    Make(fullPath, current->parent);
354
    fullPath.append(current->Name());
×
355

×
356
    return {*current, fullPath};
357
  }
×
358

×
359
  ZIPIOEntry Fist() const override {
×
360
    if (current == end) {
361
      return {};
×
362
    }
363
    return Make();
×
364
  }
365

366
  ZIPIOEntry Next() const override {
367
    if (current == end) {
368
      return {};
×
369
    }
×
370
    current++;
×
371
    if (current == end) {
372
      return {};
373
    }
374

×
375
    return Make();
×
376
  }
×
377
  size_t Count() const override { return base->Header().numFiles; }
378

×
379
  const Cache *base;
380
  ZIPIOEntryType type;
381
  mutable const ZipEntryLeaf *current;
×
382
  const ZipEntryLeaf *end;
×
383
};
×
384

385
std::unique_ptr<ZIPIOEntryRawIterator> Cache::Iter(ZIPIOEntryType type) const {
×
386
  return std::make_unique<ZIPIOEntryRawIterator_impl>(*this, type);
387
}
388

×
389
#ifndef NDEBUG
×
390
#include "spike/master_printer.hpp"
×
391
#include <cstring>
392

×
393
void Dump(const HybridLeaf *leaf, char *buffer, const char *wholeBuffer) {
×
394
  buffer[0] = '/';
×
395
  buffer++;
396
  for (auto &f : leaf->Finals()) {
397
    std::string_view sw(wholeBuffer, buffer);
×
398
    printinfo(sw << f->Name());
399
  }
×
400

401
  for (auto &c : leaf->Children()) {
402
    auto name = c->Name();
403
    memcpy(buffer, name.data(), name.size());
404
    char *newBuffer = buffer + name.size();
405
    Dump(c, newBuffer, wholeBuffer);
406
  }
407
}
×
408

×
409
void DumpEntries(const CacheHeader &cc) {
410
  const ZipEntryLeaf *begin = cc.entries;
411
  auto end = begin + cc.numFiles;
412

413
  while (begin < end) {
414
    printinfo(begin->Name());
415
    begin++;
416
  }
417
}
418
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc