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

llnl / dftracer-utils / 23935950925

03 Apr 2026 06:01AM UTC coverage: 51.257% (-0.2%) from 51.498%
23935950925

Pull #63

github

web-flow
Merge a8f78da48 into 773a62661
Pull Request #63: feat(aggregator): support profile/system counter aggregation and custom metric Arrow output

23412 of 58927 branches covered (39.73%)

Branch coverage included in aggregate %.

344 of 571 new or added lines in 7 files covered. (60.25%)

9 existing lines in 4 files now uncovered.

20297 of 26348 relevant lines covered (77.03%)

13069.39 hits per line

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

47.52
/src/dftracer/utils/utilities/reader/internal/gzip_reader.cpp
1
#include <dftracer/utils/core/coro/task.h>
2
#include <dftracer/utils/core/utils/timer.h>
3
#include <dftracer/utils/utilities/indexer/internal/indexer.h>
4
#include <dftracer/utils/utilities/indexer/internal/indexer_factory.h>
5
#include <dftracer/utils/utilities/reader/internal/error.h>
6
#include <dftracer/utils/utilities/reader/internal/gzip_reader.h>
7
#include <dftracer/utils/utilities/reader/internal/stream_config.h>
8
#include <dftracer/utils/utilities/reader/internal/streams/gzip_byte_stream.h>
9
#include <dftracer/utils/utilities/reader/internal/streams/gzip_line_byte_stream.h>
10
#include <dftracer/utils/utilities/reader/internal/streams/line_stream.h>
11
#include <dftracer/utils/utilities/reader/internal/streams/multi_line_stream.h>
12
#include <dftracer/utils/utilities/reader/internal/string_line_processor.h>
13

14
#include <cstdio>
15
#include <cstring>
16
#include <limits>
17
#include <string_view>
18

19
static void validate_parameters(
154,656✔
20
    const char *buffer, std::size_t buffer_size, std::size_t start_bytes,
21
    std::size_t end_bytes,
22
    std::size_t max_bytes = std::numeric_limits<std::size_t>::max()) {
23
    if (!buffer || buffer_size == 0) {
154,656!
24
        throw dftracer::utils::utilities::reader::internal::ReaderError(
12!
25
            dftracer::utils::utilities::reader::internal::ReaderError::
26
                INVALID_ARGUMENT,
27
            "Invalid buffer parameters");
×
28
    }
29
    if (start_bytes >= end_bytes) {
154,656✔
30
        throw dftracer::utils::utilities::reader::internal::ReaderError(
20!
31
            dftracer::utils::utilities::reader::internal::ReaderError::
32
                INVALID_ARGUMENT,
33
            "start_bytes must be less than end_bytes");
30!
34
    }
35
    if (max_bytes != SIZE_MAX) {
154,636✔
36
        if (end_bytes > max_bytes) {
154,636✔
37
            throw dftracer::utils::utilities::reader::internal::ReaderError(
4!
38
                dftracer::utils::utilities::reader::internal::ReaderError::
39
                    INVALID_ARGUMENT,
40
                "end_bytes exceeds maximum available bytes");
6!
41
        }
42
        if (start_bytes > max_bytes) {
154,632✔
43
            throw dftracer::utils::utilities::reader::internal::ReaderError(
×
44
                dftracer::utils::utilities::reader::internal::ReaderError::
45
                    INVALID_ARGUMENT,
46
                "start_bytes exceeds maximum available bytes");
×
47
        }
48
    }
77,315✔
49
}
154,644✔
50

51
static void check_reader_state(bool is_open, const void *indexer) {
160,183✔
52
    if (!is_open || !indexer) {
160,183!
UNCOV
53
        throw std::runtime_error("Reader is not open");
×
54
    }
55
}
160,183✔
56

57
static constexpr std::size_t DEFAULT_READER_BUFFER_SIZE = 1 * 1024 * 1024;
58

59
namespace dftracer::utils::utilities::reader::internal {
60

61
GzipReader::GzipReader(const std::string &gz_path_,
1,843!
62
                       const std::string &idx_path_,
63
                       std::size_t index_ckpt_size)
459✔
64
    : gz_path(gz_path_),
922!
65
      idx_path(idx_path_),
922!
66
      is_open(false),
923✔
67
      default_buffer_size(DEFAULT_READER_BUFFER_SIZE),
923✔
68
      indexer(nullptr) {
2,305!
69
    try {
70
        indexer = dftracer::utils::utilities::indexer::internal::
461✔
71
            IndexerFactory::create(gz_path, idx_path, index_ckpt_size, false);
921✔
72
        is_open = true;
910✔
73

74
        DFTRACER_UTILS_LOG_DEBUG(
75
            "Successfully created GZIP reader for gz: %s and index: %s",
76
            gz_path.c_str(), idx_path.c_str());
77
    } catch (const std::exception &e) {
467!
78
        throw ReaderError(ReaderError::INITIALIZATION_ERROR,
18!
79
                          "Failed to initialize reader with indexer: " +
18!
80
                              std::string(e.what()));
18!
81
    }
12!
82
}
1,420✔
83

84
GzipReader::GzipReader(
660!
85
    std::shared_ptr<dftracer::utils::utilities::indexer::internal::Indexer>
86
        indexer_)
132✔
87
    : default_buffer_size(DEFAULT_READER_BUFFER_SIZE),
264✔
88
      indexer(std::move(indexer_)) {
528✔
89
    if (!indexer) {
264✔
90
        throw ReaderError(ReaderError::INITIALIZATION_ERROR,
×
91
                          "Invalid indexer provided");
×
92
    }
93
    is_open = true;
264✔
94
    gz_path = indexer->get_archive_path();
264!
95
    idx_path = indexer->get_idx_path();
264!
96
}
396✔
97

98
GzipReader::~GzipReader() {
1,764✔
99
    DFTRACER_UTILS_LOG_DEBUG("Destroying GZIP reader for gz: %s and index: %s",
100
                             gz_path.c_str(), idx_path.c_str());
101
    reset();
1,176!
102
    is_open = false;
1,176✔
103
}
1,764✔
104

105
GzipReader::GzipReader(GzipReader &&other) noexcept
×
106
    : gz_path(std::move(other.gz_path)),
×
107
      idx_path(std::move(other.idx_path)),
×
108
      is_open(other.is_open),
×
109
      default_buffer_size(other.default_buffer_size),
×
110
      indexer(std::move(other.indexer)) {
×
111
    other.is_open = false;
×
112
}
×
113

114
GzipReader &GzipReader::operator=(GzipReader &&other) noexcept {
×
115
    if (this != &other) {
×
116
        gz_path = std::move(other.gz_path);
×
117
        idx_path = std::move(other.idx_path);
×
118
        is_open = other.is_open;
×
119
        default_buffer_size = other.default_buffer_size;
×
120
        indexer = std::move(other.indexer);
×
121
        other.is_open = false;
×
122
    }
123
    return *this;
×
124
}
125

126
std::size_t GzipReader::get_max_bytes() const {
376✔
127
    check_reader_state(is_open, indexer.get());
376✔
128
    std::size_t max_bytes =
188✔
129
        static_cast<std::size_t>(indexer.get()->get_max_bytes());
376✔
130
    DFTRACER_UTILS_LOG_DEBUG("Maximum bytes available: %zu", max_bytes);
131
    return max_bytes;
376✔
132
}
133

134
std::size_t GzipReader::get_num_lines() const {
106✔
135
    check_reader_state(is_open, indexer.get());
106✔
136
    std::size_t num_lines = static_cast<std::size_t>(indexer->get_num_lines());
106✔
137
    DFTRACER_UTILS_LOG_DEBUG("Total lines available: %zu", num_lines);
138
    return num_lines;
106✔
139
}
140

141
const std::string &GzipReader::get_archive_path() const { return gz_path; }
14✔
142

143
const std::string &GzipReader::get_idx_path() const { return idx_path; }
8✔
144

145
void GzipReader::set_buffer_size(std::size_t size) {
×
146
    default_buffer_size = size;
×
147
}
×
148

149
void GzipReader::reset() {
1,184✔
150
    check_reader_state(is_open, indexer.get());
1,184✔
151
    stream_cache_.clear();
1,184✔
152
}
1,184✔
153

154
coro::CoroTask<std::size_t> GzipReader::read_async(std::size_t start_bytes,
74,892!
155
                                                   std::size_t end_bytes,
156
                                                   char *buffer,
157
                                                   std::size_t buffer_size) {
12,482!
158
    check_reader_state(is_open, indexer.get());
12,482!
159
    validate_parameters(buffer, buffer_size, start_bytes, end_bytes,
12,482✔
160
                        indexer.get()->get_max_bytes());
12,482!
161

162
    DFTRACER_UTILS_LOG_DEBUG(
163
        "GzipReader::read - request: start_bytes=%zu, end_bytes=%zu, "
164
        "buffer_size=%zu",
165
        start_bytes, end_bytes, buffer_size);
166

167
    // Check if we can reuse cached stream
168
    if (!stream_cache_.can_continue(StreamType::BYTES, gz_path, start_bytes,
24,940!
169
                                    end_bytes)) {
12,470✔
170
        DFTRACER_UTILS_LOG_DEBUG("%s",
171
                                 "GzipReader::read - creating new byte stream");
172
        auto new_stream = stream(StreamConfig()
322!
173
                                     .stream_type(StreamType::BYTES)
161!
174
                                     .range_type(RangeType::BYTE_RANGE)
161!
175
                                     .from(start_bytes)
161!
176
                                     .to(end_bytes));
161!
177
        stream_cache_.update(std::move(new_stream), StreamType::BYTES, gz_path,
322!
178
                             start_bytes, end_bytes);
161✔
179
    } else {
161✔
180
        DFTRACER_UTILS_LOG_DEBUG(
181
            "%s", "GzipReader::read - reusing cached byte stream");
182
    }
183

184
    std::size_t result =
24,940✔
185
        co_await stream_cache_.get()->read_async(buffer, buffer_size);
37,422!
186
    DFTRACER_UTILS_LOG_DEBUG("GzipReader::read - returned %zu bytes", result);
187

188
    // Update position for next potential read
189
    stream_cache_.update_position(start_bytes + result);
12,470!
190

191
    co_return result;
12,470!
192
}
62,386!
193

194
coro::CoroTask<std::size_t> GzipReader::read_line_bytes_async(
518,762!
195
    std::size_t start_bytes, std::size_t end_bytes, char *buffer,
196
    std::size_t buffer_size) {
64,845!
197
    check_reader_state(is_open, indexer.get());
194,535✔
198

199
    if (end_bytes > indexer.get()->get_max_bytes()) {
64,845!
200
        end_bytes = indexer.get()->get_max_bytes();
×
201
    }
202

203
    validate_parameters(buffer, buffer_size, start_bytes, end_bytes,
64,845!
204
                        indexer.get()->get_max_bytes());
64,845!
205

206
    // Check if we can reuse cached stream
207
    if (!stream_cache_.can_continue(StreamType::MULTI_LINES_BYTES, gz_path,
129,690✔
208
                                    start_bytes, end_bytes)) {
64,845✔
209
        auto new_stream = stream(StreamConfig()
2,032!
210
                                     .stream_type(StreamType::MULTI_LINES_BYTES)
1,016!
211
                                     .range_type(RangeType::BYTE_RANGE)
1,016!
212
                                     .from(start_bytes)
1,016!
213
                                     .to(end_bytes));
1,016!
214
        stream_cache_.update(std::move(new_stream),
2,032!
215
                             StreamType::MULTI_LINES_BYTES, gz_path,
1,016✔
216
                             start_bytes, end_bytes);
1,016✔
217
    }
1,016✔
218

219
    std::size_t result =
259,380✔
220
        co_await stream_cache_.get()->read_async(buffer, buffer_size);
324,225!
221

222
    // Update position for next potential read
223
    stream_cache_.update_position(start_bytes + result);
64,845!
224

225
    co_return result;
64,845!
226
}
842,989!
227

228
coro::CoroTask<std::string> GzipReader::read_lines_async(std::size_t start_line,
2,006!
229
                                                         std::size_t end_line) {
163!
230
    check_reader_state(is_open, indexer.get());
163!
231

232
    if (start_line == 0 || end_line == 0) {
163✔
233
        throw std::runtime_error("Line numbers must be 1-based (start from 1)");
6!
234
    }
235

236
    if (start_line > end_line) {
157✔
237
        throw std::runtime_error("Start line must be <= end line");
3!
238
    }
239

240
    std::size_t total_lines = indexer.get()->get_num_lines();
154!
241
    if (start_line > total_lines || end_line > total_lines) {
154✔
242
        throw std::runtime_error("Line numbers exceed total lines in file (" +
4!
243
                                 std::to_string(total_lines) + ")");
4!
244
    }
245

246
    // Check if we can reuse cached stream
247
    if (!stream_cache_.can_continue(StreamType::MULTI_LINES, gz_path,
304!
248
                                    start_line, end_line)) {
152✔
249
        auto new_stream = stream(StreamConfig()
304!
250
                                     .stream_type(StreamType::MULTI_LINES)
152!
251
                                     .range_type(RangeType::LINE_RANGE)
152!
252
                                     .from(start_line)
152!
253
                                     .to(end_line));
152!
254
        stream_cache_.update(std::move(new_stream), StreamType::MULTI_LINES,
304!
255
                             gz_path, start_line, end_line);
152✔
256
    }
152✔
257

258
    std::string result;
152✔
259
    // Pre-allocate to avoid reallocations (like old StringLineProcessor)
260
    std::size_t estimated_lines = end_line - start_line + 1;
152✔
261
    result.reserve(estimated_lines * 100);  // Estimate ~100 bytes per line
152!
262

263
    std::vector<char> buffer(default_buffer_size);
152!
264

265
    while (!stream_cache_.get()->done()) {
561!
266
        std::size_t bytes_read = co_await stream_cache_.get()->read_async(
1,799!
267
            buffer.data(), buffer.size());
409✔
268
        if (bytes_read == 0) break;
409!
269

270
        result.append(buffer.data(), bytes_read);
409!
271
    }
409✔
272

273
    co_return result;
1,180!
274
}
3,459!
275

276
coro::CoroTask<void> GzipReader::read_lines_with_processor_async(
×
277
    std::size_t start_line, std::size_t end_line, LineProcessor &processor) {
×
278
    check_reader_state(is_open, indexer.get());
×
279

280
    if (start_line == 0 || end_line == 0) {
×
281
        throw std::runtime_error("Line numbers must be 1-based (start from 1)");
×
282
    }
283

284
    if (start_line > end_line) {
×
285
        throw std::runtime_error("Start line must be <= end line");
×
286
    }
287

288
    std::size_t total_lines = indexer.get()->get_num_lines();
×
289
    if (start_line > total_lines || end_line > total_lines) {
×
290
        throw std::runtime_error("Line numbers exceed total lines in file (" +
×
291
                                 std::to_string(total_lines) + ")");
×
292
    }
293

294
    processor.begin(start_line, end_line);
×
295

296
    // Create a LineStream that returns one line at a time
297
    auto line_stream = stream(StreamConfig()
×
298
                                  .stream_type(StreamType::LINE)
×
299
                                  .range_type(RangeType::LINE_RANGE)
×
300
                                  .from(start_line)
×
301
                                  .to(end_line));
×
302

303
    std::vector<char> buffer(default_buffer_size);
×
304

305
    while (!line_stream->done()) {
×
306
        std::size_t bytes_read =
307
            co_await line_stream->read_async(buffer.data(), buffer.size());
×
308
        if (bytes_read == 0) break;
×
309

310
        // LineStream returns one complete line with \n
311
        // Processor expects line without \n
312
        std::size_t line_length = bytes_read;
313
        if (line_length > 0 && buffer[line_length - 1] == '\n') {
×
314
            line_length--;
315
        }
316

317
        if (!co_await processor.process(buffer.data(), line_length)) {
×
318
            processor.end();
×
319
            co_return;
320
        }
321
    }
×
322

323
    processor.end();
×
324
}
×
325

326
coro::CoroTask<void> GzipReader::read_line_bytes_with_processor_async(
×
327
    std::size_t start_bytes, std::size_t end_bytes, LineProcessor &processor) {
×
328
    check_reader_state(is_open, indexer.get());
×
329

330
    if (end_bytes > indexer.get()->get_max_bytes()) {
×
331
        end_bytes = indexer.get()->get_max_bytes();
×
332
    }
333

334
    if (start_bytes >= end_bytes) {
×
335
        co_return;
336
    }
337

338
    processor.begin(start_bytes, end_bytes);
×
339

340
    auto lines_stream = stream(StreamConfig()
×
341
                                   .stream_type(StreamType::LINE_BYTES)
×
342
                                   .range_type(RangeType::BYTE_RANGE)
×
343
                                   .from(start_bytes)
×
344
                                   .to(end_bytes));
×
345

346
    std::vector<char> buffer(default_buffer_size);
×
347

348
    while (!lines_stream->done()) {
×
349
        std::size_t bytes_read =
350
            co_await lines_stream->read_async(buffer.data(), buffer.size());
×
351
        if (bytes_read == 0) break;
×
352
        co_await processor.process(buffer.data(), bytes_read);
×
353
    }
×
354

355
    processor.end();
×
356
}
×
357

358
bool GzipReader::is_valid() const { return is_open && indexer.get(); }
74!
359

360
std::string GzipReader::get_format_name() const { return "GZIP"; }
2!
361

362
std::unique_ptr<ReaderStream> GzipReader::stream(const StreamConfig &config) {
3,538✔
363
    check_reader_state(is_open, indexer.get());
3,538!
364

365
    // Extract config parameters
366
    StreamType stream_type = config.stream_type();
3,538✔
367
    RangeType range_type = config.range_type();
3,538✔
368
    std::size_t start = config.start();
3,538✔
369
    std::size_t end = config.end();
3,538✔
370
    std::size_t buffer_size = config.buffer_size();
3,537✔
371

372
    // Convert line range to byte range if needed
373
    std::size_t start_bytes = start;
3,538✔
374
    std::size_t end_bytes = end;
3,538✔
375
    std::size_t actual_start_line =
3,538✔
376
        1;  // Track what line number start_bytes corresponds to
377

378
    if (range_type == RangeType::LINE_RANGE) {
3,538✔
379
        // Convert line numbers to byte offsets using checkpoints
380
        if (start == 0 || end == 0) {
452!
381
            throw ReaderError(ReaderError::INVALID_ARGUMENT,
×
382
                              "Line numbers must be 1-based (start from 1)");
×
383
        }
384
        if (start > end) {
452✔
385
            throw ReaderError(ReaderError::INVALID_ARGUMENT,
×
386
                              "Start line must be <= end line");
×
387
        }
388

389
        std::size_t total_lines = indexer->get_num_lines();
452!
390
        if (start > total_lines || end > total_lines) {
452!
391
            throw ReaderError(ReaderError::INVALID_ARGUMENT,
×
392
                              "Line numbers exceed total lines in file (" +
×
393
                                  std::to_string(total_lines) + ")");
×
394
        }
395

396
        // Get checkpoints for the line range
397
        std::vector<
398
            dftracer::utils::utilities::indexer::internal::IndexerCheckpoint>
399
            checkpoints = indexer->get_checkpoints_for_line_range(start, end);
452!
400

401
        DFTRACER_UTILS_LOG_DEBUG("Line range %zu-%zu: found %zu checkpoints",
402
                                 start, end, checkpoints.size());
403

404
        if (checkpoints.empty()) {
452✔
405
            // No checkpoints, read from beginning
406
            start_bytes = 0;
180✔
407
            end_bytes = indexer->get_max_bytes();
180!
408
            actual_start_line = 1;
180✔
409
            DFTRACER_UTILS_LOG_DEBUG(
410
                "No checkpoints found, using full file: start_bytes=%zu, "
411
                "end_bytes=%zu, max_bytes=%zu",
412
                start_bytes, end_bytes, indexer->get_max_bytes());
413
        } else {
90✔
414
            // Use checkpoint to determine byte range.
415
            //
416
            // Checkpoint uc_offset values fall at deflate block boundaries
417
            // which may land in the middle of a text line.  When we start
418
            // decompressing from such a mid-line position the first "line"
419
            // seen by MultiLineStream is a partial fragment.  If
420
            // actual_start_line == start_line the fragment is emitted as
421
            // the requested first line, producing wrong content.
422
            //
423
            // To avoid this we choose a checkpoint whose last_line_num is
424
            // strictly less than (start - 1), guaranteeing
425
            // actual_start_line < start.  MultiLineStream then filters
426
            // out the (potentially partial) early lines before reaching
427
            // the requested range.
428
            auto all_checkpoints = indexer->get_checkpoints();
272!
429
            bool found_start = false;
272✔
430

431
            // Walk checkpoints from the end to find the latest one whose
432
            // line range ends before (start - 1).
433
            for (auto it = all_checkpoints.rbegin();
13,668✔
434
                 it != all_checkpoints.rend(); ++it) {
19,703!
435
                if (it->last_line_num < start - 1) {
12,940!
436
                    start_bytes = it->uc_offset;
139!
437
                    actual_start_line = it->last_line_num + 1;
139!
438
                    found_start = true;
139✔
439
                    break;
139✔
440
                }
441
            }
6,630✔
442

443
            if (!found_start) {
272✔
444
                // No suitable checkpoint found -- start from beginning
445
                start_bytes = 0;
133✔
446
                actual_start_line = 1;
133✔
447
            }
67✔
448

449
            const auto &last_checkpoint = checkpoints.back();
272✔
450
            end_bytes = last_checkpoint.uc_offset + last_checkpoint.uc_size;
272✔
451

452
            DFTRACER_UTILS_LOG_DEBUG(
453
                "Using checkpoints: matched_first_idx=%zu "
454
                "(first_line=%zu, last_line=%zu), "
455
                "end_checkpoint_idx=%zu (first_line=%zu, last_line=%zu), "
456
                "byte_range=%zu-%zu, actual_start_line=%zu",
457
                checkpoints[0].checkpoint_idx, checkpoints[0].first_line_num,
458
                checkpoints[0].last_line_num, last_checkpoint.checkpoint_idx,
459
                last_checkpoint.first_line_num, last_checkpoint.last_line_num,
460
                start_bytes, end_bytes, actual_start_line);
461
        }
272✔
462
    }
452✔
463

464
    // Create appropriate stream type
465
    switch (stream_type) {
3,537!
466
        case StreamType::BYTES: {
193✔
467
            auto byte_stream = std::make_unique<GzipByteStream>(buffer_size);
386!
468
            byte_stream->initialize(gz_path, start_bytes, end_bytes, *indexer);
386!
469
            return byte_stream;
386✔
470
        }
386✔
471
        case StreamType::LINE_BYTES: {
155✔
472
            // Single line-aligned bytes at a time
473
            auto line_byte_stream =
474
                std::make_unique<GzipLineByteStream>(buffer_size);
310!
475
            line_byte_stream->initialize(gz_path, start_bytes, end_bytes,
619!
476
                                         *indexer);
310✔
477

478
            // Wrap with LineStream to return one line-aligned chunk at a time
479
            if (range_type == RangeType::LINE_RANGE) {
310✔
480
                return std::make_unique<LineStream>(
6!
481
                    std::move(line_byte_stream), start, end, actual_start_line);
4✔
482
            } else {
483
                return std::make_unique<LineStream>(
459!
484
                    std::move(line_byte_stream));
306✔
485
            }
486
        }
310✔
487
        case StreamType::MULTI_LINES_BYTES: {
1,128✔
488
            // Multiple line-aligned bytes per read
489
            auto line_byte_stream =
490
                std::make_unique<GzipLineByteStream>(buffer_size);
2,257!
491
            line_byte_stream->initialize(gz_path, start_bytes, end_bytes,
4,515!
492
                                         *indexer);
2,258✔
493
            return line_byte_stream;
2,258✔
494
        }
2,257✔
495
        case StreamType::LINE: {
54✔
496
            // Single parsed line per read
497
            auto line_byte_stream =
498
                std::make_unique<GzipLineByteStream>(buffer_size);
108!
499
            line_byte_stream->initialize(gz_path, start_bytes, end_bytes,
216!
500
                                         *indexer);
108✔
501

502
            if (range_type == RangeType::LINE_RANGE) {
108✔
503
                return std::make_unique<LineStream>(
159!
504
                    std::move(line_byte_stream), start, end, actual_start_line);
106✔
505
            } else {
506
                return std::make_unique<LineStream>(
3!
507
                    std::move(line_byte_stream));
2✔
508
            }
509
        }
108✔
510
        case StreamType::MULTI_LINES: {
238✔
511
            // Multiple parsed lines per read
512
            auto line_byte_stream =
513
                std::make_unique<GzipLineByteStream>(buffer_size);
476!
514
            line_byte_stream->initialize(gz_path, start_bytes, end_bytes,
952!
515
                                         *indexer);
476✔
516

517
            if (range_type == RangeType::LINE_RANGE) {
476✔
518
                return std::make_unique<MultiLineStream>(
507!
519
                    std::move(line_byte_stream), start, end, actual_start_line);
337✔
520
            } else {
521
                return std::make_unique<MultiLineStream>(
207!
522
                    std::move(line_byte_stream));
138✔
523
            }
524
        }
476✔
525
        default:
526
            throw ReaderError(ReaderError::INVALID_ARGUMENT,
×
527
                              "Invalid stream type");
×
528
    }
529
}
1,769✔
530

531
}  // namespace dftracer::utils::utilities::reader::internal
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

© 2026 Coveralls, Inc