mfro hat geschrieben:Vielleicht nochmal einen Schritt zurücktreten und sich das Ganze aus der Entfernung angucken. Ohne weitere Info, warum Du das unbedingt so brauchst, ist das schwer einzuschätzen (drum mag es sein, daß ich auf dem Holzweg bin), aber irgendwie werd' ich das Gefühl nicht los, Du siehst den Wald vor Bäumen nicht.
Das kann man nie ausschließen.
mfro hat geschrieben:Ein Container, der Elemente (zweier oder mehrerer) unterschiedlicher Größen enthält, muß zum Zugriff auf ein einzelnes Element immer traversiert werden (schließlich weiß man ja nicht, wo das gesuchte Element sein könnte, ohne die Größe aller vorherigen Elemente zu kennen und aufzuaddieren). Irgendwie kann ich mir nicht vorstellen, daß das - egal was man treibt - sonderlich effektiv werden kann.
Oder man schafft einen Vector, der den Index auf die Adresse des Objektes umlegt. Die Adressen sind immer gleich groß, die Traversion ist also unabhängig von der Größe der Objekte.
mfro hat geschrieben:Wäre es nicht viel gescheiter, statt eines einzigen Containers zwei (einen für die Liniensegmente, einen für die Punkte) in einem dritten zu kapseln und über den den Zugriff zu regeln (Element(5) ist ein Punkt und deshalb in Punkte(2) zu finden)? Selbstverständlich braucht man dazu eine weitere Indirektion, aber der Zugriff ist letztendlich sicherlich deutlich effektiver. Ebenso kann man die Speicherverwaltung auf die jeweilige Elementgröße optimieren und deine Namen kannst Du in der Kapsel auch gleich unterbringen.
Ich habe nicht nur Punkte und Linien. Aktuell dürfte ich bei um die 100 unterschiedlicher Objekttypen liegen und das wird sich vermutlich noch verdoppeln.
Ich versuche Abstract-Syntax-Tree-Knoten platt zu klopfen. Das wäre zum Beispiel ein Baum wie "1+2", der aus drei Knoten besteht: + und den beiden Blättern 1 und 2. Möglichkeit 1 ist, zur Compile-Zeit solche Elemente zu erkennen und zu vernichten. Aus den drei Knoten wird einer: 3. Bei einem Baum wie "a+2" geht das aber nicht mehr, denn diesen muss ich zur Laufzeit auswerten.
Nun haben wir für einen Ausdruck wie "a+2" schon drei unterschiedliche Knotentypen: Die Addition und die zwei Blätter Lesezugriff auf "a" und den Integer-Wert 2.
Sobald das Programm etwas Nennenswertes tut, erhalten wir ASTs mit Tausenden oder Millionen Knoten. Nehmen wir an, jeder Knoten ist im Schnitt 40 Byte groß, so haben wir bei einer Million Knoten 40 Megabyte Nutzdaten und eine unglaubliche Menge an Verwaltungsdaten für den Speicher.
Es gibt zwei Strategien: Man macht alle Knoten gleich groß, also so groß, wie der größte Knoten ist und fertig. Software-technisch allerdings ein Albtraum, da das Basisobjekt alle Variablen kennen muss, die man in einer Spezialisierung benötigen würde. Machbar, aber unschön. Man kann es automatisiereren, aber das treibt die Compile-Zeit hoch. Auch unschön.
Oder man nimmt einfach Vererbung und fertig - dann sind die Knoten aber unterschiedlich groß. Dafür verbrauchen kleine Knoten aber eben auch weniger Speicher.
Nächster Schritt: Ich möchte den AST auf die Festplatte schreiben. Ich muss also alle Adressen durch Indizes austauschen. Und praktischerweise habe ich alle zu speichernden Daten in einem Memory-Pool, dem ich eine Adresse geben kann und der spuckt mir dafür einen Index raus. Aktuell muss ich in meiner Sprache "#includes" immer neu parsen. Ich möchte aber nur einen fertigen AST laden, die Indizes gegen Adressen austauschen und fertig.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.
Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.