Other various files are obviously not included here, because they're not relevant.
Created
April 11, 2015 15:51
-
-
Save shadowmint/d49650668e9a74c324a1 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
#include "option.h" | |
#include "iterator.h" | |
using namespace std; | |
namespace npp { | |
/// An intrusive linked list for collecting resource instances | |
template<typename TId, typename TValue> | |
class Resource { | |
private: | |
/// Next item in the chain | |
unique_ptr<Resource<TId, TValue>> data; | |
protected: | |
/// The id this value | |
TId id; | |
/// The value on this value | |
TValue value; | |
public: | |
/// Create a new instance and assign the values to it | |
Resource(TId id, TValue value) { | |
this->id = id; | |
this->value = value; | |
} | |
/// Destructor | |
virtual ~Resource() { | |
} | |
/// Safely clone a new instance of this | |
virtual Resource<TId, TValue> *Clone(); | |
/// Overload * to get value | |
TValue operator*() { | |
TValue rtn = this->value; | |
return rtn; | |
} | |
/// Check if the id matches | |
bool Is(TId id) { | |
return this->id == id; | |
} | |
/// Return the next item in the chain | |
Option<Resource<TId, TValue>*> Next() { | |
if (data) { | |
return Some<Resource<TId, TValue>*>(data.get()); | |
} | |
return None<Resource<TId, TValue>*>(); | |
} | |
/// Find the final link in this chain of values | |
Resource<TId, TValue> *Last() { | |
Resource<TId, TValue> *rtn = this; | |
while (rtn->Next()) { | |
rtn = *rtn->Next(); | |
} | |
return rtn; | |
} | |
/// Push a resource onto the chain | |
void Push(Resource<TId, TValue>* value) { | |
if (data) { | |
auto last = Last(); | |
last->Push(value); | |
} | |
else { | |
data = unique_ptr<Resource<TId, TValue>>(value); | |
} | |
} | |
/// Return an iterator to the contents | |
template<typename TOut> | |
Iterator<Resource<TId, TValue>*, TOut*> Iter() { | |
return iter<Resource<TId, TValue>, TOut*>(this, [] (Resource<TId, TValue>* root, std::function< bool(TOut *value) > handler) { | |
auto tmp = root; | |
while(tmp) { | |
if (!handler((TOut *) tmp)) | |
break; | |
tmp = tmp->Next().Or(NULL); | |
} | |
}); | |
} | |
/// Return an iterator to the contents, by id value | |
template<typename TOut> | |
Iterator<Resource<TId, TValue>*, TOut*> Iter(TId query) { | |
return iter<Resource<TId, TValue>, TOut*>(this, [query] (Resource<TId, TValue>* root, std::function< bool(TOut *value) > handler) { | |
auto tmp = root; | |
while(tmp) { | |
if (tmp->Is(query)) { | |
if (!handler((TOut *) tmp)) | |
break; | |
} | |
tmp = tmp->Next().Or(NULL); | |
} | |
}); | |
} | |
/// Return an iterator to the contents, by custom filter | |
/// ...oddly, this is actually useful. | |
template<typename TOut> | |
Iterator<Resource<TId, TValue>*, TOut*> Iter(std::function< bool(Resource<TId, TValue>*) > filter) { | |
return iter<Resource<TId, TValue>, TOut*>(this, [filter] (Resource<TId, TValue>* root, std::function< bool(TOut *value) > handler) { | |
auto tmp = root; | |
while(tmp) { | |
if (filter(tmp)) { | |
if (!handler((TOut *) tmp)) | |
break; | |
} | |
tmp = tmp->Next().Or(NULL); | |
} | |
}); | |
} | |
/// Create a new resource chain with a custom filter | |
Option<Resource<TId, TValue>*> Filter(std::function< bool(Resource<TId, TValue>*) > filter) { | |
auto iter = this->Iter<Resource<TId, TValue>>(filter); | |
if (iter.Any()) { | |
auto index = 0; | |
auto root = (*iter.First())->Clone(); | |
iter.Each([&] (Resource<TId, TValue>* r) { | |
if (index != 0) { | |
root->Push(r->Clone()); | |
} | |
++index; | |
}); | |
return Some<Resource<TId, TValue>*>(root); | |
} | |
return None<Resource<TId, TValue>*>(); | |
} | |
}; | |
} |
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
#include <npp/test/test_suite.h> | |
#include <npp/types.h> | |
#include <npp/resource.h> | |
using namespace npp; | |
using namespace npp::test; | |
int alloc_counter = 0; | |
int dealloc_counter = 0; | |
enum RType { | |
ThingOne = 1, | |
ThingTwo = 2 | |
}; | |
class RValue : public Resource<RType, i32> { | |
public: | |
RValue(int value) : Resource(ThingOne, value) { | |
alloc_counter += 1; | |
} | |
~RValue() { | |
dealloc_counter += 1; | |
} | |
Resource<RType, i32>* Clone() { | |
return new RValue(this->value); | |
} | |
}; | |
class LValue : public Resource<RType, i32> { | |
public: | |
LValue(int value) : Resource(ThingTwo, value) { | |
alloc_counter += 1; | |
} | |
~LValue() { | |
dealloc_counter += 1; | |
} | |
Resource<RType, i32>* Clone() { | |
return new LValue(this->value); | |
} | |
}; | |
void test_alloc_dealloc() { | |
auto foo = new RValue(100); | |
delete foo; | |
ASSERT(alloc_counter == dealloc_counter); | |
} | |
void test_push() { | |
auto counter = alloc_counter; | |
auto foo = new RValue(100); | |
foo->Push(new RValue(200)); | |
delete foo; | |
ASSERT(alloc_counter == counter + 2); | |
ASSERT(alloc_counter == dealloc_counter); | |
} | |
void test_iter() { | |
auto count = 0; | |
auto acount = alloc_counter; | |
auto foo = new RValue(100); | |
foo->Push(new RValue(101)); | |
foo->Push(new LValue(200)); | |
foo->Push(new LValue(201)); | |
foo->Push(new LValue(202)); | |
foo->Iter<Resource<RType, i32>>().Each([&] (Resource<RType, i32> *v) { | |
count += 1; | |
}); | |
delete foo; | |
ASSERT(count == 5); | |
ASSERT(alloc_counter == (acount + 5)); | |
ASSERT(dealloc_counter == (acount + 5)); | |
} | |
void test_iter_id() { | |
auto l_count = 0; | |
auto r_count = 0; | |
auto foo = new RValue(100); | |
foo->Push(new RValue(101)); | |
foo->Push(new LValue(200)); | |
foo->Push(new LValue(201)); | |
foo->Push(new LValue(202)); | |
foo->Iter<LValue>(ThingTwo).Each([&] (LValue *l) { | |
l_count += 1; | |
}); | |
foo->Iter<RValue>(ThingOne).Each([&] (RValue *l) { | |
r_count += 1; | |
}); | |
delete foo; | |
ASSERT(l_count == 3); | |
ASSERT(r_count == 2); | |
} | |
void test_filter_by_function() { | |
auto foo = new RValue(100); | |
foo->Push(new RValue(101)); | |
foo->Push(new LValue(100)); | |
foo->Push(new LValue(201)); | |
foo->Push(new LValue(202)); | |
auto filtered = foo->Filter([] (Resource<RType, i32>* value) { | |
return **value == 100; | |
}); | |
/*ASSERT(filtered.Some()); | |
ASSERT(*filtered.Count() == 2);*/ | |
delete foo; | |
} | |
class Tests: public TestSuite { | |
public: | |
Tests() { | |
TEST(test_alloc_dealloc) | |
TEST(test_push) | |
TEST(test_iter) | |
TEST(test_iter_id) | |
TEST(test_filter_by_function); | |
} | |
}; | |
int main(int argc, char **argv) { | |
return (new Tests())->Report(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment