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

afxres / binary-cxx / 17874582719

20 Sep 2025 03:14AM UTC coverage: 99.129% (-0.1%) from 99.231%
17874582719

push

github

afxres
Add underlying allocator interface and implementation

54 of 54 new or added lines in 5 files covered. (100.0%)

1 existing line in 1 file now uncovered.

797 of 804 relevant lines covered (99.13%)

131.7 hits per line

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

99.39
/code/binary/src/Allocator.cpp
1
#include "binary/Allocator.hpp"
2

3
#include <cassert>
4
#include <cstdint>
5
#include <cstring>
6
#include <stdexcept>
7

8
#include "binary/internal/Exception.hpp"
9
#include "binary/internal/Length.hpp"
10

11
namespace binary {
12
constexpr size_t AllocatorAnchorSize = 4;
13
constexpr size_t AllocatorCapacitySeed = 256;
14

15
Allocator::Allocator()
86✔
16
    : Allocator({}, INT32_MAX) {}
86✔
17

18
Allocator::Allocator(std::span<std::byte> span)
1✔
19
    : Allocator(span, INT32_MAX) {}
1✔
20

21
Allocator::Allocator(std::span<std::byte> span, size_t maxCapacity)
102✔
22
    : allocated(false)
102✔
23
    , bridge(nullptr)
102✔
24
    , buffer(span.data())
102✔
25
    , offset(0)
102✔
26
    , bounds(std::min(span.size(), maxCapacity))
102✔
27
    , limits(maxCapacity) {
102✔
28
    if (maxCapacity > INT32_MAX) {
102✔
29
        throw std::invalid_argument("maxCapacity > INT32_MAX");
2✔
30
    }
31
}
100✔
32

33
Allocator::Allocator(IAllocator& allocator)
367✔
34
    : Allocator(allocator, INT32_MAX) {}
367✔
35

36
Allocator::Allocator(IAllocator& allocator, size_t maxCapacity)
367✔
37
    : allocated(false)
367✔
38
    , bridge(&allocator)
367✔
39
    , buffer(nullptr)
367✔
40
    , offset(0)
367✔
41
    , bounds(0)
367✔
42
    , limits(maxCapacity) {
367✔
43
    if (maxCapacity > INT32_MAX) {
367✔
UNCOV
44
        throw std::invalid_argument("maxCapacity > INT32_MAX");
×
45
    }
46
}
367✔
47

48
Allocator::~Allocator() {
467✔
49
    if (this->allocated) {
467✔
50
        free(this->buffer);
77✔
51
    }
52
}
467✔
53

54
std::span<const std::byte> Allocator::AsSpan() const {
76✔
55
    return std::span<const std::byte>(this->buffer, this->offset);
76✔
56
}
57

58
void Allocator::Resize(size_t length) {
405✔
59
    assert(this->limits <= INT32_MAX);
405✔
60
    assert(this->bounds <= INT32_MAX);
405✔
61
    assert(this->offset <= INT32_MAX);
405✔
62
    assert(this->offset <= this->bounds);
405✔
63
    assert(this->bounds <= this->limits);
405✔
64
    assert(length != 0);
405✔
65

66
    size_t offset = this->offset;
405✔
67
    size_t limits = this->limits;
405✔
68
    uint64_t amount = static_cast<uint64_t>(offset) + length;
405✔
69
    if (length > INT32_MAX || amount > limits) {
405✔
70
        throw std::length_error("maximum capacity reached");
6✔
71
    }
72
    size_t source = this->bounds;
399✔
73
    uint64_t cursor = static_cast<uint64_t>(source);
399✔
74
    if (cursor == 0) {
399✔
75
        cursor = AllocatorCapacitySeed;
391✔
76
    }
77
    while (cursor < amount) {
487✔
78
        cursor *= 2;
88✔
79
    }
80
    if (cursor > limits) {
399✔
81
        cursor = limits;
2✔
82
    }
83
    assert(amount <= cursor);
399✔
84
    assert(cursor <= this->limits);
399✔
85

86
    size_t bounds = static_cast<size_t>(cursor);
399✔
87
    if (this->bridge == nullptr) {
399✔
88
        auto target = static_cast<std::byte*>(malloc(bounds));
84✔
89
        ::binary::internal::EnsureMemoryAccess(target);
84✔
90
        if (offset != 0) {
84✔
91
            memcpy(target, this->buffer, offset);
8✔
92
        }
93
        if (this->allocated) {
84✔
94
            free(this->buffer);
7✔
95
        }
96
        this->allocated = true;
84✔
97
        this->buffer = target;
84✔
98
    } else {
99
        this->buffer = this->bridge->Resize(bounds);
315✔
100
        assert(this->buffer != nullptr);
315✔
101
        assert(this->allocated == false);
315✔
102
    }
103
    this->bounds = bounds;
399✔
104
    assert(offset <= source);
399✔
105
    assert(offset <= this->bounds);
399✔
106
}
399✔
107

108
size_t Allocator::Anchor() {
16✔
109
    Ensure(AllocatorAnchorSize);
16✔
110
    size_t offset = this->offset;
16✔
111
    this->offset = offset + AllocatorAnchorSize;
16✔
112
    return offset;
16✔
113
}
114

115
std::byte* Allocator::Assign(size_t length) {
647✔
116
    assert(length != 0);
647✔
117
    Ensure(length);
647✔
118
    size_t offset = this->offset;
643✔
119
    this->offset = offset + length;
643✔
120
    return this->buffer + offset;
643✔
121
}
122

123
std::byte* Allocator::Create(size_t length) {
13✔
124
    assert(length != 0);
13✔
125
    Ensure(length);
13✔
126
    size_t offset = this->offset;
13✔
127
    return this->buffer + offset;
13✔
128
}
129

130
void Allocator::FinishAnchor(size_t anchor) {
23✔
131
    assert(this->bounds <= INT32_MAX);
23✔
132
    assert(this->offset <= this->bounds);
23✔
133
    size_t offset = this->offset;
23✔
134
    uint64_t refers = static_cast<uint64_t>(anchor) + AllocatorAnchorSize;
23✔
135
    if (anchor > INT32_MAX || refers > offset) {
23✔
136
        throw std::logic_error("allocator has been modified unexpectedly");
7✔
137
    }
138
    size_t length = offset - static_cast<size_t>(refers);
16✔
139
    std::byte* target = this->buffer + anchor;
16✔
140
    if (length == 0) {
16✔
141
        this->offset = offset - 3;
2✔
142
        ::binary::internal::EncodeLengthPrefix(target, length, 1);
2✔
143
        assert(this->offset >= 1);
2✔
144
        assert(this->offset <= this->bounds);
2✔
145
    } else {
146
        ::binary::internal::EncodeLengthPrefix(target, length, 4);
14✔
147
        assert(this->offset >= 4);
14✔
148
        assert(this->offset <= this->bounds);
14✔
149
    }
150
}
16✔
151

152
void Allocator::FinishCreate(size_t length) {
5✔
153
    size_t offset = this->offset;
5✔
154
    assert(this->bounds <= INT32_MAX);
5✔
155
    assert(this->bounds >= offset);
5✔
156
    assert(this->bounds >= offset + length);
5✔
157
    this->offset = offset + length;
5✔
158
}
5✔
159

160
void Allocator::Ensure(size_t length) {
691✔
161
    assert(this->bounds <= INT32_MAX);
691✔
162
    assert(this->offset <= this->bounds);
691✔
163
    if (length > INT32_MAX || static_cast<uint64_t>(this->offset) + length > this->bounds) [[unlikely]] {
691✔
164
        Resize(length);
405✔
165
    }
166
    assert(this->bounds <= this->limits);
685✔
167
    assert(this->bounds >= this->offset + length);
685✔
168
}
685✔
169

170
void Allocator::Expand(size_t length) {
10✔
171
    Ensure(length);
10✔
172
    this->offset += length;
10✔
173
    assert(this->bounds <= INT32_MAX);
10✔
174
    assert(this->offset <= this->bounds);
10✔
175
}
10✔
176

177
void Allocator::Append(std::byte data) {
2✔
178
    *Assign(sizeof(std::byte)) = data;
2✔
179
}
2✔
180

181
void Allocator::Append(const std::span<const std::byte>& span) {
132✔
182
    if (span.empty()) {
132✔
183
        return;
2✔
184
    }
185
    memcpy(Assign(span.size()), span.data(), span.size());
130✔
186
}
187

188
void Allocator::Append(size_t length, const std::function<void(std::span<std::byte>)>& action) {
25✔
189
    if (length == 0) {
25✔
190
        return;
1✔
191
    }
192
    action(std::span<std::byte>(Assign(length), length));
24✔
193
}
194

195
void Allocator::Append(size_t maxLength, const std::function<void(std::span<std::byte>, size_t&)>& action) {
7✔
196
    if (maxLength == 0) {
7✔
197
        return;
1✔
198
    }
199
    size_t actual = SIZE_MAX;
6✔
200
    std::byte* target = Create(maxLength);
6✔
201
    action(std::span<std::byte>(target, maxLength), actual);
6✔
202
    if (actual > maxLength) {
6✔
203
        ::binary::internal::ThrowInvalidBytesWrittenValue();
4✔
204
    }
205
    FinishCreate(actual);
2✔
206
}
207

208
void Allocator::AppendWithLengthPrefix(const std::function<void(Allocator&)>& action) {
4✔
209
    size_t anchor = Anchor();
4✔
210
    action(*this);
4✔
211
    FinishAnchor(anchor);
4✔
212
}
4✔
213

214
void Allocator::AppendWithLengthPrefix(size_t maxLength, const std::function<void(std::span<std::byte>, size_t&)>& action) {
7✔
215
    ::binary::internal::EnsureLengthPrefixLength(maxLength);
7✔
216
    size_t actual;
217
    size_t prefixLength = ::binary::internal::EncodeLengthPrefixLength(maxLength);
7✔
218
    std::byte* target = Create(maxLength + prefixLength);
7✔
219
    if (maxLength == 0) {
7✔
220
        actual = 0;
1✔
221
    } else {
222
        actual = SIZE_MAX;
6✔
223
        action(std::span<std::byte>(target + prefixLength, maxLength), actual);
6✔
224
        if (actual > maxLength) {
6✔
225
            ::binary::internal::ThrowInvalidBytesWrittenValue();
4✔
226
        }
227
    }
228
    ::binary::internal::EncodeLengthPrefix(target, actual, prefixLength);
3✔
229
    FinishCreate(actual + prefixLength);
3✔
230
}
3✔
231
}
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