unit Unit1; { (c) 2010 bflm, contact: befelemepeseveze at Google's free mail Free sample code - copy, use, modify, distribute, sell, release under other license, ... } {$mode objfpc}{$h+} interface const DEFAULT_FMODE = 432; // =0660(8) type { TGDBM } TGDBM = class private FCacheSize: Integer; FCentFree: Longbool; FCoalesceBlks: Longbool; FDBF: Pointer; FSyncMode: Longbool; function GetFDesc: Integer; procedure Open(Name: String; OpenRW: Integer; const Sync, NoLock: Boolean; BlockSize: Integer; Mode: Integer); procedure SetCacheSize(const AValue: Integer); procedure SetCentFree(const AValue: Longbool); procedure SetCoalesceBlks(const AValue: Longbool); procedure SetSyncMode(const AValue: Longbool); public constructor CreateNewDB(const Name: String; const Sync: Boolean = False; const NoLock: Boolean = False; const BlockSize: Integer = 0; const FMode: Integer = DEFAULT_FMODE); constructor CreateOrOpen(const Name: String; const Sync: Boolean = False; const NoLock: Boolean = False; const BlockSize: Integer = 0; const FMode: Integer = DEFAULT_FMODE); constructor CreateReader(const Name: String); constructor CreateWriter(const Name: String; const Sync: Boolean = False; const NoLock: Boolean = False); destructor Destroy; override; { True if Key deleted } function Delete(const Key: String): Boolean; { True if Key deleted } function Delete(const Key; const KeyLen: Integer): Boolean; function Exists(const Key: String): Boolean; function Exists(const Key; const KeyLen: Integer): Boolean; { True if Key found => Value set } function Fetch(const Key: String; out Value: String): Boolean; { True if Key found => Value set. Value MUST be disposed using C free. } function Fetch(const Key; const KeyLen: Integer; out Value: Pointer; out Len: Integer): Boolean; { True if FirstKey returned } function FirstKey(out Key: String): Boolean; { True if FirstKey returned } function FirstKey(out Key: Pointer; out Len: Integer): Boolean; { True if Key already existed => new Value NOT stored } function Insert(const Key, Value: String): Boolean; { True if Key already existed => new Value NOT stored } function Insert(const Key; const KeyLen: Integer; const Value; const ValueLen: Integer): Boolean; { True if Next returned } function NextKey(const Key: String; var Next: String): Boolean; { True if Next returned. Key MUST be disposed using C free. } function NextKey(const Key; const KeyLen: Integer; var Next: Pointer; var Len: Integer): Boolean; procedure Reorganize; procedure Replace(const Key, Value: String); procedure Replace(const Key; const KeyLen: Integer; const Value; const ValueLen: Integer); procedure Sync; property CacheSize: Integer read FCacheSize Write SetCacheSize; property CentFree: Longbool read FCentFree Write SetCentFree; property CoalesceBlks: Longbool read FCoalesceBlks Write SetCoalesceBlks; property FDesc: Integer read GetFDesc; property SyncMode: Longbool read FSyncMode Write SetSyncMode; end; implementation uses SysUtils, gdbm; procedure CFree(P: pointer); cdecl; external 'c' Name 'free'; function Datum(const Buf: Pointer; const Len: Integer): TDatum; inline; begin Result.dptr := Buf; Result.dsize := Len; end; procedure Fail; begin raise Exception.Create(gdbm_strerror(gdbm_errno)); end; function CheckError(const Ret: Integer): Integer; begin if Ret <> 0 then Fail; Result := Ret; end; operator := (const Datum: TDatum): String; begin if Datum.dptr <> nil then begin SetLength(Result, Datum.dsize); Move(Datum.dptr^, Result[1], Datum.dsize); CFree(Datum.dptr); end else Result := ''; end; operator := (const S: String): TDatum; begin Assert(S <> ''); Result.dptr := PChar(S); Result.dsize := Length(S); end; { TGDBM } constructor TGDBM.CreateNewDB(const Name: String; const Sync, NoLock: Boolean; const BlockSize: Integer = 0; const FMode: Integer = DEFAULT_FMODE); begin inherited Create; Open(Name, GDBM_NEWDB, Sync, NoLock, BlockSize, FMode); end; constructor TGDBM.CreateOrOpen(const Name: String; const Sync, NoLock: Boolean; const BlockSize: Integer; const FMode: Integer); begin inherited Create; Open(Name, GDBM_WRCREAT, Sync, NoLock, BlockSize, FMode); end; constructor TGDBM.CreateReader(const Name: String); begin inherited Create; Open(Name, GDBM_READER, False, False, 0, 0); end; constructor TGDBM.CreateWriter(const Name: String; const Sync, NoLock: Boolean); begin inherited Create; Open(Name, GDBM_WRITER, Sync, NoLock, 0, 0); end; destructor TGDBM.Destroy; begin if FDBF <> nil then gdbm_close(FDBF); inherited; end; function TGDBM.Delete(const Key: String): Boolean; var K: TDatum; begin K := Key; Result := gdbm_delete(FDBF, K) = 0; end; function TGDBM.Delete(const Key; const KeyLen: Integer): Boolean; begin Result := gdbm_delete(FDBF, Datum(@Key, KeyLen)) = 0; end; function TGDBM.Exists(const Key: String): Boolean; var K: TDatum; begin K := Key; Result := gdbm_exists(FDBF, K) <> 0; end; function TGDBM.Exists(const Key; const KeyLen: Integer): Boolean; begin Result := gdbm_exists(FDBF, Datum(@Key, KeyLen)) <> 0; end; function TGDBM.Fetch(const Key: String; out Value: String): Boolean; var K, V: TDatum; begin K := Key; V := gdbm_fetch(FDBF, K); if V.dptr <> nil then begin Value := V; Exit(True); end; Result := False; end; function TGDBM.Fetch(const Key; const KeyLen: Integer; out Value: Pointer; out Len: Integer): Boolean; var V: TDatum; begin V := gdbm_fetch(FDBF, Datum(@Key, KeyLen)); if V.dptr = nil then Exit(False); Value := V.dptr; Len := V.dsize; Result := True; end; function TGDBM.FirstKey(out Key: String): Boolean; var K: TDatum; begin K := gdbm_firstkey(FDBF); if K.dptr <> nil then begin Key := K; Exit(True); end; Result := False; end; function TGDBM.FirstKey(out Key: Pointer; out Len: Integer): Boolean; var K: TDatum; begin K := gdbm_firstkey(FDBF); if K.dptr <> nil then begin Key := K.dptr; Len := K.dsize; Exit(True); end; Result := False; end; procedure TGDBM.Open(Name: String; OpenRW: Integer; const Sync, NoLock: Boolean; BlockSize: Integer; Mode: Integer); begin Assert(Name <> ''); FSyncMode := Sync; if SyncMode then OpenRW += GDBM_DOSYNC; if NoLock then; OpenRW += GDBM_NOLOCK; FDBF := gdbm_open(PChar(Name), BlockSize, OpenRW, Mode, nil); if FDBF = nil then Fail; end; function TGDBM.GetFDesc: Integer; begin Result := gdbm_fdesc(FDBF); end; procedure TGDBM.SetCacheSize(const AValue: Integer); var Ret: Integer; begin if FCacheSize = AValue then exit; FCacheSize := AValue; Ret := gdbm_setopt(FDBF, GDBM_CACHESIZE, @FCacheSize, SizeOf(FCacheSize)); if Ret <> 0 then Fail; end; procedure TGDBM.SetCentFree(const AValue: Longbool); begin if FCentFree = AValue then exit; FCentFree := AValue; CheckError(gdbm_setopt(FDBF, GDBM_CENTFREE, @FCentFree, SizeOf(FCentFree))); end; procedure TGDBM.SetCoalesceBlks(const AValue: Longbool); begin if FCoalesceBlks = AValue then exit; FCoalesceBlks := AValue; CheckError(gdbm_setopt(FDBF, GDBM_COALESCEBLKS, @FCoalesceBlks, SizeOf(FCoalesceBlks))); end; procedure TGDBM.SetSyncMode(const AValue: Longbool); begin if FSyncMode = AValue then exit; FSyncMode := AValue; CheckError(gdbm_setopt(FDBF, GDBM_SYNCMODE, @FSyncMode, SizeOf(FSyncMode))); end; function TGDBM.Insert(const Key, Value: String): Boolean; var K, V: TDatum; Ret: Integer; begin K := Key; V := Value; Ret := gdbm_store(FDBF, K, V, GDBM_INSERT); ; if Ret < 0 then // reader attempts insert Fail; Result := Ret <> 0; end; function TGDBM.Insert(const Key; const KeyLen: Integer; const Value; const ValueLen: Integer): Boolean; var Ret: Integer; begin Ret := gdbm_store(FDBF, Datum(@Key, KeyLen), Datum(@Value, ValueLen), GDBM_INSERT); if Ret < 0 then // reader attempts insert Fail; Result := Ret <> 0; end; function TGDBM.NextKey(const Key: String; var Next: String): Boolean; var K, N: TDatum; begin K := Key; N := gdbm_nextkey(FDBF, K); if N.dptr <> nil then begin Next := N; Exit(True); end; Result := False; end; function TGDBM.NextKey(const Key; const KeyLen: Integer; var Next: Pointer; var Len: Integer): Boolean; var N: TDatum; begin N := gdbm_nextkey(FDBF, Datum(@Key, KeyLen)); if N.dptr <> nil then begin Next := N.dptr; Len := N.dsize; Exit(True); end; Result := False; end; procedure TGDBM.Reorganize; var Ret: Integer; begin Ret := gdbm_reorganize(FDBF); if Ret <> 0 then Fail; end; procedure TGDBM.Replace(const Key, Value: String); var K, V: TDatum; begin K := Key; V := Value; CheckError(gdbm_store(FDBF, K, V, GDBM_REPLACE)); end; procedure TGDBM.Replace(const Key; const KeyLen: Integer; const Value; const ValueLen: Integer); begin CheckError(gdbm_store(FDBF, Datum(@Key, KeyLen), Datum(@Value, ValueLen), GDBM_REPLACE)); end; procedure TGDBM.Sync; begin gdbm_sync(FDBF); end; end.
Thursday, May 20, 2010
Sampler: GDBM OO wrapper
Monday, May 10, 2010
Sampler: Generic enumerators for generic containers
unit Unit1; { (c) 2010 bflm, contact: befelemepeseveze at Google's free mail Free sample code - copy, use, modify, distribute, sell, release under other license, ... } {$mode objfpc}{$H+} interface type { TEnumerator } generic TEnumerator<TValue, TIterator> = object public type TGetCurrent = function(const Iterator: TIterator): TValue of object; TMoveNext = function(var Iterator: TIterator): Boolean of object; private var FGetCurrent: TGetCurrent; FMoveNext: TMoveNext; FIterator: TIterator; function GetCurrent: TValue; public procedure Init(const InitialIterator: TIterator; const Mover: TMoveNext; const Getter: TGetCurrent); function MoveNext: Boolean; property Current: TValue read GetCurrent; end; { TVector } generic TVector<T> = object public type TData = array of T; TCompare = function(const A, B: T): Integer; TVectorEnumerator = specialize TEnumerator<T, Integer>; private var FData: TData; FLen: Integer; private function GetCap: Integer; function GetData: TData; function GetItems(const Index: Integer): T; inline; function GetLen: Integer; inline; function MoveNext(var Index: Integer): Boolean; procedure Sort(Left, Right: Integer; const Compare: TCompare); procedure SetCap(const AValue: Integer); procedure SetData(const AValue: TData); procedure SetItems(const Index: Integer; const AValue: T); inline; procedure SetLen(const AValue: Integer); public function GetEnumerator: TVectorEnumerator; function Add(const Value: T): Integer; procedure Clear; procedure Pack; procedure Sort(const Compare: TCompare); property Cap: Integer read GetCap write SetCap; property Data: TData read GetData write SetData; property Items[const Index: Integer]: T read GetItems write SetItems; default; property Len: Integer read GetLen write SetLen; end; implementation { TEnumerator } function TEnumerator.GetCurrent: TValue; begin Result := FGetCurrent(FIterator); end; function TEnumerator.MoveNext: Boolean; begin Result := FMoveNext(FIterator); end; procedure TEnumerator.Init(const InitialIterator: TIterator; const Mover: TMoveNext; const Getter: TGetCurrent); begin Assert(Assigned(Mover)); Assert(Assigned(Getter)); FIterator := InitialIterator; FMoveNext := Mover; FGetCurrent := Getter; end; { TVector } function TVector.Add(const Value: T): Integer; var NeedCap: Integer; begin NeedCap := Len + 1; if NeedCap > Cap then Cap := 2 * NeedCap; Result := FLen; Inc(FLen); Items[Result] := Value; end; procedure TVector.Clear; begin Cap := 0; end; function TVector.GetItems(const Index: Integer): T; begin Result := FData[Index]; end; function TVector.GetCap: Integer; begin Result := Length(FData); end; function TVector.GetData: TData; begin Result := Copy(FData, 0, Len); end; function TVector.GetEnumerator: TVectorEnumerator; begin Result.Init(-1, @MoveNext, @GetItems); end; function TVector.GetLen: Integer; begin if FData = nil then FLen := 0; // boot Result := FLen; end; function TVector.MoveNext(var Index: Integer): Boolean; begin Result := Index + 1 < Len; if Result then Inc(Index); end; procedure TVector.SetCap(const AValue: Integer); begin if AValue = Cap then Exit; if Len > AValue then FLen := AValue; SetLength(FData, AValue); end; procedure TVector.SetData(const AValue: TData); begin FData := AValue; FLen := Cap; end; procedure TVector.SetItems(const Index: Integer; const AValue: T); begin FData[Index] := AValue; end; procedure TVector.SetLen(const AValue: Integer); begin if AValue = Len then Exit; if AValue > Cap then Cap := AValue else if AValue <= Cap div 2 then Cap := Cap div 2; FLen := AValue; end; procedure TVector.Sort(Left, Right: Integer; const Compare: TCompare); var L, R: Integer; Pivot, Swap: T; begin repeat L := Left; R := Right; Pivot := Items[(Left + Right) div 2]; repeat while Compare(Pivot, Items[L]) > 0 do L += 1; while Compare(Pivot, Items[R]) < 0 do R -= 1; if L <= R then begin Swap := Items[L]; Items[L] := Items[R]; Items[R] := Swap; L += 1; R -= 1; end; until L > R; if Left < R then Sort(Left, R, Compare); Left := L; until L >= Right; end; procedure TVector.Pack; begin Cap := Len; end; procedure TVector.Sort(const Compare: TCompare); begin if Len > 1 then Sort(0, FLen - 1, Compare); end; end.
program project1; {$mode objfpc}{$H+} uses Unit1; type TIntVector = specialize TVector<Integer>; function IntCmp(const A, B: Integer): Integer; begin Result := A - B; end; procedure Dump(const Vector: TIntVector); var V: Integer; begin Write(Vector.Len, ' item(s): '); for V in Vector do Write(V, ' '); Writeln; end; procedure Test(const N, X: Integer); var Vector: TIntVector; I: Integer; begin for I := 1 to N do Vector.Add(I xor X); Dump(Vector); Vector.Sort(@IntCmp); Dump(Vector); WriteLn; end; begin // main {$if declared(HaltOnNotReleased)} HaltOnNotReleased := True; {$endif} Test(0, 0); Test(1, 0); Test(11, 0); Test(13, $55); Test(17, $AA); Test(19, $FF); end.
$ fpc -B -gh project1 && ./project1 Free Pascal Compiler version 2.5.1 [2010/05/05] for x86_64 Copyright (c) 1993-2009 by Florian Klaempfl Target OS: Linux for x86-64 Compiling project1.pas Compiling unit1.pas Linking project1 /usr/bin/ld: warning: link.res contains output sections; did you forget -T? 259 lines compiled, 0.1 sec 0 item(s): 0 item(s): 1 item(s): 1 1 item(s): 1 11 item(s): 1 2 3 4 5 6 7 8 9 10 11 11 item(s): 1 2 3 4 5 6 7 8 9 10 11 13 item(s): 84 87 86 81 80 83 82 93 92 95 94 89 88 13 item(s): 80 81 82 83 84 86 87 88 89 92 93 94 95 17 item(s): 171 168 169 174 175 172 173 162 163 160 161 166 167 164 165 186 187 17 item(s): 160 161 162 163 164 165 166 167 168 169 171 172 173 174 175 186 187 19 item(s): 254 253 252 251 250 249 248 247 246 245 244 243 242 241 240 239 238 237 236 19 item(s): 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 Heap dump by heaptrc unit 11 memory blocks allocated : 840/840 11 memory blocks freed : 840/840 0 unfreed memory blocks : 0 True heap size : 98304 True free heap : 98304 $
Wednesday, May 5, 2010
Unicode Category Membership Checking
Submitted a feature proposal on Mantis. Reviews are welcome.
Subscribe to:
Posts (Atom)