Define an array of Char as constant? - arrays

I use this function in Delphi 10.3.3:
function StrTrimCharsLeft(const S: string; const Chars: array of Char): string;
var
I, L: SizeInt;
begin
I := 1;
L := Length(S);
while (I <= L) and ArrayContainsChar(Chars, S[I]) do
Inc(I);
Result := Copy(S, I, L - I + 1);
end;
When I use the function in this way I get an error:
[dcc32 Error]: E2250 There is no overloaded version of 'StrTrimCharsLeft' that can be called with these arguments
const
BomChars = ['ï', '»', '¿'];
...
s := JclStrings.StrTrimCharsLeft(s, BomChars);
But when I use it in this way, all works well without an error:
s := JclStrings.StrTrimCharsLeft(s, ['ï', '»', '¿']);
So how can I define and use an array of Char as a constant?

When you write
const
BomChars = ['ï', '»', '¿'];
you have declared a set named BomChars -- not an array!
If you instead declare BomChars as a static array,
const
BomChars: array[0..2] of Char = ('ï', '»', '¿');
it will work. (See Declared Constants § Array Constants.)
(StrTrimCharsLeft(s, ['ï', '»', '¿']); works because here the brackets are part of the open array syntax. Specifically, the brackets are part of an "open array constructor".)

Related

How to declare variables based on a struct in a for-loop [duplicate]

This question already has an answer here:
Struct in for loop initializer
(1 answer)
Closed 3 years ago.
Here is a working program that declares variables prior to a for-loop.
package main
import "fmt"
type brackets struct {
ch string
pos int
}
type stack []brackets
func main() {
p := brackets{ch: "a"}
st := make(stack,0)
for i := 0; i < 3; i++ {
p = brackets{ch: "a", pos: 1}
st = append(st, p)
fmt.Println(p)
fmt.Println(st)
}
}
I want to declare the same variables as part of the for-loop. How? Here is a faulty attempt.
package main
import "fmt"
type brackets struct {
ch string
pos int
}
type stack []brackets
func main() {
// p := brackets{ch: "a"}
// st := make(stack,0)
for st, p, i := make(stack,0), brackets{ch: "a"}, 0; i < 3; i++ {
p = brackets{ch: "a", pos: 1}
st = append(st, p)
fmt.Println(p)
fmt.Println(st)
}
}
I get the following error:
syntax error: st, p, i := make(stack, 0), brackets used as value
I am puzzled, as it is very easy to declare standard types such as ints and strings. Why not my struct?
The composite literal section of the specification says:
A parsing ambiguity arises when a composite literal using the TypeName form of the LiteralType appears as an operand between the keyword and the opening brace of the block of an "if", "for", or "switch" statement, and the composite literal is not enclosed in parentheses, square brackets, or curly braces. In this rare case, the opening brace of the literal is erroneously parsed as the one introducing the block of statements. To resolve the ambiguity, the composite literal must appear within parentheses.
Fix the code by adding parentheses around the composite literal:
for st, p, i := make(stack,0), (brackets{ch: "a"}), 0; i < 3; i++ {
p = brackets{ch: "a", pos: 1}
st = append(st, p)
fmt.Println(p)
fmt.Println(st)
}
Run it on the playground.

How to pass pointer to slice to C function in go

Background: using cgo to call C functions from Golang.
I want to use a C function which has this signature: int f(int *count, char ***strs).
It will modify the data of count and strs, which is the reason why it uses pointer to them.
The value of count is the length of strs; strs is an array of string; the return value is simply an (boolean) indicator which states whether there is an error or not.
In golang, I can successfully pass and modify count by using C.f((*C.int)(&count)); pass []string by using []*C.char. Sample code is like this:
/*
#include <stdio.h>
int f(int *c, char **str) {
int i;
printf("%d\n", *c);
for (i = 0; i < *c; i++) {
printf("%s\n", str[i]);
}
*c = (*c) + 1;
return 1;
}
*/
import "C"
func go_f(strs []string) int {
count := len(strs)
c_count := C.int(count)
c_strs := make([]*C.char, count)
for index, value := range strs {
c_strs[index] = C.CString(value)
defer C.free(unsafe.Pointer(c_strs[index]))
}
err := C.f(&c_argc, (**C.char)(&c_argv[0]))
return int(err)
}
As you can see, the C function is currently int f(int *c, char **str), but what I'd like is int f(int *c, char ***str).
This is to say: what I actually want is to enable the modification to the string array (e.g. resize) in C and turn it back to a Go string slice so I can still use it in Go.
How to do this? I've searched and experimented for a while but with no luck.
A Go slice is both allocated in Go, and a different data structure than a C array, so you can't pass it to a C function (cgo will also prevent you from doing this because a slice contains a Go pointer)
You need to allocate the array in C in order to manipulate the array in C. Just like with C.CString, you will also need to track where to free the outer array, especially if the C function may possibly allocate a new array.
cArray := C.malloc(C.size_t(c_count) * C.size_t(unsafe.Sizeof(uintptr(0))))
// convert the C array to a Go Array so we can index it
a := (*[1<<30 - 1]*C.char)(cArray)
for index, value := range strs {
a[index] = C.CString(value)
}
err := C.f(&c_count, (***C.char)(unsafe.Pointer(&cArray)))

Delphi - How to pass a 'Type' as a parameter

I would like to know if it is possible to pass a declared type (in this case a record) to my function. I would not even ask if it was not for the SizeOf() function, because it can take a type as a parameter.
I'm translating code from C and I would like to keep it as close to the original as possible.
The C program declares PushArray and PushStruct as macros. Since Delphi does not have macro support, I'm trying to turn them into functions.
I've googled this a bit and it seems that I could possible use generic types.
Like function PushStruct<T>(Arena : Pmemory_arena; dtype : <T>) but you can only use this in an OOP type application.
function PushSize_(Arena : Pmemory_arena; Size : memory_index) : pointer;
begin
Assert((Arena^.Used + Size) <= Arena^.Size);
Result := Arena^.Base + Arena^.Used;
Arena^.Used := Arena^.Used + Size;
end;
function PushStruct(Arena : Pmemory_arena; dtype : ?) : pointer;
begin
result := PushSize_(Arena, sizeof(dtype));
end;
function PushArray(Arena : Pmemory_arena; Count: uint32; dtype : ?) : pointer;
begin
result := PushSize_(Arena, (Count)*sizeof(dtype))
end;
Here is the original C code:
#define PushStruct(Arena, type) (type *)PushSize_(Arena, sizeof(type))
#define PushArray(Arena, Count, type) (type *)PushSize_(Arena, (Count)*sizeof(type))
void *
PushSize_(memory_arena *Arena, memory_index Size)
{
Assert((Arena->Used + Size) <= Arena->Size);
void *Result = Arena->Base + Arena->Used;
Arena->Used += Size;
return(Result);
}
The C code isn't passing a type to the function. The pre-processor is expanding the macro and computing the size. You can see that from the prototype of the function:
void *PushSize_(memory_arena *Arena, memory_index Size)
Since you don't have macros in Delphi, you cannot arrange a direct translation. Personally, if it were me I would not attempt to match the C code exactly. I'd pass the size and leave it to the caller to use SizeOf. I don't think that's a terrible burden. It still leaves you with something very close to a literal translation – all you are missing is the convenience macros.
If you wanted to use generics, you could do so, but it would require you to use a static method. For instance:
type
TMyClass = class
class function PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer; static;
class function PushStruct<T>(Arena: Pmemory_arena): Pointer; static;
end;
....
class function TMyClass.PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer;
begin
Result := ....;
end;
class function TMyClass.PushStruct<T>(Arena: Pmemory_arena): Pointer;
begin
Result := PushSize(Arena, SizeOf(T));
end;
If you want to return a typed pointer that would look like this:
type
TMyClass<T> = class
type P = ^ T;
class function PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer; static;
class function PushStruct(Arena: Pmemory_arena): P; static;
end;
....
class function TMyClass<T>.PushSize(Arena: Pmemory_arena; Size: memory_index): Pointer;
begin
Result := ....;
end;
class function TMyClass<T>.PushStruct(Arena: Pmemory_arena): P;
begin
Result := PushSize(Arena, SizeOf(T));
end;
Obviously you'd know what name to use instead of TMyClass!
I'm not convinced that generics are a good fit here because I guess you are wanting as literal a translation as possible. I would not choose to use generics in this scenario.
You could "expand the macros" by simply declaring your own Push* funtions for each record type as needed:
type
// just guessing here...
PMemoryArena = ^TMemoryArena;
TMemoryArena = record
Base: Pointer;
Used: Cardinal;
Size: Cardinal;
end;
TMemoryIndex = Cardinal;
// 1st example record type
PMyRecord1 = ^TMyRecord1;
TMyRecord1 = record
I1: Integer;
I2: Integer;
end;
// 2nd example record type
PMyRecord2 = ^TMyRecord2;
TMyRecord2 = record
D1: Double;
D2: Double;
end;
function PushSize_(Arena: PMemoryArena; Size: TMemoryIndex): Pointer; inline;
begin
Assert(Arena^.Used + Size <= Arena^.Size);
Result := Pointer(NativeUInt(Arena^.Base) + Arena^.Used);
Inc(Arena^.Used, Size);
end;
function PushMyRecord1(Arena: PMemoryArena): PMyRecord1;
begin
Result := PMyRecord1(PushSize_(Arena, SizeOf(TMyRecord1)));
end;
function PushMyRecord2(Arena: PMemoryArena): PMyRecord2;
begin
Result := PMyRecord2(PushSize_(Arena, SizeOf(TMyRecord2)));
end;
It does seem kind of unnecessary.
why not, for example
function PushStruct(Arena : Pmemory_arena) : pointer;
begin
result := PushSize_(Arena, sizeof( Arena ));
end;

Multidimensional Slices in Go

I would like to have an array / slice in Go with a variadic number of elements (not known at compile time) and be able to dinamically add new elements of different types, for instance:
data[0] := "string"
data[1] // slice
data[1][0] := "another string"
data[1][1] := 42 // int
Is this possible somehow?
It's a bit ugly but possible using empty interfaces, interface{}:
package main
import "fmt"
func main() {
variadic := []interface{}{}
variadic = append(variadic, "foo")
variadic = append(variadic, []interface{}{"bar", 42})
//this will print "foo"
fmt.Println(variadic[0])
//note that you have to cast variadic[1] to an array before accessing it
fmt.Println(variadic[1].([]interface{})[0])
}
If you allow the assumption that each element must be an array of anything with varying length, it's a bit less ugly:
package main
import "fmt"
func main() {
variadic := [][]interface{}{}
variadic = append(variadic, []interface{}{"foo"})
variadic = append(variadic, []interface{}{"bar", 42})
fmt.Println(variadic[0])
fmt.Println(variadic[1][0])
fmt.Println(variadic[1][1])
}

Array as an argument of a function

I have 2 2-dimensional arrays and a function.
I would like that function to take the array as an argument.
I tried code like this:
var array1:array[1..10,1..10] of integer;
array2:array[1..20,1..10] of integer;
function name(var my_array:array of array of integer, n:integer);
function name(var my_array:array[1..n,1..10] of integer;const n:integer);
But I got errors while trying to compile the code. Any tips?
If you would like me to paste error codes for each version please leave a comment with a request.
For
function name(var my_array:array of array of integer, n:integer);
The error code is: "Incompatible type for arg no. : Got "Array[0..10] of Array[0..10] of SmallInt", expected "Open array od SmallInt" every time I call the function.
You need to declare your own type, and then use that type as the parameter to your function. Instead of passing the array dimensions, use the Low and High functions from the System unit; they will work with both static (pre-declared) and dynamic arrays, and avoid hard-coding array sizes and iterators.
You want to avoid hard-coding integer indexes, becaue static arrays in Pascal don't have to start with index 0; the following is a perfectly legal Pascal array declaration, where the array bounds are from index -3 to 3:
var
Arr: array[-3..3] of Integer;
Here's an example using a dynamic array (array of array of Integer) that loops through the two dimensional array and sums the values; it initializes a 5 x 5 array, populates it with data, and then calls the SumTwoDimIntArray function to sum the values.
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TTwoDimIntArray = array of array of Integer;
function SumTwoDimIntArray(Arr: TTwoDimIntArray): Integer;
var
i, j: Integer;
begin
Result := 0;
for i := Low(Arr) to High(Arr) do
for j := Low(Arr[i]) to High(Arr[i]) do
Result := Result + Arr[i][j];
end;
var
MyArr: TTwoDimIntArray;
i, j: Integer;
begin
SetLength(MyArr, 5);
for i := Low(MyArr) to High(MyArr) do
begin
SetLength(MyArr[i], 5);
for j := Low(MyArr[i]) to High(MyArr[i]) do
MyArr[i][j] := j + 1;
end;
WriteLn(Format('Sum is %d', [SumTwoDimIntArray(MyArr)]));
ReadLn;
end.
You shuld use a new type in these situations . like the following:
Type
vector = array [1..20,1..20] of integer;
var array1:vector;
array2:vector;
function name(var my_array:vector, n:integer);
function name(var my_array:vector;const n:integer);

Resources