Skip to content

Commit

Permalink
Use default init allocator for vectors
Browse files Browse the repository at this point in the history
This speeds up our case as we don't need to zero the memory first.
  • Loading branch information
willmmiles committed Feb 15, 2024
1 parent 09a4797 commit 9550a53
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/WebResponseImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#undef max
#endif
#include <vector>
#include "default_init_allocator.h"
// It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max.

class AsyncBasicResponse: public AsyncWebServerResponse {
Expand All @@ -46,7 +47,7 @@ class AsyncAbstractResponse: public AsyncWebServerResponse {
// This is inefficient with vector, but if we use some other container,
// we won't be able to access it as contiguous array of bytes when reading from it,
// so by gaining performance in one place, we'll lose it in another.
std::vector<uint8_t> _packet, _cache;
std::vector<uint8_t, default_init_allocator<uint8_t>> _packet, _cache;
size_t _readDataFromCacheOrContent(uint8_t* data, const size_t len);
size_t _fillBufferAndProcessTemplates(uint8_t* buf, size_t maxLen);
protected:
Expand Down
34 changes: 34 additions & 0 deletions src/default_init_allocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

// A C++ allocator that default-initializes objects
// This principally useful for vectors of POD types, where default allocation is a no-op; so the vector can be resized "for free".
//
// Code shamelessly stolen from https://stackoverflow.com/a/21028912/8715474

#include <memory>

template <typename T, typename A = std::allocator<T>>
class default_init_allocator : public A {
typedef std::allocator_traits<A> a_t;
public:
// http://en.cppreference.com/w/cpp/language/using_declaration
using A::A; // Inherit constructors from A

template <typename U> struct rebind {
using other =
default_init_allocator
< U, typename a_t::template rebind_alloc<U> >;
};

template <typename U>
void construct(U* ptr)
noexcept(std::is_nothrow_default_constructible<U>::value) {
::new(static_cast<void*>(ptr)) U;
}

template <typename U, typename...Args>
void construct(U* ptr, Args&&... args) {
a_t::construct(static_cast<A&>(*this),
ptr, std::forward<Args>(args)...);
}
};

0 comments on commit 9550a53

Please sign in to comment.