src: Add DMA localagent
[barometer.git] / src / dma / vendor / github.com / valyala / fasttemplate / template.go
diff --git a/src/dma/vendor/github.com/valyala/fasttemplate/template.go b/src/dma/vendor/github.com/valyala/fasttemplate/template.go
new file mode 100644 (file)
index 0000000..9120920
--- /dev/null
@@ -0,0 +1,317 @@
+// Package fasttemplate implements simple and fast template library.
+//
+// Fasttemplate is faster than text/template, strings.Replace
+// and strings.Replacer.
+//
+// Fasttemplate ideally fits for fast and simple placeholders' substitutions.
+package fasttemplate
+
+import (
+       "bytes"
+       "fmt"
+       "github.com/valyala/bytebufferpool"
+       "io"
+)
+
+// ExecuteFunc calls f on each template tag (placeholder) occurrence.
+//
+// Returns the number of bytes written to w.
+//
+// This function is optimized for constantly changing templates.
+// Use Template.ExecuteFunc for frozen templates.
+func ExecuteFunc(template, startTag, endTag string, w io.Writer, f TagFunc) (int64, error) {
+       s := unsafeString2Bytes(template)
+       a := unsafeString2Bytes(startTag)
+       b := unsafeString2Bytes(endTag)
+
+       var nn int64
+       var ni int
+       var err error
+       for {
+               n := bytes.Index(s, a)
+               if n < 0 {
+                       break
+               }
+               ni, err = w.Write(s[:n])
+               nn += int64(ni)
+               if err != nil {
+                       return nn, err
+               }
+
+               s = s[n+len(a):]
+               n = bytes.Index(s, b)
+               if n < 0 {
+                       // cannot find end tag - just write it to the output.
+                       ni, _ = w.Write(a)
+                       nn += int64(ni)
+                       break
+               }
+
+               ni, err = f(w, unsafeBytes2String(s[:n]))
+               nn += int64(ni)
+               s = s[n+len(b):]
+       }
+       ni, err = w.Write(s)
+       nn += int64(ni)
+
+       return nn, err
+}
+
+// Execute substitutes template tags (placeholders) with the corresponding
+// values from the map m and writes the result to the given writer w.
+//
+// Substitution map m may contain values with the following types:
+//   * []byte - the fastest value type
+//   * string - convenient value type
+//   * TagFunc - flexible value type
+//
+// Returns the number of bytes written to w.
+//
+// This function is optimized for constantly changing templates.
+// Use Template.Execute for frozen templates.
+func Execute(template, startTag, endTag string, w io.Writer, m map[string]interface{}) (int64, error) {
+       return ExecuteFunc(template, startTag, endTag, w, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
+}
+
+// ExecuteFuncString calls f on each template tag (placeholder) occurrence
+// and substitutes it with the data written to TagFunc's w.
+//
+// Returns the resulting string.
+//
+// This function is optimized for constantly changing templates.
+// Use Template.ExecuteFuncString for frozen templates.
+func ExecuteFuncString(template, startTag, endTag string, f TagFunc) string {
+       tagsCount := bytes.Count(unsafeString2Bytes(template), unsafeString2Bytes(startTag))
+       if tagsCount == 0 {
+               return template
+       }
+
+       bb := byteBufferPool.Get()
+       if _, err := ExecuteFunc(template, startTag, endTag, bb, f); err != nil {
+               panic(fmt.Sprintf("unexpected error: %s", err))
+       }
+       s := string(bb.B)
+       bb.Reset()
+       byteBufferPool.Put(bb)
+       return s
+}
+
+var byteBufferPool bytebufferpool.Pool
+
+// ExecuteString substitutes template tags (placeholders) with the corresponding
+// values from the map m and returns the result.
+//
+// Substitution map m may contain values with the following types:
+//   * []byte - the fastest value type
+//   * string - convenient value type
+//   * TagFunc - flexible value type
+//
+// This function is optimized for constantly changing templates.
+// Use Template.ExecuteString for frozen templates.
+func ExecuteString(template, startTag, endTag string, m map[string]interface{}) string {
+       return ExecuteFuncString(template, startTag, endTag, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
+}
+
+// Template implements simple template engine, which can be used for fast
+// tags' (aka placeholders) substitution.
+type Template struct {
+       template string
+       startTag string
+       endTag   string
+
+       texts          [][]byte
+       tags           []string
+       byteBufferPool bytebufferpool.Pool
+}
+
+// New parses the given template using the given startTag and endTag
+// as tag start and tag end.
+//
+// The returned template can be executed by concurrently running goroutines
+// using Execute* methods.
+//
+// New panics if the given template cannot be parsed. Use NewTemplate instead
+// if template may contain errors.
+func New(template, startTag, endTag string) *Template {
+       t, err := NewTemplate(template, startTag, endTag)
+       if err != nil {
+               panic(err)
+       }
+       return t
+}
+
+// NewTemplate parses the given template using the given startTag and endTag
+// as tag start and tag end.
+//
+// The returned template can be executed by concurrently running goroutines
+// using Execute* methods.
+func NewTemplate(template, startTag, endTag string) (*Template, error) {
+       var t Template
+       err := t.Reset(template, startTag, endTag)
+       if err != nil {
+               return nil, err
+       }
+       return &t, nil
+}
+
+// TagFunc can be used as a substitution value in the map passed to Execute*.
+// Execute* functions pass tag (placeholder) name in 'tag' argument.
+//
+// TagFunc must be safe to call from concurrently running goroutines.
+//
+// TagFunc must write contents to w and return the number of bytes written.
+type TagFunc func(w io.Writer, tag string) (int, error)
+
+// Reset resets the template t to new one defined by
+// template, startTag and endTag.
+//
+// Reset allows Template object re-use.
+//
+// Reset may be called only if no other goroutines call t methods at the moment.
+func (t *Template) Reset(template, startTag, endTag string) error {
+       // Keep these vars in t, so GC won't collect them and won't break
+       // vars derived via unsafe*
+       t.template = template
+       t.startTag = startTag
+       t.endTag = endTag
+       t.texts = t.texts[:0]
+       t.tags = t.tags[:0]
+
+       if len(startTag) == 0 {
+               panic("startTag cannot be empty")
+       }
+       if len(endTag) == 0 {
+               panic("endTag cannot be empty")
+       }
+
+       s := unsafeString2Bytes(template)
+       a := unsafeString2Bytes(startTag)
+       b := unsafeString2Bytes(endTag)
+
+       tagsCount := bytes.Count(s, a)
+       if tagsCount == 0 {
+               return nil
+       }
+
+       if tagsCount+1 > cap(t.texts) {
+               t.texts = make([][]byte, 0, tagsCount+1)
+       }
+       if tagsCount > cap(t.tags) {
+               t.tags = make([]string, 0, tagsCount)
+       }
+
+       for {
+               n := bytes.Index(s, a)
+               if n < 0 {
+                       t.texts = append(t.texts, s)
+                       break
+               }
+               t.texts = append(t.texts, s[:n])
+
+               s = s[n+len(a):]
+               n = bytes.Index(s, b)
+               if n < 0 {
+                       return fmt.Errorf("Cannot find end tag=%q in the template=%q starting from %q", endTag, template, s)
+               }
+
+               t.tags = append(t.tags, unsafeBytes2String(s[:n]))
+               s = s[n+len(b):]
+       }
+
+       return nil
+}
+
+// ExecuteFunc calls f on each template tag (placeholder) occurrence.
+//
+// Returns the number of bytes written to w.
+//
+// This function is optimized for frozen templates.
+// Use ExecuteFunc for constantly changing templates.
+func (t *Template) ExecuteFunc(w io.Writer, f TagFunc) (int64, error) {
+       var nn int64
+
+       n := len(t.texts) - 1
+       if n == -1 {
+               ni, err := w.Write(unsafeString2Bytes(t.template))
+               return int64(ni), err
+       }
+
+       for i := 0; i < n; i++ {
+               ni, err := w.Write(t.texts[i])
+               nn += int64(ni)
+               if err != nil {
+                       return nn, err
+               }
+
+               ni, err = f(w, t.tags[i])
+               nn += int64(ni)
+               if err != nil {
+                       return nn, err
+               }
+       }
+       ni, err := w.Write(t.texts[n])
+       nn += int64(ni)
+       return nn, err
+}
+
+// Execute substitutes template tags (placeholders) with the corresponding
+// values from the map m and writes the result to the given writer w.
+//
+// Substitution map m may contain values with the following types:
+//   * []byte - the fastest value type
+//   * string - convenient value type
+//   * TagFunc - flexible value type
+//
+// Returns the number of bytes written to w.
+func (t *Template) Execute(w io.Writer, m map[string]interface{}) (int64, error) {
+       return t.ExecuteFunc(w, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
+}
+
+// ExecuteFuncString calls f on each template tag (placeholder) occurrence
+// and substitutes it with the data written to TagFunc's w.
+//
+// Returns the resulting string.
+//
+// This function is optimized for frozen templates.
+// Use ExecuteFuncString for constantly changing templates.
+func (t *Template) ExecuteFuncString(f TagFunc) string {
+       bb := t.byteBufferPool.Get()
+       if _, err := t.ExecuteFunc(bb, f); err != nil {
+               panic(fmt.Sprintf("unexpected error: %s", err))
+       }
+       s := string(bb.Bytes())
+       bb.Reset()
+       t.byteBufferPool.Put(bb)
+       return s
+}
+
+// ExecuteString substitutes template tags (placeholders) with the corresponding
+// values from the map m and returns the result.
+//
+// Substitution map m may contain values with the following types:
+//   * []byte - the fastest value type
+//   * string - convenient value type
+//   * TagFunc - flexible value type
+//
+// This function is optimized for frozen templates.
+// Use ExecuteString for constantly changing templates.
+func (t *Template) ExecuteString(m map[string]interface{}) string {
+       return t.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
+}
+
+func stdTagFunc(w io.Writer, tag string, m map[string]interface{}) (int, error) {
+       v := m[tag]
+       if v == nil {
+               return 0, nil
+       }
+       switch value := v.(type) {
+       case []byte:
+               return w.Write(value)
+       case string:
+               return w.Write([]byte(value))
+       case TagFunc:
+               return value(w, tag)
+       default:
+               panic(fmt.Sprintf("tag=%q contains unexpected value type=%#v. Expected []byte, string or TagFunc", tag, v))
+       }
+}