@@ -82,6 +82,20 @@ Allocator::SplitsExceededException::SplitsExceededException
{
}

Allocator::OrphanAllocationException::OrphanAllocationException
(Allocator &allocator, Allocation &allocation)
: Allocator::Exception(allocator, EXCSTR(L"Allocation has no parent."))
, allocation(allocation)
{
}

Allocator::PoolCollisionException::PoolCollisionException
(Allocator &allocator, Address &address)
: Allocator::Exception(allocator, EXCSTR(L"A memory address was already pooled with the given address."))
, address(address)
{
}

Allocator::Allocator
(void)
: split(true)
@@ -233,14 +247,25 @@ bool
Allocator::hasParent
(const Allocation &allocation) const
{
return this->parents.count(&allocation) > 0;
return this->parents.count(const_cast<Allocation *>(&allocation)) > 0;
}

bool
Allocator::hasChildren
(const Allocation &allocation) const
{
return this->children.count(const_cast<Allocation *>(&allocation)) > 0;
}

bool
Allocator::isChild
(const Allocation &parent, const Allocation &child) const
{
return this->hasParent(child) && this->children.at(&parent).find(const_cast<Allocation *>(&child)) != this->children.end();
if (!this->hasParent(child))
return false;

const std::set<Allocation *> &familyRef = this->children.at(const_cast<Allocation *>(&parent));
return familyRef.find(const_cast<Allocation *>(&child)) != familyRef.end();
}

void
@@ -283,6 +308,14 @@ Allocator::throwIfNoAllocation
throw UnallocatedAddressException(const_cast<Allocator &>(*this), const_cast<Address &>(address));
}

void
Allocator::throwIfNoParent
(const Allocation &allocation) const
{
if (!this->hasParent(allocation))
throw OrphanAllocationException(const_cast<Allocator &>(*this), const_cast<Allocation &>(allocation));
}

const Address
Allocator::addressOf
(const Allocation &allocation) const
@@ -502,22 +535,23 @@ Allocator::allocate
(SIZE_T size)
{
Allocation newAllocation = this->null();
return this->allocate(&newAllocation, size);
this->allocate(&newAllocation, size);
return newAllocation;
}

void
Allocator::reallocate
(const Allocation &allocation, SIZE_T size)
{
/* just call the protected reallocation function */
this->reallocate(&allocation, size)
this->reallocate(const_cast<Allocation *>(&allocation), size);
}

void
Allocator::deallocate
(Allocation &allocation)
{
this->deallocate(&allocation)
this->deallocate(&allocation);
}

Data
@@ -556,7 +590,7 @@ Allocator::parent
{
this->throwIfNoParent(allocation);

return this->parents.at(&allocation);
return *this->parents[const_cast<Allocation *>(&allocation)];
}

const Allocation &
@@ -565,20 +599,20 @@ Allocator::parent
{
this->throwIfNoParent(allocation);

return this->parents.at(&allocation);
return *this->parents.at(const_cast<Allocation *>(&allocation));
}

std::set<const Allocation *>
Allocator::children
Allocator::getChildren
(const Allocation &allocation)
{
this->throwIfNoParent(allocation);

if (!this->hasChildren(allocation))
return std::set<const Allocation *>();

return std::set<const Allocation *>(this->children.at(&allocation).begin()
,this->children.at(&allocation).end());
return std::set<const Allocation *>(this->children.at(const_cast<Allocation *>(&allocation)).begin()
,this->children.at(const_cast<Allocation *>(&allocation)).end());
}

Address
@@ -641,7 +675,7 @@ Allocator::reallocate
* calculate child->end().label() + delta
* if it's less than child->start(), it has been deleted
* if it's greater than child->start(), it has been resized */
if (this->chidlren.count(allocation) > 0 && paternalEnd < allocation->end())
if (this->children.count(allocation) > 0 && allocation->end() >= paternalEnd)
{
std::set<Allocation *>::iterator childIter;
std::vector<Allocation *> deadChildren;
@@ -651,9 +685,9 @@ Allocator::reallocate
childIter!=this->children.at(allocation).end();
++childIter)
{
if (*childIter->begin() >= paternalEnd)
if ((*childIter)->start() >= paternalEnd)
deadChildren.push_back(*childIter);
else if (*childIter->end() > paternalEnd)
else if ((*childIter)->end() > paternalEnd)
this->addressPools.at(*childIter)->setMax(paternalEnd);
}

@@ -728,12 +762,12 @@ Allocator::rebind

if (this->hasParent(*allocation))
{
if (address.usesPool(this->addressPools.at(allocation->address())))
if (newAddress.usesPool(this->addressPools.at(allocation->address())))
localNewAddress = newAddress;
else
localNewAddress = this->addressPools.at(allocation->address())->address(newAddress.label());
}
else if (address.usesPool(&this->pooledAddresses))
else if (newAddress.usesPool(&this->pooledAddresses))
localNewAddress = newAddress;
else
localNewAddress = this->pooledAddresses.address(newAddress.label());
@@ -756,10 +790,10 @@ Allocator::rebind

if (this->hasChildren(*allocation))
{
ChildMap::iterator childIter;
std::set<Allocation *>::iterator childIter;

for (childIter = this->children.at(*allocation).begin();
childIter != this->children.at(*allocation).end();
for (childIter = this->children.at(const_cast<Allocation *>(allocation)).begin();
childIter != this->children.at(const_cast<Allocation *>(allocation)).end();
++childIter)
{
this->rebind(*childIter
@@ -789,7 +823,7 @@ Allocator::unbind
if (!this->hasParent(*allocation))
this->throwIfNotPooled(allocation->baseAddress());
else
this->abandonParent(allocation);
this->disownChild(allocation);

if (this->children.count(allocation) > 0)
{
@@ -1615,5 +1649,5 @@ Allocation::children
{
this->throwIfInvalid();

return this->allocator->children(*this);
return this->allocator->getChildren(*this);
}
@@ -1,16 +1,67 @@
#include "main.hpp"

using namespace Neurology;
using namespace NeurologyTest;

int
main
(int argc, char *argv[])
{
Object<int> intObject;
std::vector<TestFailure> failures;
std::vector<Test *> tests = {new AddressTest};
int result;

intObject = 69; // nice
for (std::vector<Test *>::iterator iter=tests.begin();
iter!=tests.end();
++iter)
(*iter)->launch(&failures);

std::cout << *intObject << std::endl;
if (failures.size() == 0)
{
wprintf(L"\r\n[$] All tests passed!\r\n\r\n");
result = 0;
}
else
{
std::map<const char *, std::vector<TestFailure> > organizedFails;
wprintf(L"[#] Errors occurred.\r\n");
wprintf(L"[*] Organizing failures...");

return 0;
for (std::vector<TestFailure>::iterator iter=failures.begin();
iter!=failures.end();
++iter)
{
organizedFails[iter->test].push_back(*iter);
}

wprintf(L"done.\r\n\r\n==========\r\n\r\n");
wprintf(L"[!] %I64d total failures.\r\n\r\n", failures.size());

for (std::map<const char *, std::vector<TestFailure> >::iterator iter=organizedFails.begin();
iter!=organizedFails.end();
++iter)
{
wprintf(L"[!] %I64d failures in %S...\r\n", iter->second.size(), iter->first);

for (std::vector<TestFailure>::iterator failIter=iter->second.begin();
failIter!=iter->second.end();
++failIter)
{
wprintf(L"... %S (line %I64d, file %S)\r\n", failIter->expression, failIter->line, failIter->fileName);
}

wprintf(L"\r\n");
}

result = 1;
}

for (std::vector<Test *>::iterator iter=tests.begin();
iter!=tests.end();
++iter)
{
delete *iter;
}

system("pause");
return result;
}
@@ -1,8 +1,6 @@
#pragma once

#include <iostream>
#include <map>

#include <assert.h>

#include <neurology.hpp>
#pragma comment(lib, "neurology")
#include "test.hpp"
#include "tests/address.hpp"
@@ -0,0 +1,71 @@
#include "test.hpp"

using namespace NeurologyTest;

Test::Test
(void)
{
}

void
Test::run
(std::vector<TestFailure> *failures)
{
/* null test, return no failures. */
return;
}

void
Test::launch
(std::vector<TestFailure> *failures)
{
std::uintptr_t failureCount = failures->size();

this->assertMessage(L"[*] Running %S.", typeid(*this).name());

this->run(failures);

this->assertMessage(L"[*] %I64d new errors.", failures->size() - failureCount);
}

void
Test::assertMacro
(std::vector<TestFailure> *failures, const char *test, const char *expression, bool result, std::uintptr_t line, const char *fileName)

{
this->assertMessage(L"[%s] [%S] assertion: %S... %s"
,(result) ? L"+" : L"!"
,test
,expression
,(result) ? L"success" : L"failure");

if (!result)
failures->push_back(TestFailure(test, expression, line, fileName));
}

TestFailure::TestFailure
(void)
: test(NULL)
, expression(NULL)
, line(0)
, fileName(NULL)
{
}

TestFailure::TestFailure
(const char *test, const char *expression, std::uintptr_t line, const char *fileName)
: test(test)
, expression(expression)
, line(line)
, fileName(fileName)
{
}

TestFailure::TestFailure
(const TestFailure &failure)
: test(failure.test)
, expression(failure.expression)
, line(failure.line)
, fileName(failure.fileName)
{
}
@@ -0,0 +1,51 @@
#pragma once

#include <cstdint>
#include <stdio.h>
#include <typeinfo>
#include <vector>

#include <neurology.hpp>
#pragma comment(lib, "neurology")

#define NEXPAND(exp) #exp
#define NSTR(exp) NEXPAND(exp)
#define NASSERT(expression) this->assertMacro(failures, typeid(*this).name(), NSTR(expression), (expression), __LINE__, __FILE__)

namespace NeurologyTest
{
class TestFailure;

class Test
{
public:
Test(void);

virtual void run(std::vector<TestFailure> *failures);

void launch(std::vector<TestFailure> *failures);

template <class ... Args> void assertMessage(LPWSTR format, Args ... args)
{
wprintf(format, args...);
wprintf(L"\r\n");
}

void assertMacro(std::vector<TestFailure> *failures, const char *test, const char *expression
,bool result, std::uintptr_t line, const char *fileName);
};

class TestFailure
{
public:
const char *test;
const char *expression;
std::uintptr_t line;
const char *fileName;

TestFailure(void);
TestFailure(const char *test, const char *expression, std::uintptr_t line, const char *fileName);
TestFailure(const TestFailure &failure);
};
}

@@ -0,0 +1,56 @@
#include "address.hpp"

using namespace Neurology;
using namespace NeurologyTest;

AddressTest::AddressTest
(void)
: Test()
{
}

void
AddressTest::run
(std::vector<TestFailure> *failures)
{
Address address;
Address addressOfAddress;
Address basicAddress = Address(0xDEADBEEFDEFACED1);

NASSERT(address.isNull());
NASSERT(!address.hasPool()); // has no pool yet
NASSERT(!address.inRange()); // not in any range because it has no pool;

addressOfAddress = Address(&address);

NASSERT(addressOfAddress.label() == (Label)&address);
NASSERT(!addressOfAddress.isNull());
NASSERT(addressOfAddress.hasPool()); // has a pool because it's bound to the default AddressPool
NASSERT(addressOfAddress.usesPool(&AddressPool::Instance));
NASSERT(addressOfAddress.inRange()); // by default it should be in range because the default range is all possible addresses

NASSERT(basicAddress+1 == basicAddress.label()+1);
NASSERT(basicAddress-1 == basicAddress.label()-1);
NASSERT(basicAddress+(-1) == basicAddress.label()-1);
NASSERT(basicAddress-(-1) == basicAddress.label()+1);

basicAddress += 1;

NASSERT(basicAddress == 0xDEADBEEFDEFACED1 + 1);

basicAddress -= 1;

NASSERT(basicAddress == 0xDEADBEEFDEFACED1);

basicAddress += -1;

NASSERT(basicAddress == 0xDEADBEEFDEFACED1 - 1);

basicAddress -= -1;

NASSERT(basicAddress == 0xDEADBEEFDEFACED1);

NASSERT(basicAddress < basicAddress+1);
NASSERT(basicAddress > basicAddress-1);
NASSERT(basicAddress != addressOfAddress);
}
@@ -0,0 +1,19 @@
#pragma once

#include <stdio.h>
#include <vector>

#include <neurology/address.hpp>

#include "../test.hpp"

namespace NeurologyTest
{
class AddressTest : public Test
{
public:
AddressTest();

virtual void run(std::vector<TestFailure> *failures);
};
}
@@ -0,0 +1,22 @@
#include "tests/localalloc.hpp"

using namespace Neurology;

void
TestLocalAllocator
(void)
{
Allocation testAllocation;

assert(testAllocation.isNull());
assert(!testAllocation.isBound());
assert(!testAllocation.isValid());

/* isLocal should return false because this allocation is not bound to an allocator */
assert(!testAllocation.isLocal());

testAllocation = LocalAllocator::Instance.null();

assert(testAllocation.allocatedFrom(&LocalAllocator::Instance));
assert(testAllocation.isLocal());
}
@@ -0,0 +1,7 @@
#pragma once

#include <cassert>

#include <neurology/allocators/local.hpp>

void TestLocalAllocator(void);