mirror of https://github.com/deavmi/niknaks
Compare commits
4 Commits
e5a46f8652
...
67d8af2954
Author | SHA1 | Date |
---|---|---|
Tristan B. Velloza Kildaire | 67d8af2954 | |
Tristan B. Velloza Kildaire | 4a431c43d1 | |
Tristan B. Velloza Kildaire | 11fd2f856e | |
Tristan B. Velloza Kildaire | 0e232822fa |
|
@ -40,6 +40,8 @@ is expected to grow over time.
|
|||
* `niknaks.containers`
|
||||
* Some useful container types
|
||||
* Things such as `CacheMap`
|
||||
* `niknaks.mechanisms`
|
||||
* User-defined input prompter, retry mechanisms
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -596,7 +596,7 @@ unittest
|
|||
// then 0 moves into 1's place
|
||||
// 0's position is then filled with T.init
|
||||
|
||||
public T[] shift(T)(T[] array, size_t position, bool rightwards = false, bool shrink = false)
|
||||
public T[] shiftInto(T)(T[] array, size_t position, bool rightwards = false, bool shrink = false)
|
||||
{
|
||||
// Out of range
|
||||
if(position >= array.length)
|
||||
|
@ -629,6 +629,32 @@ public T[] shift(T)(T[] array, size_t position, bool rightwards = false, bool sh
|
|||
array = array[1..$];
|
||||
}
|
||||
}
|
||||
// if leftwards
|
||||
else
|
||||
{
|
||||
// nothing furtherright
|
||||
if(position == array.length-1)
|
||||
{
|
||||
return array;
|
||||
}
|
||||
|
||||
for(size_t i = position; i < array.length-1; i++)
|
||||
{
|
||||
array[i] = array[i+1];
|
||||
}
|
||||
|
||||
// no shrink, then fill with T.init
|
||||
if(!shrink)
|
||||
{
|
||||
array[$-1] = T.init;
|
||||
}
|
||||
// chomp right-hand side
|
||||
else
|
||||
{
|
||||
array = array[0..$-1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return array;
|
||||
}
|
||||
|
@ -637,57 +663,83 @@ public T[] shift(T)(T[] array, size_t position, bool rightwards = false, bool sh
|
|||
unittest
|
||||
{
|
||||
int[] numbas = [1, 5, 2];
|
||||
numbas = numbas.shift(1, true);
|
||||
numbas = numbas.shiftInto(1, true);
|
||||
|
||||
// should now be [0, 1, 2]
|
||||
writeln(numbas);
|
||||
assert(numbas == [0, 1, 2]);
|
||||
|
||||
numbas = [1, 5, 2];
|
||||
numbas = numbas.shift(0, true);
|
||||
numbas = numbas.shiftInto(0, true);
|
||||
|
||||
// should now be [1, 5, 2]
|
||||
writeln(numbas);
|
||||
assert(numbas == [1, 5, 2]);
|
||||
|
||||
numbas = [1, 5, 2];
|
||||
numbas = numbas.shift(2, true);
|
||||
numbas = numbas.shiftInto(2, true);
|
||||
|
||||
// should now be [0, 1, 5]
|
||||
writeln(numbas);
|
||||
assert(numbas == [0, 1, 5]);
|
||||
|
||||
numbas = [1, 2];
|
||||
numbas = numbas.shift(1, true);
|
||||
numbas = numbas.shiftInto(1, true);
|
||||
|
||||
// should now be [0, 1]
|
||||
writeln(numbas);
|
||||
assert(numbas == [0, 1]);
|
||||
|
||||
numbas = [1, 2];
|
||||
numbas = numbas.shift(0, true);
|
||||
numbas = numbas.shiftInto(0, true);
|
||||
|
||||
// should now be [1, 2]
|
||||
writeln(numbas);
|
||||
assert(numbas == [1, 2]);
|
||||
|
||||
numbas = [];
|
||||
numbas = numbas.shift(0, true);
|
||||
numbas = numbas.shiftInto(0, false);
|
||||
|
||||
// should now be []
|
||||
writeln(numbas);
|
||||
assert(numbas == []);
|
||||
}
|
||||
|
||||
public T[] remove(T)(T[] array, size_t idx)
|
||||
// leftwards testung (no shrink)
|
||||
unittest
|
||||
{
|
||||
// Return your array on this
|
||||
if(!(idx < array.length))
|
||||
{
|
||||
return array;
|
||||
}
|
||||
int[] numbas = [1, 5, 2];
|
||||
numbas = numbas.shiftInto(1, false);
|
||||
|
||||
return null;
|
||||
// should now be [1, 2, 0]
|
||||
writeln(numbas);
|
||||
assert(numbas == [1, 2, 0]);
|
||||
|
||||
numbas = [1, 5, 2];
|
||||
numbas = numbas.shiftInto(0, false);
|
||||
|
||||
// should now be [5, 2, 0]
|
||||
writeln(numbas);
|
||||
assert(numbas == [5, 2, 0]);
|
||||
|
||||
numbas = [1, 5, 2];
|
||||
numbas = numbas.shiftInto(2, false);
|
||||
|
||||
// should now be [1, 5, 2]
|
||||
writeln(numbas);
|
||||
assert(numbas == [1, 5, 2]);
|
||||
|
||||
numbas = [];
|
||||
numbas = numbas.shiftInto(0, true);
|
||||
|
||||
// should now be []
|
||||
writeln(numbas);
|
||||
assert(numbas == []);
|
||||
}
|
||||
|
||||
public T[] removeResize(T)(T[] array, size_t position)
|
||||
{
|
||||
return array.shiftInto(position, false, true);
|
||||
}
|
||||
|
||||
// TODO: make delegate kak
|
||||
|
@ -767,16 +819,34 @@ public class Tree(T)
|
|||
public bool removeNode(Tree!(T) node)
|
||||
{
|
||||
bool found = false;
|
||||
size_t idx;
|
||||
for(size_t i = 0; i < this.children.length; i++)
|
||||
{
|
||||
found = this.children[i] == node;
|
||||
if(found)
|
||||
{
|
||||
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
if(found)
|
||||
{
|
||||
this.children = this.children.removeResize(idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public T opIndex(size_t idx)
|
||||
{
|
||||
return idx < this.children.length ? this.children[idx].getValue() : T.init;
|
||||
}
|
||||
|
||||
public T getValue()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public T[] dfs
|
||||
|
|
|
@ -9,6 +9,8 @@ import std.functional : toDelegate;
|
|||
import std.datetime : Duration;
|
||||
import std.datetime.stopwatch : StopWatch, AutoStart;
|
||||
import core.thread : Thread;
|
||||
import std.stdio : File, write;
|
||||
import std.string : strip;
|
||||
|
||||
/**
|
||||
* A verdict-providing function
|
||||
|
@ -291,4 +293,203 @@ unittest
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-defined prompt
|
||||
*/
|
||||
public struct Prompt
|
||||
{
|
||||
private string query;
|
||||
private string value;
|
||||
|
||||
/**
|
||||
* Constructs a new prompt
|
||||
* with the given query
|
||||
*
|
||||
* Params:
|
||||
* query = the prompt
|
||||
* query itself
|
||||
*/
|
||||
this(string query)
|
||||
{
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the prompt query
|
||||
*
|
||||
* Returns: the query
|
||||
*/
|
||||
public string getQuery()
|
||||
{
|
||||
return this.query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves this prompt's
|
||||
* answer
|
||||
*
|
||||
* Returns: the answer
|
||||
*/
|
||||
public string getValue()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill this prompt's
|
||||
* query with a corresponding
|
||||
* answer
|
||||
*
|
||||
* Params:
|
||||
* value = the answer
|
||||
*/
|
||||
public void fill(string value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A prompting mechanism
|
||||
* which can be filled up
|
||||
* with questions and a
|
||||
* file-based source to
|
||||
* read answers in from
|
||||
* and associate with
|
||||
* their original respective
|
||||
* questions
|
||||
*/
|
||||
public class Prompter
|
||||
{
|
||||
/**
|
||||
* Source file
|
||||
*/
|
||||
private File source;
|
||||
|
||||
/**
|
||||
* Whether or not to close
|
||||
* the source file on destruction
|
||||
*/
|
||||
private bool closeOnDestruct;
|
||||
|
||||
/**
|
||||
* Prompts to query by
|
||||
*/
|
||||
private Prompt[] prompts;
|
||||
|
||||
/**
|
||||
* Constructs a new prompter
|
||||
* with the given file source
|
||||
* from where the input is to
|
||||
* be read from.
|
||||
*
|
||||
* Params:
|
||||
* source = the `File` to
|
||||
* read from
|
||||
* closeOnDestruct = if
|
||||
* set to `true` then on
|
||||
* destruction we will close
|
||||
* the source, if `false` it
|
||||
* is left untouched
|
||||
*
|
||||
* Throws:
|
||||
* Exception if the provided
|
||||
* `File` is not open
|
||||
*/
|
||||
this(File source, bool closeOnDestruct = false)
|
||||
{
|
||||
if(!source.isOpen())
|
||||
{
|
||||
throw new Exception("Source not open");
|
||||
}
|
||||
|
||||
this.closeOnDestruct = closeOnDestruct;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given prompt
|
||||
*
|
||||
* Params:
|
||||
* prompt = the prompt
|
||||
*/
|
||||
public void addPrompt(Prompt prompt)
|
||||
{
|
||||
this.prompts ~= prompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the prompting
|
||||
* by querying each attached
|
||||
* prompt for an answer
|
||||
* which is then associated
|
||||
* with the given prompt
|
||||
*
|
||||
* Returns: the answered
|
||||
* prompts
|
||||
*/
|
||||
public Prompt[] prompt()
|
||||
{
|
||||
char[] buff;
|
||||
|
||||
foreach(ref Prompt prompt; this.prompts)
|
||||
{
|
||||
scope(exit)
|
||||
{
|
||||
buff.length = 0;
|
||||
}
|
||||
|
||||
// Perform the query
|
||||
write(prompt.getQuery());
|
||||
this.source.readln(buff);
|
||||
|
||||
// Fill answer into prompt
|
||||
prompt.fill(strip(cast(string)buff));
|
||||
}
|
||||
|
||||
return this.prompts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~this()
|
||||
{
|
||||
if(this.closeOnDestruct)
|
||||
{
|
||||
this.source.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
version(unittest)
|
||||
{
|
||||
import std.process : pipe, Pipe;
|
||||
import std.conv : to;
|
||||
import std.stdio : writeln;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
Pipe pipe = pipe();
|
||||
|
||||
// Create a prompter with some prompts
|
||||
Prompter p = new Prompter(pipe.readEnd());
|
||||
p.addPrompt(Prompt("What is your name?"));
|
||||
p.addPrompt(Prompt("How old are you"));
|
||||
|
||||
// Fill up pipe with data for read end
|
||||
File writeEnd = pipe.writeEnd();
|
||||
writeEnd.writeln("Tristan Brice Velloza Kildaire");
|
||||
writeEnd.writeln(1);
|
||||
writeEnd.flush();
|
||||
|
||||
// Perform the prompt and get the
|
||||
// answers back out
|
||||
Prompt[] ans = p.prompt();
|
||||
|
||||
writeln(ans);
|
||||
|
||||
assert(ans[0].getValue() == "Tristan Brice Velloza Kildaire");
|
||||
assert(to!(int)(ans[1].getValue()) == 1); // TODO: Allow union conversion later
|
||||
}
|
Loading…
Reference in New Issue