splicer.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package splicer
  2. import (
  3. "servitor/pub"
  4. "sync"
  5. )
  6. /*
  7. TODO:
  8. This can be optimized by storing more than 1 element from each container,
  9. and then refilling elements of the containers in parallel.
  10. */
  11. type Splicer []struct {
  12. basepoint uint
  13. page pub.Container
  14. element pub.Tangible
  15. }
  16. func (s Splicer) Harvest(quantity uint, startingPoint uint) ([]pub.Tangible, pub.Container, uint) {
  17. clone := s.clone()
  18. for i := 0; i < int(startingPoint); i++ {
  19. clone.microharvest()
  20. }
  21. output := make([]pub.Tangible, 0, quantity)
  22. for i := 0; i < int(quantity); i++ {
  23. harvested := clone.microharvest()
  24. if harvested == nil {
  25. clone = nil
  26. break
  27. }
  28. output = append(output, harvested)
  29. }
  30. return output, clone, 0
  31. }
  32. func (s Splicer) clone() *Splicer {
  33. newSplicer := make(Splicer, len(s))
  34. copy(newSplicer, s)
  35. return &newSplicer
  36. }
  37. func (s Splicer) microharvest() pub.Tangible {
  38. var mostRecent pub.Tangible
  39. var mostRecentIndex int
  40. for i, candidate := range s {
  41. if mostRecent == nil {
  42. mostRecent = candidate.element
  43. mostRecentIndex = i
  44. continue
  45. }
  46. if candidate.element == nil {
  47. continue
  48. }
  49. if candidate.element.Timestamp().After(mostRecent.Timestamp()) {
  50. mostRecent = candidate.element
  51. mostRecentIndex = i
  52. continue
  53. }
  54. }
  55. if mostRecent == nil {
  56. return nil
  57. }
  58. if s[mostRecentIndex].page != nil {
  59. var elements []pub.Tangible
  60. elements, s[mostRecentIndex].page, s[mostRecentIndex].basepoint = s[mostRecentIndex].page.Harvest(1, s[mostRecentIndex].basepoint)
  61. if len(elements) > 1 {
  62. panic("harvest returned more that one element when I only asked for one")
  63. } else if len(elements) == 0 {
  64. s[mostRecentIndex].element = nil
  65. } else {
  66. s[mostRecentIndex].element = elements[0]
  67. }
  68. } else {
  69. s[mostRecentIndex].element = nil
  70. }
  71. return mostRecent
  72. }
  73. func NewSplicer(inputs []string) *Splicer {
  74. s := make(Splicer, len(inputs))
  75. var wg sync.WaitGroup
  76. for i, input := range inputs {
  77. i := i
  78. input := input
  79. wg.Add(1)
  80. go func() {
  81. fetched := pub.FetchUserInput(input)
  82. var children pub.Container
  83. switch narrowed := fetched.(type) {
  84. case pub.Tangible:
  85. children = narrowed.Children()
  86. case *pub.Collection:
  87. children = narrowed
  88. default:
  89. panic("cannot splice non-Tangible, non-Collection")
  90. }
  91. if children != nil {
  92. var elements []pub.Tangible
  93. elements, s[i].page, s[i].basepoint = children.Harvest(1, 0)
  94. if len(elements) > 1 {
  95. panic("harvest returned more that one element when I only asked for one")
  96. } else if len(elements) == 0 {
  97. s[i].element = nil
  98. } else {
  99. s[i].element = elements[0]
  100. }
  101. } else {
  102. s[i].element = nil
  103. }
  104. wg.Done()
  105. }()
  106. }
  107. wg.Wait()
  108. return &s
  109. }