| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 | /* * EliasDB * * Copyright 2016 Matthias Ladkau. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */package utilimport (	"fmt"	"devt.de/krotik/eliasdb/storage/file")/*OffsetCurrentSize is the offset for the size on a slotsize header.*/const OffsetCurrentSize = 0/*OffetAvailableSize is the offset for the available size on a slotsize header.*/const OffetAvailableSize = file.SizeUnsignedShort/*UnsignedShortMax is the maximum value of an unsigned short as used for slotsizes.*/const UnsignedShortMax = 0xFFFF/*MaxAvailableSizeDifference represents the maximal size of the differencebetween available size and current size*/const MaxAvailableSizeDifference = UnsignedShortMax - 1/*SizeInfoSize represents the size of the size info*/const SizeInfoSize = OffetAvailableSize + file.SizeUnsignedShort/*CurrentSize returns the current size of a slot.*/func CurrentSize(record *file.Record, offset int) uint32 {	currentSize := record.ReadUInt16(offset + OffsetCurrentSize)	if currentSize == UnsignedShortMax {		return 0	}	return AvailableSize(record, offset) - uint32(currentSize)}/*SetCurrentSize sets the current size of a slot.*/func SetCurrentSize(record *file.Record, offset int, value uint32) {	if value == 0 {		record.WriteUInt16(offset+OffsetCurrentSize, UnsignedShortMax)		return	}	size := AvailableSize(record, offset)	if (size > MaxAvailableSizeDifference &&		value < size-MaxAvailableSizeDifference) ||		value > size {		panic(fmt.Sprint("Cannot store current size as difference "+			"to available size. Value:", value, " Available size:", size))	}	record.WriteUInt16(offset+OffsetCurrentSize, uint16(size-value))}/*AvailableSize returns the available size of a slot.*/func AvailableSize(record *file.Record, offset int) uint32 {	value := record.ReadUInt16(offset + OffetAvailableSize)	return decodeSize(value)}/*SetAvailableSize sets the available size of a slot.*/func SetAvailableSize(record *file.Record, offset int, value uint32) {	currentSize := CurrentSize(record, offset)	size := encodeSize(value)	// Safeguard against not using normalized size values	if decodeSize(size) != value {		panic("Size value was not normalized")	}	record.WriteUInt16(offset+OffetAvailableSize, size)	// Current size needs to be updated since it depends on the available size	SetCurrentSize(record, offset, currentSize)}/*NormalizeSlotSize normalizes a given slot size.*/func NormalizeSlotSize(value uint32) uint32 {	return decodeSize(encodeSize(value))}const sizeMask = 1<<15 | 1<<14const multi0 = 1const multi1 = 1 << 4const multi2 = 1 << 8const multi3 = 1 << 13const base0 = 0const base1 = base0 + multi0*((1<<14)-2)const base2 = base1 + multi1*((1<<14)-2)const base3 = base2 + multi2*((1<<14)-2)/*decodeSize decodes a given size value.*/func decodeSize(packedSize uint16) uint32 {	size := packedSize & sizeMask	multiplier := size >> 14	counter := uint32(packedSize - size)	switch multiplier {	case 0:		return counter * multi0	case 1:		return base1 + counter*multi1	case 2:		return base2 + counter*multi2	default:		return base3 + counter*multi3	}}/*encodeSize encodes a given size value.*/func encodeSize(size uint32) uint16 {	var multiplier, counter, v uint32	switch {	case size <= base1:		multiplier = 0		counter = size / multi0	case size < base2:		multiplier = 1 << 14		v = size - base1		counter = v / multi1		if v%multi1 != 0 {			counter++		}	case size < base3:		multiplier = 2 << 14		v = size - base2		counter = v / multi2		if v%multi2 != 0 {			counter++		}	default:		multiplier = 3 << 14		v = size - base3		counter = v / multi3		if v%multi3 != 0 {			counter++		}	}	if counter >= (1 << 14) {		panic(fmt.Sprint("Cannot pack slot size:", size))	}	return uint16(multiplier + counter)}
 |