1 /** 2 Aedi, a dependency injection library. 3 4 Aedi is a dependency injection library. It does provide a set of containers that do 5 IoC, and an interface to configure application components (structs, objects, etc.) 6 7 Aim: 8 9 The aim of library is to provide a dependency injection solution that is 10 feature rich, easy to use, easy to learn, and easy to extend up to your needs. 11 12 D by default comes with garbage collector which is responsible for destruction and 13 deallocation of components that were used, and discarded by the application. Current implementation 14 of garbage collector can be inefficient for cases when many small objects are continously 15 created and destroyed by application. Therefore aedi framework allows users to select what 16 allocation strategy to use for managed components by using std.experimental.allocator library. 17 18 To change the allocator used for components in a container, it is possible to 19 pass new allocator implementation to $(D_INLINECODE configure) method as third argument 20 just like in example below: 21 ------------- 22 with (container.configure("singleton", Mallocator.instance.allocatorObject)) { 23 // ... registered components with Mallocator as allocator for them 24 } 25 ------------- 26 27 The allocator passed in $(D_INLINECODE configure) will be used as default implementation. 28 As alternative syntax it is possible to pass the allocator in a fluent syntax by chaining 29 $(D_INLINECODE along) to $(D_INLINECODE configure) with allocator as it's argument. Example 30 below shows such variant: 31 ------------- 32 with (container.configure("prototype").along(MmapAllocator.instance.allocatorObject)) { 33 // ... registered components with Mallocator as allocator for them 34 } 35 ------------- 36 37 The default allocator strategy can be overriden per component by directly specifying the 38 allocator that should be used by registered component using $(D_INLINECODE allocator) property 39 for registered component. Example below shows such use case: 40 ------------- 41 register!Size("size.sedan") // Register a size of a generic "sedan" into container 42 .set!"width"(200UL) 43 .set!"height"(150UL) 44 .set!"length"(500UL) 45 .allocator(MmapAllocator.instance.allocatorObject); // Change allocator object for this particular component to mmap allocator. 46 ------------- 47 48 As a consequence to using custom allocation strategies, for all containers, $(D_INLINECODE terminate) 49 method should be called when containers lifetime ends (whether at end of application, or during some other 50 event), otherwise it is not guaranteed that components are finalized correctly, even if they were allocated on 51 garbage collector. 52 53 License: 54 Boost Software License - Version 1.0 - August 17th, 2003 55 56 Permission is hereby granted, free of charge, to any person or organization 57 obtaining a copy of the software and accompanying documentation covered by 58 this license (the "Software") to use, reproduce, display, distribute, 59 execute, and transmit the Software, and to prepare derivative works of the 60 Software, and to permit third-parties to whom the Software is furnished to 61 do so, all subject to the following: 62 63 The copyright notices in the Software and this entire statement, including 64 the above license grant, this restriction and the following disclaimer, 65 must be included in all copies of the Software, in whole or in part, and 66 all derivative works of the Software, unless such copies or derivative 67 works are solely in the form of machine-executable object code generated by 68 a source language processor. 69 70 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 71 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 72 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 73 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 74 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 75 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 76 DEALINGS IN THE SOFTWARE. 77 78 Authors: 79 aermicioi 80 **/ 81 82 module memory_management; 83 84 import aermicioi.aedi; 85 import std.experimental.allocator; 86 import std.experimental.allocator.mallocator; 87 import std.experimental.allocator.gc_allocator; 88 import std.experimental.allocator.mmap_allocator; 89 import std.stdio; 90 91 /** 92 A struct that should be managed by container. 93 **/ 94 struct Color { 95 ubyte r; 96 ubyte g; 97 ubyte b; 98 } 99 100 /** 101 Size of a car. 102 **/ 103 struct Size { 104 105 ulong width; 106 ulong height; 107 ulong length; 108 } 109 110 /** 111 Interface for engines. 112 113 An engine should implement it, in order to be installable in a car. 114 **/ 115 interface Engine { 116 117 public { 118 119 void turnOn(); 120 void run(); 121 void turnOff(); 122 } 123 } 124 125 /** 126 A concrete implementation of Engine that uses gasoline for propelling. 127 **/ 128 class GasolineEngine : Engine { 129 130 public { 131 132 void turnOn() { 133 writeln("pururukVrooomVrrr"); 134 135 } 136 137 void run() { 138 writeln("vrooom"); 139 } 140 141 void turnOff() { 142 writeln("vrrrPrrft"); 143 } 144 } 145 } 146 147 /** 148 A concrete implementation of Engine that uses diesel for propelling. 149 **/ 150 class DieselEngine : Engine { 151 152 public { 153 154 void turnOn() { 155 writeln("pururukVruumVrrr"); 156 157 } 158 159 void run() { 160 writeln("vruum"); 161 } 162 163 void turnOff() { 164 writeln("vrrrPft"); 165 } 166 } 167 } 168 169 /** 170 A concrete implementation of Engine that uses electricity for propelling. 171 **/ 172 class ElectricEngine : Engine { 173 public { 174 175 void turnOn() { 176 writeln("pzt"); 177 178 } 179 180 void run() { 181 writeln("vvvvvvvvv"); 182 } 183 184 void turnOff() { 185 writeln("tzp"); 186 } 187 } 188 } 189 190 /** 191 Tire, what it can represent else? 192 **/ 193 class Tire { 194 private { 195 int size_; 196 float pressure_; 197 string vendor_; 198 } 199 200 public @property { 201 Tire size(int size) @safe nothrow { 202 this.size_ = size; 203 204 return this; 205 } 206 207 int size() @safe nothrow { 208 return this.size_; 209 } 210 211 Tire pressure(float pressure) @safe nothrow { 212 this.pressure_ = pressure; 213 214 return this; 215 } 216 217 float pressure() @safe nothrow { 218 return this.pressure_; 219 } 220 221 Tire vendor(string vendor) @safe nothrow { 222 this.vendor_ = vendor; 223 224 return this; 225 } 226 227 string vendor() @safe nothrow { 228 return this.vendor_; 229 } 230 } 231 232 public override string toString() { 233 import std.algorithm; 234 import std.range; 235 import std.conv; 236 import std.utf; 237 238 return only("Tire(", this.size.to!string, " inch, ", this.pressure.to!string, " atm, ", this.vendor, ")") 239 .joiner 240 .byChar 241 .array; 242 } 243 } 244 245 /** 246 A class representing a car. 247 **/ 248 class Car { 249 250 private { 251 Color color_; // Car color 252 Size size_; // Car size 253 Engine engine_; // Car engine 254 255 Tire frontLeft_; 256 Tire frontRight_; 257 Tire backLeft_; 258 Tire backRight_; 259 } 260 261 public { 262 263 /** 264 Constructor of car. 265 266 Constructs a car with a set of sizes. A car cannot of course have 267 undefined sizes, so we should provide it during construction. 268 269 Params: 270 size = size of a car. 271 **/ 272 this(Size size, Engine engine) { 273 this.size_ = size; 274 this.engine = engine; 275 } 276 277 @property { 278 279 /** 280 Set color of car 281 282 Set color of car. A car can live with undefined color (physics allow it). 283 284 Params: 285 color = color of a car. 286 287 Returns: 288 Car 289 **/ 290 Car color(Color color) @safe nothrow { 291 this.color_ = color; 292 293 return this; 294 } 295 296 Color color() @safe nothrow { 297 return this.color_; 298 } 299 300 Size size() @safe nothrow { 301 return this.size_; 302 } 303 304 /** 305 Set engine used in car. 306 307 Params: 308 engine = engine used in car to propel it. 309 310 Returns: 311 Car 312 **/ 313 Car engine(Engine engine) @safe nothrow { 314 this.engine_ = engine; 315 316 return this; 317 } 318 319 Engine engine() @safe nothrow { 320 return this.engine_; 321 } 322 323 Car frontLeft(Tire frontLeft) @safe nothrow { 324 this.frontLeft_ = frontLeft; 325 326 return this; 327 } 328 329 Tire frontLeft() @safe nothrow { 330 return this.frontLeft_; 331 } 332 333 Car frontRight(Tire frontRight) @safe nothrow { 334 this.frontRight_ = frontRight; 335 336 return this; 337 } 338 339 Tire frontRight() @safe nothrow { 340 return this.frontRight_; 341 } 342 343 Car backLeft(Tire backLeft) @safe nothrow { 344 this.backLeft_ = backLeft; 345 346 return this; 347 } 348 349 Tire backLeft() @safe nothrow { 350 return this.backLeft_; 351 } 352 353 Car backRight(Tire backRight) @safe nothrow { 354 this.backRight_ = backRight; 355 356 return this; 357 } 358 359 Tire backRight() @safe nothrow { 360 return this.backRight_; 361 } 362 363 } 364 365 void start() { 366 engine.turnOn(); 367 } 368 369 void run() { 370 engine.run(); 371 } 372 373 void stop() { 374 engine.turnOff(); 375 } 376 } 377 } 378 379 /** 380 A manufacturer of cars. 381 **/ 382 class CarManufacturer { 383 384 public { 385 Car manufacture(Size size) { 386 return new Car(size, new DieselEngine()); // Manufacture a car. 387 } 388 } 389 } 390 391 void drive(Car car, string name) { 392 writeln("Uuh, what a nice car, ", name," with following specs:"); 393 writeln("Size:\t", car.size()); 394 writeln("Color:\t", car.color()); 395 writeln("Engine:\t", car.engine()); 396 writeln("Tire front left:\t", car.frontLeft(), "\t located at memory ", cast(void*) car.frontLeft()); 397 writeln("Tire front right:\t", car.frontRight(), "\t located at memory ", cast(void*) car.frontRight()); 398 writeln("Tire back left: \t", car.backLeft(), "\t located at memory ", cast(void*) car.backLeft()); 399 writeln("Tire back right:\t", car.backRight(), "\t located at memory ", cast(void*) car.backRight()); 400 } 401 402 void main() { 403 auto container = aggregate( // Create a joint container hosting other two containers 404 singleton(), "singleton", // Create singleton container, and store it in joint container by "singleton" identity 405 prototype(), "prototype" // Create prototype container, and store it in joint container by "prototype" identity 406 ); 407 scope (exit) container.terminate(); 408 409 with (container.configure("singleton", Mallocator.instance.allocatorObject)) { // Configure singleton container with mallocator instead of gc allocator. 410 register!Color; // Let's register a default implementation of Color 411 412 register!Color("color.green") // Register "green" color into container. 413 .set!"r"(cast(ubyte) 0) 414 .set!"g"(cast(ubyte) 255) 415 .set!"b"(cast(ubyte) 0); 416 417 register!Size // Let's register default implementation of a Size 418 .set!"width"(200UL) 419 .set!"height"(150UL) 420 .set!"length"(300UL); 421 422 register!Size("size.sedan") // Register a size of a generic "sedan" into container 423 .set!"width"(200UL) 424 .set!"height"(150UL) 425 .set!"length"(500UL) 426 .allocator(MmapAllocator.instance.allocatorObject); // Change allocator object for this particular component to mmap allocator. 427 428 register!(Engine, ElectricEngine); 429 430 register!Car 431 .autowire 432 .autowire!"color" 433 .set!"frontLeft"(lref!Tire) 434 .set!"frontRight"(lref!Tire) 435 .set!"backLeft"(lref!Tire) 436 .set!"backRight"(lref!Tire); 437 } 438 439 with (container.configure("prototype").along(MmapAllocator.instance.allocatorObject)) { // Configure prototype container with mmap allocator instead of gc allocator. 440 441 register!Tire // Registering Tire into "prototype" container used by aggregate container 442 .set!"size"(17) 443 .set!"pressure"(3.0) 444 .set!"vendor"("divine tire"); 445 } 446 447 container.instantiate(); // Boot container (or prepare managed code/data). 448 449 container.locate!Car.drive("Electric car"); 450 451 }