Tips and hints are welcome.
(all this will be part of a small framework (visual and non visual objects))
11/08/2009
- Added the Datastore Class (Sort, Update, ... will be added in the near future)
- Added sample to show usage of the datastore.
The first part is this array class
Code: Select all
;# Array Class
;# CopyRight 2009 by Smollies
;# Initial release
Procedure sf_FreePBString(*Address)
Protected string.String
PokeI(@string, *Address)
EndProcedure
;Private
#SNARRAY_STRING = 1
#SNARRAY_VALUE = 2
Structure CSNARRAY
*vTable
Size.i
Flags.b
*Data
EndStructure
Structure SNARRAYELEMENT
StructureUnion
Value.i
String.s
EndStructureUnion
EndStructure
Structure SNARRAYDATA
Data.SNARRAYELEMENT[0]
EndStructure
Interface ISNARRAY
Release()
GetString.b(iIndex.i, sValue.String)
GetValue.b(iIndex.i, iValue.Integer)
ReDim.b(iDim.i)
SetString.b(iIndex.i, sValue.s)
SetValue.b(iIndex.i, iValue.i)
Size.i()
EndInterface
Procedure.i SnArray_Size(*this.CSNARRAY)
ProcedureReturn *this\Size
EndProcedure
Procedure.b SnArray_ReDim(*this.CSNARRAY, iDim.i)
Protected lData.i, lRes.b = #False, i.i, *p.SNARRAYDATA
*p = *this\Data
If iDim >= 0
If *this\Flags & #SNARRAY_STRING And iDim < *this\Size
;Release string memory
For i=iDim To *this\Size
sf_FreePBString(@*p\Data[i]\String)
Next
EndIf
lData = ReAllocateMemory(*this\Data, (iDim+1)*SizeOf(SNARRAYELEMENT))
If lData
*this\Size = iDim
*this\Data = lData
lRes = #True
EndIf
EndIf
ProcedureReturn lRes
EndProcedure
Procedure SnArray_Release(*this.CSNARRAY)
Protected i.i, *p.SNARRAYDATA
*p = *this\Data
If *this\Flags & #SNARRAY_STRING
For i = 0 To *this\Size
*p\Data[i]\String = ""
sf_FreePBString(@*p\Data[i]\String)
Next
EndIf
FreeMemory(*this\Data)
FreeMemory(*this)
EndProcedure
Procedure.b SnArray_SetValue(*this.CSNARRAY, iIndex.i, iValue.i)
Protected *p.SNARRAYELEMENT, lRes.b = #False
If iIndex >= 0 And iIndex <= *this\Size
*p = *this\Data + iIndex*SizeOf(SNARRAYELEMENT)
*p\Value = iValue
lRes = #True
EndIf
ProcedureReturn lRes
EndProcedure
Procedure.b SnArray_SetString(*this.CSNARRAY, iIndex.i, sValue.s)
Protected *p.SNARRAYELEMENT, lRes.b = #False
If iIndex >= 0 And iIndex <= *this\Size
*p = *this\Data + iIndex*SizeOf(SNARRAYELEMENT)
*p\String = sValue
lRes = #True
EndIf
ProcedureReturn lRes
EndProcedure
Procedure.b SnArray_GetValue(*this.CSNARRAY, iIndex.i, *iValue.Integer)
Protected *p.SNARRAYELEMENT, lRes.b = #False
If iIndex >= 0 And iIndex <= *this\Size
*p = *this\Data + iIndex*SizeOf(SNARRAYELEMENT)
If *p
*iValue\i = *p\Value
EndIf
lRes = #True
EndIf
ProcedureReturn lRes
EndProcedure
Procedure.b SnArray_GetString(*this.CSNARRAY, iIndex.i, *sValue.String)
Protected *p.SNARRAYELEMENT, lRes.b = #False
If iIndex >= 0 And iIndex <= *this\Size
*p = *this\Data + iIndex*SizeOf(SNARRAYELEMENT)
*sValue\s = *p\String
lRes = #True
EndIf
ProcedureReturn lRes
EndProcedure
Procedure.i SnArray(iDim.i, bFlags.b = #SNARRAY_VALUE)
Protected *object.CSNARRAY
If iDim >= 0
*object = AllocateMemory(SizeOf(CSNARRAY))
If *object
*object\vTable = ?VTABLE_CSNARRAY
*object\Size = iDim
*object\Flags = bFlags
*object\Data = AllocateMemory((iDim + 1)*SizeOf(SNARRAYELEMENT))
If Not *object\Data
FreeMemory(*object)
*object = #Null
EndIf
EndIf
EndIf
ProcedureReturn *object
EndProcedure
DataSection
VTABLE_CSNARRAY:
Data.i @SnArray_Release()
Data.i @SnArray_GetString()
Data.i @SnArray_GetValue()
Data.i @SnArray_ReDim()
Data.i @SnArray_SetString()
Data.i @SnArray_SetValue()
Data.i @SnArray_Size()
EndDataSection
Code: Select all
;# Datastore Class
;# CopyRight 2009 by Smollies
;# Initial release
#SN_ERROR = -1
;Row state identifiers
#SNDS_INSERT = "I"
#SNDS_DELETE = "D"
#SNDS_UPDATE = "U"
#SNDS_NONE = "N"
;Data buffers
Enumeration
#SNDS_DATA
#SNDS_DELETED
#SNDS_VISIBLE
EndEnumeration
Interface ISNDS
Release()
AddRow.i()
DeleteRow.b(iRow.i)
GetColCount.i()
GetItem(iRow.i, iCol.i, *sValue.String, bType.b = #SNDS_VISIBLE)
GetRowCount.i(bType.b)
Reset()
SetItem(iRow.i, iCol.i, sValue.s)
EndInterface
Structure CSNDS
*vTable
Buffer.i
Cols.i
Rows.i
DRows.i
SRows.i
*Data.ISNARRAY
*DData.ISNARRAY
*SData.ISNARRAY
EndStructure
Procedure.i SNDS(iCol.i, iBuffer.i = 100)
Protected *object.CSNDS
If iCol > 0
*object = AllocateMemory(SizeOf(CSNDS))
If *object
*object\vTable = ?VTABLE_CSNDS
*object\Cols = iCol + 1 ;extra col to store rowstate
*object\Buffer = iBuffer
*object\Rows = 0
*object\SRows = 0
*object\DRows = 0
*object\Data = SnArray(0)
*object\SData = SnArray(0)
*object\DData = SnArray(0)
EndIf
EndIf
ProcedureReturn *object
EndProcedure
Procedure SnDS_Release(*this.CSNDS)
Protected i.i, lData.Integer, lArr.ISNARRAY
;Free data
For i = 0 To *this\Data\Size()
If *this\Data\GetValue(i, lData)
lArr = lData\i
If lArr
lArr\Release()
EndIf
EndIf
Next
*this\Data\Release()
*this\SData\Release()
*this\DData\Release()
FreeMemory(*this)
EndProcedure
;Returns address of array or error
Procedure.i SnDS_GetData(*this.CSNDS, iRow.i)
Protected lVal.Integer, lIndex.i, lRes.i = #SN_ERROR
If iRow >= 0 And iRow <= *this\Rows
lIndex = iRow / *this\Buffer + 1
If *this\Data\GetValue(lIndex, @lVal)
lRes = lVal\i
EndIf
EndIf
ProcedureReturn lRes
EndProcedure
Procedure.i SnDS_GetColCount(*this.CSNDS)
ProcedureReturn *this\Cols - 1 ;Rowstate col => -1
EndProcedure
Procedure.s SnDS_GetRowState(*this.CSNDS, iRow.i)
Protected lRes.s = "", lArr.ISNARRAY, lVal.String
If iRow > 0 And iRow <= *this\Rows
lArr = SnDS_GetData(*this, iRow)
If lArr
If lArr\GetString((*this\Rows % *this\Buffer) * *this\Cols, lVal)
lRes = lVal\s
EndIf
EndIf
EndIf
ProcedureReturn lRes
EndProcedure
Procedure.b SnDS_SetRowState(*this.CSNDS, iRow.i, sValue.s)
Protected lRes.b = #False, lArr.ISNARRAY
If iRow > 0 And iRow <= *this\Rows
lArr = SnDS_GetData(*this, iRow)
If lArr
If lArr\SetString((*this\Rows % *this\Buffer) * *this\Cols, sValue)
lRes = #True
EndIf
EndIf
EndIf
ProcedureReturn lRes
EndProcedure
;Add row
Procedure.i SnDS_AddRow(*this.CSNDS)
Protected lContinue.b = #True, lSize.i, lArr.ISNARRAY, lRes.i = #SN_ERROR
*this\Rows + 1 ;Data count
*this\SRows + 1 ;Visible row count
;Data
If (*this\Rows % *this\Buffer = 0 Or *this\Rows = 1) And lContinue
;We need extra array containing *this\Buffer rows
lContinue = #False
lSize = *this\Data\Size() + 1
If *this\Data\Redim(lSize)
;Create array holding data
lArr = SnArray(*this\Cols * *this\Buffer, #SNARRAY_STRING)
If lArr
lContinue = *this\Data\SetValue(lSize, lArr)
EndIf
EndIf
EndIf
If lContinue
;Visible rows array
If (*this\SRows % *this\Buffer = 0 Or *this\SRows = 1)
lContinue = *this\SData\ReDim(*this\SData\Size() + *this\Buffer)
EndIf
If lContinue
*this\SData\SetValue(*this\SRows, *this\Rows)
;Set rowstate
If SnDS_SetRowState(*this, *this\Rows, #SNDS_INSERT)
lRes = *this\SRows
EndIf
EndIf
EndIf
If lRes = #SN_ERROR
*this\Rows - 1
*this\SRows - 1
EndIf
ProcedureReturn lRes
EndProcedure
;Visible rows
Procedure.b SnDS_DeleteRow(*this.CSNDS, iRow.i)
Protected lRes.b = #False, lRow.Integer, lArr.ISNARRAY, lState.s, i.i
If iRow > 0 And iRow <= *this\SRows
; Get data row
If *this\SData\GetValue(iRow, lRow)
If lRow\i > 0 And lRow\i <= *this\Rows
;Get rowstate
lState = SnDS_GetRowState(*this, lRow\i)
If lState = #SNDS_INSERT
SnDS_SetRowState(*this, lRow\i, #SNDS_NONE)
Else
SnDS_SetRowState(*this, lRow\i, #SNDS_DELETE)
EndIf
*this\DRows + 1
If (*this\DRows % *this\Buffer = 0 Or *this\DRows = 1)
*this\DData\ReDim(*this\DData\Size() + *this\Buffer)
EndIf
*this\DData\SetValue(*this\DRows, lRow\i)
;Remove from visible array
If iRow < *this\SRows
For i = iRow To *this\SRows - 1
*this\SData\GetValue(i + 1, lRow)
*this\SData\SetValue(i, lRow\i)
Next
EndIf
*this\SRows - 1
lRes = #True
EndIf
EndIf
EndIf
ProcedureReturn lRes
EndProcedure
Procedure SnDS_Reset(*this.CSNDS)
Protected i.i
For i = 1 To *this\Rows
SnDS_SetRowState(*this, i, #SNDS_NONE)
*this\SData\SetValue(i,i)
Next
;Remove delete array
*this\SRows + *this\DRows
*this\DData\Redim(0)
*this\DRows = 0
EndProcedure
Procedure.i SnDS_GetRowCount(*this.CSNDS, bType.b)
Protected lRes.i = 0
Select bType
Case #SNDS_DATA
lRes = *this\Rows
Case #SNDS_VISIBLE
lRes = *this\SRows
Case #SNDS_DELETED
lRes = *this\DRows
EndSelect
ProcedureReturn lRes
EndProcedure
;VISIBLE ROWS
Procedure.b SnDS_SetItem(*this.CSNDS, iRow.i, iCol.i, sValue.s)
Protected lRes.b = #False, lRow.Integer, lArr.ISNARRAY, lState.s
If (iCol > 0 And iCol <= *this\Cols - 1) And (iRow > 0 And iRow <= *this\SRows)
; Get data row
If *this\SData\GetValue(iRow, lRow)
lArr = SnDS_GetData(*this, lRow\i)
If lArr
If lArr\SetString(((iRow % *this\Buffer) * *this\Cols) + iCol, sValue)
lState = SnDS_GetRowState(*this, lRow\i)
If lState <> #SNDS_INSERT
SnDS_SetRowState(*this, lRow\i, #SNDS_UPDATE)
EndIf
lRes = #True
EndIf
EndIf
EndIf
EndIf
ProcedureReturn lRes
EndProcedure
;VISIBLE ROWS
Procedure.b SnDS_GetItem(*this.CSNDS, iRow.i, iCol.i, *sValue.String, bType.b = #SNDS_VISIBLE)
Protected lTotal.i, lRes.b = #False, lRow.Integer, lArr.ISNARRAY
Select bType
Case #SNDS_VISIBLE
lTotal = *this\SRows
*this\SData\GetValue(iRow, lRow)
Case #SNDS_DATA
lTotal = *this\Rows
lRow\i = iRow
Case #SNDS_DELETED
lTotal = *this\DRows
*this\DData\GetValue(iRow, lRow)
EndSelect
If (iCol > 0 And iCol <= *this\Cols - 1) And (iRow > 0 And iRow <= lTotal)
lArr = SnDS_GetData(*this, lRow\i)
If lArr
If lArr\GetString(((lRow\i % *this\Buffer) * *this\Cols) + iCol, *sValue)
lRes = #True
EndIf
EndIf
EndIf
ProcedureReturn lRes
EndProcedure
DataSection
VTABLE_CSNDS:
Data.i @SnDS_Release()
Data.i @SnDS_AddRow()
Data.i @SnDS_DeleteRow()
Data.i @SnDS_GetColCount()
Data.i @SnDS_GetItem()
Data.i @SnDS_GetRowCount()
Data.i @SnDS_Reset()
Data.i @SnDS_SetItem()
EndDataSection
Code: Select all
UseSQLiteDatabase()
Procedure CheckDatabaseUpdate(Database, Query$)
Result = DatabaseUpdate(Database, Query$)
If Result = 0
Debug DatabaseError()
EndIf
ProcedureReturn Result
EndProcedure
If OpenDatabase(0, ":memory:", "", "")
CheckDatabaseUpdate(0, "CREATE TABLE food (name CHAR(50), weight INT)")
CheckDatabaseUpdate(0, "INSERT INTO food (name, weight) VALUES ('apple', '10')")
CheckDatabaseUpdate(0, "INSERT INTO food (name, weight) VALUES ('pear', '5')")
CheckDatabaseUpdate(0, "INSERT INTO food (name, weight) VALUES ('banana', '20')")
For i = 1 To 3000
CheckDatabaseUpdate(0, "INSERT INTO food (name, weight) VALUES ('test" + Str(i) + "', '20')")
Next
If DatabaseQuery(0, "SELECT * FROM food WHERE weight > 7")
DS.ISNDS = SnDS(DatabaseColumns(0))
While NextDatabaseRow(0)
llRow = DS\AddRow()
DS\SetItem(llRow, 1, GetDatabaseString(0, 0) ) ; Col 1
DS\SetItem(llRow, 2, GetDatabaseString(0, 1) ) ; Col 2
Wend
;Call this to reset the update flags after filling the datastore
DS\Reset()
FinishDatabaseQuery(0)
CloseDatabase(0)
EndIf
Debug "Columns = " + Str(DS\GetColCount())
Debug "Total rows = " + Str(DS\GetRowCount(#SNDS_DATA))
Debug "Visible rows = " + Str(DS\GetRowCount(#SNDS_VISIBLE))
Debug "Deleted rows = " + Str(DS\GetRowCount(#SNDS_DELETED))
Debug "-----"
Debug "Delete Visible row 3"
DS\DeleteRow(3)
Debug "Delete Visible row 10"
DS\DeleteRow(10)
Debug "-----"
Debug "Total rows = " + Str(DS\GetRowCount(#SNDS_DATA))
Debug "Visible rows = " + Str(DS\GetRowCount(#SNDS_VISIBLE))
Debug "Deleted rows = " + Str(DS\GetRowCount(#SNDS_DELETED))
Debug "-----"
Debug "Deleted rows :"
For i = 1 To DS\GetRowCount(#SNDS_DELETED)
If DS\GetItem(i, 1, tmp.String, #SNDS_DELETED)
Debug tmp\s
EndIf
Next
Debug "-----"
Debug "Visible rows : (TOP 10)"
For i = 1 To 10
If DS\GetItem(i, 1, tmp.String, #SNDS_VISIBLE)
Debug tmp\s
EndIf
Next
DS\Release()
EndIf