chocolacula/easy_reflection_cpp

Sweep: create stack allocator class

chocolacula opened this issue · 1 comments

Details

Feature: create a new class in library/include/er/ with name StackAlloc which implements C++ 17 allocator. It should have additional template parameter size with type size_t which means size of bytes preallocated on stack. If T has sizeof > size the memory will allocate on the heap, else on stack.

Checklist
  • library/include/er/stack_alloc.h ✅ Commit 37ab61b

Here's the PR! #16.

⚡ Sweep Free Trial: I'm creating this ticket using GPT-4. You have 4 GPT-4 tickets left for the month and 2 for the day. For more GPT-4 tickets, visit our payment portal.

Actions (click)

  • ↻ Restart Sweep

Step 1: 🔎 Searching

I found the following snippets in your repository. I will now analyze these snippets and come up with a plan.

Some code snippets I looked at (click to expand). If some file is missing from here, you can mention the path in the ticket description.

#pragma once
#include <stack>
#include "../err_helper.h"
#include "er/reflection/type_name.h"
#include "istack.h"
#include "stack_iterator.h"
namespace er {
template <typename T>
struct StdStack : public IStack, public sequence::ErrHelper {
StdStack() = delete;
StdStack(std::stack<T>* stack, bool is_const)
: _stack(stack), //
_is_const(is_const) {
}
Expected<None> assign(Var var) override {
auto t = TypeId::get(_stack);
if (var.type() != t) {
return Error(format("Cannot assign type: {} to {}", //
reflection::type_name(var.type()), //
reflection::type_name(t)));
}
_stack = static_cast<std::stack<T>*>(const_cast<void*>(var.raw()));
_is_const = var.is_const();
return None();
}
void unsafe_assign(void* ptr) override {
_stack = static_cast<std::stack<T>*>(ptr);
_is_const = false;
}
Var own_var() const override {
return Var(_stack, TypeId::get(_stack), _is_const);
}
TypeId nested_type() const override {
return TypeId::get<T>();
}
void for_each(std::function<void(Var)> callback) const override {
const auto nested_type = TypeId::get<T>();
const auto end = StackIterator<T>::end(_stack);
for (auto it = StackIterator<T>::begin(_stack); it != end; ++it) {
callback(Var(&(*it), nested_type, true));
}
}
void for_each(std::function<void(Var)> callback) override {
const auto nested_type = TypeId::get<T>();
const auto end = StackIterator<T>::end(_stack);
for (auto it = StackIterator<T>::begin(_stack); it != end; ++it) {
callback(Var(&(*it), nested_type, _is_const));
}
}
void unsafe_for_each(std::function<void(void*)> callback) const override {
for (auto it = StackIterator<T>::begin(_stack); it != StackIterator<T>::end(_stack); ++it) {
callback(&(*it));
}
}
void clear() override {
while (!_stack->empty()) {
_stack->pop();
}
}
size_t size() const override {
return _stack->size();
}
Expected<None> push(Var value) override {
auto nested_type = TypeId::get<T>();
if (nested_type != value.type()) {
return error("Trying to set with type: {} to set<{}>", //
value.type(), nested_type);
}
_stack->push(*static_cast<const T*>(value.raw()));
return None();
}
void pop() override {
_stack->pop();
}
Expected<Var> top() override {
if (_stack->empty()) {
return Error("The stack is empty");
}
return Var(&_stack->top(), TypeId::get<T>(), _is_const);
};
private:
std::stack<T>* _stack;
bool _is_const;
};

#pragma once
#include "var.h"
namespace er {
struct Box {
Box(const Box& other) = delete;
Box& operator=(const Box& other) = delete;
Box() = default;
Box(Box&& other) noexcept = default;
Box& operator=(Box&& other) noexcept = default;
explicit Box(TypeId id);
~Box();
Var var();
Box clone();
bool uses_heap() const;
private:
TypeId _type;
bool _optimized;
// max size of stack memory for dynamic allocation optimization
static const size_t kMemSize = sizeof(std::unordered_map<int, int>);
union Data {
void* ptr;
char stack_mem[kMemSize];
} _data;
};


Step 2: ⌨️ Coding

  • library/include/er/stack_alloc.h ✅ Commit 37ab61b
• Begin by including the necessary headers. This will likely include `` for the allocator, `` for placement new, and `` for `std::max`.
• Declare the `StackAlloc` class within the `er` namespace. It should be a template class with two parameters: `T` and `size`.
• The `StackAlloc` class should have the following public types, as required by the Allocator concept: `value_type`, `pointer`, `const_pointer`, `reference`, `const_reference`, `size_type`, and `difference_type`.
• Implement the `allocate` function. This function should check if the size of `T` is greater than `size`. If it is, it should use `::operator new` to allocate memory on the heap. Otherwise, it should use placement new to allocate memory on the stack.
• Implement the `deallocate` function. This function should check if the pointer passed to it points to the stack or the heap, and use the appropriate delete operator.
• Implement the `construct` and `destroy` functions. These functions should use placement new and explicit destructor invocation, respectively.
• Implement the `max_size` function. This function should return the maximum number of objects that can be allocated by the allocator.
• Implement the `address` function. This function should return the address of an object.
• Implement the `StackAlloc` copy constructor and copy assignment operator. These should be trivial, as the `StackAlloc` class does not own any resources.
• Implement the `StackAlloc` move constructor and move assignment operator. These should also be trivial, as the `StackAlloc` class does not own any resources.
• Implement the `StackAlloc` destructor. This should also be trivial, as the `StackAlloc` class does not own any resources.

Step 3: 🔁 Code Review

I have finished reviewing the code for completeness. I did not find errors for sweep/stack_alloc_class.

.


🎉 Latest improvements to Sweep:

  • Sweep can now passively improve your repository! Check out Rules to learn more.

💡 To recreate the pull request edit the issue title or description. To tweak the pull request, leave a comment on the pull request.
Join Our Discord