diff --git a/task01/isok.h b/task01/isok.h index 5611af5..7b2d6e9 100644 --- a/task01/isok.h +++ b/task01/isok.h @@ -1,18 +1,6 @@ -// Ȝ ѳҙ ҙ ӳܖ ߙ. -// Әș ٔۙ -ȳ, ٚ ȣ ȓ TIME_KEEPER. ȣ, TimeKeeper.h ܘ Әș ӳҙ -// https://gist.github.com/wardencliffe/164128a000c1625b5d0f097f6d5df455 -// ۙ ߘ-Әƿ ѳۙ ј ٘, ӕ ܚ. :) - #include #include - -//#define TIME_KEEPER 1 - -#include - -#ifdef TIME_KEEPER -# include "../../TimeKeeper.h" -#endif +#include #define MIN(a, b) ((a) < (b) ? (a) : (b)) @@ -24,6 +12,7 @@ // Declaration //////////////////////////////////////////////////////////////// + template class myvector { @@ -65,21 +54,25 @@ class myvector void resize_internal(int new_size); + void free_data(); + void clean_stack_data(); + private: - T m_buffer_stack[BUFFER_STACK_SIZE]; + uint8_t m_buffer_stack[BUFFER_STACK_SIZE * ELEMENT_SIZE]; + T * m_data_stack = reinterpret_cast(m_buffer_stack); - T * m_data = m_buffer_stack; + T * m_data = m_data_stack; int m_size = 0; int m_capacity = BUFFER_STACK_SIZE; - - T m_empty_element = T(); }; + //////////////////////////////////////////////////////////////// // Definition //////////////////////////////////////////////////////////////// + template myvector::myvector() { @@ -89,8 +82,7 @@ myvector::myvector() template myvector::~myvector() { - if (m_data != m_buffer_stack) - delete[] m_data; + clear(); } template @@ -109,7 +101,7 @@ template void myvector::add(const T & value) { check_before_add(1); - m_data[m_size] = value; + new (&m_data[m_size]) T(value); ++m_size; } @@ -117,7 +109,6 @@ template T& myvector::add() { check_before_add(1); - m_data[m_size] = m_empty_element; ++m_size; return m_data[m_size - 1]; } @@ -125,48 +116,53 @@ T& myvector::add() template void myvector::erase(int index) { - if (index < m_size) + if (index >= 0 && index < m_size) { - while (++index < m_size) - m_data[index - 1] = std::move_if_noexcept(m_data[index]); + m_data[index].~T(); + if (index < m_size - 1) + { + // Not last element erased so we should move tail of a vector + memmove(m_data + index, m_data + index + 1, (m_size - index - 1) * ELEMENT_SIZE); + } --m_size; - m_data[m_size] = m_empty_element; - check_after_remove(); + m_data[m_size].~T(); // probably required if no move semantics supported + // Disabled for now because adds some a little overhead + //check_after_remove(); } } template -void myvector::push_back(const T& value) +void myvector::push_back(const T & value) { add(value); } template -void myvector::erase(const T* item) +void myvector::erase(const T * item) { - erase(item - m_data); + erase(static_cast(item - m_data)); } template -T& myvector::operator[](int index) +T & myvector::operator[](int index) { return *(m_data + CLAMP(index, 0, m_capacity - 1)); } template -const T& myvector::operator[](int index) const +const T & myvector::operator[](int index) const { return *(m_data + CLAMP(index, 0, m_capacity - 1)); } template -T* myvector::begin() +T * myvector::begin() { return m_data; } template -T* myvector::end() +T * myvector::end() { return m_data + m_size; } @@ -174,19 +170,16 @@ T* myvector::end() template void myvector::clear() { - if (m_data != m_buffer_stack) + if (m_data != m_data_stack) { - delete[] m_data; - m_data = m_buffer_stack; + free_data(); + m_data = m_data_stack; m_capacity = BUFFER_STACK_SIZE; } - - if (!IS_POD) + else { - for (int i = 0; i < BUFFER_STACK_SIZE; ++i) - m_data[i] = m_empty_element; + clean_stack_data(); } - m_size = 0; } @@ -195,18 +188,26 @@ void myvector::resize(int new_size) { if (new_size < m_size) { + // Remove elements if (!IS_POD) { for (int i = new_size; i < m_size; ++i) - m_data[i] = m_empty_element; + m_data[i].~T(); } } else if (new_size > m_size) { + // Add elements resize_internal(new_size); - if (IS_POD) + { memset(m_data + m_size, 0, (new_size - m_size) * ELEMENT_SIZE); + } + else + { + for (int i = m_size; i < new_size; ++i) + new (&m_data[i]) T(); + } } m_size = new_size; } @@ -221,15 +222,15 @@ void myvector::reserve(int min_capacity) template void myvector::check_before_add(int count) { - if (m_size + 1 + count > m_capacity) - resize_internal(m_size + 1 + count); + if (m_size + count > m_capacity) + resize_internal(m_size + count); } template void myvector::check_after_remove() { if (m_size * 4 < m_capacity) - resize_internal(m_size + 1); + resize_internal(m_size); } template @@ -238,10 +239,10 @@ void myvector::resize_internal(int new_size) static const float min_factor = 1.2f; static const float factor_step = 0.2f; - if (m_data == m_buffer_stack && new_size < BUFFER_STACK_SIZE) + if (m_data == m_data_stack && new_size <= BUFFER_STACK_SIZE) return; - int chosen_size = 128; + int chosen_size = BUFFER_STACK_SIZE * 4; float factor = 4.0f; while (chosen_size - 1 < new_size) { @@ -259,42 +260,69 @@ void myvector::resize_internal(int new_size) if (chosen_size == m_capacity) return; - if (chosen_size < BUFFER_STACK_SIZE) + if (chosen_size <= BUFFER_STACK_SIZE) { - if (m_data != m_buffer_stack) + if (m_data != m_data_stack) { - delete[] m_data; - m_data = m_buffer_stack; + free_data(); + m_data = m_data_stack; + m_capacity = BUFFER_STACK_SIZE; } } else { - T * new_data = new T[chosen_size]; - int copy_size = chosen_size < m_size ? chosen_size : m_size; - if (copy_size > 0) + bool need_to_copy = false; + T * new_data = nullptr; + if (m_data == m_data_stack) { - if (IS_POD) - { - memcpy(new_data, m_data, copy_size * ELEMENT_SIZE); - } - else - { - T * src_data = m_data; - T * dst_data = new_data; - for (int i = 0; i < copy_size; ++i, ++src_data, ++dst_data) - *dst_data = *src_data; - } + // Create new memory + new_data = reinterpret_cast(malloc(chosen_size * ELEMENT_SIZE)); + need_to_copy = true; } - if (m_data != m_buffer_stack) + else { - delete[] m_data; + // Try to reallocate memory + new_data = reinterpret_cast(realloc(m_data, chosen_size * ELEMENT_SIZE)); + + // This can be failed so we should check this and workaround + if (!new_data) + { + new_data = reinterpret_cast(malloc(chosen_size * ELEMENT_SIZE)); + need_to_copy = true; + } } - else if (!IS_POD) + if (need_to_copy) { - for (int i = 0; i < copy_size; ++i) - m_data[i] = m_empty_element; + int copy_size = chosen_size < m_size ? chosen_size : m_size; + if (copy_size > 0) + memcpy(new_data, m_data, copy_size * ELEMENT_SIZE); + if (m_data == m_data_stack) + clean_stack_data(); + else + free_data(); } m_data = new_data; m_capacity = chosen_size; } } + +template +void myvector::free_data() +{ + if (!IS_POD) + { + for (int i = 0; i < m_size; ++i) + m_data[i].~T(); + } + free(m_data); +} + +template +void myvector::clean_stack_data() +{ + if (!IS_POD) + { + for (int i = 0; i < BUFFER_STACK_SIZE && i < m_size; ++i) + m_data[i].~T(); + } +}