December 12, 2021

On Sunday, 12 December 2021 at 08:58:29 UTC, Ola Fosheim Grøstad wrote:

>
    this(string s)@trusted{
        begin = s.ptr;
        end = s.ptr + s.length;
    }

}

Bug, it fails if the string ends or starts with ';'.

Fix:

        this(string s)@trusted{
            begin = s.ptr;
            end = s.ptr + s.length;
            while(begin!=end && *begin==stripchar) begin++;
            while(begin!=end && *(end-1)==stripchar) end--;
        }
December 12, 2021

Of course, since it is easy to mess up and use ranges in the wrong way, you might want to add asserts. That is most likely helpful to newbies that might want to use your kickass library function:

auto helpfuldeatheater(char stripchar)(string str) {
	struct voldemort {
        immutable(char)* begin, end;
        bool empty(){ return begin == end; }
        char front(){ assert(!empty); return *begin; }
        char back()@trusted{ assert(!empty); return *(end-1); }
        void popFront()@trusted{
			assert(!empty);
    		while(begin != end){begin++; if (*begin != stripchar) break; }
        }
        void popBack()@trusted{
            assert(!empty);
            while(begin != end){end--; if (*(end-1) != stripchar) break; }
        }
        this(string s)@trusted{
            begin = s.ptr;
            end = s.ptr + s.length;
            while(begin!=end && *begin==stripchar) begin++;
            while(begin!=end && *(end-1)==stripchar) end--;
        }
	}
    return voldemort(str);
}
December 13, 2021
On Saturday, 11 December 2021 at 09:25:37 UTC, Ola Fosheim Grøstad wrote:
>
> ```putchar(…)``` is too slow!
>
>

On planet Mars maybe, but here on earth, my computer can do about 4 billion ticks per second, and my entire program (using putchar) takes only 3084 ticks.


December 13, 2021
On Monday, 13 December 2021 at 05:46:06 UTC, forkit wrote:
> On Saturday, 11 December 2021 at 09:25:37 UTC, Ola Fosheim Grøstad wrote:
>>
>> ```putchar(…)``` is too slow!
>>
>>
>
> On planet Mars maybe, but here on earth, my computer can do about 4 billion ticks per second, and my entire program (using putchar) takes only 3084 ticks.

Can I borrow a couple of your ticks?
December 13, 2021

On Friday, 10 December 2021 at 18:47:53 UTC, Stanislav Blinov wrote:

>

Threshold could be relative for short strings and absolute for long ones. Makes little sense reallocating if you only waste a couple bytes, but makes perfect sense if you've just removed pages and pages of semicolons ;)

Like this?

@safe:

string prematureoptimizations(string s, char stripchar) @trusted {
    import core.memory;
    immutable uint flags = GC.BlkAttr.NO_SCAN|GC.BlkAttr.APPENDABLE;
    char* begin = cast(char*)GC.malloc(s.length+1, flags);
    char* end = begin + 1;
    foreach(c; s) {
        immutable size_t notsemicolon = c != stripchar;
        // hack: avoid conditional by writing semicolon outside buffer
        *(end - notsemicolon) = c;
        end += notsemicolon;
    }
    immutable size_t len = end - begin - 1;
    begin = cast(char*)GC.realloc(begin, len, flags);
    return cast(string)begin[0..len];
}

void main() {
    import std.stdio;
    string str = "abc;def;ab";
    writeln(prematureoptimizations(str, ';'));
}

December 23, 2021

On Monday, 13 December 2021 at 09:36:57 UTC, Ola Fosheim Grøstad wrote:

>
@safe:

string prematureoptimizations(string s, char stripchar) @trusted {
    import core.memory;
    immutable uint flags = GC.BlkAttr.NO_SCAN|GC.BlkAttr.APPENDABLE;
    char* begin = cast(char*)GC.malloc(s.length+1, flags);
    char* end = begin + 1;
    foreach(c; s) {
        immutable size_t notsemicolon = c != stripchar;
        // hack: avoid conditional by writing semicolon outside buffer
        *(end - notsemicolon) = c;
        end += notsemicolon;
    }
    immutable size_t len = end - begin - 1;
    begin = cast(char*)GC.realloc(begin, len, flags);
    return cast(string)begin[0..len];
}

void main() {
    import std.stdio;
    string str = "abc;def;ab";
    writeln(prematureoptimizations(str, ';'));
}

It seems faster than algorithms in Phobos. We would love to see this in our new Phobos.

enum str = "abc;def;gh";
enum res = "abcdefgh";

void main()
{
  void mallocReplace()
  {
    import core.memory;

    immutable uint flags =
      GC.BlkAttr.NO_SCAN|
      GC.BlkAttr.APPENDABLE;

    char* begin = cast(char*)GC.malloc(str.length+1, flags);
    char* end = begin + 1;

    foreach(c; str)
    {
      immutable size_t f = c != ';';
      *(end - f) = c;
      end += f;
    }
    immutable size_t len = end - begin - 1;
    begin = cast(char*)GC.realloc(begin, len, flags);

    assert(begin[0..len] == res);
  }

  void normalReplace()
  {
    import std.string;

    string result = str.replace(';',"");
    assert(result == res);
  }

  void delegate() t1 = &normalReplace;
  void delegate() t2 = &mallocReplace;

  import std.stdio : writefln;
  import std.datetime.stopwatch : benchmark;

  auto bm = benchmark!(t1, t2)(1_000_000);

  writefln("Replace: %s msecs", bm[0].total!"msecs");
  writefln("Malloc : %s msecs", bm[1].total!"msecs");
}/* Console Out:
Replace: 436 msecs
Malloc : 259 msecs
*/
December 23, 2021

On Thursday, 23 December 2021 at 07:14:35 UTC, Salih Dincer wrote:

>

It seems faster than algorithms in Phobos. We would love to see this in our new Phobos.

  void mallocReplace()
>

void normalReplace()
string result = str.replace(';',"");

}/* Console Out:
Replace: 436 msecs
Malloc : 259 msecs
*/

You're comparing apples and oranges. When benchmarking, at least look at the generated assembly first.

replace is not in Phobos, it's a D runtime vestige. It's not getting inlined even in release builds with lto, whereas that manual version would. Also, benchmark with runtime strings, not literals, otherwise the compiler might even swallow the thing whole.

What you're benchmarking is, basically, inlined optimized search in a literal versus a function call.

December 23, 2021

On Thursday, 23 December 2021 at 07:14:35 UTC, Salih Dincer wrote:

>

It seems faster than algorithms in Phobos. We would love to see this in our new Phobos.

>

Replace: 436 msecs
Malloc : 259 msecs
*/

It seems because MallocReplace is cheating a lot:

  • it is not called through another function like replace is called;
  • accesses directly the constant str;
  • assumes that it has a single character to replace;
  • assumes that the character will be deleted not replaced with something;
  • assumes that the character is always ';'
  • assumes that the replacing string is not bigger than the replaced one, so it knows exactly how much space to allocate;
  • does not have any parameter, at least on x86 this means that there is no arg pushes when it's called.
  • does not return a string, just compares its result with another constant;

Since we already know all this stuff, we can go further :)

string superFast()
{
    enum r = str.replace(";", "");
    return r;
}

>

Replace: 436 msecs
Malloc : 259 msecs
SuperFast: 0 msecs

December 23, 2021

On Thursday, 23 December 2021 at 16:13:49 UTC, Stanislav Blinov wrote:

>

You're comparing apples and oranges.
When benchmarking, at least look at
the generated assembly first.

I looked now and you're right. Insomuch that it should be eggplant not apple, banana not orange...:)

Because it's an irrelevant benchmarking!

Thank you all...

1 2 3 4 5
Next ›   Last »