Skip to content

Commit

Permalink
refactor(container): document Linked_Bump_Allocator and Raw_Bump_Vector
Browse files Browse the repository at this point in the history
  • Loading branch information
strager committed Nov 5, 2023
1 parent e0c6e19 commit 580f51d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/quick-lint-js/container/linked-bump-allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Linked_Bump_Allocator final : public Memory_Resource {

~Linked_Bump_Allocator() override;

// Deallocate previously-allocated memory.
void release();

struct Rewind_State {
Expand Down Expand Up @@ -67,6 +68,7 @@ class Linked_Bump_Allocator final : public Memory_Resource {
Rewind_State rewind_;
};

// See rewind().
Rewind_State prepare_for_rewind() {
return Rewind_State{
.chunk_ = this->chunk_,
Expand All @@ -75,21 +77,31 @@ class Linked_Bump_Allocator final : public Memory_Resource {
};
}

// Deallocate all allocations made since the creation of the Rewind_State
// (returned by this->prepare_for_rewind()).
void rewind(Rewind_State&& r);

// Calls this->prepare_for_rewind() immediately then this->rewind() on
// destruction.
[[nodiscard]] Rewind_Guard make_rewind_guard() { return Rewind_Guard(this); }

// Allocate space for an instance of T, then construct T.
template <class T, class... Args>
T* new_object(Args&&... args) {
return new (this->allocate_bytes(sizeof(T), alignof(T)))
T(std::forward<Args>(args)...);
}

// Allocate space for an instance of T, then construct T via copy or move
// construction.
template <class T>
T* new_object_copy(T&& value) {
return this->new_object<T>(std::forward<T>(value));
}

// Allocate space for objects.size() instances of T, then construct result[i]
// via copy or move construction from objects[i] for i from 0 to
// objects.size()-1.
template <class T>
Span<T> new_objects_copy(Span<const T> objects) {
Span<T> new_objects = this->allocate_uninitialized_span<T>(
Expand All @@ -99,6 +111,8 @@ class Linked_Bump_Allocator final : public Memory_Resource {
return new_objects;
}

// Allocate space for object.size() instances of T. Does not construct any
// T-s.
template <class T>
[[nodiscard]] Span<T> allocate_uninitialized_span(std::size_t size) {
std::size_t byte_size = size * sizeof(T);
Expand All @@ -107,11 +121,15 @@ class Linked_Bump_Allocator final : public Memory_Resource {
return Span<T>(items, narrow_cast<Span_Size>(size));
}

// Allocate space for object.size() instances of T, then default-construct
// object.size() instances.
template <class T>
[[nodiscard]] Span<T> allocate_span(Span_Size size) {
return this->allocate_span<T>(narrow_cast<std::size_t>(size));
}

// Allocate space for object.size() instances of T, then default-construct
// object.size() instances.
template <class T>
[[nodiscard]] Span<T> allocate_span(std::size_t size) {
Span<T> items = this->allocate_uninitialized_span<T>(size);
Expand All @@ -123,6 +141,11 @@ class Linked_Bump_Allocator final : public Memory_Resource {
return items;
}

// Given previously-allocated space for old_size instances of T, allocate
// adjacent space for (new_size-old_size) instances of T after the old
// allocation and return true.
//
// If adjacent space is not available, do nothing and return false.
template <class T>
bool try_grow_array_in_place(T* array, std::size_t old_size,
std::size_t new_size) {
Expand All @@ -131,6 +154,7 @@ class Linked_Bump_Allocator final : public Memory_Resource {
new_size * sizeof(T));
}

// For testing only.
std::size_t remaining_bytes_in_current_chunk() const {
return narrow_cast<std::size_t>(this->chunk_end_ - this->next_allocation_);
}
Expand All @@ -149,6 +173,8 @@ class Linked_Bump_Allocator final : public Memory_Resource {
friend class Linked_Bump_Allocator;
};

// In debug modes, cause all allocations to fail with a precondition failure
// until the Disable_Guard is destructed.
[[nodiscard]] Disable_Guard disable() { return Disable_Guard(this); }

protected:
Expand All @@ -165,6 +191,11 @@ class Linked_Bump_Allocator final : public Memory_Resource {

static inline constexpr std::size_t default_chunk_size = 4096 - sizeof(Chunk);

// Given previously-allocated space of old_byte_size bytes, allocate adjacent
// space for (new_byte_size-old_byte_size) bytes after the old allocation and
// return true.
//
// If adjacent space is not available, do nothing and return false.
bool try_grow_array_in_place_impl(char* array, std::size_t old_byte_size,
std::size_t new_byte_size);

Expand Down
31 changes: 31 additions & 0 deletions src/quick-lint-js/container/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ class Uninstrumented_Vector : private Vector {

using Bump_Vector_Size = std::ptrdiff_t;

// Like std::pmr::vector. Some differences:
//
// * No exception safety.
// * Extended interface for convenience.
template <class T>
class Raw_Bump_Vector {
public:
Expand All @@ -108,12 +112,18 @@ class Raw_Bump_Vector {

static_assert(is_winkable_v<T>);

// Create an empty vector.
explicit Raw_Bump_Vector(Linked_Bump_Allocator *allocator)
: allocator_(allocator) {}

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

// Move items from another Raw_Bump_Vector by taking its allocation.
//
// This function does not move individual items.
//
// Postcondition: other.empty()
Raw_Bump_Vector(Raw_Bump_Vector &&other)
: data_(other.data_),
data_end_(other.data_end_),
Expand All @@ -124,8 +134,15 @@ class Raw_Bump_Vector {
other.capacity_end_ = nullptr;
}

// Destruct items in the container, as in this->clear(), then release the
// memory.
//
// If the allocator is a Linked_Bump_Allocator, then memory is only released
// if this Raw_Bump_Vector's capacity is the last thing allocated with that
// allocator.
~Raw_Bump_Vector() { this->clear(); }

// Return the pointer given in Raw_Bump_Vector's constructor.
Linked_Bump_Allocator *get_allocator() const { return this->allocator_; }

bool empty() const { return this->data_ == this->data_end_; }
Expand Down Expand Up @@ -163,18 +180,23 @@ class Raw_Bump_Vector {
return this->data_end_[-1];
}

// Precondition: index is in bounds. This means that '&(*this)[this->size()]'
// (indexing one past the end) is invalid. To get one past the end, call
// this->end() instead or write '&this->data()[this->size()]'.
T &operator[](size_type index) {
QLJS_ASSERT(index < this->size());
return this->data_[index];
}

// Precondition: (none)
void reserve(size_type new_capacity) {
QLJS_ASSERT(new_capacity >= 0);
if (this->capacity() < new_capacity) {
this->reserve_grow(new_capacity);
}
}

// Precondition: new_capacity > this->capacity()
void reserve_grow(size_type new_capacity) {
QLJS_ASSERT(new_capacity > this->capacity());
if (this->data_) {
Expand Down Expand Up @@ -266,6 +288,10 @@ class Raw_Bump_Vector {
return span;
}

// Call the destructor of each item, then deallocate memory used for the
// items.
//
// Postcondition: this->empty()
void clear() {
if (this->data_) {
std::destroy(this->data_, this->data_end_);
Expand All @@ -278,6 +304,10 @@ class Raw_Bump_Vector {
}
}

// If new_size > this->size(): default-construct new items at the end.
// If new_size < this->size(): destruct items at the end.
//
// Postcondition: this->size() == new_size
void resize(size_type new_size) {
size_type old_size = this->size();
if (new_size == old_size) {
Expand Down Expand Up @@ -327,6 +357,7 @@ class Raw_Bump_Vector {
}

private:
// Growth strategy.
void reserve_grow_by_at_least(size_type minimum_new_entries) {
size_type old_capacity = this->capacity();
constexpr size_type minimum_capacity = 4;
Expand Down

0 comments on commit 580f51d

Please sign in to comment.