You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

202 lines
5.0 KiB

//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//
package velocypack
import (
"fmt"
"io"
)
// vpackAssert panics if v is false.
func vpackAssert(v bool) {
if !v {
panic("VELOCYPACK_ASSERT failed")
}
}
// readBytes reads bytes from the given reader until the given slice is full.
func readBytes(dst []byte, r io.Reader) error {
offset := 0
l := len(dst)
for {
n, err := r.Read(dst[offset:])
offset += n
l -= n
if l == 0 {
// We're done
return nil
}
if err != nil {
return WithStack(err)
}
}
}
// read an unsigned little endian integer value of the
// specified length, starting at the specified byte offset
func readIntegerFixed(start []byte, length uint) uint64 {
return readIntegerNonEmpty(start, length)
}
// read an unsigned little endian integer value of the
// specified length, starting at the specified byte offset
func readIntegerFixedFromReader(r io.Reader, length uint) (uint64, []byte, error) {
buf := make([]byte, length)
if err := readBytes(buf, r); err != nil {
return 0, nil, WithStack(err)
}
return readIntegerFixed(buf, length), buf, nil
}
// read an unsigned little endian integer value of the
// specified length, starting at the specified byte offset
func readIntegerNonEmpty(s []byte, length uint) uint64 {
x := uint(0)
v := uint64(0)
for i := uint(0); i < length; i++ {
v += uint64(s[i]) << x
x += 8
}
return v
}
// read an unsigned little endian integer value of the
// specified length, starting at the specified byte offset
func readIntegerNonEmptyFromReader(r io.Reader, length uint) (uint64, []byte, error) {
buf := make([]byte, length)
if err := readBytes(buf, r); err != nil {
return 0, nil, WithStack(err)
}
return readIntegerNonEmpty(buf, length), buf, nil
}
func toInt64(v uint64) int64 {
shift2 := uint64(1) << 63
shift := int64(shift2 - 1)
if v >= shift2 {
return (int64(v-shift2) - shift) - 1
} else {
return int64(v)
}
}
func toUInt64(v int64) uint64 {
// If v is negative, we need to add 2^63 to make it positive,
// before we can cast it to an uint64_t:
if v >= 0 {
return uint64(v)
}
shift2 := uint64(1) << 63
shift := int64(shift2 - 1)
return uint64((v+shift)+1) + shift2
// return v >= 0 ? static_cast<uint64_t>(v)
// : static_cast<uint64_t>((v + shift) + 1) + shift2;
// Note that g++ and clang++ with -O3 compile this away to
// nothing. Further note that a plain cast from int64_t to
// uint64_t is not guaranteed to work for negative values!
}
// read a variable length integer in unsigned LEB128 format
func readVariableValueLength(source []byte, offset ValueLength, reverse bool) ValueLength {
length := ValueLength(0)
p := uint(0)
for {
v := ValueLength(source[offset])
length += (v & 0x7f) << p
p += 7
if reverse {
offset--
} else {
offset++
}
if v&0x80 == 0 {
break
}
}
return length
}
// read a variable length integer in unsigned LEB128 format
func readVariableValueLengthFromReader(r io.Reader, reverse bool) (ValueLength, []byte, error) {
if reverse {
return 0, nil, WithStack(fmt.Errorf("reverse is not supported"))
}
length := ValueLength(0)
p := uint(0)
buf := make([]byte, 1)
bytes := make([]byte, 0, 8)
for {
if n, err := r.Read(buf); n != 1 {
if err != nil {
return 0, nil, WithStack(err)
} else {
return 0, nil, WithStack(fmt.Errorf("failed to read 1 byte"))
}
}
bytes = append(bytes, buf[0])
v := ValueLength(buf[0])
length += (v & 0x7f) << p
p += 7
if v&0x80 == 0 {
break
}
}
return length, bytes, nil
}
// store a variable length integer in unsigned LEB128 format
func storeVariableValueLength(dst []byte, offset, value ValueLength, reverse bool) {
vpackAssert(value > 0)
idx := offset
if reverse {
for value >= 0x80 {
dst[idx] = byte(value | 0x80)
idx--
value >>= 7
}
dst[idx] = byte(value & 0x7f)
} else {
for value >= 0x80 {
dst[idx] = byte(value | 0x80)
idx++
value >>= 7
}
dst[idx] = byte(value & 0x7f)
}
}
// optionalBool returns the first arg element if available, otherwise returns defaultValue.
func optionalBool(arg []bool, defaultValue bool) bool {
if len(arg) == 0 {
return defaultValue
}
return arg[0]
}
// alignAt returns the first number >= value that is aligned at the given alignment.
// alignment must be a power of 2.
func alignAt(value, alignment uint) uint {
mask := ^(alignment - 1)
return (value + alignment - 1) & mask
}