views:

953

answers:

5

The businesswise calm of the summer has started so I picked up the migration to D2009. I roughly determined for every subsystem of the program if they should remain ascii, or can be unicode, and started porting.

It went pretty ok, all components were there in D2009 versions (some, like VSTView, slightly incompatible though) but I now have run into a problem, in some part that must remain ansistring, I extensively use TStringList, mostly as a basic map.

Is there already something easy to replace it with, or should I simply include a cut down ansistring tstringlist, based on old Delphi or FPC source?

I can't imagine I'm the first to run into this?

The changes must be relatively localised, so that the code remains compilable with BDS2006 while I go through the validation-trajectory. A few ifdefs here and there are no problem. Of course string->ansistring and char ->ansichar etc don't count as modifications in my source, since I have to do that anyway, and it is fully backwards compat.

Edit: I've been able to work away some of the stuff in reader/writer classes. This makes going for Mason's solution easier than I originally thought. I'll holds Gabr's suggestion in mind as a fallback.

Generics is pretty much the reason I bought D2009. Pity that they made it FPC incompatible though

+2  A: 

Do these subsystems need to remain ansistring, or just how they communicate with the outside world (RS232, text files, etc...)? Just like I do with C#, I treat strings in Delphi 2009 as just strings, and only worry about conversions when someone else needs them.

This will also help avoid unintentional implicit conversions in your code and when calling Windows API methods, improving performance.

Bruce McGee
textfiles, RS232 are right on spot. However the persistance is not simply stringlist.savetostream or so, but handcoded with severe versioned backwards compability demands. I roughly do the same as you advise at the toplevel, but i'd prefer to keep subsystems that in/output ansistrings and use them heavily internally, ansistring to avoid trouble. Later, after the migration I update selected ones to ansistring.
Marco van de Voort
You should edit your question to mention compatibility with previous Delphi versions.
Bruce McGee
... to unicodestring obviously. About half of the filetypes are binary btw.
Marco van de Voort
+9  A: 

If by "map" you mean "hash table", you can replace it with the generic TDictionary. Try declaring something like this:

uses
  Generics.Collections;

type
  TStringMap<T: class> = TDictionary<ansiString, T>;

Then just replace your StringLists with TStringMaps of the right object type. (Better type-safety gets thrown in free.) Also, if you'd like the dictionary to own the objects and free them when you're done, change it to a TObjectDictionary and when you call the constructor, pass [doOwnsValues] to the appropriate parameter.

(BTW if you're going to use TDictionary, make sure you download D2009 Update 3. The original release had some severe bugs in TDictionary that made it almost unusable.)

EDIT: If it still has to compile under D2006, then you'll have to tweak things a little. Try something like this:

type
  TStringMap =
{$IFDEF UNICODE}
    class TDictionary<ansiString, TObject>
    (Add some basic wrapper functions here.)
    end;
{$ELSE}
    TStringList;
{$ENDIF}

The wrapper shouldn't take too much work if you were using it as a map in the first place. You lose the extra type safety in exchange for backwards compatibility, but you gain a real hash table that does its lookups in O(1) time.

Mason Wheeler
The code must remain compiling with D2006... But maybe a small wrapper will do, afaik I've the most recent updates because it is a month old electronic software delivery version. (except help update 3 that I installed by hand)
Marco van de Voort
Meanwhile played a bit more, but TDictionary supports no duplicates it seems.
Marco van de Voort
+2  A: 

You can modify Delphi 2007(or earlier)'s TStrings and TStringList classes and rename them to TAnsiStrings and TAnsiStringList. You should find that to be a very easy modification, and that will give you the classes you need.

lkessler
I don't see either of these in AnsiStrings.pas or in a search of the source directory.
Bruce McGee
ansistrings doesn't seem to include tansistringlist. The entire src/ dir doesn't grep on it? It is what I was hoping for though
Marco van de Voort
Sorry, sorry, sorry. I was wrong. It was a modification that isn't included in Delphi 2009 but is easy to do. I'll update my answer.
lkessler
+8  A: 

JCL implements TAnsiStrings and TAnsiStringList in the JclAnsiStrings unit.

gabr
+5  A: 

TStringList.LoadFromFile/SaveToFile also take an optional parameter of type TEncoding, that allows you to use TStringList to store any type of string that you want.

procedure LoadFromFile(const FileName: string; Encoding: TEncoding); overload; virtual;
procedure SaveToFile(const FileName: string; Encoding: TEncoding); overload; virtual;

Also note that by default, TStringList uses ANSI as the codepage so that all existing code works as it has.

Nick Hodges