Skip to content

Commit

Permalink
Added Graph example, finished deferred_allocator, fixed an off-by-one…
Browse files Browse the repository at this point in the history
… bug

- Graph is added and passes tests
- deferred_allocator now takes a heap and stores a reference so it can
be attached to the user's heap object
- added deferred_* container convenience aliases
- fixed bug where one-past-end pointer was incorrectly keeping the next
allocation alive (wouldn't really have hurt, only delayed collection,
but the Graph tests check the prompt release so I fixed it)
  • Loading branch information
hsutter committed Sep 17, 2016
1 parent 4f106c1 commit ae58c42
Show file tree
Hide file tree
Showing 9 changed files with 291 additions and 96 deletions.
6 changes: 3 additions & 3 deletions bitflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@
///////////////////////////////////////////////////////////////////////////////


#ifndef GALLOC_BITFLAGS
#define GALLOC_BITFLAGS
#ifndef GCPP_BITFLAGS
#define GCPP_BITFLAGS

#include "util.h"

#include <vector>
#include <algorithm>
#include <cassert>

namespace galloc {
namespace gcpp {

//----------------------------------------------------------------------------
//
Expand Down
29 changes: 0 additions & 29 deletions deferred_allocator.cpp

This file was deleted.

88 changes: 68 additions & 20 deletions deferred_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,24 @@
///////////////////////////////////////////////////////////////////////////////


#ifndef GALLOC_DEFERRED_ALLOCATOR
#define GALLOC_DEFERRED_ALLOCATOR
#ifndef GCPP_DEFERRED_ALLOCATOR
#define GCPP_DEFERRED_ALLOCATOR

#include "deferred_heap.h"

namespace galloc {
#include <vector>
#include <list>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>

namespace gcpp {

//private:
namespace detail {
deferred_heap& global_deferred_heap();
}
//namespace detail {
// deferred_heap& global_deferred_heap();
//}

//public:

Expand All @@ -41,7 +48,13 @@ namespace galloc {
template <class T>
class deferred_allocator
{
deferred_heap& h;
public:

deferred_heap& heap() const {
return h;
}

using value_type = T;
using pointer = deferred_ptr<value_type>;
using const_pointer = deferred_ptr<const value_type>;
Expand All @@ -56,18 +69,20 @@ namespace galloc {
using other = deferred_allocator<U>;
};

deferred_allocator() noexcept
deferred_allocator(deferred_heap& h_) noexcept
: h{ h_ }
{
}

template <class U>
deferred_allocator(deferred_allocator<U> const&) noexcept
deferred_allocator(deferred_allocator<U> const& that) noexcept
: h{ that.heap() }
{
}

pointer allocate(size_type n)
{
return heap().allocate<value_type>(n);
return h.allocate<value_type>(n);
}

void deallocate(pointer, size_type) noexcept
Expand All @@ -82,13 +97,13 @@ namespace galloc {
template <class U, class ...Args>
void construct(U* p, Args&& ...args)
{
heap().construct(p, std::forward<Args>(args)...);
h.construct(p, std::forward<Args>(args)...);
}

template <class U>
void destroy(U* p) noexcept
{
heap().destroy(p);
h.destroy(p);
}

size_type max_size() const noexcept
Expand All @@ -98,31 +113,64 @@ namespace galloc {

deferred_allocator select_on_container_copy_construction() const
{
return *this; // TODO deferred_heap is currently not copyable
return *this; // deferred_heap is not copyable
}

using propagate_on_container_copy_assignment = std::false_type;
using propagate_on_container_move_assignment = std::true_type;
using propagate_on_container_swap = std::true_type;
using is_always_equal = std::true_type;

static deferred_heap& heap() {
return detail::global_deferred_heap();
}
};

template <class T, class U>
inline bool operator==(deferred_allocator<T> const&, deferred_allocator<U> const&) noexcept
inline bool operator==(deferred_allocator<T> const& a, deferred_allocator<U> const& b) noexcept
{
return true;
return &a.h == &b.h;
}

template <class T, class U>
inline bool operator!=(deferred_allocator<T> const& x, deferred_allocator<U> const& y) noexcept
inline bool operator!=(deferred_allocator<T> const& a, deferred_allocator<U> const& b) noexcept
{
return !(x == y);
return !(a == b);
}


//----------------------------------------------------------------------------
//
// Convenience aliases for containers
//
//----------------------------------------------------------------------------

template<class T>
using deferred_vector = std::vector<T, deferred_allocator<T>>;

template<class T>
using deferred_list = std::list<T, deferred_allocator<T>>;

template<class K, class C = std::less<K>>
using deferred_set = std::set<K, C, deferred_allocator<K>>;

template<class K, class T, class C = std::less<K>>
using deferred_multiset = std::multiset<K, C, deferred_allocator<K>>;

template<class K, class T, class C = std::less<K>>
using deferred_map = std::map<K, T, C, deferred_allocator<std::pair<const K, T>>>;

template<class K, class T, class C = std::less<K>>
using deferred_multimap = std::multimap<K, T, C, deferred_allocator<std::pair<const K, T>>>;

template<class K, class H = std::hash<K>, class E = std::equal_to<K>>
using deferred_unordered_set = std::unordered_set<K, H, E, deferred_allocator<K>>;

template<class K, class H = std::hash<K>, class E = std::equal_to<K>>
using deferred_unordered_multiset = std::unordered_multiset<K, H, E, deferred_allocator<K>>;

template<class K, class T, class H = std::hash<K>, class E = std::equal_to<K>>
using deferred_unordered_map = std::unordered_map<K, T, H, E, deferred_allocator<std::pair<const K, T>>>;

template<class K, class T, class H = std::hash<K>, class E = std::equal_to<K>>
using deferred_unordered_multimap = std::unordered_multimap<K, H, E, deferred_allocator<std::pair<const K, T>>>;

}

#endif
31 changes: 17 additions & 14 deletions deferred_heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
///////////////////////////////////////////////////////////////////////////////


#ifndef GALLOC_DEFERRED_HEAP
#define GALLOC_DEFERRED_HEAP
#ifndef GCPP_DEFERRED_HEAP
#define GCPP_DEFERRED_HEAP

#include "gpage.h"

Expand All @@ -29,7 +29,7 @@
#include <type_traits>
#include <memory>

namespace galloc {
namespace gcpp {

// destructor contains a pointer and type-correct-but-erased dtor call.
// (Happily, a noncapturing lambda decays to a function pointer, which
Expand Down Expand Up @@ -235,6 +235,8 @@ namespace galloc {
}

void reset() noexcept { p = nullptr; /* leave mypage alone so we can assign again */ }

deferred_heap* get_heap() const noexcept { return mypage ? mypage->myheap : nullptr; }
};

// For non-roots (deferred_ptrs that are in the deferred heap), we'll additionally
Expand Down Expand Up @@ -263,7 +265,7 @@ namespace galloc {
//
template<class Hint>
dhpage(const Hint* /*--*/, size_t n, deferred_heap* heap)
: page{ std::max<size_t>(sizeof(Hint) * n * 2.62, 4096 /*good general default*/),
: page{ std::max<size_t>(sizeof(Hint) * n * 2.62, 8192 /*good general default*/),
std::max<size_t>(sizeof(Hint), 4) }
, live_starts{ page.locations(), false }
, myheap{ heap }
Expand All @@ -279,7 +281,7 @@ namespace galloc {
destructors dtors;

bool is_destroying = false;
bool collect_before_expand = false; // TODO is this worth keeping?
bool collect_before_expand = false;


public:
Expand Down Expand Up @@ -462,17 +464,17 @@ namespace galloc {
}

int compare3(const deferred_ptr& that) const { return get() < that.get() ? -1 : get() == that.get() ? 0 : 1; };
GALLOC_TOTALLY_ORDERED_COMPARISON(deferred_ptr); // maybe someday this will be default
GCPP_TOTALLY_ORDERED_COMPARISON(deferred_ptr); // maybe someday this will be default


// Checked pointer arithmetic -- TODO this should probably go into a separate array_deferred_ptr type
//
deferred_ptr& operator+=(int offset) noexcept {
#ifndef NDEBUG
assert(get() != nullptr
assert(get() != nullptr
&& "bad deferred_ptr arithmetic: can't perform arithmetic on a null pointer");

auto this_info = find_dhpage_info(get());
auto this_info = get_heap()->find_dhpage_info(get());

assert(this_info.page != nullptr
&& "corrupt non-null deferred_ptr, not pointing into deferred heap");
Expand All @@ -481,9 +483,9 @@ namespace galloc {
&& "corrupt non-null deferred_ptr, pointing to unallocated memory");

auto temp = get() + offset;
auto temp_info = find_dhpage_info(temp);
auto temp_info = get_heap()->find_dhpage_info(temp);

assert(this_info.page == temp_info.page
assert(this_info.page == temp_info.page
&& "bad deferred_ptr arithmetic: attempt to leave dhpage");

assert(
Expand All @@ -492,7 +494,7 @@ namespace galloc {
// which covers one-past-the-end of single-element allocations
( (
this_info.info.found == gpage::in_range_allocated_start
&& (offset == 0 || offset == 1)
&& (offset == -1 || offset == 0 || offset == 1)
)
// otherwise this and temp must point into the same allocation
// which is covered for arrays by the extra byte we allocated
Expand Down Expand Up @@ -554,8 +556,8 @@ namespace galloc {
assert(get() != nullptr && that.get() != nullptr
&& "bad deferred_ptr arithmetic: can't subtract pointers when one is null");

auto this_info = find_dhpage_info(get());
auto that_info = find_dhpage_info(that.get());
auto this_info = get_heap()->find_dhpage_info(get());
auto that_info = get_heap()->find_dhpage_info(that.get());

assert(this_info.page != nullptr
&& that_info.page != nullptr
Expand Down Expand Up @@ -1046,9 +1048,10 @@ namespace galloc {
inline
void deferred_heap::debug_print() const
{
std::cout << "\n*** heap snapshot [" << (void*)this << "] ***********************************************\n\n";
for (auto& pg : pages) {
pg.page.debug_print();
std::cout << " this page's deferred_ptrs.size() is " << pg.deferred_ptrs.size() << "\n";
std::cout << "\n this page's deferred_ptrs.size() is " << pg.deferred_ptrs.size() << "\n";
for (auto& dp : pg.deferred_ptrs) {
std::cout << " " << (void*)dp.p << " -> " << dp.p->get()
<< ", level " << dp.level << "\n";
Expand Down
18 changes: 12 additions & 6 deletions gpage.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
///////////////////////////////////////////////////////////////////////////////


#ifndef GALLOC_GPAGE
#define GALLOC_GPAGE
#ifndef GCPP_GPAGE
#define GCPP_GPAGE

#include "bitflags.h"

Expand All @@ -31,7 +31,7 @@
#include <string>
//#endif

namespace galloc {
namespace gcpp {

//----------------------------------------------------------------------------
//
Expand Down Expand Up @@ -165,9 +165,10 @@ namespace galloc {
// alignment of location needed by a T
const auto locations_step = 1 + (alignof(T)-1) / min_alloc;

// # contiguous locations needed total (note: array allocations get one
// extra location as a simple way to support one-past-the-end arithmetic)
const auto locations_needed = (1 + (bytes_needed - 1) / min_alloc) + (num > 1 ? 1 : 0);
// # contiguous locations needed total
// note: as a simplification, for now we just add an extra location to every
// allocation as a simple way to support one-past-the-end arithmetic
const auto locations_needed = (1 + (bytes_needed - 1) / min_alloc) + 1;

const auto end = locations() - locations_needed;
// intentionally omitting "+1" here in order to keep the
Expand Down Expand Up @@ -327,6 +328,11 @@ namespace galloc {
std::cout << "--- total_size " << total_size << " --- min_alloc " << min_alloc
<< " --- " << (void*)base << " ---------------------------\n ";

for (std::size_t i = 0; i < 64; i += 2) {
std::cout << lowest_hex_digits_of_address(base + i*min_alloc,2)[0] << ' ';
if (i % 8 == 6) { std::cout << ' '; }
}
std::cout << "\n ";
for (std::size_t i = 0; i < 64; i += 2) {
std::cout << lowest_hex_digits_of_address(base + i*min_alloc) << ' ';
if (i % 8 == 6) { std::cout << ' '; }
Expand Down
2 changes: 1 addition & 1 deletion gpage_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

#include "gpage.h"

namespace galloc {
namespace gcpp {

//----------------------------------------------------------------------------
//
Expand Down
Loading

0 comments on commit ae58c42

Please sign in to comment.