Quellcode durchsuchen

fix memory sort

Aneurin Barker Snook vor 11 Monaten
Ursprung
Commit
379450fa36
6 geänderte Dateien mit 103 neuen und 37 gelöschten Zeilen
  1. 68 4
      collection_test.go
  2. 3 0
      interfaces.go
  3. 3 3
      leveldb_iter.go
  4. 1 1
      memory.go
  5. 16 10
      memory_iter.go
  6. 12 19
      sort.go

+ 68 - 4
collection_test.go

@@ -2,6 +2,7 @@ package ezdb
 
 import (
 	"errors"
+	"fmt"
 	"testing"
 )
 
@@ -108,10 +109,8 @@ func (c *CollectionTest) get() error {
 		if err != nil {
 			c.T.Errorf("(get) failed to get student '%s': %v", key, err)
 			continue
-		} else if actual.Name != expected.Name {
-			c.T.Errorf("(get) student '%s' has wrong name (expected '%s', got '%s')", key, expected.Name, actual.Name)
-		} else if actual.Age != expected.Age {
-			c.T.Errorf("(get) student '%s' has wrong age (expected '%s', got '%s')", key, expected.Name, actual.Name)
+		} else if err := compareStudent(key, expected, actual); err != nil {
+			c.T.Errorf("(get) %v", err)
 		} else {
 			c.T.Logf("(get) correctly got student '%s'", key)
 		}
@@ -173,6 +172,60 @@ func (c *CollectionTest) iterCount() error {
 	return nil
 }
 
+func (c *CollectionTest) iterFirst() error {
+	iter := c.C.Iter().SortKeys(func(a, b string) bool {
+		return a < b
+	})
+	defer iter.Release()
+
+	expectedKey := "annie"
+	iter.First()
+	actualKey := iter.Key()
+	if actualKey != expectedKey {
+		c.T.Errorf("(iterFirst) incorrect student (expected '%s', got '%s')", expectedKey, actualKey)
+		return nil
+	}
+
+	expected := students["annie"]
+	actual, err := iter.Value()
+	if err != nil {
+		c.T.Errorf("(iterFirst) failed to get student '%s': %v", actualKey, err)
+		return err
+	}
+	if err := compareStudent(expectedKey, expected, actual); err != nil {
+		c.T.Errorf("(iterFirst) %v", err)
+	}
+
+	return nil
+}
+
+func (c *CollectionTest) iterLast() error {
+	iter := c.C.Iter().SortKeys(func(a, b string) bool {
+		return a < b
+	})
+	defer iter.Release()
+
+	expectedKey := "clive"
+	iter.Last()
+	actualKey := iter.Key()
+	if actualKey != expectedKey {
+		c.T.Errorf("(iterFirst) incorrect student (expected '%s', got '%s')", expectedKey, actualKey)
+		return nil
+	}
+
+	expected := students["clive"]
+	actual, err := iter.Value()
+	if err != nil {
+		c.T.Errorf("(iterFirst) failed to get student '%s': %v", actualKey, err)
+		return err
+	}
+	if err := compareStudent(expectedKey, expected, actual); err != nil {
+		c.T.Errorf("(iterFirst) %v", err)
+	}
+
+	return nil
+}
+
 func (c *CollectionTest) close() error {
 	if c.F["close"] != nil {
 		if err := c.F["close"](); err != nil {
@@ -197,6 +250,8 @@ func (c *CollectionTest) Run() {
 		c.get,
 		c.delete,
 		c.iterCount,
+		c.iterFirst,
+		c.iterLast,
 		c.close,
 	}
 
@@ -206,3 +261,12 @@ func (c *CollectionTest) Run() {
 		}
 	}
 }
+
+func compareStudent(expectedKey string, expected, actual *Student) error {
+	if actual.Name != expected.Name {
+		return fmt.Errorf("student '%s' has wrong name (expected '%s', got '%s')", expectedKey, expected.Name, actual.Name)
+	} else if actual.Age != expected.Age {
+		return fmt.Errorf("student '%s' has wrong age (expected '%s', got '%s')", expectedKey, expected.Name, actual.Name)
+	}
+	return nil
+}

+ 3 - 0
interfaces.go

@@ -25,6 +25,9 @@ type DocumentMarshaler[T1 any, T2 any] interface {
 type FilterFunc[T any] func(key string, value T) bool
 
 // Iterator provides functionality to explore a collection.
+//
+// Be mindful that the order of documents is not assured by any Collection implementation.
+// Use the Sort or SortKeys function before iterating over documents to ensure deterministic sort.
 type Iterator[T any] interface {
 	First() bool // Move the iterator to the first document. Returns false if there is no first document.
 	Last() bool  // Move the iterator to the last document. Returns false if there is no last document.

+ 3 - 3
leveldb_iter.go

@@ -39,7 +39,7 @@ func (i *LevelDBIterator[T]) Filter(f FilterFunc[T]) Iterator[T] {
 		m[key] = value
 	}
 
-	return newMemoryIterator(m, i)
+	return newMemoryIterator(m, nil, i)
 }
 
 func (i *LevelDBIterator[T]) First() bool {
@@ -109,13 +109,13 @@ func (i *LevelDBIterator[T]) Release() {
 
 func (i *LevelDBIterator[T]) Sort(f SortFunc[T]) Iterator[T] {
 	all, _ := i.GetAll()
-	m := newMemoryIterator(all, i)
+	m := newMemoryIterator(all, nil, i)
 	return m.Sort(f)
 }
 
 func (i *LevelDBIterator[T]) SortKeys(f SortFunc[string]) Iterator[T] {
 	all, _ := i.GetAll()
-	m := newMemoryIterator(all, i)
+	m := newMemoryIterator(all, nil, i)
 	return m.SortKeys(f)
 }
 

+ 1 - 1
memory.go

@@ -57,7 +57,7 @@ func (c *MemoryCollection[T]) Has(key string) (bool, error) {
 }
 
 func (c *MemoryCollection[T]) Iter() Iterator[T] {
-	m := newMemoryIterator[T](c.m, nil)
+	m := newMemoryIterator[T](c.m, nil, nil)
 	if !c.open {
 		m.Release()
 	}

+ 16 - 10
memory_iter.go

@@ -21,15 +21,17 @@ func (i *MemoryIterator[T]) Filter(f FilterFunc[T]) Iterator[T] {
 		return i
 	}
 
+	k := []string{}
 	m := map[string]T{}
 	i.reset()
 	for i.Next() {
 		key, value, _ := i.Get()
 		if f(key, value) {
+			k = append(k, key)
 			m[key] = value
 		}
 	}
-	return newMemoryIterator(m, i)
+	return newMemoryIterator(m, k, i)
 }
 
 func (i *MemoryIterator[T]) First() bool {
@@ -135,9 +137,9 @@ func (i *MemoryIterator[T]) Sort(f SortFunc[T]) Iterator[T] {
 		f: f,
 	}
 	sort.Stable(s)
-	m := s.Result()
+	k := s.Result()
 
-	return newMemoryIterator(m, i)
+	return newMemoryIterator(i.m, k, i)
 }
 
 func (i *MemoryIterator[T]) SortKeys(f SortFunc[string]) Iterator[T] {
@@ -145,14 +147,14 @@ func (i *MemoryIterator[T]) SortKeys(f SortFunc[string]) Iterator[T] {
 		return i
 	}
 
-	s := &keySort[T]{
-		a: makeSortable(i.m),
+	s := &keySort{
+		a: i.k,
 		f: f,
 	}
 	sort.Stable(s)
-	m := s.Result()
+	k := s.Result()
 
-	return newMemoryIterator(m, i)
+	return newMemoryIterator(i.m, k, i)
 }
 
 func (i *MemoryIterator[T]) Value() (T, error) {
@@ -164,7 +166,7 @@ func (i *MemoryIterator[T]) reset() {
 	i.pos = -1
 }
 
-func newMemoryIterator[T any](m map[string]T, prev Iterator[T]) *MemoryIterator[T] {
+func newMemoryIterator[T any](m map[string]T, k []string, prev Iterator[T]) *MemoryIterator[T] {
 	i := &MemoryIterator[T]{
 		k: []string{},
 		m: m,
@@ -173,8 +175,12 @@ func newMemoryIterator[T any](m map[string]T, prev Iterator[T]) *MemoryIterator[
 		prev: prev,
 	}
 
-	for k := range i.m {
-		i.k = append(i.k, k)
+	if len(k) > 0 {
+		i.k = k
+	} else {
+		for k := range i.m {
+			i.k = append(i.k, k)
+		}
 	}
 
 	return i

+ 12 - 19
sort.go

@@ -5,31 +5,24 @@ type sortable[T any] struct {
 	Value T
 }
 
-type keySort[T any] struct {
-	a []*sortable[T]
+type keySort struct {
+	a []string
 	f SortFunc[string]
 }
 
-func (s *keySort[T]) Len() int {
+func (s *keySort) Len() int {
 	return len(s.a)
 }
 
-func (s *keySort[T]) Less(i, j int) bool {
-	a := s.a[i]
-	b := s.a[j]
-
-	return s.f(a.Key, b.Key)
+func (s *keySort) Less(i, j int) bool {
+	return s.f(s.a[i], s.a[j])
 }
 
-func (s *keySort[T]) Result() map[string]T {
-	m := map[string]T{}
-	for _, el := range s.a {
-		m[el.Key] = el.Value
-	}
-	return m
+func (s *keySort) Result() []string {
+	return s.a
 }
 
-func (s *keySort[T]) Swap(i, j int) {
+func (s *keySort) Swap(i, j int) {
 	a := s.a[i]
 	b := s.a[j]
 	s.a[i] = b
@@ -52,12 +45,12 @@ func (s *valueSort[T]) Less(i, j int) bool {
 	return s.f(a.Value, b.Value)
 }
 
-func (s *valueSort[T]) Result() map[string]T {
-	m := map[string]T{}
+func (s *valueSort[T]) Result() []string {
+	k := []string{}
 	for _, el := range s.a {
-		m[el.Key] = el.Value
+		k = append(k, el.Key)
 	}
-	return m
+	return k
 }
 
 func (s *valueSort[T]) Swap(i, j int) {