package harfbuzz

import (
	
)

// Rune/GID set implementation, inspired by the fontconfig FcCharset type.
//
// The internal representation is a slice of `pageSet` pages, where each page is a boolean
// set of size 256, encoding the last byte of an uint32.
// Each uint32 is then mapped to a page index (`pageNumber`), defined by it second and third bytes.

// pageSet is the base storage for a compact uint32 set.
// A uint32 is first reduced to its lower byte 'b'. Then the index
// of 'b' in the page is given by the 3 high bits (from 0 to 7)
// and the position in the resulting uint32 is given by the 5 lower bits (from 0 to 31)
type pageSet [8]uint32

func ( pageSet) ( pageSet) bool {
	for ,  := range  {
		 := []
		// Does b have any bits not in a?
		if  & ^ != 0 {
			return false
		}
	}
	return true
}

func ( pageSet) ( pageSet) bool {
	for ,  := range  {
		 := []
		// Does a and b have any bits in common ?
		if & != 0 {
			return true
		}
	}
	return false
}

// assume start <= end
func ( *pageSet) (,  byte) {
	// indexes in [0; 8[
	 :=  >> 5
	 :=  >> 5

	// bit index, in [0; 32[
	 := ( & 0x1f)
	 := ( & 0x1f)

	// handle the start uint
	 := byte(31)
	if  ==  {
		 = 
	}
	 := &[]
	 := (uint32(1)<<(-+1) - 1) <<  // mask for bits from a to b (included)
	* |= 

	// handle the end uint, when required
	if  !=  {
		// fill uint between with ones
		for  :=  + 1;  < ; ++ {
			[] = 0xFFFFFFFF
		}

		// handle the last
		 := &[]
		 := (uint32(1)<<(+1) - 1) // mask for bits from a to b (included)
		* |= 
	}
}

// pageRef stores the second and third bytes of a rune (uint16(r >> 8)),
// shared by all the runes in a page.
type pageRef = uint16

type intPage struct {
	ref pageRef
	set pageSet
}

// intSet is an efficient implementation of a rune set (that is a map[rune]bool),
// used to store the Unicode points (typically supported by a font), and optimized to deal with consecutive
// runes.
type intSet []intPage

// findPageFrom is the same as findPagePos, but
// start the binary search with the given `low` index
func ( intSet) ( int,  pageRef) int {
	 := len() - 1
	for  <=  {
		 := ( + ) >> 1
		 := [].ref
		if  ==  {
			return  // found the page
		}
		if  <  {
			 =  + 1
		} else {
			 =  - 1
		}
	}
	if  < 0 || ( < len() && [].ref < ) {
		++
	}
	return -( + 1) // the page is not in the set, but should be inserted at high
}

// findPagePos searches for the leaf containing the specified number.
// It returns its index if it exists, otherwise it returns the negative of
// the (`position` + 1) where `position` is the index where it should be inserted
func ( intSet) ( pageRef) int { return .findPageFrom(0, ) }

// findPage returns the page containing the specified char, or nil
// if it doesn't exists
func ( intSet) ( pageRef) *pageSet {
	 := .findPagePos()
	if  >= 0 {
		return &[].set
	}
	return nil
}

// findOrCreatePage locates the page containing the specified char, creating it if needed,
// and returns a pointer to it
func ( *intSet) ( pageRef) *pageSet {
	 := .findPagePos()
	if  < 0 { // the page doest not exists, create it
		 = - - 1
		.insertPage(intPage{ref: }, )
	}

	return &(*)[].set
}

// insertPage inserts the given `page` at `pos`, meaning the resulting page can be accessed via &rs[pos]
func ( *intSet) ( intPage,  int) {
	// insert in slice
	* = append(*, intPage{})
	copy((*)[+1:], (*)[:])
	(*)[] = 
}

// add adds `r` to the rune set.
func ( *intSet) ( uint32) {
	 := .findOrCreatePage(uint16( >> 8))
	 := &[(&0xff)>>5] // (r&0xff)>>5 is the index in the page
	* |= (1 << ( & 0x1f)) // r & 0x1f is the bit in the uint32
}

// delete removes the rune from the rune set.
func ( intSet) ( uint32) {
	 := .findPage(uint16( >> 8))
	if  == nil {
		return
	}
	 := &[(&0xff)>>5]  // (r&0xff)>>5 is the index in the page
	* &= ^(1 << ( & 0x1f)) // r & 0x1f is the bit in the uint32
	// we don't bother removing the leaf if it's empty
}

// has returns `true` if `r` is in the set.
func ( intSet) ( uint32) bool {
	 := .findPage(uint16( >> 8))
	if  == nil {
		return false
	}
	return [(&0xff)>>5]&(1<<(&0x1f)) != 0
}

// Clear remove all values but keep the underlying storage
func ( *intSet) () { * = (*)[:0] }

// Includes return true iff a includes b, that is if b is a subset of a, that is if all runes
// of b are in a
func ( intSet) ( intSet) bool {
	,  := 0, 0 // index in b and a
	for  < len() &&  < len() {
		,  := [], []
		// Check matching pages
		if .ref == .ref {
			if  := .set.includes(.set); ! {
				return false
			}
			++
			++
		} else if .ref < .ref { // Does b have any pages not in a?
			return false
		} else {
			// increment ai to match the page of b
			 = .findPageFrom(+1, .ref)
			if  < 0 { // the page is not even in a
				return false
			}
		}
	}
	//  did we look at every page?
	return  >= len()
}

// Len returns the number of runes in the set.
func ( intSet) () int {
	 := 0
	for ,  := range  {
		for ,  := range .set {
			 += bits.OnesCount32()
		}
	}
	return 
}

// Intersects returns if [a] and [b] have at least
// one rune in common
func ( intSet) ( intSet) bool {
	,  := 0, 0 // index in b and a
	for  < len() &&  < len() {
		,  := [], []
		// Check matching pages
		if .ref == .ref {
			if .set.intersects(.set) {
				return true
			}
			++
			++
		} else if .ref < .ref {
			// increment bi
			++
		} else {
			// increment ai
			++
		}
	}
	return false
}

// assume a <= b; inclusive
func ( *intSet) (,  uint32) {
	,  := uint16(>>8), uint16(>>8)

	// handle the starting page
	,  := byte(&0xff), byte(&0xff)
	 := byte(0xFF)
	if  ==  {
		 = 
	}

	 := .findOrCreatePage()
	.addRange(, )

	// handle the next
	if  !=  { // this means pageStart < pageEnd
		// fill the strictly intermediate pages with ones
		for  :=  + 1;  < ; ++ {
			 := .findOrCreatePage()
			* = pageSet{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
		}

		// hande the last
		 := .findOrCreatePage()
		.addRange(0, )
	}
}

// ints is an helper method returning a copy of the runes in the set.
func ( intSet) () ( []uint32) {
	for ,  := range  {
		 := uint32(.ref) << 8
		for ,  := range .set {
			for  := uint32(0);  < 32; ++ {
				if &uint32(1<<) != 0 {
					 = append(, |uint32()<<5|)
				}
			}
		}
	}
	return 
}

// typed API

func ( intSet) ( GID) bool { return .has(uint32()) }
func ( *intSet) ( GID)     { .add(uint32()) }
func ( *intSet) ( []GID) {
	for ,  := range  {
		.add(uint32())
	}
}