Dealing with unsized arrays in Go and Windows API - windows

What is the idiomatic way to deal with unsized arrays in Go? I'm working on the ETW wrappers and the TdhGetEventInformation function fills in the provided memory buffer with event information. The event metadata is represented by TRACE_EVENT_INFO structure, which has an array member declared as:
EVENT_PROPERTY_INFO EventPropertyInfoArray[ANYSIZE_ARRAY];
I'm calling the TdhGetEventInformation function in a way that the provided buffer has enough space to populate event properties array:
var bufferSize uint32 = 4096
buffer := make([]byte, bufferSize)
tdhGetEventInformation.Call(
uintptr(unsafe.Pointer(eventRecord)),
0, 0,
uintptr(unsafe.Pointer(&buffer[0])),
uintptr(unsafe.Pointer(&bufferSize)),
)
However, since I'm tempting to model the Go counterpart struct with EventPropertyInfoArray field as
EventPropertyInfoArray [1]EventPropertyInfo
the compiler is not able to re dimension the array according to the number of available properties for each event, so I end up with one-array item.
Do you have any smart ideas on how handle this edge case?
Thanks in advance

So you want a variable sized array in Go? Use a slice?
EventPropertyInfoArray [1]EventPropertyInfo
Would be
EventPropertyInfoArray []EventPropertyInfo
If you have a rough idea of a maximum it could hold you could make an array using make something like this, but this wouldn't help you out in declaring a struct:
EventPropertyInfoArray = make([]EventPropertyInfo, len, capacity)

After lots of trial and error, I managed to get the right slice from the backing array through standard technique for turning arrays into slices:
properties := (*[1 << 30]EventPropertyInfo)(unsafe.Pointer(&trace.EventPropertyInfoArray[0]))[:trace.PropertyCount:trace.PropertyCount]

Related

How to append to slices as map values with reflection?

Assumptions
I'm using go1.17 not 1.18 so answers in go 1.18 may help others but not me.
I searched and tried many things but this scenario never solved.
Problem
import (
"fmt"
"reflect"
)
func main() {
l := map[string][]interface{}{"a": {}}
appendData(l["a"])
fmt.Println(l["a"])
}
func appendData(k interface{}) {
lValue := reflect.ValueOf(k)
lValue.Set(reflect.Append(lValue, reflect.ValueOf(1)))
lValue.Set(reflect.Append(lValue, reflect.ValueOf(2)))
lValue.Set(reflect.Append(lValue, reflect.ValueOf(3)))
}
I simplified the scenario into this piece of code.
I just need to have the ability to change elements of that passed slice of interfaces([]interface{}) from appendData function.
Please do not send me this line of code l["a"] = appendData(l["a"]).([]interface{}).
I know that this works but I can't implement that in my code for some reason.(I'm doing some BFS stuff and I can't do this, I have to change some values at the time)
What I Want?
I just wanna see this output:
[1, 2, 3]
Is it possible?
Are there any other alternative ways that I can change those data from somewhere else in my code?
Thanks for your help.
You will never see [1, 2, 3] printed, no matter what appendData() does if only the slice is passed.
2 things: You can't change values stored in maps. If the value must be changed, you have to reassign the new value. For details see How to update map values in Go
Second: you also can't change values stored in interfaces. For details, see Removing an element from a type asserted Slice of interfaces
The right approach: if you want to change something, always pass a pointer to it, and modify the pointed value. Of course in your case you can't pass a pointer that points to a value stored in a map (that "points into the map"), so that's not possible. Map index expressions are not addressable, for details, see Cannot take the address of map element. If you must use a map, you must store a pointer in the map, and you may pass that pointer.
Another approach is to return the new, modified slice and assign the new slice at the caller, exactly what / how the builtin append() does it (append() returns a new slice which you're expected to assign / store). If you go down this route, you may store non-pointer slices in the map, since you can reassign the modified slice to the same map key.

Struct type first line: _ struct{} [duplicate]

I am working with go, specifically QT bindings. However, I do not understand the use of leading underscores in the struct below. I am aware of the use of underscores in general but not this specific example.
type CustomLabel struct {
core.QObject
_ func() `constructor:"init"`
_ string `property:"text"`
}
Does it relate to the struct tags?
Those are called blank-fields because the blank identifier is used as the field name.
They cannot be referred to (just like any variable that has the blank identifier as its name) but they take part in the struct's memory layout. Usually and practically they are used as padding, to align subsequent fields to byte-positions (or memory-positions) that match layout of the data coming from (or going to) another system. The gain is that so these struct values (or rather their memory space) can be dumped or read simply and efficiently in one step.
#mkopriva's answer details what the specific use case from the question is for.
A word of warning: these blank fields as "type-annotations" should be used sparingly, as they add unnecessary overhead to all (!) values of such struct. These fields cannot be referred to, but they still require memory. If you add a blank field whose size is 8 bytes (e.g. int64), if you create a million elements, those 8 bytes will count a million times. As such, this is a "flawed" use of blank fields: the intention is to add meta info to the type itself (not to its instances), yet the cost is that all elements will require increased memory.
You might say then to use a type whose size is 0, such as struct{}. It's better, as if used in the right position (e.g. being the first field, for reasoning see Struct has different size if the field order is different and also Why position of `[0]byte` in the struct matters?), they won't change the struct's size. Still, code that use reflection to iterate over the struct's fields will still have to loop over these too, so it makes such code less efficient (typically all marshaling / unmarshaling process). Also, since now we can't use an arbitrary type, we lose the advantage of carrying a type information.
This last statement (about when using struct{} we lose the carried type information) can be circumvented. struct{} is not the only type with 0 size, all arrays with 0 length also have zero size (regardless of the actual element type). So we can retain the type information by using a 0-sized array of the type we'd like to incorporate, such as:
type CustomLabel struct {
_ [0]func() `constructor:"init"`
_ [0]string `property:"text"`
}
Now this CustomLabel type looks much better performance-wise as the type in question: its size is still 0. And it is still possible to access the array's element type using Type.Elem() like in this example:
type CustomLabel struct {
_ [0]func() `constructor:"init"`
_ [0]string `property:"text"`
}
func main() {
f := reflect.ValueOf(CustomLabel{}).Type().Field(0)
fmt.Println(f.Tag)
fmt.Println(f.Type)
fmt.Println(f.Type.Elem())
}
Output (try it on the Go Playground):
constructor:"init"
[0]func()
func()
For an overview of struct tags, read related question: What are the use(s) for tags in Go?
You can think of it as meta info of the type, it's not accessible through an instance of that type but can be accessed using reflect or go/ast. This gives the interested package/program some directives as to what to do with that type. For example based on those tags it could generate code using go:generate.
Considering that one of the tags says constructor:"init" and the field's type is func() it's highly probable that this is used with go:generate to generate an constructor function or initializer method named init for the type CustomLabel.
Here's an example of using reflect to get the "meta" info (although as I've already mentioned, the specific qt example is probably meant to be handled by go:generate).
type CustomLabel struct {
_ func() `constructor:"init"`
_ string `property:"text"`
}
fmt.Println(reflect.ValueOf(CustomLabel{}).Type().Field(0).Tag)
// constructor:"init"
fmt.Println(reflect.ValueOf(CustomLabel{}).Type().Field(0).Type)
// func()
https://play.golang.org/p/47yWG4U0uit

Append to the slice of base interface slice of the implementations

Why the below doesn't work?
locations := make([]*LocationEvent, 0)
data := make([]Event, 0)
data = append(data, locations...)
where *LocationEvent (struct) implements Event (interface).
While the below works fine:
data = append(data, &LocationEvent{}, &LocationEvent{})
So how it is different when expanding the actual []*LocationEvent slice using ...?
The slice type must match the type of the variadic arguments in the append function exactly. locations is of type []*LocationEvent, and thus not compatible with []Event. There is no automatic "downcasting" in Go when working with slices.
You have to copy the locations to a new slice of Event, or add the items of locations one-by-one to the data slice.
For more explanation look here: https://stackoverflow.com/a/12754757/6655315

goLang. call ".Front()" for a string list. But returns error saying string list has no Front method

I have code like this
t := strings.FieldsFunc(value, extract_word)
fmt.Println("t:", len(t),t)
m := make(map[string]int)
for word := t.Front(); word != nil; word=word.Next(){
m[word]++
}
and it gets this error
t.Front undefined (type []string has no field or method Front)
I know list has Front() method.
http://golang.org/pkg/container/list/
but why it complains here?
so confused, need help.
thank you!
[]T is not a "list" as it's referred to in other languages (e.g. Python). In Go, it's referred to as the "Slice" http://golang.org/ref/spec#Slice_types
Its elements range from 0 to len(slice)-1, and are accessed with C-like array access notation. The "front" of the slice is generally considered slice[0], though you may consider a different index the front if you're using a slice to implement something like, e.g., a stack.
No built-in type in Go has any methods defined on it, but do have built-in functions that take them as arguments, such as len.
The package you linked to implements the List type. As the documentation at the top says "Package list implements a doubly linked list." This doubly linked list, which you can create by calling list.New(), has a Front method, among the others listed in the package documentation.
t is not a List. It is a slice of strings (slices and Lists are not the same thing). The first element of a slice is [0].
I believe the for loop you mean is this (untested):
for _, word := range t {
m[word]++
}

Golang, Go : mapping with returning interface?

http://golang.org/pkg/sort/
This is from Go example.
// OrderedBy returns a Sorter that sorts using the less functions, in order.
// Call its Sort method to sort the data.
func OrderedBy(less ...lessFunc) *multiSorter {
return &multiSorter{
changes: changes,
less: less,
}
}
What does this do by colon? Is it mapping? Is it closure? Too much new syntax here. What should I read to understand this syntax in Go?
It's a factory function, creating and initialising a struct of type multisorter:
https://sites.google.com/site/gopatterns/object-oriented/constructors
Additionally, Go "constructors" can be written succinctly using initializers within a factory function:
function NewMatrix(rows, cols, int) *matrix {
return &matrix{rows, cols, make([]float, rows*cols)}
}
Also, it is using named parameters when initialising:
http://www.golang-book.com/9
This allocates memory for all the fields, sets each of them to their zero value and returns a pointer. (Circle) More often we want to give each of the fields a value. We can do this in two ways. Like this:
c := Circle{x: 0, y: 0, r: 5}
The `less ...lessFunc` in the func declaration means:
any number of parameters, each of type `lessFunc` can be passed here, and will be stored in the slice `less`
So it creates a `multiSorter` struct, which supports the sort interface, and calling the sort method from that interface (and implemented by multiSorter) will cause the object to use each lessFunc in turn while sorting
Does this make sense? I can expand more if needed...

Resources