aboutsummaryrefslogtreecommitdiffstats
path: root/library/go/yandex/tvm/roles_entities_index_builder.go
blob: 20bde16a0061893b82473255d2af45bd133d80fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package tvm

import "sort"

type stages struct {
	keys []string
	id   uint64
}

func createStages(keys []string) stages {
	return stages{
		keys: keys,
	}
}

func (s *stages) getNextStage(keys *[]string) bool {
	s.id += 1
	*keys = (*keys)[:0]

	for idx := range s.keys {
		need := (s.id >> idx) & 0x01
		if need == 1 {
			*keys = append(*keys, s.keys[idx])
		}
	}

	return len(*keys) > 0
}

func buildEntities(entities []Entity) *Entities {
	root := make(idxByAttrs)
	res := &Entities{
		subtree: subTree{
			idxByAttrs: &root,
		},
	}

	stage := createStages(getUniqueSortedKeys(entities))

	keySet := make([]string, 0, len(stage.keys))
	for stage.getNextStage(&keySet) {
		for entityID, entity := range entities {
			currentBranch := &res.subtree

			for _, key := range keySet {
				entValue, ok := entity[key]
				if !ok {
					continue
				}

				if currentBranch.idxByAttrs == nil {
					index := make(idxByAttrs)
					currentBranch.idxByAttrs = &index
				}

				kv := entityAttribute{key: key, value: entValue}
				subtree, ok := (*currentBranch.idxByAttrs)[kv]
				if !ok {
					subtree = &subTree{}
					(*currentBranch.idxByAttrs)[kv] = subtree
				}

				currentBranch = subtree
				currentBranch.entityIds = append(currentBranch.entityIds, entityID)
				res.subtree.entityIds = append(res.subtree.entityIds, entityID)
			}
		}
	}

	postProcessSubTree(&res.subtree, entities)

	return res
}

func postProcessSubTree(sub *subTree, entities []Entity) {
	tmp := make(map[int]interface{}, len(entities))
	for _, e := range sub.entityIds {
		tmp[e] = nil
	}
	sub.entityIds = sub.entityIds[:0]
	for i := range tmp {
		sub.entityIds = append(sub.entityIds, i)
	}
	sort.Ints(sub.entityIds)

	sub.entities = make([]Entity, 0, len(sub.entityIds))
	sub.entityLengths = make(map[int]interface{})
	for _, idx := range sub.entityIds {
		sub.entities = append(sub.entities, entities[idx])
		sub.entityLengths[len(entities[idx])] = nil
	}
	sub.entityIds = nil

	if sub.idxByAttrs != nil {
		for _, rest := range *sub.idxByAttrs {
			postProcessSubTree(rest, entities)
		}
	}
}

func getUniqueSortedKeys(entities []Entity) []string {
	tmp := map[string]interface{}{}

	for _, e := range entities {
		for k := range e {
			tmp[k] = nil
		}
	}

	res := make([]string, 0, len(tmp))
	for k := range tmp {
		res = append(res, k)
	}

	sort.Strings(res)
	return res
}