Supporting inout haystack in array-overload of findSplitBefore without template-bloat

Per Nordlöw per.nordlow at gmail.com
Sun Oct 27 14:29:01 UTC 2019


Is it possible to make this array-overload of findSplitBefore 
support `inout`-qualified `haystack` parameter and return type 
without using a templated `Result`?


auto findSplitBefore(T)(scope const T[] haystack, // TODO support 
inout?
                         scope const T needle)
{
     struct Result
     {
         private alias Haystack = typeof(haystack);
         private Haystack _haystack;
         private size_t _offset;

         inout(Haystack) pre() inout @trusted
         {
             return _haystack.ptr[0 .. _offset];
         }

         inout(Haystack) post() inout @trusted
         {
             if (_isMiss) { return _haystack[$ .. $]; }
             return _haystack.ptr[_offset .. _haystack.length];
         }

         bool opCast(T : bool)() const
         {
             return !_isMiss;
         }

         private bool _isMiss() const
         {
             return _haystack.length == _offset;
         }
     }

     foreach (const offset, const ref e; haystack)
     {
         if (e == needle)
         {
             return Result(haystack, offset);
         }
     }

     return Result(haystack, haystack.length);
}

///
@safe pure nothrow @nogc unittest
{
     const r = "a*b".findSplitBefore('*');
     assert(r);
     assert(r.pre == "a");
     assert(r.post == "*b");
}


This is my attempt so far


auto findSplitAfter(T)(scope inout(T)[] haystack, // TODO support 
inout?
                        scope const T needle) @trusted
{
     struct Result
     {
         private T[] _haystack;
         private size_t _offset;

         inout(T)[] pre() inout @trusted
         {
             if (_isMiss) { return _haystack[$ .. $]; }
             return _haystack.ptr[0 .. _offset + 1];
         }

         inout(T)[] post() inout @trusted
         {
             if (_isMiss) { return _haystack[0 .. $]; }
             return _haystack.ptr[_offset + 1 .. _haystack.length];
         }

         bool opCast(T : bool)() const @trusted
         {
             return !_isMiss;
         }

         private bool _isMiss() const @trusted
         {
             return _haystack.length == _offset;
         }
     }

     foreach (const offset, const ref e; haystack)
     {
         if (e == needle)
         {
             return inout(Result)(haystack, offset);
         }
     }

     return inout(Result)(haystack, haystack.length);
}

///
@safe pure nothrow @nogc unittest
{
     const r = "a*b".findSplitAfter('*');
     assert(r);
     assert(r.pre == "a*");
     assert(r.post == "b");
}


which results in the following interesting compiler error:


array_algorithm.d(506,12): Error: modify `inout` to `immutable` 
is not allowed inside `inout` function
     assert(r.pre == "a*");
            ^
array_algorithm.d(507,12): Error: modify `inout` to `immutable` 
is not allowed inside `inout` function
     assert(r.post == "b");
            ^
array_algorithm.d(514,5): Error: static assert:  
`is(typeof(r.pre()) == const(char)[])` is false
     static assert(is(typeof(r.pre()) == const(char)[]));



More information about the Digitalmars-d-learn mailing list