Пакет идентификаторов Kadelmia, написанный на go

Я новичок в Go (начал изучать его две недели назад) и хотел бы получить ваши комментарии по приведенному ниже коду. Код является реализацией идентификатора, используемого DHT (Kadelmia). Код протестирован – он работает должным образом. Заранее спасибо.

package identifier

import (
    "fmt"
    "math/bits"
)

type idBuilderType struct {
    length int
}

type identifierType struct {
    unsafe bool
    bytes  []byte
}

const (
    illegalLength  = "illegal length: %d"
    nilInput       = "invalid input: nil"
    invalidLength  = "invalid input length, expected: %d, got: %d"
    differenLength = "ids have different lengths: %d and %d"

    ERROR   = -200
    EQUAL   = 0
    GREATER = 1
    LESSER  = -1
)

// creates a builder for building of identifiers with given length
// returns nil and error if given length is lesser or equal to 0
func GetBuilder(len int) (*idBuilderType, error) {

    if len <= 0 {
        return nil, fmt.Errorf(illegalLength, len)
    }

    builder := new(idBuilderType)
    builder.length = len
    return builder, nil
}

//builds identifier. if unsafe is set to true then "unsafe identifier"
//is created. returns nil and error if given array has length different
//from length defined by builder
func (builder *idBuilderType) BuildFromBytes(bytes []byte, unsafe bool) (*identifierType, error) {

    if bytes == nil {
        return nil, fmt.Errorf(nilInput)
    }

    length := len(bytes)
    if length != builder.length {
        return nil, fmt.Errorf(invalidLength, builder.length, length)
    }

    id := new(identifierType)
    id.unsafe = unsafe
    if unsafe {
        id.bytes = bytes
    } else {
        id.bytes = make([]byte, length)
        copy(id.bytes, bytes)
    }
    return id, nil
}

//returns byte array representation of the identifier
//if identifier is unsafe then internal buffer of
//identifier returned, otherwise method returns copy
//of the buffer
func (this *identifierType) GetBytes() []byte {
    if this.unsafe {
        return this.bytes
    } else {
        bytes := make([]byte, this.GetLength())
        copy(bytes, this.bytes)
        return bytes
    }
}

func (this *identifierType) IsUnsafe() bool {
    return this.unsafe
}

//returns length of the identifier
func (this *identifierType) GetLength() int {
    return len(this.bytes)
}

//compares two identifiers.
//returns ERROR (-200) and error if identifiers have different length
//returns GREATER (1) if this identifier is greater then another
//returns EQUAL (0) if identifiers are equal
//returns LESSER (-1) if this identifier is lesser then another
func (this *identifierType) Compare(another *identifierType) (int, error) {

    err := this.checkLength(another)
    if err != nil {
        return ERROR, err
    }

    for i, b := range this.bytes {
        if b > another.bytes[i] {
            return GREATER, nil
        }

        if b < another.bytes[i] {
            return LESSER, nil
        }
    }
    return EQUAL, nil
}

//returns length of shared prefix of two identifiers
//returns ERROR (-200) and error if identifiers have different length
func (this *identifierType) GetSharedPrefixLen(another *identifierType) (int, error) {

    err := this.checkLength(another)
    if err != nil {
        return ERROR, err
    }

    count := 0

    for i, b := range this.bytes {

        if b == another.bytes[i] {
            count += 8
        } else {
            xor := byte(b ^ another.bytes[i])
            count = count + bits.LeadingZeros8(xor)
            return count, nil
        }

    }
    return count, nil
}

//calculates and returns arithmetical mean of two identifiers
//returns ERROR (-200) and error if identifiers have different length
func (this *identifierType) Mid(another *identifierType) (*identifierType, error) {

    err := this.checkLength(another)
    if err != nil {
        return nil, err
    }

    bytes := sum(this.bytes, another.bytes, this.GetLength())
    return divideByTwo(bytes, this.GetLength()+1), nil
}

func sum(bytes []byte, bytes1 []byte, length int) []byte {

    index := length
    buffer := make([]byte, index+1)
    sum := uint16(0)

    for i := index - 1; i >= 0; i-- {
        sum = uint16(bytes[i]&0xff) + uint16(bytes1[i]&0xff) + sum>>8
        buffer[i+1] = byte(sum)
    }

    if (sum >> 8) != 0 {
        buffer[0] = byte(sum >> 8)
    }

    return buffer
}

func divideByTwo(bytes []byte, len int) *identifierType {

    length := len - 1
    ba := make([]byte, length)
    carry := (bytes[0] & 1) != 0

    for i := 0; i < length; i++ {
        ba[i] = byte((bytes[i+1] & 0xff) >> 1)
        if carry {
            ba[i] = byte(ba[i] | 0b10000000)
        }

        carry = (bytes[i+1] & 1) != 0
    }
    result := new(identifierType)
    result.bytes = ba

    return result
}

func (this *identifierType) checkLength(id *identifierType) error {

    len1 := this.GetLength()
    len2 := id.GetLength()
    if len1 != len2 {
        return fmt.Errorf(differenLength, len1, len2)
    }

    return nil
}

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *