Compare commits

...

14 Commits

Author SHA1 Message Date
Tristan B. Velloza Kildaire 17dabe7995
Merge bfa7c6020f into b6106883da 2024-05-02 06:35:55 +00:00
Tristan B. Velloza Kildaire bfa7c6020f View
- Fixed range-based `opSlice(...)`

View (unittests)

- Added unittest
2024-05-02 08:35:45 +02:00
Tristan B. Velloza Kildaire 2ecb371d9a View
- Added range `opSlice()`
2024-05-02 08:34:28 +02:00
Tristan B. Velloza Kildaire a2fc15aac1 Merge branch 'master' into feature/views 2024-05-02 08:33:15 +02:00
Tristan B. Velloza Kildaire b6106883da ConfigEntry
- Space fix
2024-05-02 08:32:38 +02:00
Tristan B. Velloza Kildaire df52dab72f View
- Made `add(T[])` private
2024-05-02 08:10:04 +02:00
Tristan B. Velloza Kildaire 328239cd57 View
- made `opIndex(size_t)` and `opIndexAssign(T, size_t)` respect the "fake" size

View (unittests)

- Added code to test the above updates to the `View` type
2024-05-02 07:58:17 +02:00
Tristan B. Velloza Kildaire b383cfad65 View
- More work being done on deciding various parts of this API
- Fixed the `opIndexAssign(...)`
2024-05-01 20:27:14 +02:00
Tristan B. Velloza Kildaire 20c3969516 View
- Allow updating indices
2024-04-30 22:35:54 +02:00
Tristan B. Velloza Kildaire 71257f3926 View
- Added support for the `~=` operator overload

View (unittests)

- Use the operator overload
2024-04-30 21:35:19 +02:00
Tristan B. Velloza Kildaire 451fb668bd View (unittests)
- Added test for out-of-bounds indexing
2024-04-30 08:11:21 +02:00
Tristan B. Velloza Kildaire dba6ea59fa View
- Implemented `opSlice()`

View (unittests)

- Added test for `opSlice()`
2024-04-29 11:51:51 +02:00
Tristan B. Velloza Kildaire 0fb11d7c47 View (unittests)
- Fixed incorrect assertion
2024-04-29 11:46:26 +02:00
Tristan B. Velloza Kildaire 68d510418d View
- Initial work-in-progress for a new `View` type-buffer
2024-04-29 11:44:29 +02:00
2 changed files with 350 additions and 1 deletions

View File

@ -345,7 +345,6 @@ public struct ConfigEntry
{
return numeric();
}
else static if(__traits(isSame, T, string[]))
{
return array();

View File

@ -597,4 +597,354 @@ unittest
// Destroy the map (such that it ends the sweeper
destroy(map);
}
private struct Sector(T)
{
private T[] data;
this(T[] data)
{
this.data = data;
}
public T opIndex(size_t idx)
{
return this.data[idx];
}
public void opIndexAssign(T value, size_t index)
{
this.data[index] = value;
}
// Contract: Obtaining the length must be present
public size_t opDollar()
{
return this.data.length;
}
// Contract: Obtaining the length must be present
@property
public size_t length()
{
return opDollar();
}
public T[] opSlice(size_t start, size_t end)
{
return this.data[start..end];
}
public T[] opSlice()
{
return opSlice(0, opDollar);
}
// Contract: Rezising must be implemented
// TODO: This would then be the very reason for
// using ref actually, as resizing may only
// change a local copy when extding on
// the tail-end "extent" (SectorType)
// Actually should resizing even be done here?
}
// TODO: Make a bit better
private bool isSector(S)()
{
return __traits(hasMember, S, "opIndex");
}
import core.exception : ArrayIndexError;
import core.exception : RangeError;
public struct View(T, SectorType = Sector!(T))
if(isSector!(SectorType)())
{
private SectorType[] sectors;
// private
// Maybe current size should be here as we
// are a view, we should allow modofication
// but not make any NEW arrays
private size_t curSize;
private size_t computeTotalLen()
{
size_t l;
foreach(SectorType sector; this.sectors)
{
l += sector.opDollar();
}
return l;
}
public size_t opDollar()
{
return this.length;
}
public T opIndex(size_t idx)
{
// Within range of "fake" size
if(!(idx < this.length))
{
throw new ArrayIndexError(idx, this.length);
}
size_t thunk;
foreach(SectorType sector; this.sectors)
{
if(idx-thunk < sector.opDollar())
{
return sector[idx-thunk];
}
else
{
thunk += sector.opDollar();
}
}
throw new ArrayIndexError(idx, this.length);
}
public void opIndexAssign(T value, size_t idx)
{
// Within range of "fake" size
if(!(idx < this.length))
{
throw new ArrayIndexError(idx, this.length);
}
size_t thunk;
// TODO: Should be ref, else it is just a local struct copy
// could cheat if sector is never replaced, hence why it works
foreach(SectorType sector; this.sectors)
{
writeln(sector);
writeln("idx: ", idx);
writeln("thunk: ", thunk);
if(idx-thunk < sector.opDollar())
{
sector[idx-thunk] = value;
return;
}
else
{
thunk += sector.opDollar();
}
}
throw new ArrayIndexError(idx, this.length);
}
public T[] opSlice()
{
T[] buff;
foreach(SectorType sector; this.sectors)
{
buff ~= sector[];
}
// Trim to "fake" size
buff.length = this.curSize;
return buff;
}
public T[] opSlice(size_t start, size_t end)
{
// FIXME: This is lazy, do a check for up to where
// and actually make THIS the real implementation
return this.opSlice()[start..end];
}
private static bool isArrayAppend(P)()
{
return __traits(isSame, P, T[]);
}
private static bool isElementAppend(P)()
{
return __traits(isSame, P, T);
}
// Append
public void opOpAssign(string op, E)(E value)
if(op == "~" && (isArrayAppend!(E) || isElementAppend!(E)))
{
static if(isArrayAppend!(E))
{
add(value);
}
else
{
add([value]);
}
}
// Takes the data, constructs a kind-of SectorType
// and adds it
private void add(T[] data)
{
// Create a new sector
SectorType sec = SectorType(data);
// Update the tracking size
this.curSize += sec.length;
// Concatenate it to the view
this.sectors ~= SectorType(data);
}
@property
public size_t length()
{
return this.curSize;
}
@property
public void length(size_t size)
{
// TODO: Add support for sizing down
// TODO: Add support for sizing up
// TODO: Need we continuously compute this?
// ... we should have a tracking field for
// ... this
size_t actualSize = computeTotalLen();
// On successful exit, update the "fake" size
scope(success)
{
this.curSize = size;
}
// Don't allow sizing up (doesn't make sense for a view)
if(size > actualSize)
{
auto r = new RangeError();
r.msg = "Cannot extend the size of a view past its total size (of all attached sectors)";
throw r;
}
// If nothing changes
else if(size == actualSize)
{
// Nothing
}
// If shrinking to zero
else if(size == 0)
{
// Just drop everything
this.sectors.length = 0;
}
// If shrinking (arbitrary)
else
{
// Sectors from left-to-right to keep
size_t sectorCnt;
// Accumulator
size_t accumulator;
foreach(SectorType sector; this.sectors)
{
accumulator += sector.length;
sectorCnt++;
if(size <= accumulator)
{
break;
}
}
this.sectors.length = sectorCnt;
}
}
}
unittest
{
View!(int) view;
assert(view.opDollar() == 0);
try
{
view[1];
assert(false);
}
catch(ArrayIndexError e)
{
assert(e.index == 1);
assert(e.length == 0);
}
view ~= [1,3,45];
assert(view.opDollar() == 3);
assert(view.length == 3);
view ~= 2;
assert(view.opDollar() == 4);
assert(view.length == 4);
assert(view[0] == 1);
assert(view[1] == 3);
assert(view[2] == 45);
assert(view[3] == 2);
assert(view[0..2] == [1,3]);
// Update elements
view[0] = 71;
view[3] = 50;
// Set size to same size
view.length = view.length;
// Check that update is present
// and size unchanged
int[] all = view[];
assert(all == [71,3,45,50]);
// Truncate by 1 element
view.length = view.length-1;
all = view[];
assert(all == [71,3,45]);
// This should fail
try
{
view[3] = 3;
assert(false);
}
catch(RangeError e)
{
}
// This should fail
try
{
int j = view[3];
assert(false);
}
catch(RangeError e)
{
}
// Up-sizing past real size should not be allowed
try
{
view.length = view.length+1;
assert(false);
}
catch(RangeError e)
{
}
// Size to zero
view.length = 0;
assert(view.length == 0);
assert(view[] == []);
}