Jump to content

darnocian

Members
  • Content Count

    133
  • Joined

  • Last visited

  • Days Won

    3

Everything posted by darnocian

  1. I've been experimenting with an integrated playground IDE plugin for the Sempare Template Engine ( https://github.com/sempare/sempare-delphi-template-engine or via GetIt). The template engine is available under Apache 2.0 and has been around for years, and has backward capability back to XE4. The playground plugin is similar to the standalone playground demo app that exists in the project. Anyways, I decided it was time to have a richer IDE experience. My initial development currently it supports: - highlighting (script tags, comments, numbers, strings) - toggling whitespace visibility - IDE Options Dialog allows you to customise options (overriding defaults which are IDE theme aware) - Supports prototyping templates against mock data (in json files) - Supports script tags <% %> or {{ }} - Real-time validation of templates and evaluation/preview - Preview as raw text or in a browser As I changed the license of the template engine to be Apache from GPL, this will be available initially to supporters of the project. More to follow... Any other ideas/improvement suggestions welcome. Here are some screenshots:
  2. I stumbled across this thread again and thought I'd just add a reference to https://dev.to/sempare/accessing-data-from-the-sempare-template-engine-for-delphi-5dg8 It illustrates various approaches to accessing data from the template engine. In the thread above, we discussed static methods, but in the article you can easily see how you can access data from data stored in the context, or by creating a custom object with methods on it, which can then be called.
  3. AColorProp := LType.GetProperty('ColorProp'); Val := AColorProp.GetValue(ColorObj); //Memo1.Lines.Add('ColorObj.ColorProp.ToString = ' + ColorObj.ColorProp.ToString); Memo1.Lines.Add('ColorObj.ColorProp.ToString = ' + Cardinal(ColorObj.ColorProp).ToString); Memo1.Lines.Add('TValue.ToString = ' + Val.ToString); Should Val.ToString not be Val.AsType<TColorObj>.ToString ? I don’t think TValue.ToString is what you were expecting. It is more diagnostic in nature if you look at its implementation, as it supports all kinds of types. I suspect that what you’re seeing is simply an interpretation based on the contained value. However, in RTTI, these values are usually cast to their correct types—especially when passed to a TRttiMethod or similar, where FTypeInfo is considered appropriately.
  4. I made a little FMX test app a few years back just to see how floating point differed in performance cross platform: https://github.com/darnocian/delphi-gausslegendre-pi-approximation-test It was nothing special and just a test using Extended / Double. The approximation function was implemented in https://github.com/darnocian/delphi-gausslegendre-pi-approximation-test/blob/master/gauss.legendre.pi.pas I havn't run the benchmark again recently, but at the time, it did highlight that cross platform, a review was required of how the underlying floating point stuff was being done in the various compilers as some were way out...
  5. darnocian

    win11 24h2 msheap fastest

    I have witnessed similar behaviour actually with the MS memory manager. For one of my projects, I also switched to using the MS memory manager. I did benchmarks a while ago, but will look into publishing something in future.
  6. darnocian

    String memory usage

    I think the official term being referenced is 'string interning'.https://en.wikipedia.org/wiki/String_interning Scenarios where it may be useful is with JSON, results from dbs, or when custom collections containing strings from file or network. Depending on how the data is pulled in, you may have a spike in memory if all f the raw data is loaded, followed by the interning process which may normalise the structures. If the data is loaded incrementally, memory utilisation should correlate to the levels of duplication you know exists in the data. There is some overhead to the interning process in terms of constantly trying to deduplicate, so it depends on your scenario. If you keep the data in memory for a longish period of time, I think it can be useful to do this, especially if you are a ware that memory utilisation is a concern in your problem space. C# has a .Intern() method on string https://learn.microsoft.com/en-us/dotnet/api/system.string.intern?view=net-8.0. Similar in Java https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/String.html#intern() As Delphi strings are reference counted, you could say that having multiple variables assigned to the same string would be a form of interning. e.g. var str := 'hello world'; var str2 := str; var str3 := str; All of the above will reference the same data. Under the hood there should be a reference count (3). A non thread-safe approach to illustrate leveraging the above property by managing a TDictionary<string,string>: var GInternedStrings : TDictionary<string,string>; function Intern(const AString:string) : string; begin if not GInternedStrings.TryGetValue(AString, Result) then begin GInternedStrings.Add(AString, AString); Result := AString; end; end; initialization GInternedStrings := TDictionary<string,string>.Create; finalization GInternedStrings.Free; Here we see a lookup being done on the pool, and result being populated with a value from the pool if it exists. If no value exists, we simply add the value too the pool, and return the original. This could be used like: for var rec in records do begin rec.str := Intern(rec.str); end; Obviously, if you decide to go multi threaded, you would need to introduce some synchronisation, which will add some performance overhead due to locking and unlocking to keep the dictionary consistent. If you don't do anything multithreaded, you can get away with not having a sync object and could even just allocate a local pool in your loading procedure to localise the lifetime of the pool. Having the global pool will mean that you will have that memory 'permanently' allocated... so however you decide to manage the pool depends on your use case. Ideally, the functionality that loads data, such as TJSONValue.ParseJSONValue() or db query libraries would offer an option to do this. However, in many cases, I suspect it may be seen as an overhead in itself if the data is loaded into memory, processed and discarded. So the lifetime of the data in the app and how it is used is relevant to the effort of doing this all over.
  7. Hi, I am pleased to announce a new version of the Sempare Template Engine - v1.8.0. (https://github.com/sempare/sempare-delphi-template-engine) The Sempare Template (scripting) Engine for Delphi allows for flexible dynamic text generation. It can be used for generating email, html, reports, source code, xml, configuration, etc. Changes: NEW support calling methods on interfaces NEW support accessing properties on interfaces NEW simplified white space removal (https://github.com/sempare/sempare-delphi-template-engine/blob/main/docs/whitespace-removal.md) NEW License change to Apache 2.0 FIX to support issues under XE7 FIX AV when method method does not exist FIX improved error messaging on exceptions FIX regex threadsafety issue in lexer Most notably, license change has been from GPL to Apache 2.0. Commercial supporters are still appreciated for my time, continuous integration, support, etc. For those that don't know what this is all about, I gave a talk at Delphi Devdays 2024 this year. Here is a link to my talk: I'm hoping the Sempare Template Engine still remains one of the more feature rich, easy to use, and most pascal centric template engines out there for Delphi. Next focus in the development pipeline is native code generation from existing templates to allow you to get native speed without requiring you to make any changes (except including another source file that is auto generated from your templates). Sponsorship is appreciated.
  8. For those that are interested in a few lightweight tutorials, here are some short reads: Accesing a FireDAC dataset from the Sempare Template Engine for Delphi Accessing data from the Sempare Template Engine for Delphi Creating layouts using the Sempare Template Engine Configuring the Sempare Template Engine for Delphi Using the Sempare Template Engine for Delphi Using loops in the Sempare Template Engine for Delphi Functional templates with the Sempare Template Engine for Delphi Introducing the Sempare Template Engine Playground Wizard for the Delphi RAD Studio IDE
  9. @Ian BranchThe new version 1.8 is now available on GetIt.
  10. Yes. The request is in, but it takes a few days.
  11. Again, sorry for the cross post: The Sempare Template Engine is now available under the Apache 2.0 licensing.
  12. Hi all, I apologise for doing a double post, but some people don't see the posts everywhere. For any users, or anyone interested in the Sempare Template Engine, I would love to get some feedback from you to help with next steps in development on the project. The questionnaire is a bit general, as the objective is to guide the direction of this project and another I will be releasing soon as well. https://docs.google.com/forms/d/e/1FAIpQLScioIiDxvsWK01fMFqYr9aJ6KhCGeiw4UaU_esGuztEE7vYwA/viewform Thank you in advance. Regards, Conrad
  13. darnocian

    Sempare Template Engine 1.7.7

    Hi All, Just a quick ping that an update to the Sempare Template Engine is now available... v1.7.7 It is also available on GetIt. Please star the project if you havn't already. (Thanks) Also for those watching Delphi Dev Days (https://www.codegear.com/DevDaysofSummer/) ... There will be a video posted today (15 Aug) with some demos showing some features and how easily the template engine can be included into projects... https://github.com/sempare/sempare-delphi-template-engine Changes: - fixed a few things - new 'functional includes' syntatic sugar - release mode builds will fail if the license confirmation is not acknowledged - also fully CI enabled now on github ... what is a functional include... Lets say we have a main template where we are creating an html form: <form method=post action=/register> Name: <input name=name> E-mail: <input name=email> <input type=submit value=register> </form> so what we could do from a templating perspective: <% template 'input' %> <% label %>: <input name=<% name %>> <% end %> <% template 'button' %> <% label %>: <input type=<% type %>> <% end %> <form method=post action=/register> <% input { label="Name", name="name" } %> <% input { label="E-mail", name="email" } %> <% button { label="register", type="submit" } %> </form> So above, you can see that we can have 'inline templates' that are named 'input' and 'button'. In the form section, the 'functional include' syntax is then used to pass the params... The alternative way of doing the include traditionally is a bit more verbose, but essentially the same: <form method=post action=/register> <% include 'input', { "label": "Name", "name": "name" } %> <% include 'input', { "label": "E-mail", "name": "email" } %> <% include 'button', { "label": "register", "type": "submit" } %> </form> The above is a bit more verbose, passing a dictionary, whereas the 'functional include' syntax can be a bit more pretty on the eye... So the nice thing then is that the inline templates could be moved out to separate files. The template registry can then be configured to load the various templates as required - from disk, resources, db, etc... Custom styling, etc can then be localised to the specific 'atomic' template. This works quite nicely when using stuff like TailwindCSS (https://tailwindcss.com/) , which lends itself to styles being inline rather than being in CSS files... Anyways, have fun. Please support me if you can.
  14. darnocian

    Sempare Template Engine 1.7.7

    Hi all, For any users, or anyone interested in the template engine, I would love to get some feedback from you to help with next steps in development on the project. The questionnaire is a bit general, as the objective is to guide the direction of this project and another I will be releasing soon as well. https://docs.google.com/forms/d/e/1FAIpQLScioIiDxvsWK01fMFqYr9aJ6KhCGeiw4UaU_esGuztEE7vYwA/viewform Thank you in advance. Regards, Conrad
  15. darnocian

    detecting events

    your reference to 'debugview' makes it look like you are also after a logging framework. On getit, there are some options. Using a debugger is great for fault finding, but logging will help with a running app. Using a logging framework, you can decide when you want to enable/disable logging. If you have a console app, the poor man version is 'writeln' 😉
  16. darnocian

    detecting events

    Do you mean like getting stack trace information and looking at the procedure name? There is a feature in the Jedi project that works on Windows that allows you to identify the procedure... https://blog.dummzeuch.de/2014/03/08/using-jcldebug/ describes it conceptually
  17. darnocian

    Simulate Multiple Inheritance

    @Mike Warren All the feedback above is valid, but will add more comments... Just a comment on your interface where you flagged an error: IapShape = interface procedure SetThing(AThing: Boolean); function GetThing : boolean; // this is what was missing property Thing: Boolean read GetThing write SetThing; end; TapRectangle = class(TRectangle, IapShape) // If you want reference counting, TRectangle should inherit from TInterfacedObject, or else, you need to add the ref counting methods somewhere like TRectangle or here... private FThing: Boolean; function GetThing : boolean; // this can be as trivial as: result := FThing; procedure SetThing(AThing: Boolean); public property Thing: Boolean read FThing write SetThing; // this can actually be different to the interface, but ideally, to be consistent, it should be identical to ensure consistent behaviour end; Hope the comments help. It is possible to have a class implement multiple interfaces, and then in code, you can use methods like supports() to check if an interface supports other interfaces... Anyways, as Arnaud mentioned, composition is generally better, but depending on the scenario, having class/interface hierarchies have their uses.... Having a collection of shapes is a scenario which consist of a rectangles, circles, etc, benefits form the inheritance scenario you described, so if there are generic methods that take place on the shape, it may make sense... e.g. shape.draw, shape.area, shape.position ... but to get to the specific details of a shape, much as with classes, you can get an interface specific to the specialisation (TRectangle, IRectangle...) Anyways, the design topic is vast, and can be very opionated as well 😉 My suggestion in line with Arnaud is something like: in the above, your TRectangle or TCircle would be contained in the FShape field
  18. I have that happen fairly often as well. I find closing the project group and re-opening sometimes works... or restarting the IDE... It is a little annoying. ;(
  19. darnocian

    Markdown parsing components for FMX

    unfortunately, they just added support for adding your own markdown documentation, e.g. README.md... unfortunately, it doesn't support some features that are used on many projects on github. Anyways, there is markdown package that I've used for docs: https://github.com/grahamegrieve/delphi-markdown
  20. darnocian

    Firebird database on Android

    I used the windows embedded firebird a few months ago... I think it should be a similar process for Android... You will need to untar/gz the file.... ensure the deployment deploys all the files with your app. The trick is with the whatever driver to map onto libfbclient.so/dll . it is similar to using sqlite in being embedded...
  21. darnocian

    F2047 Circular unit reference.

    It would be awesome feature request if this problem were solved by the compiler. But I suspect we need to be able to allow forward declarations on all types first (e.g. records), before we can go cross unit. As mentioned before, if the stuff causing the circular reference is only needed in the implementation, moving the respective unit(s) referencing the respective the dependencies to the implementation may solve the problem. Otherwise, you need to have another unit that either implements the an interface/base class/abstract class dependencies that can then be used by the respective units where the circular issues exist. In this case, as general abstract strategies, the above techniques have been used to solve this type of problem, without getting into the specifics. I am not so convinced by by this approach, as dmitry identified, it would not be very convenient long term. Some analysis/refactoring is definitely required.
  22. darnocian

    Regression - Delphi 12 - IsZero()

    Ok. I was just hoping for some sort of example, as the SameValue/isZero is a generalised approach. So back to the original post, I guess we can just take it that there are some issues with the new version of the compiler, and will need to log some issues with QP once it is back again.
  23. darnocian

    Regression - Delphi 12 - IsZero()

    I'm still interested to know more about any alternatives to using epsilon for comparison. I've only seen subtle variations on the same theme, and always keen to learn something new.
  24. darnocian

    Creating dylibs for iOS

    Sorry. A bit late to answer now... .a files is a normally a C static library. In C are essentially a container around compiled .o files. There is no point to distribute .a files, unless someone is going to link against it. Typically static libraries are only useful during dev for users of libraries, and not so much for applications as they would get linked in. Your main deliverables from an app perspective would be the executable along with any shared libraries (dlls/so/dylib). Nothing stopping you from shipping anything you want of course. With shared library, the developer using the shared lib just needs to know the directory and filename, and then reference the library and functions appropriately as required. The main thing is that it is clear what platform is used and being able to distinguish 32/64bit. There is no universal convention from what I'm aware of. If you are using Delphi, use the Delphi convention... it is clear enough. <platform>/<configuration>. although, if you are only going to ship release builds, just do <platform>
×