1 /** 2 This is the `showMask` command of `dentist`. 3 4 Copyright: © 2018 Arne Ludwig <arne.ludwig@posteo.de> 5 License: Subject to the terms of the MIT license, as written in the 6 included LICENSE file. 7 Authors: Arne Ludwig <arne.ludwig@posteo.de> 8 */ 9 module dentist.commands.showMask; 10 11 import dentist.common : 12 ReferenceInterval, 13 ReferenceRegion; 14 import dentist.util.log; 15 import dentist.dazzler : readMask; 16 import std.algorithm : 17 map, 18 max, 19 maxElement, 20 sum; 21 import std.math : log10, lrint, FloatingPointControl; 22 import std.stdio : writefln, writeln, stderr; 23 import vibe.data.json : 24 serializeToJsonString, 25 toJson = serializeToJson, 26 toJsonString = serializeToPrettyJson; 27 28 /// Execute the `showMask` command with `options`. 29 void execute(Options)(in Options options) 30 { 31 auto masks = [options.repeatMask] ~ options.additionalMasks; 32 ReferenceRegion mergedMask; 33 Stats[] statsList; 34 35 foreach (mask; masks) 36 { 37 auto maskRegion = ReferenceRegion(readMask!ReferenceInterval( 38 options.refDb, 39 mask, 40 options.workdir, 41 )); 42 43 if (shouldLog(LogLevel.debug_)) 44 stderr.writeln(serializeToJsonString(maskRegion.intervals)); 45 statsList ~= statsFor(mask, maskRegion); 46 47 if (masks.length > 1) 48 mergedMask |= maskRegion; 49 } 50 51 if (masks.length > 1) 52 { 53 if (shouldLog(LogLevel.debug_)) 54 stderr.writeln(serializeToJsonString(mergedMask.intervals)); 55 statsList ~= statsFor("__merged__", mergedMask); 56 } 57 58 if (options.useJson) 59 writeln(statsList.toJsonString); 60 else 61 writeTabular(statsList); 62 } 63 64 struct Stats 65 { 66 string name; 67 size_t numIntervals; 68 size_t numMaskedBases; 69 70 size_t columnWidth() const nothrow 71 { 72 FloatingPointControl fpCtrl; 73 fpCtrl.rounding = FloatingPointControl.roundUp; 74 auto numWidth = lrint(log10(max( 75 numIntervals, 76 numMaskedBases, 77 ))); 78 numWidth = max(numWidth, name.length); 79 80 return numWidth; 81 } 82 } 83 84 Stats statsFor(string name, ReferenceRegion maskRegion) 85 { 86 return Stats( 87 name, 88 maskRegion.intervals.length, 89 maskRegion.intervals.map!"a.size".sum, 90 ); 91 } 92 93 void writeTabular(Stats[] statsList) 94 { 95 auto columnWidth = statsList.map!"a.columnWidth".maxElement; 96 97 foreach (i, stats; statsList) 98 { 99 writefln!"name: %*s"(columnWidth, stats.name); 100 writefln!"numIntervals: %*d"(columnWidth, stats.numIntervals); 101 writefln!"numMaskedBases: %*d"(columnWidth, stats.numMaskedBases); 102 103 if (i < statsList.length - 1) 104 writeln(); 105 } 106 }