OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [strings/] [replace.go] - Rev 867

Go to most recent revision | Compare with Previous | Blame | View Log

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package strings

import "io"

// A Replacer replaces a list of strings with replacements.
type Replacer struct {
        r replacer
}

// replacer is the interface that a replacement algorithm needs to implement.
type replacer interface {
        Replace(s string) string
        WriteString(w io.Writer, s string) (n int, err error)
}

// byteBitmap represents bytes which are sought for replacement.
// byteBitmap is 256 bits wide, with a bit set for each old byte to be
// replaced.
type byteBitmap [256 / 32]uint32

func (m *byteBitmap) set(b byte) {
        m[b>>5] |= uint32(1 << (b & 31))
}

// NewReplacer returns a new Replacer from a list of old, new string pairs.
// Replacements are performed in order, without overlapping matches.
func NewReplacer(oldnew ...string) *Replacer {
        if len(oldnew)%2 == 1 {
                panic("strings.NewReplacer: odd argument count")
        }

        // Possible implementations.
        var (
                bb  byteReplacer
                bs  byteStringReplacer
                gen genericReplacer
        )

        allOldBytes, allNewBytes := true, true
        for len(oldnew) > 0 {
                old, new := oldnew[0], oldnew[1]
                oldnew = oldnew[2:]
                if len(old) != 1 {
                        allOldBytes = false
                }
                if len(new) != 1 {
                        allNewBytes = false
                }

                // generic
                gen.p = append(gen.p, pair{old, new})

                // byte -> string
                if allOldBytes {
                        bs.old.set(old[0])
                        bs.new[old[0]] = []byte(new)
                }

                // byte -> byte
                if allOldBytes && allNewBytes {
                        bb.old.set(old[0])
                        bb.new[old[0]] = new[0]
                }
        }

        if allOldBytes && allNewBytes {
                return &Replacer{r: &bb}
        }
        if allOldBytes {
                return &Replacer{r: &bs}
        }
        return &Replacer{r: &gen}
}

// Replace returns a copy of s with all replacements performed.
func (r *Replacer) Replace(s string) string {
        return r.r.Replace(s)
}

// WriteString writes s to w with all replacements performed.
func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error) {
        return r.r.WriteString(w, s)
}

// genericReplacer is the fully generic (and least optimized) algorithm.
// It's used as a fallback when nothing faster can be used.
type genericReplacer struct {
        p []pair
}

type pair struct{ old, new string }

type appendSliceWriter struct {
        b []byte
}

func (w *appendSliceWriter) Write(p []byte) (int, error) {
        w.b = append(w.b, p...)
        return len(p), nil
}

func (r *genericReplacer) Replace(s string) string {
        // TODO(bradfitz): optimized version
        n, _ := r.WriteString(discard, s)
        w := appendSliceWriter{make([]byte, 0, n)}
        r.WriteString(&w, s)
        return string(w.b)
}

func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) {
        lastEmpty := false // the last replacement was of the empty string
Input:
        // TODO(bradfitz): optimized version
        for i := 0; i < len(s); {
                for _, p := range r.p {
                        if p.old == "" && lastEmpty {
                                // Don't let old match twice in a row.
                                // (it doesn't advance the input and
                                // would otherwise loop forever)
                                continue
                        }
                        if HasPrefix(s[i:], p.old) {
                                if p.new != "" {
                                        wn, err := w.Write([]byte(p.new))
                                        n += wn
                                        if err != nil {
                                                return n, err
                                        }
                                }
                                i += len(p.old)
                                lastEmpty = p.old == ""
                                continue Input
                        }
                }
                wn, err := w.Write([]byte{s[i]})
                n += wn
                if err != nil {
                        return n, err
                }
                i++
        }

        // Final empty match at end.
        for _, p := range r.p {
                if p.old == "" {
                        if p.new != "" {
                                wn, err := w.Write([]byte(p.new))
                                n += wn
                                if err != nil {
                                        return n, err
                                }
                        }
                        break
                }
        }

        return n, nil
}

// byteReplacer is the implementation that's used when all the "old"
// and "new" values are single ASCII bytes.
type byteReplacer struct {
        // old has a bit set for each old byte that should be replaced.
        old byteBitmap

        // replacement byte, indexed by old byte. only valid if
        // corresponding old bit is set.
        new [256]byte
}

func (r *byteReplacer) Replace(s string) string {
        var buf []byte // lazily allocated
        for i := 0; i < len(s); i++ {
                b := s[i]
                if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
                        if buf == nil {
                                buf = []byte(s)
                        }
                        buf[i] = r.new[b]
                }
        }
        if buf == nil {
                return s
        }
        return string(buf)
}

func (r *byteReplacer) WriteString(w io.Writer, s string) (n int, err error) {
        // TODO(bradfitz): use io.WriteString with slices of s, avoiding allocation.
        bufsize := 32 << 10
        if len(s) < bufsize {
                bufsize = len(s)
        }
        buf := make([]byte, bufsize)

        for len(s) > 0 {
                ncopy := copy(buf, s[:])
                s = s[ncopy:]
                for i, b := range buf[:ncopy] {
                        if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
                                buf[i] = r.new[b]
                        }
                }
                wn, err := w.Write(buf[:ncopy])
                n += wn
                if err != nil {
                        return n, err
                }
        }
        return n, nil
}

// byteStringReplacer is the implementation that's used when all the
// "old" values are single ASCII bytes but the "new" values vary in
// size.
type byteStringReplacer struct {
        // old has a bit set for each old byte that should be replaced.
        old byteBitmap

        // replacement string, indexed by old byte. only valid if
        // corresponding old bit is set.
        new [256][]byte
}

func (r *byteStringReplacer) Replace(s string) string {
        newSize := 0
        anyChanges := false
        for i := 0; i < len(s); i++ {
                b := s[i]
                if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
                        anyChanges = true
                        newSize += len(r.new[b])
                } else {
                        newSize++
                }
        }
        if !anyChanges {
                return s
        }
        buf := make([]byte, newSize)
        bi := buf
        for i := 0; i < len(s); i++ {
                b := s[i]
                if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
                        n := copy(bi[:], r.new[b])
                        bi = bi[n:]
                } else {
                        bi[0] = b
                        bi = bi[1:]
                }
        }
        return string(buf)
}

// WriteString maintains one buffer that's at most 32KB.  The bytes in
// s are enumerated and the buffer is filled.  If it reaches its
// capacity or a byte has a replacement, the buffer is flushed to w.
func (r *byteStringReplacer) WriteString(w io.Writer, s string) (n int, err error) {
        // TODO(bradfitz): use io.WriteString with slices of s instead.
        bufsize := 32 << 10
        if len(s) < bufsize {
                bufsize = len(s)
        }
        buf := make([]byte, bufsize)
        bi := buf[:0]

        for i := 0; i < len(s); i++ {
                b := s[i]
                var new []byte
                if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
                        new = r.new[b]
                } else {
                        bi = append(bi, b)
                }
                if len(bi) == cap(bi) || (len(bi) > 0 && len(new) > 0) {
                        nw, err := w.Write(bi)
                        n += nw
                        if err != nil {
                                return n, err
                        }
                        bi = buf[:0]
                }
                if len(new) > 0 {
                        nw, err := w.Write(new)
                        n += nw
                        if err != nil {
                                return n, err
                        }
                }
        }
        if len(bi) > 0 {
                nw, err := w.Write(bi)
                n += nw
                if err != nil {
                        return n, err
                }
        }
        return n, nil
}

// strings is too low-level to import io/ioutil
var discard io.Writer = devNull(0)

type devNull int

func (devNull) Write(p []byte) (int, error) {
        return len(p), nil
}

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.