Mercurial > foo_out_sdl
diff foosdk/sdk/pfc/alloc.h @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/pfc/alloc.h Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,541 @@ +#pragma once + +#include "primitives.h" + +namespace pfc { + + static void * raw_malloc(t_size p_size) { + return p_size > 0 ? new_ptr_check_t(malloc(p_size)) : NULL; + } + + static void raw_free(void * p_block) throw() {free(p_block);} + + inline void* raw_realloc(void * p_ptr,t_size p_size) { + if (p_size == 0) {raw_free(p_ptr); return NULL;} + else if (p_ptr == NULL) return raw_malloc(p_size); + else return pfc::new_ptr_check_t(::realloc(p_ptr,p_size)); + } + + inline bool raw_realloc_inplace(void * p_block,t_size p_size) throw() { + if (p_block == NULL) return p_size == 0; +#ifdef _MSC_VER + if (p_size == 0) return false; + return _expand(p_block,p_size) != NULL; +#else + return false; +#endif + } + + template<typename T> + t_size calc_array_width(t_size p_width) { + return pfc::mul_safe_t<std::bad_alloc,t_size>(p_width,sizeof(T)); + } + + template<typename T> + T * __raw_malloc_t(t_size p_size) { + return reinterpret_cast<T*>(raw_malloc(calc_array_width<T>(p_size))); + } + + template<typename T> + void __raw_free_t(T * p_block) throw() { + raw_free(reinterpret_cast<void*>(p_block)); + } + + template<typename T> + T * __raw_realloc_t(T * p_block,t_size p_size) { + return reinterpret_cast<T*>(raw_realloc(p_block,calc_array_width<T>(p_size))); + } + + template<typename T> + bool __raw_realloc_inplace_t(T * p_block,t_size p_size) { + return raw_realloc_inplace(p_block,calc_array_width<T>(p_size)); + } + + + template<typename t_exception,typename t_int> + inline t_int safe_shift_left_t(t_int p_val,t_size p_shift = 1) { + t_int newval = p_val << p_shift; + if (newval >> p_shift != p_val) throw t_exception(); + return newval; + } + + template<typename t_item> class alloc_dummy { + private: typedef alloc_dummy<t_item> t_self; + public: + alloc_dummy() {} + void set_size(t_size p_size) {throw pfc::exception_not_implemented();} + t_size get_size() const {throw pfc::exception_not_implemented();} + const t_item & operator[](t_size p_index) const {throw pfc::exception_not_implemented();} + t_item & operator[](t_size p_index) {throw pfc::exception_not_implemented();} + + bool is_ptr_owned(const void * p_item) const {return false;} + + //set to true when we prioritize speed over memory usage + enum { alloc_prioritizes_speed = false }; + + //not mandatory + const t_item * get_ptr() const {throw pfc::exception_not_implemented();} + t_item * get_ptr() {throw pfc::exception_not_implemented();} + void prealloc(t_size) {throw pfc::exception_not_implemented();} + void force_reset() {throw pfc::exception_not_implemented();} + void move_from(t_self &) {throw pfc::exception_not_implemented();} + private: + const t_self & operator=(const t_self &) {throw pfc::exception_not_implemented();} + alloc_dummy(const t_self&) {throw pfc::exception_not_implemented();} + }; + + template<typename t_item> + bool is_pointer_in_range(const t_item * p_buffer,t_size p_buffer_size,const void * p_pointer) { + return p_pointer >= reinterpret_cast<const void*>(p_buffer) && p_pointer < reinterpret_cast<const void*>(p_buffer + p_buffer_size); + } + + + //! Simple inefficient fully portable allocator. + template<typename t_item> class alloc_simple { + private: typedef alloc_simple<t_item> t_self; + public: + alloc_simple() : m_data(NULL), m_size(0) {} + void set_size(t_size p_size) { + if (p_size != m_size) { + t_item * l_data = NULL; + if (p_size > 0) l_data = new t_item[p_size]; + try { + pfc::memcpy_t(l_data,m_data,pfc::min_t(m_size,p_size)); + } catch(...) { + delete[] l_data; + throw; + } + delete[] m_data; + m_data = l_data; + m_size = p_size; + } + } + t_size get_size() const {return m_size;} + const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < m_size); return m_data[p_index];} + t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < m_size); return m_data[p_index];} + bool is_ptr_owned(const void * p_item) const {return is_pointer_in_range(get_ptr(),get_size(),p_item);} + + enum { alloc_prioritizes_speed = false }; + + t_item * get_ptr() {return m_data;} + const t_item * get_ptr() const {return m_data;} + + void prealloc(t_size) {} + void force_reset() {set_size(0);} + + ~alloc_simple() {delete[] m_data;} + + void move_from(t_self & other) noexcept { + delete[] m_data; + m_data = replace_null_t(other.m_data); + m_size = replace_null_t(other.m_size); + } + private: + const t_self & operator=(const t_self &) = delete; + alloc_simple(const t_self&) = delete; + + t_item * m_data; + t_size m_size; + }; + + template<typename t_item> class __array_fast_helper_t { + private: + typedef __array_fast_helper_t<t_item> t_self; + public: + __array_fast_helper_t() : m_buffer(NULL), m_size(0), m_size_total(0) {} + + + void set_size(t_size p_size,t_size p_size_total) { + PFC_ASSERT(p_size <= p_size_total); + PFC_ASSERT(m_size <= m_size_total); + if (p_size_total > m_size_total) { + resize_storage(p_size_total); + resize_content(p_size); + } else { + resize_content(p_size); + resize_storage(p_size_total); + } + } + + + + t_size get_size() const {return m_size;} + t_size get_size_total() const {return m_size_total;} + const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < m_size); return m_buffer[p_index];} + t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < m_size); return m_buffer[p_index];} + ~__array_fast_helper_t() { + set_size(0,0); + } + t_item * get_ptr() {return m_buffer;} + const t_item * get_ptr() const {return m_buffer;} + bool is_ptr_owned(const void * p_item) const {return is_pointer_in_range(m_buffer,m_size_total,p_item);} + + void move_from(t_self & other) { + set_size(0,0); + m_buffer = replace_null_t(other.m_buffer); + m_size = replace_null_t(other.m_size); + m_size_total = replace_null_t(other.m_size_total); + } + private: + const t_self & operator=(const t_self &) = delete; + __array_fast_helper_t(const t_self &) = delete; + + + void resize_content(t_size p_size) { + if constexpr (traits_t<t_item>::needs_constructor || traits_t<t_item>::needs_destructor) { + if (p_size > m_size) {//expand + do { + __unsafe__in_place_constructor_t(m_buffer[m_size]); + m_size++; + } while(m_size < p_size); + } else if (p_size < m_size) { + __unsafe__in_place_destructor_array_t(m_buffer + p_size, m_size - p_size); + m_size = p_size; + } + } else { + m_size = p_size; + } + } + + void resize_storage(t_size p_size) { + PFC_ASSERT( m_size <= m_size_total ); + PFC_ASSERT( m_size <= p_size ); + if (m_size_total != p_size) { + if constexpr (pfc::traits_t<t_item>::realloc_safe) { + m_buffer = pfc::__raw_realloc_t(m_buffer,p_size); + m_size_total = p_size; + } else if (__raw_realloc_inplace_t(m_buffer,p_size)) { + //success + m_size_total = p_size; + } else { + t_item * newbuffer = pfc::__raw_malloc_t<t_item>(p_size); + try { + pfc::__unsafe__in_place_constructor_array_copy_t(newbuffer,m_size,m_buffer); + } catch(...) { + pfc::__raw_free_t(newbuffer); + throw; + } + pfc::__unsafe__in_place_destructor_array_t(m_buffer,m_size); + pfc::__raw_free_t(m_buffer); + m_buffer = newbuffer; + m_size_total = p_size; + } + } + } + + t_item * m_buffer; + t_size m_size,m_size_total; + }; + + template<typename t_item> class __array_lite_helper_t { + private: + typedef __array_lite_helper_t<t_item> t_self; + public: + __array_lite_helper_t() : m_buffer(NULL), m_size(0) {} + + + void set_size(t_size p_size) { + if (p_size > m_size) { // expand + resize_storage(p_size); + resize_content(p_size); + } else if (p_size < m_size) { // shrink + resize_content(p_size); + resize_storage(p_size); + } + } + + + + t_size get_size() const {return m_size;} + const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < m_size); return m_buffer[p_index];} + t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < m_size); return m_buffer[p_index];} + ~__array_lite_helper_t() { + set_size(0); + } + t_item * get_ptr() {return m_buffer;} + const t_item * get_ptr() const {return m_buffer;} + bool is_ptr_owned(const void * p_item) const {return is_pointer_in_range(m_buffer,m_size,p_item);} + + void move_from(t_self & other) { + set_size(0); + m_buffer = replace_null_t(other.m_buffer); + m_size = replace_null_t(other.m_size); + } + private: + const t_self & operator=(const t_self &) = delete; + __array_lite_helper_t(const t_self &) = delete; + + + void resize_content(t_size p_size) { + if constexpr (traits_t<t_item>::needs_constructor || traits_t<t_item>::needs_destructor) { + if (p_size > m_size) {//expand + do { + __unsafe__in_place_constructor_t(m_buffer[m_size]); + m_size++; + } while(m_size < p_size); + } else if (p_size < m_size) { + __unsafe__in_place_destructor_array_t(m_buffer + p_size, m_size - p_size); + m_size = p_size; + } + } else { + m_size = p_size; + } + } + + void resize_storage(t_size p_size) { + PFC_ASSERT( m_size <= p_size ); + if constexpr (pfc::traits_t<t_item>::realloc_safe) { + m_buffer = pfc::__raw_realloc_t(m_buffer,p_size); + //m_size_total = p_size; + } else if (__raw_realloc_inplace_t(m_buffer,p_size)) { + //success + //m_size_total = p_size; + } else { + t_item * newbuffer = pfc::__raw_malloc_t<t_item>(p_size); + try { + pfc::__unsafe__in_place_constructor_array_copy_t(newbuffer,m_size,m_buffer); + } catch(...) { + pfc::__raw_free_t(newbuffer); + throw; + } + pfc::__unsafe__in_place_destructor_array_t(m_buffer,m_size); + pfc::__raw_free_t(m_buffer); + m_buffer = newbuffer; + //m_size_total = p_size; + } + } + + t_item * m_buffer; + t_size m_size; + }; + + template<typename t_item> class alloc_standard { + private: typedef alloc_standard<t_item> t_self; + public: + alloc_standard() {} + void set_size(t_size p_size) {m_content.set_size(p_size);} + + t_size get_size() const {return m_content.get_size();} + + const t_item & operator[](t_size p_index) const {return m_content[p_index];} + t_item & operator[](t_size p_index) {return m_content[p_index];} + + const t_item * get_ptr() const {return m_content.get_ptr();} + t_item * get_ptr() {return m_content.get_ptr();} + + bool is_ptr_owned(const void * p_item) const {return m_content.is_ptr_owned(p_item);} + void prealloc(t_size p_size) {} + void force_reset() {set_size(0);} + + enum { alloc_prioritizes_speed = false }; + + void move_from(t_self & other) { m_content.move_from(other.m_content); } + private: + alloc_standard(const t_self &) = delete; + const t_self & operator=(const t_self&) = delete; + + __array_lite_helper_t<t_item> m_content; + }; + + template<typename t_item> class alloc_fast { + private: typedef alloc_fast<t_item> t_self; + public: + alloc_fast() {} + + void set_size(t_size p_size) { + t_size size_base = m_data.get_size_total(); + if (size_base == 0) size_base = 1; + while(size_base < p_size) { + size_base = safe_shift_left_t<std::bad_alloc,t_size>(size_base,1); + } + while(size_base >> 2 > p_size) { + size_base >>= 1; + } + m_data.set_size(p_size,size_base); + } + + t_size get_size() const {return m_data.get_size();} + const t_item & operator[](t_size p_index) const {return m_data[p_index];} + t_item & operator[](t_size p_index) {return m_data[p_index];} + + const t_item * get_ptr() const {return m_data.get_ptr();} + t_item * get_ptr() {return m_data.get_ptr();} + bool is_ptr_owned(const void * p_item) const {return m_data.is_ptr_owned(p_item);} + void prealloc(t_size) {} + void force_reset() {m_data.set_size(0,0);} + + enum { alloc_prioritizes_speed = true }; + + void move_from(t_self & other) { m_data.move_from(other.m_data); } + private: + alloc_fast(const t_self &) = delete; + const t_self & operator=(const t_self&) = delete; + __array_fast_helper_t<t_item> m_data; + }; + + template<typename t_item> class alloc_fast_aggressive { + private: typedef alloc_fast_aggressive<t_item> t_self; + public: + alloc_fast_aggressive() {} + + void set_size(t_size p_size) { + t_size size_base = m_data.get_size_total(); + if (size_base == 0) size_base = 1; + while(size_base < p_size) { + size_base = safe_shift_left_t<std::bad_alloc,t_size>(size_base,1); + } + m_data.set_size(p_size,size_base); + } + + void prealloc(t_size p_size) { + if (p_size > 0) { + t_size size_base = m_data.get_size_total(); + if (size_base == 0) size_base = 1; + while(size_base < p_size) { + size_base = safe_shift_left_t<std::bad_alloc,t_size>(size_base,1); + } + m_data.set_size(m_data.get_size(),size_base); + } + } + + t_size get_size() const {return m_data.get_size();} + const t_item & operator[](t_size p_index) const {;return m_data[p_index];} + t_item & operator[](t_size p_index) {return m_data[p_index];} + + const t_item * get_ptr() const {return m_data.get_ptr();} + t_item * get_ptr() {return m_data.get_ptr();} + bool is_ptr_owned(const void * p_item) const {return m_data.is_ptr_owned(p_item);} + void force_reset() {m_data.set_size(0,0);} + + enum { alloc_prioritizes_speed = true }; + + void move_from(t_self & other) { m_data.move_from(other.m_data); } + private: + alloc_fast_aggressive(const t_self &) = delete; + const t_self & operator=(const t_self&) = delete; + __array_fast_helper_t<t_item> m_data; + }; + + template<t_size p_width> class alloc_fixed { + public: + template<typename t_item> class alloc { + private: typedef alloc<t_item> t_self; + public: + alloc() : m_size(0) {} + + void set_size(t_size p_size) { + static_assert_t<sizeof(m_array) == sizeof(t_item[p_width])>(); + + if (p_size > p_width) throw pfc::exception_overflow(); + else if (p_size > m_size) { + __unsafe__in_place_constructor_array_t(get_ptr()+m_size,p_size-m_size); + m_size = p_size; + } else if (p_size < m_size) { + __unsafe__in_place_destructor_array_t(get_ptr()+p_size,m_size-p_size); + m_size = p_size; + } + } + + ~alloc() { + if constexpr (pfc::traits_t<t_item>::needs_destructor) set_size(0); + } + + t_size get_size() const {return m_size;} + + t_item * get_ptr() {return reinterpret_cast<t_item*>(&m_array);} + const t_item * get_ptr() const {return reinterpret_cast<const t_item*>(&m_array);} + + const t_item & operator[](t_size n) const {return get_ptr()[n];} + t_item & operator[](t_size n) {return get_ptr()[n];} + bool is_ptr_owned(const void * p_item) const {return is_pointer_in_range(get_ptr(),p_width,p_item);} + void prealloc(t_size) {} + void force_reset() {set_size(0);} + + enum { alloc_prioritizes_speed = false }; + + void move_from(t_self & other) { + const size_t count = other.get_size(); + set_size( count ); + for(size_t w = 0; w < count; ++w) this->get_ptr()[w] = other.get_ptr()[w]; + } + private: + alloc(const t_self&) {throw pfc::exception_not_implemented();} + const t_self& operator=(const t_self&) {throw pfc::exception_not_implemented();} + + t_uint8 m_array[sizeof(t_item[p_width])]; + t_size m_size; + }; + }; + + template<t_size p_width, template<typename> class t_alloc = alloc_standard > class alloc_hybrid { + public: + template<typename t_item> class alloc { + private: typedef alloc<t_item> t_self; + public: + alloc() {} + + void set_size(t_size p_size) { + if (p_size > p_width) { + m_fixed.set_size(p_width); + m_variable.set_size(p_size - p_width); + } else { + m_fixed.set_size(p_size); + m_variable.set_size(0); + } + } + + t_item & operator[](t_size p_index) { + PFC_ASSERT(p_index < get_size()); + if (p_index < p_width) return m_fixed[p_index]; + else return m_variable[p_index - p_width]; + } + + const t_item & operator[](t_size p_index) const { + PFC_ASSERT(p_index < get_size()); + if (p_index < p_width) return m_fixed[p_index]; + else return m_variable[p_index - p_width]; + } + + t_size get_size() const {return m_fixed.get_size() + m_variable.get_size();} + bool is_ptr_owned(const void * p_item) const {return m_fixed.is_ptr_owned(p_item) || m_variable.is_ptr_owned(p_item);} + void prealloc(t_size p_size) { + if (p_size > p_width) m_variable.prealloc(p_size - p_width); + } + void force_reset() { + m_fixed.force_reset(); m_variable.force_reset(); + } + enum { alloc_prioritizes_speed = t_alloc<t_item>::alloc_prioritizes_speed }; + + void move_from(t_self & other) { + m_fixed.move_from(other.m_fixed); + m_variable.move_from(other.m_variable); + } + private: + alloc(const t_self&) {throw pfc::exception_not_implemented();} + const t_self& operator=(const t_self&) {throw pfc::exception_not_implemented();} + + typename alloc_fixed<p_width>::template alloc<t_item> m_fixed; + t_alloc<t_item> m_variable; + }; + }; + + template<typename t_item> class traits_t<alloc_simple<t_item> > : public traits_default_movable {}; + template<typename t_item> class traits_t<__array_fast_helper_t<t_item> > : public traits_default_movable {}; + template<typename t_item> class traits_t<alloc_standard<t_item> > : public pfc::traits_t<__array_fast_helper_t<t_item> > {}; + template<typename t_item> class traits_t<alloc_fast<t_item> > : public pfc::traits_t<__array_fast_helper_t<t_item> > {}; + template<typename t_item> class traits_t<alloc_fast_aggressive<t_item> > : public pfc::traits_t<__array_fast_helper_t<t_item> > {}; + +#if 0//not working (compiler bug?) + template<t_size p_width,typename t_item> class traits_t<typename alloc_fixed<p_width>::template alloc<t_item> > : public pfc::traits_t<t_item> { + public: + enum { + needs_constructor = true, + }; + }; + + template<t_size p_width,template<typename> class t_alloc,typename t_item> + class traits_t<typename alloc_hybrid<p_width,t_alloc>::template alloc<t_item> > : public traits_combined<t_alloc,typename alloc_fixed<p_width>::template alloc<t_item> > {}; +#endif + + +};
