Skip to content

Commit 9a30e5e

Browse files
committed
feat: add small_fifo container
1 parent dffe9f4 commit 9a30e5e

3 files changed

Lines changed: 688 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ if(WITH_TESTS)
692692
test/pcm_sample_transformer_test.cpp
693693
test/pinned_byte_span_store_test.cpp
694694
test/scoped_output_capture_test.cpp
695+
test/small_fifo_test.cpp
695696
test/sorted_array_map_test.cpp
696697
test/sparse_chunk_codec_test.cpp
697698
test/sparse_file_seeker_test.cpp
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/* vim:set ts=2 sw=2 sts=2 et: */
2+
/**
3+
* \author Marcus Holland-Moritz (github@mhxnet.de)
4+
* \copyright Copyright (c) Marcus Holland-Moritz
5+
*
6+
* This file is part of dwarfs.
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the “Software”), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
* SOFTWARE.
25+
*
26+
* SPDX-License-Identifier: MIT
27+
*/
28+
29+
#pragma once
30+
31+
#include <cstddef>
32+
#include <iterator>
33+
#include <utility>
34+
35+
#include <dwarfs/small_vector.h>
36+
37+
namespace dwarfs::container {
38+
39+
/**
40+
* A minimal FIFO over small_vector, for short-lived, usually tiny queues
41+
*
42+
* std::deque allocates a whole block up front (512 bytes under libstdc++,
43+
* 4096 under libc++), even for a single element. That's often wasteful.
44+
*
45+
* Storage is reclaimed to the inline buffer whenever the queue drains, which
46+
* for a produce-a-few / consume-to-empty pattern means no allocation at all
47+
* after the first growth beyond N.
48+
*/
49+
template <typename T, std::size_t N>
50+
class small_fifo {
51+
public:
52+
using value_type = T;
53+
54+
static constexpr size_t inline_capacity = N;
55+
56+
small_fifo() = default;
57+
58+
template <std::input_iterator InputIt>
59+
small_fifo(InputIt first, InputIt last)
60+
: v_{first, last} {}
61+
62+
bool empty() const noexcept { return head_ == v_.size(); }
63+
64+
std::size_t size() const noexcept { return v_.size() - head_; }
65+
66+
std::size_t capacity() const noexcept { return v_.capacity(); }
67+
68+
T& front() noexcept { return v_[head_]; }
69+
T const& front() const noexcept { return v_[head_]; }
70+
71+
void pop_front() {
72+
++head_;
73+
74+
if (head_ == v_.size()) {
75+
// drained: return to the inline buffer and reuse it next time round
76+
v_.clear();
77+
head_ = 0;
78+
} else if (head_ >= N && 2 * head_ >= v_.size()) {
79+
// amortized O(1): compact once dead slots outnumber live ones
80+
v_.erase(v_.begin(), v_.begin() + head_);
81+
head_ = 0;
82+
}
83+
}
84+
85+
void push_back(T value) { v_.push_back(std::move(value)); }
86+
87+
template <typename... Args>
88+
T& emplace_back(Args&&... args) {
89+
return v_.emplace_back(std::forward<Args>(args)...);
90+
}
91+
92+
// bulk append: the common case is an empty queue, where the incoming
93+
// buffer can simply be adopted.
94+
template <typename Range>
95+
void append(Range&& r) {
96+
if (empty()) {
97+
clear();
98+
}
99+
for (auto&& e : r) {
100+
v_.push_back(std::move(e));
101+
}
102+
}
103+
104+
void clear() noexcept {
105+
v_.clear();
106+
head_ = 0;
107+
}
108+
109+
private:
110+
small_vector<T, N> v_;
111+
std::size_t head_{0};
112+
};
113+
114+
} // namespace dwarfs::container

0 commit comments

Comments
 (0)