1 /** 2 Copyright: Copyright (c) 2016, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 10 Various utilities used by generators. 11 TODO change the name of this module to location_filter. 12 */ 13 module cpptooling.generator.utility; 14 15 import std.functional : unaryFun; 16 import std.traits; 17 import std.range : ElementType; 18 19 version (unittest) { 20 import unit_threaded : shouldEqual; 21 } 22 23 /** Filter according to location existence and predicate. 24 * 25 * A false result is: 26 * - neither a location for a declaration or definition exist. 27 * - fails the predicate. 28 * 29 * The predicate is only called when a location exist. 30 */ 31 template filterAnyLocation(alias predicate) { 32 alias predFun = unaryFun!predicate; 33 34 auto filterAnyLocation(Range, LookupT)(Range range, LookupT lookup) { 35 import std.algorithm : filter, map; 36 import std.typecons : tuple; 37 import std.range : ElementType; 38 import cpptooling.data.type : LocationTag, Location; 39 40 struct LocElem { 41 LocationTag location; 42 ElementType!Range value; 43 } 44 45 // dfmt off 46 return range 47 // get the location associated with each item 48 .map!(a => tuple(lookup(a.usr), a)) 49 // remove those that don't have a location 50 .filter!(a => a[0].length != 0) 51 // unpack the location. a declaration or definition, doesn't matter 52 .map!(a => tuple(a[0].front.any, a[1])) 53 // pack data in a struct that make it easier to use with named 54 // fields 55 .map!(a => LocElem(a[0].front, a[1])) 56 .filter!(a => predicate(a)); 57 // dfmt on 58 } 59 } 60 61 @("shall only let USRs with a location pass") 62 unittest { 63 import std.algorithm : joiner; 64 import std.array : array; 65 import std.range : only, dropOne; 66 import std.typecons : Nullable; 67 import cpptooling.data.symbol.types : USRType; 68 import cpptooling.data.type : LocationTag, Location; 69 70 auto valid_loc = LocationTag(Location("valid.h", 1, 2)); 71 72 static struct ImplAny { 73 Nullable!LocationTag data; 74 75 static auto makeNull() { 76 auto rval = ImplAny(LocationTag.init); 77 rval.data.nullify; 78 return rval; 79 } 80 81 this(LocationTag data) { 82 this.data = data; 83 } 84 85 auto any() { 86 return data.isNull ? only(LocationTag.init).dropOne : only(data.get); 87 } 88 } 89 90 static struct ImplUSR { 91 USRType usr; 92 int id; /// only for test purpose to ensure the data has passed through 93 } 94 95 // dfmt off 96 // predicate says "yes", expecting meaning of life 97 filterAnyLocation!(a => true)( 98 only(ImplUSR(USRType("fool"), 42)), (USRType a) { return only(ImplAny(valid_loc)); } ) 99 .front.value.id.shouldEqual(42); 100 101 // lookup says "no location for that USR", expecting filter to catch and remove the nothingness 102 filterAnyLocation!(a => true)( 103 only(ImplUSR(USRType("fool"), 42)), (USRType a) { return only(ImplAny.makeNull).dropOne; } ) 104 .array() 105 .length.shouldEqual(0); 106 107 // predicate says "no", expecting filter to remove the input 108 filterAnyLocation!(a => false)( 109 only(ImplUSR(USRType("fool"), 42)), (USRType a) { return only(ImplAny(valid_loc)); } ) 110 .array() 111 .length.shouldEqual(0); 112 113 // dfmt on 114 }