diff --git a/homeworks/11_garbage_collector/README.md b/homeworks/11_garbage_collector/README.md new file mode 100644 index 0000000..db6adfe --- /dev/null +++ b/homeworks/11_garbage_collector/README.md @@ -0,0 +1,12 @@ +# Домашнее задание №11 + +В домашнем задании нужно реализовать функцию трассировки объектов. + +Трассировка объектов будет осуществляться со стеков, рекурсивно проходя все объекты в куче. Важно написать реализацию алгоритма так, чтобы не было повторных обходов одних и тех же объектов. Циклов не будет, проверку на это реализовывать не нужно. Для обхода объектов можно использовать алгоритмы DFS или BFS. + +Различать указатели и свободные участки памяти нужно будет при помощи значений в памяти, если значение непустое — значит это указатель, который указывает на какой-то другой участок памяти. + +Для выполнения домашнего задания подготовлен шаблон кода и основные тесты, которую помогут проверить корректность реализации конвертации. Шаблона доступен по [ссылке](https://github.com/Balun-courses/deep_go/blob/master/homework/garbage_collector/homework_test.go) + +Задание со звездочкой +Выполнять необязательно, но можно попробовать реализовать функцию трассировки объектов, которая будет учитывать циклы, используя алгоритм раскраски вершин, либо несколько множеств посещеных вершин. \ No newline at end of file diff --git a/homeworks/11_garbage_collector/homework_test.go b/homeworks/11_garbage_collector/homework_test.go new file mode 100644 index 0000000..2812651 --- /dev/null +++ b/homeworks/11_garbage_collector/homework_test.go @@ -0,0 +1,85 @@ +package main + +import ( + "testing" + "unsafe" + + "github.com/stretchr/testify/assert" +) + +// go test -v homework_test.go + +func Trace(stacks [][]uintptr) []uintptr { + seen := map[uintptr]bool{} + result := []uintptr{} + + var dfs func(ptr uintptr) + dfs = func(ptr uintptr) { + if ptr == 0 || seen[ptr] { + return + } + seen[ptr] = true + result = append(result, ptr) + + //nolint:govet + uptr := *(*uintptr)(unsafe.Pointer(ptr)) + dfs(uptr) + } + + for _, row := range stacks { + for _, ptr := range row { + dfs(ptr) + } + } + return result + +} + +// For test purpose we want to allocate this globally +var heapObjects = []int{ + 0x00, 0x00, 0x00, 0x00, 0x00, +} + +var ( + heapPointer1 = &heapObjects[1] + heapPointer2 = &heapObjects[2] + heapPointer3 = (*int)(nil) + heapPointer4 = &heapPointer3 +) + +func TestTrace(t *testing.T) { + + var stacks = [][]uintptr{ + { + uintptr(unsafe.Pointer(&heapPointer1)), 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, uintptr(unsafe.Pointer(&heapObjects[0])), + 0x00, 0x00, 0x00, 0x00, + }, + { + uintptr(unsafe.Pointer(&heapPointer2)), 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, uintptr(unsafe.Pointer(&heapObjects[1])), + 0x00, 0x00, 0x00, uintptr(unsafe.Pointer(&heapObjects[2])), + uintptr(unsafe.Pointer(&heapPointer4)), 0x00, 0x00, 0x00, + }, + { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, uintptr(unsafe.Pointer(&heapObjects[3])), + }, + } + + pointers := Trace(stacks) + expectedPointers := []uintptr{ + uintptr(unsafe.Pointer(&heapPointer1)), + uintptr(unsafe.Pointer(&heapObjects[0])), + uintptr(unsafe.Pointer(&heapPointer2)), + uintptr(unsafe.Pointer(&heapObjects[1])), + uintptr(unsafe.Pointer(&heapObjects[2])), + uintptr(unsafe.Pointer(&heapPointer4)), + uintptr(unsafe.Pointer(&heapPointer3)), + uintptr(unsafe.Pointer(&heapObjects[3])), + } + assert.ElementsMatch(t, expectedPointers, pointers) +}