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 opIn_r(string key) 50 { 51 return key in cache; 52 } 53 54 void add(string key) 55 { 56 assert(key !in cache); 57 cache.add(key); 58 cache.save(); 59 } 60 61 void remove(string key) 62 { 63 assert(key in cache); 64 cache.remove(key); 65 cache.save(); 66 } 67 68 @property string[] lines() { return cache.keys; } 69 @property size_t length() { return cache.length; } 70 } 71 72 unittest 73 { 74 import std.file, std.conv, core.thread; 75 76 enum FN = "test.txt"; 77 scope(exit) if (FN.exists) remove(FN); 78 79 { 80 auto s = PersistentStringSet(FN); 81 assert("foo" !in s); 82 assert(s.length == 0); 83 s.add("foo"); 84 } 85 { 86 auto s = PersistentStringSet(FN); 87 assert("foo" in s); 88 assert(s.length == 1); 89 s.remove("foo"); 90 } 91 { 92 auto s = PersistentStringSet(FN); 93 assert("foo" !in s); 94 Thread.sleep(filesystemTimestampGranularity); 95 std.file.write(FN, "foo\n"); 96 assert("foo" in s); 97 Thread.sleep(filesystemTimestampGranularity); 98 std.file.write(FN, "bar\n"); 99 assert(s.lines == ["bar"], text(s.lines)); 100 } 101 }