1 /** 2 * ae.sys.persistence.stringset 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.sys.persistence.stringset; 15 16 import ae.sys.persistence.core; 17 18 // **************************************************************************** 19 20 // http://d.puremagic.com/issues/show_bug.cgi?id=7016 21 static import ae.sys.file; 22 23 /// A string hashset, stored one line per entry. 24 struct PersistentStringSet 25 { 26 import ae.utils.aa : HashSet; 27 28 static HashSet!string load(string fileName) 29 { 30 import std.file : readText; 31 import std.string : splitLines; 32 33 return HashSet!string(fileName.readText().splitLines()); 34 } 35 36 static void save(string fileName, HashSet!string data) 37 { 38 import std.array : join; 39 import ae.sys.file : atomicWrite; 40 41 atomicWrite(fileName, data.keys.join("\n")); 42 } 43 44 alias Cache = FileCache!(load, save, FlushPolicy.manual); 45 Cache cache; 46 47 this(string fileName) { cache = Cache(fileName); } 48 49 auto opBinaryRight(string op)(string key) 50 if (op == "in") 51 { 52 return key in cache; 53 } 54 55 void add(string key) 56 { 57 assert(key !in cache); 58 cache.add(key); 59 cache.save(); 60 } 61 62 void remove(string key) 63 { 64 assert(key in cache); 65 cache.remove(key); 66 cache.save(); 67 } 68 69 @property string[] lines() { return cache.keys; } 70 @property size_t length() { return cache.length; } 71 } 72 73 unittest 74 { 75 import std.file, std.conv, core.thread; 76 77 enum FN = "test.txt"; 78 if (FN.exists) remove(FN); 79 scope(exit) if (FN.exists) remove(FN); 80 81 { 82 auto s = PersistentStringSet(FN); 83 assert("foo" !in s); 84 assert(s.length == 0); 85 s.add("foo"); 86 } 87 { 88 auto s = PersistentStringSet(FN); 89 assert("foo" in s); 90 assert(s.length == 1); 91 s.remove("foo"); 92 } 93 { 94 auto s = PersistentStringSet(FN); 95 assert("foo" !in s); 96 Thread.sleep(filesystemTimestampGranularity); 97 std.file.write(FN, "foo\n"); 98 assert("foo" in s); 99 Thread.sleep(filesystemTimestampGranularity); 100 std.file.write(FN, "bar\n"); 101 assert(s.lines == ["bar"], text(s.lines)); 102 } 103 }