Compare commits

...

4 Commits

Author SHA1 Message Date
Tristan B. Velloza Kildaire 67d8af2954
Merge 4a431c43d1 into 0e232822fa 2024-04-26 14:36:47 +00:00
Tristan B. Velloza Kildaire 4a431c43d1 TreeNode
- Added removal
- Added indexing support
2024-04-26 16:35:21 +02:00
Tristan B. Velloza Kildaire 11fd2f856e Methods
- Added leftwards shifting mechanism
2024-04-26 16:28:19 +02:00
Tristan B. Velloza Kildaire 0e232822fa
Feature: Prompting framework (#16)
* Prompter

- Added

Prompt

- Added

* Prompter

- Fixed source `File` check

Prompter (unittests)

- Added a unittest

* Prompter

- Fixed `prompt()`

Prompter (unittests)

- `flush()` pipe write end

* Prompter (unittests)

- Cleaned up

* Prompter (unittests)

- Cleaned up

* Prompter (unittests)

- Fixed missing import

* Prompter

- Added more docs

* Prompter

- Added more docs

* Prompt

- Documented

* Prompter

- Cleand up

* Prompter (unittests)

- Removed unittest

* README

- Updated
2024-04-15 10:45:16 +02:00
3 changed files with 289 additions and 16 deletions

View File

@ -40,6 +40,8 @@ is expected to grow over time.
* `niknaks.containers` * `niknaks.containers`
* Some useful container types * Some useful container types
* Things such as `CacheMap` * Things such as `CacheMap`
* `niknaks.mechanisms`
* User-defined input prompter, retry mechanisms
## License ## License

View File

@ -596,7 +596,7 @@ unittest
// then 0 moves into 1's place // then 0 moves into 1's place
// 0's position is then filled with T.init // 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 // Out of range
if(position >= array.length) 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..$]; 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; return array;
} }
@ -637,57 +663,83 @@ public T[] shift(T)(T[] array, size_t position, bool rightwards = false, bool sh
unittest unittest
{ {
int[] numbas = [1, 5, 2]; int[] numbas = [1, 5, 2];
numbas = numbas.shift(1, true); numbas = numbas.shiftInto(1, true);
// should now be [0, 1, 2] // should now be [0, 1, 2]
writeln(numbas); writeln(numbas);
assert(numbas == [0, 1, 2]); assert(numbas == [0, 1, 2]);
numbas = [1, 5, 2]; numbas = [1, 5, 2];
numbas = numbas.shift(0, true); numbas = numbas.shiftInto(0, true);
// should now be [1, 5, 2] // should now be [1, 5, 2]
writeln(numbas); writeln(numbas);
assert(numbas == [1, 5, 2]); assert(numbas == [1, 5, 2]);
numbas = [1, 5, 2]; numbas = [1, 5, 2];
numbas = numbas.shift(2, true); numbas = numbas.shiftInto(2, true);
// should now be [0, 1, 5] // should now be [0, 1, 5]
writeln(numbas); writeln(numbas);
assert(numbas == [0, 1, 5]); assert(numbas == [0, 1, 5]);
numbas = [1, 2]; numbas = [1, 2];
numbas = numbas.shift(1, true); numbas = numbas.shiftInto(1, true);
// should now be [0, 1] // should now be [0, 1]
writeln(numbas); writeln(numbas);
assert(numbas == [0, 1]); assert(numbas == [0, 1]);
numbas = [1, 2]; numbas = [1, 2];
numbas = numbas.shift(0, true); numbas = numbas.shiftInto(0, true);
// should now be [1, 2] // should now be [1, 2]
writeln(numbas); writeln(numbas);
assert(numbas == [1, 2]); assert(numbas == [1, 2]);
numbas = []; numbas = [];
numbas = numbas.shift(0, true); numbas = numbas.shiftInto(0, false);
// should now be [] // should now be []
writeln(numbas); writeln(numbas);
assert(numbas == []); assert(numbas == []);
} }
public T[] remove(T)(T[] array, size_t idx) // leftwards testung (no shrink)
unittest
{ {
// Return your array on this int[] numbas = [1, 5, 2];
if(!(idx < array.length)) numbas = numbas.shiftInto(1, false);
{
return array;
}
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 // TODO: make delegate kak
@ -767,16 +819,34 @@ public class Tree(T)
public bool removeNode(Tree!(T) node) public bool removeNode(Tree!(T) node)
{ {
bool found = false; bool found = false;
size_t idx;
for(size_t i = 0; i < this.children.length; i++) for(size_t i = 0; i < this.children.length; i++)
{ {
found = this.children[i] == node; found = this.children[i] == node;
if(found) 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 public T[] dfs

View File

@ -9,6 +9,8 @@ import std.functional : toDelegate;
import std.datetime : Duration; import std.datetime : Duration;
import std.datetime.stopwatch : StopWatch, AutoStart; import std.datetime.stopwatch : StopWatch, AutoStart;
import core.thread : Thread; import core.thread : Thread;
import std.stdio : File, write;
import std.string : strip;
/** /**
* A verdict-providing function * 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
}