DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (27a812186ff4)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef vm_StringBuffer_h
#define vm_StringBuffer_h

#include "mozilla/DebugOnly.h"

#include "jscntxt.h"

#include "js/Vector.h"

namespace js {

/*
 * String builder that eagerly checks for over-allocation past the maximum
 * string length.
 *
 * Any operation which would exceed the maximum string length causes an
 * exception report on the context and results in a failed return value.
 *
 * Well-sized extractions (which waste no more than 1/4 of their char
 * buffer space) are guaranteed for strings built by this interface.
 * See |extractWellSized|.
 */
class StringBuffer
{
    /* cb's buffer is taken by the new string so use ContextAllocPolicy. */
    typedef Vector<jschar, 32, ContextAllocPolicy> CharBuffer;

    CharBuffer cb;

    ExclusiveContext* context() const {
        return cb.allocPolicy().context()->asExclusiveContext();
    }

    StringBuffer(const StringBuffer& other) MOZ_DELETE;
    void operator=(const StringBuffer& other) MOZ_DELETE;

  public:
    explicit StringBuffer(ExclusiveContext* cx) : cb(cx) { }

    inline bool reserve(size_t len) { return cb.reserve(len); }
    inline bool resize(size_t len) { return cb.resize(len); }
    inline bool append(const jschar c) { return cb.append(c); }
    inline bool append(const jschar* chars, size_t len) { return cb.append(chars, len); }
    inline bool append(const JS::ConstCharPtr chars, size_t len) { return cb.append(chars.get(), len); }
    inline bool append(const jschar* begin, const jschar* end) { return cb.append(begin, end); }
    inline bool append(JSString* str);
    inline bool append(JSLinearString* str);
    inline bool appendN(const jschar c, size_t n) { return cb.appendN(c, n); }
    inline bool appendInflated(const char* cstr, size_t len);

    template <size_t ArrayLength>
    bool append(const char (&array)[ArrayLength]) {
        return cb.append(array, array + ArrayLength - 1); /* No trailing '\0'. */
    }

    /* Infallible variants usable when the corresponding space is reserved. */
    void infallibleAppend(const jschar c) {
        cb.infallibleAppend(c);
    }
    void infallibleAppend(const jschar* chars, size_t len) {
        cb.infallibleAppend(chars, len);
    }
    void infallibleAppend(const JS::ConstCharPtr chars, size_t len) {
        cb.infallibleAppend(chars.get(), len);
    }
    void infallibleAppend(const jschar* begin, const jschar* end) {
        cb.infallibleAppend(begin, end);
    }
    void infallibleAppendN(const jschar c, size_t n) {
        cb.infallibleAppendN(c, n);
    }

    jschar* begin() { return cb.begin(); }
    jschar* end() { return cb.end(); }
    const jschar* begin() const { return cb.begin(); }
    const jschar* end() const { return cb.end(); }
    bool empty() const { return cb.empty(); }
    size_t length() const { return cb.length(); }

    /*
     * Creates a string from the characters in this buffer, then (regardless
     * whether string creation succeeded or failed) empties the buffer.
     */
    JSFlatString* finishString();

    /* Identical to finishString() except that an atom is created. */
    JSAtom* finishAtom();

    /*
     * Creates a raw string from the characters in this buffer.  The string is
     * exactly the characters in this buffer: it is *not* null-terminated
     * unless the last appended character was |(jschar)0|.
     */
    jschar* extractWellSized();
};

inline bool
StringBuffer::append(JSLinearString* str)
{
    JS::Anchor<JSString*> anch(str);
    return cb.append(str->chars(), str->length());
}

inline bool
StringBuffer::append(JSString* str)
{
    JSLinearString* linear = str->ensureLinear(context());
    if (!linear)
        return false;
    return append(linear);
}

inline bool
StringBuffer::appendInflated(const char* cstr, size_t cstrlen)
{
    size_t lengthBefore = length();
    if (!cb.growByUninitialized(cstrlen))
        return false;
    InflateStringToBuffer(cstr, cstrlen, begin() + lengthBefore);
    return true;
}

/* ES5 9.8 ToString, appending the result to the string buffer. */
extern bool
ValueToStringBufferSlow(JSContext* cx, const Value& v, StringBuffer& sb);

inline bool
ValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb)
{
    if (v.isString())
        return sb.append(v.toString());

    return ValueToStringBufferSlow(cx, v, sb);
}

/* ES5 9.8 ToString for booleans, appending the result to the string buffer. */
inline bool
BooleanToStringBuffer(bool b, StringBuffer& sb)
{
    return b ? sb.append("true") : sb.append("false");
}

}  /* namespace js */

#endif /* vm_StringBuffer_h */