You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

252 lines
6.4 KiB

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