1 module test3;
2 
3 import std.algorithm : map;
4 import std.stdio;
5 import core.thread.fiber;
6 import std.container.rbtree;
7 
8 struct Item
9 {
10 	uint id;
11 	string description;
12 }
13 
14 struct ItemPtr
15 {
16 	uint id;
17 	Item* payload;
18 
19 	this(uint i)
20 	{
21 		id = i;
22 		payload = null;
23 	}
24 
25 	this(ref Item i)
26 	{
27 		id = i.id;
28 		payload = &i;
29 	}
30 
31 	this(uint i, Item* p)
32 	{
33 		id = i;
34 		payload = p;
35 	}
36 }
37 
38 struct ItemIndex
39 {
40 	alias Impl = RedBlackTree!(ItemPtr, "a.id < b.id");
41 	Impl _impl;
42 	alias _impl this;
43 
44 	auto keys()
45 	{
46 		import std.array : array;
47 		return _impl[].map!"a.id".array;
48 	}
49 
50 	struct Range
51 	{
52 		import std.array : back, empty, front, popBack, popFront;
53 
54 		alias Type = ItemPtr;
55 		alias Keys = typeof(ItemIndex.init.keys());
56 		private ItemIndex* _idx;
57 		private Keys _keys;
58 
59 		this(ref ItemIndex si)
60 		{
61 			_idx = &si;
62 			_keys = si.keys;
63 		}
64 
65 		this(ItemIndex* i, Keys k)
66 		{
67 			_idx = i;
68 			_keys = k;
69 		}
70 
71 		@disable this();
72 
73 		bool empty()
74 		{
75 			return _keys.empty;
76 		}
77 
78 		Type front()
79 		{
80 			auto e = ItemPtr(_keys.front);
81 			return _idx.equalRange(e).front;
82 		}
83 
84 		void popFront()
85 		{
86 			_keys.popFront;
87 		}
88 
89 		Type back()
90 		{
91 			auto e = ItemPtr(_keys.front);
92 			return _idx.equalRange(e).front;
93 		}
94 
95 		void popBack()
96 		{
97 			_keys.popBack;
98 		}
99 
100 		typeof(this) save()
101 		{
102 			auto instance = this;
103 			instance._keys = _keys.dup;
104 			return instance;
105 		}
106 
107 		Type opIndex(size_t idx)
108 		{
109 			auto e = ItemPtr(_keys.front);
110 			return _idx.equalRange(e).front;
111 		}
112 
113 		size_t length()
114 		{
115 			return _keys.length;
116 		}
117 	}
118 
119 	auto opIndex(uint i)
120 	{
121 		return _impl.equalRange(ItemPtr(i, null)).front;
122 	}
123 
124 	auto opSlice()
125 	{
126 		return Range(this);
127 	}
128 }
129 
130 void testItemIndex()
131 {
132 	Item[] data = [
133 		Item(100, "item100"),
134 		Item(200, "item200"),
135 		Item(50, "item50"),
136 	];
137 
138 	auto index = ItemIndex();
139 	index._impl = new ItemIndex.Impl(data.map!((ref a)=>ItemPtr(a.id, &a)));
140 
141 	writeln(index[].map!"*a.payload");
142 	writeln;
143 
144 	auto idx = index[];
145 
146 	scope Fiber composed = new Fiber(()
147 	{
148 		while(!idx.empty)
149 		{
150 			writeln(*idx.front.payload);
151 			idx.popFront;
152 			Fiber.yield();
153 		}
154 	});
155 
156 	composed.call();
157 	composed.call();
158 	composed.call();
159 	composed.call();
160 
161 	// since each fiber has run to completion, each should have state TERM
162 	assert( composed.state == Fiber.State.TERM );
163 }