Letztes Wort loeschen



  • mr. wrong schrieb:

    void mrwrong(std::string& s)
    {
      const char x = ' ';
      __m128i zero = _mm_setzero_si128();
      __m128i cx16 = _mm_set1_epi8(x);
      const char *start=s.c_str(), *b = start + s.size();
      for (int i=s.size()%16;i--;)
        if (*--b == x)
          goto end;
      for (b -= 16;; b -= 16) {
        __m128i  x = _mm_loadu_si128((__m128i const *)b);
        unsigned u = _mm_movemask_epi8(_mm_cmpeq_epi8(zero, x));
        unsigned v = _mm_movemask_epi8(_mm_cmpeq_epi8(cx16, x)) & ~u & (u - 1);
        if (v) { b += __builtin_ctz(v); goto end; }
        if (__builtin_expect(b == start,0)) { return; }
      }
     end:
      s.erase(b - start);
    }
    

    👍



  • Das muss ich erst mal verdauen, da lernt man doch die Profis schätzen. 😮



  • bedenke aber, dass der Code mr. wongs code plattform- und compilerabhängig ist.
    Wenn es weiterhin unabhängig sein soll, musst du schon mit präprozessorcommandos etwas basteln, um im Notfall auf deine alte Methode zurückzuspringen.



  • Unabhängig vom OS sollte es schon sein. Ich programmiere mit dem Qt-Creator unter OSX und die Sachen sollten dann aber auch unter Linux, Windows und Android laufen.

    Nichts desto Trotz ist die Lösung von MrWrong schon beeindruckend. Ich habe früher auf dem Amiga mit dem Seka-Assembler so Demos programmiert und daher ist eine Restfaszination für die einzig reale Computersprache immer noch da.

    Mittlerweile bin ich aber über die vielen Abstraktionsebenen doch froh 😃

    EDIT: So, ohne Spezialfälle habe ich es jetzt so gelöst. Gibt es damit auch Probleme?

    _text.erase(_text.find_last_of(' '));
    


  • CppNeuland schrieb:

    EDIT: So, ohne Spezialfälle habe ich es jetzt so gelöst. Gibt es damit auch Probleme?

    _text.erase(_text.find_last_of(' '));
    

    Ja, string::erase() löst eine out_of_range exception aus falls im string kein Leerzeichen gefunden wird (find_last_of() == string::npos).

    - osdt



  • Nathan schrieb:

    mr. wrong schrieb:

    void mrwrong(std::string& s)
    {
      const char x = ' ';
      __m128i zero = _mm_setzero_si128();
      __m128i cx16 = _mm_set1_epi8(x);
      const char *start=s.c_str(), *b = start + s.size();
      for (int i=s.size()%16;i--;)
        if (*--b == x)
          goto end;
      for (b -= 16;; b -= 16) {
        __m128i  x = _mm_loadu_si128((__m128i const *)b);
        unsigned u = _mm_movemask_epi8(_mm_cmpeq_epi8(zero, x));
        unsigned v = _mm_movemask_epi8(_mm_cmpeq_epi8(cx16, x)) & ~u & (u - 1);
        if (v) { b += __builtin_ctz(v); goto end; }
        if (__builtin_expect(b == start,0)) { return; }
      }
     end:
      s.erase(b - start);
    }
    

    👍

    Ich dachte bis jetzt "goto" soll man nicht verwenden?


  • Mod

    mrwrong: 1531876 ns
    arcoth: 3441873 ns
    neuland: 5500253 ns
    [...]
    mrwrong: 968054  ns
    arcoth : 3047209 ns
    neuland: 4573583 ns
    mrwrong: 958147  ns
    arcoth : 3222022 ns
    neuland: 4567348 ns
    

    Die Ausgabe bekomme ich, wenn ich mrwrongs, CppNeulands neuesten und meinen Code, der im Übrigen - soweit ich sehe - plattformunabhängig ist, vergleiche. Am meisten unnötige Zeit schluckt wohl die Funktion

    qword qword_from( char const* p )
    {
    	return  *p
    	       | ( qword(p[1]) << 8 )
    	       | ( qword(p[2]) << 16 )
    	       | ( qword(p[3]) << 24 )
    	       | ( qword(p[4]) << 32 )
    	       | ( qword(p[5]) << 40 )
    	       | ( qword(p[6]) << 48 )
    	       | ( qword(p[7]) << 56 );
    }
    

    , dafür nimmt mrwrong in seiner Variante natürlich _mm_loadu_si128 . Wenn ich stattdessen die UB-Methode nehme,

    qword qword_from( char const* p )
    {
    	return *reinterpret_cast<qword const*>(p);
    }
    

    bekomme ich etwa

    mrwrong: 1502699 ns
    arcoth : 1395314 ns
    neuland: 7582803 ns
    [...]
    mrwrong: 981523  ns
    arcoth : 1093849 ns
    neuland: 4553076 ns
    mrwrong: 887963  ns
    arcoth : 1098256 ns
    neuland: 4938181 ns
    

    Ich dachte bis jetzt "goto" soll man nicht verwenden?

    Das ist nur eine Faustregel, um Spaghetti-Code zu vermeiden. Hier vereinfacht es den Code.



  • osdt schrieb:

    CppNeuland schrieb:

    EDIT: So, ohne Spezialfälle habe ich es jetzt so gelöst. Gibt es damit auch Probleme?

    _text.erase(_text.find_last_of(' '));
    

    Ja, string::erase() löst eine out_of_range exception aus falls im string kein Leerzeichen gefunden wird (find_last_of() == string::npos).

    - osdt

    Aja, na dann versuche ich es mal so:

    size_t pos = _text.find_last_of(' ');
            if ( pos != string::npos )
                _text.erase(pos);
    


  • Und wenn der ganze String ein Wort ist?



  • Spezialfälle habe ich jetzt nicht mit drin, aber in diesem Fall wird ja erase übersprungen. Die ganze Sache ist eh nur um das Command Pattern mal an einem konkreten Minimalbeispiel mir klar zu machen. Das wird also nie so irgendwie produktiv laufen.

    Ich hatte halt zwei Beispielklassen mit Text, eine kann Zeichen hinzufügen und das letzte Zeichen löschen und eine kann dies mit Worten tun. Und beim Wort löschen kam ich dann auf die erste Lösung hier...der Rest ist bekannt.


Anmelden zum Antworten