Last active
November 19, 2018 01:00
-
-
Save leo60228/2d8df597116e7a15a55eebe72b19cb09 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "vendor/gsl-lite/include/gsl.hpp" | |
#include <cstdint> | |
#include <array> | |
#include <stdexcept> | |
#include <iostream> | |
template<std::size_t BufSize> | |
class buffer_window : public gsl::span<std::uint8_t> { | |
gsl::span<std::uint8_t> backing_buffer; | |
explicit buffer_window( | |
const gsl::span<std::uint8_t>& buf, | |
std::size_t index_, | |
std::size_t size | |
) : backing_buffer(buf), | |
gsl::span<std::uint8_t>(&buf[index_], size), | |
index(index_) {} | |
template<std::size_t size> | |
friend buffer_window<size> operator+(const buffer_window<size>& window, std::size_t increased); | |
template<std::size_t size> | |
friend buffer_window<size> operator-(const buffer_window<size>& window, std::size_t decreased); | |
public: | |
gsl::span<uint8_t> full() const { | |
return backing_buffer; | |
} | |
std::size_t index; | |
buffer_window(const gsl::span<std::uint8_t>& buf) : backing_buffer(buf), index(0) {} | |
void push_back(std::uint8_t byte) { | |
full()[index + size()] = byte; | |
gsl::span<std::uint8_t>::operator=(full().subspan(index, size() + 1)); | |
} | |
void move(std::ptrdiff_t distance, std::size_t size) { | |
index += distance; | |
gsl::span<std::uint8_t>::operator=(full().subspan(index, size)); | |
} | |
void move(std::ptrdiff_t distance) { | |
move(distance, size()); | |
} | |
void move_after(std::size_t new_size) { | |
move(size(), new_size); | |
} | |
template<typename T> | |
void insert_back(T begin, const T& end) { | |
while (begin != end) { | |
push_back(*begin); | |
++begin; | |
} | |
} | |
template<typename T> | |
void insert_at(std::size_t index, T begin, const T& end) { | |
while (begin != end) { | |
(*this)[index] = *begin; | |
++begin; | |
++index; | |
} | |
} | |
buffer_window<BufSize>& operator=(const buffer_window<BufSize>& source) { | |
backing_buffer = source.backing_buffer; | |
gsl::span<std::uint8_t>::operator=(source); | |
return *this; | |
} | |
buffer_window<BufSize>& operator=(const gsl::span<std::uint8_t>& source) { | |
if (source.data() < full().data() || source.data() + source.size() > full().data() + full().size()) { | |
allocating_exception<std::out_of_range>("Source is unrelated to the buffer").lazy_throw(); | |
} | |
gsl::span<std::uint8_t>::operator=(source); | |
return *this; | |
} | |
buffer_window<BufSize>& operator+=(std::size_t increased) { | |
*this = *this + increased; | |
return *this; | |
} | |
buffer_window<BufSize>& operator-=(std::size_t decreased) { | |
*this = *this - decreased; | |
return *this; | |
} | |
}; | |
template<std::size_t BufSize> | |
buffer_window<BufSize> operator+(const buffer_window<BufSize>& window, std::size_t increased) { | |
return buffer_window<BufSize>(window.full(), window.index, window.size() + increased); | |
} | |
template<std::size_t BufSize> | |
buffer_window<BufSize> operator-(const buffer_window<BufSize>& window, std::size_t decreased) { | |
return buffer_window<BufSize>(window.full(), window.index, window.size() - decreased); | |
} | |
template<std::size_t BufSize> | |
buffer_window<BufSize> make_buffer_window(std::uint8_t(& buf)[BufSize]) { | |
return buffer_window<BufSize>(buf); | |
} | |
#ifdef LEO_UTIL_DEMO | |
#ifdef LEO_UTIL_NEVER_ALLOCATE | |
#include "alloca.h" | |
#endif | |
void buffer_window_demo() { | |
std::cout << "# BUFFER_WINDOW DEMO" << std::endl; | |
gsl::span<uint8_t> buffer; | |
#ifndef LEO_UTIL_NEVER_ALLOCATE | |
std::cout << "allocating 2KB buffer on heap (bypassing DISABLE_ALLOCATION)" << std::endl; | |
{ | |
heap_enabling_context heap_enabler; | |
buffer = gsl::span<uint8_t>(new uint8_t[2048], 2048); | |
} | |
buffer_window<2048> span(buffer); | |
#else | |
std::cout << "allocating 2KB buffer on stack (MAY SEGFAULT ON SOME SYSTEMS)" << std::endl; | |
buffer = gsl::span<uint8_t>(new(alloca(2048)) uint8_t[2048], 2048); | |
buffer_window<2048> span(buffer); | |
#endif | |
std::cout << "initializing with 1kb of 0x05" << std::endl; | |
span.insert_back(byte_iterator(1024, 5), byte_iterator(1024, 5).end()); | |
std::cout << "span[512] is currently " << (int) span[512] << std::endl; | |
std::cout << "size is " << span.size() << ", decreasing by 512" << std::endl; | |
span -= 512; | |
std::cout << "size is now " << span.size() << ", pushing 6" << std::endl; | |
span.push_back(6); | |
std::cout << "size is now " << span.size() << ", increasing by 511" << std::endl; | |
span += 511; | |
std::cout << "size is again " << span.size() << std::endl; | |
std::cout << "span[512] is now " << (int) span[512] << std::endl; | |
std::cout << "moving forward" << std::endl; | |
span.move_after(512); | |
std::cout << "size is now " << span.size() << ", and span[0] is " << (int) span[0] << std::endl; | |
std::cout << "inserting 512x 9s" << std::endl; | |
span.insert_at(0, byte_iterator(512, 9), byte_iterator(512, 9).end()); | |
std::cout << "size is still " << span.size() << ", moving to first 2048 via operator=" << std::endl; | |
span = span.full().first(2048); | |
std::cout << "size is now " << span.size() << ", span[0] is " << (int) span[0]; | |
std::cout << ", span[512] is " << (int) span[512]; | |
std::cout << ", span[1024] is " << (int) span[1024]; | |
std::cout << ", and span[1540] is " << (int) span[1540] << std::endl; | |
std::cout << "trying to move to full buffer with operator=, should succeed" << std::endl; | |
span = span.full(); | |
std::cout << "succeeded with size of " << span.size() << std::endl; | |
#ifndef LEO_UTIL_NEVER_ALLOCATE | |
std::cout << "trying to move to new buffer with operator=, should fail..." << std::endl; | |
uint8_t bad_buffer[20]; | |
try { | |
span = bad_buffer; | |
std::cout << "succeeded (incorrect) with new size of " << span.size(); | |
} catch (std::exception& ex) { | |
std::cout << "errored with: " << ex.what() << std::endl; | |
} | |
#else | |
std::cout << "skipping tests involving exceptions..." << std::endl; | |
#endif | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment