www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - SlicedString Length

reply Salih Dincer <salihdb hotmail.com> writes:
Hi,

I have a string wrapper called SlicedString. What it does is very 
simple: Returning each piece as a slice with a assured separator 
at compile time by used indexOf() ! Here it is:

```d
struct SlicedString(string E)
{
   long index, back, next = -1;
   string data;

   auto length() const
   {
     import std.array : split;
     import std.range : walkLength;
     return data.split(E).walkLength;
   }

   auto popIndex(ref SlicedString!E range)
   {
     scope(exit) range.popFront();
     return [range.back, range.next];
   }

   auto elementsPos()
   {
     long[][] result;
     auto r = SlicedString!E(index, back, next, data);

     while(!r.empty)
     {
       result ~= popIndex(r);
     }
     return result;
   }

   bool empty() { return index == 0; }
   auto front() { return data[back..next]; }
   void popFront()
   {
     import std.string : find = indexOf;
     --index;
     back = ++next;
     next = data.find(E, next);
     if(next == -1)
     {
       next = data.length;
     }
   }
}

auto sliceOff(string E = " ")(string data)
{
   SlicedString!E s;
   s.data = data;
   s.popFront();

   return s;
}

// UNIT TESTS:

void main()
{
   auto str = "abc def ghi";
   auto slc =  str.sliceOff;

   auto len = slc.length;
   slc.index = len;

   import std.stdio, std.algorithm: equal;
   assert(slc.equal(["abc", "def", "ghi"]));

   // Print range:
   foreach(s; slc) s.write;
   writeln;

   // Print Elements Position
   slc.elementsPos.writeln;
   slc.elementsPos.writeln;
}
```

The unit tests work as I want, but I find calculating the length 
with split() too expensive; despite walkLength()...


Is there a more accurate method? Last year, Ali Çehreli told me 
that splitter() was also possible, but then he did something with 
map(). I really don't understand these!

Thanks...

SDB 79
Oct 20 2023
parent Salih Dincer <salihdb hotmail.com> writes:
Good news!

I collected them in a template with the condition of running 
split() once at compile time.  The result seems perfect?  What 
are your thoughts?

```d
void main()
{
   auto slc = sliceOff!"abc def ghi";

   auto len = slc.length;
   slc.index = len;

   import std.stdio, std.algorithm: equal;
   assert(slc.equal(["abc", "def", "ghi"]));

   foreach(s; slc) s.write;
   writeln; // abcdefghi

   // Push Test
   with(slc)
   {
     string test = "jkl";
     push(test);

     auto p = elementsPos[$ - 1];
     assert(data[p[0]..p[1]] == test);
   }

   foreach(s; slc) s.write;
   writeln; // abcdefghijkl

   auto tmp = slc.dup;
   assert(tmp.front == "abc");
   tmp.popFront;
   assert(slc.front == "abc");
   assert(tmp.front == "def");
}

template sliceOff(string STR, string SEP = " ")
{
   auto sliceOff()
   {
     SlicedString s;
     s.popFront();
     return s;
   }

   import std.array : split;
   import std.range : walkLength;
   enum LEN = STR.split(SEP).walkLength;

   struct SlicedString
   {
     long index, back, next = -1;
     size_t len = LEN;
     string data = STR;

     auto push(string data)
     {
       this.data ~= SEP ~ data;
       len++;
       index++;
     }

     auto elementsPos()
     {
       long[][] result;
       auto r = this.dup;
       while(!r.empty)
       {
         result ~= [r.back, r.next];
         r.popFront();
       }
       return result;
     }

     alias dup = save;
     auto save() { return this; }
     auto length() { return len; }
     bool empty() { return index == 0; }
     auto front() { return data[back..next]; }
     void popFront()
     {
       import std.string : find = indexOf;
       --index;
       back = ++next;
       next = data.find(SEP, next);
       if(next == -1)
       {
         next = data.length;
       }
     }
   }
}
```

SDB 79
Oct 20 2023