github.com/df-mc/dragonfly@v0.9.13/server/world/chunk/palette.go (about)

     1  package chunk
     2  
     3  import (
     4  	"math"
     5  )
     6  
     7  // paletteSize is the size of a palette. It indicates the amount of bits occupied per value stored.
     8  type paletteSize byte
     9  
    10  // Palette is a palette of values that every PalettedStorage has. Storages hold 'pointers' to indices
    11  // in this palette.
    12  type Palette struct {
    13  	last      uint32
    14  	lastIndex int16
    15  	size      paletteSize
    16  
    17  	// values is a map of values. A PalettedStorage points to the index to this value.
    18  	values []uint32
    19  }
    20  
    21  // newPalette returns a new Palette with size and a slice of added values.
    22  func newPalette(size paletteSize, values []uint32) *Palette {
    23  	return &Palette{size: size, values: values, last: math.MaxUint32}
    24  }
    25  
    26  // Len returns the amount of unique values in the Palette.
    27  func (palette *Palette) Len() int {
    28  	return len(palette.values)
    29  }
    30  
    31  // Add adds a values to the Palette. It does not first check if the value was already set in the Palette.
    32  // The index at which the value was added is returned. Another bool is returned indicating if the Palette
    33  // was resized as a result of adding the value.
    34  func (palette *Palette) Add(v uint32) (index int16, resize bool) {
    35  	i := int16(len(palette.values))
    36  	palette.values = append(palette.values, v)
    37  
    38  	if palette.needsResize() {
    39  		palette.increaseSize()
    40  		return i, true
    41  	}
    42  	return i, false
    43  }
    44  
    45  // Replace calls the function passed for each value present in the Palette. The value returned by the
    46  // function replaces the value present at the index of the value passed.
    47  func (palette *Palette) Replace(f func(v uint32) uint32) {
    48  	// Reset last runtime ID as it now has a different offset.
    49  	palette.last = math.MaxUint32
    50  	for index, v := range palette.values {
    51  		palette.values[index] = f(v)
    52  	}
    53  }
    54  
    55  // Index loops through the values of the Palette and looks for the index of the given value. If the value could
    56  // not be found, -1 is returned.
    57  func (palette *Palette) Index(runtimeID uint32) int16 {
    58  	if runtimeID == palette.last {
    59  		// Fast path out.
    60  		return palette.lastIndex
    61  	}
    62  	// Slow path in a separate function allows for inlining the fast path.
    63  	return palette.indexSlow(runtimeID)
    64  }
    65  
    66  // indexSlow searches the index of a value in the Palette's values by iterating through the Palette's values.
    67  func (palette *Palette) indexSlow(runtimeID uint32) int16 {
    68  	l := len(palette.values)
    69  	for i := 0; i < l; i++ {
    70  		if palette.values[i] == runtimeID {
    71  			palette.last = runtimeID
    72  			v := int16(i)
    73  			palette.lastIndex = v
    74  			return v
    75  		}
    76  	}
    77  	return -1
    78  }
    79  
    80  // Value returns the value in the Palette at a specific index.
    81  func (palette *Palette) Value(i uint16) uint32 {
    82  	return palette.values[i]
    83  }
    84  
    85  // needsResize checks if the Palette, and with it the holding PalettedStorage, needs to be resized to a bigger
    86  // size.
    87  func (palette *Palette) needsResize() bool {
    88  	return len(palette.values) > (1 << palette.size)
    89  }
    90  
    91  var sizes = [...]paletteSize{0, 1, 2, 3, 4, 5, 6, 8, 16}
    92  var offsets = [...]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 8: 7, 16: 8}
    93  
    94  // increaseSize increases the size of the Palette to the next palette size.
    95  func (palette *Palette) increaseSize() {
    96  	palette.size = sizes[offsets[palette.size]+1]
    97  }
    98  
    99  // padded returns true if the Palette size is 3, 5 or 6.
   100  func (p paletteSize) padded() bool {
   101  	return p == 3 || p == 5 || p == 6
   102  }
   103  
   104  // paletteSizeFor finds a suitable paletteSize for the amount of values passed n.
   105  func paletteSizeFor(n int) paletteSize {
   106  	for _, size := range sizes {
   107  		if n <= (1 << size) {
   108  			return size
   109  		}
   110  	}
   111  	// Should never happen.
   112  	return 0
   113  }
   114  
   115  // uint32s returns the amount of uint32s needed to represent a storage with this palette size.
   116  func (p paletteSize) uint32s() (n int) {
   117  	uint32Count := 0
   118  	if p != 0 {
   119  		// indicesPerUint32 is the amount of indices that may be stored in a single uint32.
   120  		indicesPerUint32 := 32 / int(p)
   121  		// uint32Count is the amount of uint32s required to store all indices: 4096 indices need to be stored in
   122  		// total.
   123  		uint32Count = 4096 / indicesPerUint32
   124  	}
   125  	if p.padded() {
   126  		// We've got one of the padded sizes, so the storage has another uint32 to be able to store
   127  		// every index.
   128  		uint32Count++
   129  	}
   130  	return uint32Count
   131  }