Skip to content

Commit

Permalink
Rewrite scan (#46)
Browse files Browse the repository at this point in the history
Rewrite the way scan works to narrow it down to arrays and structs as
containers.

This change hopefully:

- Makes the algorithm easier to follow.
- Fixes the issue when a pointer points to a container but has a smaller
type than the container itself. (see new test)
- Fixes the issue when a container is not resized to accomodate more
data. (see new test)


Also fixes the panic on #44
  • Loading branch information
pelletier authored Sep 19, 2023
2 parents b75d687 + f10d5bc commit 9ca1316
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 201 deletions.
43 changes: 16 additions & 27 deletions internal/serde/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,52 +209,51 @@ func DeserializeAny(d *Deserializer, t reflect.Type, p unsafe.Pointer) {
}

func serializePointedAt(s *Serializer, t reflect.Type, p unsafe.Pointer) {
// fmt.Printf("Serialize pointed at: %d (%s)\n", p, t)
// If this is a nil pointer, write it as such.
if p == nil {
// fmt.Printf("\t=>NIL\n")
serializeVarint(s, 0)
return
}

id, new := s.assignPointerID(p)
serializeVarint(s, int(id))
// fmt.Printf("\t=>Assigned ID %d\n", id)
if !new {
// fmt.Printf("\t=>Already seen\n")
// This exact pointer has already been serialized. Write its ID
// and move on.
return
}
// fmt.Printf("\t=>New pointer\n")

// Now, this is pointer that is seen for the first time.

// Check the region of this pointer.
r := s.regions.regionOf(p)
r := s.containers.of(p)

// If this pointer does not belong to any region or is the container of
// the region, write a negative offset to flag it is on its own, and
// write its data.
if !r.valid() || (r.offset(p) == 0 && t == r.typ) {
// fmt.Printf("\t=>Is container (region %t)\n", r.Valid())
// If this pointer does not belong to any region, write a negative
// offset to flag it is on its own, and write its data.
if !r.valid() {
serializeVarint(s, -1)
SerializeAny(s, t, p)
return
}

// The pointer points into a memory region.
offset := r.offset(p)
offset := int(r.offset(p))
serializeVarint(s, offset)

// fmt.Printf("\t=>Offset in container: %d\n", offset)

// Write the type of the container.
serializeType(s, r.typ)
// fmt.Printf("\t=>Container at: %d (%s)\n", r.Pointer(), r.Type())

// Serialize the parent.
serializePointedAt(s, r.typ, r.start)
// Serialize the parent. If offset is zero, we reuse the id to store the
// parent. We could have a more compact representation here, but right
// now we need this since the pointers <> id map in the serializer does
// not discriminate between the container and the first element of it.
if offset == 0 {
serializeVarint(s, int(id))
serializeVarint(s, -1)
SerializeAny(s, r.typ, r.addr)
return
}
serializePointedAt(s, r.typ, r.addr)
}

func deserializePointedAt(d *Deserializer, t reflect.Type) reflect.Value {
Expand All @@ -264,25 +263,19 @@ func deserializePointedAt(d *Deserializer, t reflect.Type) reflect.Value {
// reflect.Value that contains a *T (where T is given by the argument
// t).

// fmt.Printf("Deserialize pointed at: %s\n", t)

ptr, id := d.readPtr()
// fmt.Printf("\t=> ptr=%d, id=%d\n", ptr, id)
if ptr != nil || id == 0 { // pointer already seen or nil
// fmt.Printf("\t=>Returning existing data\n")
return reflect.NewAt(t, ptr)
}

offset := deserializeVarint(d)
// fmt.Printf("\t=>Read offset %d\n", offset)

// Negative offset means this is either a container or a standalone
// value.
if offset < 0 {
e := reflect.New(t)
ep := e.UnsafePointer()
d.store(id, ep)
// fmt.Printf("\t=>Negative offset: container %d\n", ep)
DeserializeAny(d, t, ep)
return e
}
Expand All @@ -291,16 +284,12 @@ func deserializePointedAt(d *Deserializer, t reflect.Type) reflect.Value {
// then return the pointer itself with an offset.
ct := deserializeType(d)

// fmt.Printf("\t=>Container type: %s\n", ct)

// cp is a pointer to the container
cp := deserializePointedAt(d, ct)

// Create the pointer with an offset into the container.
ep := unsafe.Add(cp.UnsafePointer(), offset)
r := reflect.NewAt(t, ep)
d.store(id, ep)
// fmt.Printf("\t=>Returning id=%d ep=%d\n", id, ep)
return r
}

Expand Down
Loading

0 comments on commit 9ca1316

Please sign in to comment.