das Stream-projekt



  • prolog(kann übersprungen werden):
    auch für den Otze wirds nun zeit in die böse welt rauszutreten, und mal sein erstes größeres projekt zu starten, viel theorie liegt hinter ihm, nun will er mal das ausprobieren, was er in fast einem Jahr(was? ist das schon solange her?) gelernt hat

    thema(sollte nicht übersprungen werden 😃 ):

    (eine weitere)Einleitung:
    ich will hier erstmal meine Überlegungen schildern, die mich hinterher auf den ansatz bringen sollten, den ich vorstellen wollte:

    Dieses projekt soll eine Art streambibliothek werden, wie die c++ streams, aber mit einer leicht geänderten gewichtung,etwas weniger von der lokalisierung weg zur streammanipulation.

    Was meine ich damit? nun, wenn man die streams betrachtet wie sie vom standard implementiert werden, dann sieht man, dass es zwar sehr einfach ist, daten auf ein neues "medium" auszugeben,sei es netzwerk, console,datei,archiv,oder ein editfeld der winapi,aber das verändern des frontends ist sehr schwierig. Der Frontend ist auf die lokalisierung spezialisiert,dh ein stream kann gut auf länderspezifische gegebenheiten spezialisiert werden,wie zb bei zahlen:

    1,000,000.55 US
    1.000.000,55 Germany
    

    ok, das geht gut, aber wie stehts mir verschlüsselungen, packverfahren oder anderen manipulativen einwirkungen auf den stream?

    einen stream so zu modifizieren, dass er zahlen nichtmehr modifiziert ist schon ziemlich umständlich, num_get/num_put zu überladen ist zwar in dem fall nicht schwierig, aber auch nicht sicher, da man nicht die gewissheit hat, dass keines der objekte die in die stream schreiben, den stream nicht kurzzeitig wieder modifizieren, sodass die mit mühevoller kleinarbeit erstellten facets ihre aufgaben nicht erfüllen können. Ok, die situation wird wohl nur selten vorkommen, fakt ist aber, dass man sich nicht sicher sein kann, solange man nicht alle komponenten selber schreibt(und wer tut das schon?).

    anderes beispiel:
    Huffman mithilfe von facets? nein, ich bin dumm, aber nicht so dumm, das zu versuchen :D, es ist schlichtweg unmöglich(ich habe auf meinen streifzug durch google aber einige ansätze zum encoden direkt in streams gesehen, ist also nicht so, dass es nicht gemacht wird,ein dynamischer huffmann zb kann sehr gut funktionieren).

    dazu kommt noch, dass es nicht wirklich einfach ist, die facets zu benutzen, sie sind ein thema für sich, und viele programmierer scheuen sich davor(auch wenn ich wie gesagt meinen bitstream hinterher mit facets implementiert hab, spaß gemacht hats mir nicht, und schön wars erstrecht nicht).

    ich hab ja grad das Huffman verfahren angesprochen, dass es mit facets nur schlecht bis garnicht geht sollte klar sein,wieso nicht mit dem buffer versuchen?

    hierzu kann ich einen thread aus dem jahre 2002 hier aus dem Forum empfehlen,indem ein projekt zum thema "kryptostream" vorgestellt wurde, was daraus wurde, weis ich nicht, auf einmal schiens sich totgelaufen zu haben.

    auch wenns da nur um verschlüsselung ging,wenn das packverfahren wie dort auf dateibasis abläuft, gibts da keine großen probleme.
    Aufjedenfall: die verschlüsselung wurde dort mithilfe von doublebuffering im im stream enthaltenem buffer durchgeführt. Die idee ist ja nicht schlecht,aber was ist,wenn ich einen einfachen kompressions/verschlüsselungs-algorithmus habe, der sogar netzwerktauglich ist? ich müsste also einen komplett neuen buffer schreiben, wenn doch wahrscheinlich ein filter genügt hätte.

    Ergebnisse:
    ok, etwas neues muss her, es sollte einfach und schnell erweiterbar sein, und flexibel genug sein, dass man "mal eben" was zwischenschieben kann.
    Ein weiterer punkt war auch, dass abgespeckt werden sollte, ein schlankes und einheitliches system ist viel einfacher zu verstehen(also:die lokales fliegen raus 😃 )

    am anfang meiner überlung standen erstmal die basisklassen, sie garantierten eine fast beliebige erweiterbarkeit, die es einfach machen sollte, etwas vollkommen neues zu integrieren

    BaseStream
              /  \
             /    \
     BaseIstream   BaseOstream
           |           |
     IstreamHolder  OstreamHolder
    

    Basestream ist für ganz triviale sachen zuständig: verwalten der traits und des buffers,und der von den standardströmen bekannten exceptionmask,und die standardabfragen wie bad/good oder eof,etc.
    BaseIstream bzw BaseOstream verwalten dann nurnoch die ein bzw ausgabe, dh op<<//>> read/write get/put getline/writeline.

    IstreamHolder und OstreamHolder haben einen zweck, den ich erst später erklären werde, aufjedenfall können sie einen istream/ostream halten.

    Der buffer soll selbst größtenteils so sein, wie man ihn bereits kennt, nur ohne die locales ;).

    nun fragt ihr euch: wo bleiben die mutatoren? auch sie fallen etwas meiner vereinfachungslust zum opfer, sie verhalten sich etwas anders(aber alles zu seiner zeit).

    Das eigentliche große Konzept, worauf dieser Streamansatz basiert ist die verknüpfung vieler kleiner streambausteine, mit anderer worten: streams sind zu neuen streams verknüpfbar(genau, mithilfe von den beiden Holdern).

    Die verknüpfung findet wieder über die operatoren<< und >> statt,und jeder teilstream kann seine eigene spezielle aufgabe erledigen, aber ein beispiel sagt oft mehr als tausend worte:

    XorCrypt.SetBuffer(NetworkBuffer);
    XorCrypt<<Encoder<<Locale<<EinKomplexerDatentyp;
    
    //oder:
    OstreamHolder Stream=(XorCrypt<<Encoder<<Locale);
    Stream<<EinKomplexerDatentyp;
    Stream[0].SetBuffer(OfStreamBuffer);//verändern des buffers von XorCrypt
    Stream<<EinAndererKomplexerDatentyp;//diesmal ausgabe in eine datei
    

    die ersten 4 objekte sind streamobjekte, und das letzte ist halt ein komplexer datentyp,der zuerst mithilfe der locale transformiert,dann gepackt, dann verschlüsselt, und am ende ins netzwerk rausgeschleußt wird.

    Der punkt ist halt, dass jedes objekt von sich aus ein eigener stream und zu jeder zeit transformierbar ist(klar, man sollte nicht unbedingt in Locale den buffer ändern, weil dann bei meiner bisherigen planung die connection zum rest flöten ginge...),

    Fazit:die streams werden zu einem multifunktionshammer ausgebaut, bei dem man schafft,Kopf und den den hammer benutzenden arbeiter problemlos austauschen kann. Jeder teil ist alleine "überlebensfähig",und jedes teil tut genau eine sache.

    natürlich ist das nur ein früher ansatz und es sind noch einige sachen nicht so ganz sicher, aber bevor ich (noch) mehr arbeit darein stecke, wollte ich euch mal fragen, was ihr:

    1. von der idee an sich haltet
    2. anregungen
    3. verbesserungsvorschläge
    4. sinnvolle kritik
    5. frewillige helfer, die ein bischen bei der implementation helfen?

    ps: bevor mir jemand vorwirft, ich hätte nicht gut genug recherchiert: das habe ich...mehrere tage lang 😉
    pps: 8k zeichen, doch ihr habts überlebt 😃



  • es scheint mir etwas monströs einen neuen basistyp stream zu erstellen. die idee an sich, streams bzgl lokalisierung und deviceverwendung zu verallgemeinern, sprich wie in deinem beispiel sehr leicht modizifieren zu können (also z.b. von Blowfish auf ein PubKey verfahren umschalten), ist auch recht nett.
    was machst du mit mutatoren, die nur in speziellen klassen funktionieren?
    ansosten fänd ich es vielleicht ganz nett. solange es klein und übersichtlich bleibt, sprich leicht zu erweitern. könnte mir z.b. vorstellen, dass es ein basisframework gibt, dass zunaechst mal dein in und out stream zur verfügung stellt, so wie eine doku, die klar und einfach darstellt, wie ich daraus einen netzwerkstream mache, und z.b. verschlüsselung einbaue.



  • @otze
    Die Filtering-Streams bzw. Filtering-Streambufs von James Kanze hast du dir angeschaut, oder?



  • HumeSikkins schrieb:

    @otze
    Die Filtering-Streams bzw. Filtering-Streambufs von James Kanze hast du dir angeschaut, oder?

    nein, hab zwar bei boost.org geschaut, bin aber dann wieder abgezogen, als ich da nichts gefunden habe,ausser halt dem state saver, woher sollte ich wissen, dass es zwar sowas schon in boost gibt, nur halt noch nicht teil der distribution?



  • so, das projekt ist schon relativ weit gediehen 🙂

    mein neuester überlegungsstand:
    das hauptproblem an der ganzen sache ist, dass die typinformation darüber welchen datentyp man haben will, relativ schnell verloren geht(relativ? nach dem ersten stream^^).

    Die typinformation ist aber wichtig, damit die einzelnen streams wissen, wie sie die daten zu behandeln haben(formatierung und so^^).

    die usprüngliche idee war es, die daten die von einem teilstream verarbeitet wurden zwischenzubuffern,wenn der buffer voll war, sollte er die daten an den nächsten teilstream weitergeben. das funktionierte leider mur in der theorie, da beim buffern die typinformation verloren geht, und auch der versuch, die typinformation im buffer mitzuspeichern ging gründlich schief. Desweiteren ging das ganze den Bach runter, wenn man den Buffer eines Streams geändert hat.

    nun bin ich bei folgendem ansatz angelangt(jaja meine Ascii skizzen):

    Buffer              Buffer            Buffer   
       ^                  ^                  ^ 
       |                  |                  |
    Controler<-Stream<-Controler<-Stream<-Controler<-Stream<<Input
    

    das system welches dahinterliegt ist folgendes: ich lege eine zusätzliche abstraktionsebene an, welche die unterscheidung buffer/stream schaffen soll.
    Wenn also kein Stream "angeschlossen" ist, so soll direkt in den Buffer geschrieben werden, ansonsten wird der bearbeitete input direkt an den nächsten Stream weitergegeben, der die daten wieder weiterverarbeitet,und wieder an den controler übergibt...

    Die typinformation will ich dadurch weitergeben,dass der Controler ebenfalls die operatoren << und >> bekommt. für zeichenweise ein- oder ausgaben wird dann put/get zur verfügung stehen.

    das hat natürlich auch wieder einen nachteil: der controler muss wissen, wie man die daten in den buffer schreiben soll, denn wie gesagt soll es keinen unterschied machen,ob der controler die daten an einen stream weitergibt, oder in den buffer schreibt.
    Die frage ist nun, ob ich den controler einfach stur byteweise in den buffer schreiben lassen sollte(denn für formatierungen ist der stream verantwortlich), oder ob ich die möglichkeit lasse, den controler umzubauen(vererbung/template spezialisierung)

    was meint ihr? seht ihr vielleicht eine weitere möglichkeit(die nichts mit "lass das bleiben, böser otze" zu tun hat)?



  • hmm hat wer lust den input zu testen? 😉
    sind bisher ca 1300 zeilen code Oo, und die buffer ansich sind nochnichmal drin^^


Anmelden zum Antworten