iw4x-client/src/Utils/Chain.hpp

150 lines
2.2 KiB
C++
Raw Normal View History

2017-01-20 08:36:52 -05:00
#pragma once
2017-01-19 16:23:59 -05:00
namespace Utils
{
template <typename T>
class Chain
{
public:
class Entry
{
private:
std::shared_ptr<T> object;
std::shared_ptr<Entry> next;
public:
bool hasNext()
{
return (this->next.use_count() > 0);
}
bool isValid()
{
return (this->object.use_count() > 0);
2017-01-19 16:23:59 -05:00
}
void set(T object)
{
this->object = std::make_shared<T>();
2017-01-19 16:23:59 -05:00
*this->object.get() = object;
}
std::shared_ptr<T> get()
{
return this->object;
}
Entry getNext()
{
if (this->hasNext())
{
return *(this->next.get());
}
else
{
return Entry();
}
}
std::shared_ptr<Entry> getNextEntry()
{
return this->next;
}
void setNextEntry(std::shared_ptr<Entry> entry)
{
this->next = entry;
}
T *operator->()
{
return (this->object.get());
}
Entry& operator++ ()
{
*this = this->getNext();
return *this;
}
Entry operator++ (int)
{
Entry result = *this;
this->operator++();
return result;
}
};
private:
std::mutex mutex;
Entry object;
public:
void add(T object)
{
std::lock_guard<std::mutex> _(this->mutex);
if (!this->empty())
2017-01-19 16:23:59 -05:00
{
// Create new chain entry
std::shared_ptr<Entry> currentObject = std::make_shared<Entry>();
2017-01-19 16:23:59 -05:00
*currentObject.get() = this->object;
// Add it to the chain
this->object = Entry();
this->object.setNextEntry(currentObject);
}
this->object.set(object);
}
void remove(std::shared_ptr<T> object)
{
std::lock_guard<std::mutex> _(this->mutex);
if (!this->empty())
{
if (this->object.get().get() == object.get())
{
this->object = this->object.getNext();
}
else if (this->object.hasNext())
2017-01-19 16:23:59 -05:00
{
for (auto entry = this->object; entry.isValid(); ++entry)
{
auto next = entry.getNext();
if (next.isValid() && next.get().get() == object.get())
{
*entry.getNextEntry().get() = next.getNext();
}
}
}
}
}
void remove(Entry entry)
{
if (entry.isValid())
{
this->remove(entry.Get());
}
}
bool empty()
{
return !this->object.isValid();
}
Entry begin()
{
return this->object;
}
void clear()
{
this->object = Entry();
}
};
}