aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2024-09-28 11:06:36 -0400
committerClyne Sullivan <clyne@bitgloo.com>2024-09-28 11:06:36 -0400
commitb480537a274ed15d71a59f5babf194a651c78910 (patch)
treee353fb85424e6c677f985e70956074b023fcffc4
parentfffe9352660f5fa672be0b50e13b657e10ce975f (diff)
keyboard input buffering
-rw-r--r--Makefile4
-rw-r--r--circularbuffer.hpp573
-rw-r--r--kernel.cpp47
-rw-r--r--keyboard.cpp44
-rw-r--r--keyboard.hpp25
-rw-r--r--memory.cpp9
-rw-r--r--memory.hpp31
7 files changed, 681 insertions, 52 deletions
diff --git a/Makefile b/Makefile
index f3674a6..0480943 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-CXXFLAGS := -m32 -ggdb -g3 -O0 -fno-pic -ffreestanding -fno-rtti -fno-exceptions -std=c++23
-LDFLAGS := -m32 -static -T link.ld -ffreestanding -nostdlib
+CXXFLAGS := -m32 -ggdb -g3 -O0 -fno-pic -fno-rtti -fno-exceptions -std=c++23
+LDFLAGS := $(CXXFLAGS) -T link.ld -static -nostdlib -fno-use-cxa-atexit
CXXFILES := acpi.cpp \
boot.cpp \
diff --git a/circularbuffer.hpp b/circularbuffer.hpp
new file mode 100644
index 0000000..64a9e48
--- /dev/null
+++ b/circularbuffer.hpp
@@ -0,0 +1,573 @@
+/*
+MIT License
+
+Copyright (c) 2020 Vinit James
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef CIRCULAR_BUFFER_H
+#define CIRCULAR_BUFFER_H
+
+#include <algorithm>
+#include <iterator>
+#include <mutex>
+#include <memory>
+#include <stdexcept>
+#include <utility>
+
+
+template<typename T>
+class CircularBuffer {
+private:
+
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ template <bool isConst> struct BufferIterator;
+
+
+public:
+ typedef T value_type;
+
+ // clyne
+ constexpr CircularBuffer()
+ :_buff{}, _max_size{0} {}
+
+ explicit CircularBuffer(size_t size)
+ :_buff{std::unique_ptr<T[]>(new value_type[size])}, _max_size{size}{}
+
+ CircularBuffer(const CircularBuffer& other)
+ :_buff{std::unique_ptr<T[]>(new value_type[other._max_size])},
+ _max_size{other._max_size},
+ _size{other._size},
+ _head{other._head},
+ _tail{other._tail}{
+ std::copy(other.data(), other.data() + _max_size, _buff.get());
+ }
+
+
+ CircularBuffer& operator=(const CircularBuffer& other){
+ if ( this != &other){
+ _buff.reset(new value_type[other._max_size]);
+ _max_size = other._max_size;
+ _size = other._size;
+ _head = other._head;
+ _tail = other._tail;
+ std::copy(other.data(), other.data() + _max_size, _buff.get());
+ }
+ return *this;
+ }
+
+ CircularBuffer(CircularBuffer&& other) noexcept
+ :_buff{std::move(other._buff)},
+ _max_size{other._max_size},
+ _size{other._size},
+ _head{other._head},
+ _tail{other._tail}{
+
+ other._buff = nullptr;
+ other._max_size = 0;
+ other._size = 0;
+ other._head = 0;
+ other._tail = 0;
+ }
+
+
+ CircularBuffer& operator=(CircularBuffer&& other) noexcept{
+ if ( this != &other){
+ _buff = std::move(other._buff);
+ _max_size = other._max_size;
+ _size = other._size;
+ _head = other._head;
+ _tail = other._tail;
+
+ other._buff = nullptr;
+ other._max_size = 0;
+ other._size = 0;
+ other._head = 0;
+ other._tail = 0;
+ }
+ return *this;
+ }
+
+ void push_back(const value_type& data);
+ void push_back(value_type&& data) noexcept;
+ void pop_front();
+ reference front();
+ reference back();
+ const_reference front() const;
+ const_reference back() const;
+ void clear();
+ bool empty() const ;
+ bool full() const ;
+ size_type capacity() const ;
+ size_type size() const;
+ size_type buffer_size() const {return sizeof(value_type)*_max_size;};
+ const_pointer data() const { return _buff.get(); }
+
+ const_reference operator[](size_type index) const;
+ reference operator[](size_type index);
+ const_reference at(size_type index) const;
+ reference at(size_type index);
+
+ typedef BufferIterator<false> iterator;
+ typedef BufferIterator<true> const_iterator;
+
+ iterator begin();
+ const_iterator begin() const;
+ iterator end();
+ const_iterator end() const;
+ const_iterator cbegin() const noexcept;
+ const_iterator cend() const noexcept;
+ iterator rbegin() noexcept;
+ const_iterator rbegin() const noexcept;
+ iterator rend() noexcept;
+ const_iterator rend() const noexcept;
+
+
+private:
+ void _increment_bufferstate();
+ void _decrement_bufferstate();
+ // clyne
+ //mutable std::mutex _mtx;
+ std::unique_ptr<value_type[]> _buff;
+ size_type _head = 0;
+ size_type _tail = 0;
+ size_type _size = 0;
+ size_type _max_size = 0;
+
+ template<bool isConst = false>
+ struct BufferIterator{
+ public:
+ friend class CircularBuffer<T>;
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef typename std::conditional<isConst, const value_type&, value_type&>::type reference;
+ typedef typename std::conditional<isConst, const value_type*, value_type*>::type pointer;
+ typedef typename std::conditional<isConst, const CircularBuffer<value_type>*,
+ CircularBuffer<value_type>*>::type cbuf_pointer;
+ private:
+ cbuf_pointer _ptrToBuffer;
+ size_type _offset;
+ size_type _index;
+ bool _reverse;
+
+ bool _comparable(const BufferIterator<isConst>& other) const{
+ return (_ptrToBuffer == other._ptrToBuffer)&&(_reverse == other._reverse);
+ }
+
+ public:
+ BufferIterator()
+ :_ptrToBuffer{nullptr}, _offset{0}, _index{0}, _reverse{false}{}
+
+ BufferIterator(const BufferIterator<false>& it)
+ :_ptrToBuffer{it._ptrToBuffer},
+ _offset{it._offset},
+ _index{it._index},
+ _reverse{it._reverse}{}
+
+ reference operator*(){
+ if(_reverse)
+ return (*_ptrToBuffer)[(_ptrToBuffer->size() - _index - 1)];
+ return (*_ptrToBuffer)[_index];
+ }
+
+ pointer operator->() { return &(operator*()); }
+
+ reference operator[](size_type index){
+ BufferIterator iter = *this;
+ iter._index += index;
+ return *iter;
+ }
+
+ BufferIterator& operator++(){
+ ++_index;
+ return *this;
+ }
+
+ BufferIterator operator++(int){
+ BufferIterator iter = *this;
+ ++_index;
+ return iter;
+ }
+
+ BufferIterator& operator--(){
+ --_index;
+ return *this;
+ }
+
+ BufferIterator operator--(int){
+ BufferIterator iter = *this;
+ --_index;
+ return iter;
+ }
+
+ friend BufferIterator operator+(BufferIterator lhsiter, difference_type n){
+ lhsiter._index += n;
+ return lhsiter;
+ }
+
+ friend BufferIterator operator+(difference_type n, BufferIterator rhsiter){
+ rhsiter._index += n;
+ return rhsiter;
+ }
+
+
+ BufferIterator& operator+=(difference_type n){
+ _index += n;
+ return *this;
+ }
+
+ friend BufferIterator operator-(BufferIterator lhsiter, difference_type n){
+ lhsiter._index -= n;
+ return lhsiter;
+ }
+
+ friend difference_type operator-(const BufferIterator& lhsiter, const BufferIterator& rhsiter){
+
+ return lhsiter._index - rhsiter._index;
+ }
+
+ BufferIterator& operator-=(difference_type n){
+ _index -= n;
+ return *this;
+ }
+
+ bool operator==(const BufferIterator& other) const{
+ if (!_comparable(other))
+ return false;
+ return ((_index == other._index)&&(_offset == other._offset));
+ }
+
+ bool operator!=(const BufferIterator& other) const{
+ if (!_comparable(other))
+ return true;
+ return ((_index != other._index)||(_offset != other._offset));
+ }
+
+ bool operator<(const BufferIterator& other) const {
+ if (!_comparable(other))
+ return false;
+ return ((_index + _offset)<(other._index+other._offset));
+ }
+
+ bool operator>(const BufferIterator& other) const{
+ if (!_comparable(other))
+ return false;
+ return ((_index + _offset)>(other._index+other._offset));
+ }
+
+ bool operator<=(const BufferIterator& other) const {
+ if (!_comparable(other))
+ return false;
+ return ((_index + _offset)<=(other._index+other._offset));
+ }
+
+ bool operator>=(const BufferIterator& other) const {
+ if (!_comparable(other))
+ return false;
+ return ((_index + _offset)>=(other._index+other._offset));
+ }
+ };
+};
+
+template<typename T>
+inline
+bool CircularBuffer<T>::full() const{
+ return _size == _max_size;
+}
+
+template<typename T>
+inline
+bool CircularBuffer<T>::empty() const{
+ return _size == 0;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::size_type CircularBuffer<T>::capacity() const{
+ return _max_size;
+}
+
+template<typename T>
+inline
+void CircularBuffer<T>::clear(){
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ _head = _tail = _size = 0;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::size_type CircularBuffer<T>::size() const{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ return _size;
+ }
+
+template<typename T>
+inline
+typename CircularBuffer<T>::reference CircularBuffer<T>::front() {
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ // clyne
+ if(empty())
+ abort(); //throw std::length_error("front function called on empty buffer");
+ return _buff[_tail];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::reference CircularBuffer<T>::back() {
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ if(empty())
+ abort(); //throw std::length_error("back function called on empty buffer");
+ return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_reference CircularBuffer<T>::front() const{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ if(empty())
+ abort(); //throw std::length_error("front function called on empty buffer");
+ return _buff[_tail];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_reference CircularBuffer<T>::back() const{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ if(empty())
+ abort(); //throw std::length_error("back function called on empty buffer");
+ return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1];
+}
+
+template<typename T>
+inline
+void CircularBuffer<T>::push_back(const T& data){
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ //if(full())
+ // _buff[_tail].~T();
+ _buff[_head] = data;
+ _increment_bufferstate();
+}
+
+template<typename T>
+inline
+void CircularBuffer<T>::push_back(T&& data) noexcept{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ _buff[_head] = std::move(data);
+ _increment_bufferstate();
+}
+
+
+template<typename T>
+inline
+void CircularBuffer<T>::_increment_bufferstate(){
+ if(full())
+ _tail = (_tail + 1)%_max_size;
+ else
+ ++_size;
+ _head = (_head + 1)%_max_size;
+}
+
+template<typename T>
+inline
+void CircularBuffer<T>::pop_front(){
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ if(empty())
+ abort(); //throw std::length_error("pop_front called on empty buffer");
+ _decrement_bufferstate();
+}
+
+template<typename T>
+inline
+void CircularBuffer<T>::_decrement_bufferstate(){
+ --_size;
+ _tail = (_tail + 1)%_max_size;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::reference CircularBuffer<T>::operator[](size_t index) {
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ if((index<0)||(index>=_size))
+ abort(); //throw std::out_of_range("Index is out of Range of buffer size");
+ index += _tail;
+ index %= _max_size;
+ return _buff[index];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_reference CircularBuffer<T>::operator[](size_t index) const {
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ if((index<0)||(index>=_size))
+ abort(); //throw std::out_of_range("Index is out of Range of buffer size");
+ index += _tail;
+ index %= _max_size;
+ return _buff[index];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::reference CircularBuffer<T>::at(size_t index) {
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ if((index<0)||(index>=_size))
+ abort(); //throw std::out_of_range("Index is out of Range of buffer size");
+ index += _tail;
+ index %= _max_size;
+ return _buff[index];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_reference CircularBuffer<T>::at(size_t index) const {
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ if((index<0)||(index>=_size))
+ abort(); //throw std::out_of_range("Index is out of Range of buffer size");
+ index += _tail;
+ index %= _max_size;
+ return _buff[index];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::iterator CircularBuffer<T>::begin() {
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = 0;
+ iter._reverse = false;
+ return iter;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::begin() const{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ const_iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = 0;
+ iter._reverse = false;
+ return iter;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::iterator CircularBuffer<T>::end() {
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = _size;
+ iter._reverse = false;
+ return iter;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::end() const{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ const_iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = _size;
+ iter._reverse = false;
+ return iter;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::cbegin() const noexcept{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ const_iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = 0;
+ iter._reverse = false;
+ return iter;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::cend() const noexcept{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ const_iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = _size;
+ iter._reverse = false;
+ return iter;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::iterator CircularBuffer<T>::rbegin() noexcept{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = 0;
+ iter._reverse = true;
+ return iter;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::rbegin() const noexcept{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ const_iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = 0;
+ iter._reverse = true;
+ return iter;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::iterator CircularBuffer<T>::rend() noexcept{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = _size;
+ iter._reverse = true;
+ return iter;
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::rend() const noexcept{
+ //std::lock_guard<std::mutex> _lck(_mtx);
+ const_iterator iter;
+ iter._ptrToBuffer = this;
+ iter._offset = _tail;
+ iter._index = _size;
+ iter._reverse = true;
+ return iter;
+}
+
+#endif /* CIRCULAR_BUFFER_H */
diff --git a/kernel.cpp b/kernel.cpp
index 26d5b7d..408a19e 100644
--- a/kernel.cpp
+++ b/kernel.cpp
@@ -40,35 +40,28 @@ void kernel_main(void)
tasking_initialize();
term.write("Tasking enabled.\n");
- //tasking_spawn([] {
- // for (;;) {
- // do pit_delay_ms(1);
- // while (termBusy);
-
- // termBusy = true;
- // term.write('B');
- // termBusy = false;
- // }
- //}, 256);
-
- //tasking_spawn([] {
- // for (;;) {
- // do pit_delay_ms(1);
- // while (termBusy);
-
- // termBusy = true;
- // term.write('C');
- // termBusy = false;
- // }
- //}, 256);
-
for (;;) {
- pit_delay_ms(100);
- //while (termBusy);
+ const auto ch = keyboard_read();
+ if (ch)
+ term.write(*ch);
- //termBusy = true;
- //term.write('A');
- //termBusy = false;
+ pit_delay_ms(10);
}
}
+extern "C"
+void abort()
+{
+ term.write("!!! abort() called !!!");
+ asm volatile("cli");
+ for (;;);
+}
+
+extern "C"
+int __cxa_atexit(void (*func)(void *), void *arg, void *dso_handle)
+{
+ return 0;
+}
+
+int __dso_handle = 0;
+
diff --git a/keyboard.cpp b/keyboard.cpp
index 18d7acd..29178f9 100644
--- a/keyboard.cpp
+++ b/keyboard.cpp
@@ -1,33 +1,16 @@
+#include "circularbuffer.hpp"
#include "idt.hpp"
+#include "keyboard.hpp"
#include "portio.hpp"
#include "vgaterminal.hpp"
#include <array>
#include <cstdint>
-#define K_CONTROL_L -1
-#define K_SHIFT_L -2
-#define K_ALT_L -3
-#define K_CAPS -4
-#define K_NUM -5
-#define K_SCROLL -6
-#define K_SHIFT_R -7
-#define K_ESCAPE -8
-#define K_F1 -10
-#define K_F2 -11
-#define K_F3 -12
-#define K_F4 -13
-#define K_F5 -14
-#define K_F6 -15
-#define K_F7 -16
-#define K_F8 -17
-#define K_F9 -18
-#define K_F10 -19
-#define K_F11 -20
-#define K_F12 -21
-
extern TextOutput& term;
+static CircularBuffer<char> keyboardBuffer;
+
static const std::array<char, 0x59> ScanCodeSet1 {{
0, K_ESCAPE,
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
@@ -52,14 +35,29 @@ static constexpr auto keycode(auto ch) {
void keyboard_initialize()
{
+ keyboardBuffer = CircularBuffer<char>(128);
+
idt_register_callback(33, [](auto& regs) {
const auto kc = inb(0x60);
if (!isReleased(kc)) {
const auto ch = ScanCodeSet1[keycode(kc)];
- if (ch > 0)
- term.write(ch);
+ //if (ch > 0)
+ // term.write(ch);
+
+ keyboardBuffer.push_back(ch);
}
});
}
+std::optional<char> keyboard_read()
+{
+ if (keyboardBuffer.empty()) {
+ return {};
+ } else {
+ const auto ch = keyboardBuffer.front();
+ keyboardBuffer.pop_front();
+ return ch;
+ }
+}
+
diff --git a/keyboard.hpp b/keyboard.hpp
index 40b57c9..694ff89 100644
--- a/keyboard.hpp
+++ b/keyboard.hpp
@@ -1,7 +1,32 @@
#ifndef KEYBOARD_HPP
#define KEYBOARD_HPP
+#include <optional>
+
+#define K_CONTROL_L -1
+#define K_SHIFT_L -2
+#define K_ALT_L -3
+#define K_CAPS -4
+#define K_NUM -5
+#define K_SCROLL -6
+#define K_SHIFT_R -7
+#define K_ESCAPE -8
+#define K_F1 -10
+#define K_F2 -11
+#define K_F3 -12
+#define K_F4 -13
+#define K_F5 -14
+#define K_F6 -15
+#define K_F7 -16
+#define K_F8 -17
+#define K_F9 -18
+#define K_F10 -19
+#define K_F11 -20
+#define K_F12 -21
+
void keyboard_initialize();
+std::optional<char> keyboard_read();
+
#endif // KEYBOARD_HPP
diff --git a/memory.cpp b/memory.cpp
index 2cc15be..59e2bbe 100644
--- a/memory.cpp
+++ b/memory.cpp
@@ -85,3 +85,12 @@ void *operator new[](std::size_t size)
return memory_alloc(size);
}
+void operator delete(void *ptr)
+{
+
+}
+
+void operator delete[](void *ptr)
+{
+
+}
diff --git a/memory.hpp b/memory.hpp
index 8955262..0467bf6 100644
--- a/memory.hpp
+++ b/memory.hpp
@@ -1,6 +1,37 @@
#ifndef MEMORY_HPP
#define MEMORY_HPP
+#include <cstddef>
+#include <type_traits>
+
+template<typename T>
+struct kallocator
+{
+ using value_type = T;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using propagate_on_container_move_assignment = std::true_type;
+ using is_always_equal = std::true_type;
+
+ template<class U>
+ struct rebind {
+ typedef kallocator<U> other;
+ };
+
+ kallocator() = default;
+
+ template<typename U>
+ kallocator(const kallocator<U>&) noexcept {}
+
+ T* allocate(std::size_t n) {
+ return new T[n];
+ }
+
+ void deallocate([[maybe_unused]] T* p, [[maybe_unused]] std::size_t n) {
+
+ }
+};
+
void memory_initialize();
#endif // MEMORY_HPP