Array Klasse



  • Hallo Leute!

    Ich hatte gestern eine Idee für eine Arrayklasse und habe sie nun mal provisorisch implementiert.

    Die Idee ist, dass man über einen Generator das Array nach seinen Wünschen anpassen kann. Diese Idee ist aus 'Generative Programming' geklaut.

    Ich überlege nur, was man noch 'customizen' könnte...
    Und vorallem: was haltet ihr von diesen Ansatz generell?

    Der Code: array.hpp
    Ich ahbe den gestern Nacht auf meinem VC7 hingepfuscht - es kann also durchaus non-Standard Code sein.
    Und es sind n paar kleine VC7 Workarounds drinnen 😞

    Hier ein kleines Programm:

    #include "array.hpp"
    #include <iostream>
    using namespace std;
    
    int main()
    {
        ts::variableArray<int>::type a;
        a.push_back(7);
        a.push_back(10);
        a.push_back(9);
        a.push_front(1);
        for(int i=0; i<a.size(); ++i)
        {
            cout<<a[i]<<endl;
        }
    
        ts::variableArray<int>::type b(a);
        ts::fixedArray<int, 4>::type c(b);
        cout<<endl;
        for(int j=0; j<c.size(); ++j)
        {
            cout<<c[j]<<endl;
        }
        ts::ArrayConfig::ArrayGenerator
          <int, ts::ArrayConfig::variableSize<int>, ts::ArrayConfig::pod, ts::ArrayConfig::poly>::type
            d; //direkt den Generator verwenden
        d=a;
        cout<<endl;
        for(int l=0; l<d.size(); ++l)
        {
            cout<<d[l]<<endl;
        }
    }
    

    ElementType gibt an, ob es sich um eine 'normale' Klasse handelt, oder einen POD Typen.
    Morphology gibt an, ob nur ein bestimmter Type in das Array hinein darf oder ob es polymorph verwendet werden darf.
    sizetype gibt an, ob es sein variables oder fixes Array ist.
    Und Type ist der Element Typ.

    Ich überlege momentan, ob man für Zeiger noch eine Option einführt, so dass Zeiger richtige behandelt werden (delete). Aber momentan fällt mir dazu keine effektive Implementierung ein 😞

    Gibt es sonst noch Optionen die man einstellen können sollte? Oder ist das Design sowieso mies?

    Die Namen werde ich demnächst mal überdenken - denn mit einigen bin ich nicht zufrieden...

    ausserdem muss ich noch CallTraits einführen.

    danke für eure Kommentare! 👍



  • [OT]Soll nicht gegen Dich gerichtet sein, aber das heißt eigentlich "provisorisch" - ich glaube es ist besser ich sag Dir sowas als irgendwelche potentiellen Auftraggeber... (Ist sonst eigentlich nicht meine Art Rechtschreibfehler auszubessern aber ich dachte das könnte Dich interessieren.)[/OT]



  • thx!

    Das kommt davon, wenn man beim Schreiben nicht mitdenkt!

    danke! 👍



  • [OT] Sorry, dass ich hier ebenfalls mit OT komme, aber was heißt POD? Habe das
    in den letzten 5min 2mal gelesen. [/OT]



  • @SirLant
    Viele Fragen kann man leicht mit einem Blick in die FAQ beantworten.



  • Damit ist Shade´s Frage aber immer noch nicht beantwortet.

    Ihr driftet immer viel zu sehr nach OT ab!



  • ts::ArrayConfig::ArrayGenerator 
          <int, ts::ArrayConfig::variableSize<int>, ts::ArrayConfig::pod, ts::ArrayConfig::poly>::type 
            d;
    

    was macht das genau? wir da ein array erstellt welches polymorphe PODs verwalten soll und seine grösse dynamisch anpasst?



  • japro schrieb:

    ts::ArrayConfig::ArrayGenerator 
          <int, ts::ArrayConfig::variableSize<int>, ts::ArrayConfig::pod, ts::ArrayConfig::poly>::type 
            d;
    

    was macht das genau? wir da ein array erstellt welches polymorphe PODs verwalten soll und seine grösse dynamisch anpasst?

    ja. Wobei das polymorph bei int keinen Sinn ergibt. Polymorph und Monomorph macht nur bei Zeigern sinn.

    Der Generator hat eben den Vorteil, dass man sich nicht um die Policies selber kümmern muss (es aber kann: denn man muss ja den Generator nicht verwenden und kann die typedefs ja auch selber machen)

    Nur mit dem variable Size habe ich n Problem. Ich denke ich werde das in ein
    unsigned sizetype
    umwandeln
    mittels
    int const variableSize = 0;
    kann man dann sagen, dass man eine variable größe will. und mittels
    20 hätte man dann ein fixed array 🙂

    weiters funktioniert CopySwap() nicht korrekt.
    muss ich heute abend verbessern.

    die neue version würde dann so aussehen:

    ts::ArrayConfig::ArrayGenerator 
          <int, ts::ArrayConfig::variableSize, ts::ArrayConfig::pod, ts::ArrayConfig::poly>::type 
            d;
    

    statt mono und poly -morph könnte man noch ein nonmorph für nicht Zeiger typen einführen... oder wäre das sinnlos, da poly ja das selbe wie nonmorph machen würde...



  • Die neue Version ist online 🙂
    array.hpp

    Das swap sollte jetzt funktionieren und ausserdem sind n paar neue Methoden hinzugekommen, sowie ein kleiner performance bug bei op= wurde ausgebessert.

    Ich denke, dass ich Zeiger hinzunehmen werde - nämlich so, dass die array klasse selber die Zeiger verwalten kann - das würde smartpointer ersparen, die dann kein langsames ref counting oder ähnliches verwenden müssten.

    weiters denke ich, dass man range checks noch hinzufügen könnte. also dass der user selber sagen kann, welche exception fliegt und vorallem, ob op[] überhaupt etwas in dieser richtung machen soll... das würde dann die Methode at() ersparen, die sowieso niemand verwendet 🙂

    habt ihr noch vorschläge?

    ihr könnt auch kritik anbringen!
    ich weiss, der code ist nicht dokumentiert, aber vielleicht erbarmt sich ja doch jemand ihn durchzuackern? die nächste version wird aber kommentare haben: versprochen.

    [nachtrag:
    angepasstes code beispiel:

    #include "array.hpp"
    #include <iostream>
    using namespace std;
    
    int main()
    {
        ts::variableArray<int>::type a;
        a.push_back(7);
        a.push_back(10);
        a.push_back(9);
        a.push_front(1);
        for(int i=0; i<a.size(); ++i)
        {
            cout<<a[i]<<endl;
        }
    
        ts::variableArray<int>::type b(a);
        ts::fixedArray<int, 4>::type c(b);
        cout<<endl;
        for(int j=0; j<c.size(); ++j)
        {
            cout<<c[j]<<endl;
        }
        ts::ArrayConfig::ArrayGenerator
            <int, ts::ArrayConfig::dynamic, ts::ArrayConfig::normal, ts::ArrayConfig::poly>::type
                d;
        d=a;
        cout<<endl;
        for(int l=0; l<d.size(); ++l)
        {
            cout<<d[l]<<endl;
        }
    }
    

    ]



  • So, wieder eine neue Version.

    Diesmal hat sich viel geändert: neben ein paar bugfixen gibt es jetzt unterstützung für Zeiger!

    array.hpp

    Hier ein kleines Test programm:

    #include "array.hpp"
    #include <iostream>
    using namespace std;
    
    class Test
    {
    public:
        Test() { cout<<"ctor\n"; ctor++; }
        Test(Test const&) { cout<<"cctor\n"; ctor++; }
        ~Test() { cout<<"dtor\n";  dtor++;}
    
        static int ctor;
        static int dtor;
    };
    int Test::ctor=0;
    int Test::dtor=0;
    
    int main()
    {
        {
            //important: Test must not be a pointer!
            ts::variablePtrArray<Test>::type Arr;
            Arr.push_back(new Test());
        }
        cout<<endl<<Test::ctor<<" : "<<Test::dtor<<endl<<endl;
        //ausgabe: "2 : 2" - 2 ctors und 2 dtors calls :)
    
        ts::variableArray<int>::type a;
        a.push_back(7);
        a.push_back(10);
        a.push_back(9);
        a.push_front(1);
        for(int i=0; i<a.size(); ++i)
        {
            cout<<a[i]<<endl;
        }
    
        ts::variableArray<int>::type b(a);
        ts::fixedArray<int, 4>::type c(b);
        cout<<endl;
        for(int j=0; j<c.size(); ++j)
        {
            cout<<c[j]<<endl;
        }
        ts::ArrayConfig::ArrayGenerator
            <int, ts::ArrayConfig::dynamic, ts::ArrayConfig::normal, ts::ArrayConfig::asserting, ts::ArrayConfig::poly>::type
                d;
        d=a;
        cout<<endl;
        for(int l=0; l<d.size(); ++l)
        {
            cout<<d[l]<<endl;
        }
    }
    

    die unterstützung für Zeiger ist n bisschen kompliziert implementiert, denn ich wollte die geschwindigkeit des bestehenden codes nicht verlangsamen.
    ein std::copy bzw. std::memcpy ist natürlich schneller als eine Schleife - deshalb gibt es für die Kopierer und Allokatoren jeweils auch eine Pointer-Variante.

    Das macht die Sache zwar etwas komplexer, aber dafür ist es schön schnell...



  • neue Version: array.hpp

    kleine Bugfixes und ein bisschen das Interface an die STL angepasst.
    IfThenElse wurde ausgelagert (if.hpp).

    Ich habe auch ein paar kleine Performancetests gegen die VC++7 Standard Library laufen lassen. Mein variableArray war immer eine spur schneller - allerdings waren die Beispiele nicht praxisrelevant.

    Aber ich bin zufrieden, denn mein variableArray ist also nicht signifikant langsamer als die VC++7 STL. Wenn jemand gegen STLPort testen könnte?

    Ich glaube ich werde bei Zeiten mal eine handvall anderer Container auf diese Art implementieren...

    Schade dass es so wenig Antworten von euch gibt - aber wenigstens keine Negativen. Also nehme ich an, dass es kein allzugroßer Käse ist, den ich hier mache.



  • Hallo!

    Um ganz ehrlich zu sein habe ich für meinen Teil hier nur nicht geantwortet weil ich stark bezweifle dass ich Dir helfen könnte.

    edit: Ich werde aber gerne im Laufe des Tages mal ein paar Tests mit STLport und gcc machen und dann die Resultate posten!



  • @nman:
    thx.

    Es war ja auch kein Vorwurf, sondern eine Feststellung 🙂

    btw: neue Version: array.hpp und if.hpp

    Ich habe neben ein paar bugfixes auch eine Verbesserung vorgenommen: eine Grow-Optionen.

    Man kann nun angeben ob das Array schnell wachsen soll (also Speicher 'verschwenden' um wenige Allokationen zu haben), normal wachsen soll (ungefähr so wie bisher) oder langsam wachsen soll (keinen Speicher zuviel allokieren -> Speicher sparen, dafür mehr Allokationen)

    ich hoffe es läuft auf dem gcc - denn momentan entwickle ich nur auf dem VC++7 😞



  • Hallo!
    Der gcc will das nicht kompilieren, ich habe die Fehlermeldungen mal in eine Textdatei umgeleitet und hochgeladen: errors.text



  • Ich habe gerade die Version für gcc (3.2.3) und Comeau 4.3.3 BETA fertig 🙂
    blöde typenames und templates und this-> haben gefehlt...

    Danke für die Fehlerliste. Theoretisch müsste es jetzt passen!



  • Mein g++ kompiliert das jetzt tatsächlich.
    Jetzt stellt sich mir nur die Frage wie ich das testen soll, immerhin habe ich kein VC++7 als Vergleichsmöglichkeit...



  • nman schrieb:

    Mein g++ kompiliert das jetzt tatsächlich.
    Jetzt stellt sich mir nur die Frage wie ich das testen soll, immerhin habe ich kein VC++7 als Vergleichsmöglichkeit...

    Für mich sind nur die Ergebnisse im Vergleich zu anderen Standardlibraries interessant. Also schreib n kleines Programm, zB sowas:

    #include "array.hpp"
    
    #include <windows.h>
    #include <vector>
    #include <iostream>
    using namespace std;
    
    int const loop=10000000;
    
    int stdVector()
    {
      vector<int> vec;
      int size=0;
    
      for(int i=0; i<loop; ++i)
      {
        vec.push_back(i);
        size+=vec.size();
      }
    
      while(!vec.empty())
      {
        vec.pop_back();
        size+=vec.size();
      }
      return size;
    }
    
    int myVector()
    {
      ts::variablePodArray<int>::type vec;
      int size=0;
    
      for(int i=0; i<loop; ++i)
      {
        vec.push_back(i);
        size+=vec.size();
      }
    
      while(!vec.empty())
      {
        vec.pop_back();
        size+=vec.size();
      }
      return size;
    }
    
    int main()
    {
      cout<<"start\n";
      int size;
      DWORD start=GetTickCount();
      size=stdVector();
      DWORD end=GetTickCount();
      cout<<size<<endl;
      cout<<end-start<<endl;
      start=GetTickCount();
      size=myVector();
      end=GetTickCount();
      cout<<size<<endl;
      cout<<end-start<<endl;
    }
    

    und schau nach, wie sich mein Array gegen deine STL verhält.
    Auf meinem gcc (MinGW 3.2.3) schauts momentan schlecht aus 😞

    Wenn du auch die Standard STL hast die beim gcc dabei ist, dann Danke für die Mühe - aber die habe ich jetzt auch.

    Wenn du STLPort oder ähnliches hast - nur her mit den Tests 🙂



  • Bei meinem Test hängt alles an von Grower ab. Wenn er schnellt wächst ist meine Version schneller, wenn ich langsamer wachse, dann die STL.

    Ich muss mich wohl mal eingehender mit einem passenden Wachstumsalgo rumschlagen. Aber das pop_back() ist bei mir schneller als bei der STL - wie das wohl kommt?



  • Shade Of Mine schrieb:

    Für mich sind nur die Ergebnisse im Vergleich zu anderen Standardlibraries interessant. [...] schau nach, wie sich mein Array gegen deine STL verhält.

    Ah OK, ich dachte Du willst wissen wie sich die Performance mit unterschiedlichen Compilern verändert.

    Wenn du auch die Standard STL hast die beim gcc dabei ist, dann Danke für die Mühe - aber die habe ich jetzt auch.

    Wenn du STLPort oder ähnliches hast - nur her mit den Tests 🙂

    Ich habe auch STLport, muss aber wieder mal updaten, meine Version ist nicht mehr ganz taufrisch...



  • Hm, beim STLport kompilieren swappt mein Rechner leider so schlimm dass er absolut unbenutzbar wird, muss wohl noch etwas warten... 😞

    edit: Nachdem ich allerdings schon begonnen hatte die Zeit zu stoppen hier trotzdem das (unnütze) Ergebnis:

    nman: ~/c++/shadesArray > uname -a
    Linux method 2.6.0 #2 Mon Dec 22 23:45:22 CET 2003 i686 AMD Athlon(tm) Processor AuthenticAMD GNU/Linux
    nman: ~/c++/shadesArray > gcc -dumpversion
    3.2.3
    nman: ~/c++/shadesArray > echo $CXXFLAGS
    -march=athlon -O2 -pipe -fomit-frame-pointer -w
    nman: ~/c++/shadesArray > g++ -o stdArray stdArray.cpp ${CXXFLAGS}
    nman: ~/c++/shadesArray > g++ -o shadesArray shadesArray.cpp ${CXXFLAGS}
    nman: ~/c++/shadesArray > time ./stdArray
    276447232
    real    0m1.866s
    user    0m0.956s
    sys     0m0.308s
    nman: ~/c++/shadesArray > time ./shadesArray
    276447232
    real    0m6.878s
    user    0m3.947s
    sys     0m0.807s
    nman: ~/c++/shadesArray >
    

Log in to reply