Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: zero relocation string containers #159

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
9c3d62a
ci: trigger for pull request pushes too
muggenhor Sep 5, 2023
a9576b3
ci: give names to workflows to make them distinguishable in the WebUI
muggenhor Sep 5, 2023
145cb94
ci: simply CMake setup and get colored diagnostics
muggenhor Sep 5, 2023
6808cf1
refactor: be less picky about the type of 'items' used for bucket con…
muggenhor Jul 27, 2022
3362e08
feat: expose character type as value_type to mimic std::basic_string_…
muggenhor Jul 31, 2022
4b99058
feat: make storage container parametrizable
muggenhor Aug 1, 2022
76358d5
feat: add empty(), front(), back() to frozen::string matching std::st…
muggenhor Aug 1, 2022
c0a3c7e
fix(map): avoid returning references to temporaries
muggenhor Aug 5, 2022
c4c378a
feat: add specialized variant of bits::carray for storing strings
muggenhor Aug 1, 2022
93d97d7
feat: provide make(_unordered)?_set specializations for string literals
muggenhor Aug 1, 2022
463f89e
feat: support storing strings contained in pairs & tuples too
muggenhor Aug 2, 2022
2e1ef6f
feat: provide make(_unordered)?_map specializations for string literals
muggenhor Aug 2, 2022
05db045
perf: use smallest possible integer to encode sizes and offsets
muggenhor Aug 8, 2023
2a82f46
fix: msvc compile error where template overload gets eliminated incor…
muggenhor Aug 14, 2023
5036dfc
fix: work around msvc compiler bugs related to NTTP/array refs in par…
muggenhor Aug 15, 2023
a7d4008
fix: work around msvc compiler bug with range-based-for in constexpr
muggenhor Aug 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
name: CI
name: Linux

on: [push]
on:
push:
pull_request:

jobs:
build_frozen:
Expand Down Expand Up @@ -32,16 +34,13 @@ jobs:
run: cmake -E make_directory build

- name: Configure
working-directory: build
env:
CXX: ${{matrix.compiler}}
CXXFLAGS: -std=c++${{matrix.cxxstandard}}
run: cmake -DCMAKE_BUILD_TYPE=DEBUG "-Dfrozen.coverage=ON" -DCMAKE_VERBOSE_MAKEFILE=ON ..
CXXFLAGS: -std=c++${{matrix.cxxstandard}} -fdiagnostics-color=always
run: cmake -DCMAKE_BUILD_TYPE=DEBUG "-Dfrozen.coverage=ON" -DCMAKE_VERBOSE_MAKEFILE=ON -B build -S .

- name: Build
working-directory: build
run: cmake --build .
run: cmake --build build

- name: Test
working-directory: build
run: cmake --build . --target test
run: cmake --build build --target test
20 changes: 8 additions & 12 deletions .github/workflows/osx.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
name: CI
name: OSX

on: [push]
on:
push:
pull_request:

jobs:
build_frozen:
Expand All @@ -20,19 +22,13 @@ jobs:
with:
fetch-depth: 1

- name: Prepare
run: cmake -E make_directory build

- name: Configure
working-directory: build
env:
CXXFLAGS: -std=c++${{matrix.cxxstandard}}
run: cmake -DCMAKE_BUILD_TYPE=DEBUG "-Dfrozen.coverage=ON" -DCMAKE_VERBOSE_MAKEFILE=ON ..
CXXFLAGS: -std=c++${{matrix.cxxstandard}} -fdiagnostics-color=always
run: cmake -DCMAKE_BUILD_TYPE=DEBUG "-Dfrozen.coverage=ON" -DCMAKE_VERBOSE_MAKEFILE=ON -B build -S .

- name: Build
working-directory: build
run: cmake --build .
run: cmake --build build

- name: Test
working-directory: build
run: cmake --build . --target test
run: cmake --build build --target test
15 changes: 6 additions & 9 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
name: CI
name: Windows

on: [push]
on:
push:
pull_request:

jobs:
build_frozen:
Expand All @@ -20,15 +22,10 @@ jobs:
with:
fetch-depth: 1

- name: Prepare
run: cmake -E make_directory build

- name: Configure
working-directory: build
env:
CXXFLAGS: /std:c++${{matrix.cxxstandard}}
run: cmake -DCMAKE_BUILD_TYPE=DEBUG "-Dfrozen.coverage=ON" -DCMAKE_VERBOSE_MAKEFILE=ON ..
run: cmake -DCMAKE_BUILD_TYPE=DEBUG "-Dfrozen.coverage=ON" -DCMAKE_VERBOSE_MAKEFILE=ON -B build -S .

- name: Build
working-directory: build
run: cmake --build .
run: cmake --build build
11 changes: 10 additions & 1 deletion examples/value_modification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@ MAYBE_CONSTINIT static frozen::unordered_map<frozen::string, int, 2> fruits = {
{"n_pears", 0},
};

// Force conversion to a const reference. std::cref(ref).get() fails with libc++
template <typename T>
constexpr decltype(auto) const_ref(const T& ref) noexcept {
return ref;
}

int main() {
// Update the values using at()
fruits.at("n_apples") = 10;
fruits.at("n_pears") = fruits.at("n_apples") * 2;
std::cout << "n_apples: " << fruits.at("n_apples") << std::endl;
std::cout << "n_pears: " << fruits.at("n_pears") << std::endl;

static_assert(std::is_same<decltype(const_ref(fruits).at("n_apples")), const int&>::value, "");
static_assert(std::is_same<decltype(fruits.at("n_apples")), int&>::value, "");

// You can also update values via the iterator returned by find()
auto found = fruits.find("n_apples");
found->second = 0;
Expand All @@ -34,4 +43,4 @@ int main() {
auto range = fruits.equal_range("n_apples");
range.first->second = 1337;
std::cout << "n_apples: " << fruits.at("n_apples") << std::endl;
}
}
11 changes: 11 additions & 0 deletions include/frozen/bits/algorithms.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,17 @@ constexpr bool lexicographical_compare(InputIt1 first1, InputIt1 last1, InputIt2
return (first1 == last1) && (first2 != last2);
}

template <typename Int>
constexpr Int accumulate(std::initializer_list<Int> items)
{
Int sum {}; // zero or default init
for (const auto& item : items) {
sum += item;
}

return sum;
}

} // namespace bits
} // namespace frozen

Expand Down
51 changes: 49 additions & 2 deletions include/frozen/bits/basic_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,58 @@ namespace bits {
// used as a fake argument for frozen::make_set and frozen::make_map in the case of N=0
struct ignored_arg {};

constexpr std::size_t number_of_bits(std::size_t x)
{
return x < 2 ? x : 1 + number_of_bits(x >> 1);
}

template <std::size_t total_size>
struct size_integer {
static constexpr std::size_t needed_bits = number_of_bits(total_size);

using type = std::conditional_t<
needed_bits <= 8u
, std::uint8_t
, std::conditional_t<
needed_bits <= 16u
, std::uint16_t
, std::conditional_t<
needed_bits <= 32u
, std::uint32_t
, std::conditional_t<
needed_bits <= 64u
, std::uint64_t
, std::size_t // 128 bit system: don't know, but lets stop optimizing for size here
>
>
>
>;
};

template <std::size_t total_size>
using size_integer_t = typename size_integer<total_size>::type;

// Helper type to work around apparent compiler bugs in MSVC related to having "too complex"
// template parameters involving either NTTP or references-to-array.
template <class T, std::size_t N>
struct array_ref {
using array_type = const T(&) [N];
using pointer = T*;

pointer array;

operator pointer () const noexcept { return array; }
operator array_type() const noexcept { return array; }
};

template <class T, std::size_t N>
class cvector {
public:
using size_type = size_integer_t<N>;

private:
T data [N] = {}; // zero-initialization for scalar type T, default-initialized otherwise
std::size_t dsize = 0;
size_type dsize = 0;

public:
// Container typdefs
Expand All @@ -51,7 +99,6 @@ class cvector {
using const_pointer = const value_type *;
using iterator = pointer;
using const_iterator = const_pointer;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;

// Constructors
Expand Down
45 changes: 45 additions & 0 deletions include/frozen/bits/mpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ namespace bits {
// Forward declarations
template <class, std::size_t>
class carray;
template <typename T, std::size_t N, std::size_t string_size>
struct pic_array;

template <typename T>
struct remove_cv : std::remove_cv<T> {};
Expand All @@ -46,9 +48,52 @@ struct remove_cv<carray<T, N>> {
using type = carray<typename remove_cv<T>::type, N>;
};

template <typename T, std::size_t N, std::size_t string_size>
struct remove_cv<pic_array<T, N, string_size>> {
using type = pic_array<typename remove_cv<T>::type, N, string_size>;
};

template <typename T>
using remove_cv_t = typename remove_cv<T>::type;

template <typename Container, typename ElemRef, typename Value>
class copy_cv_iter_ref
{
private:
using cv_container = std::remove_reference_t<Container>;
using c_value = std::conditional_t<std::is_const<cv_container>::value, std::add_const_t<Value>, Value>;
using cv_value = std::conditional_t<std::is_volatile<cv_container>::value, std::add_volatile_t<c_value>, c_value>;
using cv_ref_value = std::conditional_t<std::is_lvalue_reference<ElemRef>::value, std::add_lvalue_reference_t<cv_value>, cv_value>;
using cv_rvref_value = std::conditional_t<
std::is_lvalue_reference<cv_ref_value>::value
&& std::is_rvalue_reference<Container>::value
, std::add_rvalue_reference_t<cv_value>
, cv_ref_value>;
public:
using type = cv_rvref_value;
};

template <typename Container, typename ElemRef, typename Value>
using copy_cv_iter_ref_t = typename copy_cv_iter_ref<Container, ElemRef, Value>::type;

struct has_type_selector
{
// Relies on SFINAE to eliminate this overload when the type of it's first parameter does not
// have a 'type' member type.
template <class T>
static std::true_type test(const T&, typename T::type* = nullptr);
static std::false_type test(...);
};

template <class T>
struct has_type : decltype(has_type_selector::test(std::declval<T>())) {};

template <typename T>
struct is_pair : std::false_type {};

template <class... T>
struct is_pair<std::pair<T...>> : std::true_type {};

} // namespace bits

} // namespace frozen
Expand Down
Loading