mirror of
https://github.com/jimeh/casecmp.git
synced 2026-02-19 10:26:40 +00:00
initial commit
This commit is contained in:
22
vendor/github.com/qiangxue/fasthttp-routing/LICENSE
generated
vendored
Normal file
22
vendor/github.com/qiangxue/fasthttp-routing/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
The BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2016, Qiang Xue
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
||||
the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or
|
||||
promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
244
vendor/github.com/qiangxue/fasthttp-routing/README.md
generated
vendored
Normal file
244
vendor/github.com/qiangxue/fasthttp-routing/README.md
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
# fasthttp-routing
|
||||
|
||||
[](http://godoc.org/github.com/qiangxue/fasthttp-routing)
|
||||
[](http://goreportcard.com/report/qiangxue/fasthttp-routing)
|
||||
|
||||
## Description
|
||||
|
||||
fasthttp-routing is a Go package that is adapted from [ozzo-routing](https://github.com/go-ozzo/ozzo-routing) to provide
|
||||
fast and powerful routing features for the high-performance [fasthttp](https://github.com/valyala/fasthttp) server.
|
||||
The package has the following features:
|
||||
|
||||
* middleware pipeline architecture, similar to that of the [Express framework](http://expressjs.com).
|
||||
* extremely fast request routing with zero dynamic memory allocation
|
||||
* modular code organization through route grouping
|
||||
* flexible URL path matching, supporting URL parameters and regular expressions
|
||||
* URL creation according to the predefined routes
|
||||
|
||||
## Requirements
|
||||
|
||||
Go 1.5 or above.
|
||||
|
||||
## Installation
|
||||
|
||||
Run the following command to install the package:
|
||||
|
||||
```
|
||||
go get github.com/qiangxue/fasthttp-routing
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
Create a `server.go` file with the following content:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qiangxue/fasthttp-routing"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := routing.New()
|
||||
|
||||
router.Get("/", func(c *routing.Context) error {
|
||||
fmt.Fprintf(c, "Hello, world!")
|
||||
return nil
|
||||
})
|
||||
|
||||
panic(fasthttp.ListenAndServe(":8080", router.HandleRequest))
|
||||
}
|
||||
```
|
||||
|
||||
Now run the following command to start the Web server:
|
||||
|
||||
```
|
||||
go run server.go
|
||||
```
|
||||
|
||||
You should be able to access URLs such as `http://localhost:8080`.
|
||||
|
||||
|
||||
### Routes
|
||||
|
||||
ozzo-routing works by building a routing table in a router and then dispatching HTTP requests to the matching handlers
|
||||
found in the routing table. An intuitive illustration of a routing table is as follows:
|
||||
|
||||
|
||||
Routes | Handlers
|
||||
--------------------|-----------------
|
||||
`GET /users` | m1, m2, h1, ...
|
||||
`POST /users` | m1, m2, h2, ...
|
||||
`PUT /users/<id>` | m1, m2, h3, ...
|
||||
`DELETE /users/<id>`| m1, m2, h4, ...
|
||||
|
||||
|
||||
For an incoming request `GET /users`, the first route would match and the handlers m1, m2, and h1 would be executed.
|
||||
If the request is `PUT /users/123`, the third route would match and the corresponding handlers would be executed.
|
||||
Note that the token `<id>` can match any number of non-slash characters and the matching part can be accessed as
|
||||
a path parameter value in the handlers.
|
||||
|
||||
**If an incoming request matches multiple routes in the table, the route added first to the table will take precedence.
|
||||
All other matching routes will be ignored.**
|
||||
|
||||
The actual implementation of the routing table uses a variant of the radix tree data structure, which makes the routing
|
||||
process as fast as working with a hash table, thanks to the inspiration from [httprouter](https://github.com/julienschmidt/httprouter).
|
||||
|
||||
To add a new route and its handlers to the routing table, call the `To` method like the following:
|
||||
|
||||
```go
|
||||
router := routing.New()
|
||||
router.To("GET", "/users", m1, m2, h1)
|
||||
router.To("POST", "/users", m1, m2, h2)
|
||||
```
|
||||
|
||||
You can also use shortcut methods, such as `Get`, `Post`, `Put`, etc., which are named after the HTTP method names:
|
||||
|
||||
```go
|
||||
router.Get("/users", m1, m2, h1)
|
||||
router.Post("/users", m1, m2, h2)
|
||||
```
|
||||
|
||||
If you have multiple routes with the same URL path but different HTTP methods, like the above example, you can
|
||||
chain them together as follows,
|
||||
|
||||
```go
|
||||
router.Get("/users", m1, m2, h1).Post(m1, m2, h2)
|
||||
```
|
||||
|
||||
If you want to use the same set of handlers to handle the same URL path but different HTTP methods, you can take
|
||||
the following shortcut:
|
||||
|
||||
```go
|
||||
router.To("GET,POST", "/users", m1, m2, h)
|
||||
```
|
||||
|
||||
A route may contain parameter tokens which are in the format of `<name:pattern>`, where `name` stands for the parameter
|
||||
name, and `pattern` is a regular expression which the parameter value should match. A token `<name>` is equivalent
|
||||
to `<name:[^/]*>`, i.e., it matches any number of non-slash characters. At the end of a route, an asterisk character
|
||||
can be used to match any number of arbitrary characters. Below are some examples:
|
||||
|
||||
* `/users/<username>`: matches `/users/admin`
|
||||
* `/users/accnt-<id:\d+>`: matches `/users/accnt-123`, but not `/users/accnt-admin`
|
||||
* `/users/<username>/*`: matches `/users/admin/profile/address`
|
||||
|
||||
When a URL path matches a route, the matching parameters on the URL path can be accessed via `Context.Param()`:
|
||||
|
||||
```go
|
||||
router := routing.New()
|
||||
|
||||
router.Get("/users/<username>", func (c *routing.Context) error {
|
||||
fmt.Fprintf(c, "Name: %v", c.Param("username"))
|
||||
return nil
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
### Route Groups
|
||||
|
||||
Route group is a way of grouping together the routes which have the same route prefix. The routes in a group also
|
||||
share the same handlers that are registered with the group via its `Use` method. For example,
|
||||
|
||||
```go
|
||||
router := routing.New()
|
||||
api := router.Group("/api")
|
||||
api.Use(m1, m2)
|
||||
api.Get("/users", h1).Post(h2)
|
||||
api.Put("/users/<id>", h3).Delete(h4)
|
||||
```
|
||||
|
||||
The above `/api` route group establishes the following routing table:
|
||||
|
||||
|
||||
Routes | Handlers
|
||||
------------------------|-------------
|
||||
`GET /api/users` | m1, m2, h1, ...
|
||||
`POST /api/users` | m1, m2, h2, ...
|
||||
`PUT /api/users/<id>` | m1, m2, h3, ...
|
||||
`DELETE /api/users/<id>`| m1, m2, h4, ...
|
||||
|
||||
|
||||
As you can see, all these routes have the same route prefix `/api` and the handlers `m1` and `m2`. In other similar
|
||||
routing frameworks, the handlers registered with a route group are also called *middlewares*.
|
||||
|
||||
Route groups can be nested. That is, a route group can create a child group by calling the `Group()` method. The router
|
||||
serves as the top level route group. A child group inherits the handlers registered with its parent group. For example,
|
||||
|
||||
```go
|
||||
router := routing.New()
|
||||
router.Use(m1)
|
||||
|
||||
api := router.Group("/api")
|
||||
api.Use(m2)
|
||||
|
||||
users := group.Group("/users")
|
||||
users.Use(m3)
|
||||
users.Put("/<id>", h1)
|
||||
```
|
||||
|
||||
Because the router serves as the parent of the `api` group which is the parent of the `users` group,
|
||||
the `PUT /api/users/<id>` route is associated with the handlers `m1`, `m2`, `m3`, and `h1`.
|
||||
|
||||
|
||||
### Router
|
||||
|
||||
Router manages the routing table and dispatches incoming requests to appropriate handlers. A router instance is created
|
||||
by calling the `routing.New()` method.
|
||||
|
||||
To hook up router with fasthttp, use the following code:
|
||||
|
||||
```go
|
||||
router := routing.New()
|
||||
fasthttp.ListenAndServe(":8080", router.HandleRequest)
|
||||
```
|
||||
|
||||
|
||||
### Handlers
|
||||
|
||||
A handler is a function with the signature `func(*routing.Context) error`. A handler is executed by the router if
|
||||
the incoming request URL path matches the route that the handler is associated with. Through the `routing.Context`
|
||||
parameter, you can access the request information in handlers.
|
||||
|
||||
A route may be associated with multiple handlers. These handlers will be executed in the order that they are registered
|
||||
to the route. The execution sequence can be terminated in the middle using one of the following two methods:
|
||||
|
||||
* A handler returns an error: the router will skip the rest of the handlers and handle the returned error.
|
||||
* A handler calls `Context.Abort()`: the router will simply skip the rest of the handlers. There is no error to be handled.
|
||||
|
||||
A handler can call `Context.Next()` to explicitly execute the rest of the unexecuted handlers and take actions after
|
||||
they finish execution. For example, a response compression handler may start the output buffer, call `Context.Next()`,
|
||||
and then compress and send the output to response.
|
||||
|
||||
|
||||
### Context
|
||||
|
||||
For each incoming request, a `routing.Context` object is passed through the relevant handlers. Because `routing.Context`
|
||||
embeds `fasthttp.RequestCtx`, you can access all properties and methods provided by the latter.
|
||||
|
||||
Additionally, the `Context.Param()` method allows handlers to access the URL path parameters that match the current route.
|
||||
Using `Context.Get()` and `Context.Set()`, handlers can share data between each other. For example, an authentication
|
||||
handler can store the authenticated user identity by calling `Context.Set()`, and other handlers can retrieve back
|
||||
the identity information by calling `Context.Get()`.
|
||||
|
||||
Context also provides a handy `WriteData()` method that can be used to write data of arbitrary type to the response.
|
||||
The `WriteData()` method can also be overridden (by replacement) to achieve more versatile response data writing.
|
||||
|
||||
|
||||
### Error Handling
|
||||
|
||||
A handler may return an error indicating some erroneous condition. Sometimes, a handler or the code it calls may cause
|
||||
a panic. Both should be handled properly to ensure best user experience. It is recommended that you use
|
||||
the `fault.Recover` handler or a similar error handler to handle these errors.
|
||||
|
||||
If an error is not handled by any handler, the router will handle it by calling its `handleError()` method which
|
||||
simply sets an appropriate HTTP status code and writes the error message to the response.
|
||||
|
||||
When an incoming request has no matching route, the router will call the handlers registered via the `Router.NotFound()`
|
||||
method. All the handlers registered via `Router.Use()` will also be called in advance. By default, the following two
|
||||
handlers are registered with `Router.NotFound()`:
|
||||
|
||||
* `routing.MethodNotAllowedHandler`: a handler that sends an `Allow` HTTP header indicating the allowed HTTP methods for a requested URL
|
||||
* `routing.NotFoundHandler`: a handler triggering 404 HTTP error
|
||||
126
vendor/github.com/qiangxue/fasthttp-routing/context.go
generated
vendored
Normal file
126
vendor/github.com/qiangxue/fasthttp-routing/context.go
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright 2016 Qiang Xue. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package routing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// SerializeFunc serializes the given data of arbitrary type into a byte array.
|
||||
type SerializeFunc func(data interface{}) ([]byte, error)
|
||||
|
||||
// Context represents the contextual data and environment while processing an incoming HTTP request.
|
||||
type Context struct {
|
||||
*fasthttp.RequestCtx
|
||||
|
||||
Serialize SerializeFunc // the function serializing the given data of arbitrary type into a byte array.
|
||||
|
||||
router *Router
|
||||
pnames []string // list of route parameter names
|
||||
pvalues []string // list of parameter values corresponding to pnames
|
||||
data map[string]interface{} // data items managed by Get and Set
|
||||
index int // the index of the currently executing handler in handlers
|
||||
handlers []Handler // the handlers associated with the current route
|
||||
}
|
||||
|
||||
// Router returns the Router that is handling the incoming HTTP request.
|
||||
func (c *Context) Router() *Router {
|
||||
return c.router
|
||||
}
|
||||
|
||||
// Param returns the named parameter value that is found in the URL path matching the current route.
|
||||
// If the named parameter cannot be found, an empty string will be returned.
|
||||
func (c *Context) Param(name string) string {
|
||||
for i, n := range c.pnames {
|
||||
if n == name {
|
||||
return c.pvalues[i]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get returns the named data item previously registered with the context by calling Set.
|
||||
// If the named data item cannot be found, nil will be returned.
|
||||
func (c *Context) Get(name string) interface{} {
|
||||
return c.data[name]
|
||||
}
|
||||
|
||||
// Set stores the named data item in the context so that it can be retrieved later.
|
||||
func (c *Context) Set(name string, value interface{}) {
|
||||
if c.data == nil {
|
||||
c.data = make(map[string]interface{})
|
||||
}
|
||||
c.data[name] = value
|
||||
}
|
||||
|
||||
// Next calls the rest of the handlers associated with the current route.
|
||||
// If any of these handlers returns an error, Next will return the error and skip the following handlers.
|
||||
// Next is normally used when a handler needs to do some postprocessing after the rest of the handlers
|
||||
// are executed.
|
||||
func (c *Context) Next() error {
|
||||
c.index++
|
||||
for n := len(c.handlers); c.index < n; c.index++ {
|
||||
if err := c.handlers[c.index](c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Abort skips the rest of the handlers associated with the current route.
|
||||
// Abort is normally used when a handler handles the request normally and wants to skip the rest of the handlers.
|
||||
// If a handler wants to indicate an error condition, it should simply return the error without calling Abort.
|
||||
func (c *Context) Abort() {
|
||||
c.index = len(c.handlers)
|
||||
}
|
||||
|
||||
// URL creates a URL using the named route and the parameter values.
|
||||
// The parameters should be given in the sequence of name1, value1, name2, value2, and so on.
|
||||
// If a parameter in the route is not provided a value, the parameter token will remain in the resulting URL.
|
||||
// Parameter values will be properly URL encoded.
|
||||
// The method returns an empty string if the URL creation fails.
|
||||
func (c *Context) URL(route string, pairs ...interface{}) string {
|
||||
if r := c.router.routes[route]; r != nil {
|
||||
return r.URL(pairs...)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// WriteData writes the given data of arbitrary type to the response.
|
||||
// The method calls the Serialize() method to convert the data into a byte array and then writes
|
||||
// the byte array to the response.
|
||||
func (c *Context) WriteData(data interface{}) (err error) {
|
||||
var bytes []byte
|
||||
if bytes, err = c.Serialize(data); err == nil {
|
||||
_, err = c.Write(bytes)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// init sets the request and response of the context and resets all other properties.
|
||||
func (c *Context) init(ctx *fasthttp.RequestCtx) {
|
||||
c.RequestCtx = ctx
|
||||
c.data = nil
|
||||
c.index = -1
|
||||
c.Serialize = Serialize
|
||||
}
|
||||
|
||||
// Serialize converts the given data into a byte array.
|
||||
// If the data is neither a byte array nor a string, it will call fmt.Sprint to convert it into a string.
|
||||
func Serialize(data interface{}) (bytes []byte, err error) {
|
||||
switch data.(type) {
|
||||
case []byte:
|
||||
return data.([]byte), nil
|
||||
case string:
|
||||
return []byte(data.(string)), nil
|
||||
default:
|
||||
if data != nil {
|
||||
return []byte(fmt.Sprint(data)), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
40
vendor/github.com/qiangxue/fasthttp-routing/error.go
generated
vendored
Normal file
40
vendor/github.com/qiangxue/fasthttp-routing/error.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2016 Qiang Xue. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package routing
|
||||
|
||||
import "net/http"
|
||||
|
||||
// HTTPError represents an HTTP error with HTTP status code and error message
|
||||
type HTTPError interface {
|
||||
error
|
||||
// StatusCode returns the HTTP status code of the error
|
||||
StatusCode() int
|
||||
}
|
||||
|
||||
// Error contains the error information reported by calling Context.Error().
|
||||
type httpError struct {
|
||||
Status int `json:"status" xml:"status"`
|
||||
Message string `json:"message" xml:"message"`
|
||||
}
|
||||
|
||||
// NewHTTPError creates a new HttpError instance.
|
||||
// If the error message is not given, http.StatusText() will be called
|
||||
// to generate the message based on the status code.
|
||||
func NewHTTPError(status int, message ...string) HTTPError {
|
||||
if len(message) > 0 {
|
||||
return &httpError{status, message[0]}
|
||||
}
|
||||
return &httpError{status, http.StatusText(status)}
|
||||
}
|
||||
|
||||
// Error returns the error message.
|
||||
func (e *httpError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
// StatusCode returns the HTTP status code.
|
||||
func (e *httpError) StatusCode() int {
|
||||
return e.Status
|
||||
}
|
||||
107
vendor/github.com/qiangxue/fasthttp-routing/group.go
generated
vendored
Normal file
107
vendor/github.com/qiangxue/fasthttp-routing/group.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright 2016 Qiang Xue. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package routing
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RouteGroup represents a group of routes that share the same path prefix.
|
||||
type RouteGroup struct {
|
||||
prefix string
|
||||
router *Router
|
||||
handlers []Handler
|
||||
}
|
||||
|
||||
// newRouteGroup creates a new RouteGroup with the given path prefix, router, and handlers.
|
||||
func newRouteGroup(prefix string, router *Router, handlers []Handler) *RouteGroup {
|
||||
return &RouteGroup{
|
||||
prefix: prefix,
|
||||
router: router,
|
||||
handlers: handlers,
|
||||
}
|
||||
}
|
||||
|
||||
// Get adds a GET route to the router with the given route path and handlers.
|
||||
func (r *RouteGroup) Get(path string, handlers ...Handler) *Route {
|
||||
return newRoute(path, r).Get(handlers...)
|
||||
}
|
||||
|
||||
// Post adds a POST route to the router with the given route path and handlers.
|
||||
func (r *RouteGroup) Post(path string, handlers ...Handler) *Route {
|
||||
return newRoute(path, r).Post(handlers...)
|
||||
}
|
||||
|
||||
// Put adds a PUT route to the router with the given route path and handlers.
|
||||
func (r *RouteGroup) Put(path string, handlers ...Handler) *Route {
|
||||
return newRoute(path, r).Put(handlers...)
|
||||
}
|
||||
|
||||
// Patch adds a PATCH route to the router with the given route path and handlers.
|
||||
func (r *RouteGroup) Patch(path string, handlers ...Handler) *Route {
|
||||
return newRoute(path, r).Patch(handlers...)
|
||||
}
|
||||
|
||||
// Delete adds a DELETE route to the router with the given route path and handlers.
|
||||
func (r *RouteGroup) Delete(path string, handlers ...Handler) *Route {
|
||||
return newRoute(path, r).Delete(handlers...)
|
||||
}
|
||||
|
||||
// Connect adds a CONNECT route to the router with the given route path and handlers.
|
||||
func (r *RouteGroup) Connect(path string, handlers ...Handler) *Route {
|
||||
return newRoute(path, r).Connect(handlers...)
|
||||
}
|
||||
|
||||
// Head adds a HEAD route to the router with the given route path and handlers.
|
||||
func (r *RouteGroup) Head(path string, handlers ...Handler) *Route {
|
||||
return newRoute(path, r).Head(handlers...)
|
||||
}
|
||||
|
||||
// Options adds an OPTIONS route to the router with the given route path and handlers.
|
||||
func (r *RouteGroup) Options(path string, handlers ...Handler) *Route {
|
||||
return newRoute(path, r).Options(handlers...)
|
||||
}
|
||||
|
||||
// Trace adds a TRACE route to the router with the given route path and handlers.
|
||||
func (r *RouteGroup) Trace(path string, handlers ...Handler) *Route {
|
||||
return newRoute(path, r).Trace(handlers...)
|
||||
}
|
||||
|
||||
// Any adds a route with the given route, handlers, and the HTTP methods as listed in routing.Methods.
|
||||
func (r *RouteGroup) Any(path string, handlers ...Handler) *Route {
|
||||
route := newRoute(path, r)
|
||||
for _, method := range Methods {
|
||||
route.add(method, handlers)
|
||||
}
|
||||
return route
|
||||
}
|
||||
|
||||
// To adds a route to the router with the given HTTP methods, route path, and handlers.
|
||||
// Multiple HTTP methods should be separated by commas (without any surrounding spaces).
|
||||
func (r *RouteGroup) To(methods, path string, handlers ...Handler) *Route {
|
||||
route := newRoute(path, r)
|
||||
for _, method := range strings.Split(methods, ",") {
|
||||
route.add(method, handlers)
|
||||
}
|
||||
return route
|
||||
}
|
||||
|
||||
// Group creates a RouteGroup with the given route path prefix and handlers.
|
||||
// The new group will combine the existing path prefix with the new one.
|
||||
// If no handler is provided, the new group will inherit the handlers registered
|
||||
// with the current group.
|
||||
func (r *RouteGroup) Group(prefix string, handlers ...Handler) *RouteGroup {
|
||||
if len(handlers) == 0 {
|
||||
handlers = make([]Handler, len(r.handlers))
|
||||
copy(handlers, r.handlers)
|
||||
}
|
||||
return newRouteGroup(r.prefix+prefix, r.router, handlers)
|
||||
}
|
||||
|
||||
// Use registers one or multiple handlers to the current route group.
|
||||
// These handlers will be shared by all routes belong to this group and its subgroups.
|
||||
func (r *RouteGroup) Use(handlers ...Handler) {
|
||||
r.handlers = append(r.handlers, handlers...)
|
||||
}
|
||||
161
vendor/github.com/qiangxue/fasthttp-routing/route.go
generated
vendored
Normal file
161
vendor/github.com/qiangxue/fasthttp-routing/route.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright 2016 Qiang Xue. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package routing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Route represents a URL path pattern that can be used to match requested URLs.
|
||||
type Route struct {
|
||||
group *RouteGroup
|
||||
name, path string
|
||||
template string
|
||||
}
|
||||
|
||||
// newRoute creates a new Route with the given route path and route group.
|
||||
func newRoute(path string, group *RouteGroup) *Route {
|
||||
path = group.prefix + path
|
||||
name := path
|
||||
|
||||
// an asterisk at the end matches any number of characters
|
||||
if strings.HasSuffix(path, "*") {
|
||||
path = path[:len(path)-1] + "<:.*>"
|
||||
}
|
||||
|
||||
route := &Route{
|
||||
group: group,
|
||||
name: name,
|
||||
path: path,
|
||||
template: buildURLTemplate(path),
|
||||
}
|
||||
group.router.routes[name] = route
|
||||
|
||||
return route
|
||||
}
|
||||
|
||||
// Name sets the name of the route.
|
||||
// This method will update the registration of the route in the router as well.
|
||||
func (r *Route) Name(name string) *Route {
|
||||
r.name = name
|
||||
r.group.router.routes[name] = r
|
||||
return r
|
||||
}
|
||||
|
||||
// Get adds the route to the router using the GET HTTP method.
|
||||
func (r *Route) Get(handlers ...Handler) *Route {
|
||||
return r.add("GET", handlers)
|
||||
}
|
||||
|
||||
// Post adds the route to the router using the POST HTTP method.
|
||||
func (r *Route) Post(handlers ...Handler) *Route {
|
||||
return r.add("POST", handlers)
|
||||
}
|
||||
|
||||
// Put adds the route to the router using the PUT HTTP method.
|
||||
func (r *Route) Put(handlers ...Handler) *Route {
|
||||
return r.add("PUT", handlers)
|
||||
}
|
||||
|
||||
// Patch adds the route to the router using the PATCH HTTP method.
|
||||
func (r *Route) Patch(handlers ...Handler) *Route {
|
||||
return r.add("PATCH", handlers)
|
||||
}
|
||||
|
||||
// Delete adds the route to the router using the DELETE HTTP method.
|
||||
func (r *Route) Delete(handlers ...Handler) *Route {
|
||||
return r.add("DELETE", handlers)
|
||||
}
|
||||
|
||||
// Connect adds the route to the router using the CONNECT HTTP method.
|
||||
func (r *Route) Connect(handlers ...Handler) *Route {
|
||||
return r.add("CONNECT", handlers)
|
||||
}
|
||||
|
||||
// Head adds the route to the router using the HEAD HTTP method.
|
||||
func (r *Route) Head(handlers ...Handler) *Route {
|
||||
return r.add("HEAD", handlers)
|
||||
}
|
||||
|
||||
// Options adds the route to the router using the OPTIONS HTTP method.
|
||||
func (r *Route) Options(handlers ...Handler) *Route {
|
||||
return r.add("OPTIONS", handlers)
|
||||
}
|
||||
|
||||
// Trace adds the route to the router using the TRACE HTTP method.
|
||||
func (r *Route) Trace(handlers ...Handler) *Route {
|
||||
return r.add("TRACE", handlers)
|
||||
}
|
||||
|
||||
// To adds the route to the router with the given HTTP methods and handlers.
|
||||
// Multiple HTTP methods should be separated by commas (without any surrounding spaces).
|
||||
func (r *Route) To(methods string, handlers ...Handler) *Route {
|
||||
for _, method := range strings.Split(methods, ",") {
|
||||
r.add(method, handlers)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// URL creates a URL using the current route and the given parameters.
|
||||
// The parameters should be given in the sequence of name1, value1, name2, value2, and so on.
|
||||
// If a parameter in the route is not provided a value, the parameter token will remain in the resulting URL.
|
||||
// The method will perform URL encoding for all given parameter values.
|
||||
func (r *Route) URL(pairs ...interface{}) (s string) {
|
||||
s = r.template
|
||||
for i := 0; i < len(pairs); i++ {
|
||||
name := fmt.Sprintf("<%v>", pairs[i])
|
||||
value := ""
|
||||
if i < len(pairs)-1 {
|
||||
value = url.QueryEscape(fmt.Sprint(pairs[i+1]))
|
||||
}
|
||||
s = strings.Replace(s, name, value, -1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// add registers the route, the specified HTTP method and the handlers to the router.
|
||||
// The handlers will be combined with the handlers of the route group.
|
||||
func (r *Route) add(method string, handlers []Handler) *Route {
|
||||
hh := combineHandlers(r.group.handlers, handlers)
|
||||
r.group.router.add(method, r.path, hh)
|
||||
return r
|
||||
}
|
||||
|
||||
// buildURLTemplate converts a route pattern into a URL template by removing regular expressions in parameter tokens.
|
||||
func buildURLTemplate(path string) string {
|
||||
template, start, end := "", -1, -1
|
||||
for i := 0; i < len(path); i++ {
|
||||
if path[i] == '<' && start < 0 {
|
||||
start = i
|
||||
} else if path[i] == '>' && start >= 0 {
|
||||
name := path[start+1 : i]
|
||||
for j := start + 1; j < i; j++ {
|
||||
if path[j] == ':' {
|
||||
name = path[start+1 : j]
|
||||
break
|
||||
}
|
||||
}
|
||||
template += path[end+1:start] + "<" + name + ">"
|
||||
end = i
|
||||
start = -1
|
||||
}
|
||||
}
|
||||
if end < 0 {
|
||||
template = path
|
||||
} else if end < len(path)-1 {
|
||||
template += path[end+1:]
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
// combineHandlers merges two lists of handlers into a new list.
|
||||
func combineHandlers(h1 []Handler, h2 []Handler) []Handler {
|
||||
hh := make([]Handler, len(h1)+len(h2))
|
||||
copy(hh, h1)
|
||||
copy(hh[len(h1):], h2)
|
||||
return hh
|
||||
}
|
||||
169
vendor/github.com/qiangxue/fasthttp-routing/router.go
generated
vendored
Normal file
169
vendor/github.com/qiangxue/fasthttp-routing/router.go
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright 2016 Qiang Xue. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package routing provides high performance and powerful HTTP routing capabilities.
|
||||
package routing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
type (
|
||||
// Handler is the function for handling HTTP requests.
|
||||
Handler func(*Context) error
|
||||
|
||||
// Router manages routes and dispatches HTTP requests to the handlers of the matching routes.
|
||||
Router struct {
|
||||
RouteGroup
|
||||
pool sync.Pool
|
||||
routes map[string]*Route
|
||||
stores map[string]routeStore
|
||||
maxParams int
|
||||
notFound []Handler
|
||||
notFoundHandlers []Handler
|
||||
}
|
||||
|
||||
// routeStore stores route paths and the corresponding handlers.
|
||||
routeStore interface {
|
||||
Add(key string, data interface{}) int
|
||||
Get(key string, pvalues []string) (data interface{}, pnames []string)
|
||||
String() string
|
||||
}
|
||||
)
|
||||
|
||||
// Methods lists all supported HTTP methods by Router.
|
||||
var Methods = []string{
|
||||
"CONNECT",
|
||||
"DELETE",
|
||||
"GET",
|
||||
"HEAD",
|
||||
"OPTIONS",
|
||||
"PATCH",
|
||||
"POST",
|
||||
"PUT",
|
||||
"TRACE",
|
||||
}
|
||||
|
||||
// New creates a new Router object.
|
||||
func New() *Router {
|
||||
r := &Router{
|
||||
routes: make(map[string]*Route),
|
||||
stores: make(map[string]routeStore),
|
||||
}
|
||||
r.RouteGroup = *newRouteGroup("", r, make([]Handler, 0))
|
||||
r.NotFound(MethodNotAllowedHandler, NotFoundHandler)
|
||||
r.pool.New = func() interface{} {
|
||||
return &Context{
|
||||
pvalues: make([]string, r.maxParams),
|
||||
router: r,
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// HandleRequest handles the HTTP request.
|
||||
func (r *Router) HandleRequest(ctx *fasthttp.RequestCtx) {
|
||||
c := r.pool.Get().(*Context)
|
||||
c.init(ctx)
|
||||
c.handlers, c.pnames = r.find(string(ctx.Method()), string(ctx.Path()), c.pvalues)
|
||||
if err := c.Next(); err != nil {
|
||||
r.handleError(c, err)
|
||||
}
|
||||
r.pool.Put(c)
|
||||
}
|
||||
|
||||
// Route returns the named route.
|
||||
// Nil is returned if the named route cannot be found.
|
||||
func (r *Router) Route(name string) *Route {
|
||||
return r.routes[name]
|
||||
}
|
||||
|
||||
// Use appends the specified handlers to the router and shares them with all routes.
|
||||
func (r *Router) Use(handlers ...Handler) {
|
||||
r.RouteGroup.Use(handlers...)
|
||||
r.notFoundHandlers = combineHandlers(r.handlers, r.notFound)
|
||||
}
|
||||
|
||||
// NotFound specifies the handlers that should be invoked when the router cannot find any route matching a request.
|
||||
// Note that the handlers registered via Use will be invoked first in this case.
|
||||
func (r *Router) NotFound(handlers ...Handler) {
|
||||
r.notFound = handlers
|
||||
r.notFoundHandlers = combineHandlers(r.handlers, r.notFound)
|
||||
}
|
||||
|
||||
// handleError is the error handler for handling any unhandled errors.
|
||||
func (r *Router) handleError(c *Context, err error) {
|
||||
if httpError, ok := err.(HTTPError); ok {
|
||||
c.Error(httpError.Error(), httpError.StatusCode())
|
||||
} else {
|
||||
c.Error(err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) add(method, path string, handlers []Handler) {
|
||||
store := r.stores[method]
|
||||
if store == nil {
|
||||
store = newStore()
|
||||
r.stores[method] = store
|
||||
}
|
||||
if n := store.Add(path, handlers); n > r.maxParams {
|
||||
r.maxParams = n
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) find(method, path string, pvalues []string) (handlers []Handler, pnames []string) {
|
||||
var hh interface{}
|
||||
if store := r.stores[method]; store != nil {
|
||||
hh, pnames = store.Get(path, pvalues)
|
||||
}
|
||||
if hh != nil {
|
||||
return hh.([]Handler), pnames
|
||||
}
|
||||
return r.notFoundHandlers, pnames
|
||||
}
|
||||
|
||||
func (r *Router) findAllowedMethods(path string) map[string]bool {
|
||||
methods := make(map[string]bool)
|
||||
pvalues := make([]string, r.maxParams)
|
||||
for m, store := range r.stores {
|
||||
if handlers, _ := store.Get(path, pvalues); handlers != nil {
|
||||
methods[m] = true
|
||||
}
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
// NotFoundHandler returns a 404 HTTP error indicating a request has no matching route.
|
||||
func NotFoundHandler(*Context) error {
|
||||
return NewHTTPError(http.StatusNotFound)
|
||||
}
|
||||
|
||||
// MethodNotAllowedHandler handles the situation when a request has matching route without matching HTTP method.
|
||||
// In this case, the handler will respond with an Allow HTTP header listing the allowed HTTP methods.
|
||||
// Otherwise, the handler will do nothing and let the next handler (usually a NotFoundHandler) to handle the problem.
|
||||
func MethodNotAllowedHandler(c *Context) error {
|
||||
methods := c.Router().findAllowedMethods(string(c.Path()))
|
||||
if len(methods) == 0 {
|
||||
return nil
|
||||
}
|
||||
methods["OPTIONS"] = true
|
||||
ms := make([]string, len(methods))
|
||||
i := 0
|
||||
for method := range methods {
|
||||
ms[i] = method
|
||||
i++
|
||||
}
|
||||
sort.Strings(ms)
|
||||
c.Response.Header.Set("Allow", strings.Join(ms, ", "))
|
||||
if string(c.Method()) != "OPTIONS" {
|
||||
c.Response.SetStatusCode(http.StatusMethodNotAllowed)
|
||||
}
|
||||
c.Abort()
|
||||
return nil
|
||||
}
|
||||
317
vendor/github.com/qiangxue/fasthttp-routing/store.go
generated
vendored
Normal file
317
vendor/github.com/qiangxue/fasthttp-routing/store.go
generated
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
// Copyright 2016 Qiang Xue. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package routing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// store is a radix tree that supports storing data with parametric keys and retrieving them back with concrete keys.
|
||||
// When retrieving a data item with a concrete key, the matching parameter names and values will be returned as well.
|
||||
// A parametric key is a string containing tokens in the format of "<name>", "<name:pattern>", or "<:pattern>".
|
||||
// Each token represents a single parameter.
|
||||
type store struct {
|
||||
root *node // the root node of the radix tree
|
||||
count int // the number of data nodes in the tree
|
||||
}
|
||||
|
||||
// newStore creates a new store.
|
||||
func newStore() *store {
|
||||
return &store{
|
||||
root: &node{
|
||||
static: true,
|
||||
children: make([]*node, 256),
|
||||
pchildren: make([]*node, 0),
|
||||
pindex: -1,
|
||||
pnames: []string{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a new data item with the given parametric key.
|
||||
// The number of parameters in the key is returned.
|
||||
func (s *store) Add(key string, data interface{}) int {
|
||||
s.count++
|
||||
return s.root.add(key, data, s.count)
|
||||
}
|
||||
|
||||
// Get returns the data item matching the given concrete key.
|
||||
// If the data item was added to the store with a parametric key before, the matching
|
||||
// parameter names and values will be returned as well.
|
||||
func (s *store) Get(path string, pvalues []string) (data interface{}, pnames []string) {
|
||||
data, pnames, _ = s.root.get(path, pvalues)
|
||||
return
|
||||
}
|
||||
|
||||
// String dumps the radix tree kept in the store as a string.
|
||||
func (s *store) String() string {
|
||||
return s.root.print(0)
|
||||
}
|
||||
|
||||
// node represents a radix trie node
|
||||
type node struct {
|
||||
static bool // whether the node is a static node or param node
|
||||
|
||||
key string // the key identifying this node
|
||||
data interface{} // the data associated with this node. nil if not a data node.
|
||||
|
||||
order int // the order at which the data was added. used to be pick the first one when matching multiple
|
||||
minOrder int // minimum order among all the child nodes and this node
|
||||
|
||||
children []*node // child static nodes, indexed by the first byte of each child key
|
||||
pchildren []*node // child param nodes
|
||||
|
||||
regex *regexp.Regexp // regular expression for a param node containing regular expression key
|
||||
pindex int // the parameter index, meaningful only for param node
|
||||
pnames []string // the parameter names collected from the root till this node
|
||||
}
|
||||
|
||||
// add adds a new data item to the tree rooted at the current node.
|
||||
// The number of parameters in the key is returned.
|
||||
func (n *node) add(key string, data interface{}, order int) int {
|
||||
matched := 0
|
||||
|
||||
// find the common prefix
|
||||
for ; matched < len(key) && matched < len(n.key); matched++ {
|
||||
if key[matched] != n.key[matched] {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if matched == len(n.key) {
|
||||
if matched == len(key) {
|
||||
// the node key is the same as the key: make the current node as data node
|
||||
// if the node is already a data node, ignore the new data since we only care the first matched node
|
||||
if n.data == nil {
|
||||
n.data = data
|
||||
n.order = order
|
||||
}
|
||||
return n.pindex + 1
|
||||
}
|
||||
|
||||
// the node key is a prefix of the key: create a child node
|
||||
newKey := key[matched:]
|
||||
|
||||
// try adding to a static child
|
||||
if child := n.children[newKey[0]]; child != nil {
|
||||
if pn := child.add(newKey, data, order); pn >= 0 {
|
||||
return pn
|
||||
}
|
||||
}
|
||||
// try adding to a param child
|
||||
for _, child := range n.pchildren {
|
||||
if pn := child.add(newKey, data, order); pn >= 0 {
|
||||
return pn
|
||||
}
|
||||
}
|
||||
|
||||
return n.addChild(newKey, data, order)
|
||||
}
|
||||
|
||||
if matched == 0 || !n.static {
|
||||
// no common prefix, or partial common prefix with a non-static node: should skip this node
|
||||
return -1
|
||||
}
|
||||
|
||||
// the node key shares a partial prefix with the key: split the node key
|
||||
n1 := &node{
|
||||
static: true,
|
||||
key: n.key[matched:],
|
||||
data: n.data,
|
||||
order: n.order,
|
||||
minOrder: n.minOrder,
|
||||
pchildren: n.pchildren,
|
||||
children: n.children,
|
||||
pindex: n.pindex,
|
||||
pnames: n.pnames,
|
||||
}
|
||||
|
||||
n.key = key[0:matched]
|
||||
n.data = nil
|
||||
n.pchildren = make([]*node, 0)
|
||||
n.children = make([]*node, 256)
|
||||
n.children[n1.key[0]] = n1
|
||||
|
||||
return n.add(key, data, order)
|
||||
}
|
||||
|
||||
// addChild creates static and param nodes to store the given data
|
||||
func (n *node) addChild(key string, data interface{}, order int) int {
|
||||
// find the first occurrence of a param token
|
||||
p0, p1 := -1, -1
|
||||
for i := 0; i < len(key); i++ {
|
||||
if p0 < 0 && key[i] == '<' {
|
||||
p0 = i
|
||||
}
|
||||
if p0 >= 0 && key[i] == '>' {
|
||||
p1 = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if p0 > 0 && p1 > 0 || p1 < 0 {
|
||||
// param token occurs after a static string, or no param token: create a static node
|
||||
child := &node{
|
||||
static: true,
|
||||
key: key,
|
||||
minOrder: order,
|
||||
children: make([]*node, 256),
|
||||
pchildren: make([]*node, 0),
|
||||
pindex: n.pindex,
|
||||
pnames: n.pnames,
|
||||
}
|
||||
n.children[key[0]] = child
|
||||
if p1 > 0 {
|
||||
// param token occurs after a static string
|
||||
child.key = key[:p0]
|
||||
n = child
|
||||
} else {
|
||||
// no param token: done adding the child
|
||||
child.data = data
|
||||
child.order = order
|
||||
return child.pindex + 1
|
||||
}
|
||||
}
|
||||
|
||||
// add param node
|
||||
child := &node{
|
||||
static: false,
|
||||
key: key[p0 : p1+1],
|
||||
minOrder: order,
|
||||
children: make([]*node, 256),
|
||||
pchildren: make([]*node, 0),
|
||||
pindex: n.pindex,
|
||||
pnames: n.pnames,
|
||||
}
|
||||
pattern := ""
|
||||
pname := key[p0+1 : p1]
|
||||
for i := p0 + 1; i < p1; i++ {
|
||||
if key[i] == ':' {
|
||||
pname = key[p0+1 : i]
|
||||
pattern = key[i+1 : p1]
|
||||
break
|
||||
}
|
||||
}
|
||||
if pattern != "" {
|
||||
// the param token contains a regular expression
|
||||
child.regex = regexp.MustCompile("^" + pattern)
|
||||
}
|
||||
pnames := make([]string, len(n.pnames)+1)
|
||||
copy(pnames, n.pnames)
|
||||
pnames[len(n.pnames)] = pname
|
||||
child.pnames = pnames
|
||||
child.pindex = len(pnames) - 1
|
||||
n.pchildren = append(n.pchildren, child)
|
||||
|
||||
if p1 == len(key)-1 {
|
||||
// the param token is at the end of the key
|
||||
child.data = data
|
||||
child.order = order
|
||||
return child.pindex + 1
|
||||
}
|
||||
|
||||
// process the rest of the key
|
||||
return child.addChild(key[p1+1:], data, order)
|
||||
}
|
||||
|
||||
// get returns the data item with the key matching the tree rooted at the current node
|
||||
func (n *node) get(key string, pvalues []string) (data interface{}, pnames []string, order int) {
|
||||
order = math.MaxInt32
|
||||
|
||||
repeat:
|
||||
if n.static {
|
||||
// check if the node key is a prefix of the given key
|
||||
// a slightly optimized version of strings.HasPrefix
|
||||
nkl := len(n.key)
|
||||
if nkl > len(key) {
|
||||
return
|
||||
}
|
||||
for i := nkl - 1; i >= 0; i-- {
|
||||
if n.key[i] != key[i] {
|
||||
return
|
||||
}
|
||||
}
|
||||
key = key[nkl:]
|
||||
} else if n.regex != nil {
|
||||
// param node with regular expression
|
||||
if n.regex.String() == "^.*" {
|
||||
pvalues[n.pindex] = key
|
||||
key = ""
|
||||
} else if match := n.regex.FindStringIndex(key); match != nil {
|
||||
pvalues[n.pindex] = key[0:match[1]]
|
||||
key = key[match[1]:]
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// param node matching non-"/" characters
|
||||
i, kl := 0, len(key)
|
||||
for ; i < kl; i++ {
|
||||
if key[i] == '/' {
|
||||
pvalues[n.pindex] = key[0:i]
|
||||
key = key[i:]
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == kl {
|
||||
pvalues[n.pindex] = key
|
||||
key = ""
|
||||
}
|
||||
}
|
||||
|
||||
if len(key) > 0 {
|
||||
// find a static child that can match the rest of the key
|
||||
if child := n.children[key[0]]; child != nil {
|
||||
if len(n.pchildren) == 0 {
|
||||
// use goto to avoid recursion when no param children
|
||||
n = child
|
||||
goto repeat
|
||||
}
|
||||
data, pnames, order = child.get(key, pvalues)
|
||||
}
|
||||
} else if n.data != nil {
|
||||
// do not return yet: a param node may match an empty string with smaller order
|
||||
data, pnames, order = n.data, n.pnames, n.order
|
||||
}
|
||||
|
||||
// try matching param children
|
||||
tvalues := pvalues
|
||||
allocated := false
|
||||
for _, child := range n.pchildren {
|
||||
if child.minOrder >= order {
|
||||
continue
|
||||
}
|
||||
if data != nil && !allocated {
|
||||
tvalues = make([]string, len(pvalues))
|
||||
allocated = true
|
||||
}
|
||||
if d, p, s := child.get(key, tvalues); d != nil && s < order {
|
||||
if allocated {
|
||||
for i := child.pindex; i < len(p); i++ {
|
||||
pvalues[i] = tvalues[i]
|
||||
}
|
||||
}
|
||||
data, pnames, order = d, p, s
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (n *node) print(level int) string {
|
||||
r := fmt.Sprintf("%v{key: %v, regex: %v, data: %v, order: %v, minOrder: %v, pindex: %v, pnames: %v}\n", strings.Repeat(" ", level<<2), n.key, n.regex, n.data, n.order, n.minOrder, n.pindex, n.pnames)
|
||||
for _, child := range n.children {
|
||||
if child != nil {
|
||||
r += child.print(level + 1)
|
||||
}
|
||||
}
|
||||
for _, child := range n.pchildren {
|
||||
r += child.print(level + 1)
|
||||
}
|
||||
return r
|
||||
}
|
||||
Reference in New Issue
Block a user