1 /* 2 ------------------------------------------------------------------- 3 4 Copyright (C) 2014, Edwin van Leeuwen 5 6 This file is part of todod todo list manager. 7 8 Todod is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 Todod is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with Todod. If not, see <http://www.gnu.org/licenses/>. 20 21 ------------------------------------------------------------------- 22 */ 23 24 module todod.set; 25 import std.algorithm; 26 import std.array; 27 import std.container; 28 import std.json; 29 30 /// Set implemented on top of ranges. Unique and ordered (at time of adding) 31 struct Set(T) { 32 /// Add an element to the set 33 void add( E : T )( E element ) { 34 auto elements = _array.find( element ); 35 if ( elements.empty ) { 36 _array ~= element; 37 sort( _array ); 38 } else { 39 // Bit of a hack to make sure we the ids match up 40 if (!element.id.empty) 41 elements[0].id = element.id; 42 } 43 } 44 45 /// Add a range of elements 46 void add(RANGE)(RANGE elements ) { 47 // TODO optimize this since both ranges are sorted 48 foreach (element; elements) 49 add( element ); 50 } 51 52 /// Remove an element from the set 53 void remove(E : T)( E element ) { 54 auto i = countUntil( _array, element ); 55 if (i != -1) 56 _array = _array[0..i] ~ _array[i+1..$]; 57 } 58 59 /// Remove a range of elements 60 void remove(RANGE)( RANGE elements ) { 61 // TODO optimize this since both ranges are sorted 62 foreach (element; elements) 63 remove( element ); 64 } 65 66 /// Returns the front/first element of the set 67 T front() { 68 return _array.front; 69 } 70 71 /// Removes the front element from the set 72 void popFront() { 73 _array.popFront; 74 } 75 76 /// Returns true when the set is empty 77 bool empty() const { 78 if (_array.length > 0) 79 return false; 80 return true; 81 } 82 83 /// Return an array version of the set 84 T[] array() { 85 return _array; 86 } 87 88 /// Number of elements in the set 89 size_t length() const { 90 return _array.length; 91 } 92 93 /// Access by id. 94 T opIndex(size_t id) { 95 return _array[id]; 96 } 97 98 private: 99 T[] _array; 100 } 101 102 unittest { 103 import std.uuid; 104 class Test { 105 UUID id; 106 this() { 107 id = randomUUID; 108 } 109 110 override int opCmp( Object t ) const { 111 return this.id < (cast(Test)(t)).id; 112 } 113 } 114 115 Set!Test set; 116 set.add( new Test ); 117 assert( set.length == 1 ); 118 set.add( [ new Test, new Test ] ); 119 assert( set.length == 3 ); 120 } 121 122 123 /// Convert set to json array. The element needs to implement a toJSON function 124 JSONValue[] toJSON(T)( Set!T set ) { 125 JSONValue[] json; 126 foreach (t; set) 127 json ~= t.toJSON; 128 return json; 129 } 130 131 /// Load set from JSON, needs delegate to convert json into the element type 132 Set!T jsonToSet(T)( in JSONValue json, T delegate( in JSONValue ) convert ) { 133 Set!T set; 134 assert( json.type == JSON_TYPE.ARRAY ); 135 foreach ( js; json.array ) 136 set.add( convert( js ) ); 137 return set; 138 } 139 140 /// Convert Set to JSON given a function to convert the element type to JSON 141 JSONValue setToJSON( T )( Set!T set, JSONValue delegate( in T ) convert ) { 142 JSONValue[] json; 143 foreach ( el; set ) { 144 json ~= convert( el ); 145 } 146 return JSONValue(json); 147 }