blob: 6d020a0512a3444de030cb63d024b6c0124fef5b [file] [log] [blame]
#ifndef JSON5EncoderCpp_StackHeapString
#define JSON5EncoderCpp_StackHeapString
#include <cstdint>
#include <cstring>
#include <Python.h>
namespace JSON5EncoderCpp {
inline namespace {
static constexpr Py_ssize_t StackHeapStringStackSize = 64;
static constexpr Py_ssize_t StackHeapStringHeapSize = 256;
static constexpr Py_ssize_t StackHeapStringHeapFactor = 4;
template <class T>
class StackHeapString {
StackHeapString(const StackHeapString&) = delete;
StackHeapString(StackHeapString&&) = delete;
StackHeapString &operator =(const StackHeapString&) = delete;
StackHeapString &operator =(StackHeapString&&) = delete;
public:
StackHeapString() = default;
~StackHeapString() {
if (m_heap != nullptr) {
PyMem_RawFree(m_heap);
}
}
const T *data() const& {
if (JSON5EncoderCpp_expect(m_heap == nullptr, true)) {
return m_stack;
} else {
return m_heap;
}
}
Py_ssize_t size() const& {
return m_size;
}
bool push_back(T c) {
if (JSON5EncoderCpp_expect(m_left == 0, false)) {
if (m_heap == nullptr) {
void *new_ptr = PyMem_RawMalloc(sizeof(T) * StackHeapStringHeapSize);
if (new_ptr == nullptr) {
PyErr_NoMemory();
return false;
}
m_heap = reinterpret_cast<T*>(new_ptr);
m_left = StackHeapStringHeapSize - StackHeapStringStackSize;
std::memcpy(m_heap, m_stack, sizeof(T) * StackHeapStringStackSize);
} else {
void *new_ptr = PyMem_RawRealloc(m_heap, sizeof(T) * (m_size * StackHeapStringHeapFactor));
if (new_ptr == nullptr) {
PyErr_NoMemory();
return false;
}
m_heap = reinterpret_cast<T*>(new_ptr);
m_left = m_size * (StackHeapStringHeapFactor - 1);
}
}
if (JSON5EncoderCpp_expect(m_heap == nullptr, true)) {
m_stack[m_size] = c;
} else {
m_heap[m_size] = c;
}
++m_size;
--m_left;
return true;
}
private:
Py_ssize_t m_size = 0;
Py_ssize_t m_left = StackHeapStringStackSize;
T *m_heap = nullptr;
T m_stack[StackHeapStringStackSize];
};
}
}
#endif // ifndef JSON5EncoderCpp_StackHeapString