Skip to content

Instantly share code, notes, and snippets.

@johnmcfarlane
Created January 19, 2017 02:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnmcfarlane/69b929c4e2dd4eff1b65af6f0bf7a3d4 to your computer and use it in GitHub Desktop.
Save johnmcfarlane/69b929c4e2dd4eff1b65af6f0bf7a3d4 to your computer and use it in GitHub Desktop.
2-pointer sequence; like a vector without dynamic growth; somewhat standards-compliant
#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