TreeStructInfo - format tekstowych i binarnych plików konfiguracyjnych

10

Po wielu miesiącach żmudnej pracy, w końcu udało się ukończyć pracę nad projektem TreeStructInfo; Poniżej znajduje się więc ogólny opis zarówno formatu plików, jak i przygotowanego API do ich obsługi, dlatego że jest to zaganienie dość obszerne;

Strona projektu: https://tsinfo.4programmers.net
Specyfikacja formatu: https://tsinfo.4programmers.net/pl/format/1.0.htm


Czym jest TreeStructInfo?

Format TreeStructInfo to projekt tekstowych i binarnych plików konfiguracyjnych, umożliwiających zapis informacji w postaci czytelnych drzewiastych struktur; Opracowany został z myślą o przechowywaniu różnego rodzaju ustawień aplikacji, gier i innych narzędzi; Umożliwia tworzenie zarówno prostych - jednoplikowych konfiguracji, a także bardziej złożonych, wieloplikowych systemów konfiguracyjnych; Nie jest on zależny od platform programowych, więc można z niego korzystać np. pod Windows, Linuks czy OS X;

Format ten według mnie stanowi ciekawą alternatywę przede wszytkim dla rejestru systemu oraz plików Ini, a także dla takich formatów jak XML, YAML czy TOML, z racji bardzo prostej budowy i składni, a także unikalnej funkcjonalności;

Uwaga! Format TreeStructInfo nie powinien być stosowany w zastępstwie systemów bazodanowych - nie takie jest jego pierwotne przeznaczenie i do tego się zbytnio nie nadaje;


1. Formy plików TreeStructInfo

Format ten przewiduje dwie formy plików konfiguracyjnych - tekstową oraz binarną; Pomiędzy tymi formami istnieje pełna kompatybilność; Dowolny plik tekstowy przekonwertowany na formę binarną i z powrotem, będzie posiadać dokładnie taką samą zawartość, jak pierwotna - konwersja nie powoduje utraty części zapisanych informacji;

Pliki binarne zawierać mogą te same elementy, co pliki tekstowe;


1.1. Forma tekstowa

Forma ta służy do tworzenia otwartych konfiguracji, umożliwiając tworzenie plików w dowolnych edytorach, a także umoliżliwiając użytkownikowi swobodę wprowadzania modyfikacji;

Pliki w formie tekstowej budowane są w sposób liniowy - jedna linia może zawierać tylko jedną informację (np. nagłówek drzewa, deklarację atrybutu itd.); Kolejnym atutem jest bardzo czytelna składnia, oparta na niedużej ilości słów i fraz kluczowych, a także znikomej liczby używanych znaków specjalnych; Dzięki temu zawartość plików tekstowych jest bardzo przyjazna dla człowieka, a zapisywane do atrybutów dane mogą zawierać praktycznie dowolne znaki, z wyjątkiem kilku zarezerwowanych;

Przykładowy plik: https://tsinfo.4programmers.net/pl/format/1.0.htm#idSampleFile

Główną zaletą plików tekstowych jest możliwość dzielenia drzewa konfiguracji na mniejsze części, co może znacząco wpłynąć na ich czytelność; Dzielenie drzewa odbywa się za pomocą referencjonowania elementów - ich deklaracje określają miejsce elementów w drzewie, zaś definicje posiadają już konkretną zawartość;

Fragmentacja drzewa z wykorzystaniem referencjonowanych elementów to pierwszy z dwóch metod dzielenia drzew; Drugim sposobem jest podział drzewa na wiele plików, powiązanych ze sobą na podstawie dowiązań (linków do plików dołączanych);

Więcej: https://tsinfo.4programmers.net/pl/format/1.0.htm#idTextForm


1.2. Forma binarna

Forma binarna służy do przechowywania takich samych konfiguracji jak forma tekstowa, jednak odróżnia ją mniejszy (czasem znacząco) rozmiar, a także dużo większa szybkość ładowania zawartości plików do pamęci; Dzieje się tak dlatego, że do plików binarnych nie są zapisywane takie informacje jak słowa kluczowe czy wcięcia, a przetwarzanie tych plików odbywa się bardzo prostą i szybką rekurencyjną techniką;

Forma ta przeznaczona jest dla zamkniętych konfiguracji, zawartych w większych plikach, dzięki czemu ich ładowanie jest po prostu krótsze, prostsze i szybsze; Natomiast w żadnym wpadku nie służy do maskowania danych, dlatego że zawartość nie jest szyfrowana;

Więcej: https://tsinfo.4programmers.net/pl/format/1.0.htm#idBinaryForm


2. Elementy drzew

Do budowy drzew wykorzystywane są trzy typy elementów: atrybuty, węzły oraz linki do plików dołączanych; Przeznaczenie poszczególnych elementów:

  • atrybuty - służą do przechowywania pojedynczych danych; Przechowywane mogą być dane wielu typów i w wielu postaciach, jako wartości jednoliniowe lub wieloliniowe;
  • węzły - umożliwiają grupowanie elementów oraz tworzenia drzewiastej struktury informacji;
  • linki do plików dołączanych - udostępniają możliwość dowiązania w ich miejscu innych drzew, zawartych w osobnych plikach; Dołączane drzewa z zewnętrznych plików mogą być zapisane w dowolnej formie (tekstowej lub binarnej); Elementami łączącymi drzewa w miejscu linków są tzw. węzły wirtualne;

Więcej: https://tsinfo.4programmers.net/pl/format/1.0.htm#idBasicElements


3. Komentarze

Format ten zezwala na używanie komentarzy zarówno jednoliniowych, jak i wieloliniowych; Same komentarze nie są postrzegane jako osobne elementy - są integralną częścią elementów drzew, a także samych drzew i nie mogą istnieć w dowolnych miejscach plików;

Komentarze dzielą się na dwie grupy - główny komentarz drzewa, zapisywany na samym początku plików, a także komentarze elementów, zapisywane zawsze ponad deklaracjami lub definicjami elementów;

Elementy referencjonowane (których ciała definiowane sa poza głównym ciałem drzewa) mogą posiadać dwa komentarze - jeden deklaracji i jeden definicji; Mogą być jedno lub wieloliniowe; Elementy te nie muszą posiadać ich obu - mogą posiadać tylko jeden (deklaracji lub definicji), lub nie posiadać go wcale;

Wszelkie komentarze są informacjami dodatkowymi i nieobowiązkowymi, bez względu na ich typ;

Więcej: https://tsinfo.4programmers.net/pl/format/1.0.htm#idComments


4. Tworzenie systemów konfiguracyjnych

Format umożliwia także tworzenie rozbudowanych, wieloplikowych konfiguracji; Z racji tej, że dowolne pliki TreeStructInfo nie zawierają w sobie informacji o tym, czy egzystują jako pojedyncze pliki, czy są dołączane przez inne pliki, do budowy systemów konfiguracyjnych można wykorzystać zarówno pliki tekstowe, jak i binarne;

Pliki natomiast mogą posiadać informację o tym, czy same linkują inne pliki; Informacje te zapisywane są za pomocą linków do plików dołączanych;

Liczba plików, z których budowane są systemy konfiguracyjne nie jest ustalona, więc można wykorzystać dowolną ich ilość; Nie zaleca się jednak tworzenia zbyt wielkich systemów - główny plik nie powinien linkować więcej, niż kilkanaście plików; Jeśli istnieć będzie potrzeba przechowywania dużo większych konfiguracji - rozwiązaniem jest stworzenie po prostu większej liczby głównych plików;


5. Dostęp do elementów drzew

Kolejnym atutem formatu jest dostęp do elementów drzew na podstawie standardowych ścieżek, na podobieństwo śieżek do elementów rejestru Windows; Ścieżki dostępu tworzone są z nazw elementów oraz znaków separatora - znaku \;

Ścieżki do elementów drzew posiadają zawsze taką samą formę; Zawsze - bez względu na to, czy odwołujemy się do elementu w tym samym drzewie, czy do elementu z drzewa linkowanego; A jeśli z drzewa linkowanego, to bez względu na poziom dowiązania (drzewo linkowane także może linkować następne, a następne także następne);

Dzięki takiemu rozwiązaniu, pliki formatu TreeStructInfo stają się bardziej przyjazne i jeszcze prostsze w użyciu we własnych programach;

Ścieżki dostępu nie są używane do budowy plików konfiguracyjnych - wykorzystywane sa jedynie w API, podczas zapisu lub odczytu danych;
Więcej: https://tsinfo.4programmers.net/pl/format/1.0.htm#idElementsPaths


6. Podsumowanie

Powyższy, mocno skrócony opis formatu przedstawia tylko najważniejsze jego możliwości; Funkcjonalność formatu jest na tyle bogata, że pliki konfiguracyjne TreeStructInfo posiadają szeroki wachlarz zastosowań; Zastosowane zabiegi zależą głównie od potrzeb oraz wyobraźni;

Szczegółowy opis możliwości formatu przedstawiony jest specyfikacji pierwszej wersji formatu, do której link znajduje się na samej górze tego posta;


API do obsługi plików TreeStructInfo

Sam format miałby niewielką wartość, gdyby nie było żadnej możliwości jego wykorzystania we własnych programach; Dlatego też stworzyłem bibliotekę, która pozwala na wykorzystywanie plików konfiguracyjnych w obu formach, w pełnej zgodzie ze specyfikacją; Biblioteka ta umożliwia wykorzystanie wszystkich aspektów formatu;

Co umożliwia oficjalne API:

  1. ładowanie plików konfiguracyjnych w obu formach z różnych źródeł - z plików dyskowych, z list lub strumieni, a także z zasobów plików wykonywalnych lub bibliotek DLL, na podstawie nazwy lub ID;
  2. zapis i odczyt danych wszystkich opisanych w specyfikacji typów danych:
  3. wartości logiczne - różne łańcuchy,
  4. liczby całkowite - różne systemy liczbowe (dec, hex, oct i bin)
  5. liczby rzeczywiste - różne notacje,
  6. walutę - różna precyzja,
  7. pojedyncze znaki - wartość znaku lub jego kod w różnych systemach liczbowych,
  8. łańcuchy znaków - jednoliniowe lub wieloliniowe,
  9. data i czas - dowolny format, wraz z dodatkowymi, nieformatowanymi ciągami,
  10. współrzędne punktów - różne systemy liczbowe,
  11. listy - zawartość dowolnych list dziedziczących po klasie TStrings,
  12. strumienie - zawartości dowolnych strumieni dziedziczących po klasie TStream,
  13. dowolnych buforów - możliwość zapisu dowolnych danych w postaci mapy heksadecymalnej;
  14. obsługę dowolnych systemów konfiguracyjnych;
  15. znacznie, znacznie więcej;

Biblioteka ta napisana została w Lazarusie, pod FPC 2.6.2, ale ze względów na wykorzystane podstawowe elementy kodu, możliwe jest jej użycie we wcześniejszych wersajch FPC; Nie jest też uzależniona od platformy, więc nadaje się nie tylko dla Windows;

Do przygotowanego API stworzona została także dokumentacja, opisująca dosłownie każdy element API (od stałych, przez typy i wpólne procedury i funkcje, po klasy i ich składowe); Wszystkie informacje o API są w dokumentacji on-line, dlatego też nie było potrzeby komentowania kodu;

Oprócz samej dokumentacji przygotowany został tutorial, przedstawiający różne sposoby wykorzystania oficjalnej biblioteki; Opisuje on wszystkie metody i właściwości klas do obsługi plików - klasy TSimpleTSInfoFile z podstawową funkcjonalnością oraz TTSinfoFile, zawierającej metody dodatkowe, rzadziej używane;

Oficjalne API do pobrania: https://tsinfo.4programmers.net/pl/download/index.htm

Dokumentacja API: [link nieaktywny]
Tutorial API: [link nieaktywny]

Bibliotekę udostępniam na warunkach licencji GNU Lesser GPL 3, więc z otwartym źródłem i możliwością wykorzystania jej w dowolnych projektach - otwartych lub zamkniętych, darmowych lub komercyjnych; Korzystajcie więc jak Wam się podoba;


To tyle jeśli chodzi o ogólne informacje na temat projektu TreeStructInfo; Wszystkich zainteresowanych zachęcam do zapoznania się ze specyfikacją formatu, a Pascalowców programujących w Lazarusie, o zapoznanie się i przetestowanie oficjalnego API;

Mam nadzieję, że projekt przypadnie do gustu i że znajdą się chętni do jego wykorzystania we własnych aplikacjach czy grach;Pozostałych zachęcam do pomocy w rozwijaniu projektu - być może ktoś miałby czas i chciałby wspomóc projekt swoim API, napisanym w innym języku niż Object Pascal;

Przygotowałem ten format i API także dla siebie - z tego formatu będę korzystał w swoich przyszłych programach; No i grach, bo SnakeASCII już został przystosowany do tego formatu - dane dotyczące podstawowych plansz będą zapisane w plikach TreeStructInfo i wrzucone do zasobów pliku wykonywalnego, skąd API umożliwia odczyt plików w bardzo prosty sposób;


Przy okazji dziękuję wszystkim za pomoc przy pracy nad tym projektem, głównie @babubabu - który poświęcił czas na przetestowanie biblioteki;

Życzę więc miłej lektury specyfikacji i przyjemnego korzystania z oficjalnej biblioteki :]

4

Po tygodniowej przerwie, przyszedł czas na aktualizację; Wprowadziłem trochę usprawnień i modyfikacji, część elementów poszła do nila; Poniżej opis nowych rzeczy i lista tych, których już nie ma z nami;


1. Format TreeStructInfo

Główną zmianą w samym formacie (czyli w specyfikacji) jest zmiana strony kodowej plików w formie tekstowej i binarnej; Wcześniej pliki tekstowe musiały zawierać znaki o stałej szerokości (jednobajtowe), czyli zgodne z kodowaniem ASCII i ANSI; Problemem jednak był malutki i dynamiczny zakres możliwych do wykorzystania znaków, przez co nie było możliwości przechowywania łańcuchów ze znakami obcych języków lub innych-szczególnych znaków;

Dlatego też została wprowadzona możliwość wykorzystania strony kodowej UTF-8, zarówno dla plików w formie tekstowej, jak i łańcuchów zapisywanych w plikach w formie binarnej; Tak więc od kilku dni, domyślną stroną kodową dla formatu TreeStructInfo jest wspomniany UTF-8;

Zmiana strony kodowej plików nie powoduje niezgodności z poprzednią wersją; Pliki tekstowe kodowanej w ANSI nadal pozostają zgodne z obecnym kodowaniem, dlatego że UTF-8 jest w pełni zgodne z ASCII; Jedynym problemem mogą być wykorzystane znaki diakrytyczne i wszystkie inne spoza ASCII; W takim przypadku łańcuchy te należy przekonwertować odpowiednimi funkcjami z RTL na obecne kodowanie;

Kolejną modyfikacją formatu jest usunięcie znaku # ze zbioru znaków zarezerwowanych; Znak ten stanowił prefiks dla kodu znaku w wartości atrybutu; Z racji tej, że obecna strona kodowa posiada zmienną szerokość znaków - ułatwieniem jest możliwość zapisu takich znaków jako łańcuchów;

Ostatnią modyfikacją formatu jest zmiana wartości znaku, służącego do oznaczenia wartości atrybutu jako jednej pustej linii listy; Wcześniej tym znakiem był #255, jednak znak ten jest zabroniony do użytku w plikach kodowanych w UTF-8; Dlatego też do określenia listy bądź macierzy z jednym pustym elementem, wykorzystuje się znak tabulacji poziomej, czyli znaku #9;

Jeśli chodzi o sam format - to wszystkie zmiany; Reszta pozostaje w poprzedniej postaci;


2. Oficjalne API

Oficjalne API zostało przystosowane do obsługi nowej strony kodowej; Fizycznych zmian wiele nie było - nie trzeba było przerabiać całej biblioteki, aby móc korzystac z plików kodowanych w UTF-8; Poniżej lista wprowadzonych modyfikacji;

dodano:

  • ładowanie i zapis drzew w plikach ze stroną kodową UTF-8,
  • usuwanie znacznika BOM z plików źródłowych,
  • obsługę poprawnej konwersji wielkości znaków w łańcuchach zapisywanych do atrybutów metodą WriteString,
  • możliwość określenia wielkości znaków odczytywanego łańcucha z atrybutu za pomocą metody ReadString (dodatkowy parametr AFormat typu TFormatString),
  • funkcję ValueToString w module TSInfoUtils.pp, wykorzystywaną w metodzie ReadString;

usunięto:

  • stałe CHAR_PREFIX i CHARACTER_SYSTEMS z modułu TSInfoConsts.pp,
  • typ TFormatChar z modułu TSInfoTypes.pp,
  • funkcje CharacterToValue i ValueToCharacter z modułu TSInfoUtils.pp,
  • metody TSimpleTSInfoFile.WriteChar i TSimpleTSInfoFile.ReadChar z modułu TSInfoFiles.pp;

Czyli dodane i usunięte zostały wymienione elementy po to, aby API było zgodne z nową stroną kodową oraz całą specyfikacją formatu;


3. Strona projektu

Specyfikacja formatu oraz dokumentacja API na stronie projektu zostały zaktualizowane; Aktualne źródła oficjalnej biblioteki są dostępne przede wszystkim na stronie projektu w dziale pobierania; Źródła dostępne są także w serwisie GitHub:

https://github.com/furious-programming/TreeStructInfo

Readme oraz Wiki zostaną uzupełnione w najbliższych dniach; Natomiast pierwsza wersja release pojawi się nieco wcześniej, dlatego że jeszcze dwie rzeczy będą wprowadzone w API; No i muszę ogarnąć funkcję tagowania w GIT :]


4. Plany na najbliższą przyszłość

Jeśli chodzi o sam format i jego specyfikację to myślę, że w najbliższym czasie nie będzie nowych rzeczy ani usuwanych starych; W API natomiast pojawi się nowa funkcjonalność, usprawniająca odczyt danych z atrybutów i redukująca w małym stopniu ilość zapisywanych danych;

Otóż zostaną dodane do klasy TSimpleTSInfoFile nowe metody, które pozwolą na tokenizowanie atrybutów, bez konieczności zapisywania w osobnym atrybucie ich liczby i nazywania ich numerami; Metody te będą działać na zasadzie funkcji FindFirst i FindNext, dzięki czemu w prosty sposób będzie można odczytywać dane z atrybutów, nie znając ich liczby i identyfikatorów; Dzięki temu ułatwi się ich odczyt i zlikwiduje się konieczność użycia dodatkowego atrybutu, dlatego plik o poniższej treści:

tsinfo version "1.0"
  :: liczba atrybutów
  attr Count "3"
  :: atrybuty do odczytu
  attr 0 "Value"
  attr 1 "Value"
  attr 2 "Value"
end tree

będzie można zastąpić poniższym:

tsinfo version "1.0"
  :: atrybuty do odczytu
  attr 0 "Value"
  attr 1 "Value"
  attr 2 "Value"
end tree

Aby utrzymać zgodność z obecną formą odwoływania się do elementów drzewa, tokenizowanie atrybutów będzie opierać się o metodę TSimpleTSInfoFile.OpenChildNode, co umożliwi pracę także z elementami z drzew linkowanych; W przypadku gdy żaden węzeł nie zostanie otwarty - tokenizowane będą atrybuty z głównego węzła głównego drzewa konfiguracji;

Kolejną funkcją będzie możliwość ładowania drzewa bez linkwania zewnętrznych plików, jeśli w ładowanych drzewie znajdują się linki do plików dołączanych; To umożliwi zwiększenie szybkości ładowania plików do pamięci, korzystanie tylko z tego, z czego chcemy, a także umożliwi konwersję plików na binarne, jeśli taki plik znajduje się w systemie konfiguracji; Tym bardziej, jeśli taki plik jest linkowany i sam linkuje inne pliki;

Podsumowując, będzie to znaczne usprawnienie odczytu konfiguracji, które będzie miało szerokie zastosowanie (w tych szczególnych, wyżej wymienionych przypadkach);


5. Podsumowanie

Jeśli ktoś zechciał już skorzystać z formatu TreeStructInfo i oficjalnej biblioteki, to proszę sobie pobrać najnowsze źródła ze strony projektu; W chwili obecnej oficjalne API posiada status beta, jednak po wprowadzeniu funkcji tokeniozowania atrybutów, status ten zmieni się na release, a jego wersja oznaczona zostanie numerem 1.0, jako wersja finalna i stabilna; Oczywiście to nie oznacza, że prace nad projektem zostaną definitywnie zakończone;

Życzę miłego korzystania z API i formatu, a także zachęcam do przyłączenia się do prac nad rozwojem projektu, jeśli tylko znajdą się osoby z chęciami, umiejętnościami i oczywiście wolnym czasem;

Dziękuję za oceny - dzięki temu wiem, że projekt się podoba i że warto go rozwijać; Dziękuję również za sugestie, znajdujące się w komentarzach do poprzedniego posta; Jednak zachęcam do dyskusji w postach - nie bójcie się także krytykowania; To że jestem moderatorem nie oznacza przecież, że na krytykę mojego projektu odpowiem banami... :]

1

niezbyt czytelnie to wygląda...
napisz może jakiś program demonstrujący użycie takiego formatu.

No ale szacun za chęci mimo wszystko :)

1

niezbyt czytelnie to wygląda...

@pytajnik123 - ale dlaczego? Tu na forum niestety nie mam kolorowania składni, więc będę musiał sprawdzić jak to zrobić ręcznie; Na stronie projektu jest pokazana zawartość przykładowego pliku - tam jest kolorowanie składni, ale plik jest krótki i zawiera prawie wszystkie dozwolone elementy (łącznie z referencjonowanymi), więc może sprawiać wrażenie przesadzonego; Ale to jest tylko przykład - dedykowane pliki będą wyglądać lepiej, dlatego że nie będzie w nich "wszystkiego";

napisz może jakiś program demonstrujący użycie takiego formatu.

Piszę - http://4programmers.net/Forum/Off-Topic/Oceny_i_recenzje/234190-snakeascii_czyli_kultowy_waz_w_specyficznej_tekstowej_formie - jednak nie umiem jednocześnie rozwijać API, aktualizować GITa, uzupełniać dokumentację, tworzyć pluginy do edytorów i dedykowany edytor, rozwijać grę i pisać przykładowe programy... Najpierw wypuszczę stabilną wersję API i uzupełnię stronę projektu, a dopiero później będę myślał nad innymi rzeczami; W każdym razie nie martw się - póki co nie przewiduję zakończenia prac nad projektem :]

Pierwszym przykładowym programem będzie gra SnakeASCII, która już została przygotowana do obsługi plików TreeStructInfo i działa w ich oparciu, jednak aktualnych źródeł jeszcze nie udostępniałem; Nastąpi to jak wydzielę obsługę planszy i węża do osobnej klasy, aby można było ją wykorzystać w kilku miejscach (jedna klasa gry dla kilku jej trybów);

PS: Dodałem kolorowanie składni do przykładowych zawartości plików, podanych w poprzednim swoim poście.

1

Minął tydzień od ostatniej aktualizacji, więc czas na kolejną;

Tym razem wprowadzone zostały nowe-ostatnie funkcje, które zamierzałem wprowadzić, aby zwiększyć wygodę korzystania z plików konfiguracyjnych; Nic nie zostało usunięte, za to dodałem nowe typy i nowe metody bazowej klasy; Poniżej opis najprawdopodobniej ostatnich zmian - czas w końcu na wersję release;


1. Oficjalne API

Jeśli ktoś przeglądał repozytorium projektu TreeStructInfo na GitHub to pewnie zauważył nowe commity;

W module TSInfoConsts.pp dodana została stała CURRENT_NODE_SYMBOL ze znakiem ~, wykorzystywanym do oznaczania ścieżki aktualnie otwartego węzła za pomocą metody OpenChildNode; Dzięki temu można zwiększyć czytelność kodu, zawierającego odwołania do elementów po otwarciu danego węzła; Poniższe odwołania są równoznaczne:

tsiConfig.WriteInteger('Value',   $BADFACE);
tsiConfig.WriteInteger('~\Value', $BADFACE);

Przykład odwołania się do atrybutu z węzła potomnego względem węzła aktualnie otwartego:

tsiConfig.WriteInteger('Foo\Bald\Bar\Value',   $BADFACE);
tsiConfig.WriteInteger('~\Foo\Bald\Bar\Value', $BADFACE);

Jeśli w ścieżce znajduje się identyfikator ~ - metoda wyszukująca element (czyli metoda FindElement) po prostu pomija go;

Kolejną nowością jest dodanie do modułu TSInfoUtils.pp funkcji IsCurrentNodeSymbol, która po prostu sprawdza, czy dany ciąg znaków ścieżki lub identyfikatora oznacza odwołanie się do aktualnie otwartego węzła; Funkcja ta wykorzystywana jest teraz w kilkudziesięciu metodach, aby przystosować je do obsługi znaku ~;

Następną nowością jest wprowadzenie flagi ffNoLinking, możliwej do użycia w konstruktorach klasy TSimpleTSInfoFile; Umożliwia ona załadowanie drzewa bez linkowania ewentualnych drzew z innych plików; Użycie jej spowoduje, że linkowanie będzie pominięte, bez względu na to czy ładowany plik jest głownym plikiem konfiguracji, czy plikiem linkowanym;

Jednak największą zmianą są cztery nowe metody, umożliwiające tokenizowanie elementów drzewa:

  • FindFirstAttribute - pozwala wyszukać pierwszy atrybut w danym węźle,
  • FindNextAttribute - służy do wyszukiwania kolejnych atrybutuów w danym węźle,
  • FindFirstChildNode - umożliwia wyszukanie pierwszego węzła potomnego w danym węźle,
  • FindNextChildNode - pozwala wyszukiwać kolejne węzły potomne w danym węźle;

Metody te bazują na dwóch nowych typach obiektów - TTSInfoAttributeToken i TTSInfoChildNodeToken - do których wpisywane są informacje o znalezionych elementach; Typy te pozwalają na pobieranie informacji o elementach, umożliwiając zarówno odczyt danych jak i ich modyfikację, jednak nie udostępniają referencji do instancji klas elementów; Samo wyszukiwanie elementów nie jest uzależnione od ich stanu referencjonowania;

Jak wygląda tokenizowanie elementów? Bardzo prosto; Poniżej przykład tokenizowania atrybutów i węzłów potomnych, znajdujących się w głównym węźle drzewa lub w aktualnie otwartym węźle:

var
  attrToken: TTSInfoAttributeToken;
  nodeToken: TTSInfoChildNodeToken;
{ tokenizowanie atrybutów }
if tsiConfig.FindFirstAttribute(attrToken) then
repeat
  { wykorzystanie tokenu }
until not tsiConfig.FindNextAttribute(attrToken);
{ tokenizowanie węzłów potomnych }
if tsiConfig.FindFirstChildNode(nodeToken) then
repeat
  { wykorzystanie tokenu }
until not tsiConfig.FindNextChildNode(nodeToken);

a także przykład tokenizowania elementów zawartych w węźle potomnym względem głównego węzła drzewa lub względem aktualnie otwartego węzła:

{ tokenizowanie atrybutów }
if tsiConfig.FindFirstAttribute(attrToken, '~\Foo\Bald\') then
repeat
  { wykorzystanie tokenu }
until not tsiConfig.FindNextAttribute(attrToken);
{ tokenizowanie węzłów potomnych }
if tsiConfig.FindFirstChildNode(nodeToken, '~\Foo\Bald\') then
repeat
  { wykorzystanie tokenu }
until not tsiConfig.FindNextChildNode(nodeToken);

Jak widać proces tokenizowania jest bardzo prosty i przyjemny - coś jak wykorzystanie funkcji FindFirst i FindNext z modułu SysUtils;

Więcej informacji oczywiście w uzupełnionej dokumentacji API, a także w tutorialu dotyczącym obsługi klasy TSimpleTSInfoFile;


2. Format TreeStructInfo

Jedyną nowością jest wpis dotyczący częściowej rezerwacji znaku ~, oznajmiający, że łańcuch znaków zawierający tylko jeden znak ~ jest nieporawidłowym identyfikatorem; Pozostałe elementy bez zmian i mam nadzieję, że już więcej modyfikacji nie będzie (chyba, że ortografia itd.);


Podsumowanie

To by było na tyle zmian w projekcie; Oficjalne API jest już dopięte na ostatni guzik - stabilną wersję najnowszych źródeł można pobrać ze strony projektu (w dziale pobierz), a także z repozytorium na GitHub;

Zostało już niewiele do zrobienia:

  • otagować stabilną wersję źródeł w repo,
  • dodać binarki do repo i umożliwić ich pobranie ze strony projektu,
  • uzupełnić plik README.md w repo;

Mam nadzieję, że uda się to zrobić jeszcze przed końcem tego miesiąca; W każdym razie z biblioteki można już śmiało korzystać i nie bać się, że funkcjonalność bądź specyfikacja się zmieni;


To tyle - jeśli ktoś korzysta już z oficjalnego API, to polecam pobrać najnowsze źródła (są w pełni kompatybilne z poprzednią wersją); Oczywiście życzę miłego korzystania z API i plików konfiguracyjnych, a także proszę o ewentualny feedback, jeśli uznacie że coś nie gra :]

2

Minęło już trochę czasu od poprzedniej aktualizacji, więc czas na kolejną;


1. Składnia plików

Miało nie być znaczących zmian, jednak z racji niezrozumienia przeznaczenia części funkcjonalności formatu, głupich i nieuargumentowanych docinek i chamskiego feedbacku (niestety w zupełnie obcym serwisie, do którego trafiłem przez przypadek), postanowiłem nieco zmodyfikować składnię tekstowych plików konfiguracyjnych;

Pierwsza zmiana dotyczy słów i fraz kluczowych, wykorzystywanych do tworzenia deklaracji i definicji elementów referencjonowanych; Wcześniej stosowane były trzy słowa kluczowe:

  • &attr

  • &node

  • &end
    zostały one zamienione na bardziej intuicyjne i bardziej czytelne frazy kluczowe:

  • ref attr

  • ref node

  • end ref

Przykład zastosowania elementów referencjonowanych poniżej:

tsinfo version "1.0"
  :: standardowy atrybut
  attr Integer "0xBADFACE"
  :: referencjonowany atrybut
  ref attr Float
  :: standardowy węzeł potomny
  node First
  end
  :: referencjonowany węzeł potomny
  ref node Second
end tree

:: referencjonowany atrybut
ref attr Float "3,14"

:: referencjonowany węzeł potomny
ref node Second
  :: i jego zawartość
  attr Referencing "True"
end ref

Druga modyfikacja składni dotyczy wartości i ilości flag, wykorzystywanych w linkach do plików dołączanych; Wcześniej istniały tylko dwie flagi:

  • "binary"
  • "updatable"

ich zakres został zwiększony do czterech, nazwanych bardziej intuicyjnie:

  • "text"
  • "binary"
  • "read"
  • "write"

Pierwsze dwie flagi stosuje się do określenia formy linkowanego pliku (plik tekstowy lub binarny), dwie kolejne do określenia trybu linkowania (tylko do odczytu lub do odczytu i zapisu); Deklaracje linków do plików dołączanych mogą teraz wyglądać następująco:

:: dowiązanie pliku tekstowego w trybie tylko do odczytu
link "FileName.ext" as "Virtual Node Name"
link "FileName.ext" as "Virtual Node Name" flags ""
link "FileName.ext" as "Virtual Node Name" flags "text"
link "FileName.ext" as "Virtual Node Name" flags "text" "read"

:: dowiązanie pliku tekstowego w trybie do odczytu i zapisu
link "FileName.ext" as "Virtual Node Name" flags "text" "write"

:: dowiązanie pliku binarnego w trybie tylko do odczytu
link "FileName.ext" as "Virtual Node Name" flags "binary"
link "FileName.ext" as "Virtual Node Name" flags "binary" "read"

:: dowiązanie pliku binarnego w trybie do odczytu i zapisu
link "FileName.ext" as "Virtual Node Name" flags "binary" "write"

Skrócona forma deklaracji linków jest nadal możliwa do zastosowania;


2. Oficjalne API

Biblioteka została przystosowana do nowych fraz kluczowych i nowego zbioru flag - były to małe poprawki; Oczywiście specyfikacja formatu, dokumentacja API i tutorial do jego obsługi zostały odpowiednio poprawione;


Podsumowanie

To były już ostatnie modyfikacje, związane zarówno z funkcjonalnością formatu, jak i z oficjalnym API do obsługi plików TreeStructInfo; Więcej już nic nie będzie poprawiane lub rozszerzane - to finalna forma; Sama specyfikacja może się jeszcze nieco zmienić, ale tylko jeśli chodzi o literówki czy poprawienie nieskładnych zdań (podobnie z dokumentacją API);

W dziale pobierania dostępna jest oficjalna biblioteka, do pobrania w formie archiwum .zip; Jedno archiwum zawiera same źródła (pliki .pp), a drugie zawiera standardową paczkę (package), możliwą do wykorzystania we własnych projektach; W serwisie GitHub znajduje się także pierwszy release biblioteki oraz skrócona wersja specyfikacji formatu w języku koślawo-angielskim;

To by było na tyle - specyfikacja formatu jest, wersja produkcyjna API jest, dekumentacja i tutorial są; W takim razie życzę miłego korzystania z biblioteki i przepraszam za ewentualne problemy, wynikłe z modyfikacji składni i API.

0

ref attr Float "3,14"

z kropka tez bedzie prawidlowe?

ref attr Float "3.14"

1

@mca64 - tak, kropka też będzie poprawna, ale w szczególnym przypadku;

Metody zapisujące lub odczytujące liczby zmiennoprzecinkowe, walutę oraz datę i czas korzystają z rekordów typu TFormatSettings, więc znak separatora dziesiętnego zawsze brany jest z takiego rekordu; Jeśli korzystasz z podstawowej metody zapisu liczb zmiennoprzecinkowych, to znak separatora dziesiętnego brany jest z rekordu DefaultFormatSettings, czyli domyślnie znak przecinka;

Jeśli interesuje Cię inny znak separatora, to skorzystaj z rozszerzonej wersji metody zapisującej/odczytującej, do której podaje się rekord TFormatSettings - możesz uzupełnić ten rekord odpowiednią funkcją, która pobierze dane lokalizacyjne z systemu, albo uzupełnić go samemu, jeśli chcesz całkiem customowe wartości;

Te metody wykorzystują algorytmy konwersji z biblioteki standardowej, czyli funkcje FloatToStrF oraz TryStrToFloat, więc jeśli znasz te funkcje, to powinieneś wszystko zrozumieć bez problemu;

Przykład zapisu liczby zmiennoprzecinkowej w podstawowej formie:

var
  tsiConfig: TSimpleTSInfoFile;
begin
  tsiConfig := TTSInfoFile.Create('C:\Config.tsinfo', [ffLoadFile, ffWrite]);
  try
    tsiConfig.WriteFloat('Float', 3.14);
  finally
    tsiConfig.Free();
  end;
end.

oraz z własnym separatorem dziesiętnym:

var
  tsiConfig: TSimpleTSInfoFile;
  fsCustom: TFormatSettings;
begin
  tsiConfig := TTSInfoFile.Create('C:\Config.tsinfo', [ffLoadFile, ffWrite]);
  try
    fsCustom := DefaultFormatSettings;
    fsCustom.DecimalSeparator := '.';
    tsiConfig.WriteFloat('Float', 3.14, fsCustom);
  finally
    tsiConfig.Free();
  end;
end.

Pierwszy kod zapisze liczbę w postaci 3,14, a drugi już z innym separatorem - 3.14; Po więcej informacji odsyłam do odpowiedniego działu specyfikacji, w którym zawarta jest informacja dotycząca separatorów w liczbach zmiennoprzecinkowych:

liczby zmiennoprzecinkowe napisał(a)

Znakiem separatora dziesiętnego nie musi być znak ,, a separatora tysięcznego znak (znak spacji). Znaki te uzależnione są głównie od standardów zapisu liczb zmiennoprzecinkowych względem danej lokalizacji, stąd np. separatorem dziesiętnym może być znak ..


Jeśli korzystasz z oficjalnej biblioteki i z czymś masz problem, to załóż wątek w odpowiedzim dziale - w nim udzielę Ci wszelkich informacji dotyczących danego zagadnienia.

0

ok juz rozumiem. Zastanawialem sie czy ten znak jest na sztywno czy z TFormatSettings

1

Wszystko jest dynamicznie, dlatego że metody zapisujące/odczytujące korzystają z funkcji konwertujących z biblioteki standardowej; Właściwych funkcji konwertujących (w tym przypadku FloatToValue oraz ValueToFloat) nie pisałem w całości ręcznie; Jedynym wyjątkiem są funkcje do konwersji daty i czasu, dlatego że te z RTL nie obsługiwały w pełni tego, co narzuca specyfikacja.

1

Nie wiem jaki jest tego powód, ale już któryś raz z kolei zadawane jest mi pytanie, dlaczego sugerowany maksymalny rozmiar tekstowych i binarnych plików konfiguracyjnych jest taki mały; Jedni widzą w tym jakąś dziwną ułomność, inni dochodzą do wniosku, że oficjalna biblioteka nie poradzi sobie z większymi plikami;

Odpowiedź jest prosta - to sugerowany maksymalny romiar, a nie sztywny, po przekroczeniu którego komputer zapłonie...

Tak więc prostując dziwne mity i domysły trzeba jasno napisać, że maksymalny rozmiar plików konfiguracyjnych w obu formach nie jest ustalony - pliki mogą mieć teoretycznie dowolne rozmiary, bez względu na ich formę i przeznaczenie (samodzielne pliki lub wchodzące w skład systemów konfiguracyjnych);

Dlatego też wprowadziłem poprawkę w specyfikacji formatu, podciągając nieco sugerowane maksymalne rozmiary.

0

Pytanko odnośnie kolejności definicji referencjonowanych elementów (https://tsinfo.4programmers.net/pl/format/1.0.htm#idOrderOfDefRefElements). Po co takie ograniczenie i zawiłość, skoro i tak elementy te przenoszone są w trakcie parsowania do miejsc ich deklaracji i z takiego stanu tworzy się reprezentacje danych w API?

1

Nie nazwałbym tego ani "ograniczeniem", ani "zawiłością" - ustalona kolejność jest po prostu konieczna i nieodzowna, ale może po kolei, komentując Twoje słowa;


"Ograniczenie" jest konieczne, aby wykluczyć błędy parsowania, podczas istnienia kilku referencjonowanych elementów o takich samych identyfikatorach; W specyfikacji zaznaczyłem, że dwa elementy nie mogą posiadać takiej samej nazwy, ale tylko w przypadku, gdy są tego samego typu i znajdują się w tym samym węźle; W przypadku złamania tej zasady, nie będzie możliwe odróżnienie tych elementów w ścieżkach dostępu (ścieżki będą takie same);

Przykład pliku konfiguracyjnego, w którym zachowanie kolejności definicji jest kluczowe:

tsinfo version "1.0"
  ref attr String
  node Foo
    ref attr String
    node Bald
      ref attr String
    end
  end
end tree

ref attr String "value"
ref attr String "value"
ref attr String "value"

Jak widać wszystkie referencjonowane atrybuty posiadają taką samą nazwę, jednak znajdują się w innych węzłach, więc są składniowo poprawne; W jaki sposób więc rozróżnić która definicja należy do pierwszej deklaracji, która do drugiej, a która do trzeciej? A no właśnie; A co, jeśli te atrybuty będą posiadać różne wartości (to raczej normalne) i podczas parsowania pliku pomieszasz definicje? Przyporządkujesz złe wartości, więc program otrzyma złe dane; Dlatego też kolejność musi być określona (patrz niżej);


Zawiłość o której wspominasz, to po prostu rekurencja (więc nic skomplikowanego), do której dochodzi ważność typów elementów - są ich dwa (referencjonowanie stosuje się tylko na atrybutach i węzłach - na linkach już nie), więc łatwo zapamiętać;

Najprościej jest, jeśli wykorzystuje się referencjonowanie jednopoziomowe - deklaracja każdego elementu referencjonowanego znajduje się w głównym ciele drzewa; Wtedy kolejność oczywiście nadal jest rekurencyjna, ale sprowadza się do kolejności liniowej, czyli wykonuje się sprawdzanie drzewa od góry (od początku/od węzła głównego) do dołu (do linii zamykającej główne ciało drzewa);

Jeżeli wykorzystuje się referencjonowanie wielopoziomowe, czyli prościej mówiąc sytuację, gdzie elementy referencjonowane znajdują się wewnątrz ciał referencjonowanych węzłów - kolejność jest rekurencyjna, ale już nie jest liniowa; Wtedy tak samo sprawdza się drzewo od góry do dołu, ale po napotkaniu referencjonowanego węzła, po zdefiniowaniu jego ciała od razu jest sprawdzana jego zawartość;

Sama kolejność opiera się na hierarchii ważności elementów - jeżeli w danym węźle znajdują się i referencjonowane atrybuty, i referencjonowane węzły potomne - najpierw definiuje się atrybuty, potem węzły; Linki do plików dołączanych nie posiadają postaci referencjonowanej, dlatego że nie ma ona sensu; Każdy link musi być zapisany tylko i wyłącznie w jednej linii, więc na referencjonowaniu nic by się nie zyskało, a w zamian można skomplikować strukturę drzewa i utrudnić analizę człowiekowi (człowiekowi, bo parser łyka referencjonowanie bez problemu);


Myślę, że teraz zrozumiesz dlaczego kolejność jest ważna (i konieczna);

Należy jednak pamiętać, że referencjonowanie elementów zostało opracowane po to, aby móc dzielić jedno drzewo konfiguracji na mniejsze części, łatwiejsze do analizy dla człowieka; Dzielenie konfiguracji ma sens tylko wtedy, gdy drzewo zawiera dużo elementów, a same ich ciała (np. wieloliniowe i długie wartości atrybutów) wizualnie zmniejszają czytelność drzewa; Jeżeli drzewo zawiera mało elementów (np. kilkanaście), ich referencjonowanie nie wpłynie na poprawienie czytelności drzewa, więc nic się na tym nie zyska;

Podobne przeznaczenie ma dzielenie konfiguracji na kilka plików, tworząc system konfiguracji; Aby się to opłacało - drzewo musi zawierać bardzo dużo elementów; Wyjątkiem jest wydzielenie części konfiguracji do pliku binarnego, dlatego że sensem używania plików binarnych jest znacznie krótszy czas przetwarzania (nawet ponad 40%); Ale długo by opowiadać - wszystko opisałem w specyfikacji formatu;

[...] skoro i tak elementy te przenoszone są w trakcie parsowania do miejsc ich deklaracji i z takiego stanu tworzy się reprezentacje danych w API?

Przenoszenie definicji elementów referencjonowanych w miejsca ich deklaracji to zapewne jeden z kilku sposobów przetwarzania tekstowych plików konfiguracyjnych; Wybrałem taki sposób, dlatego że jest on odwracalny - odwrotną operację (przenoszenia definicji w trakcie generowania wyjścia) można wykorzystać w klasie serializującej drzewo z pamięci do pliku;

Wcale nie trzeba tego robić - plik można parsować w locie, od razu wyszukując definicje i je przetwarzać; Jednak z moich obserwacji wynikło, że bezpieczniej jest je poprzenosić, od razu reagując na braki definicji; Jeśli któryś z elementów referencjonowanych nie posiada swojej definicji (co jest de facto niezgodne ze specyfikacją) - oficjalne API dorabia jego puste ciało (dopisuje do deklaracji pustą wartość atrybutu lub dodaje linie zakańczającą definicję węzła); To jest małe usprawnienie, eliminujące niedużą część błędów składniowych;

Oficjalne API poprawia więcej błędów lub dziwnych sposobów zapisu, ale jeśli zawartość pliku jest naprawdę spartolona, to po prostu lecą wyjątki, a samo drzewo jest awaryjnie czyszczone, aby można było odpowiednio zareagować podczas wykrycia uszkodzonego pliku lub zawierającego niepoprawnie zapisane dane.

2

Po niemal miesięcznej przerwie od wydania stabilnej wersji API, ujawnił się dość poważny bug, uniemożliwiający dodawanie dziesiątek tysięcy elementów do pojedynczego węzła; Choć tego typu zabiegi są zdecydowanie niezalecane (nie chcę widzieć miny kogoś, kto miałby otworzyć taki plik i go analizować...), to jednak trzeba było go poprawić; Jakimś cudem umknął on w setkach testów, jakie przeprowadzałem na API, dlatego też jest mi niezmiernie przykro, że wersja nazwana stabilną posiadała tak powazny błąd;

Błąd leżał w klasie TBaseTSInfoElementsList, a dokładniej w metodzie SetNewListSize, która alokuje bądź realokuje blok pamięci dla listy elementów, jeśli aktualnie przydzielona pamięć została wypełniona utworzonymi elementami; Po realokacji bloku pamięci dla listy, pamięć zajęta przez aktualnie zgromadzone elementy była kopiowana procedurą Move, a pozostała wolna przestrzeń nowego bloku była zerowana procedurą FillChar; Tu pojawiał się problem, bo przy ogromnej ilości elementów do przesucięcia (ponad 10 tysięcy), rzucany był wyjątek SIGSEGV, który ciężko było namierzyć;

Rozwiązanie podpatrzyłem z klasy TStringList - wykorzystałem rzutowanie macierzy przechowującej elementy na PAnsiChar, a także zamieniłem procedurę FillChar na FillWord; Dzięki temu wyjątek nie zostaje rzucony przy alokacji dużych bloków pamięci;


API przetestowałem na ogromnych ilościach elementów i wszystko gra; Jednak z racji tej, że pracuję na przestarzałym sprzęcie (IBM R31, 1,13GHz + 512MB RAM), testy przeprowadziłem na dużych ilościach elementów, jednak nie tak ogromnych, na jakie można by sobie pozwolić; W każdym razie stworzenie 100 000 elementów zajmuje kilkanaście sekund, ładowanie takiego pliku do pamięci także kilkanaście sekund;

Drugi test przeprowadziłem tworząc 1 000 węzłów, a w każdym z nich po 1 000 atrybutów (łącznie 1 000 000 elementów); Tworzenie i zapis takiego drzewa trwa podobnie - kilkanaście sekund, ładowanie drzewa z pliku także kilkanaście sekund; Plik z takim drzewem zajmuje 16,1 MiB (16 908 922 B), więc bez problemu API działa na wielokrotnie większych plikach, niż sugerowany ich rozmiar;


W odkryciu błędu ma swój udział @Bartosz Wójcik, któremu dziękuję za dociekliwość i pytania na temat sugerowanego maksymalnego rozmiaru plików konfiguracyjnych; Pomimo tego, że wcześniej API radziło sobie z dużymi plikami, to błąd umknął mi w testach i dobrze, że Bartek zasugerował wykonanie testu;


Wszelkie materiały na stronie zostały poprawione - dokumentacja oficjalnego API (dwie metody z klasy TBaseTSInfoElementsList i jedna nowa stała w module TSInfoConsts.pp), pliki do pobrania z działu pobierz, a także pliki w repozytorium w GitHub; Niestety bug był na tyle poważny, że musiałem usunąć release, zaktualizować repo i stworzyć nowy release, o takiej samej treści i pod takim samym linkiem; Dodałem także nowy wpis na głównej stronie projektu, w punkcie z nowościami;

Najnowsze źródła są możliwe do pobrania ze strony projektu z działu pobierz, a także z repozytorium w GitHub; Release w GitHub tak jak wcześniej posiada dwa dodatkowe archiwa - Source.zip z gołymi plikami źródłowymi .pp (cztery pliki), a także Package.zip ze zaktualizowaną paczką, możliwą do dołączenia do własnych projektów;

Za wszelkie trudności przepraszam, jednak trudno napisać jakikolwiek program bez bugów; Natomiast w najbliższym czasie, jeśli tylko znajdę chwilę, przeprowadzę kompleksowe testy wydajności oficjalnego API; Przede wszystkim żeby rozwiać wszelkie wątpliwości i przedstawić jakieś wyniki, które oczywiście opublikuję w tym wątku, a programy testowe dołączę do repozytorium, aby wyniki były dostępne dla każdego;

Tak więc jesli ktoś korzysta z API, to dobrze by było pobrać najnowszą jego wersję.

0

Zupełnie nie podoba mi się system typów atrybutów, a jeszcze bardziej sposób ich zapisu. Nie ma nic o zakresach, o binarnej reprezentacji, zapisy są niejednoznaczne, bardzo pokracznie pokręciłeś user-defined locale z gdzieniegdzie sztywnym polskim zapisem. To wręcz pułapki dla użytkowników i potencjalnych twórców API (niezbyt zachęcające jest dla nich to, że z projektu ten Pascal wycieka).

1

Wg. mnie fajny projekt na zabicie nudy, ale nie widzę powodu dlaczego ktoś miałby kiedykolwiek użyć ten format, a nie XML którego praktycznie każdy zna i nie musi się uczyć i ma biblioteki praktycznie w każdym języku programowania.

0

Przeglądam tak sobie dokumentację na stronie twojego projektu i nie znalazłem nigdzie zapisu gramatyki twojego formatu (być może słabo szukałem). Widziałem co prawda przykłady zastosowania, nie sądzisz jednak, że udostępnienie gramatyki ułatwiłoby przeniesienie funkcjonalności do innych języków ? Zapis formalny nie zawsze jest przejrzysty ale już dla programisty piszącego taki analizator składniowy może być sporym ułatwieniem i może zmniejszyć prawdopodobieństwo wystąpienia rozbieżności między implementacjami bądź wyjaśnić ewentualne nieścisłości, których same przykłady nie muszą prezentować :)

1

@Rev:

Zupełnie nie podoba mi się system typów atrybutów, a jeszcze bardziej sposób ich zapisu.

A konkretniej? Bo nie wiem czy masz na myśli słowo kluczowe attr, identyfikator mogący się składać z praktycznie wszystkich dostępnych dla UTF-8 znaków, sposób zapisu samej wartości atrybutu czy zapis wieloliniowej wartości; Uściślij proszę;

Nie ma nic o zakresach, o binarnej reprezentacji

O jakich zakresach? Binarna reprezentacja jest bardzo szczegółowo opisana w specyfikacji;

zapisy są niejednoznaczne

Tu podobnie - zapisy czego? Piszesz dość ogólnie, więc ciężko mi cokolwiek odpisać;

bardzo pokracznie pokręciłeś user-defined locale z gdzieniegdzie sztywnym polskim zapisem.

Mały problem miałem z informacjami dotyczacymi uzależnienia pewnych zapisów od danej lokalizacji; Myślę, że nie jest aż tak źle i nie jest trudno zrozumieć te wytyczne; Ale dziękuję za informacje - postaram się te zapisy poprawić, aby nie było wątpliwości;

niezbyt zachęcające jest dla nich to, że z projektu ten Pascal wycieka

Nie rozumiem - przecież musiałem napisać to, że API jest napisane w Pascalu, a konkretniej dla FPC; Oczywiście zdaję sobie sprawę, że Pascal nie jest jakimś szczególnie popularnym i szeroko stosowanym językiem, ale nie uważam, że programowanie w tym języku to strata czasu;

Chyba że masz na myśli składnię formatu? Składnia jest wzorowana na dwóch językach - Pascalu i Visual Basicu - dlatego opiera się na słowach i frazach kluczowych oraz wykorzystuje liniową budowę plików tekstowych; Dzięki temu zapisane drzewa w formie tekstowej są bardzo czytelne, a ich zapisy są jednoznaczne, co było jednym z głównych celów;


@krwq:

Wg. mnie fajny projekt na zabicie nudy, ale nie widzę powodu dlaczego ktoś miałby kiedykolwiek użyć ten format, a nie XML którego praktycznie każdy zna i nie musi się uczyć i ma biblioteki praktycznie w każdym języku programowania.

Nie pisałem tego API dla zabicia czasu, tylko z potrzeby, a dodatkowo udostępniłem otwarte API do pobrania i wykorzystania; Ja z tego formatu korzystam obecnie i będę korzystać, a skoro już udostępniłem API, to i przygotowałem materiały (dokumentację API i specyfikację formatu), aby było wiadomo jak tworzyć pliki konfiguracyjne i obsługiwać je przez API;

Wiem i zdawałem sobie sprawę, że spotkam się z dużym oporem, dlatego że tego typu nowości nie są szeroko aprobowane i wyczekiwane; Przyzwyczajenie do istniejących od dłuższego czasu technologii i mnogość bibliotek w wielu językach utrudnia zaproponowanie czegoś nowego; Ale nie żałuję - mam coś, co zawsze chciałem mieć, więc nawet jeśli nikt prócz mnie z tego nie skorzysta (choć ruch na stronie projektu jest niezły jak na słabą reklamę projektu), to i tak nie będę uważał, że straciłem czas; Format miał być dla mnie - dopiero pod koniec prac postanowiłem się podzielić kodem;


@matek3005:

Przeglądam tak sobie dokumentację na stronie twojego projektu i nie znalazłem nigdzie zapisu gramatyki twojego formatu

No i nie znajdziesz opisu w dokumentacji, bo ona opisuje API, a nie format; Wszelkie informacje dotyczące gramatyki formatu i jego funkcjonalności zawarte są w specyfikacji, zarówno dotyczące formy tekstowej, jak i binarnej;

Specyfikację starałem się napisać tak, aby zawrzeć wszelkie ważne informacje i aby wszystko było opisane jednoznacznie; Jeśli coś jest niejasne to pytajcie śmiało - postaram się wyjaśnić i ewentualnie poprawić materiały na stronie;


Pamiętajcie jednak, że przykładowe pliki podane czy to w specyfikacji formatu, czy w dokumentacji (bądź tutorialu obsługi API) są minimalistyczne; W specyfikacji na samym początku jest podana zawartość przykładowego pliku konfiguracyjnego, który sprawia wrażenie przesadzonego i nieczytelnego; Powodem jest mała ilośc zapisanych informacji przy jednoczesnym zastosowaniu pełnej funkcjonalności - czyli użyte są wszystkie bajery, jak referencjonowanie elementów, komentarze i linkowanie zewnętrznych plików;

W dedykowanych plikach dla danego programu nie trzeba stosować wszystkiego - to tylko możliwości, które zastosować można, ale nie trzeba; Te zabiegi mają służyć przede wszystkim do dzielenia długich konfiguracji na mniejsze części i do zwiększenia czytelności długich drzew, a nie do utrudniania analizy zawartości plików;

Dziękuję za krytykę - wezmę to pod uwagę przy rozwijaniu projektu; Jeżeli macie jeszcze jakieś pytania dotyczące formatu to pytajcie śmiało - postaram się odpowiedzieć i podać jakieś przykładu zapisu, aby zobrazować swoje argumenty.

2

Po długiej przerwie czas na kolejną aktualizację;

Zmiany objęły jedynie API do obsługi tekstowych i binarnych plików TreeStructInfo; Nowymi elementami są dwie metody z klasy TSimpleTSInfoFile, które mają na celu pomoc przy tokenizowaniu elementów drzewa; Owymi metodami są:

procedure RenameAttributeTokens(ANodePath, AAttrName: AnsiString; AStartIndex: Integer; ADirection: TRenamingDirection);
procedure RenameChildNodeTokens(ANodePath, ANodeName: AnsiString; AStartIndex: Integer; ADirection: TRenamingDirection);

Metody te służą do masowej zmiany nazw elementów, które mogą być tokenizowane (atrybutów lub węzłów); Funkcje te są przydatne, aby po dodaniu czy usunięciu elementów z węzła, była możliwość nazwania ich po kolei, gdzie jedynym zmiennym fragmentem w nazwie jest numerek; Dzięki tym metodom można ustalić kolejne nazwy elementom, aby na żądanie móc odwoływać się do nich według standardowych ścieżek dostępu; A że format nie przewiduje duplikacji nazw elementów jednego typu w jednym węźle-rodzicu, metody te są bardzo przydatne;

Przykładowe użycie metody zmianiającej nazwy atrybutów:

uses
  TSInfoFiles, TSInfoTypes;
var
  tsiConfig: TSimpleTSInfoFile;
begin
  tsiConfig := TSimpleTSInfoFile.Create('C:\Config.tsinfo', [ffLoadFile, ffTextFile, ffWrite]);
  try
    try
      { dodanie/usunięcie atrybutów }
    finally
      tsiConfig.RenameAttributeTokens('Node Name\', 'Item %d', 0, rdAscending);
    end;
  finally
    tsiConfig.Free();
  end;
end;

W pierwszym parametrze podaje się nazwę lub ścieżkę węzła, w którym znajdują się elementy do zmiany nazw (pusty ciąg oznacza aktualnie otwarty węzeł), w drugim nową nazwę dla elementów, gdzie znacznik %d określa miejsce wstawiania kolejnych numerków (znacznik jest obowiązkowy i może istnieć w ciągu nazwy tylko raz); Trzecim parametrem jest początkowy indeks, a ostatnim kierunek iterowania:

  • rdAscending - indeksy będą rosnąć o 1,
  • rdDescending - indeksy będą maleć o 1;
    Metody te mogą być używane także w przypadku drzew linkowanych z osobnych plików - wystarczy podać ścieżkę do węzła-rodzica z dowolnego drzewa dołączanego (tekstowego lub binarnego, linkowanego jedno- lub wielopoziomowo); Stan referencjonowania elementów nie ma znaczenia;

Wymienione metody póki co nie są opisane w dokumentacji, podobnie jak typ TRenamingDirection; Będą one częścią nowej wersji API (wersja 1.1), w której być może znajdą się jeszcze inne nowe rzeczy, albo zostaną poprawione te obecne; W każdym razie nowe metody i kilka innych rzeczy znajduje się już w repo na GitHub; Z repozytorium zostały także usunięte kopie plików źródłowych z katalogu Package - od teraz plik projektu paczki linkuje pliki źródłowe z katalogu Source.

2

@babubabu - zrobiłem krótki program do testów, skoro chcesz się pobawić :]

Kod programu:

program TSInfoTester;

{$MODE OBJFPC}{$LONGSTRINGS ON}{$HINTS ON}

  {$DEFINE OLD_API_TEST}
//{$DEFINE DUMP_TO_FILE}
//{$DEFINE MULTIPLE_TESTS}

uses
  Windows, TSInfoFiles, TSInfoTypes, SysUtils;

const
  ELEMENTS_COUNT = UInt32(100);
  OUTPUT_FILE_NAME = UTF8String('C:\Config.tsinfo');
  {$IFDEF MULTIPLE_TESTS}
  TEST_COUNT = UInt32(10);
  {$ENDIF}
var
  tsiConfig: TTSInfoFile;
  intChildNodeToken, intSubChildNodeToken, intAttrToken: Int32;
  intStart: Int64 = 0;
  intStop: Int64 = 0;
  intFreq: Int64 = 0;
  {$IFDEF OLD_API_TEST}
  strChildNode, strSubChildNode: UTF8String;
  {$ENDIF}
  {$IFDEF MULTIPLE_TESTS}
  intTestToken: UInt32;
  {$ENDIF}
begin
  QueryPerformanceFrequency(intFreq);

  {$IFDEF MULTIPLE_TESTS}
  for intTestToken := 0 to TEST_COUNT - 1 do
  begin
  {$ENDIF}
    tsiConfig := TTSInfoFile.Create(OUTPUT_FILE_NAME, [ffTextFile {$IFDEF DUMP_TO_FILE}, ffWrite {$ENDIF}]);
    try
      QueryPerformanceCounter(intStart);

      for intChildNodeToken := 0 to ELEMENTS_COUNT - 1 do
      try
        {$IFDEF OLD_API_TEST}
        strChildNode := Format('Node [%d]', [intChildNodeToken]);
        tsiConfig.CreateChildNode('', False, strChildNode);
        {$ELSE}
        tsiConfig.CreateChildNode('', False, Format('Node [%d]', [intChildNodeToken]), True);
        {$ENDIF}

        for intSubChildNodeToken := 0 to ELEMENTS_COUNT - 1 do
        try
          {$IFDEF OLD_API_TEST}
          strSubChildNode := Format('SubNode [%d]', [intSubChildNodeToken]);
          tsiConfig.CreateChildNode(Format('%s\', [strChildNode]), False, strSubChildNode);
          {$ELSE}
          tsiConfig.CreateChildNode('', False, Format('SubNode [%d]', [intSubChildNodeToken]), True);
          {$ENDIF}

          for intAttrToken := 0 to ELEMENTS_COUNT - 1 do
          begin
            {$IFDEF OLD_API_TEST}
            tsiConfig.CreateAttribute(Format('%s\%s\', [strChildNode, strSubChildNode]), False,
                                      Format('Attribute [%d]', [intAttrToken]));
            {$ELSE}
            tsiConfig.CreateAttribute('', False, Format('Attribute [%d]', [intAttrToken]));
            {$ENDIF}
          end;
        finally
          {$IFNDEF OLD_API_TEST}
          tsiConfig.GoToPreviousNode();
          {$ENDIF}
        end;
      finally
        {$IFNDEF OLD_API_TEST}
        tsiConfig.GoToPreviousNode();
        {$ENDIF}
      end;

      QueryPerformanceCounter(intStop);
    finally
      WriteLn('Creating time: ', ((intStop - intStart) / intFreq):2:3, ' sec');
      {$IFDEF DUMP_TO_FILE}
      QueryPerformanceCounter(intStart);
      {$ENDIF}
      tsiConfig.Free();
      {$IFDEF DUMP_TO_FILE}
      QueryPerformanceCounter(intStop);
      WriteLn('Dumping time:  ', ((intStop - intStart) / intFreq):2:3, ' sec');
      {$ENDIF}
    end;
  {$IFDEF MULTIPLE_TESTS}
  end;
  {$ENDIF}

  Write('done...');
  ReadLn;
end.

Utwórz nowy konsolowy program, dołącz do niego albo surowe pliki źródłowe, albo dodaj paczkę TreeStructInfo w menu Project\Project Inspector i gałąź Required Packages (ewentualnie jeszcze paczkę LCL);

Co wykonuje program - tworzy nowy obiekt drzewa klasy TTSimpleTSInfoFile, a następnie tworzy milion zagnieżdżonych elementów wewnątrz drzewa; Wygenerowany plik znajdzie się w C:\Config.tsinfo, będzie zajmował niecałe 30MiB i ponad milion linii tekstu;

Do dyspozycji są częściowo zaremowane definicje w dyrektywach kompilatora:

  • {$DEFINE OLD_API_TEST} - testuje starą wersję API, przed wprowadzeniem nowej metody (implementacja tej metody jest tylko u mnie w lokalnym repo, oraz nie jest dokończona, więc ta definicja musi być odblokowana),

  • {$DEFINE DUMP_TO_FILE} - mierzy dodatkowo czas zapisu drzewa z pamięci do pliku, choć wiadome że czas na róznych dyskach i systemach będzie różny,

  • {$DEFINE MULTIPLE_TESTS} - wykonuje 10 testów tworzenia i ewentualnie zapisu drzewa, jeśli zaremowana - wykonuje jeden test;
    Opis maszyny, na której wykonałem testy:

  • procesor - Celeron 1,13GHz

  • pamięć RAM - 512MB

  • system - WinXP
    Output po 10 testach starego API, bez testu zapisu na dysk i na prawie całkiem odciążonej maszynie:

Creating time: 32.217 sec
Creating time: 32.131 sec
Creating time: 32.228 sec
Creating time: 31.833 sec
Creating time: 30.898 sec
Creating time: 30.857 sec
Creating time: 30.998 sec
Creating time: 30.853 sec
Creating time: 31.132 sec
Creating time: 30.657 sec
done...

i output tego samego, ale z użyciem nowej metody GoToPreviousNode, która zwalnia z szukania węzła-rodzica przy tworzeniu nowych elementów:

Creating time: 6.215 sec
Creating time: 6.056 sec
Creating time: 6.238 sec
Creating time: 6.248 sec
Creating time: 6.141 sec
Creating time: 6.105 sec
Creating time: 6.319 sec
Creating time: 6.209 sec
Creating time: 6.153 sec
Creating time: 6.118 sec
done...

Jak widać przy tak dużej ilości tworzonych elementów, nowa metoda jest kluczowa; Testy przeprowadzane poza debugerem, plik zawierał symbole debugera i został zoptymalizowany metodą -O1 (podstawowa optymalizacja);

@babubabu - jeśli chcesz przetestować także działanie testera z użyciem metody GoToPreviousNode, to dodaj do klasy TSimpleTSInfoFile publiczną metodę zadeklarowaną w ten sposób:

procedure GoToPreviousNode(AKeepReadOnlyMode: Boolean = True); experimental;

a zdefiniowaną tak:

procedure TSimpleTSInfoFile.GoToPreviousNode(AKeepReadOnlyMode: Boolean = True);
begin
  if FCurrentNode.FParentNode = FRootNode then
  begin
    FCurrentNode := FRootNode;
    FCurrentlyOpenNodePath := '';
  end
  else
    FCurrentNode := FCurrentNode.FParentNode;

  if not AKeepReadOnlyMode then
    FReadOnlyMode := False;
end;

i możesz zablokować dyrektywę {$IFDEF OLD_API_TEST} - powinno się skompilować bez warningów i hintów;

To w sumie tyle; Ewentualnie jeżeli plik ma być tworzony gdzieś indziej niż bezpośrednio na dysku C:\ - zmień wartość stałej OUTPUT_FILE_NAME na inną; Jak potestujesz to pochwal się wynikami.

1

AMD Athlon II 640 x4 3.0GHz 6GB RAM DDR3 1333MHz
Output:

Creating time: 7.855 sec
Creating time: 7.731 sec
Creating time: 7.850 sec
Creating time: 7.837 sec
Creating time: 8.009 sec
Creating time: 7.794 sec
Creating time: 7.865 sec
Creating time: 7.788 sec
Creating time: 7.822 sec
Creating time: 7.743 sec
done...

copy-paste kod testowy. Dodanie odpowiednich paczek i ciśnięcie F9 Nic nie wyłączałem i nie optymalizowałem. W tle:

  • Lazarus
  • Opera
  • Steam
  • Skype
  • Avast!
  • Curse
  • Daemon tools
  • i jeszcze jakieś śmieciowe programiki.

Intel Core i5-4570 3.20GHz 8GB RAM 2133MHz
Output:

Creating time: 3.864 sec
Creating time: 3.817 sec
Creating time: 3.822 sec
Creating time: 3.827 sec
Creating time: 3.834 sec
Creating time: 3.811 sec
Creating time: 3.824 sec
Creating time: 3.804 sec
Creating time: 3.821 sec
Creating time: 3.818 sec
done...

Też kupę śmieciowych programów w tle.

Na obu piecach Win7 Home Premium 64-bit

1

Ja wiedziałem, że mój dziadziuś pracuje baaardzo wolno w porównaniu do sprzętu na dzisiejszym poziomie (wiele rdzeni, wiele GB pamięci), ale nie przypuszczałem, że różnica będzie aż tak duża; Milion elementów to dużo, nie sądzę żeby komukolwiek była potrzebna tak duża konfiguracja; A nawet jeśli, to tak ogromną ilość danych lepiej trzymać w bazie danych, a nie plikach tekstowych; Ale i tak cieszę się, że API działa tak szybko :]

Zapewne będzie jeszcze wiele poprawek i nowych rzeczy, z czego metodę GoToPreviousNode planuję wdrożyć już od dłuższego czasu; Jednak muszę brać pod uwagę to, że metoda OpenChildNode pozwala na otwarcie dowolnego węzła, nawet znajdującego się w wielopoziomowo linkowanym drzewie; A że główny węzeł linkowanego drzewa nie posiada wskazania na węzeł dołączający drzewo, muszę opracować sposób na "wychodzenie" z linkowanego drzewa; Da się to łatwo zrobić na podstawie ścieżki z pola FCurrentlyOpenNodePath, więc trzeba to tylko potestować;

@babubabu - gdybyś mógł jeszcze przetestować nową metodę (odpiąć definicję OLD_API_TEST), to byłbym wdzięczny; Przygotowany moduł TSInfoFiles.pp (zawierający wymaganą metodę GoToPreviousNode) dodaję do załączników tego posta.

0
C:\lazarus\dodatki\treestructinfo 1.0 stable (official package)\TSInfoFiles.pp(346,123) Error: Identifier not found "TRenamingDirection"
C:\lazarus\dodatki\treestructinfo 1.0 stable (official package)\TSInfoFiles.pp(347,123) Error: Identifier not found "TRenamingDirection"
C:\lazarus\dodatki\treestructinfo 1.0 stable (official package)\TSInfoFiles.pp(583,1) Fatal: There were 2 errors compiling module, stopping
2

AMD Athlon II 640 x4 3.0GHz 6GB RAM DDR3 1333MHz
Output:

Creating time: 1.406 sec
Creating time: 1.404 sec
Creating time: 1.385 sec
Creating time: 1.391 sec
Creating time: 1.384 sec
Creating time: 1.377 sec
Creating time: 1.384 sec
Creating time: 1.380 sec
Creating time: 1.378 sec
Creating time: 1.381 sec
done...

I kupę śmieciowych programów w tle.

Na i5 nie testuje bo wyłączony i ogólnie spadam spać bo rano do roboty. Ale biorąc pod uwagę fakt, że i5 jest mniej więcej 2x wydajniejszy od athlona to czasy powinny spaść poniżej sekundy. Jak nie zapomnę to wrzucę jutro wyniki z i5.


Nie wpadłeś na pomysł by rozdzielić niektóre zadania na wątki? Mogę trochę pomóc bo fascynuje mnie rozbijanie czasochłonnych zadań na wątki.
Sortowanie bąbelkowe, można powiedzieć, ukończyłem. Brakuje tylko jednego warunku :P

0

Heh, nieźle - dziękuję za testy :]

Ale biorąc pod uwagę fakt, że i5 jest mniej więcej 2x wydajniejszy od athlona to czasy powinny spaść poniżej sekundy. Jak nie zapomnę to wrzucę jutro wyniki z i5.

Fajnie by było, jakby co to będę czekał na nowe wyniki;

Nie wpadłeś na pomysł by rozdzielić niektóre zadania na wątki? Mogę trochę pomóc bo fascynuje mnie rozbijanie czasochłonnych zadań na wątki.

No niebardzo - ten program ma służyć jedynie do przetestowania szybkości API, jeśli o inne cele chodzi, to jest bezużyteczny; Poza tym po co była by mi tak gigantyczna konfiguracja? Kilkaset czy kilka tysięcy elementów to jeszcze by uszło, ale co zapisywać w milionie elementów?

Załadowanie lub utworzenie pliku Config.tsinfo spowoduje zaalokowanie ~70MiB w pamięci RAM, więc narzut jest względnie mały, w porównaniu do rozmiaru pliku na dysku (~30MiB); Ale to bardziej ciekawostka, bo taka konfiguracja jest przerostem formy nad treścią;


Druga sprawa - przy bardzo dużych konfiguracjach (jak ktoś koniecznie nie chce bazy danych) zalecam skorzystanie z binarnej formy; Daje ona sporego kopa przy ładowaniu i zapisywaniu plików, bo nie musi formatować zawartości i robić innych, zbędnych w tym przypadku rzeczy; Ale tak jak pisałem i napiszę jeszcze raz (na zaś) - ten format ma służyć względnie małym konfiguracjom, do bardzo dużych czy gigantycznych konfiguracji, od tekstowych plików dużo wydajniejsze są systemy bazodanowe; Choć słyszałem już o takim wariactwie, jak gigabajtowe pliki XML... paranoja...

0

@furious programming Można liczyć w najbliższym czasie na repo z testami?

1

Jeśli tylko znajdę czas to na pewno dorzucę do repo przede wszystkim walidator plików, żeby można było łatwo sprawdzić czy plik jest poprawny czy nie; O testowych plikach i testowych programach także pomyślę;

Ale tak jak wspomniałem - jeśli tylko znajdę chwilę wolnego czasu :]

1

Powoli przymierzam się do zaimplementowania zabezpiecznia przed zapętleniem linkowania;

Takie zabezpiecznie będzie służyć przede wszystkim do wykrycia próby linkowania pliku, który został już wcześniej załadowany; Jest to ważne nie tylko ze względu bezpieczeństwa, ale pozwoli także na dodanie nowej - ciekawej funkcji; Tą funkcją docelowo ma być możliwość dołączania tego samego pliku w wielu miejscach w drzewie, ale bez każdorazowego ładowania pliku do pamięci; Czyli dostęp do pliku będzie możliwy z więcej niż jednego miejsca w drzewie (za pomocą różnych ścieżek dostępu), ale obiekt z załadowanym drzewem w pamięci będzie tylko jeden;

Funkcja ta pozwoli po pierwsze na zapewnienie bezpieczeństwa ładowania bardziej złożonych konfiguracji, a po drugie na rozszerzenie funkcji linkowania zewnętrznych plików; Oczywiście nadal możliwe będzie dowolne mieszanie plików w formie tekstowej i binarnej;

Te i inne nowości zostaną w najbliższych miesiącach dodane do API, a jeśli wszystko pójdzie dobrze i testy nie wykażą błędów - pojawi się wersja 1.1 oficjalnej biblioteki; A w niedługim czasie także i dokumentacja oraz tutorial do tej wersji API.

1

Prace nad kolejną wersją API we Free Pascalu powolutku idą do przodu; Kilka dni temu zabrałem się za rozwijanie biblioteki, tak abym w swoim projekcie mógł użyć nowej jej wersji; Kolejna wersja przyniesie dużo zmian i dużo małych poprawek, zwiększających wygodę użytkowania API i posiadających kilka dodatkowych zabezpieczeń;

Przede wszsytkim zmieniony został mechanizm ładowania plików z różnych źródeł - nie będzie to już wykonywane w konstruktorze klasy TSimpleTSInfoFile; Zamiast kilku przeładowanych konstruktorów, stworzone zostały osobne metody typu LoadFrom*, dzięki czemu stworzenie pustego drzewa realizowane będzie za pomocą konstruktora, a załadowanie drzewa z danego źródła (pliku, strumienia, listy, zasobu zwykłego lub zasobu Lazarusa) umożliwiać będzie pięć metod typu LoadFrom*;

Drugą dużą zmianą będzie przepisany mechanizm parsera, który nie będzie korzystał z wstępnego komponowania zawartości pliku (czyli przeniesienia linii definicji elementów referencjonowanych w miejsca ich deklaracji); W zamian wykorzystywał będzie kolejkę (FIFO), w której najpierw zostaną odłożone elementy referencjonowane, a następnie zostaną przeniesione w odpowiednie miejsca w drzewie; To powinno przede wszystkim zmniejszyć ilość kodu parsera, a być może spowoduje także poprawę efektywności; Ale to dowiem się w najbliższych dniach, dlatego że dopiero zabieram się za poprawienie kodu klas TTSInfoTextInputReader i TTSInfoTextOutputWriter;

Klasa kolejki - TTSInfoElementsQueue - do wstępnego przechowania natywnych elementów referencjonowanych (już po ich przeparsowaniu) wykorzystuje mechanizm listy jednokierunkowej, co sprawia, że zarówno dodanie nowego elementu do kolejki jak i jego zdjęcie będzie szybsze, niż w przypadku użycia tablicowego bufora; Klasa bazowej listy elementów - TTSInfoElementsList - do tej pory używała właśnie takiego tablicowego bufora, wykorzystywanego m.in. w bazowej klasie TStrings; W nowej wersji API także będzie działać na podstawie listy jednokierunkowej, co przyspieszy przede wszystkim tworzenie drzewa w pamięci, dzięki czemu m.in. wzrośnie szybkość ładowania drzewa w postaci tekstowej; Właśnie zabieram się za testy tej klasy - wygląda obiecująco;

Dużą i bardzo ważną rzeczą będzie dodanie zabezpieczenia, które uniemożliwi zapętlenie linkowania plików dołączanych; Jest to dość trudne, dlatego że biblioteka musi być niezależna od platformy; Zbudowanie takiego mechanizmu na podstawie ścieżek do plików będzie trudne, ale mam kilka innych pomysłów bazujących na otwieraniu kolejnych plików i pozostawienie ich otwartych przez cały proces ładowania; Dzięki temu będzie można wykryć zapętlenie - próba otwarcia już otwartego i zablokowanego do odczytu pliku spowoduje rzucenie wyjątku;

To tyle, jeśli o główne zmiany chodzi - pomniejszych będzie też dużo, ale nie ma co ich wymieniać; W każdym razie zmieny obejmą jedynie API - składnia formatu i jego funkcjonalność pozostają bez zmian;

W poprzednim poście ze stycznia wspomniałem, że nowa wersja biblioteki oznaczona będzie numerem 1.1 - niestety tak się nie stanie; Nowe API nie będzie wstecznie kompatybilne (głównie za sprawą oddzielenia ładowania drzew od konstruktorów), dlatego też nowa wersja oznaczona zostanie numerem 2.0; Nie wiem dokładnie kiedy nowa wersja zostanie ukończona, jednak nie później niż za miesiąc, góra dwa;


Z racji tej, że @spartanPAGE dzielnie walczy z przygotowaniem biblioteki dla C++ i w najbliższych tygodniach powinien ją ukończyć - projekt TreeStructInfo staje się projektem forumowym; Dlatego też przenoszę ten wątek do niedawno utworzonej nowej kategorii forum - **http://4programmers.net/Forum/Spolecznosc/Projekty**;

Zachęcam do przyłączenia się do prac nad rozwojem projektu - przydaliby się magicy od C# i Java :]

1

ostatnio stanalem przed koniecznoscia wyboru formatu configow w jednym projekcie, dla beki rozwazylem tez treestructinfo

jaka jest jedna zaleta tego formatu ktorej nie ma YAML?

formal spec yamla jest krotszy niz treestruct, jezeli patrzymy tylko na rozdzialy z ficzerami, a nie wyjasnienia dot kodowania stringow itp

1 użytkowników online, w tym zalogowanych: 0, gości: 1