-
Content Count
138 -
Joined
-
Last visited
-
Days Won
4
darnocian last won the day on January 7
darnocian had the most liked content!
Community Reputation
93 ExcellentRecent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
variadic-arguments How to create a Delphi variadic method similar to Write/Writeln without requiring brackets for arguments?
darnocian replied to bravesofts's topic in Algorithms, Data Structures and Class Design
Further, just talking about the safety concepts... I would classify using variadic behaviour with the va_* like functionality as unsafe, even if it is appealing, and possibly more optimal than having them wrapped by an 'array of const', where fields are encoded into a TVarRec etc, I'd rather stick to the pascal idiom as it is easier to loop through the parameters multiple times, query type information as you go , etc. -
variadic-arguments How to create a Delphi variadic method similar to Write/Writeln without requiring brackets for arguments?
darnocian replied to bravesofts's topic in Algorithms, Data Structures and Class Design
You can create vararg functions in Delphi - but not all compilers support it... 32bit Windows DCC32 only binds to external functions (so mapping onto functions exposed from external sources like .obj, .dll, etc) I created a sample to illustrate that works on 12.2 using Win64 compiler... I havn't done a test on older compilers. program VarArgsDemo; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; function SumNumbers(const acount: integer): double; cdecl; varargs; var LVAList: TVarArgList; i: integer; begin result := 0; VarArgStart(LVAList); for i := 0 to acount - 1 do result := result + VarArgGetValue(LVAList, double); VarArgEnd(LVAList); end; begin try writeln(floattostr(SumNumbers(5, 1.1, 2.2, 3.3, 4.4, 5.5))); except on E: Exception do writeln(E.ClassName, ': ', E.Message); end; end. This relies on some magic TVarArgList, VarArgStart, VarArgGetValue, VarArgEnd If you are familiar with C, you will note how these map onto the equivalents: va_list, va_start, va_arg, va_end So VarArgStart positions LVAList in the correct location on the stack so that subsequent calls to VarArgGetValue will extract the values from the stack. Note that it is up to you to come up with the logic to help VarArgGetValue reference the appropriate type so that the LVAlist increment is done appropriately. In my example, I've kept it simple, with the problem just summing ACount doubles. If you think about C's printf, where you may want to support different types like printf("%d %s %f\n", 10, "hello world", 42.123); you would have to parse the string to then call something like VarArgGetValue(LVAList, integer), VarArgGetValue(LVAList, string), VarArgGetValue(LVAList, double) to extract the values to do something meaningful with them. -
Hi, I just got an email from Appercept (https://www.appercept.com) offering a 20% black friday deal on the Appercept AWS SDK for Delphi - for anyone interested in utilising services on Amazon Web Services. A coupon BLACKCYBER20 just needs to be applied on checkout it seems. I have it from through the Emb Enterprise edition, but it may be useful for anyone on Pro that wants access to a very good SDK. IMO It has excellent documentation, responsive support and continuous development!
-
Circular references with API design
darnocian replied to Darian Miller's topic in Algorithms, Data Structures and Class Design
I agree with @Uwe Raabe As you state that the APIs may return structures that cross reference one another - a record would not be suitable here, unless you had pointer support. The record is normally defined as something with a fixed size, and as Uwe pointed out, the interdependence means this constraint would not be met. So you would either need a pointer to a record (a forward can be defined for that), or use classes (that we know are heap bound). If your codegen can do some analysis and identify which entities have interdependencies, you could choose to use records in one case and classes in another, but IMO, just having a single consistent approach will save you in the long run. I'd just go for using classes. -
Sempare Template Engine - new article on the Template Registry
darnocian posted a topic in Tips / Blogs / Tutorials / Videos
The Sempare Template Engine has been around for 5 years, being applied to traditional apps as well as to web. Further, it has support for XE4+. Here is a new article on the Template Registry that can help you to scale template management within your application. https://dev.to/sempare/the-sempare-template-engine-advanced-template-registry-features-29o9 -
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:
-
Sempare Template - How to get contextual data in a utility class method?
darnocian replied to Edwin Yip's topic in Delphi Third-Party
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. -
TValue.ToString for TAlphaColor type returns a strange result.
darnocian replied to dmitrybv's topic in RTL and Delphi Object Pascal
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. -
Execution time difference between 32b and 64b, using static arrays
darnocian replied to lg17's topic in General Help
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... -
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.
-
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.
-
Sempare Template Engine 1.8.0 and license change to Apache 2.0
darnocian replied to darnocian's topic in I made this
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 -
Sempare Template Engine 1.8.0 and license change to Apache 2.0
darnocian replied to darnocian's topic in I made this
@Ian BranchThe new version 1.8 is now available on GetIt. -
Sempare Template Engine 1.8.0 and license change to Apache 2.0
darnocian replied to darnocian's topic in I made this
Yes. The request is in, but it takes a few days. -
The BEST template engine for generating webpages on the server side?
darnocian replied to Edwin Yip's topic in Tips / Blogs / Tutorials / Videos
Ok. I won't in future. 😉