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
5package iterator_test
6
7import (
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
21var (
22	client *Client
23	ctx    = context.Background()
24)
25
26var 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
37func 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.
56func 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.
88func 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.
111func 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.
129func 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.
155func 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).
168type 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.
178func (it *SieveIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
179
180func (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.
211func (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	}
215outer:
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
234func (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