packedlist.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. * Public Domain Software
  3. *
  4. * I (Matthias Ladkau) am the author of the source code in this file.
  5. * I have placed the source code in this file in the public domain.
  6. *
  7. * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
  8. */
  9. package bitutil
  10. import (
  11. "bytes"
  12. "encoding/binary"
  13. "math"
  14. )
  15. /*
  16. Different types of list packing
  17. */
  18. const (
  19. packListType2Bit = 0x1
  20. packListType3Bit = 0x2
  21. packListType6Bit = 0x3
  22. packListTypeVar = 0x0
  23. )
  24. /*
  25. PackList packs a given list to a string. Depending on the given highest number the
  26. list is packed in the most efficient way.
  27. */
  28. func PackList(unpackedlist []uint64, highest uint64) string {
  29. // Depending on the highest number convert to given list
  30. switch {
  31. case highest <= 3:
  32. list := make([]byte, len(unpackedlist))
  33. for i, num := range unpackedlist {
  34. list[i] = byte(num)
  35. }
  36. return PackList2Bit(list)
  37. case highest <= 7:
  38. list := make([]byte, len(unpackedlist))
  39. for i, num := range unpackedlist {
  40. list[i] = byte(num)
  41. }
  42. return PackList3Bit(list)
  43. case highest <= 63:
  44. list := make([]byte, len(unpackedlist))
  45. for i, num := range unpackedlist {
  46. list[i] = byte(num)
  47. }
  48. return PackList6Bit(list)
  49. case highest <= math.MaxUint8:
  50. list := make([]byte, len(unpackedlist))
  51. for i, num := range unpackedlist {
  52. list[i] = byte(num)
  53. }
  54. return PackList8Bit(list)
  55. case highest <= math.MaxUint16:
  56. list := make([]uint16, len(unpackedlist))
  57. for i, num := range unpackedlist {
  58. list[i] = uint16(num)
  59. }
  60. return PackList16Bit(list)
  61. case highest <= math.MaxUint32:
  62. list := make([]uint32, len(unpackedlist))
  63. for i, num := range unpackedlist {
  64. list[i] = uint32(num)
  65. }
  66. return PackList32Bit(list)
  67. }
  68. return PackList64Bit(unpackedlist)
  69. }
  70. /*
  71. UnpackList unpacks a list from a packed string.
  72. */
  73. func UnpackList(packedlist string) []uint64 {
  74. plist := []byte(packedlist)
  75. if len(plist) == 0 {
  76. return nil
  77. }
  78. if plist[0]&0xC0 == packListTypeVar {
  79. return UnpackBigList(packedlist)
  80. }
  81. res := UnpackSmallList(packedlist)
  82. ret := make([]uint64, len(res))
  83. for i, item := range res {
  84. ret[i] = uint64(item)
  85. }
  86. return ret
  87. }
  88. /*
  89. PackList8Bit packs a list of 8 bit numbers.
  90. */
  91. func PackList8Bit(list []uint8) string {
  92. var bb bytes.Buffer
  93. bb.WriteByte(0x00)
  94. for i := 0; i < len(list); i++ {
  95. binary.Write(&bb, binary.LittleEndian, list[i])
  96. }
  97. return bb.String()
  98. }
  99. /*
  100. PackList16Bit packs a list of 16 bit numbers.
  101. */
  102. func PackList16Bit(list []uint16) string {
  103. var bb bytes.Buffer
  104. bb.WriteByte(0x01)
  105. for i := 0; i < len(list); i++ {
  106. binary.Write(&bb, binary.LittleEndian, list[i])
  107. }
  108. return bb.String()
  109. }
  110. /*
  111. PackList32Bit packs a list of 32 bit numbers.
  112. */
  113. func PackList32Bit(list []uint32) string {
  114. var bb bytes.Buffer
  115. bb.WriteByte(0x02)
  116. for i := 0; i < len(list); i++ {
  117. binary.Write(&bb, binary.LittleEndian, list[i])
  118. }
  119. return bb.String()
  120. }
  121. /*
  122. PackList64Bit packs a list of 64 bit numbers.
  123. */
  124. func PackList64Bit(list []uint64) string {
  125. var bb bytes.Buffer
  126. bb.WriteByte(0x03)
  127. for i := 0; i < len(list); i++ {
  128. binary.Write(&bb, binary.LittleEndian, list[i])
  129. }
  130. return bb.String()
  131. }
  132. /*
  133. UnpackBigList unpacks a list which has large values.
  134. */
  135. func UnpackBigList(packedlist string) []uint64 {
  136. var ret []uint64
  137. plist := []byte(packedlist)
  138. numlist := plist[1:]
  139. reader := bytes.NewReader(numlist)
  140. if plist[0] == 0x00 {
  141. var item uint8
  142. size := len(numlist)
  143. ret = make([]uint64, size)
  144. for i := 0; i < size; i++ {
  145. binary.Read(reader, binary.LittleEndian, &item)
  146. ret[i] = uint64(item)
  147. }
  148. } else if plist[0] == 0x01 {
  149. var item uint16
  150. size := len(numlist) / 2
  151. ret = make([]uint64, size)
  152. for i := 0; i < size; i++ {
  153. binary.Read(reader, binary.LittleEndian, &item)
  154. ret[i] = uint64(item)
  155. }
  156. } else if plist[0] == 0x02 {
  157. var item uint32
  158. size := len(numlist) / 4
  159. ret = make([]uint64, size)
  160. for i := 0; i < size; i++ {
  161. binary.Read(reader, binary.LittleEndian, &item)
  162. ret[i] = uint64(item)
  163. }
  164. } else if plist[0] == 0x03 {
  165. size := len(numlist) / 8
  166. ret = make([]uint64, size)
  167. binary.Read(reader, binary.LittleEndian, ret)
  168. }
  169. return ret
  170. }
  171. /*
  172. PackList2Bit packs a list of bytes into a string using 2 bits for each item.
  173. (Items must be between 1 and 3)
  174. */
  175. func PackList2Bit(list []byte) string {
  176. if len(list) == 0 {
  177. return ""
  178. }
  179. // Packing the list with 2 bit items reduces the size by a factor of 4
  180. ret := make([]byte, int(math.Ceil(float64(1)/3+float64(len(list)-1)/4)))
  181. if len(list) == 1 {
  182. ret[0] = list2byte2bit(packListType2Bit, list[0], 0, 0)
  183. } else if len(list) == 2 {
  184. ret[0] = list2byte2bit(packListType2Bit, list[0], list[1], 0)
  185. } else {
  186. ret[0] = list2byte2bit(packListType2Bit, list[0], list[1], list[2])
  187. j := 1
  188. for i := 3; i < len(list); i += 4 {
  189. if len(list[i:]) == 1 {
  190. ret[j] = list2byte2bit(list[i], 0, 0, 0)
  191. } else if len(list[i:]) == 2 {
  192. ret[j] = list2byte2bit(list[i], list[i+1], 0, 0)
  193. } else if len(list[i:]) == 3 {
  194. ret[j] = list2byte2bit(list[i], list[i+1], list[i+2], 0)
  195. } else {
  196. ret[j] = list2byte2bit(list[i], list[i+1], list[i+2], list[i+3])
  197. }
  198. j++
  199. }
  200. }
  201. return string(ret)
  202. }
  203. /*
  204. PackList3Bit packs a list of bytes into a string using 3 bits for each item.
  205. (Items must be between 1 and 7)
  206. */
  207. func PackList3Bit(list []byte) string {
  208. if len(list) == 0 {
  209. return ""
  210. }
  211. // Packing the list with 2 bit items reduces the size by a factor of 2
  212. ret := make([]byte, int(math.Ceil(float64(len(list))/2)))
  213. if len(list) == 1 {
  214. ret[0] = list2byte3bitAndHeader(packListType3Bit, list[0], 0)
  215. } else {
  216. ret[0] = list2byte3bitAndHeader(packListType3Bit, list[0], list[1])
  217. j := 1
  218. for i := 2; i < len(list); i += 2 {
  219. if len(list[i:]) == 1 {
  220. ret[j] = list2byte3bitAndHeader(0, list[i], 0)
  221. } else {
  222. ret[j] = list2byte3bitAndHeader(0, list[i], list[i+1])
  223. }
  224. j++
  225. }
  226. }
  227. return string(ret)
  228. }
  229. /*
  230. PackList6Bit packs a list of bytes into a string using 6 bits for each item.
  231. (Items must be between 1 and 63)
  232. */
  233. func PackList6Bit(list []byte) string {
  234. if len(list) == 0 {
  235. return ""
  236. }
  237. // Packing the list with 6 bit items does not reduce the factor
  238. ret := make([]byte, len(list))
  239. if len(list) == 1 {
  240. ret[0] = list2byte6bitAndHeader(packListType6Bit, list[0])
  241. } else {
  242. ret[0] = list2byte6bitAndHeader(packListType6Bit, list[0])
  243. for i := 1; i < len(list); i++ {
  244. ret[i] = list2byte6bitAndHeader(0, list[i])
  245. }
  246. }
  247. return string(ret)
  248. }
  249. /*
  250. UnpackSmallList unpacks a string into a list of bytes. Returns the list of bytes
  251. or a list of a single 0x00 byte if the numbers in the list are too big.
  252. */
  253. func UnpackSmallList(packedlist string) []byte {
  254. plist := []byte(packedlist)
  255. if len(plist) == 0 {
  256. return []byte{}
  257. }
  258. ltype := plist[0] & 0xC0 >> 6
  259. if ltype == packListType2Bit {
  260. return unpacklist2bit(plist)
  261. } else if ltype == packListType3Bit {
  262. return unpacklist3bit(plist)
  263. } else if ltype == packListType6Bit {
  264. return unpacklist6bit(plist)
  265. }
  266. // Must be gob encoded
  267. return []byte{00}
  268. }
  269. func unpacklist2bit(packedlist []byte) []byte {
  270. ret := make([]byte, 0, len(packedlist)*3)
  271. for i := 0; i < len(packedlist); i++ {
  272. b1, b2, b3, b4 := byte2list2bit(packedlist[i])
  273. if i > 0 && b1 != 0 {
  274. ret = append(ret, b1)
  275. }
  276. if b2 != 0 {
  277. ret = append(ret, b2)
  278. }
  279. if b3 != 0 {
  280. ret = append(ret, b3)
  281. }
  282. if b4 != 0 {
  283. ret = append(ret, b4)
  284. }
  285. }
  286. return ret
  287. }
  288. func unpacklist3bit(packedlist []byte) []byte {
  289. ret := make([]byte, 0, len(packedlist)*2)
  290. for i := 0; i < len(packedlist); i++ {
  291. b1, b2 := byte2list3bit(packedlist[i])
  292. if b1 != 0 {
  293. ret = append(ret, b1)
  294. }
  295. if b2 != 0 {
  296. ret = append(ret, b2)
  297. }
  298. }
  299. return ret
  300. }
  301. func unpacklist6bit(packedlist []byte) []byte {
  302. ret := make([]byte, 0, len(packedlist))
  303. for i := 0; i < len(packedlist); i++ {
  304. ret = append(ret, byte2list6bit(packedlist[i]))
  305. }
  306. return ret
  307. }
  308. func byte2list2bit(b byte) (b1 byte, b2 byte, b3 byte, b4 byte) {
  309. b1 = b & 0xC0 >> 6
  310. b2 = b & 0x30 >> 4
  311. b3 = b & 0x0C >> 2
  312. b4 = b & 0x03
  313. return b1, b2, b3, b4
  314. }
  315. func list2byte2bit(b1 byte, b2 byte, b3 byte, b4 byte) byte {
  316. return (b1 & 0x03 << 6) |
  317. (b2 & 0x03 << 4) |
  318. (b3 & 0x03 << 2) |
  319. (b4 & 0x03)
  320. }
  321. func list2byte3bitAndHeader(b1 byte, b2 byte, b3 byte) byte {
  322. return (b1 & 0x03 << 6) |
  323. (b2 & 0x07 << 3) |
  324. (b3 & 0x07)
  325. }
  326. func byte2list3bit(b byte) (b2 byte, b3 byte) {
  327. b2 = b & 0x38 >> 3
  328. b3 = b & 0x07
  329. return b2, b3
  330. }
  331. func list2byte6bitAndHeader(b1 byte, b2 byte) byte {
  332. return (b1 & 0x03 << 6) |
  333. (b2 & 0x3F)
  334. }
  335. func byte2list6bit(b byte) byte {
  336. return b & 0x3F
  337. }