github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/common/bitutil/compress.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2017 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package bitutil
    26  
    27  import "errors"
    28  
    29  var (
    30  //如果引用的字节
    31  //
    32  	errMissingData = errors.New("missing bytes on input")
    33  
    34  //如果没有使用所有字节,则从解压返回errunreferenceddata。
    35  //在对输入数据进行解压缩之后。
    36  	errUnreferencedData = errors.New("extra bytes on input")
    37  
    38  //如果位集头具有
    39  //定义的比特数多于可用的目标缓冲区空间数。
    40  	errExceededTarget = errors.New("target data size exceeded")
    41  
    42  //如果中引用了数据字节,则从解压缩返回errZeroContent。
    43  //位集头实际上是一个零字节。
    44  	errZeroContent = errors.New("zero byte in input content")
    45  )
    46  
    47  //由compressBytes和compressBytes实现的压缩算法是
    48  //针对包含大量零字节的稀疏输入数据进行了优化。减压
    49  //需要解压数据长度的知识。
    50  //
    51  //压缩工程如下:
    52  //
    53  //如果数据只包含零,
    54  //compressbytes(data)==nil
    55  //否则,如果len(data)<=1,
    56  //compressBytes(data)==数据
    57  //否则:
    58  //compressbytes(data)==附加(compressbytes(nonzerobitset(data)),nonzerobytes(data)…)
    59  //哪里
    60  //非零位集(data)是一个带有len(data)位(msb first)的位向量:
    61  //非零位集(数据)[I/8]&&(1<(7-I%8))!=0,如果数据[i]!= 0
    62  //len(非零位集(数据))==(len(数据)+7)/8
    63  //非零字节(数据)包含相同顺序的非零字节数据
    64  
    65  //compressBytes根据稀疏位集压缩输入字节片
    66  //表示算法。如果结果大于原始输入,则不
    67  //
    68  func CompressBytes(data []byte) []byte {
    69  	if out := bitsetEncodeBytes(data); len(out) < len(data) {
    70  		return out
    71  	}
    72  	cpy := make([]byte, len(data))
    73  	copy(cpy, data)
    74  	return cpy
    75  }
    76  
    77  //bitsetEncodeBytes根据稀疏数据压缩输入字节片
    78  //
    79  func bitsetEncodeBytes(data []byte) []byte {
    80  //空切片压缩为零
    81  	if len(data) == 0 {
    82  		return nil
    83  	}
    84  //单字节片压缩为零或保留单字节
    85  	if len(data) == 1 {
    86  		if data[0] == 0 {
    87  			return nil
    88  		}
    89  		return data
    90  	}
    91  //计算集合字节的位集,并收集非零字节
    92  	nonZeroBitset := make([]byte, (len(data)+7)/8)
    93  	nonZeroBytes := make([]byte, 0, len(data))
    94  
    95  	for i, b := range data {
    96  		if b != 0 {
    97  			nonZeroBytes = append(nonZeroBytes, b)
    98  			nonZeroBitset[i/8] |= 1 << byte(7-i%8)
    99  		}
   100  	}
   101  	if len(nonZeroBytes) == 0 {
   102  		return nil
   103  	}
   104  	return append(bitsetEncodeBytes(nonZeroBitset), nonZeroBytes...)
   105  }
   106  
   107  //解压缩字节用已知的目标大小解压缩数据。如果输入数据
   108  //匹配目标的大小,这意味着在第一个压缩过程中没有进行压缩
   109  //地点。
   110  func DecompressBytes(data []byte, target int) ([]byte, error) {
   111  	if len(data) > target {
   112  		return nil, errExceededTarget
   113  	}
   114  	if len(data) == target {
   115  		cpy := make([]byte, len(data))
   116  		copy(cpy, data)
   117  		return cpy, nil
   118  	}
   119  	return bitsetDecodeBytes(data, target)
   120  }
   121  
   122  //bitsetdecodebytes用已知的目标大小解压缩数据。
   123  func bitsetDecodeBytes(data []byte, target int) ([]byte, error) {
   124  	out, size, err := bitsetDecodePartialBytes(data, target)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	if size != len(data) {
   129  		return nil, errUnreferencedData
   130  	}
   131  	return out, nil
   132  }
   133  
   134  //BitsetDecodePartialBytes以已知的目标大小解压缩数据,但确实如此
   135  //不强制使用所有输入字节。除了减压
   136  //输出,函数返回相应的压缩输入数据的长度
   137  //因为输入片可能更长。
   138  func bitsetDecodePartialBytes(data []byte, target int) ([]byte, int, error) {
   139  //健全性检查0个目标以避免无限递归
   140  	if target == 0 {
   141  		return nil, 0, nil
   142  	}
   143  //处理零和单字节角情况
   144  	decomp := make([]byte, target)
   145  	if len(data) == 0 {
   146  		return decomp, 0, nil
   147  	}
   148  	if target == 1 {
   149  decomp[0] = data[0] //复制以避免引用输入切片
   150  		if data[0] != 0 {
   151  			return decomp, 1, nil
   152  		}
   153  		return decomp, 0, nil
   154  	}
   155  //解压集合字节的位集并分配非零字节
   156  	nonZeroBitset, ptr, err := bitsetDecodePartialBytes(data, (target+7)/8)
   157  	if err != nil {
   158  		return nil, ptr, err
   159  	}
   160  	for i := 0; i < 8*len(nonZeroBitset); i++ {
   161  		if nonZeroBitset[i/8]&(1<<byte(7-i%8)) != 0 {
   162  //确保我们有足够的数据插入正确的插槽
   163  			if ptr >= len(data) {
   164  				return nil, 0, errMissingData
   165  			}
   166  			if i >= len(decomp) {
   167  				return nil, 0, errExceededTarget
   168  			}
   169  //确保数据有效并推入插槽
   170  			if data[ptr] == 0 {
   171  				return nil, 0, errZeroContent
   172  			}
   173  			decomp[i] = data[ptr]
   174  			ptr++
   175  		}
   176  	}
   177  	return decomp, ptr, nil
   178  }