package fasthttp

import (
	
	
	
	
	

	
)

const (
	argsNoValue  = true
	argsHasValue = false
)

// AcquireArgs returns an empty Args object from the pool.
//
// The returned Args may be returned to the pool with ReleaseArgs
// when no longer needed. This allows reducing GC load.
func () *Args {
	return argsPool.Get().(*Args)
}

// ReleaseArgs returns the object acquired via AcquireArgs to the pool.
//
// Do not access the released Args object, otherwise data races may occur.
func ( *Args) {
	.Reset()
	argsPool.Put()
}

var argsPool = &sync.Pool{
	New: func() interface{} {
		return &Args{}
	},
}

// Args represents query arguments.
//
// It is forbidden copying Args instances. Create new instances instead
// and use CopyTo().
//
// Args instance MUST NOT be used from concurrently running goroutines.
type Args struct {
	noCopy noCopy

	args []argsKV
	buf  []byte
}

type argsKV struct {
	key     []byte
	value   []byte
	noValue bool
}

// Reset clears query args.
func ( *Args) () {
	.args = .args[:0]
}

// CopyTo copies all args to dst.
func ( *Args) ( *Args) {
	.args = copyArgs(.args, .args)
}

// VisitAll calls f for each existing arg.
//
// f must not retain references to key and value after returning.
// Make key and/or value copies if you need storing them after returning.
func ( *Args) ( func(,  []byte)) {
	visitArgs(.args, )
}

// Len returns the number of query args.
func ( *Args) () int {
	return len(.args)
}

// Parse parses the given string containing query args.
func ( *Args) ( string) {
	.buf = append(.buf[:0], ...)
	.ParseBytes(.buf)
}

// ParseBytes parses the given b containing query args.
func ( *Args) ( []byte) {
	.Reset()

	var  argsScanner
	.b = 

	var  *argsKV
	.args,  = allocArg(.args)
	for .next() {
		if len(.key) > 0 || len(.value) > 0 {
			.args,  = allocArg(.args)
		}
	}
	.args = releaseArg(.args)
}

// String returns string representation of query args.
func ( *Args) () string {
	return string(.QueryString())
}

// QueryString returns query string for the args.
//
// The returned value is valid until the Args is reused or released (ReleaseArgs).
// Do not store references to the returned value. Make copies instead.
func ( *Args) () []byte {
	.buf = .AppendBytes(.buf[:0])
	return .buf
}

// Sort sorts Args by key and then value using 'f' as comparison function.
//
// For example args.Sort(bytes.Compare)
func ( *Args) ( func(,  []byte) int) {
	sort.SliceStable(.args, func(,  int) bool {
		 := (.args[].key, .args[].key)
		if  == 0 {
			return (.args[].value, .args[].value) == -1
		}
		return  == -1
	})
}

// AppendBytes appends query string to dst and returns the extended dst.
func ( *Args) ( []byte) []byte {
	for ,  := 0, len(.args);  < ; ++ {
		 := &.args[]
		 = AppendQuotedArg(, .key)
		if !.noValue {
			 = append(, '=')
			if len(.value) > 0 {
				 = AppendQuotedArg(, .value)
			}
		}
		if +1 <  {
			 = append(, '&')
		}
	}
	return 
}

// WriteTo writes query string to w.
//
// WriteTo implements io.WriterTo interface.
func ( *Args) ( io.Writer) (int64, error) {
	,  := .Write(.QueryString())
	return int64(), 
}

// Del deletes argument with the given key from query args.
func ( *Args) ( string) {
	.args = delAllArgs(.args, )
}

// DelBytes deletes argument with the given key from query args.
func ( *Args) ( []byte) {
	.args = delAllArgs(.args, b2s())
}

// Add adds 'key=value' argument.
//
// Multiple values for the same key may be added.
func ( *Args) (,  string) {
	.args = appendArg(.args, , , argsHasValue)
}

// AddBytesK adds 'key=value' argument.
//
// Multiple values for the same key may be added.
func ( *Args) ( []byte,  string) {
	.args = appendArg(.args, b2s(), , argsHasValue)
}

// AddBytesV adds 'key=value' argument.
//
// Multiple values for the same key may be added.
func ( *Args) ( string,  []byte) {
	.args = appendArg(.args, , b2s(), argsHasValue)
}

// AddBytesKV adds 'key=value' argument.
//
// Multiple values for the same key may be added.
func ( *Args) (,  []byte) {
	.args = appendArg(.args, b2s(), b2s(), argsHasValue)
}

// AddNoValue adds only 'key' as argument without the '='.
//
// Multiple values for the same key may be added.
func ( *Args) ( string) {
	.args = appendArg(.args, , "", argsNoValue)
}

// AddBytesKNoValue adds only 'key' as argument without the '='.
//
// Multiple values for the same key may be added.
func ( *Args) ( []byte) {
	.args = appendArg(.args, b2s(), "", argsNoValue)
}

// Set sets 'key=value' argument.
func ( *Args) (,  string) {
	.args = setArg(.args, , , argsHasValue)
}

// SetBytesK sets 'key=value' argument.
func ( *Args) ( []byte,  string) {
	.args = setArg(.args, b2s(), , argsHasValue)
}

// SetBytesV sets 'key=value' argument.
func ( *Args) ( string,  []byte) {
	.args = setArg(.args, , b2s(), argsHasValue)
}

// SetBytesKV sets 'key=value' argument.
func ( *Args) (,  []byte) {
	.args = setArgBytes(.args, , , argsHasValue)
}

// SetNoValue sets only 'key' as argument without the '='.
//
// Only key in argument, like key1&key2
func ( *Args) ( string) {
	.args = setArg(.args, , "", argsNoValue)
}

// SetBytesKNoValue sets 'key' argument.
func ( *Args) ( []byte) {
	.args = setArg(.args, b2s(), "", argsNoValue)
}

// Peek returns query arg value for the given key.
//
// The returned value is valid until the Args is reused or released (ReleaseArgs).
// Do not store references to the returned value. Make copies instead.
func ( *Args) ( string) []byte {
	return peekArgStr(.args, )
}

// PeekBytes returns query arg value for the given key.
//
// The returned value is valid until the Args is reused or released (ReleaseArgs).
// Do not store references to the returned value. Make copies instead.
func ( *Args) ( []byte) []byte {
	return peekArgBytes(.args, )
}

// PeekMulti returns all the arg values for the given key.
func ( *Args) ( string) [][]byte {
	var  [][]byte
	.VisitAll(func(,  []byte) {
		if string() ==  {
			 = append(, )
		}
	})
	return 
}

// PeekMultiBytes returns all the arg values for the given key.
func ( *Args) ( []byte) [][]byte {
	return .PeekMulti(b2s())
}

// Has returns true if the given key exists in Args.
func ( *Args) ( string) bool {
	return hasArg(.args, )
}

// HasBytes returns true if the given key exists in Args.
func ( *Args) ( []byte) bool {
	return hasArg(.args, b2s())
}

// ErrNoArgValue is returned when Args value with the given key is missing.
var ErrNoArgValue = errors.New("no Args value for the given key")

// GetUint returns uint value for the given key.
func ( *Args) ( string) (int, error) {
	 := .Peek()
	if len() == 0 {
		return -1, ErrNoArgValue
	}
	return ParseUint()
}

// SetUint sets uint value for the given key.
func ( *Args) ( string,  int) {
	 := bytebufferpool.Get()
	.B = AppendUint(.B[:0], )
	.SetBytesV(, .B)
	bytebufferpool.Put()
}

// SetUintBytes sets uint value for the given key.
func ( *Args) ( []byte,  int) {
	.SetUint(b2s(), )
}

// GetUintOrZero returns uint value for the given key.
//
// Zero (0) is returned on error.
func ( *Args) ( string) int {
	,  := .GetUint()
	if  != nil {
		 = 0
	}
	return 
}

// GetUfloat returns ufloat value for the given key.
func ( *Args) ( string) (float64, error) {
	 := .Peek()
	if len() == 0 {
		return -1, ErrNoArgValue
	}
	return ParseUfloat()
}

// GetUfloatOrZero returns ufloat value for the given key.
//
// Zero (0) is returned on error.
func ( *Args) ( string) float64 {
	,  := .GetUfloat()
	if  != nil {
		 = 0
	}
	return 
}

// GetBool returns boolean value for the given key.
//
// true is returned for "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes",
// otherwise false is returned.
func ( *Args) ( string) bool {
	switch string(.Peek()) {
	// Support the same true cases as strconv.ParseBool
	// See: https://github.com/golang/go/blob/4e1b11e2c9bdb0ddea1141eed487be1a626ff5be/src/strconv/atob.go#L12
	// and Y and Yes versions.
	case "1", "t", "T", "true", "TRUE", "True", "y", "yes", "Y", "YES", "Yes":
		return true
	default:
		return false
	}
}

func visitArgs( []argsKV,  func(,  []byte)) {
	for ,  := 0, len();  < ; ++ {
		 := &[]
		(.key, .value)
	}
}

func visitArgsKey( []argsKV,  func( []byte)) {
	for ,  := 0, len();  < ; ++ {
		 := &[]
		(.key)
	}
}

func copyArgs(,  []argsKV) []argsKV {
	if cap() < len() {
		 := make([]argsKV, len())
		 := len()
		 = [:cap()] // copy all of dst.
		copy(, )
		for  := ;  < len(); ++ {
			// Make sure nothing is nil.
			[].key = []byte{}
			[].value = []byte{}
		}
		 = 
	}
	 := len()
	 = [:]
	for  := 0;  < ; ++ {
		 := &[]
		 := &[]
		.key = append(.key[:0], .key...)
		if .noValue {
			.value = .value[:0]
		} else {
			.value = append(.value[:0], .value...)
		}
		.noValue = .noValue
	}
	return 
}

func delAllArgsBytes( []argsKV,  []byte) []argsKV {
	return delAllArgs(, b2s())
}

func delAllArgs( []argsKV,  string) []argsKV {
	for ,  := 0, len();  < ; ++ {
		 := &[]
		if  == string(.key) {
			 := *
			copy([:], [+1:])
			--
			--
			[] = 
			 = [:]
		}
	}
	return 
}

func setArgBytes( []argsKV, ,  []byte,  bool) []argsKV {
	return setArg(, b2s(), b2s(), )
}

func setArg( []argsKV, ,  string,  bool) []argsKV {
	 := len()
	for  := 0;  < ; ++ {
		 := &[]
		if  == string(.key) {
			if  {
				.value = .value[:0]
			} else {
				.value = append(.value[:0], ...)
			}
			.noValue = 
			return 
		}
	}
	return appendArg(, , , )
}

func appendArgBytes( []argsKV, ,  []byte,  bool) []argsKV {
	return appendArg(, b2s(), b2s(), )
}

func appendArg( []argsKV, ,  string,  bool) []argsKV {
	var  *argsKV
	,  = allocArg()
	.key = append(.key[:0], ...)
	if  {
		.value = .value[:0]
	} else {
		.value = append(.value[:0], ...)
	}
	.noValue = 
	return 
}

func allocArg( []argsKV) ([]argsKV, *argsKV) {
	 := len()
	if cap() >  {
		 = [:+1]
	} else {
		 = append(, argsKV{
			value: []byte{},
		})
	}
	return , &[]
}

func releaseArg( []argsKV) []argsKV {
	return [:len()-1]
}

func hasArg( []argsKV,  string) bool {
	for ,  := 0, len();  < ; ++ {
		 := &[]
		if  == string(.key) {
			return true
		}
	}
	return false
}

func peekArgBytes( []argsKV,  []byte) []byte {
	for ,  := 0, len();  < ; ++ {
		 := &[]
		if bytes.Equal(.key, ) {
			return .value
		}
	}
	return nil
}

func peekArgStr( []argsKV,  string) []byte {
	for ,  := 0, len();  < ; ++ {
		 := &[]
		if string(.key) ==  {
			return .value
		}
	}
	return nil
}

type argsScanner struct {
	b []byte
}

func ( *argsScanner) ( *argsKV) bool {
	if len(.b) == 0 {
		return false
	}
	.noValue = argsHasValue

	 := true
	 := 0
	for ,  := range .b {
		switch  {
		case '=':
			if  {
				 = false
				.key = decodeArgAppend(.key[:0], .b[:])
				 =  + 1
			}
		case '&':
			if  {
				.key = decodeArgAppend(.key[:0], .b[:])
				.value = .value[:0]
				.noValue = argsNoValue
			} else {
				.value = decodeArgAppend(.value[:0], .b[:])
			}
			.b = .b[+1:]
			return true
		}
	}

	if  {
		.key = decodeArgAppend(.key[:0], .b)
		.value = .value[:0]
		.noValue = argsNoValue
	} else {
		.value = decodeArgAppend(.value[:0], .b[:])
	}
	.b = .b[len(.b):]
	return true
}

func decodeArgAppend(,  []byte) []byte {
	 := bytes.IndexByte(, '%')
	 := bytes.IndexByte(, '+')
	if  == -1 &&  == -1 {
		// fast path: src doesn't contain encoded chars
		return append(, ...)
	}

	 := 0
	switch {
	case  == -1:
		 = 
	case  == -1:
		 = 
	case  > :
		 = 
	default:
		 = 
	}

	 = append(, [:]...)

	// slow path
	for  := ;  < len(); ++ {
		 := []
		switch  {
		case '%':
			if +2 >= len() {
				return append(, [:]...)
			}
			 := hex2intTable[[+2]]
			 := hex2intTable[[+1]]
			if  == 16 ||  == 16 {
				 = append(, '%')
			} else {
				 = append(, <<4|)
				 += 2
			}
		case '+':
			 = append(, ' ')
		default:
			 = append(, )
		}
	}
	return 
}

// decodeArgAppendNoPlus is almost identical to decodeArgAppend, but it doesn't
// substitute '+' with ' '.
//
// The function is copy-pasted from decodeArgAppend due to the performance
// reasons only.
func decodeArgAppendNoPlus(,  []byte) []byte {
	 := bytes.IndexByte(, '%')
	if  < 0 {
		// fast path: src doesn't contain encoded chars
		return append(, ...)
	}
	 = append(, [:]...)

	// slow path
	for  := ;  < len(); ++ {
		 := []
		if  == '%' {
			if +2 >= len() {
				return append(, [:]...)
			}
			 := hex2intTable[[+2]]
			 := hex2intTable[[+1]]
			if  == 16 ||  == 16 {
				 = append(, '%')
			} else {
				 = append(, <<4|)
				 += 2
			}
		} else {
			 = append(, )
		}
	}
	return 
}

func peekAllArgBytesToDst( [][]byte,  []argsKV,  []byte) [][]byte {
	for ,  := 0, len();  < ; ++ {
		 := &[]
		if bytes.Equal(.key, ) {
			 = append(, .value)
		}
	}
	return 
}

func peekArgsKeys( [][]byte,  []argsKV) [][]byte {
	for ,  := 0, len();  < ; ++ {
		 := &[]
		 = append(, .key)
	}
	return 
}