package pstoremem

import (
	
	

	
	pstore 
	
)

type protoSegment struct {
	sync.RWMutex
	protocols map[peer.ID]map[protocol.ID]struct{}
}

type protoSegments [256]*protoSegment

func ( *protoSegments) ( peer.ID) *protoSegment {
	return [[len()-1]]
}

var errTooManyProtocols = errors.New("too many protocols")

type memoryProtoBook struct {
	segments protoSegments

	maxProtos int
}

var _ pstore.ProtoBook = (*memoryProtoBook)(nil)

type ProtoBookOption func(book *memoryProtoBook) error

func ( int) ProtoBookOption {
	return func( *memoryProtoBook) error {
		.maxProtos = 
		return nil
	}
}

func ( ...ProtoBookOption) (*memoryProtoBook, error) {
	 := &memoryProtoBook{
		segments: func() ( protoSegments) {
			for  := range  {
				[] = &protoSegment{
					protocols: make(map[peer.ID]map[protocol.ID]struct{}),
				}
			}
			return 
		}(),
		maxProtos: 128,
	}

	for ,  := range  {
		if  := ();  != nil {
			return nil, 
		}
	}
	return , nil
}

func ( *memoryProtoBook) ( peer.ID,  ...protocol.ID) error {
	if len() > .maxProtos {
		return errTooManyProtocols
	}

	 := make(map[protocol.ID]struct{}, len())
	for ,  := range  {
		[] = struct{}{}
	}

	 := .segments.get()
	.Lock()
	.protocols[] = 
	.Unlock()

	return nil
}

func ( *memoryProtoBook) ( peer.ID,  ...protocol.ID) error {
	 := .segments.get()
	.Lock()
	defer .Unlock()

	,  := .protocols[]
	if ! {
		 = make(map[protocol.ID]struct{})
		.protocols[] = 
	}
	if len()+len() > .maxProtos {
		return errTooManyProtocols
	}

	for ,  := range  {
		[] = struct{}{}
	}
	return nil
}

func ( *memoryProtoBook) ( peer.ID) ([]protocol.ID, error) {
	 := .segments.get()
	.RLock()
	defer .RUnlock()

	 := make([]protocol.ID, 0, len(.protocols[]))
	for  := range .protocols[] {
		 = append(, )
	}

	return , nil
}

func ( *memoryProtoBook) ( peer.ID,  ...protocol.ID) error {
	 := .segments.get()
	.Lock()
	defer .Unlock()

	,  := .protocols[]
	if ! {
		// nothing to remove.
		return nil
	}

	for ,  := range  {
		delete(, )
	}
	if len() == 0 {
		delete(.protocols, )
	}
	return nil
}

func ( *memoryProtoBook) ( peer.ID,  ...protocol.ID) ([]protocol.ID, error) {
	 := .segments.get()
	.RLock()
	defer .RUnlock()

	 := make([]protocol.ID, 0, len())
	for ,  := range  {
		if ,  := .protocols[][];  {
			 = append(, )
		}
	}

	return , nil
}

func ( *memoryProtoBook) ( peer.ID,  ...protocol.ID) (protocol.ID, error) {
	 := .segments.get()
	.RLock()
	defer .RUnlock()

	for ,  := range  {
		if ,  := .protocols[][];  {
			return , nil
		}
	}
	return "", nil
}

func ( *memoryProtoBook) ( peer.ID) {
	 := .segments.get()
	.Lock()
	delete(.protocols, )
	.Unlock()
}