1 /**
2 
3 License:
4 	Boost Software License - Version 1.0 - August 17th, 2003
5 
6     Permission is hereby granted, free of charge, to any person or organization
7     obtaining a copy of the software and accompanying documentation covered by
8     this license (the "Software") to use, reproduce, display, distribute,
9     execute, and transmit the Software, and to prepare derivative works of the
10     Software, and to permit third-parties to whom the Software is furnished to
11     do so, all subject to the following:
12 
13     The copyright notices in the Software and this entire statement, including
14     the above license grant, this restriction and the following disclaimer,
15     must be included in all copies of the Software, in whole or in part, and
16     all derivative works of the Software, unless such copies or derivative
17     works are solely in the form of machine-executable object code generated by
18     a source language processor.
19 
20     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22     FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23     SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24     FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26     DEALINGS IN THE SOFTWARE.
27 
28 Authors:
29 	Alexandru Ermicioi
30 **/
31 module aermicioi.aedi.storage.object_storage;
32 
33 import aermicioi.aedi.exception.not_found_exception;
34 import aermicioi.aedi.storage.alias_aware;
35 import aermicioi.aedi.storage.locator;
36 import aermicioi.aedi.storage.storage;
37 
38 import std.conv;
39 
40 /**
41  Implementation of Storage, Locator and AliasAware interfaces.
42 
43  Stores Type elements by KeyType identity in.
44 **/
45 @safe class ObjectStorage(Type = Object, KeyType = string) : Locator!(Type, KeyType), Storage!(Type, KeyType), AliasAware!(KeyType) {
46 
47     private {
48 
49         Type[const(KeyType)] values;
50 
51         KeyType[const(KeyType)] aliasings;
52     }
53 
54     public {
55 
56         /**
57         Fetch an element by identity.
58 
59         Params:
60         	identity = the identity of element to be returned
61 
62         Throws:
63         	NotFoundException when no element is present in storage.
64 
65         Returns:
66         	Type the element with identity.
67         **/
68         Type get(KeyType identity) {
69 
70             if (!this.has(identity)) {
71                 throw new NotFoundException("Element ${identity} not found.", identity.to!string);
72             }
73 
74             return this.values[this.resolve(identity)];
75         }
76 
77         /**
78         Check if an element is present in storage.
79 
80         Params:
81         	identity = the identity of element.
82 
83         Returns:
84         	bool if element with identity exists in storage.
85         **/
86         bool has(in KeyType identity) inout {
87             return (this.resolve(identity) in this.values) !is null;
88         }
89 
90 		/**
91 		Save an element in storage by identity.
92 
93 		Params:
94 			identity = the identity of element in storage.
95 			element = the element which is saved in storage.
96 
97 		Returns:
98 			ObjectStorage
99 		**/
100         ObjectStorage set(Type element, KeyType identity) {
101 
102             this.values[identity] = element;
103 
104             return this;
105         }
106 
107 		/**
108 		Remove an element with identity from storage.
109 
110 		Params:
111 			identity = identity of element which should be removed from storage.
112 
113 		Returns:
114 			ObjectStorage
115 		**/
116         ObjectStorage remove(KeyType identity) {
117 
118             this.values.remove(identity);
119 
120             return this;
121         }
122 
123         /**
124         Get the contents of storage as associative array.
125 
126         Returns:
127         	Type[KeyType] the contents of storage.
128         **/
129         inout(Type[const(KeyType)]) contents() inout {
130             return this.values;
131         }
132 
133         /**
134         Iterate over elements in storage
135 
136         Params:
137         	dg = the delegate which will do something on each element.
138 
139         Returns:
140         	int
141         **/
142         int opApply(scope int delegate(Type value) dg) @trusted {
143 
144         	foreach (value; this.contents()) {
145 
146         		auto result = dg(value);
147 
148         		if (result != 0) {
149         			return result;
150         		}
151         	}
152 
153         	return 0;
154         }
155 
156         /**
157         ditto
158         **/
159         int opApply(scope int delegate(const KeyType key, Type value) dg) @trusted {
160 
161         	foreach (key, value; this.contents()) {
162 
163         		auto result = dg(key, value);
164 
165         		if (result != 0) {
166         			return result;
167         		}
168         	}
169 
170         	return 0;
171         }
172 
173         /**
174         Alias an identity with alias_/
175 
176         Params:
177         	identity = identity which will be aliased
178         	alias_ = the new alias of identity.
179 
180         Returns:
181         	ObejcStorage
182         **/
183         ObjectStorage link(KeyType identity, KeyType alias_) {
184 
185             this.aliasings[alias_] = identity;
186 
187             return this;
188         }
189 
190         /**
191         Removes alias.
192 
193         Params:
194         	alias_ = alias to remove.
195 
196         Returns:
197             this
198 
199         **/
200         ObjectStorage unlink(KeyType alias_) {
201             this.aliasings.remove(alias_);
202 
203             return this;
204         }
205 
206         /**
207         Resolve the alias to an element identity.
208 
209         Params:
210         	alias_ = the alias to an identity.
211         Returns:
212         	KeyType the last found identity in alias chain.
213         **/
214         const(KeyType) resolve(in KeyType alias_) const {
215             if (alias_ in this.aliasings) {
216                 return this.resolve(this.aliasings[alias_]);
217             }
218 
219             return alias_;
220         }
221     }
222 }