Skip to content

Commit

Permalink
Path: Added GetNearestPrefix function to Pathmap
Browse files Browse the repository at this point in the history
The GetNearestPrefix function attempts to find the closest mounted
prefix of a path in the pathmap. This method will be used by the
permission check within the go sysdb provider to find the closest
mounted child's flag of a given flag.

Change-Id: If3dcebec26c2ff83116d836d6bcb3c88144f7acc
  • Loading branch information
msulimov-arista committed Feb 27, 2023
1 parent d41e2b5 commit 39d430f
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 1 deletion.
22 changes: 22 additions & 0 deletions path/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,28 @@ func (m *MapOf[T]) Get(p key.Path) (T, bool) {
return m.val, m.ok
}

// GetLongestPrefix returns the longest prefix of p in the pathmap
// and its value. If the first component of p is not in the pathmap
// (ie: p is malformed), returns a nil path, default value and false
// Otherwise returns the longest prefix of p in the pathMap (which
// be p itself), it's value and true
func (m *MapOf[T]) GetLongestPrefix(p key.Path) (key.Path, T, bool) {
var zeroT T
for i, element := range p {
next, ok := m.children.Get(element)
if !ok && i == 0 {
// malformed path where first component not in pathmap
return nil, zeroT, false
}
if !ok {
// return longest prefix found so far
return p[:i], m.val, true
}
m = next
}
return p, m.val, true // whole path in pathmap
}

func newKeyMap[T any]() *gomap.Map[key.Key, *MapOf[T]] {
return gomap.New[key.Key, *MapOf[T]](func(a, b key.Key) bool { return a.Equal(b) }, key.Hash)
}
Expand Down
84 changes: 83 additions & 1 deletion path/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func TestMapGet(t *testing.T) {
v interface{}
ok bool
}{{
path: key.Path{},
path: nil,
v: 0,
ok: true,
}, {
Expand Down Expand Up @@ -202,6 +202,88 @@ func TestMapGet(t *testing.T) {
}
}

func TestMapGetLongestPrefix(t *testing.T) {
regularMap := Map{}
regularMap.Set(key.Path{}, 33)
regularMap.Set(key.Path{key.New("a"), key.New("b")}, -132)
regularMap.Set(key.Path{key.New("a"), key.New("b"), key.New("c")}, 111)
regularMap.Set(key.Path{key.New("z")}, 203)
regularMap.Set(key.Path{key.New("z"), key.New("zz")}, -24)

emptyMap := Map{}

testCases := []struct {
mp Map
path key.Path
nearestPath key.Path
v interface{}
ok bool
}{{
mp: regularMap,
path: key.Path{},
nearestPath: key.Path{},
v: 33,
ok: true,
}, {
mp: regularMap,
path: key.Path{key.New("a"), key.New("b"), key.New("c"), key.New("d")},
nearestPath: key.Path{key.New("a"), key.New("b"), key.New("c")},
v: 111,
ok: true,
}, {
mp: regularMap,
path: key.Path{key.New("a"), key.New("b")},
nearestPath: key.Path{key.New("a"), key.New("b")},
v: -132,
ok: true,
}, {
mp: regularMap,
path: key.Path{key.New("z"), key.New("a"), key.New("b"), key.New("z")},
nearestPath: key.Path{key.New("z")},
v: 203,
ok: true,
}, {
mp: regularMap,
path: key.Path{key.New("baz"), key.New("qux")},
nearestPath: nil,
v: nil,
ok: false,
}, {
mp: regularMap,
path: key.Path{key.New("c"), key.New("a")},
nearestPath: nil,
v: nil,
ok: false,
}, {
mp: emptyMap,
path: key.Path{},
nearestPath: nil,
v: nil,
ok: true,
}, {
mp: emptyMap,
path: key.Path{key.New("a"), key.New("b"), key.New("c"), key.New("d")},
nearestPath: nil,
v: nil,
ok: false,
}}

for _, tc := range testCases {
nearestPath, v, ok := tc.mp.GetLongestPrefix(tc.path)
if ok != tc.ok {
t.Errorf("Test case %v: Expected Ok: %v, got ok: %v", tc, tc.ok, ok)
}
if !nearestPath.Equal(tc.nearestPath) {
t.Errorf("Test case %v: Expected nearestPath: %v,"+
" got nearestPath: %v", tc, tc.nearestPath, nearestPath)
}
if v != tc.v {
t.Errorf("Test case %v: Expected value: %v, got value: %v",
tc, tc.v, v)
}
}
}

func countNodes(m *Map) int {
if m == nil {
return 0
Expand Down

0 comments on commit 39d430f

Please sign in to comment.