92 lines
2.2 KiB
D
92 lines
2.2 KiB
D
|
import std.experimental.logger;
|
||
|
import std.traits;
|
||
|
|
||
|
import article;
|
||
|
import page;
|
||
|
import project;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Default ordering and list with pointers to ordered articles.
|
||
|
* (Note: this is code which will actually be compiled and passed on!)
|
||
|
*/
|
||
|
GenericCache!(Article, "a.firstPublished > b.firstPublished") articles;
|
||
|
GenericCache!(Page, "a.title < b.title") pages;
|
||
|
GenericCache!(Project, "a.title < b.title") projects;
|
||
|
|
||
|
/**
|
||
|
* In memory cache of T (where T is like a page). Right now it simply holds everything in memory.
|
||
|
*
|
||
|
* At a later date, this cache might start unloading lesser-accessed items, and load them later
|
||
|
* again if needed.
|
||
|
*/
|
||
|
struct GenericCache(T, string sortOrder)
|
||
|
if (isImplicitlyConvertible!(T, Page)) {
|
||
|
public:
|
||
|
|
||
|
void addItem(T item) {
|
||
|
logf("Added %s '%s'", T.stringof, item.slug);
|
||
|
m_map[item.slug] = item;
|
||
|
sortItems();
|
||
|
}
|
||
|
void removeItem(T item) {
|
||
|
logf("Removed %s '%s'", T.stringof, item.slug);
|
||
|
m_map.remove(item.slug);
|
||
|
sortItems();
|
||
|
}
|
||
|
|
||
|
void removeItemByName(string name) {
|
||
|
foreach(item; m_map.byValue) {
|
||
|
if (item.name == name) removeItem(item);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void changeItem(T item) {
|
||
|
import std.algorithm;
|
||
|
import std.range;
|
||
|
|
||
|
auto r = m_map.byValue.find!((a,b) => a.name == b.name)(item);
|
||
|
if (r.empty()) {
|
||
|
warningf("Could not find old %s with name %s", T.stringof, item.name);
|
||
|
return;
|
||
|
}
|
||
|
T oldItem = r.front;
|
||
|
if (oldItem.slug != item.slug) {
|
||
|
logf("Slug of %s '%s' changed to '%s'", T.stringof, oldItem.slug, item.slug);
|
||
|
m_map.remove(oldItem.slug);
|
||
|
}
|
||
|
m_map[item.slug] = item;
|
||
|
sortItems();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Overload []-operator to redirect to our internal map.
|
||
|
*/
|
||
|
T opIndex(string key) {
|
||
|
return m_map[key];
|
||
|
}
|
||
|
|
||
|
T* opBinaryRight(string op)(const scope string key) {
|
||
|
static if (op == "in") {
|
||
|
return key in m_map;
|
||
|
} else static assert(false, "Operation " ~ op ~ "is not supported on this class");
|
||
|
}
|
||
|
|
||
|
T[] sortedList() {
|
||
|
return m_publicItems;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
|
||
|
T[string] m_map;
|
||
|
T[] m_publicItems;
|
||
|
|
||
|
void sortItems() {
|
||
|
import std.algorithm;
|
||
|
import std.array;
|
||
|
m_publicItems = sort!sortOrder(m_map.values)
|
||
|
.filter!(x => !x.isHidden)
|
||
|
.array;
|
||
|
}
|
||
|
}
|