github.com/cayleygraph/cayley@v0.7.7/graph/iterator/fixed.go (about)

     1  // Copyright 2014 The Cayley Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package iterator
    16  
    17  // Defines one of the base iterators, the Fixed iterator. A fixed iterator is quite simple; it
    18  // contains an explicit fixed array of values.
    19  //
    20  // A fixed iterator requires an Equality function to be passed to it, by reason that graph.Ref, the
    21  // opaque Quad store value, may not answer to ==.
    22  
    23  import (
    24  	"context"
    25  	"fmt"
    26  
    27  	"github.com/cayleygraph/cayley/graph"
    28  )
    29  
    30  var _ graph.IteratorFuture = &Fixed{}
    31  
    32  // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and
    33  // an equality function.
    34  type Fixed struct {
    35  	it *fixed
    36  	graph.Iterator
    37  }
    38  
    39  // Creates a new Fixed iterator with a custom comparator.
    40  func NewFixed(vals ...graph.Ref) *Fixed {
    41  	it := &Fixed{
    42  		it: newFixed(vals...),
    43  	}
    44  	it.Iterator = graph.AsLegacy(it.it)
    45  	return it
    46  }
    47  
    48  // Add a value to the iterator. The array now contains this value.
    49  // TODO(barakmich): This ought to be a set someday, disallowing repeated values.
    50  func (it *Fixed) Add(v graph.Ref) {
    51  	it.it.Add(v)
    52  }
    53  
    54  // Values returns a list of values stored in iterator. Slice should not be modified.
    55  func (it *Fixed) Values() []graph.Ref {
    56  	return it.it.Values()
    57  }
    58  
    59  func (it *Fixed) AsShape() graph.IteratorShape {
    60  	it.Close()
    61  	return it.it
    62  }
    63  
    64  var _ graph.IteratorShape = &fixed{}
    65  
    66  // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and
    67  // an equality function.
    68  type fixed struct {
    69  	values []graph.Ref
    70  }
    71  
    72  // Creates a new Fixed iterator with a custom comparator.
    73  func newFixed(vals ...graph.Ref) *fixed {
    74  	return &fixed{
    75  		values: append([]graph.Ref{}, vals...),
    76  	}
    77  }
    78  
    79  func (it *fixed) Iterate() graph.Scanner {
    80  	return newFixedNext(it.values)
    81  }
    82  
    83  func (it *fixed) Lookup() graph.Index {
    84  	return newFixedContains(it.values)
    85  }
    86  
    87  func (it *fixed) AsLegacy() graph.Iterator {
    88  	it2 := &Fixed{it: it}
    89  	it2.Iterator = graph.NewLegacy(it, it2)
    90  	return it2
    91  }
    92  
    93  // Add a value to the iterator. The array now contains this value.
    94  // TODO(barakmich): This ought to be a set someday, disallowing repeated values.
    95  func (it *fixed) Add(v graph.Ref) {
    96  	it.values = append(it.values, v)
    97  }
    98  
    99  // Values returns a list of values stored in iterator. Slice must not be modified.
   100  func (it *fixed) Values() []graph.Ref {
   101  	return it.values
   102  }
   103  
   104  func (it *fixed) String() string {
   105  	return fmt.Sprintf("Fixed(%v)", it.values)
   106  }
   107  
   108  // No sub-iterators.
   109  func (it *fixed) SubIterators() []graph.IteratorShape {
   110  	return nil
   111  }
   112  
   113  // Optimize() for a Fixed iterator is simple. Returns a Null iterator if it's empty
   114  // (so that other iterators upstream can treat this as null) or there is no
   115  // optimization.
   116  func (it *fixed) Optimize(ctx context.Context) (graph.IteratorShape, bool) {
   117  	if len(it.values) == 1 && it.values[0] == nil {
   118  		return newNull(), true
   119  	}
   120  
   121  	return it, false
   122  }
   123  
   124  // As we right now have to scan the entire list, Next and Contains are linear with the
   125  // size. However, a better data structure could remove these limits.
   126  func (it *fixed) Stats(ctx context.Context) (graph.IteratorCosts, error) {
   127  	return graph.IteratorCosts{
   128  		ContainsCost: 1,
   129  		NextCost:     1,
   130  		Size: graph.Size{
   131  			Size:  int64(len(it.values)),
   132  			Exact: true,
   133  		},
   134  	}, nil
   135  }
   136  
   137  // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and
   138  // an equality function.
   139  type fixedNext struct {
   140  	values []graph.Ref
   141  	ind    int
   142  	result graph.Ref
   143  }
   144  
   145  // Creates a new Fixed iterator with a custom comparator.
   146  func newFixedNext(vals []graph.Ref) *fixedNext {
   147  	return &fixedNext{
   148  		values: vals,
   149  	}
   150  }
   151  
   152  func (it *fixedNext) Close() error {
   153  	return nil
   154  }
   155  
   156  func (it *fixedNext) TagResults(dst map[string]graph.Ref) {}
   157  
   158  func (it *fixedNext) String() string {
   159  	return fmt.Sprintf("Fixed(%v)", it.values)
   160  }
   161  
   162  // Next advances the iterator.
   163  func (it *fixedNext) Next(ctx context.Context) bool {
   164  	if it.ind >= len(it.values) {
   165  		return false
   166  	}
   167  	out := it.values[it.ind]
   168  	it.result = out
   169  	it.ind++
   170  	return true
   171  }
   172  
   173  func (it *fixedNext) Err() error {
   174  	return nil
   175  }
   176  
   177  func (it *fixedNext) Result() graph.Ref {
   178  	return it.result
   179  }
   180  
   181  func (it *fixedNext) NextPath(ctx context.Context) bool {
   182  	return false
   183  }
   184  
   185  // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and
   186  // an equality function.
   187  type fixedContains struct {
   188  	values []graph.Ref
   189  	keys   []interface{}
   190  	result graph.Ref
   191  }
   192  
   193  // Creates a new Fixed iterator with a custom comparator.
   194  func newFixedContains(vals []graph.Ref) *fixedContains {
   195  	keys := make([]interface{}, 0, len(vals))
   196  	for _, v := range vals {
   197  		keys = append(keys, graph.ToKey(v))
   198  	}
   199  	return &fixedContains{
   200  		values: vals,
   201  		keys:   keys,
   202  	}
   203  }
   204  
   205  func (it *fixedContains) Close() error {
   206  	return nil
   207  }
   208  
   209  func (it *fixedContains) TagResults(dst map[string]graph.Ref) {}
   210  
   211  func (it *fixedContains) String() string {
   212  	return fmt.Sprintf("Fixed(%v)", it.values)
   213  }
   214  
   215  // Check if the passed value is equal to one of the values stored in the iterator.
   216  func (it *fixedContains) Contains(ctx context.Context, v graph.Ref) bool {
   217  	// Could be optimized by keeping it sorted or using a better datastructure.
   218  	// However, for fixed iterators, which are by definition kind of tiny, this
   219  	// isn't a big issue.
   220  	vk := graph.ToKey(v)
   221  	for i, x := range it.keys {
   222  		if x == vk {
   223  			it.result = it.values[i]
   224  			return true
   225  		}
   226  	}
   227  	return false
   228  }
   229  
   230  func (it *fixedContains) Err() error {
   231  	return nil
   232  }
   233  
   234  func (it *fixedContains) Result() graph.Ref {
   235  	return it.result
   236  }
   237  
   238  func (it *fixedContains) NextPath(ctx context.Context) bool {
   239  	return false
   240  }