package bbolt

import 

// hashmapFreeCount returns count of free pages(hashmap version)
func ( *freelist) () int {
	// use the forwardMap to get the total count
	 := 0
	for ,  := range .forwardMap {
		 += int()
	}
	return 
}

// hashmapAllocate serves the same purpose as arrayAllocate, but use hashmap as backend
func ( *freelist) ( txid,  int) pgid {
	if  == 0 {
		return 0
	}

	// if we have a exact size match just return short path
	if ,  := .freemaps[uint64()];  {
		for  := range  {
			// remove the span
			.delSpan(, uint64())

			.allocs[] = 

			for  := pgid(0);  < pgid(); ++ {
				delete(.cache, +)
			}
			return 
		}
	}

	// lookup the map to find larger span
	for ,  := range .freemaps {
		if  < uint64() {
			continue
		}

		for  := range  {
			// remove the initial
			.delSpan(, )

			.allocs[] = 

			 :=  - uint64()

			// add remain span
			.addSpan(+pgid(), )

			for  := pgid(0);  < pgid(); ++ {
				delete(.cache, +)
			}
			return 
		}
	}

	return 0
}

// hashmapReadIDs reads pgids as input an initial the freelist(hashmap version)
func ( *freelist) ( []pgid) {
	.init()

	// Rebuild the page cache.
	.reindex()
}

// hashmapGetFreePageIDs returns the sorted free page ids
func ( *freelist) () []pgid {
	 := .free_count()
	if  == 0 {
		return nil
	}

	 := make([]pgid, 0, )
	for ,  := range .forwardMap {
		for  := 0;  < int(); ++ {
			 = append(, +pgid())
		}
	}
	sort.Sort(pgids())

	return 
}

// hashmapMergeSpans try to merge list of pages(represented by pgids) with existing spans
func ( *freelist) ( pgids) {
	for ,  := range  {
		// try to see if we can merge and update
		.mergeWithExistingSpan()
	}
}

// mergeWithExistingSpan merges pid to the existing free spans, try to merge it backward and forward
func ( *freelist) ( pgid) {
	 :=  - 1
	 :=  + 1

	,  := .backwardMap[]
	,  := .forwardMap[]
	 := 
	 := uint64(1)

	if  {
		//merge with previous span
		 :=  + 1 - pgid()
		.delSpan(, )

		 -= pgid()
		 += 
	}

	if  {
		// merge with next span
		.delSpan(, )
		 += 
	}

	.addSpan(, )
}

func ( *freelist) ( pgid,  uint64) {
	.backwardMap[-1+pgid()] = 
	.forwardMap[] = 
	if ,  := .freemaps[]; ! {
		.freemaps[] = make(map[pgid]struct{})
	}

	.freemaps[][] = struct{}{}
}

func ( *freelist) ( pgid,  uint64) {
	delete(.forwardMap, )
	delete(.backwardMap, +pgid(-1))
	delete(.freemaps[], )
	if len(.freemaps[]) == 0 {
		delete(.freemaps, )
	}
}

// initial from pgids using when use hashmap version
// pgids must be sorted
func ( *freelist) ( []pgid) {
	if len() == 0 {
		return
	}

	 := uint64(1)
	 := [0]

	if !sort.SliceIsSorted([]pgid(), func(,  int) bool { return [] < [] }) {
		panic("pgids not sorted")
	}

	.freemaps = make(map[uint64]pidSet)
	.forwardMap = make(map[pgid]uint64)
	.backwardMap = make(map[pgid]uint64)

	for  := 1;  < len(); ++ {
		// continuous page
		if [] == [-1]+1 {
			++
		} else {
			.addSpan(, )

			 = 1
			 = []
		}
	}

	// init the tail
	if  != 0 &&  != 0 {
		.addSpan(, )
	}
}