serialization_littleendian.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. //go:build (386 && !appengine) || (amd64 && !appengine) || (arm && !appengine) || (arm64 && !appengine) || (ppc64le && !appengine) || (mipsle && !appengine) || (mips64le && !appengine) || (mips64p32le && !appengine) || (wasm && !appengine)
  2. // +build 386,!appengine amd64,!appengine arm,!appengine arm64,!appengine ppc64le,!appengine mipsle,!appengine mips64le,!appengine mips64p32le,!appengine wasm,!appengine
  3. package roaring
  4. import (
  5. "encoding/binary"
  6. "errors"
  7. "io"
  8. "reflect"
  9. "runtime"
  10. "unsafe"
  11. )
  12. func (ac *arrayContainer) writeTo(stream io.Writer) (int, error) {
  13. buf := uint16SliceAsByteSlice(ac.content)
  14. return stream.Write(buf)
  15. }
  16. func (bc *bitmapContainer) writeTo(stream io.Writer) (int, error) {
  17. if bc.cardinality <= arrayDefaultMaxSize {
  18. return 0, errors.New("refusing to write bitmap container with cardinality of array container")
  19. }
  20. buf := uint64SliceAsByteSlice(bc.bitmap)
  21. return stream.Write(buf)
  22. }
  23. func uint64SliceAsByteSlice(slice []uint64) []byte {
  24. // make a new slice header
  25. header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
  26. // update its capacity and length
  27. header.Len *= 8
  28. header.Cap *= 8
  29. // instantiate result and use KeepAlive so data isn't unmapped.
  30. result := *(*[]byte)(unsafe.Pointer(&header))
  31. runtime.KeepAlive(&slice)
  32. // return it
  33. return result
  34. }
  35. func uint16SliceAsByteSlice(slice []uint16) []byte {
  36. // make a new slice header
  37. header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
  38. // update its capacity and length
  39. header.Len *= 2
  40. header.Cap *= 2
  41. // instantiate result and use KeepAlive so data isn't unmapped.
  42. result := *(*[]byte)(unsafe.Pointer(&header))
  43. runtime.KeepAlive(&slice)
  44. // return it
  45. return result
  46. }
  47. func interval16SliceAsByteSlice(slice []interval16) []byte {
  48. // make a new slice header
  49. header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
  50. // update its capacity and length
  51. header.Len *= 4
  52. header.Cap *= 4
  53. // instantiate result and use KeepAlive so data isn't unmapped.
  54. result := *(*[]byte)(unsafe.Pointer(&header))
  55. runtime.KeepAlive(&slice)
  56. // return it
  57. return result
  58. }
  59. func (bc *bitmapContainer) asLittleEndianByteSlice() []byte {
  60. return uint64SliceAsByteSlice(bc.bitmap)
  61. }
  62. // Deserialization code follows
  63. ////
  64. // These methods (byteSliceAsUint16Slice,...) do not make copies,
  65. // they are pointer-based (unsafe). The caller is responsible to
  66. // ensure that the input slice does not get garbage collected, deleted
  67. // or modified while you hold the returned slince.
  68. ////
  69. func byteSliceAsUint16Slice(slice []byte) (result []uint16) { // here we create a new slice holder
  70. if len(slice)%2 != 0 {
  71. panic("Slice size should be divisible by 2")
  72. }
  73. // reference: https://go101.org/article/unsafe.html
  74. // make a new slice header
  75. bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  76. rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
  77. // transfer the data from the given slice to a new variable (our result)
  78. rHeader.Data = bHeader.Data
  79. rHeader.Len = bHeader.Len / 2
  80. rHeader.Cap = bHeader.Cap / 2
  81. // instantiate result and use KeepAlive so data isn't unmapped.
  82. runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
  83. // return result
  84. return
  85. }
  86. func byteSliceAsUint64Slice(slice []byte) (result []uint64) {
  87. if len(slice)%8 != 0 {
  88. panic("Slice size should be divisible by 8")
  89. }
  90. // reference: https://go101.org/article/unsafe.html
  91. // make a new slice header
  92. bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  93. rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
  94. // transfer the data from the given slice to a new variable (our result)
  95. rHeader.Data = bHeader.Data
  96. rHeader.Len = bHeader.Len / 8
  97. rHeader.Cap = bHeader.Cap / 8
  98. // instantiate result and use KeepAlive so data isn't unmapped.
  99. runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
  100. // return result
  101. return
  102. }
  103. func byteSliceAsInterval16Slice(slice []byte) (result []interval16) {
  104. if len(slice)%4 != 0 {
  105. panic("Slice size should be divisible by 4")
  106. }
  107. // reference: https://go101.org/article/unsafe.html
  108. // make a new slice header
  109. bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  110. rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
  111. // transfer the data from the given slice to a new variable (our result)
  112. rHeader.Data = bHeader.Data
  113. rHeader.Len = bHeader.Len / 4
  114. rHeader.Cap = bHeader.Cap / 4
  115. // instantiate result and use KeepAlive so data isn't unmapped.
  116. runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
  117. // return result
  118. return
  119. }
  120. func byteSliceAsContainerSlice(slice []byte) (result []container) {
  121. var c container
  122. containerSize := int(unsafe.Sizeof(c))
  123. if len(slice)%containerSize != 0 {
  124. panic("Slice size should be divisible by unsafe.Sizeof(container)")
  125. }
  126. // reference: https://go101.org/article/unsafe.html
  127. // make a new slice header
  128. bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  129. rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
  130. // transfer the data from the given slice to a new variable (our result)
  131. rHeader.Data = bHeader.Data
  132. rHeader.Len = bHeader.Len / containerSize
  133. rHeader.Cap = bHeader.Cap / containerSize
  134. // instantiate result and use KeepAlive so data isn't unmapped.
  135. runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
  136. // return result
  137. return
  138. }
  139. func byteSliceAsBitsetSlice(slice []byte) (result []bitmapContainer) {
  140. bitsetSize := int(unsafe.Sizeof(bitmapContainer{}))
  141. if len(slice)%bitsetSize != 0 {
  142. panic("Slice size should be divisible by unsafe.Sizeof(bitmapContainer)")
  143. }
  144. // reference: https://go101.org/article/unsafe.html
  145. // make a new slice header
  146. bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  147. rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
  148. // transfer the data from the given slice to a new variable (our result)
  149. rHeader.Data = bHeader.Data
  150. rHeader.Len = bHeader.Len / bitsetSize
  151. rHeader.Cap = bHeader.Cap / bitsetSize
  152. // instantiate result and use KeepAlive so data isn't unmapped.
  153. runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
  154. // return result
  155. return
  156. }
  157. func byteSliceAsArraySlice(slice []byte) (result []arrayContainer) {
  158. arraySize := int(unsafe.Sizeof(arrayContainer{}))
  159. if len(slice)%arraySize != 0 {
  160. panic("Slice size should be divisible by unsafe.Sizeof(arrayContainer)")
  161. }
  162. // reference: https://go101.org/article/unsafe.html
  163. // make a new slice header
  164. bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  165. rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
  166. // transfer the data from the given slice to a new variable (our result)
  167. rHeader.Data = bHeader.Data
  168. rHeader.Len = bHeader.Len / arraySize
  169. rHeader.Cap = bHeader.Cap / arraySize
  170. // instantiate result and use KeepAlive so data isn't unmapped.
  171. runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
  172. // return result
  173. return
  174. }
  175. func byteSliceAsRun16Slice(slice []byte) (result []runContainer16) {
  176. run16Size := int(unsafe.Sizeof(runContainer16{}))
  177. if len(slice)%run16Size != 0 {
  178. panic("Slice size should be divisible by unsafe.Sizeof(runContainer16)")
  179. }
  180. // reference: https://go101.org/article/unsafe.html
  181. // make a new slice header
  182. bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  183. rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
  184. // transfer the data from the given slice to a new variable (our result)
  185. rHeader.Data = bHeader.Data
  186. rHeader.Len = bHeader.Len / run16Size
  187. rHeader.Cap = bHeader.Cap / run16Size
  188. // instantiate result and use KeepAlive so data isn't unmapped.
  189. runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
  190. // return result
  191. return
  192. }
  193. func byteSliceAsBoolSlice(slice []byte) (result []bool) {
  194. boolSize := int(unsafe.Sizeof(true))
  195. if len(slice)%boolSize != 0 {
  196. panic("Slice size should be divisible by unsafe.Sizeof(bool)")
  197. }
  198. // reference: https://go101.org/article/unsafe.html
  199. // make a new slice header
  200. bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
  201. rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
  202. // transfer the data from the given slice to a new variable (our result)
  203. rHeader.Data = bHeader.Data
  204. rHeader.Len = bHeader.Len / boolSize
  205. rHeader.Cap = bHeader.Cap / boolSize
  206. // instantiate result and use KeepAlive so data isn't unmapped.
  207. runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
  208. // return result
  209. return
  210. }
  211. // FrozenView creates a static view of a serialized bitmap stored in buf.
  212. // It uses CRoaring's frozen bitmap format.
  213. //
  214. // The format specification is available here:
  215. // https://github.com/RoaringBitmap/CRoaring/blob/2c867e9f9c9e2a3a7032791f94c4c7ae3013f6e0/src/roaring.c#L2756-L2783
  216. //
  217. // The provided byte array (buf) is expected to be a constant.
  218. // The function makes the best effort attempt not to copy data.
  219. // Only little endian is supported. The function will err if it detects a big
  220. // endian serialized file.
  221. // You should take care not to modify buff as it will likely result in
  222. // unexpected program behavior.
  223. // If said buffer comes from a memory map, it's advisable to give it read
  224. // only permissions, either at creation or by calling Mprotect from the
  225. // golang.org/x/sys/unix package.
  226. //
  227. // Resulting bitmaps are effectively immutable in the following sense:
  228. // a copy-on-write marker is used so that when you modify the resulting
  229. // bitmap, copies of selected data (containers) are made.
  230. // You should *not* change the copy-on-write status of the resulting
  231. // bitmaps (SetCopyOnWrite).
  232. //
  233. // If buf becomes unavailable, then a bitmap created with
  234. // FromBuffer would be effectively broken. Furthermore, any
  235. // bitmap derived from this bitmap (e.g., via Or, And) might
  236. // also be broken. Thus, before making buf unavailable, you should
  237. // call CloneCopyOnWriteContainers on all such bitmaps.
  238. //
  239. func (rb *Bitmap) FrozenView(buf []byte) error {
  240. return rb.highlowcontainer.frozenView(buf)
  241. }
  242. /* Verbatim specification from CRoaring.
  243. *
  244. * FROZEN SERIALIZATION FORMAT DESCRIPTION
  245. *
  246. * -- (beginning must be aligned by 32 bytes) --
  247. * <bitset_data> uint64_t[BITSET_CONTAINER_SIZE_IN_WORDS * num_bitset_containers]
  248. * <run_data> rle16_t[total number of rle elements in all run containers]
  249. * <array_data> uint16_t[total number of array elements in all array containers]
  250. * <keys> uint16_t[num_containers]
  251. * <counts> uint16_t[num_containers]
  252. * <typecodes> uint8_t[num_containers]
  253. * <header> uint32_t
  254. *
  255. * <header> is a 4-byte value which is a bit union of FROZEN_COOKIE (15 bits)
  256. * and the number of containers (17 bits).
  257. *
  258. * <counts> stores number of elements for every container.
  259. * Its meaning depends on container type.
  260. * For array and bitset containers, this value is the container cardinality minus one.
  261. * For run container, it is the number of rle_t elements (n_runs).
  262. *
  263. * <bitset_data>,<array_data>,<run_data> are flat arrays of elements of
  264. * all containers of respective type.
  265. *
  266. * <*_data> and <keys> are kept close together because they are not accessed
  267. * during deserilization. This may reduce IO in case of large mmaped bitmaps.
  268. * All members have their native alignments during deserilization except <header>,
  269. * which is not guaranteed to be aligned by 4 bytes.
  270. */
  271. const FROZEN_COOKIE = 13766
  272. var (
  273. FrozenBitmapInvalidCookie = errors.New("header does not contain the FROZEN_COOKIE")
  274. FrozenBitmapBigEndian = errors.New("loading big endian frozen bitmaps is not supported")
  275. FrozenBitmapIncomplete = errors.New("input buffer too small to contain a frozen bitmap")
  276. FrozenBitmapOverpopulated = errors.New("too many containers")
  277. FrozenBitmapUnexpectedData = errors.New("spurious data in input")
  278. FrozenBitmapInvalidTypecode = errors.New("unrecognized typecode")
  279. FrozenBitmapBufferTooSmall = errors.New("buffer too small")
  280. )
  281. func (ra *roaringArray) frozenView(buf []byte) error {
  282. if len(buf) < 4 {
  283. return FrozenBitmapIncomplete
  284. }
  285. headerBE := binary.BigEndian.Uint32(buf[len(buf)-4:])
  286. if headerBE&0x7fff == FROZEN_COOKIE {
  287. return FrozenBitmapBigEndian
  288. }
  289. header := binary.LittleEndian.Uint32(buf[len(buf)-4:])
  290. buf = buf[:len(buf)-4]
  291. if header&0x7fff != FROZEN_COOKIE {
  292. return FrozenBitmapInvalidCookie
  293. }
  294. nCont := int(header >> 15)
  295. if nCont > (1 << 16) {
  296. return FrozenBitmapOverpopulated
  297. }
  298. // 1 byte per type, 2 bytes per key, 2 bytes per count.
  299. if len(buf) < 5*nCont {
  300. return FrozenBitmapIncomplete
  301. }
  302. types := buf[len(buf)-nCont:]
  303. buf = buf[:len(buf)-nCont]
  304. counts := byteSliceAsUint16Slice(buf[len(buf)-2*nCont:])
  305. buf = buf[:len(buf)-2*nCont]
  306. keys := byteSliceAsUint16Slice(buf[len(buf)-2*nCont:])
  307. buf = buf[:len(buf)-2*nCont]
  308. nBitmap, nArray, nRun := 0, 0, 0
  309. nArrayEl, nRunEl := 0, 0
  310. for i, t := range types {
  311. switch t {
  312. case 1:
  313. nBitmap++
  314. case 2:
  315. nArray++
  316. nArrayEl += int(counts[i]) + 1
  317. case 3:
  318. nRun++
  319. nRunEl += int(counts[i])
  320. default:
  321. return FrozenBitmapInvalidTypecode
  322. }
  323. }
  324. if len(buf) < (1<<13)*nBitmap+4*nRunEl+2*nArrayEl {
  325. return FrozenBitmapIncomplete
  326. }
  327. bitsetsArena := byteSliceAsUint64Slice(buf[:(1<<13)*nBitmap])
  328. buf = buf[(1<<13)*nBitmap:]
  329. runsArena := byteSliceAsInterval16Slice(buf[:4*nRunEl])
  330. buf = buf[4*nRunEl:]
  331. arraysArena := byteSliceAsUint16Slice(buf[:2*nArrayEl])
  332. buf = buf[2*nArrayEl:]
  333. if len(buf) != 0 {
  334. return FrozenBitmapUnexpectedData
  335. }
  336. var c container
  337. containersSz := int(unsafe.Sizeof(c))*nCont
  338. bitsetsSz := int(unsafe.Sizeof(bitmapContainer{}))*nBitmap
  339. arraysSz := int(unsafe.Sizeof(arrayContainer{}))*nArray
  340. runsSz := int(unsafe.Sizeof(runContainer16{}))*nRun
  341. needCOWSz := int(unsafe.Sizeof(true))*nCont
  342. bitmapArenaSz := containersSz + bitsetsSz + arraysSz + runsSz + needCOWSz
  343. bitmapArena := make([]byte, bitmapArenaSz)
  344. containers := byteSliceAsContainerSlice(bitmapArena[:containersSz])
  345. bitmapArena = bitmapArena[containersSz:]
  346. bitsets := byteSliceAsBitsetSlice(bitmapArena[:bitsetsSz])
  347. bitmapArena = bitmapArena[bitsetsSz:]
  348. arrays := byteSliceAsArraySlice(bitmapArena[:arraysSz])
  349. bitmapArena = bitmapArena[arraysSz:]
  350. runs := byteSliceAsRun16Slice(bitmapArena[:runsSz])
  351. bitmapArena = bitmapArena[runsSz:]
  352. needCOW := byteSliceAsBoolSlice(bitmapArena)
  353. iBitset, iArray, iRun := 0, 0, 0
  354. for i, t := range types {
  355. needCOW[i] = true
  356. switch t {
  357. case 1:
  358. containers[i] = &bitsets[iBitset]
  359. bitsets[iBitset].cardinality = int(counts[i]) + 1
  360. bitsets[iBitset].bitmap = bitsetsArena[:1024]
  361. bitsetsArena = bitsetsArena[1024:]
  362. iBitset++
  363. case 2:
  364. containers[i] = &arrays[iArray]
  365. sz := int(counts[i]) + 1
  366. arrays[iArray].content = arraysArena[:sz]
  367. arraysArena = arraysArena[sz:]
  368. iArray++
  369. case 3:
  370. containers[i] = &runs[iRun]
  371. runs[iRun].iv = runsArena[:counts[i]]
  372. runsArena = runsArena[counts[i]:]
  373. iRun++
  374. }
  375. }
  376. // Not consuming the full input is a bug.
  377. if iBitset != nBitmap || len(bitsetsArena) != 0 ||
  378. iArray != nArray || len(arraysArena) != 0 ||
  379. iRun != nRun || len(runsArena) != 0 {
  380. panic("we missed something")
  381. }
  382. ra.keys = keys
  383. ra.containers = containers
  384. ra.needCopyOnWrite = needCOW
  385. ra.copyOnWrite = true
  386. return nil
  387. }
  388. func (bm *Bitmap) GetFrozenSizeInBytes() uint64 {
  389. nBits, nArrayEl, nRunEl := uint64(0), uint64(0), uint64(0)
  390. for _, c := range bm.highlowcontainer.containers {
  391. switch v := c.(type) {
  392. case *bitmapContainer:
  393. nBits++
  394. case *arrayContainer:
  395. nArrayEl += uint64(len(v.content))
  396. case *runContainer16:
  397. nRunEl += uint64(len(v.iv))
  398. }
  399. }
  400. return 4 + 5*uint64(len(bm.highlowcontainer.containers)) +
  401. (nBits << 13) + 2*nArrayEl + 4*nRunEl
  402. }
  403. func (bm *Bitmap) Freeze() ([]byte, error) {
  404. sz := bm.GetFrozenSizeInBytes()
  405. buf := make([]byte, sz)
  406. _, err := bm.FreezeTo(buf)
  407. return buf, err
  408. }
  409. func (bm *Bitmap) FreezeTo(buf []byte) (int, error) {
  410. containers := bm.highlowcontainer.containers
  411. nCont := len(containers)
  412. nBits, nArrayEl, nRunEl := 0, 0, 0
  413. for _, c := range containers {
  414. switch v := c.(type) {
  415. case *bitmapContainer:
  416. nBits++
  417. case *arrayContainer:
  418. nArrayEl += len(v.content)
  419. case *runContainer16:
  420. nRunEl += len(v.iv)
  421. }
  422. }
  423. serialSize := 4 + 5*nCont + (1<<13)*nBits + 4*nRunEl + 2*nArrayEl
  424. if len(buf) < serialSize {
  425. return 0, FrozenBitmapBufferTooSmall
  426. }
  427. bitsArena := byteSliceAsUint64Slice(buf[:(1<<13)*nBits])
  428. buf = buf[(1<<13)*nBits:]
  429. runsArena := byteSliceAsInterval16Slice(buf[:4*nRunEl])
  430. buf = buf[4*nRunEl:]
  431. arraysArena := byteSliceAsUint16Slice(buf[:2*nArrayEl])
  432. buf = buf[2*nArrayEl:]
  433. keys := byteSliceAsUint16Slice(buf[:2*nCont])
  434. buf = buf[2*nCont:]
  435. counts := byteSliceAsUint16Slice(buf[:2*nCont])
  436. buf = buf[2*nCont:]
  437. types := buf[:nCont]
  438. buf = buf[nCont:]
  439. header := uint32(FROZEN_COOKIE | (nCont << 15))
  440. binary.LittleEndian.PutUint32(buf[:4], header)
  441. copy(keys, bm.highlowcontainer.keys[:])
  442. for i, c := range containers {
  443. switch v := c.(type) {
  444. case *bitmapContainer:
  445. copy(bitsArena, v.bitmap)
  446. bitsArena = bitsArena[1024:]
  447. counts[i] = uint16(v.cardinality - 1)
  448. types[i] = 1
  449. case *arrayContainer:
  450. copy(arraysArena, v.content)
  451. arraysArena = arraysArena[len(v.content):]
  452. elems := len(v.content)
  453. counts[i] = uint16(elems - 1)
  454. types[i] = 2
  455. case *runContainer16:
  456. copy(runsArena, v.iv)
  457. runs := len(v.iv)
  458. runsArena = runsArena[runs:]
  459. counts[i] = uint16(runs)
  460. types[i] = 3
  461. }
  462. }
  463. return serialSize, nil
  464. }
  465. func (bm *Bitmap) WriteFrozenTo(wr io.Writer) (int, error) {
  466. // FIXME: this is a naive version that iterates 4 times through the
  467. // containers and allocates 3*len(containers) bytes; it's quite likely
  468. // it can be done more efficiently.
  469. containers := bm.highlowcontainer.containers
  470. written := 0
  471. for _, c := range containers {
  472. c, ok := c.(*bitmapContainer)
  473. if !ok {
  474. continue
  475. }
  476. n, err := wr.Write(uint64SliceAsByteSlice(c.bitmap))
  477. written += n
  478. if err != nil {
  479. return written, err
  480. }
  481. }
  482. for _, c := range containers {
  483. c, ok := c.(*runContainer16)
  484. if !ok {
  485. continue
  486. }
  487. n, err := wr.Write(interval16SliceAsByteSlice(c.iv))
  488. written += n
  489. if err != nil {
  490. return written, err
  491. }
  492. }
  493. for _, c := range containers {
  494. c, ok := c.(*arrayContainer)
  495. if !ok {
  496. continue
  497. }
  498. n, err := wr.Write(uint16SliceAsByteSlice(c.content))
  499. written += n
  500. if err != nil {
  501. return written, err
  502. }
  503. }
  504. n, err := wr.Write(uint16SliceAsByteSlice(bm.highlowcontainer.keys))
  505. written += n
  506. if err != nil {
  507. return written, err
  508. }
  509. countTypeBuf := make([]byte, 3*len(containers))
  510. counts := byteSliceAsUint16Slice(countTypeBuf[:2*len(containers)])
  511. types := countTypeBuf[2*len(containers):]
  512. for i, c := range containers {
  513. switch c := c.(type) {
  514. case *bitmapContainer:
  515. counts[i] = uint16(c.cardinality - 1)
  516. types[i] = 1
  517. case *arrayContainer:
  518. elems := len(c.content)
  519. counts[i] = uint16(elems - 1)
  520. types[i] = 2
  521. case *runContainer16:
  522. runs := len(c.iv)
  523. counts[i] = uint16(runs)
  524. types[i] = 3
  525. }
  526. }
  527. n, err = wr.Write(countTypeBuf)
  528. written += n
  529. if err != nil {
  530. return written, err
  531. }
  532. header := uint32(FROZEN_COOKIE | (len(containers) << 15))
  533. if err := binary.Write(wr, binary.LittleEndian, header); err != nil {
  534. return written, err
  535. }
  536. written += 4
  537. return written, nil
  538. }