Skip to content

Commit f7f24d4

Browse files
committed
add BEMAN_INPLACE_VECTOR_FIXED_SIZE_T option
1 parent 501804e commit f7f24d4

File tree

3 files changed

+68
-22
lines changed

3 files changed

+68
-22
lines changed

CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ option(
2727
${PROJECT_IS_TOP_LEVEL}
2828
)
2929

30+
option(
31+
BEMAN_INPLACE_VECTOR_FIXED_SIZE_T
32+
"Fixes size_t in inplace_vector, otherwise size_t is dynamic against \
33+
inplace_vector's capacity. Default: OFF. Values: { ON, OFF }."
34+
OFF
35+
)
36+
37+
configure_file(
38+
"${PROJECT_SOURCE_DIR}/include/beman/inplace_vector/config.hpp.in"
39+
"${PROJECT_BINARY_DIR}/include/beman/inplace_vector/config.hpp"
40+
@ONLY
41+
)
42+
3043
include(FetchContent)
3144
include(GNUInstallDirs)
3245

@@ -38,6 +51,7 @@ target_include_directories(
3851
beman.inplace_vector
3952
INTERFACE
4053
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
54+
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
4155
$<INSTALL_INTERFACE:include>
4256
)
4357

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2+
3+
#pragma once
4+
5+
#define BEMAN_INPLACE_VECTOR_CONFIG
6+
7+
#cmakedefine01 BEMAN_INPLACE_VECTOR_FIXED_SIZE_T

include/beman/inplace_vector/inplace_vector.hpp

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
#pragma once
22
#pragma GCC diagnostic ignored "-Wunused-parameter"
33

4+
#include <beman/inplace_vector/config.hpp>
5+
#ifndef BEMAN_INPLACE_VECTOR_CONFIG
6+
#error "Config file not run"
7+
#endif
8+
49
/*
510
* SPDX-FileCopyrightText: Copyright (c) 2023 Gonzalo Brito Gadeschi. All rights
611
reserved.
@@ -282,15 +287,31 @@ namespace beman::details::inplace_vector {
282287

283288
// clang-format off
284289
// Smallest unsigned integer that can represent values in [0, N].
285-
template <size_t N>
290+
template <std::size_t N>
286291
using smallest_size_t
287292
= std::conditional_t<(N < std::numeric_limits<uint8_t>::max()), uint8_t,
288293
std::conditional_t<(N < std::numeric_limits<uint16_t>::max()), uint16_t,
289294
std::conditional_t<(N < std::numeric_limits<uint32_t>::max()), uint32_t,
290295
std::conditional_t<(N < std::numeric_limits<uint64_t>::max()), uint64_t,
291-
size_t>>>>;
296+
std::size_t>>>>;
292297
// clang-format on
293298

299+
/*
300+
* This is generally for managing the size type in the storage block.
301+
* This behavior can be turned off by setting the
302+
* BEMAN_INPLACE_VECTOR_FIXED_SIZE_T build option as there has been report of
303+
* performance impact.
304+
*
305+
* This macro is set in the config.hpp.
306+
*/
307+
template <std::size_t N>
308+
using size_t_for =
309+
#if BEMAN_INPLACE_VECTOR_FIXED_SIZE_T == 1
310+
std::size_t;
311+
#else
312+
smallest_size_t<N>;
313+
#endif
314+
294315
// Index a random-access and sized range doing bound checks in debug builds
295316
template <std::ranges::random_access_range Rng, std::integral Index>
296317
static constexpr decltype(auto) index(Rng &&rng, Index i) noexcept
@@ -317,7 +338,7 @@ template <class T> struct zero_sized {
317338
using size_type = uint8_t;
318339
static constexpr T *storage_data() noexcept { return nullptr; }
319340
static constexpr size_type storage_size() noexcept { return 0; }
320-
static constexpr void unsafe_set_size(size_t new_size) noexcept {
341+
static constexpr void unsafe_set_size(std::size_t new_size) noexcept {
321342
IV_EXPECT(new_size == 0 &&
322343
"tried to change size of empty storage to non-zero value");
323344
}
@@ -332,13 +353,13 @@ template <class T> struct zero_sized {
332353
};
333354

334355
// Storage for trivial types.
335-
template <class T, size_t N> struct trivial {
356+
template <class T, std::size_t N> struct trivial {
336357
static_assert(std::is_trivial_v<T>,
337358
"storage::trivial<T, C> requires Trivial<T>");
338-
static_assert(N != size_t{0}, "N == 0, use zero_sized");
359+
static_assert(N != std::size_t{0}, "N == 0, use zero_sized");
339360

340361
protected:
341-
using size_type = smallest_size_t<N>;
362+
using size_type = size_t_for<N>;
342363

343364
private:
344365
// If value_type is const, then const std::array of non-const elements:
@@ -354,7 +375,7 @@ template <class T, size_t N> struct trivial {
354375
}
355376
constexpr T *storage_data() noexcept { return storage_data_.data(); }
356377
constexpr size_type storage_size() const noexcept { return storage_size_; }
357-
constexpr void unsafe_set_size(size_t new_size) noexcept {
378+
constexpr void unsafe_set_size(std::size_t new_size) noexcept {
358379
IV_EXPECT(size_type(new_size) <= N && "new_size out-of-bounds [0, N]");
359380
storage_size_ = size_type(new_size);
360381
}
@@ -368,26 +389,27 @@ template <class T, size_t N> struct trivial {
368389
constexpr ~trivial() = default;
369390
};
370391

371-
template <class T, size_t N> struct raw_byte_based_storage {
392+
template <class T, std::size_t N> struct raw_byte_based_storage {
393+
public:
372394
alignas(T) std::byte _d[sizeof(T) * N];
373-
constexpr T *storage_data(size_t i) noexcept {
395+
constexpr T *storage_data(std::size_t i) noexcept {
374396
IV_EXPECT(i < N);
375397
return reinterpret_cast<T *>(_d) + i;
376398
}
377-
constexpr const T *storage_data(size_t i) const noexcept {
399+
constexpr const T *storage_data(std::size_t i) const noexcept {
378400
IV_EXPECT(i < N);
379401
return reinterpret_cast<const T *>(_d) + i;
380402
}
381403
};
382404

383405
/// Storage for non-trivial elements.
384-
template <class T, size_t N> struct non_trivial {
406+
template <class T, std::size_t N> struct non_trivial {
385407
static_assert(!std::is_trivial_v<T>,
386408
"use storage::trivial for Trivial<T> elements");
387-
static_assert(N != size_t{0}, "use storage::zero for N==0");
409+
static_assert(N != std::size_t{0}, "use storage::zero for N==0");
388410

389411
protected:
390-
using size_type = smallest_size_t<N>;
412+
using size_type = size_t_for<N>;
391413

392414
private:
393415
using byte_based_storage = std::conditional_t<
@@ -402,7 +424,7 @@ template <class T, size_t N> struct non_trivial {
402424
}
403425
constexpr T *storage_data() noexcept { return storage_data_.storage_data(0); }
404426
constexpr size_type storage_size() const noexcept { return storage_size_; }
405-
constexpr void unsafe_set_size(size_t new_size) noexcept {
427+
constexpr void unsafe_set_size(std::size_t new_size) noexcept {
406428
IV_EXPECT(size_type(new_size) <= N && "new_size out-of-bounds [0, N)");
407429
storage_size_ = size_type(new_size);
408430
}
@@ -423,7 +445,7 @@ template <class T, size_t N> struct non_trivial {
423445
};
424446

425447
// Selects the vector storage.
426-
template <class T, size_t N>
448+
template <class T, std::size_t N>
427449
using storage_for = std::conditional_t<
428450
N == 0, zero_sized<T>,
429451
std::conditional_t<std::is_trivial_v<T>, trivial<T, N>, non_trivial<T, N>>>;
@@ -433,7 +455,7 @@ using storage_for = std::conditional_t<
433455
namespace beman {
434456

435457
/// Dynamically-resizable fixed-N vector with inplace storage.
436-
template <class T, size_t N>
458+
template <class T, std::size_t N>
437459
struct inplace_vector
438460
: private details::inplace_vector::storage::storage_for<T, N> {
439461
private:
@@ -450,7 +472,8 @@ struct inplace_vector
450472
using const_pointer = const T *;
451473
using reference = value_type &;
452474
using const_reference = const value_type &;
453-
using size_type = size_t;
475+
// Note: This may be different from base_t::size_t.
476+
using size_type = std::size_t;
454477
using difference_type = std::ptrdiff_t;
455478
using iterator = pointer;
456479
using const_iterator = const_pointer;
@@ -518,7 +541,9 @@ struct inplace_vector
518541
[[nodiscard]] constexpr bool empty() const noexcept {
519542
return storage_size() == 0;
520543
};
521-
constexpr size_type size() const noexcept { return storage_size(); }
544+
constexpr size_type size() const noexcept {
545+
return size_type(storage_size());
546+
}
522547
static constexpr size_type max_size() noexcept { return N; }
523548
static constexpr size_type capacity() noexcept { return N; }
524549
// constexpr void resize(size_type sz);
@@ -730,8 +755,8 @@ struct inplace_vector
730755
{
731756
assert_iterator_in_range(position);
732757
if constexpr (std::random_access_iterator<InputIterator>) {
733-
if (size() + static_cast<size_type>(std::distance(first, last)) >
734-
capacity()) [[unlikely]]
758+
if (size() + size_type(std::distance(first, last)) > capacity())
759+
[[unlikely]]
735760
throw std::bad_alloc{};
736761
}
737762
auto b = end();
@@ -764,7 +789,7 @@ struct inplace_vector
764789
{
765790
assert_iterator_in_range(position);
766791
auto b = end();
767-
for (size_type i = 0; i < n; ++i)
792+
for (auto i = size_type(0); i < n; ++i)
768793
emplace_back(x);
769794
auto pos = begin() + (position - begin());
770795
std::rotate(pos, b, end());
@@ -827,7 +852,7 @@ struct inplace_vector
827852
iterator f = begin() + (first - begin());
828853
if (first != last) {
829854
unsafe_destroy(std::move(f + (last - first), end(), f), end());
830-
unsafe_set_size(size() - static_cast<size_type>(last - first));
855+
unsafe_set_size(size() - size_type(last - first));
831856
}
832857
return f;
833858
}

0 commit comments

Comments
 (0)