MergeBodies is like MergeFiles except it deals directly with bodies, rather than with entire files.
(bodies []Body)
| 26 | // MergeBodies is like MergeFiles except it deals directly with bodies, rather |
| 27 | // than with entire files. |
| 28 | func MergeBodies(bodies []Body) Body { |
| 29 | if len(bodies) == 0 { |
| 30 | // Swap out for our singleton empty body, to reduce the number of |
| 31 | // empty slices we have hanging around. |
| 32 | return emptyBody |
| 33 | } |
| 34 | |
| 35 | // If any of the given bodies are already merged bodies, we'll unpack |
| 36 | // to flatten to a single mergedBodies, since that's conceptually simpler. |
| 37 | // This also, as a side-effect, eliminates any empty bodies, since |
| 38 | // empties are merged bodies with no inner bodies. |
| 39 | var newLen int |
| 40 | var flatten bool |
| 41 | for _, body := range bodies { |
| 42 | if children, merged := body.(mergedBodies); merged { |
| 43 | newLen += len(children) |
| 44 | flatten = true |
| 45 | } else { |
| 46 | newLen++ |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | if !flatten { // not just newLen == len, because we might have mergedBodies with single bodies inside |
| 51 | return mergedBodies(bodies) |
| 52 | } |
| 53 | |
| 54 | if newLen == 0 { |
| 55 | // Don't allocate a new empty when we already have one |
| 56 | return emptyBody |
| 57 | } |
| 58 | |
| 59 | new := make([]Body, 0, newLen) |
| 60 | for _, body := range bodies { |
| 61 | if children, merged := body.(mergedBodies); merged { |
| 62 | new = append(new, children...) |
| 63 | } else { |
| 64 | new = append(new, body) |
| 65 | } |
| 66 | } |
| 67 | return mergedBodies(new) |
| 68 | } |
| 69 | |
| 70 | var emptyBody = mergedBodies([]Body{}) |
| 71 |