Meinungen zu INI/Config Loader



  • NaaK schrieb:

    TyRoXx schrieb:

    Wie wäre es, die Datei einmal zu parsen und die Ergebnisse zu speichern? Zum Beispiel als map<string, map<string, string> > .

    Das war meine erste Idee als ich den Loader bauen wollte. Ich wollte es genau wie du sagtest in einer Map speichern und später in eine Struktur übernehmen aber dann dachte ich mir, dass ich nicht immer alles brauchen werde. Vielleicht werde ich die Variante dennoch mal bauen um zu sehen, was für mich effizienter ist.

    map ist effizienter. das bißchen RAM ist ein Nichts. 2k ini bei 6G ram.
    Und Ram-Zugriffge sind SCHNELL, die Platte ist 1000000-mal langsamer. Allein, daß Du die Datei gelesen hast, hat so viele Zyklen gekostet, damit hättest Du ein ganzes Apfelmännchen malen können. Warum riskieren, sie nochmal lesen zu müssen?

    NaaK schrieb:

    volkard schrieb:

    Dein Programmierstil ist ziemlich hübsch. 👍
    Was mich windert, ist daß Du bei

    if(currentLine[0] == '[' && currentLine[currentLine.length()-1] == ']')
    

    reinverschachteslt, statt auch den continue-Trick

    if( not(currentLine[0] == '[' && currentLine[currentLine.length()-1] == ']') )
    

    zu verwenden.
    Außerdem sind es verschachtelte Schleifen, die unterschiedliche Dinge tun, vielleicht wollen die auch in unterschiedlichen Funktionen wohnen.

    Danke dir 🙂

    Stimmt eigentlich könnte ich es dort ebenso machen und vielleicht das ganze auf Funktionen auslagern.

    Ja, das würde mir gefallen. Sind aber leider die alten Künste, die man nicht mehr so braucht. Zeig die map-variante doch dann mal, denn ich meckere gerne an Code rum. Vielleicht finde ich noch was. 🙂
    Ich fürchte, die map-Variante wird so klein, daß man nicht auslagern sollte. Oh, ich fürchte, man kann gar nicht. Oh, ich fürchte sie wird optimal, ohne daß man was dagegen machen kann.



  • volkard schrieb:

    map ist effizienter. das bißchen RAM ist ein Nichts. 2k ini bei 6G ram.
    Und Ram-Zugriffge sind SCHNELL, die Platte ist 1000000-mal langsamer. Allein, daß Du die Datei gelesen hast, hat so viele Zyklen gekostet, damit hättest Du ein ganzes Apfelmännchen malen können. Warum riskieren, sie nochmal lesen zu müssen?

    Ich wollte eigentlich garnicht immer wieder Werte auslesen die ich brauche, sondern diese in einer Struktur speichern. Die Klasse könnte das dann selber entscheiden und vorallem für sich definieren welche Werte er haben möchte. Du hast aber schon Recht, die Datei wird so winzig klein sein, dass ich die Daten auch im RAM ablegen kann.

    volkard schrieb:

    Ja, das würde mir gefallen. Sind aber leider die alten Künste, die man nicht mehr so braucht. Zeig die map-variante doch dann mal, denn ich meckere gerne an Code rum. Vielleicht finde ich noch was. 🙂
    Ich fürchte, die map-Variante wird so klein, daß man nicht auslagern sollte. Oh, ich fürchte, man kann gar nicht. Oh, ich fürchte sie wird optimal, ohne daß man was dagegen machen kann.

    Hehe, werde ich dann auf jeden Fall nachliefern. Im Moment bin ich aber auf einem System ohne C++ Umgebung.



  • So hab mal die Map-Variante auf die schnelle geschrieben. Ich hab sie bisher nur kurz testen können aber es scheint zu funktionieren.

    bool CConfig::Load2(const std::string &filename)
    {
      m_iFile.open(filename.c_str());
      if(!m_iFile.is_open())
        return false;
    
      std::string currentLine;
      std::string currentSection;
      bool readingSection = false; // false till first appearance of [section]
    
      while(std::getline(m_iFile, currentLine))
      {
        trim(currentLine); // remove whitespaces
    
        if(currentLine.empty())
          continue;
    
        // save current section
        if(currentLine[0] == '[' && currentLine[currentLine.length()-1] == ']')
        {
          currentSection = currentLine.substr(1,currentLine.length()-2);
          readingSection = true;
          continue;
        }
    
        // kill 'sectionless' keys
        if(!readingSection)
          continue;
    
        int pos = currentLine.find('=');
        // no or more than 1 '=' found? skip line
        if(pos == currentLine.npos)
          continue;
        if(pos != currentLine.rfind('='))
          continue;
    
        // get key and his value
        std::string key   = currentLine.substr(0,pos);
        std::string value = currentLine.substr(pos+1, currentLine.length());
        trim(key);
        trim(value);
    
        // save in map
        m_sectionMap[currentSection].insert(key_value_td(key,value));
      }
    
      return true;
    }
    

    Ist eigentlich nur rasch runtergetippt, weil ich jetzt leider weg muss. Die Load2 ist vielleicht ein schlechter Ort dafür und die getter sollten ja klar sein, einfach aus der Map per Paramaeter auslesen.

    Hier vielleicht noch wie die Map aussieht:

    typedef std::string section_td;
      typedef std::string key_td;
      typedef std::string value_td;
      typedef std::pair<key_td,value_td> key_value_td;
      typedef std::map<key_td,value_td> keyMap_td;
      std::map<section_td,keyMap_td> m_sectionMap;
    

    Morgen überleg ich mir dann wie ich das ganze vielleicht in ein Template verpacke um keine typ-spezifische getter zu haben.


  • Administrator

    Was mir kurz aufgefallen ist, dass du verschiedentlich currentLine.npos verwendest. npos ist allerdings eine statische Konstante von std::basic_string . Der Kompiler müsste dies eigentlich verweigern zu kompilieren oder zumindest eine Warnung ausgeben. Korrekter Zugriff wäre eigentlich std::string::npos .

    Grüssli



  • Dravere schrieb:

    Der Kompiler müsste dies eigentlich verweigern zu kompilieren

    Nein, statische Klassenmember sind auch Member jedes einzelnen Objekts.

    oder zumindest eine Warnung ausgeben.

    Warnungen sind Geschmackssache 😉 Und da es keinerlei Nachteil bietet, würde vermutlich nur eine Warnung wegen nichtbefolgten Coding-Guidelines/übliche Konventionen anschlagen.


  • Administrator

    pumuckl schrieb:

    Dravere schrieb:

    Der Kompiler müsste dies eigentlich verweigern zu kompilieren

    Nein, statische Klassenmember sind auch Member jedes einzelnen Objekts.

    oder zumindest eine Warnung ausgeben.

    Warnungen sind Geschmackssache 😉 Und da es keinerlei Nachteil bietet, würde vermutlich nur eine Warnung wegen nichtbefolgten Coding-Guidelines/übliche Konventionen anschlagen.

    ... in C++ lernt man echt nie aus ... allerdings frage ich mich da mal wieder, wie sinnvoll denn sowas sein soll. Unnötiges und verwirrendes Feature weshalb es wohl niemand wirklich so macht. Naja.

    Grüssli



  • Das ist nicht unnötig oder wirr.
    Eine Eigenschaft, die JEDES Objekt der Klasse hat, hat auch DIESES Objekt der Klasse.



  • Ich kriege keine Warnungen wegen npos (Warning Level 3 in VS08).

    Habe vorhin das ganze mal etwas mehr getestet und beim speichern in die Map machte der Code nicht das was ich wollte. Map.insert überschreibt natürlich keine Werte, weshalb ich das geändert habe:

    // save in map and overwrite/update if key is already existing
    // edit this if you do not want to update and take the first entry instead
    keyMap_td::iterator keyMap_it = m_sectionMap[currentSection].find(key);
    if(keyMap_it == m_sectionMap[currentSection].end())
      m_sectionMap[currentSection].insert(key_value_td(key,value));
    else
      keyMap_it->second = value; // update
    

    Wenn man den ersten vorkommenden Wert speichern möchte, dann braucht man nichts ändern. Ich wollte ja, dass der letzte vorkommende Wert gespeichert wird, deswegen die Veränderung. Man könnte auch eine Variable setzen und beim initialisieren angeben was man möchte aber so wie ich es will ist eigentlich die gängigere Lösung.

    Als getter hab ich nur noch einen getKey, weil ich glaube, dass man nie wirklich wissen kann, was der Caller denn jetzt für einen Typ möchte. Deswegen caste ich beim Aufruf.



  • Zum Speichern noch ein eventueller Hinweis: möchtest du den Loader allgemein halten, wäre es eventuell nicht verkehrt, wenn er Kommentare und Leerzeilen zum einen erkennt und zum anderen beim Speichern belässt bzw. neu schreibt. Stell dir vor, du würdest die php.ini laden und beim Speichern fehlen sämtliche Kommentare 😉 Außerdem wäre es u.U. praktisch, wenn die Reihenfolge der Einträge erhalten bleibt.


  • Administrator

    volkard schrieb:

    Das ist nicht unnötig oder wirr.
    Eine Eigenschaft, die JEDES Objekt der Klasse hat, hat auch DIESES Objekt der Klasse.

    1. Es geht um den Zugriff. Dieser Zugriff ist unnötig und wird als Zusatz im Standard definiert. Der Implizite Zugriff in der Klasse selbst, geht über die qualifizierte ID. Zum Beispiel: std::string::npos .
    2. Eine statisch Eigenschaft gehört eben nicht zum Objekt der Klasse. Es existiert nur ein Zugriff darauf. Der Standard selbst sagt explizit, dass das statische Objekt zur Klasse gehört und nicht zu den Objekten der Klasse.

    Daher ist diese Möglichkeit, welche zusätzlich geregelt wird, nach meinem Empfinden etwas völlig unnötiges. Und weil eben das Objekt zur Klasse gehört, sollte man auch über die Klasse darauf zugreifen, wie es grundsätzlich so gut wie jeder macht.

    @Naak,
    Kleiner Tipp für das Einfügen. Lies dir mal die Beschreibung von diesem Operator durch:
    http://www.cplusplus.com/reference/stl/map/operator[]/

    Oder den Rückgabewert von insert :
    http://www.cplusplus.com/reference/stl/map/insert/

    Grüssli



  • Dravere schrieb:

    volkard schrieb:

    Das ist nicht unnötig oder wirr.
    Eine Eigenschaft, die JEDES Objekt der Klasse hat, hat auch DIESES Objekt der Klasse.

    1. Es geht um den Zugriff. Dieser Zugriff ist unnötig und wird als Zusatz im Standard definiert. Der Implizite Zugriff in der Klasse selbst, geht über die qualifizierte ID. Zum Beispiel: std::string::npos .
    2. Eine statisch Eigenschaft gehört eben nicht zum Objekt der Klasse. Es existiert nur ein Zugriff darauf. Der Standard selbst sagt explizit, dass das statische Objekt zur Klasse gehört und nicht zu den Objekten der Klasse.

    Daher ist diese Möglichkeit, welche zusätzlich geregelt wird, nach meinem Empfinden etwas völlig unnötiges. Und weil eben das Objekt zur Klasse gehört, sollte man auch über die Klasse darauf zugreifen, wie es grundsätzlich so gut wie jeder macht.

    Deine Argumentation folge ich nicht. Ich halte es für konsistent, daß shared Variablen shared Variablen sind, womit ich meine, daß es Variablen sind, die den Objekten dieser Klasse gemeinsam gehören.


  • Mod

    Dravere schrieb:

    Dieser Zugriff ist unnötig und wird als Zusatz im Standard definiert.

    Aus der Formulierung in 9.4/2 kann hier keine besondere Bevorzugung einer Variante erkennen. Historisch gesehen es ohnehin eher umgekehrt (D&E C++ Kapitel 13.4).

    Dravere schrieb:

    Der Implizite Zugriff in der Klasse selbst, geht über die qualifizierte ID. Zum Beispiel: std::string::npos

    Das halte für insignifikant. Schließlich existiert nicht in jedem Kontext ein Objekt auf das man implizit zurückgreifen könnte (z.B. innerhalb der Definition einer statischen Memberfunktion). Das ist also nur zwingende Konsequenz und nicht als Wertung zu verstehen.

    Das der Zugriff meist über einen qualifizierten Bezeichner erfolgt, dürfte praktisch ebenfalls daran liegen, dass häufig gar kein Objekt da ist, auf das man zurückgreifen könnte. Im nächsten Standard ist zudem zu bedenken, dass im Zusammenhang mit auto-Variablen der exakte Typ gar nicht mehr ausdrücklich auftaucht - dann dürfte die Memberzugriffssyntax auch häufíger benutzt werden.


Anmelden zum Antworten