1
2
3
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
51
52 }
53
54
55
56 func Example_webHandler() {
57
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
77
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
88 func Example_pageLoop() {
89
90 const max = 42
91 const pageSize = 5
92 p := iterator.NewPager(Primes(max), pageSize, "" )
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
105
106
107
108 }
109
110
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
123
124
125 }
126
127
128
129 func Example_serverPages() {
130
131
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
149
150 }
151
152
153
154
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
165
166
167
168 type SieveIterator struct {
169 pageInfo *iterator.PageInfo
170 nextFunc func() error
171 max int
172 p []int
173 pos int
174 items []int
175 }
176
177
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
191 }
192
193
194 it.calc(start + pageSize)
195
196
197
198
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
205 }
206
207 return strconv.Itoa(start + pageSize), nil
208 }
209
210
211 func (it *SieveIterator) calc(max int) {
212 if it.max > 0 && max > it.max+1 {
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
223 continue outer
224 case p > sqrt:
225
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