Created
January 19, 2017 02:22
-
-
Save johnmcfarlane/69b929c4e2dd4eff1b65af6f0bf7a3d4 to your computer and use it in GitHub Desktop.
2-pointer sequence; like a vector without dynamic growth; somewhat standards-compliant
This file contains 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
#include <algorithm> | |
#include <iterator> | |
#include <memory> | |
namespace sg14 { | |
template<typename T> | |
class buffer : public std::iterator_traits<T*> { | |
public: | |
using size_type = typename buffer<T>::difference_type; | |
buffer() noexcept = default; | |
buffer(buffer const& rhs) | |
:buffer(rhs.size()) | |
{ | |
std::copy(std::begin(rhs), std::end(rhs), std::begin(*this)); | |
} | |
buffer(int size) | |
:first(new T[size]), last(data() + size) { } | |
buffer& operator=(buffer const& rhs) | |
{ | |
using std::swap; | |
auto copy = rhs; | |
swap(*this, copy); | |
return *this; | |
} | |
bool empty() const noexcept | |
{ | |
return cbegin() == cend(); | |
} | |
size_type size() const noexcept | |
{ | |
return std::distance(cbegin(), cend()); | |
} | |
T* begin() noexcept | |
{ | |
return data(); | |
} | |
T const* begin() const noexcept | |
{ | |
return data(); | |
} | |
T const* cbegin() const noexcept | |
{ | |
return data(); | |
} | |
T* end() noexcept | |
{ | |
return last; | |
} | |
T const* end() const noexcept | |
{ | |
return last; | |
} | |
T const* cend() const noexcept | |
{ | |
return last; | |
} | |
T* data() noexcept | |
{ | |
return first.get(); | |
} | |
T const* data() const noexcept | |
{ | |
return first.get(); | |
} | |
friend void swap(buffer& lhs, buffer& rhs) noexcept | |
{ | |
using std::swap; | |
swap(lhs.first, rhs.first); | |
swap(lhs.last, rhs.last); | |
} | |
private: | |
std::unique_ptr<T[]> first; | |
T* last = nullptr; | |
}; | |
template<typename LT, typename RT> | |
bool | |
operator==(buffer<LT> const& lhs, buffer<RT> const& rhs) noexcept(noexcept(std::equal(std::begin(lhs), std::end(lhs), | |
std::begin(rhs)))) | |
{ | |
return (lhs.size() == rhs.size()) && std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs)); | |
} | |
template<typename LT, typename RT> | |
bool operator!=(buffer<LT> const& lhs, buffer<RT> const& rhs) noexcept(noexcept(lhs == rhs)) | |
{ | |
return !(lhs == rhs); | |
} | |
} | |
#include <cassert> | |
#include <iostream> | |
#include <string> | |
#include <type_traits> | |
namespace { | |
using byte = std::uint8_t; | |
constexpr auto uninitialized = byte{0x1a}; | |
template<typename T> | |
void test(T const& some_value) | |
{ | |
using buffer = sg14::buffer<T>; | |
static_assert(sizeof(buffer) == 2 * sizeof(T*), ""); | |
static_assert(std::is_same<typename buffer::iterator_category, std::random_access_iterator_tag>::value, ""); | |
static_assert(std::is_same<typename buffer::value_type, T>::value, ""); | |
static_assert(std::is_same<typename buffer::difference_type, std::ptrdiff_t>::value, ""); | |
static_assert(std::is_same<typename buffer::pointer, T*>::value, ""); | |
static_assert(std::is_same<typename buffer::reference, T&>::value, ""); | |
static_assert(std::is_same<typename buffer::size_type, std::ptrdiff_t>::value, ""); | |
buffer sequence(10); | |
std::fill(std::begin(sequence), std::end(sequence), some_value); | |
auto empty_sequence = buffer(); | |
assert(empty_sequence.size() == 0); | |
{ | |
auto copied_sequence(sequence); | |
assert(sequence == copied_sequence); | |
assert(empty_sequence != copied_sequence); | |
copied_sequence = empty_sequence; | |
assert(sequence != copied_sequence); | |
assert(empty_sequence == copied_sequence); | |
} | |
assert(sequence != empty_sequence); | |
for (auto n : sequence) { | |
assert(n == some_value); | |
} | |
} | |
template<typename T> | |
void test_pod(sg14::buffer<T> const& default_sequence, T const& some_value) | |
{ | |
// for every byte in the buffer. | |
auto data_begin = reinterpret_cast<std::uint8_t const*>(default_sequence.data()); | |
auto data_end = reinterpret_cast<std::uint8_t const*>(default_sequence.data() + default_sequence.size()); | |
std::for_each(data_begin, data_end, [](T b) { | |
assert(b == uninitialized); | |
}); | |
test(some_value); | |
} | |
template<typename T> | |
void test_non_pod(sg14::buffer<T> const& default_sequence, T const& some_value) | |
{ | |
std::for_each(std::begin(default_sequence), std::end(default_sequence), [](T e) { | |
assert(e == T()); | |
}); | |
test(some_value); | |
} | |
void trash_heap() | |
{ | |
constexpr auto bytes_of_heap_to_trash = 10000; | |
auto buffer = (std::uint8_t*) (malloc(bytes_of_heap_to_trash)); | |
std::fill(buffer, buffer + bytes_of_heap_to_trash, uninitialized); | |
delete buffer; | |
} | |
} | |
int main() | |
{ | |
trash_heap(); | |
auto char_buffer = sg14::buffer<char>(10); | |
auto int_buffer = sg14::buffer<int>(10); | |
auto double_buffer = sg14::buffer<double>(10); | |
auto string_buffer = sg14::buffer<std::string>(10); | |
test_pod(char_buffer, char{0x7f}); | |
test_pod(int_buffer, 0x12345678); | |
test_pod(double_buffer, 98765.4321); | |
test_non_pod(string_buffer, std::string{"abc XYZ 987"}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment