func (l ID) Cmp(r ID) int {
	if r.IsNil() {
		return -1
	}
	return bytes.Compare(l[:], r[:])
}
Cmp compares two IDs.
There are 3 possible return values.

-1 : Argument id is less than calling id.
0 : Argument id and calling id are identical.
+1 : Argument id is greater than calling id.

Comparison is done on the actual numerical value of the ids.
Not the string representation.
package c4
import (
	"bytes"
	"crypto/sha512"
	"io"
	"math/big"
	"sort"
	"strconv"
	"strings"
	"github.com/xtgo/set"
)
const (
	charset = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
	base    = 58
)
var (
	lut     [256]byte
	lowbyte = byte('1')
	prefix  = []byte{'c', '4'}
	idlen   = 90
	nilID = Identify(bytes.NewReader([]byte{}))
	voidID ID
	maxID ID
)
type errBadChar int
func (e errBadChar) Error() string {
	return "non c4 id character at position " + strconv.Itoa(int(e))
}
type errBadLength int
func (e errBadLength) Error() string {
	return "c4 ids must be 90 characters long, input length " + strconv.Itoa(int(e))
}
type errNil struct{}
func (e errNil) Error() string {
	return "unexpected nil id"
}
type errInvalidTree struct{}
func (e errInvalidTree) Error() string {
	return "invalid tree data"
}
func init() {
	for i := range lut {
		lut[i] = 0xFF
	}
	for i, c := range charset {
		lut[c] = byte(i)
	}
	for i := range maxID[:] {
		maxID[i] = 0xFF
	}
}
func Identify(src io.Reader) (id ID) {
	h := sha512.New()
	_, err := io.Copy(h, src)
	if err != nil && err != io.EOF {
		return id
	}
	copy(id[:], h.Sum(nil))
	return id
}
type ID [64]byte
type Identifiable interface {
	ID() ID
}
func (id ID) IsNil() bool {
	for _, b := range id[:] {
		if b != 0 {
			return false
		}
	}
	return true
}
func Parse(source string) (ID, error) {
	var id ID
	if len(source) == 0 {
		return voidID, errBadLength(len(source))
	}
	src := []byte(source)
	if len(src) != 90 {
		return id, errBadLength(len(src))
	}
	bigNum := new(big.Int)
	bigBase := big.NewInt(base)
	for i := 2; i < len(src); i++ {
		b := lut[src[i]]
		if b == 0xFF {
			return id, errBadChar(i)
		}
		bigNum.Mul(bigNum, bigBase)
		bigNum.Add(bigNum, big.NewInt(int64(b)))
	}
	data := bigNum.Bytes()
	if len(data) > 64 {
		data = data[:64]
	}
	shift := 64 - len(data)
	for i := 0; i < shift; i++ {
		data = append(data, 0)
	}
	if shift > 0 {
		copy(data[shift:], data)
		for i := 0; i < shift; i++ {
			data[i] = 0
		}
	}
	copy(id[:], data)
	return id, nil
}
func (id ID) Digest() []byte {
	return id[:]
}