www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Supporting inout haystack in array-overload of findSplitBefore without

reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
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)[]));
Oct 27 2019
parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Sunday, 27 October 2019 at 14:29:01 UTC, Per Nordlöw wrote:
 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)[]));
A non-templated and less bloated but still suboptimal solution is to defined inlined overloads for the member functions, this case `pre()`: auto findSplitAfter_inout(T)(scope inout(T)[] haystack, scope const T needle) trusted { static struct Result { private T[] _haystack; private size_t _offset; auto pre() trusted { pragma(inline, true); if (_isMiss) { return _haystack[$ .. $]; } return _haystack.ptr[0 .. _offset + 1]; } auto pre() const trusted { pragma(inline, true); if (_isMiss) { return _haystack[$ .. $]; } return _haystack.ptr[0 .. _offset + 1]; } auto pre() immutable trusted { pragma(inline, true); if (_isMiss) { return _haystack[$ .. $]; } return _haystack.ptr[0 .. _offset + 1]; } auto post() const trusted { if (_isMiss) { return _haystack[0 .. $]; } return _haystack.ptr[_offset + 1 .. _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 inout(Result)(haystack, offset); } } return inout(Result)(haystack, haystack.length); } /// safe pure nothrow nogc unittest { auto r = "a*b".findSplitAfter_inout('*'); static assert(is(typeof(r.pre()) == string)); assert(r); assert(r.pre == "a*"); assert(r.post == "b"); }
Oct 27 2019
parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Sunday, 27 October 2019 at 14:57:29 UTC, Per Nordlöw wrote:
  safe pure nothrow  nogc unittest
 {
     auto r = "a*b".findSplitAfter_inout('*');
     static assert(is(typeof(r.pre()) == string));
     assert(r);
     assert(r.pre == "a*");
     assert(r.post == "b");
 }
Made it work! :) /** Array-overload for `findSplitAfter` with default predicate. * * See_Also: https://forum.dlang.org/post/dhxwgtaubzbmjaqjmnmq forum.dlang.org */ auto findSplitAfter(T)(scope inout(T)[] haystack, // TODO support inout? See_Also: https://forum.dlang.org/post/jtpchtddgenhjuwhqdsq forum.dlang.org scope const T needle) trusted { static struct Result { private T[] _haystack; private size_t _offset; pragma(inline, true): inout(T)[] pre() trusted inout { if (_isMiss) { return _haystack[$ .. $]; } return _haystack.ptr[0 .. _offset + 1]; } inout(T)[] post() trusted inout { if (_isMiss) { return _haystack[0 .. $]; } return _haystack.ptr[_offset + 1 .. _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 inout(Result)(haystack, offset); } } return inout(Result)(haystack, haystack.length); } /// safe pure nothrow nogc unittest { char[] haystack; auto r = haystack.findSplitAfter('*'); static assert(is(typeof(r.pre()) == char[])); static assert(is(typeof(r.post()) == char[])); } /// safe pure nothrow nogc unittest { const(char)[] haystack; auto r = haystack.findSplitAfter('*'); static assert(is(typeof(r.pre()) == const(char)[])); static assert(is(typeof(r.post()) == const(char)[])); } /// safe pure nothrow nogc unittest { auto r = "a*b".findSplitAfter('*'); static assert(is(typeof(r.pre()) == string)); static assert(is(typeof(r.post()) == string)); assert(r); assert(r.pre == "a*"); assert(r.post == "b"); }
Oct 27 2019