...

Source file src/google.golang.org/api/iterator/examples_test.go

Documentation: google.golang.org/api/iterator

     1  // Copyright 2016 Google LLC.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package iterator_test
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"fmt"
    11  	"html/template"
    12  	"log"
    13  	"math"
    14  	"net/http"
    15  	"sort"
    16  	"strconv"
    17  
    18  	"google.golang.org/api/iterator"
    19  )
    20  
    21  var (
    22  	client *Client
    23  	ctx    = context.Background()
    24  )
    25  
    26  var pageTemplate = template.Must(template.New("").Parse(`
    27  <table>
    28    {{range .Entries}}
    29      <tr><td>{{.}}</td></tr>
    30    {{end}}
    31  </table>
    32  {{with .Next}}
    33    <a href="/entries?pageToken={{.}}">Next Page</a>
    34  {{end}}
    35  `))
    36  
    37  func Example() {
    38  	it := Primes(19)
    39  
    40  	for {
    41  		item, err := it.Next()
    42  		if err == iterator.Done {
    43  			break
    44  		}
    45  		if err != nil {
    46  			log.Fatal(err)
    47  		}
    48  		fmt.Printf("%d ", item)
    49  	}
    50  	// Output:
    51  	// 2 3 5 7 11 13 17 19
    52  }
    53  
    54  // This example demonstrates how to use Pager to support
    55  // pagination on a web site.
    56  func Example_webHandler() {
    57  	// Assuming some response writer and request per https://golang.org/pkg/net/http/#Handler.
    58  	var w http.ResponseWriter
    59  	var r *http.Request
    60  
    61  	const pageSize = 25
    62  	it := client.Items(ctx)
    63  	var items []int
    64  	pageToken, err := iterator.NewPager(it, pageSize, r.URL.Query().Get("pageToken")).NextPage(&items)
    65  	if err != nil {
    66  		http.Error(w, fmt.Sprintf("getting next page: %v", err), http.StatusInternalServerError)
    67  	}
    68  	data := struct {
    69  		Items []int
    70  		Next  string
    71  	}{
    72  		items,
    73  		pageToken,
    74  	}
    75  	var buf bytes.Buffer
    76  	// pageTemplate is a global html/template.Template that is only parsed once, rather than for
    77  	// every invocation.
    78  	if err := pageTemplate.Execute(&buf, data); err != nil {
    79  		http.Error(w, fmt.Sprintf("executing page template: %v", err), http.StatusInternalServerError)
    80  	}
    81  	w.Header().Set("Content-Type", "text/html; charset=utf-8")
    82  	if _, err := buf.WriteTo(w); err != nil {
    83  		log.Printf("writing response: %v", err)
    84  	}
    85  }
    86  
    87  // This example demonstrates how to use a Pager to page through an iterator in a loop.
    88  func Example_pageLoop() {
    89  	// Find all primes up to 42, in pages of size 5.
    90  	const max = 42
    91  	const pageSize = 5
    92  	p := iterator.NewPager(Primes(max), pageSize, "" /* start from the beginning */)
    93  	for page := 0; ; page++ {
    94  		var items []int
    95  		pageToken, err := p.NextPage(&items)
    96  		if err != nil {
    97  			log.Fatalf("Iterator paging failed: %v", err)
    98  		}
    99  		fmt.Printf("Page %d: %v\n", page, items)
   100  		if pageToken == "" {
   101  			break
   102  		}
   103  	}
   104  	// Output:
   105  	// Page 0: [2 3 5 7 11]
   106  	// Page 1: [13 17 19 23 29]
   107  	// Page 2: [31 37 41]
   108  }
   109  
   110  // The example demonstrates how to use a Pager to request a page from a given token.
   111  func Example_pageToken() {
   112  	const pageSize = 5
   113  	const pageToken = "1337"
   114  	p := iterator.NewPager(Primes(0), pageSize, pageToken)
   115  
   116  	var items []int
   117  	nextPage, err := p.NextPage(&items)
   118  	if err != nil {
   119  		log.Fatalf("Iterator paging failed: %v", err)
   120  	}
   121  	fmt.Printf("Primes: %v\nToken:  %q\n", items, nextPage)
   122  	// Output:
   123  	// Primes: [1361 1367 1373 1381 1399]
   124  	// Token:  "1400"
   125  }
   126  
   127  // This example demonstrates how to get exactly the items in the buffer, without
   128  // triggering an extra RPC.
   129  func Example_serverPages() {
   130  	// The iterator returned by Primes has a default page size of 20, which means
   131  	// it will return all the primes in the range [2, 21).
   132  	it := Primes(0)
   133  	var items []int
   134  	for {
   135  		item, err := it.Next()
   136  		if err == iterator.Done {
   137  			break
   138  		}
   139  		if err != nil {
   140  			log.Fatal(err)
   141  		}
   142  		items = append(items, item)
   143  		if it.PageInfo().Remaining() == 0 {
   144  			break
   145  		}
   146  	}
   147  	fmt.Println(items)
   148  	// Output:
   149  	// [2 3 5 7 11 13 17 19]
   150  }
   151  
   152  // Primes returns a iterator which returns a sequence of prime numbers.
   153  // If non-zero, max specifies the maximum number which could possibly be
   154  // returned.
   155  func Primes(max int) *SieveIterator {
   156  	it := &SieveIterator{pos: 2, max: max}
   157  	it.pageInfo, it.nextFunc = iterator.NewPageInfo(
   158  		it.fetch,
   159  		func() int { return len(it.items) },
   160  		func() interface{} { b := it.items; it.items = nil; return b })
   161  	return it
   162  }
   163  
   164  // SieveIterator is an iterator that returns primes using the sieve of
   165  // Eratosthenes. It is a demonstration of how an iterator might work.
   166  // Internally, it uses "page size" as the number of ints to consider,
   167  // and "page token" as the first number to consider (defaults to 2).
   168  type SieveIterator struct {
   169  	pageInfo *iterator.PageInfo
   170  	nextFunc func() error
   171  	max      int   // The largest number to consider.
   172  	p        []int // Primes in the range [2, pos).
   173  	pos      int   // Next number to consider when generating p.
   174  	items    []int
   175  }
   176  
   177  // PageInfo returns a PageInfo, which supports pagination.
   178  func (it *SieveIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
   179  
   180  func (it *SieveIterator) fetch(pageSize int, pageToken string) (string, error) {
   181  	start := 2
   182  	if pageToken != "" {
   183  		s, err := strconv.Atoi(pageToken)
   184  		if err != nil || s < 2 {
   185  			return "", fmt.Errorf("invalid token %q", pageToken)
   186  		}
   187  		start = s
   188  	}
   189  	if pageSize == 0 {
   190  		pageSize = 20 // Default page size.
   191  	}
   192  
   193  	// Make sure sufficient primes have been calculated.
   194  	it.calc(start + pageSize)
   195  
   196  	// Find the subslice of primes which match this page.
   197  	// Note that PageInfo requires that fetch does not remove any existing items,
   198  	// so we cannot assume that items is empty at this call.
   199  	items := it.p[sort.SearchInts(it.p, start):]
   200  	items = items[:sort.SearchInts(items, start+pageSize)]
   201  	it.items = append(it.items, items...)
   202  
   203  	if it.max > 0 && start+pageSize > it.max {
   204  		return "", nil // No more possible numbers to return.
   205  	}
   206  
   207  	return strconv.Itoa(start + pageSize), nil
   208  }
   209  
   210  // calc populates p with all primes up to, but not including, max.
   211  func (it *SieveIterator) calc(max int) {
   212  	if it.max > 0 && max > it.max+1 { // it.max is an inclusive bounds, max is exclusive.
   213  		max = it.max + 1
   214  	}
   215  outer:
   216  	for x := it.pos; x < max; x++ {
   217  		sqrt := int(math.Sqrt(float64(x)))
   218  	inner:
   219  		for _, p := range it.p {
   220  			switch {
   221  			case x%p == 0:
   222  				// Not a prime.
   223  				continue outer
   224  			case p > sqrt:
   225  				// Only need to check up to sqrt.
   226  				break inner
   227  			}
   228  		}
   229  		it.p = append(it.p, x)
   230  	}
   231  	it.pos = max
   232  }
   233  
   234  func (it *SieveIterator) Next() (int, error) {
   235  	if err := it.nextFunc(); err != nil {
   236  		return 0, err
   237  	}
   238  	item := it.items[0]
   239  	it.items = it.items[1:]
   240  	return item, nil
   241  }
   242  

View as plain text