#pragma once #include #include #include #include #include #include #include namespace gp{ template class buffer; template bool hold_same_data(const gp::buffer& lhs, const gp::buffer& rhs); template class buffer final{ public: private: pointer_iterator begin_elem; pointer_iterator end_elem; static constexpr size_t local_strlen(const char* str) { auto ptr = str; do{}while(*(ptr++)); return ptr-str-1; } public: using associated_iterator = pointer_iterator; constexpr buffer(const char* val) requires std::is_same_v : begin_elem{const_cast(val)} , end_elem{const_cast(val)+local_strlen(val)} {} constexpr buffer(T* beg_ptr, T* end_ptr) : begin_elem{beg_ptr} , end_elem{end_ptr} {} constexpr buffer(associated_iterator beg_ptr, associated_iterator end_ptr) : begin_elem{beg_ptr} , end_elem{end_ptr} {} constexpr buffer(T* beg_ptr, std::size_t sz) : begin_elem{beg_ptr} , end_elem{beg_ptr+sz} {} constexpr size_t size() const { return end_elem - begin_elem; } constexpr associated_iterator begin() const { return begin_elem; } constexpr associated_iterator end() const { return end_elem; } constexpr T& operator[](std::size_t offset) { if constexpr (gp_config::has_buffer_bounds) { gp_config::assertion( offset < size(), "Buffer bounds infringed" ); } return *(begin_elem+offset); } constexpr const T& operator[](std::size_t offset) const { if constexpr (gp_config::has_buffer_bounds) { gp_config::assertion( offset < size(), "Buffer bounds infringed" ); } return *(begin_elem+offset); } optional> at(std::size_t offset) { auto elem = begin()+offset; if(!contains(elem)) { return nullopt; } return elem; } constexpr bool contains(pointer_iterator ptr) { return ptr.data < end_elem.data && ptr.data >= begin_elem.data; } template buffer cast() { if constexpr(sizeof(T)%sizeof(U) == 0) { return buffer(reinterpret_cast(&*begin_elem), size()*(sizeof(T)/sizeof(U))); } else { if((size()*sizeof(T))%sizeof(U) == 0) { return buffer(reinterpret_cast(&*begin_elem), size()*sizeof(T)/sizeof(U)); } else if constexpr (gp_config::has_exceptions) { throw bad_buffer_cast{}; } else { gp_config::assertion( false, "Buffer bounds infringed during cast" ); } } } /** * Create a new subslice of the buffer containing `new_sz` elements exactly, or no elements * @param new_sz the size of the new slice * @return a slice of size new_sz or an empty slice */ buffer slice_start(size_t new_sz) { if(new_sz<=size()) { return buffer{&*begin(), &*(begin()+new_sz)}; } else { return buffer{(T*)nullptr,(size_t)0}; } } /** * Create a new subslice from the end of the buffer containing `new_sz` elements exactly, or no elements * @param new_sz the size of the new slice * @return a slice of size new_sz or an empty slice */ buffer slice_end(size_t new_sz) { if(new_sz<=size()) { return buffer{&*(end()-(new_sz)), &*end()}; } else { return buffer{(T*)nullptr,(size_t)0}; } } /** * Create a new subslice from the end of the buffer containing `rm_sz` elements less elements than the original * buffer, or no elements * @param rm_sz the number of elements to remove from the start of the slice * @return a new slice */ buffer trim_start(size_t rm_sz) { if(rm_sz<=size()) { return buffer{begin().data + rm_sz, end().data}; } else { return buffer{(T*)nullptr,(size_t)0}; } } /** * Create a new subslice from the start of the buffer containing `rm_sz` elements less elements than the * original buffer, or no elements * @param rm_sz the number of elements to remove from the start of the slice * @return a new slice */ buffer trim_end(size_t rm_sz) { if(rm_sz<=size()) { return buffer{begin().data, end().data - rm_sz}; } else { return buffer{(T*)nullptr,(size_t)0}; } } friend bool hold_same_data(const gp::buffer& lhs, const gp::buffer& rhs); bool starts_with(gp::buffer oth) { return hold_same_data(this->slice_start(oth.size()), oth); } optional front() { if(size() == 0) return nullopt; return *begin(); } optional back() { if(size() == 0) return nullopt; return *slice_end(1).begin(); } }; template bool hold_same_data(const gp::buffer& lhs, const gp::buffer& rhs) { if(lhs.size() != rhs.size()) return false; size_t idx = 0; while(idx != lhs.size()) { if(lhs[idx] != rhs[idx]) return false; ++idx; } return true; } }