Skip to content

Commit

Permalink
Intermediate changes
Browse files Browse the repository at this point in the history
  • Loading branch information
akukh committed Jul 25, 2024
1 parent 65fe6be commit b73f3ac
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 8 deletions.
6 changes: 6 additions & 0 deletions flux-config/flux/config/features.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
# define FLUX_NO_SANITIZE(...)
#endif

#if __has_attribute(__no_sanitize__)
# define FLUX_NO_CFI __attribute__((__no_sanitize__("cfi")))
#else
# define FLUX_NO_CFI /* nothing */
#endif

#if __has_cpp_attribute(__gnu__::__always_inline__)
# define FLUX_ALWAYS_INLINE [[__gnu__::__always_inline__]]
#elif __has_cpp_attribute(clang::always_inline)
Expand Down
37 changes: 37 additions & 0 deletions flux-foundation/flux/foundation/containers/detail/temp_value.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

namespace flux::fou::detail {

// clang-format off
template <typename T, typename Allocator>
struct temp_value final {
using allocator_traits = allocator_traits<Allocator>;

union {
T value;
};
Allocator& allocator;

template <typename... Args>
FLUX_NO_CFI constexpr explicit temp_value(Allocator& alloc, Args&&... args) noexcept
: allocator(alloc) {
construct_at(addressof(value), ::std::forward<Args>(args)...);
}

temp_value(temp_value const&) = delete;
temp_value& operator=(temp_value const&) = delete;

constexpr ~temp_value() requires meta::trivially_destructible<T> = default;
constexpr ~temp_value() { destroy_at(addressof(value)); }

constexpr T& get() noexcept {
return value;
}

constexpr T const& get() const noexcept {
return value;
}
};
// clang-format on

} // namespace flux::fou::detail
104 changes: 96 additions & 8 deletions flux-foundation/flux/foundation/containers/vector.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

Check notice on line 1 in flux-foundation/flux/foundation/containers/vector.hpp

View workflow job for this annotation

GitHub Actions / lint

Run clang-format on flux-foundation/flux/foundation/containers/vector.hpp

File flux-foundation/flux/foundation/containers/vector.hpp does not conform to Custom style guidelines. (lines 82, 221, 223)

#include <flux/foundation/containers/detail/temp_value.hpp>

// TODO:
// * Implement wrap_iter for vector;
// * Implement rebind for std_allocator_adapter, so it can be fully compatible;
Expand Down Expand Up @@ -53,7 +55,7 @@ class [[nodiscard, clang::trivial_abi]] vector final {

public:
using value_type = T;
using allocator_type = default_allocator_type;
using allocator_type = Allocator;
using size_type = typename allocator_traits::size_type;
using difference_type = typename allocator_traits::difference_type;
using pointer = T*;
Expand All @@ -76,7 +78,9 @@ class [[nodiscard, clang::trivial_abi]] vector final {
FLUX_NO_UNIQUE_ADDRESS pointer end_cap_ = {};
FLUX_NO_UNIQUE_ADDRESS allocator_type allocator_ = {};

constexpr vector() noexcept {}
constexpr vector() noexcept {
// Do nothing.
}

constexpr explicit vector(size_type count) noexcept {
if (count > 0) {
Expand Down Expand Up @@ -156,7 +160,7 @@ class [[nodiscard, clang::trivial_abi]] vector final {
} else { // Just clear the vector if we have enough capacity.
clear();
}

// Re-assign the vector with new values.
end_ = ranges::uninitialized_fill_n(end_, difference_type(count), value);
}
// constexpr void assign(::std::initializer_list<T> list) noexcept {
Expand Down Expand Up @@ -199,6 +203,29 @@ class [[nodiscard, clang::trivial_abi]] vector final {
resize(count, value_type{});
}

template <typename... Args>
constexpr iterator emplace(const_iterator position, Args&&... args) noexcept {
pointer whereptr = begin_ + (position - begin());
if (end_ < end_cap_) {
if (whereptr == end_) {
construct_one_at_end(::std::forward<Args>(args)...);
} else {
move_elements(/* from: */ whereptr, /* by: */ 1);
construct_in_place(whereptr, ::std::forward<Args>(args)...);
}

return iterator{whereptr};
}

return iterator{emplace_reallocate(whereptr, ::std::forward<Args>(args)...)};
}

template <typename... Args>
constexpr reference emplace_back(Args&&... args) noexcept {
FLUX_ASSERT(size() < capacity(), "emplace_back(args...) called on a full static_vector");
return construct_one_at_end(::std::forward<Args>(args)...);
}

// Capacity
[[nodiscard]] static constexpr size_type max_size() noexcept {
return static_cast<size_type>(::std::numeric_limits<difference_type>::max());
Expand Down Expand Up @@ -323,13 +350,13 @@ class [[nodiscard, clang::trivial_abi]] vector final {

constexpr void vreallocate(size_type capacity) noexcept {
FLUX_ASSERT(capacity != 0, "vreallocate(capacity) called with zero capacity");
// clang-format off
auto old_begin = begin_;
auto old_end = end_;

[[maybe_unused]] auto old_capacity = static_cast<size_type>(end_cap_ - begin_);
[[maybe_unused]] auto old_size = static_cast<size_type>(end_ - begin_);
[[maybe_unused]] auto const old_capacity = static_cast<size_type>(end_cap_ - begin_);
[[maybe_unused]] auto const old_size = static_cast<size_type>(end_ - begin_);

// clang-format off
auto [new_begin, new_capacity] = allocate_at_least(allocator_, capacity);
pointer new_end;
if constexpr (meta::relocatable<T>) {
Expand All @@ -343,13 +370,53 @@ class [[nodiscard, clang::trivial_abi]] vector final {
new_end = ranges::uninitialized_copy_no_overlap(old_begin, old_end, new_begin);
destroy_range(old_begin, old_end);
}
FLUX_ASSERT(new_begin + old_size == new_end,
"vreallocate(capacity) failed to move memory");
// clang-format on
FLUX_ASSERT(new_begin + old_size == new_end, "vreallocate(capacity) failed to move memory");
allocator_traits::deallocate(allocator_, old_begin, old_capacity);
begin_ = new_begin;
end_ = new_end;
end_cap_ = new_begin + new_capacity;
}

template <typename... Args>
constexpr pointer emplace_reallocate(pointer const position, Args&&... args) noexcept {
// Reallocate and insert by perfectly forwarding `args` at `position`.
FLUX_ASSERT(end_ == end_cap_, "emplace_reallocate(position, args) called on a full vector");
auto old_begin = begin_;
auto old_end = end_;
auto const old_size = static_cast<size_type>(end_ - begin_);
auto const position_offset = static_cast<size_type>(position - begin_);

// clang-format off
auto const new_size = old_size + 1;
auto [new_begin, new_capacity] =
allocate_at_least(allocator_, detail::grow_twice(new_size));
// clang-format on
construct_in_place(new_begin + position_offset, ::std::forward<Args>(args)...);

if (position == end_) { // at back, provide strong guarantee
if constexpr (meta::relocatable<T>) {
ranges::uninitialized_relocate_no_overlap(old_begin, old_end, new_begin);
} else if constexpr (meta::sufficiently_move_constructible<T>) {
ranges::uninitialized_move(old_begin, old_end, new_begin);
destroy_range(old_begin, old_end);
} else {
ranges::uninitialized_copy_no_overlap(old_begin, old_end, new_begin);
destroy_range(old_begin, old_end);
}
} else { // provide basic guarantee
// clang-format off
ranges::uninitialized_relocate_no_overlap(old_begin, old_end, new_begin);
ranges::uninitialized_relocate_no_overlap(position , old_end,
new_begin + position_offset + 1);
// clang-format on
}
allocator_traits::deallocate(allocator_, old_begin, capacity());
begin_ = new_begin;
end_ = new_begin + new_size;
end_cap_ = new_begin + new_capacity;

return begin_ + position_offset;
}

constexpr void vdeallocate() noexcept {
Expand Down Expand Up @@ -431,6 +498,27 @@ class [[nodiscard, clang::trivial_abi]] vector final {
constexpr void copy_assign_alloc(vector& other, meta::false_type) noexcept {
(void)other;
}

// clang-format off
template <typename... Args>
constexpr reference construct_one_at_end(Args&&... args) noexcept {
FLUX_ASSERT(end_ != end_cap_, "construct_one_at_end(args) called on a full vector");
construct_in_place(end_, ::std::forward<Args>(args)...);
++end_;
return back();
}

constexpr iterator move_elements(pointer position, meta::integral auto n) noexcept {
auto const elements_to_move = ranges::distance(position, end_);
end_ += static_cast<size_type>(n);

auto first = position;
auto last = ranges::next(first, elements_to_move);
auto result = ranges::next(first, static_cast<difference_type>(n) + elements_to_move);
ranges::uninitialized_relocate_backward(first, last, result);
return first;
}
// clang-format on
};

} // namespace flux::fou

0 comments on commit b73f3ac

Please sign in to comment.