|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- // Copyright 2016 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- package iterator_test
-
- import (
- "bytes"
- "context"
- "fmt"
- "html/template"
- "log"
- "math"
- "net/http"
- "sort"
- "strconv"
-
- "google.golang.org/api/iterator"
- )
-
- var (
- client *Client
- ctx = context.Background()
- )
-
- var pageTemplate = template.Must(template.New("").Parse(`
- <table>
- {{range .Entries}}
- <tr><td>{{.}}</td></tr>
- {{end}}
- </table>
- {{with .Next}}
- <a href="/entries?pageToken={{.}}">Next Page</a>
- {{end}}
- `))
-
- func Example() {
- it := Primes(19)
-
- for {
- item, err := it.Next()
- if err == iterator.Done {
- break
- }
- if err != nil {
- log.Fatal(err)
- }
- fmt.Printf("%d ", item)
- }
- // Output:
- // 2 3 5 7 11 13 17 19
- }
-
- // This example demonstrates how to use Pager to support
- // pagination on a web site.
- func Example_webHandler() {
- // Assuming some response writer and request per https://golang.org/pkg/net/http/#Handler.
- var w http.ResponseWriter
- var r *http.Request
-
- const pageSize = 25
- it := client.Items(ctx)
- var items []int
- pageToken, err := iterator.NewPager(it, pageSize, r.URL.Query().Get("pageToken")).NextPage(&items)
- if err != nil {
- http.Error(w, fmt.Sprintf("getting next page: %v", err), http.StatusInternalServerError)
- }
- data := struct {
- Items []int
- Next string
- }{
- items,
- pageToken,
- }
- var buf bytes.Buffer
- // pageTemplate is a global html/template.Template that is only parsed once, rather than for
- // every invocation.
- if err := pageTemplate.Execute(&buf, data); err != nil {
- http.Error(w, fmt.Sprintf("executing page template: %v", err), http.StatusInternalServerError)
- }
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- if _, err := buf.WriteTo(w); err != nil {
- log.Printf("writing response: %v", err)
- }
- }
-
- // This example demonstrates how to use a Pager to page through an iterator in a loop.
- func Example_pageLoop() {
- // Find all primes up to 42, in pages of size 5.
- const max = 42
- const pageSize = 5
- p := iterator.NewPager(Primes(max), pageSize, "" /* start from the beginning */)
- for page := 0; ; page++ {
- var items []int
- pageToken, err := p.NextPage(&items)
- if err != nil {
- log.Fatalf("Iterator paging failed: %v", err)
- }
- fmt.Printf("Page %d: %v\n", page, items)
- if pageToken == "" {
- break
- }
- }
- // Output:
- // Page 0: [2 3 5 7 11]
- // Page 1: [13 17 19 23 29]
- // Page 2: [31 37 41]
- }
-
- // The example demonstrates how to use a Pager to request a page from a given token.
- func Example_pageToken() {
- const pageSize = 5
- const pageToken = "1337"
- p := iterator.NewPager(Primes(0), pageSize, pageToken)
-
- var items []int
- nextPage, err := p.NextPage(&items)
- if err != nil {
- log.Fatalf("Iterator paging failed: %v", err)
- }
- fmt.Printf("Primes: %v\nToken: %q\n", items, nextPage)
- // Output:
- // Primes: [1361 1367 1373 1381 1399]
- // Token: "1400"
- }
-
- // This example demonstrates how to get exactly the items in the buffer, without
- // triggering an extra RPC.
- func Example_serverPages() {
- // The iterator returned by Primes has a default page size of 20, which means
- // it will return all the primes in the range [2, 21).
- it := Primes(0)
- var items []int
- for {
- item, err := it.Next()
- if err == iterator.Done {
- break
- }
- if err != nil {
- log.Fatal(err)
- }
- items = append(items, item)
- if it.PageInfo().Remaining() == 0 {
- break
- }
- }
- fmt.Println(items)
- // Output:
- // [2 3 5 7 11 13 17 19]
- }
-
- // Primes returns a iterator which returns a sequence of prime numbers.
- // If non-zero, max specifies the maximum number which could possibly be
- // returned.
- func Primes(max int) *SieveIterator {
- it := &SieveIterator{pos: 2, max: max}
- it.pageInfo, it.nextFunc = iterator.NewPageInfo(
- it.fetch,
- func() int { return len(it.items) },
- func() interface{} { b := it.items; it.items = nil; return b })
- return it
- }
-
- // SieveIterator is an iterator that returns primes using the sieve of
- // Eratosthenes. It is a demonstration of how an iterator might work.
- // Internally, it uses "page size" as the number of ints to consider,
- // and "page token" as the first number to consider (defaults to 2).
- type SieveIterator struct {
- pageInfo *iterator.PageInfo
- nextFunc func() error
- max int // The largest number to consider.
- p []int // Primes in the range [2, pos).
- pos int // Next number to consider when generating p.
- items []int
- }
-
- // PageInfo returns a PageInfo, which supports pagination.
- func (it *SieveIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
-
- func (it *SieveIterator) fetch(pageSize int, pageToken string) (string, error) {
- start := 2
- if pageToken != "" {
- s, err := strconv.Atoi(pageToken)
- if err != nil || s < 2 {
- return "", fmt.Errorf("invalid token %q", pageToken)
- }
- start = s
- }
- if pageSize == 0 {
- pageSize = 20 // Default page size.
- }
-
- // Make sure sufficient primes have been calculated.
- it.calc(start + pageSize)
-
- // Find the subslice of primes which match this page.
- // Note that PageInfo requires that fetch does not remove any existing items,
- // so we cannot assume that items is empty at this call.
- items := it.p[sort.SearchInts(it.p, start):]
- items = items[:sort.SearchInts(items, start+pageSize)]
- it.items = append(it.items, items...)
-
- if it.max > 0 && start+pageSize > it.max {
- return "", nil // No more possible numbers to return.
- }
-
- return strconv.Itoa(start + pageSize), nil
- }
-
- // calc populates p with all primes up to, but not including, max.
- func (it *SieveIterator) calc(max int) {
- if it.max > 0 && max > it.max+1 { // it.max is an inclusive bounds, max is exclusive.
- max = it.max + 1
- }
- outer:
- for x := it.pos; x < max; x++ {
- sqrt := int(math.Sqrt(float64(x)))
- inner:
- for _, p := range it.p {
- switch {
- case x%p == 0:
- // Not a prime.
- continue outer
- case p > sqrt:
- // Only need to check up to sqrt.
- break inner
- }
- }
- it.p = append(it.p, x)
- }
- it.pos = max
- }
-
- func (it *SieveIterator) Next() (int, error) {
- if err := it.nextFunc(); err != nil {
- return 0, err
- }
- item := it.items[0]
- it.items = it.items[1:]
- return item, nil
- }
|