func()

in s2/cell_index.go [409:493]


func (c *CellIndex) Build() {
	// To build the cell tree and leaf cell ranges, we maintain a stack of
	// (CellID, label) pairs that contain the current leaf cell. This struct
	// represents an instruction to push or pop a (cellID, label) pair.
	//
	// If label >= 0, the (cellID, label) pair is pushed on the stack.
	// If CellID == SentinelCellID, a pair is popped from the stack.
	// Otherwise the stack is unchanged but a rangeNode is still emitted.

	// delta represents an entry in a stack of (CellID, label) pairs used in the
	// construction of the CellIndex structure.
	type delta struct {
		startID CellID
		cellID  CellID
		label   int32
	}

	deltas := make([]delta, 0, 2*len(c.cellTree)+2)

	// Create two deltas for each (cellID, label) pair: one to add the pair to
	// the stack (at the start of its leaf cell range), and one to remove it from
	// the stack (at the end of its leaf cell range).
	for _, node := range c.cellTree {
		deltas = append(deltas, delta{
			startID: node.cellID.RangeMin(),
			cellID:  node.cellID,
			label:   node.label,
		})
		deltas = append(deltas, delta{
			startID: node.cellID.RangeMax().Next(),
			cellID:  SentinelCellID,
			label:   -1,
		})
	}

	// We also create two special deltas to ensure that a RangeNode is emitted at
	// the beginning and end of the CellID range.
	deltas = append(deltas, delta{
		startID: CellIDFromFace(0).ChildBeginAtLevel(maxLevel),
		cellID:  CellID(0),
		label:   -1,
	})
	deltas = append(deltas, delta{
		startID: CellIDFromFace(5).ChildEndAtLevel(maxLevel),
		cellID:  CellID(0),
		label:   -1,
	})

	sort.Slice(deltas, func(i, j int) bool {
		// deltas are sorted first by startID, then in reverse order by cellID,
		// and then by label. This is necessary to ensure that (1) larger cells
		// are pushed on the stack before smaller cells, and (2) cells are popped
		// off the stack before any new cells are added.

		if si, sj := deltas[i].startID, deltas[j].startID; si != sj {
			return si < sj
		}
		if si, sj := deltas[i].cellID, deltas[j].cellID; si != sj {
			return si > sj
		}
		return deltas[i].label < deltas[j].label
	})

	// Now walk through the deltas to build the leaf cell ranges and cell tree
	// (which is essentially a permanent form of the "stack" described above).
	c.cellTree = nil
	c.rangeNodes = nil
	contents := int32(-1)
	for i := 0; i < len(deltas); {
		startID := deltas[i].startID
		// Process all the deltas associated with the current startID.
		for ; i < len(deltas) && deltas[i].startID == startID; i++ {
			if deltas[i].label >= 0 {
				c.cellTree = append(c.cellTree, cellIndexNode{
					cellID: deltas[i].cellID,
					label:  deltas[i].label,
					parent: contents})
				contents = int32(len(c.cellTree) - 1)
			} else if deltas[i].cellID == SentinelCellID {
				contents = c.cellTree[contents].parent
			}
		}
		c.rangeNodes = append(c.rangeNodes, rangeNode{startID, contents})
	}
}