<commit_before>#include "clay.hpp"
#include <cstdio>
#include <cstdlib>
#include <cstdarg>

bool shouldPrintFullMatchErrors;

//
// invoke stack - a compilation call stack
//

static vector<CompileContextEntry> contextStack;

static const unsigned RECURSION_WARNING_LEVEL = 1000;

void pushCompileContext(ObjectPtr obj) {
    if (contextStack.size() >= RECURSION_WARNING_LEVEL)
        warning("potential runaway recursion");
    if (!contextStack.empty())
        contextStack.back().location = topLocation();
    contextStack.push_back(CompileContextEntry(obj));
}

void pushCompileContext(ObjectPtr obj, const vector<ObjectPtr> &params) {
    if (contextStack.size() >= RECURSION_WARNING_LEVEL)
        warning("potential runaway recursion");
    if (!contextStack.empty())
        contextStack.back().location = topLocation();
    contextStack.push_back(CompileContextEntry(obj, params));
}

void pushCompileContext(ObjectPtr obj, const vector<ObjectPtr> &params, const vector<unsigned> &dispatchIndices) {
    if (contextStack.size() >= RECURSION_WARNING_LEVEL)
        warning("potential runaway recursion");
    if (!contextStack.empty())
        contextStack.back().location = topLocation();
    contextStack.push_back(CompileContextEntry(obj, params, dispatchIndices));
}

void popCompileContext() {
    contextStack.pop_back();
}

vector<CompileContextEntry> getCompileContext() {
    return contextStack;
}

void setCompileContext(const vector<CompileContextEntry> &x) {
    contextStack = x;
}

//
// source location of the current item being processed
//

static vector<LocationPtr> errorLocations;

void pushLocation(LocationPtr location) {
    errorLocations.push_back(location);
}

void popLocation() {
    errorLocations.pop_back();
}

LocationPtr topLocation() {
    vector<LocationPtr>::iterator i, begin;
    i = errorLocations.end();
    begin = errorLocations.begin();
    while (i != begin) {
        --i;
        if (i->ptr()) return *i;
    }
    return NULL;
}

//
// DebugPrinter
//

static vector<ObjectPtr> debugStack;

int DebugPrinter::indent = 0;

DebugPrinter::DebugPrinter(ObjectPtr obj)
    : obj(obj)
{
    for (int i = 0; i < indent; ++i)
        std::cout << ' ';
    std::cout << "BEGIN - " << obj << '\n';
    ++indent;
    debugStack.push_back(obj);
}

DebugPrinter::~DebugPrinter()
{
    debugStack.pop_back();
    --indent;
    for (int i = 0; i < indent; ++i)
        std::cout << ' ';
    std::cout << "DONE - " << obj << '\n';
}

//
// report error
//

void computeLineCol(LocationPtr location,
                    int &line,
                    int &column,
                    int &tabColumn) {
    char *p = location->source->data;
    char *end = p + location->offset;
    line = column = tabColumn = 0;
    for (; p != end; ++p) {
        ++column;
        ++tabColumn;
        if (*p == '\n') {
            ++line;
            column = 0;
            tabColumn = 0;
        }
        else if (*p == '\t') {
            tabColumn += 7;
        }
    }
}

static void splitLines(SourcePtr source, vector<string> &lines) {
    lines.push_back(string());
    char *p = source->data;
    char *end = p + source->size;
    for (; p != end; ++p) {
        lines.back().push_back(*p);
        if (*p == '\n')
            lines.push_back(string());
    }
}

static bool endsWithNewline(const string& s) {
    if (s.size() == 0) return false;
    return s[s.size()-1] == '\n';
}

static void displayLocation(LocationPtr location, int &line, int &column) {
    int tabColumn;
    computeLineCol(location, line, column, tabColumn);
    vector<string> lines;
    splitLines(location->source, lines);
    fprintf(stderr, "###############################\n");
    for (int i = line-2; i <= line+2; ++i) {
        if ((i < 0) || (i >= (int)lines.size()))
            continue;
        fprintf(stderr, "%s", lines[i].c_str());
        if (!endsWithNewline(lines[i]))
            fprintf(stderr, "\n");
        if (i == line) {
            for (int j = 0; j < tabColumn; ++j)
                fprintf(stderr, "-");
            fprintf(stderr, "^\n");
        }
    }
    fprintf(stderr, "###############################\n");
}

static void displayCompileContext() {
    if (contextStack.empty())
        return;
    fprintf(stderr, "\n");
    fprintf(stderr, "compilation context: \n");
    for (unsigned i = contextStack.size(); i > 0; --i) {
        ObjectPtr obj = contextStack[i-1].callable;
        const vector<ObjectPtr> &params = contextStack[i-1].params;

        if (i >= 1 && contextStack[i-1].location != NULL) {
            ostringstream locout;
            printFileLineCol(locout, contextStack[i-1].location);
            fprintf(stderr, "  %s:\n", locout.str().c_str());
        }

        ostringstream sout;
        if (obj->objKind == GLOBAL_VARIABLE) {
            sout << "global ";
            printName(sout, obj);
            if (!params.empty()) {
                sout << "[";
                printNameList(sout, params);
                sout << "]";
            }
        }
        else {
            printName(sout, obj);
            if (contextStack[i-1].hasParams) {
                sout << "(";
                printNameList(sout, params, contextStack[i-1].dispatchIndices);
                sout << ")";
            }
        }
        fprintf(stderr, "    %s\n", sout.str().c_str());
    }
}

static void displayDebugStack() {
    if (debugStack.empty())
        return;
    fprintf(stderr, "\n");
    fprintf(stderr, "debug stack: \n");
    for (unsigned i = debugStack.size(); i > 0; --i) {
        ostringstream sout;
        sout << debugStack[i-1];
        fprintf(stderr, "  %s\n", sout.str().c_str());
    }
}

static bool abortOnError = false;

void setAbortOnError(bool flag) {
    abortOnError = flag;
}

void displayError(const string &msg, const string &kind) {
    LocationPtr location = topLocation();
    if (location.ptr()) {
        int line, column;
        displayLocation(location, line, column);
        fprintf(stderr, "%s(%d,%d): %s: %s\n",
                location->source->fileName.c_str(),
                line+1, column, kind.c_str(), msg.c_str());
        displayCompileContext();
        displayDebugStack();
    }
    else {
        fprintf(stderr, "error: %s\n", msg.c_str());
    }
}

void warning(const string &msg) {
    displayError(msg, "warning");
}

void error(const string &msg) {
    displayError(msg, "error");
    if (abortOnError)
        abort();
    else
        exit(-1);
}

void fmtError(const char *fmt, ...) {
    va_list ap;
    char s[256];
    va_start(ap, fmt);
    vsnprintf(s, sizeof(s)-1, fmt, ap);
    va_end(ap);
    error(s);
}

void argumentError(unsigned int index, const string &msg) {
    ostringstream sout;
    sout << "argument " << (index+1) << ": " << msg;
    error(sout.str());
}

static const char *valuesStr(int n) {
    if (n == 1)
        return "value";
    else
        return "values";
}

void arityError(int expected, int received) {
    ostringstream sout;
    sout << "expected " << expected << " " << valuesStr(expected);
    sout << ", but received " << received << " " << valuesStr(received);
    error(sout.str());
}

void arityError2(int minExpected, int received) {
    ostringstream sout;
    sout << "expected atleast " << minExpected
         << " " << valuesStr(minExpected);
    sout << ", but received " << received << " " << valuesStr(received);
    error(sout.str());
}

void ensureArity(MultiStaticPtr args, unsigned int size) {
    if (args->size() != size)
        arityError(size, args->size());
}

void ensureArity(MultiEValuePtr args, unsigned int size) {
    if (args->size() != size)
        arityError(size, args->size());
}

void ensureArity(MultiPValuePtr args, unsigned int size) {
    if (args->size() != size)
        arityError(size, args->size());
}

void ensureArity(MultiCValuePtr args, unsigned int size) {
    if (args->size() != size)
        arityError(size, args->size());
}

void arityMismatchError(int leftArity, int rightArity) {
    ostringstream sout;
    sout << "arity mismatch. ";
    sout << "left-side has " << leftArity << " " << valuesStr(leftArity);
    sout << ", whereas right-side has " << rightArity
         << " " << valuesStr(rightArity);
}

static string typeErrorMessage(const string &expected,
                               TypePtr receivedType) {
    ostringstream sout;
    sout << "expected " << expected << ", "
         << "but received " << receivedType << " type";
    return sout.str();
}

static string typeErrorMessage(TypePtr expectedType,
                               TypePtr receivedType) {
    ostringstream sout;
    sout << expectedType << " type";
    return typeErrorMessage(sout.str(), receivedType);
}

void typeError(const string &expected, TypePtr receivedType) {
    error(typeErrorMessage(expected, receivedType));
}

void typeError(TypePtr expectedType, TypePtr receivedType) {
    error(typeErrorMessage(expectedType, receivedType));
}

void argumentTypeError(unsigned int index,
                       const string &expected,
                       TypePtr receivedType) {
    argumentError(index, typeErrorMessage(expected, receivedType));
}

void argumentTypeError(unsigned int index,
                       TypePtr expectedType,
                       TypePtr receivedType) {
    argumentError(index, typeErrorMessage(expectedType, receivedType));
}

void indexRangeError(const string &kind,
                     size_t value,
                     size_t maxValue)
{
    ostringstream sout;
    sout << kind << " " << value << " is out of range. ";
    sout << "it should be less than " << maxValue;
    error(sout.str());
}

void argumentIndexRangeError(unsigned int index,
                             const string &kind,
                             size_t value,
                             size_t maxValue)
{
    ostringstream sout;
    sout << kind << " " << value << " is out of range. ";
    sout << "it should be less than " << maxValue;
    argumentError(index, sout.str());
}

void invalidStaticObjectError(ObjectPtr obj)
{
    ostringstream sout;
    sout << "invalid static object: " << obj;
    error(sout.str());
}

void argumentInvalidStaticObjectError(unsigned int index, ObjectPtr obj)
{
    ostringstream sout;
    sout << "invalid static object: " << obj;
    argumentError(index, sout.str());
}

void matchFailureError(MatchFailureError const &err)
{
    ostringstream sout;
    if (err.failedInterface)
        sout << "call does not conform to function interface";
    else
        sout << "no matching overload found";

    int hiddenPatternOverloads = 0;

    for (MatchFailureVector::const_iterator i = err.failures.begin();
         i != err.failures.end();
         ++i)
    {
        OverloadPtr overload = i->first;
        if (!shouldPrintFullMatchErrors && overload->nameIsPattern) {
            ++hiddenPatternOverloads;
            continue;
        }
        sout << "\n    ";
        LocationPtr location = overload->location;
        int line, column, tabColumn;
        computeLineCol(location, line, column, tabColumn);
        sout << location->source->fileName.c_str()
            << "(" << line+1 << "," << column << ")"
            << "\n        ";
        printMatchError(sout, i->second);
    }
    if (hiddenPatternOverloads > 0)
        sout << "\n    " << hiddenPatternOverloads << " universal overloads not shown (show with -full-match-errors option)";
    error(sout.str());
}

void printFileLineCol(ostream &out, LocationPtr location)
{
    int line, column, tabColumn;
    computeLineCol(location, line, column, tabColumn);
    out << location->source->fileName << "(" << line+1 << "," << column << ")";
}
<commit_msg>hide redundant location info for top context frame<commit_after>#include "clay.hpp"
#include <cstdio>
#include <cstdlib>
#include <cstdarg>

bool shouldPrintFullMatchErrors;

//
// invoke stack - a compilation call stack
//

static vector<CompileContextEntry> contextStack;

static const unsigned RECURSION_WARNING_LEVEL = 1000;

void pushCompileContext(ObjectPtr obj) {
    if (contextStack.size() >= RECURSION_WARNING_LEVEL)
        warning("potential runaway recursion");
    if (!contextStack.empty())
        contextStack.back().location = topLocation();
    contextStack.push_back(CompileContextEntry(obj));
}

void pushCompileContext(ObjectPtr obj, const vector<ObjectPtr> &params) {
    if (contextStack.size() >= RECURSION_WARNING_LEVEL)
        warning("potential runaway recursion");
    if (!contextStack.empty())
        contextStack.back().location = topLocation();
    contextStack.push_back(CompileContextEntry(obj, params));
}

void pushCompileContext(ObjectPtr obj, const vector<ObjectPtr> &params, const vector<unsigned> &dispatchIndices) {
    if (contextStack.size() >= RECURSION_WARNING_LEVEL)
        warning("potential runaway recursion");
    if (!contextStack.empty())
        contextStack.back().location = topLocation();
    contextStack.push_back(CompileContextEntry(obj, params, dispatchIndices));
}

void popCompileContext() {
    contextStack.pop_back();
}

vector<CompileContextEntry> getCompileContext() {
    return contextStack;
}

void setCompileContext(const vector<CompileContextEntry> &x) {
    contextStack = x;
}

//
// source location of the current item being processed
//

static vector<LocationPtr> errorLocations;

void pushLocation(LocationPtr location) {
    errorLocations.push_back(location);
}

void popLocation() {
    errorLocations.pop_back();
}

LocationPtr topLocation() {
    vector<LocationPtr>::iterator i, begin;
    i = errorLocations.end();
    begin = errorLocations.begin();
    while (i != begin) {
        --i;
        if (i->ptr()) return *i;
    }
    return NULL;
}

//
// DebugPrinter
//

static vector<ObjectPtr> debugStack;

int DebugPrinter::indent = 0;

DebugPrinter::DebugPrinter(ObjectPtr obj)
    : obj(obj)
{
    for (int i = 0; i < indent; ++i)
        std::cout << ' ';
    std::cout << "BEGIN - " << obj << '\n';
    ++indent;
    debugStack.push_back(obj);
}

DebugPrinter::~DebugPrinter()
{
    debugStack.pop_back();
    --indent;
    for (int i = 0; i < indent; ++i)
        std::cout << ' ';
    std::cout << "DONE - " << obj << '\n';
}

//
// report error
//

void computeLineCol(LocationPtr location,
                    int &line,
                    int &column,
                    int &tabColumn) {
    char *p = location->source->data;
    char *end = p + location->offset;
    line = column = tabColumn = 0;
    for (; p != end; ++p) {
        ++column;
        ++tabColumn;
        if (*p == '\n') {
            ++line;
            column = 0;
            tabColumn = 0;
        }
        else if (*p == '\t') {
            tabColumn += 7;
        }
    }
}

static void splitLines(SourcePtr source, vector<string> &lines) {
    lines.push_back(string());
    char *p = source->data;
    char *end = p + source->size;
    for (; p != end; ++p) {
        lines.back().push_back(*p);
        if (*p == '\n')
            lines.push_back(string());
    }
}

static bool endsWithNewline(const string& s) {
    if (s.size() == 0) return false;
    return s[s.size()-1] == '\n';
}

static void displayLocation(LocationPtr location, int &line, int &column) {
    int tabColumn;
    computeLineCol(location, line, column, tabColumn);
    vector<string> lines;
    splitLines(location->source, lines);
    fprintf(stderr, "###############################\n");
    for (int i = line-2; i <= line+2; ++i) {
        if ((i < 0) || (i >= (int)lines.size()))
            continue;
        fprintf(stderr, "%s", lines[i].c_str());
        if (!endsWithNewline(lines[i]))
            fprintf(stderr, "\n");
        if (i == line) {
            for (int j = 0; j < tabColumn; ++j)
                fprintf(stderr, "-");
            fprintf(stderr, "^\n");
        }
    }
    fprintf(stderr, "###############################\n");
}

static void displayCompileContext() {
    if (contextStack.empty())
        return;
    fprintf(stderr, "\n");
    fprintf(stderr, "compilation context: \n");
    for (unsigned i = contextStack.size(); i > 0; --i) {
        ObjectPtr obj = contextStack[i-1].callable;
        const vector<ObjectPtr> &params = contextStack[i-1].params;

        if (i < contextStack.size() && contextStack[i-1].location != NULL) {
            ostringstream locout;
            printFileLineCol(locout, contextStack[i-1].location);
            fprintf(stderr, "  %s:\n", locout.str().c_str());
        }

        ostringstream sout;
        if (obj->objKind == GLOBAL_VARIABLE) {
            sout << "global ";
            printName(sout, obj);
            if (!params.empty()) {
                sout << "[";
                printNameList(sout, params);
                sout << "]";
            }
        }
        else {
            printName(sout, obj);
            if (contextStack[i-1].hasParams) {
                sout << "(";
                printNameList(sout, params, contextStack[i-1].dispatchIndices);
                sout << ")";
            }
        }
        fprintf(stderr, "    %s\n", sout.str().c_str());
    }
}

static void displayDebugStack() {
    if (debugStack.empty())
        return;
    fprintf(stderr, "\n");
    fprintf(stderr, "debug stack: \n");
    for (unsigned i = debugStack.size(); i > 0; --i) {
        ostringstream sout;
        sout << debugStack[i-1];
        fprintf(stderr, "  %s\n", sout.str().c_str());
    }
}

static bool abortOnError = false;

void setAbortOnError(bool flag) {
    abortOnError = flag;
}

void displayError(const string &msg, const string &kind) {
    LocationPtr location = topLocation();
    if (location.ptr()) {
        int line, column;
        displayLocation(location, line, column);
        fprintf(stderr, "%s(%d,%d): %s: %s\n",
                location->source->fileName.c_str(),
                line+1, column, kind.c_str(), msg.c_str());
        displayCompileContext();
        displayDebugStack();
    }
    else {
        fprintf(stderr, "error: %s\n", msg.c_str());
    }
}

void warning(const string &msg) {
    displayError(msg, "warning");
}

void error(const string &msg) {
    displayError(msg, "error");
    if (abortOnError)
        abort();
    else
        exit(-1);
}

void fmtError(const char *fmt, ...) {
    va_list ap;
    char s[256];
    va_start(ap, fmt);
    vsnprintf(s, sizeof(s)-1, fmt, ap);
    va_end(ap);
    error(s);
}

void argumentError(unsigned int index, const string &msg) {
    ostringstream sout;
    sout << "argument " << (index+1) << ": " << msg;
    error(sout.str());
}

static const char *valuesStr(int n) {
    if (n == 1)
        return "value";
    else
        return "values";
}

void arityError(int expected, int received) {
    ostringstream sout;
    sout << "expected " << expected << " " << valuesStr(expected);
    sout << ", but received " << received << " " << valuesStr(received);
    error(sout.str());
}

void arityError2(int minExpected, int received) {
    ostringstream sout;
    sout << "expected atleast " << minExpected
         << " " << valuesStr(minExpected);
    sout << ", but received " << received << " " << valuesStr(received);
    error(sout.str());
}

void ensureArity(MultiStaticPtr args, unsigned int size) {
    if (args->size() != size)
        arityError(size, args->size());
}

void ensureArity(MultiEValuePtr args, unsigned int size) {
    if (args->size() != size)
        arityError(size, args->size());
}

void ensureArity(MultiPValuePtr args, unsigned int size) {
    if (args->size() != size)
        arityError(size, args->size());
}

void ensureArity(MultiCValuePtr args, unsigned int size) {
    if (args->size() != size)
        arityError(size, args->size());
}

void arityMismatchError(int leftArity, int rightArity) {
    ostringstream sout;
    sout << "arity mismatch. ";
    sout << "left-side has " << leftArity << " " << valuesStr(leftArity);
    sout << ", whereas right-side has " << rightArity
         << " " << valuesStr(rightArity);
}

static string typeErrorMessage(const string &expected,
                               TypePtr receivedType) {
    ostringstream sout;
    sout << "expected " << expected << ", "
         << "but received " << receivedType << " type";
    return sout.str();
}

static string typeErrorMessage(TypePtr expectedType,
                               TypePtr receivedType) {
    ostringstream sout;
    sout << expectedType << " type";
    return typeErrorMessage(sout.str(), receivedType);
}

void typeError(const string &expected, TypePtr receivedType) {
    error(typeErrorMessage(expected, receivedType));
}

void typeError(TypePtr expectedType, TypePtr receivedType) {
    error(typeErrorMessage(expectedType, receivedType));
}

void argumentTypeError(unsigned int index,
                       const string &expected,
                       TypePtr receivedType) {
    argumentError(index, typeErrorMessage(expected, receivedType));
}

void argumentTypeError(unsigned int index,
                       TypePtr expectedType,
                       TypePtr receivedType) {
    argumentError(index, typeErrorMessage(expectedType, receivedType));
}

void indexRangeError(const string &kind,
                     size_t value,
                     size_t maxValue)
{
    ostringstream sout;
    sout << kind << " " << value << " is out of range. ";
    sout << "it should be less than " << maxValue;
    error(sout.str());
}

void argumentIndexRangeError(unsigned int index,
                             const string &kind,
                             size_t value,
                             size_t maxValue)
{
    ostringstream sout;
    sout << kind << " " << value << " is out of range. ";
    sout << "it should be less than " << maxValue;
    argumentError(index, sout.str());
}

void invalidStaticObjectError(ObjectPtr obj)
{
    ostringstream sout;
    sout << "invalid static object: " << obj;
    error(sout.str());
}

void argumentInvalidStaticObjectError(unsigned int index, ObjectPtr obj)
{
    ostringstream sout;
    sout << "invalid static object: " << obj;
    argumentError(index, sout.str());
}

void matchFailureError(MatchFailureError const &err)
{
    ostringstream sout;
    if (err.failedInterface)
        sout << "call does not conform to function interface";
    else
        sout << "no matching overload found";

    int hiddenPatternOverloads = 0;

    for (MatchFailureVector::const_iterator i = err.failures.begin();
         i != err.failures.end();
         ++i)
    {
        OverloadPtr overload = i->first;
        if (!shouldPrintFullMatchErrors && overload->nameIsPattern) {
            ++hiddenPatternOverloads;
            continue;
        }
        sout << "\n    ";
        LocationPtr location = overload->location;
        int line, column, tabColumn;
        computeLineCol(location, line, column, tabColumn);
        sout << location->source->fileName.c_str()
            << "(" << line+1 << "," << column << ")"
            << "\n        ";
        printMatchError(sout, i->second);
    }
    if (hiddenPatternOverloads > 0)
        sout << "\n    " << hiddenPatternOverloads << " universal overloads not shown (show with -full-match-errors option)";
    error(sout.str());
}

void printFileLineCol(ostream &out, LocationPtr location)
{
    int line, column, tabColumn;
    computeLineCol(location, line, column, tabColumn);
    out << location->source->fileName << "(" << line+1 << "," << column << ")";
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: itemconnect.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2004-08-02 16:26:36 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRUNTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRUNTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SFX_ITEMCONNECT_HXX
#include "itemconnect.hxx"
#endif

#include <boost/shared_ptr.hpp>
#include <list>

#ifndef _SFXITEMPOOL_HXX
#include <svtools/itempool.hxx>
#endif

// ============================================================================

namespace sfx {

// ============================================================================
// Helpers
// ============================================================================

namespace {

TriState lclConvertToTriState( bool bKnown, bool bIsKnownFlag, bool bIsUnknownFlag )
{
    return (bKnown && bIsKnownFlag) ? STATE_CHECK : ((!bKnown && bIsUnknownFlag) ? STATE_NOCHECK : STATE_DONTKNOW);
}

} // namespace

// ----------------------------------------------------------------------------

USHORT ItemWrapperHelper::GetWhichId( const SfxItemSet& rItemSet, USHORT nSlot )
{
    return rItemSet.GetPool()->GetWhich( nSlot );
}

bool ItemWrapperHelper::IsKnownItem( const SfxItemSet& rItemSet, USHORT nSlot )
{
    return rItemSet.GetItemState( GetWhichId( rItemSet, nSlot ), TRUE ) != SFX_ITEM_UNKNOWN;
}

const SfxPoolItem* ItemWrapperHelper::GetUniqueItem( const SfxItemSet& rItemSet, USHORT nSlot )
{
    USHORT nWhich = GetWhichId( rItemSet, nSlot );
    return (rItemSet.GetItemState( nWhich, TRUE ) >= SFX_ITEM_DEFAULT) ? rItemSet.GetItem( nWhich, TRUE ) : 0;
}

const SfxPoolItem& ItemWrapperHelper::GetDefaultItem( const SfxItemSet& rItemSet, USHORT nSlot )
{
    return rItemSet.GetPool()->GetDefaultItem( GetWhichId( rItemSet, nSlot ) );
}

void ItemWrapperHelper::RemoveDefaultItem( SfxItemSet& rDestSet, const SfxItemSet& rOldSet, USHORT nSlot )
{
    USHORT nWhich = GetWhichId( rDestSet, nSlot );
    if( rOldSet.GetItemState( nWhich, FALSE ) == SFX_ITEM_DEFAULT )
        rDestSet.ClearItem( nWhich );
}

// ============================================================================
// Base control wrapper classes
// ============================================================================

ControlWrapperBase::~ControlWrapperBase()
{
}

// ============================================================================
// Single control wrappers
// ============================================================================

DummyWindowWrapper::DummyWindowWrapper( Window& rWindow ) :
    SingleControlWrapperType( rWindow )
{
}

bool DummyWindowWrapper::IsControlDontKnow() const
{
    return false;
}

void DummyWindowWrapper::SetControlDontKnow( bool )
{
}

void* DummyWindowWrapper::GetControlValue() const
{
    return 0;
}

void DummyWindowWrapper::SetControlValue( void* )
{
}

// ----------------------------------------------------------------------------

CheckBoxWrapper::CheckBoxWrapper( CheckBox& rCheckBox ) :
        SingleControlWrapperType( rCheckBox )
{
}

bool CheckBoxWrapper::IsControlDontKnow() const
{
    return GetControl().GetState() == STATE_DONTKNOW;
}

void CheckBoxWrapper::SetControlDontKnow( bool bSet )
{
    GetControl().EnableTriState( bSet );
    GetControl().SetState( bSet ? STATE_DONTKNOW : STATE_NOCHECK );
}

BOOL CheckBoxWrapper::GetControlValue() const
{
    return GetControl().IsChecked();
}

void CheckBoxWrapper::SetControlValue( BOOL bValue )
{
    GetControl().Check( bValue );
}

// ----------------------------------------------------------------------------

EditWrapper::EditWrapper( Edit& rEdit ) :
        SingleControlWrapperType( rEdit )
{
}

bool EditWrapper::IsControlDontKnow() const
{
    // no "don't know" state - empty string is a valid value of an Edit
    return false;
}

void EditWrapper::SetControlDontKnow( bool bSet )
{
    if( bSet )
        GetControl().SetText( String() );
}

String EditWrapper::GetControlValue() const
{
    return GetControl().GetText();
}

void EditWrapper::SetControlValue( String aValue )
{
    GetControl().SetText( aValue );
}

// ----------------------------------------------------------------------------

bool ColorListBoxWrapper::IsControlDontKnow() const
{
    return GetControl().GetSelectEntryCount() == 0;
}

void ColorListBoxWrapper::SetControlDontKnow( bool bSet )
{
    if( bSet ) GetControl().SetNoSelection();
}

Color ColorListBoxWrapper::GetControlValue() const
{
    return GetControl().GetSelectEntryColor();
}

void ColorListBoxWrapper::SetControlValue( Color aColor )
{
    GetControl().SelectEntry( aColor );
}

// ============================================================================
// Multi control wrappers
// ============================================================================

typedef std::vector< ControlWrapperBase* >  ControlWrpVec;
typedef ControlWrpVec::iterator             ControlWrpVecI;
typedef ControlWrpVec::const_iterator       ControlWrpVecCI;

struct MultiControlWrapperHelper_Impl
{
    ControlWrpVec       maVec;
};

MultiControlWrapperHelper::MultiControlWrapperHelper() :
    mxImpl( new MultiControlWrapperHelper_Impl )
{
}

MultiControlWrapperHelper::~MultiControlWrapperHelper()
{
}

void MultiControlWrapperHelper::RegisterControlWrapper( ControlWrapperBase& rWrapper )
{
    mxImpl->maVec.push_back( &rWrapper );
}

void MultiControlWrapperHelper::ModifyControl( TriState eEnable, TriState eShow )
{
    for( ControlWrpVecI aIt = mxImpl->maVec.begin(), aEnd = mxImpl->maVec.end(); aIt != aEnd; ++aIt )
        (*aIt)->ModifyControl( eEnable, eShow );
}

bool MultiControlWrapperHelper::IsControlDontKnow() const
{
    bool bIs = !mxImpl->maVec.empty();
    for( ControlWrpVecCI aIt = mxImpl->maVec.begin(), aEnd = mxImpl->maVec.end(); bIs && (aIt != aEnd); ++aIt )
        bIs &= (*aIt)->IsControlDontKnow();
    return bIs;
}

void MultiControlWrapperHelper::SetControlDontKnow( bool bSet )
{
    for( ControlWrpVecI aIt = mxImpl->maVec.begin(), aEnd = mxImpl->maVec.end(); aIt != aEnd; ++aIt )
        (*aIt)->SetControlDontKnow( bSet );
}

// ============================================================================
// Base connection classes
// ============================================================================

ItemConnectionBase::ItemConnectionBase( ItemConnFlags nFlags ) :
    mnFlags( nFlags )
{
}

ItemConnectionBase::~ItemConnectionBase()
{
}

void ItemConnectionBase::Activate( bool bActive )
{
    if( bActive ) mnFlags &= ~ITEMCONN_INACTIVE; else mnFlags |= ITEMCONN_INACTIVE;
}

bool ItemConnectionBase::IsActive() const
{
    return !(mnFlags & ITEMCONN_INACTIVE);
}

void ItemConnectionBase::DoApplyFlags( const SfxItemSet& rItemSet )
{
    if( IsActive() )
        ApplyFlags( rItemSet );
}

void ItemConnectionBase::DoReset( const SfxItemSet& rItemSet )
{
    if( IsActive() )
        Reset( rItemSet );
}

bool ItemConnectionBase::DoFillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet )
{
    return IsActive() && FillItemSet( rDestSet, rOldSet );
}

TriState ItemConnectionBase::GetEnableState( bool bKnown ) const
{
    return lclConvertToTriState( bKnown, mnFlags & ITEMCONN_ENABLE_KNOWN, mnFlags & ITEMCONN_DISABLE_UNKNOWN );
}

TriState ItemConnectionBase::GetShowState( bool bKnown ) const
{
    return lclConvertToTriState( bKnown, mnFlags & ITEMCONN_SHOW_KNOWN, mnFlags & ITEMCONN_HIDE_UNKNOWN );
}

// ============================================================================
// Standard connections
// ============================================================================

DummyItemConnection::DummyItemConnection( USHORT nSlot, Window& rWindow, ItemConnFlags nFlags ) :
    ItemConnectionBase( nFlags ),
    DummyWindowWrapper( rWindow ),
    mnSlot( nSlot )
{
}

void DummyItemConnection::ApplyFlags( const SfxItemSet& rItemSet )
{
    bool bKnown = ItemWrapperHelper::IsKnownItem( rItemSet, mnSlot );
    ModifyControl( GetEnableState( bKnown ), GetShowState( bKnown ) );
}

void DummyItemConnection::Reset( const SfxItemSet& rItemSet )
{
}

bool DummyItemConnection::FillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet )
{
    return false;   // item set not changed
}

// ============================================================================
// Array of connections
// ============================================================================

class ItemConnectionArrayImpl
{
public:
    void                        Append( ItemConnectionBase* pConnection );

    void                        ApplyFlags( const SfxItemSet& rItemSet );
    void                        Reset( const SfxItemSet& rItemSet );
    bool                        FillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet );

private:
    typedef boost::shared_ptr< ItemConnectionBase > ItemConnectionRef;
    typedef std::list< ItemConnectionRef >          ItemConnectionList;
    typedef ItemConnectionList::iterator            ItemConnectionListIt;

    ItemConnectionList          maList;
};

void ItemConnectionArrayImpl::Append( ItemConnectionBase* pConnection )
{
    if( pConnection )
        maList.push_back( ItemConnectionRef( pConnection ) );
}

void ItemConnectionArrayImpl::ApplyFlags( const SfxItemSet& rItemSet )
{
    for( ItemConnectionListIt aIt = maList.begin(), aEnd = maList.end(); aIt != aEnd; ++aIt )
        (*aIt)->DoApplyFlags( rItemSet );
}

void ItemConnectionArrayImpl::Reset( const SfxItemSet& rItemSet )
{
    for( ItemConnectionListIt aIt = maList.begin(), aEnd = maList.end(); aIt != aEnd; ++aIt )
        (*aIt)->DoReset( rItemSet );
}

bool ItemConnectionArrayImpl::FillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet )
{
    bool bChanged = false;
    for( ItemConnectionListIt aIt = maList.begin(), aEnd = maList.end(); aIt != aEnd; ++aIt )
        bChanged |= (*aIt)->DoFillItemSet( rDestSet, rOldSet );
    return bChanged;
}

// ----------------------------------------------------------------------------

ItemConnectionArray::ItemConnectionArray() :
    mxImpl( new ItemConnectionArrayImpl )
{
}

ItemConnectionArray::~ItemConnectionArray()
{
}

void ItemConnectionArray::AddConnection( ItemConnectionBase* pConnection )
{
    mxImpl->Append( pConnection );
}

void ItemConnectionArray::ApplyFlags( const SfxItemSet& rItemSet )
{
    mxImpl->ApplyFlags( rItemSet );
}

void ItemConnectionArray::Reset( const SfxItemSet& rItemSet )
{
    mxImpl->Reset( rItemSet );
}

bool ItemConnectionArray::FillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet )
{
    return mxImpl->FillItemSet( rDestSet, rOldSet );
}

// ============================================================================

} // namespace sfx

<commit_msg>INTEGRATION: CWS sb25 (1.3.120); FILE MERGED 2004/11/17 15:25:21 sb 1.3.120.1: #i37077# Removed unwanted implicitly declared copy ctors and assignment operators.<commit_after>/*************************************************************************
 *
 *  $RCSfile: itemconnect.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-01-11 14:57:35 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRUNTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRUNTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SFX_ITEMCONNECT_HXX
#include "itemconnect.hxx"
#endif

#include <boost/shared_ptr.hpp>
#include <list>

#ifndef _SFXITEMPOOL_HXX
#include <svtools/itempool.hxx>
#endif

// ============================================================================

namespace sfx {

// ============================================================================
// Helpers
// ============================================================================

namespace {

TriState lclConvertToTriState( bool bKnown, bool bIsKnownFlag, bool bIsUnknownFlag )
{
    return (bKnown && bIsKnownFlag) ? STATE_CHECK : ((!bKnown && bIsUnknownFlag) ? STATE_NOCHECK : STATE_DONTKNOW);
}

} // namespace

// ----------------------------------------------------------------------------

USHORT ItemWrapperHelper::GetWhichId( const SfxItemSet& rItemSet, USHORT nSlot )
{
    return rItemSet.GetPool()->GetWhich( nSlot );
}

bool ItemWrapperHelper::IsKnownItem( const SfxItemSet& rItemSet, USHORT nSlot )
{
    return rItemSet.GetItemState( GetWhichId( rItemSet, nSlot ), TRUE ) != SFX_ITEM_UNKNOWN;
}

const SfxPoolItem* ItemWrapperHelper::GetUniqueItem( const SfxItemSet& rItemSet, USHORT nSlot )
{
    USHORT nWhich = GetWhichId( rItemSet, nSlot );
    return (rItemSet.GetItemState( nWhich, TRUE ) >= SFX_ITEM_DEFAULT) ? rItemSet.GetItem( nWhich, TRUE ) : 0;
}

const SfxPoolItem& ItemWrapperHelper::GetDefaultItem( const SfxItemSet& rItemSet, USHORT nSlot )
{
    return rItemSet.GetPool()->GetDefaultItem( GetWhichId( rItemSet, nSlot ) );
}

void ItemWrapperHelper::RemoveDefaultItem( SfxItemSet& rDestSet, const SfxItemSet& rOldSet, USHORT nSlot )
{
    USHORT nWhich = GetWhichId( rDestSet, nSlot );
    if( rOldSet.GetItemState( nWhich, FALSE ) == SFX_ITEM_DEFAULT )
        rDestSet.ClearItem( nWhich );
}

// ============================================================================
// Base control wrapper classes
// ============================================================================

ControlWrapperBase::~ControlWrapperBase()
{
}

// ============================================================================
// Single control wrappers
// ============================================================================

DummyWindowWrapper::DummyWindowWrapper( Window& rWindow ) :
    SingleControlWrapperType( rWindow )
{
}

bool DummyWindowWrapper::IsControlDontKnow() const
{
    return false;
}

void DummyWindowWrapper::SetControlDontKnow( bool )
{
}

void* DummyWindowWrapper::GetControlValue() const
{
    return 0;
}

void DummyWindowWrapper::SetControlValue( void* )
{
}

// ----------------------------------------------------------------------------

CheckBoxWrapper::CheckBoxWrapper( CheckBox& rCheckBox ) :
        SingleControlWrapperType( rCheckBox )
{
}

bool CheckBoxWrapper::IsControlDontKnow() const
{
    return GetControl().GetState() == STATE_DONTKNOW;
}

void CheckBoxWrapper::SetControlDontKnow( bool bSet )
{
    GetControl().EnableTriState( bSet );
    GetControl().SetState( bSet ? STATE_DONTKNOW : STATE_NOCHECK );
}

BOOL CheckBoxWrapper::GetControlValue() const
{
    return GetControl().IsChecked();
}

void CheckBoxWrapper::SetControlValue( BOOL bValue )
{
    GetControl().Check( bValue );
}

// ----------------------------------------------------------------------------

EditWrapper::EditWrapper( Edit& rEdit ) :
        SingleControlWrapperType( rEdit )
{
}

bool EditWrapper::IsControlDontKnow() const
{
    // no "don't know" state - empty string is a valid value of an Edit
    return false;
}

void EditWrapper::SetControlDontKnow( bool bSet )
{
    if( bSet )
        GetControl().SetText( String() );
}

String EditWrapper::GetControlValue() const
{
    return GetControl().GetText();
}

void EditWrapper::SetControlValue( String aValue )
{
    GetControl().SetText( aValue );
}

// ----------------------------------------------------------------------------

ColorListBoxWrapper::ColorListBoxWrapper(ColorListBox & rListBox):
    SingleControlWrapper< ColorListBox, Color >(rListBox)
{}

ColorListBoxWrapper::~ColorListBoxWrapper()
{}

bool ColorListBoxWrapper::IsControlDontKnow() const
{
    return GetControl().GetSelectEntryCount() == 0;
}

void ColorListBoxWrapper::SetControlDontKnow( bool bSet )
{
    if( bSet ) GetControl().SetNoSelection();
}

Color ColorListBoxWrapper::GetControlValue() const
{
    return GetControl().GetSelectEntryColor();
}

void ColorListBoxWrapper::SetControlValue( Color aColor )
{
    GetControl().SelectEntry( aColor );
}

// ============================================================================
// Multi control wrappers
// ============================================================================

typedef std::vector< ControlWrapperBase* >  ControlWrpVec;
typedef ControlWrpVec::iterator             ControlWrpVecI;
typedef ControlWrpVec::const_iterator       ControlWrpVecCI;

struct MultiControlWrapperHelper_Impl
{
    ControlWrpVec       maVec;
};

MultiControlWrapperHelper::MultiControlWrapperHelper() :
    mxImpl( new MultiControlWrapperHelper_Impl )
{
}

MultiControlWrapperHelper::~MultiControlWrapperHelper()
{
}

void MultiControlWrapperHelper::RegisterControlWrapper( ControlWrapperBase& rWrapper )
{
    mxImpl->maVec.push_back( &rWrapper );
}

void MultiControlWrapperHelper::ModifyControl( TriState eEnable, TriState eShow )
{
    for( ControlWrpVecI aIt = mxImpl->maVec.begin(), aEnd = mxImpl->maVec.end(); aIt != aEnd; ++aIt )
        (*aIt)->ModifyControl( eEnable, eShow );
}

bool MultiControlWrapperHelper::IsControlDontKnow() const
{
    bool bIs = !mxImpl->maVec.empty();
    for( ControlWrpVecCI aIt = mxImpl->maVec.begin(), aEnd = mxImpl->maVec.end(); bIs && (aIt != aEnd); ++aIt )
        bIs &= (*aIt)->IsControlDontKnow();
    return bIs;
}

void MultiControlWrapperHelper::SetControlDontKnow( bool bSet )
{
    for( ControlWrpVecI aIt = mxImpl->maVec.begin(), aEnd = mxImpl->maVec.end(); aIt != aEnd; ++aIt )
        (*aIt)->SetControlDontKnow( bSet );
}

// ============================================================================
// Base connection classes
// ============================================================================

ItemConnectionBase::ItemConnectionBase( ItemConnFlags nFlags ) :
    mnFlags( nFlags )
{
}

ItemConnectionBase::~ItemConnectionBase()
{
}

void ItemConnectionBase::Activate( bool bActive )
{
    if( bActive ) mnFlags &= ~ITEMCONN_INACTIVE; else mnFlags |= ITEMCONN_INACTIVE;
}

bool ItemConnectionBase::IsActive() const
{
    return !(mnFlags & ITEMCONN_INACTIVE);
}

void ItemConnectionBase::DoApplyFlags( const SfxItemSet& rItemSet )
{
    if( IsActive() )
        ApplyFlags( rItemSet );
}

void ItemConnectionBase::DoReset( const SfxItemSet& rItemSet )
{
    if( IsActive() )
        Reset( rItemSet );
}

bool ItemConnectionBase::DoFillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet )
{
    return IsActive() && FillItemSet( rDestSet, rOldSet );
}

TriState ItemConnectionBase::GetEnableState( bool bKnown ) const
{
    return lclConvertToTriState( bKnown, mnFlags & ITEMCONN_ENABLE_KNOWN, mnFlags & ITEMCONN_DISABLE_UNKNOWN );
}

TriState ItemConnectionBase::GetShowState( bool bKnown ) const
{
    return lclConvertToTriState( bKnown, mnFlags & ITEMCONN_SHOW_KNOWN, mnFlags & ITEMCONN_HIDE_UNKNOWN );
}

// ============================================================================
// Standard connections
// ============================================================================

DummyItemConnection::DummyItemConnection( USHORT nSlot, Window& rWindow, ItemConnFlags nFlags ) :
    ItemConnectionBase( nFlags ),
    DummyWindowWrapper( rWindow ),
    mnSlot( nSlot )
{
}

void DummyItemConnection::ApplyFlags( const SfxItemSet& rItemSet )
{
    bool bKnown = ItemWrapperHelper::IsKnownItem( rItemSet, mnSlot );
    ModifyControl( GetEnableState( bKnown ), GetShowState( bKnown ) );
}

void DummyItemConnection::Reset( const SfxItemSet& rItemSet )
{
}

bool DummyItemConnection::FillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet )
{
    return false;   // item set not changed
}

// ============================================================================
// Array of connections
// ============================================================================

class ItemConnectionArrayImpl
{
public:
    void                        Append( ItemConnectionBase* pConnection );

    void                        ApplyFlags( const SfxItemSet& rItemSet );
    void                        Reset( const SfxItemSet& rItemSet );
    bool                        FillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet );

private:
    typedef boost::shared_ptr< ItemConnectionBase > ItemConnectionRef;
    typedef std::list< ItemConnectionRef >          ItemConnectionList;
    typedef ItemConnectionList::iterator            ItemConnectionListIt;

    ItemConnectionList          maList;
};

void ItemConnectionArrayImpl::Append( ItemConnectionBase* pConnection )
{
    if( pConnection )
        maList.push_back( ItemConnectionRef( pConnection ) );
}

void ItemConnectionArrayImpl::ApplyFlags( const SfxItemSet& rItemSet )
{
    for( ItemConnectionListIt aIt = maList.begin(), aEnd = maList.end(); aIt != aEnd; ++aIt )
        (*aIt)->DoApplyFlags( rItemSet );
}

void ItemConnectionArrayImpl::Reset( const SfxItemSet& rItemSet )
{
    for( ItemConnectionListIt aIt = maList.begin(), aEnd = maList.end(); aIt != aEnd; ++aIt )
        (*aIt)->DoReset( rItemSet );
}

bool ItemConnectionArrayImpl::FillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet )
{
    bool bChanged = false;
    for( ItemConnectionListIt aIt = maList.begin(), aEnd = maList.end(); aIt != aEnd; ++aIt )
        bChanged |= (*aIt)->DoFillItemSet( rDestSet, rOldSet );
    return bChanged;
}

// ----------------------------------------------------------------------------

ItemConnectionArray::ItemConnectionArray() :
    mxImpl( new ItemConnectionArrayImpl )
{
}

ItemConnectionArray::~ItemConnectionArray()
{
}

void ItemConnectionArray::AddConnection( ItemConnectionBase* pConnection )
{
    mxImpl->Append( pConnection );
}

void ItemConnectionArray::ApplyFlags( const SfxItemSet& rItemSet )
{
    mxImpl->ApplyFlags( rItemSet );
}

void ItemConnectionArray::Reset( const SfxItemSet& rItemSet )
{
    mxImpl->Reset( rItemSet );
}

bool ItemConnectionArray::FillItemSet( SfxItemSet& rDestSet, const SfxItemSet& rOldSet )
{
    return mxImpl->FillItemSet( rDestSet, rOldSet );
}

// ============================================================================

} // namespace sfx

<|endoftext|>


<commit_before>#include <stdio.h>
#include <fstream>
#include <map>
#include <list>
#include <set>
#include <iomanip>
#include <iostream>
#include <cfloat>
#include <sstream>
#include "crf.h"
#include "common.h"

#include "../../utils/timer.h"

using namespace std;

bool PERFORM_TOKENIZATION = false;
bool OUTPUT_TAG_PROBS = false;
bool STANDOFF = false;
bool UIMA = false;
bool ENJU = false;
int NBEST = 0;
vector<vector<Token> > sentences;

string MODEL_DIR = ".";  // the default directory for saving the models

const double PROB_OUTPUT_THRESHOLD =
    0.001;  // suppress output of tags with a very low probability

void tokenize(const string &s, vector<Token> &vt,
              const bool use_upenn_tokenizer);

void crf_decode_lookahead(Sentence &s, CRF_Model &m,
                          vector<map<string, double> > &tagp);

void read_WordNet(const string &wordnetdir);

ParenConverter paren_converter;

void print_help() {
  cout << "Lookahead POS Tagger, a trainable part-of-speech tagger." << endl;
  cout << "Usage: lapos [OPTION]... [FILE]" << endl;
  cout << "Annotate each word in FILE with a part-of-speech tag." << endl;
  cout << "By default, the tagger assumes that FILE contains one sentence per "
          "line" << endl;
  cout << "and the words are tokenized with white spaces." << endl;
  cout << "Use -t option if you want to process untokenized sentences." << endl;
  cout << endl;
  cout << "Mandatory arguments to long options are mandatory for short options "
          "too." << endl;
  cout << "  -m, --model=DIR        specify the directory containing the models"
       << endl;
  cout << "  -h, --help             display this help and exit" << endl;
  cout << endl;
  cout << "With no FILE, or when FILE is -, read standard input." << endl;
  cout << endl;
  cout << "Report bugs to <tsuruoka@gmail.com>" << endl;
  exit(0);
}

struct TagProb {
  string tag;
  double prob;
  TagProb(const string &t_, const double &p_) : tag(t_), prob(p_) {}
  bool operator<(const TagProb &x) const { return prob > x.prob; }
};

int main(int argc, char **argv) {
  if (argc < 2) {
    fprintf(stderr, "[ERROR] Invalid arguments provided.\n\n");
    fprintf(stderr, "Usage: %s [MODEL] [INPUT DATA]\n\n", argv[0]);
    exit(0);
  }
  STATS_INIT("kernel", "conditional_random_fields");
  PRINT_STAT_STRING("abrv", "crf");
  string WORDNET_DIR = "";

  string ifilename;

  for (int i = 1; i < argc; i++) {
    string v = argv[i];
    if ((v == "-m" || v == "--model") && i < argc - 1) {
      MODEL_DIR = argv[i + 1];
      i++;
      continue;
    }
    if (v.substr(0, 8) == "--model=") {
      MODEL_DIR = v.substr(8);
      continue;
    }
    if (v == "-") {
      ifilename = "";
      continue;
    }
    if (v == "-h" || v == "--help") print_help();

    if (v[0] == '-') {
      cerr << "error: unknown option " << v << endl;
      cerr << "Try `stepp --help' for more information." << endl;
      exit(1);
    }
    ifilename = v;
  }

  istream *is(&std::cin);
  ifstream ifile;
  if (ifilename != "") {
    ifile.open(ifilename.c_str());
    if (!ifile) {
      cerr << "error: cannot open " << ifilename << endl;
      exit(1);
    }
    is = &ifile;
  }

  CRF_Model crfm;

  if (!crfm.load_from_file(argv[1], false)) exit(1);

  string line;
  int nlines = 0;
  while (getline(*is, line)) {
    nlines++;
    vector<Token> vt;
    tokenize(line, vt, PERFORM_TOKENIZATION);
    sentences.push_back(vt);
  }
  PRINT_STAT_INT("sentences", (int)sentences.size());

  tic();
  for (size_t s = 0; s < sentences.size(); ++s) {
    vector<Token> vt = sentences[s];
    if (vt.size() > 990) {
      cerr << "warning: the sentence is too long. it has been truncated."
           << endl;
      while (vt.size() > 990) vt.pop_back();
    }

    // convert parantheses
    vector<string> org_strs;
    for (vector<Token>::iterator i = vt.begin(); i != vt.end(); i++) {
      org_strs.push_back(i->str);
      i->str = paren_converter.Ptb2Pos(i->str);
      i->prd = "?";
    }

    if (STANDOFF) cout << line << endl;
    if (vt.size() == 0) {
      cout << endl;
      continue;
    }

    // tag the words
    vector<map<string, double> > tagp0, tagp1;
    crf_decode_lookahead(vt, crfm, tagp0);
    if (false) {
      assert(0);
      exit(1);
    } else {
      for (vector<Token>::const_iterator i = vt.begin(); i != vt.end(); i++) {
        map<string, double> dummy;
        tagp1.push_back(dummy);
      }
    }

    // merge the outputs (simple interpolation of probabilities)
    vector<map<string, double> > tagp;  // merged
    for (size_t k = 0; k < vt.size(); k++) {
      const map<string, double> &crf = tagp0[k];
      const map<string, double> &ef = tagp1[k];
      map<string, double> m, m2;  // merged

      double sum = 0;
      for (map<string, double>::const_iterator j = crf.begin(); j != crf.end();
           j++) {
        m.insert(pair<string, double>(j->first, j->second));
        sum += j->second;
      }

      for (map<string, double>::const_iterator j = ef.begin(); j != ef.end();
           j++) {
        sum += j->second;
        if (m.find(j->first) == m.end()) {
          m.insert(pair<string, double>(j->first, j->second));
        } else {
          m[j->first] += j->second;
        }
      }

      const double th = PROB_OUTPUT_THRESHOLD * sum;
      for (map<string, double>::iterator j = m.begin(); j != m.end(); j++) {
        if (j->second >= th) m2.insert(*j);
      }
      double maxp = -1;
      string maxtag;
      for (map<string, double>::iterator j = m2.begin(); j != m2.end(); j++) {
        const double p = j->second;
        if (p > maxp) {
          maxp = p;
          maxtag = j->first;
        }
      }
      tagp.push_back(m2);
      sentences[s][k].prd = maxtag;
    }
  }
  PRINT_STAT_DOUBLE("crf", toc());

#ifdef TESTING
  FILE *f = fopen("../input/crf_tag.baseline", "w");

  for (size_t i = 0; i < sentences.size(); i++) {
    vector<Token> vt = sentences[i];
    for (size_t i = 0; i < vt.size(); i++) {
      string s = vt[i].str;
      string p = vt[i].prd;
      if (i == 0)
        fprintf(f, "%s/%s", s.c_str(), p.c_str());
      else
        fprintf(f, " %s/%s", s.c_str(), p.c_str());
    }
    fprintf(f, "\n");
  }

  fclose(f);
#endif

  STATS_END();
}
<commit_msg>sirius-suite/main.cpp: prefer prefix ++operator for non-primitive types<commit_after>#include <stdio.h>
#include <fstream>
#include <map>
#include <list>
#include <set>
#include <iomanip>
#include <iostream>
#include <cfloat>
#include <sstream>
#include "crf.h"
#include "common.h"

#include "../../utils/timer.h"

using namespace std;

bool PERFORM_TOKENIZATION = false;
bool OUTPUT_TAG_PROBS = false;
bool STANDOFF = false;
bool UIMA = false;
bool ENJU = false;
int NBEST = 0;
vector<vector<Token> > sentences;

string MODEL_DIR = ".";  // the default directory for saving the models

const double PROB_OUTPUT_THRESHOLD =
    0.001;  // suppress output of tags with a very low probability

void tokenize(const string &s, vector<Token> &vt,
              const bool use_upenn_tokenizer);

void crf_decode_lookahead(Sentence &s, CRF_Model &m,
                          vector<map<string, double> > &tagp);

void read_WordNet(const string &wordnetdir);

ParenConverter paren_converter;

void print_help() {
  cout << "Lookahead POS Tagger, a trainable part-of-speech tagger." << endl;
  cout << "Usage: lapos [OPTION]... [FILE]" << endl;
  cout << "Annotate each word in FILE with a part-of-speech tag." << endl;
  cout << "By default, the tagger assumes that FILE contains one sentence per "
          "line" << endl;
  cout << "and the words are tokenized with white spaces." << endl;
  cout << "Use -t option if you want to process untokenized sentences." << endl;
  cout << endl;
  cout << "Mandatory arguments to long options are mandatory for short options "
          "too." << endl;
  cout << "  -m, --model=DIR        specify the directory containing the models"
       << endl;
  cout << "  -h, --help             display this help and exit" << endl;
  cout << endl;
  cout << "With no FILE, or when FILE is -, read standard input." << endl;
  cout << endl;
  cout << "Report bugs to <tsuruoka@gmail.com>" << endl;
  exit(0);
}

struct TagProb {
  string tag;
  double prob;
  TagProb(const string &t_, const double &p_) : tag(t_), prob(p_) {}
  bool operator<(const TagProb &x) const { return prob > x.prob; }
};

int main(int argc, char **argv) {
  if (argc < 2) {
    fprintf(stderr, "[ERROR] Invalid arguments provided.\n\n");
    fprintf(stderr, "Usage: %s [MODEL] [INPUT DATA]\n\n", argv[0]);
    exit(0);
  }
  STATS_INIT("kernel", "conditional_random_fields");
  PRINT_STAT_STRING("abrv", "crf");
  string WORDNET_DIR = "";

  string ifilename;

  for (int i = 1; i < argc; i++) {
    string v = argv[i];
    if ((v == "-m" || v == "--model") && i < argc - 1) {
      MODEL_DIR = argv[i + 1];
      i++;
      continue;
    }
    if (v.substr(0, 8) == "--model=") {
      MODEL_DIR = v.substr(8);
      continue;
    }
    if (v == "-") {
      ifilename = "";
      continue;
    }
    if (v == "-h" || v == "--help") print_help();

    if (v[0] == '-') {
      cerr << "error: unknown option " << v << endl;
      cerr << "Try `stepp --help' for more information." << endl;
      exit(1);
    }
    ifilename = v;
  }

  istream *is(&std::cin);
  ifstream ifile;
  if (ifilename != "") {
    ifile.open(ifilename.c_str());
    if (!ifile) {
      cerr << "error: cannot open " << ifilename << endl;
      exit(1);
    }
    is = &ifile;
  }

  CRF_Model crfm;

  if (!crfm.load_from_file(argv[1], false)) exit(1);

  string line;
  int nlines = 0;
  while (getline(*is, line)) {
    nlines++;
    vector<Token> vt;
    tokenize(line, vt, PERFORM_TOKENIZATION);
    sentences.push_back(vt);
  }
  PRINT_STAT_INT("sentences", (int)sentences.size());

  tic();
  for (size_t s = 0; s < sentences.size(); ++s) {
    vector<Token> vt = sentences[s];
    if (vt.size() > 990) {
      cerr << "warning: the sentence is too long. it has been truncated."
           << endl;
      while (vt.size() > 990) vt.pop_back();
    }

    // convert parantheses
    vector<string> org_strs;
    for (vector<Token>::iterator i = vt.begin(); i != vt.end(); ++i) {
      org_strs.push_back(i->str);
      i->str = paren_converter.Ptb2Pos(i->str);
      i->prd = "?";
    }

    if (STANDOFF) cout << line << endl;
    if (vt.size() == 0) {
      cout << endl;
      continue;
    }

    // tag the words
    vector<map<string, double> > tagp0, tagp1;
    crf_decode_lookahead(vt, crfm, tagp0);
    if (false) {
      assert(0);
      exit(1);
    } else {
      for (vector<Token>::const_iterator i = vt.begin(); i != vt.end(); ++i) {
        map<string, double> dummy;
        tagp1.push_back(dummy);
      }
    }

    // merge the outputs (simple interpolation of probabilities)
    vector<map<string, double> > tagp;  // merged
    for (size_t k = 0; k < vt.size(); k++) {
      const map<string, double> &crf = tagp0[k];
      const map<string, double> &ef = tagp1[k];
      map<string, double> m, m2;  // merged

      double sum = 0;
      for (map<string, double>::const_iterator j = crf.begin(); j != crf.end();
           ++j) {
        m.insert(pair<string, double>(j->first, j->second));
        sum += j->second;
      }

      for (map<string, double>::const_iterator j = ef.begin(); j != ef.end();
           ++j) {
        sum += j->second;
        if (m.find(j->first) == m.end()) {
          m.insert(pair<string, double>(j->first, j->second));
        } else {
          m[j->first] += j->second;
        }
      }

      const double th = PROB_OUTPUT_THRESHOLD * sum;
      for (map<string, double>::iterator j = m.begin(); j != m.end(); ++j) {
        if (j->second >= th) m2.insert(*j);
      }
      double maxp = -1;
      string maxtag;
      for (map<string, double>::iterator j = m2.begin(); j != m2.end(); ++j) {
        const double p = j->second;
        if (p > maxp) {
          maxp = p;
          maxtag = j->first;
        }
      }
      tagp.push_back(m2);
      sentences[s][k].prd = maxtag;
    }
  }
  PRINT_STAT_DOUBLE("crf", toc());

#ifdef TESTING
  FILE *f = fopen("../input/crf_tag.baseline", "w");

  for (size_t i = 0; i < sentences.size(); i++) {
    vector<Token> vt = sentences[i];
    for (size_t i = 0; i < vt.size(); i++) {
      string s = vt[i].str;
      string p = vt[i].prd;
      if (i == 0)
        fprintf(f, "%s/%s", s.c_str(), p.c_str());
      else
        fprintf(f, " %s/%s", s.c_str(), p.c_str());
    }
    fprintf(f, "\n");
  }

  fclose(f);
#endif

  STATS_END();
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <eventql/db/CompactionStrategy.h>
#include <eventql/db/LSMTableIndex.h>
#include <eventql/io/cstable/cstable_writer.h>
#include <eventql/util/io/fileutil.h>

#include "eventql/eventql.h"

namespace eventql {

SimpleCompactionStrategy::SimpleCompactionStrategy(
    RefPtr<Partition> partition,
    LSMTableIndexCache* idx_cache,
    size_t num_tables_soft_limit,
    size_t num_tables_hard_limit) :
    partition_(partition),
    idx_cache_(idx_cache),
    num_tables_soft_limit_(num_tables_soft_limit),
    num_tables_hard_limit_(num_tables_hard_limit) {}

bool SimpleCompactionStrategy::compact(
    const Vector<LSMTableRef>& input,
    Vector<LSMTableRef>* output) {
  if (input.empty()) {
    return false;
  }

  if (!needsCompaction(input)) {
    return false;
  }

  HashMap<SHA1Hash, uint64_t> vmap;
  for (auto tbl = input.rbegin(); tbl != input.rend(); ++tbl) {
    auto idx = idx_cache_->lookup(
        FileUtil::joinPaths(partition_->getRelativePath(), tbl->filename()));
    idx->list(&vmap);
  }

  auto table = partition_->getTable();
  auto base_path = partition_->getAbsolutePath();
  auto cstable_schema = cstable::TableSchema::fromProtobuf(*table->schema());
  auto cstable_schema_ext = cstable_schema;
  cstable_schema_ext.addBool("__lsm_is_update", false);
  cstable_schema_ext.addString("__lsm_id", false);
  cstable_schema_ext.addUnsignedInteger("__lsm_version", false);
  cstable_schema_ext.addUnsignedInteger("__lsm_sequence", false);

  auto cstable_filename = Random::singleton()->hex64();
  auto cstable_filepath = FileUtil::joinPaths(base_path, cstable_filename);

  auto cstable = cstable::CSTableWriter::createFile(
      cstable_filepath + ".cst",
      cstable::BinaryFormatVersion::v0_1_0,
      cstable_schema_ext);

  auto is_update_col = cstable->getColumnWriter("__lsm_is_update");
  auto id_col = cstable->getColumnWriter("__lsm_id");
  auto version_col = cstable->getColumnWriter("__lsm_version");
  auto sequence_col = cstable->getColumnWriter("__lsm_sequence");

  for (const auto& tbl : input) {
    auto input_cstable_file = FileUtil::joinPaths(
        base_path,
        tbl.filename() + ".cst");

    auto input_cstable = cstable::CSTableReader::openFile(input_cstable_file);
    auto input_id_col = input_cstable->getColumnReader("__lsm_id");
    auto input_version_col = input_cstable->getColumnReader("__lsm_version");
    auto input_sequence_col = input_cstable->getColumnReader("__lsm_sequence");

    Vector<Pair<
        RefPtr<cstable::ColumnReader>,
        RefPtr<cstable::ColumnWriter>>> columns;

    auto flat_columns = cstable_schema.flatColumns();
    for (const auto& col : flat_columns) {
      if (input_cstable->hasColumn(col.column_name)) {
        columns.emplace_back(
            input_cstable->getColumnReader(col.column_name),
            cstable->getColumnWriter(col.column_name));
      } else {
        if (col.dlevel_max == 0) {
          RAISE(
              kIllegalStateError,
              "can't merge CSTables after a new required column was added");
        }

        columns.emplace_back(
            nullptr,
            cstable->getColumnWriter(col.column_name));
      }
    }

    auto nrecords = input_cstable->numRecords();
    for (size_t i = 0; i < nrecords; ++i) {
      uint64_t rlvl;
      uint64_t dlvl;

      String id_str;
      input_id_col->readString(&rlvl, &dlvl, &id_str);
      SHA1Hash id(id_str.data(), id_str.size());

      uint64_t version;
      input_version_col->readUnsignedInt(&rlvl, &dlvl, &version);

      uint64_t sequence;
      input_sequence_col->readUnsignedInt(&rlvl, &dlvl, &sequence);

      const auto& vmap_iter = vmap.find(id);
      if (vmap_iter == vmap.end()) {
        RAISE(kIllegalStateError, "invalid cstable contents");
      }

      if (version == vmap_iter->second) {
        is_update_col->writeBoolean(0, 0, false);
        id_col->writeString(0, 0, id_str);
        version_col->writeUnsignedInt(0, 0, version);
        sequence_col->writeUnsignedInt(0, 0, sequence);

        for (auto& col : columns) {
          if (col.first.get()) {
            do {
              col.first->copyValue(col.second.get());
            } while (col.first->nextRepetitionLevel() > 0);
          } else {
            col.second->writeNull(0, 0);
          }
        }

        cstable->addRow();
      } else {
        for (auto& col : columns) {
          if (col.first.get()) {
            do {
              col.first->skipValue();
            } while (col.first->nextRepetitionLevel() > 0);
          }
        }
      }
    }
  }

  cstable->commit();

  OrderedMap<SHA1Hash, uint64_t> vmap_ordered;
  for (const auto& p : vmap) {
    vmap_ordered.emplace(p);
  }
  LSMTableIndex::write(vmap_ordered, cstable_filepath + ".idx");

  LSMTableRef tbl_ref;
  tbl_ref.set_filename(cstable_filename);
  tbl_ref.set_first_sequence(input.begin()->first_sequence());
  tbl_ref.set_last_sequence(input.rbegin()->last_sequence());
  tbl_ref.set_size_bytes(FileUtil::size(cstable_filepath + ".cst"));
  output->emplace_back(tbl_ref);

  return true;
}

bool SimpleCompactionStrategy::needsCompaction(
    const Vector<LSMTableRef>& tables) {
  return tables.size() > num_tables_soft_limit_;
}

bool SimpleCompactionStrategy::needsUrgentCompaction(
    const Vector<LSMTableRef>& tables) {
  return tables.size() > num_tables_hard_limit_;
}

} // namespace eventql

<commit_msg>allow skipping  broken tables in compaction<commit_after>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include "eventql/eventql.h"
#include "eventql/util/logging.h"
#include <eventql/db/CompactionStrategy.h>
#include <eventql/db/LSMTableIndex.h>
#include <eventql/io/cstable/cstable_writer.h>
#include <eventql/util/io/fileutil.h>

namespace eventql {

SimpleCompactionStrategy::SimpleCompactionStrategy(
    RefPtr<Partition> partition,
    LSMTableIndexCache* idx_cache,
    size_t num_tables_soft_limit,
    size_t num_tables_hard_limit) :
    partition_(partition),
    idx_cache_(idx_cache),
    num_tables_soft_limit_(num_tables_soft_limit),
    num_tables_hard_limit_(num_tables_hard_limit) {}

bool SimpleCompactionStrategy::compact(
    const Vector<LSMTableRef>& input,
    Vector<LSMTableRef>* output) {
  if (input.empty()) {
    return false;
  }

  if (!needsCompaction(input)) {
    return false;
  }

  HashMap<SHA1Hash, uint64_t> vmap;
  for (auto tbl = input.rbegin(); tbl != input.rend(); ++tbl) {
    auto idx = idx_cache_->lookup(
        FileUtil::joinPaths(partition_->getRelativePath(), tbl->filename()));
    idx->list(&vmap);
  }

  auto table = partition_->getTable();
  auto base_path = partition_->getAbsolutePath();
  auto cstable_schema = cstable::TableSchema::fromProtobuf(*table->schema());
  auto cstable_schema_ext = cstable_schema;
  cstable_schema_ext.addBool("__lsm_is_update", false);
  cstable_schema_ext.addString("__lsm_id", false);
  cstable_schema_ext.addUnsignedInteger("__lsm_version", false);
  cstable_schema_ext.addUnsignedInteger("__lsm_sequence", false);

  auto cstable_filename = Random::singleton()->hex64();
  auto cstable_filepath = FileUtil::joinPaths(base_path, cstable_filename);

  auto cstable = cstable::CSTableWriter::createFile(
      cstable_filepath + ".cst",
      cstable::BinaryFormatVersion::v0_1_0,
      cstable_schema_ext);

  auto is_update_col = cstable->getColumnWriter("__lsm_is_update");
  auto id_col = cstable->getColumnWriter("__lsm_id");
  auto version_col = cstable->getColumnWriter("__lsm_version");
  auto sequence_col = cstable->getColumnWriter("__lsm_sequence");

  for (const auto& tbl : input) {
    auto input_cstable_file = FileUtil::joinPaths(
        base_path,
        tbl.filename() + ".cst");

    if (!FileUtil::exists(input_cstable_file)) {
      logWarning("evqld", "missing table file: $0", input_cstable_file);
      continue;
    }

    try {
      auto input_cstable = cstable::CSTableReader::openFile(input_cstable_file);
      auto input_id_col = input_cstable->getColumnReader("__lsm_id");
      auto input_version_col = input_cstable->getColumnReader("__lsm_version");
      auto input_sequence_col = input_cstable->getColumnReader("__lsm_sequence");

      Vector<Pair<
          RefPtr<cstable::ColumnReader>,
          RefPtr<cstable::ColumnWriter>>> columns;

      auto flat_columns = cstable_schema.flatColumns();
      for (const auto& col : flat_columns) {
        if (input_cstable->hasColumn(col.column_name)) {
          columns.emplace_back(
              input_cstable->getColumnReader(col.column_name),
              cstable->getColumnWriter(col.column_name));
        } else {
          if (col.dlevel_max == 0) {
            RAISE(
                kIllegalStateError,
                "can't merge CSTables after a new required column was added");
          }

          columns.emplace_back(
              nullptr,
              cstable->getColumnWriter(col.column_name));
        }
      }

      auto nrecords = input_cstable->numRecords();
      for (size_t i = 0; i < nrecords; ++i) {
        uint64_t rlvl;
        uint64_t dlvl;

        String id_str;
        input_id_col->readString(&rlvl, &dlvl, &id_str);
        SHA1Hash id(id_str.data(), id_str.size());

        uint64_t version;
        input_version_col->readUnsignedInt(&rlvl, &dlvl, &version);

        uint64_t sequence;
        input_sequence_col->readUnsignedInt(&rlvl, &dlvl, &sequence);

        const auto& vmap_iter = vmap.find(id);
        if (vmap_iter == vmap.end()) {
          RAISE(kIllegalStateError, "invalid cstable contents");
        }

        if (version == vmap_iter->second) {
          is_update_col->writeBoolean(0, 0, false);
          id_col->writeString(0, 0, id_str);
          version_col->writeUnsignedInt(0, 0, version);
          sequence_col->writeUnsignedInt(0, 0, sequence);

          for (auto& col : columns) {
            if (col.first.get()) {
              do {
                col.first->copyValue(col.second.get());
              } while (col.first->nextRepetitionLevel() > 0);
            } else {
              col.second->writeNull(0, 0);
            }
          }

          cstable->addRow();
        } else {
          for (auto& col : columns) {
            if (col.first.get()) {
              do {
                col.first->skipValue();
              } while (col.first->nextRepetitionLevel() > 0);
            }
          }
        }
      }
    } catch (const std::exception& e) {
      logError("evqld", "error while compacting table: $0", input_cstable_file);
    }
  }

  cstable->commit();

  OrderedMap<SHA1Hash, uint64_t> vmap_ordered;
  for (const auto& p : vmap) {
    vmap_ordered.emplace(p);
  }
  LSMTableIndex::write(vmap_ordered, cstable_filepath + ".idx");

  LSMTableRef tbl_ref;
  tbl_ref.set_filename(cstable_filename);
  tbl_ref.set_first_sequence(input.begin()->first_sequence());
  tbl_ref.set_last_sequence(input.rbegin()->last_sequence());
  tbl_ref.set_size_bytes(FileUtil::size(cstable_filepath + ".cst"));
  output->emplace_back(tbl_ref);

  return true;
}

bool SimpleCompactionStrategy::needsCompaction(
    const Vector<LSMTableRef>& tables) {
  return tables.size() > num_tables_soft_limit_;
}

bool SimpleCompactionStrategy::needsUrgentCompaction(
    const Vector<LSMTableRef>& tables) {
  return tables.size() > num_tables_hard_limit_;
}

} // namespace eventql

<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "DeviceLister.h"
#include "logging/Logger.h"
#include "utils/Filename.h"

#include <dirent.h>
#include <mntent.h>
#include <sys/types.h>
#include <vector>
#include <memory>
#include <cerrno>
#include <sstream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <limits.h>
#include <unistd.h>

namespace medialibrary
{
namespace fs
{

DeviceLister::DeviceMap DeviceLister::listDevices() const
{
    static const std::vector<std::string> deviceBlacklist = { "loop", "dm-" };
    const std::string devPath = "/dev/disk/by-uuid/";
    // Don't use fs::Directory to iterate, as it resolves the symbolic links automatically.
    // We need the link name & what it points to.
    std::unique_ptr<DIR, int(*)(DIR*)> dir( opendir( devPath.c_str() ), &closedir );
    if ( dir == nullptr )
    {
        std::stringstream err;
        err << "Failed to open /dev/disk/by-uuid: " << strerror(errno);
        throw std::runtime_error( err.str() );
    }
    DeviceMap res;
    dirent* result = nullptr;

    while ( ( result = readdir( dir.get() ) ) != nullptr )
    {
        if ( strcmp( result->d_name, "." ) == 0 ||
             strcmp( result->d_name, ".." ) == 0 )
        {
            continue;
        }
        std::string path = devPath + result->d_name;
        char linkPath[PATH_MAX] = {};
        if ( readlink( path.c_str(), linkPath, PATH_MAX ) < 0 )
        {
            std::stringstream err;
            err << "Failed to resolve uuid -> device link: "
                << result->d_name << " (" << strerror(errno) << ')';
            throw std::runtime_error( err.str() );
        }
        auto deviceName = utils::file::fileName( linkPath );
        if ( std::find_if( begin( deviceBlacklist ), end( deviceBlacklist ), [&deviceName]( const std::string& pattern ) {
                return deviceName.length() >= pattern.length() && deviceName.find( pattern ) == 0;
            }) != end( deviceBlacklist ) )
            continue;
        auto uuid = result->d_name;
        LOG_INFO( "Discovered device ", deviceName, " -> {", uuid, '}' );
        res[deviceName] = uuid;
    }
    return res;
}

DeviceLister::MountpointMap DeviceLister::listMountpoints() const
{
    static const std::vector<std::string> allowedFsType = { "vfat", "exfat", "sdcardfs", "fuse",
                                                            "ntfs", "fat32", "ext3", "ext4", "esdfs" };
    MountpointMap res;
    errno = 0;
    mntent* s;
    char buff[512];
    mntent smnt;
    FILE* f = setmntent("/etc/mtab", "r");
    if ( f == nullptr )
        throw std::runtime_error( "Failed to read /etc/mtab" );
    std::unique_ptr<FILE, int(*)(FILE*)> fPtr( f, &endmntent );
    while ( getmntent_r( f, &smnt, buff, sizeof(buff) ) != nullptr )
    {
        s = &smnt;
        if ( std::find( begin( allowedFsType ), end( allowedFsType ), s->mnt_type ) == end( allowedFsType ) )
            continue;
        auto deviceName = s->mnt_fsname;
        if ( res.count( deviceName ) == 0 )
        {
            LOG_INFO( "Discovered mountpoint ", deviceName, " mounted on ", s->mnt_dir, " (", s->mnt_type, ')' );
            res[deviceName] = s->mnt_dir;
        }
        else
            LOG_INFO( "Ignoring duplicated mountpoint (", s->mnt_dir, ") for device ", deviceName );
        errno = 0;
    }
    if ( errno != 0 )
    {
        LOG_ERROR( "Failed to read mountpoints: ", strerror( errno ) );
    }
    return res;
}

std::string DeviceLister::deviceFromDeviceMapper( const std::string& devicePath ) const
{
    if ( devicePath.find( "/dev/mapper" ) != 0 )
        return {};
    char linkPath[PATH_MAX];
    if ( readlink( devicePath.c_str(), linkPath, PATH_MAX ) < 0 )
    {
        std::stringstream err;
        err << "Failed to resolve device -> mapper link: "
            << devicePath << " (" << strerror(errno) << ')';
        throw std::runtime_error( err.str() );
    }
    const auto dmName = utils::file::fileName( linkPath );
    std::string dmSlavePath = "/sys/block/" + dmName + "/slaves";
    std::unique_ptr<DIR, int(*)(DIR*)> dir( opendir( dmSlavePath.c_str() ), &closedir );
    std::string res;
    if ( dir == nullptr )
        return {};
    dirent* result;
    while ( ( result = readdir( dir.get() ) ) != nullptr )
    {
        if ( strcmp( result->d_name, "." ) == 0 ||
             strcmp( result->d_name, ".." ) == 0 )
        {
            continue;
        }
        if ( res.empty() == true )
            res = result->d_name;
        else
            LOG_WARN( "More than one slave for device mapper ", linkPath );
    }
    LOG_INFO( "Device mapper ", dmName, " maps to ", res );
    return res;
}

bool DeviceLister::isRemovable( const std::string& deviceName, const std::string& mountpoint ) const
{
#ifndef TIZEN
    (void)mountpoint;
    std::stringstream removableFilePath;
    removableFilePath << "/sys/block/" << deviceName << "/removable";
    std::unique_ptr<FILE, int(*)(FILE*)> removableFile( fopen( removableFilePath.str().c_str(), "r" ), &fclose );
    // Assume the file isn't removable by default
    if ( removableFile != nullptr )
    {
        char buff;
        if ( fread(&buff, sizeof(buff), 1, removableFile.get() ) != 1 )
            return buff == '1';
        return false;
    }
#else
    (void)deviceName;
    static const std::vector<std::string> SDMountpoints = { "/opt/storage/sdcard" };
    auto it = std::find_if( begin( SDMountpoints ), end( SDMountpoints ), [mountpoint]( const std::string& pattern ) {
        return mountpoint.length() >= pattern.length() && mountpoint.find( pattern ) == 0;
    });
    if ( it != end( SDMountpoints ) )
    {
        LOG_INFO( "Considering mountpoint ", mountpoint, " a removable SDCard" );
        return true;
    }
#endif
    return false;
}

std::vector<std::tuple<std::string, std::string, bool>> medialibrary::fs::DeviceLister::devices() const
{
    std::vector<std::tuple<std::string, std::string, bool>> res;
    auto mountpoints = listMountpoints();
    if ( mountpoints.empty() == true )
    {
        LOG_WARN( "Failed to detect any mountpoint" );
        return res;
    }
    auto devices = listDevices();
    if ( devices.empty() == true )
    {
        LOG_WARN( "Failed to detect any device" );
        return res;
    }
    for ( const auto& p : mountpoints )
    {
        const auto& devicePath = p.first;
        auto deviceName = utils::file::fileName( devicePath );
        const auto& mountpoint = p.second;
        auto it = devices.find( deviceName );
        std::string uuid;
        if ( it != end( devices ) )
            uuid = it->second;
        else
        {
            LOG_INFO( "Failed to find device for mountpoint ", mountpoint, ". Attempting to resolve"
                      " using device mapper" );
            deviceName = deviceFromDeviceMapper( devicePath );
            it = devices.find( deviceName );
            if ( it != end( devices ) )
                uuid = it->second;
            else
            {
                LOG_ERROR( "Failed to resolve mountpoint ", mountpoint, " to any known device" );
                continue;
            }
        }
        auto removable = isRemovable( deviceName, mountpoint );
        res.emplace_back( std::make_tuple( uuid, mountpoint, removable ) );
    }
    return res;
}

}
}
<commit_msg>DeviceLister: Add some logging when resolving through device mapper<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "DeviceLister.h"
#include "logging/Logger.h"
#include "utils/Filename.h"

#include <dirent.h>
#include <mntent.h>
#include <sys/types.h>
#include <vector>
#include <memory>
#include <cerrno>
#include <sstream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <limits.h>
#include <unistd.h>

namespace medialibrary
{
namespace fs
{

DeviceLister::DeviceMap DeviceLister::listDevices() const
{
    static const std::vector<std::string> deviceBlacklist = { "loop", "dm-" };
    const std::string devPath = "/dev/disk/by-uuid/";
    // Don't use fs::Directory to iterate, as it resolves the symbolic links automatically.
    // We need the link name & what it points to.
    std::unique_ptr<DIR, int(*)(DIR*)> dir( opendir( devPath.c_str() ), &closedir );
    if ( dir == nullptr )
    {
        std::stringstream err;
        err << "Failed to open /dev/disk/by-uuid: " << strerror(errno);
        throw std::runtime_error( err.str() );
    }
    DeviceMap res;
    dirent* result = nullptr;

    while ( ( result = readdir( dir.get() ) ) != nullptr )
    {
        if ( strcmp( result->d_name, "." ) == 0 ||
             strcmp( result->d_name, ".." ) == 0 )
        {
            continue;
        }
        std::string path = devPath + result->d_name;
        char linkPath[PATH_MAX] = {};
        if ( readlink( path.c_str(), linkPath, PATH_MAX ) < 0 )
        {
            std::stringstream err;
            err << "Failed to resolve uuid -> device link: "
                << result->d_name << " (" << strerror(errno) << ')';
            throw std::runtime_error( err.str() );
        }
        auto deviceName = utils::file::fileName( linkPath );
        if ( std::find_if( begin( deviceBlacklist ), end( deviceBlacklist ), [&deviceName]( const std::string& pattern ) {
                return deviceName.length() >= pattern.length() && deviceName.find( pattern ) == 0;
            }) != end( deviceBlacklist ) )
            continue;
        auto uuid = result->d_name;
        LOG_INFO( "Discovered device ", deviceName, " -> {", uuid, '}' );
        res[deviceName] = uuid;
    }
    return res;
}

DeviceLister::MountpointMap DeviceLister::listMountpoints() const
{
    static const std::vector<std::string> allowedFsType = { "vfat", "exfat", "sdcardfs", "fuse",
                                                            "ntfs", "fat32", "ext3", "ext4", "esdfs" };
    MountpointMap res;
    errno = 0;
    mntent* s;
    char buff[512];
    mntent smnt;
    FILE* f = setmntent("/etc/mtab", "r");
    if ( f == nullptr )
        throw std::runtime_error( "Failed to read /etc/mtab" );
    std::unique_ptr<FILE, int(*)(FILE*)> fPtr( f, &endmntent );
    while ( getmntent_r( f, &smnt, buff, sizeof(buff) ) != nullptr )
    {
        s = &smnt;
        if ( std::find( begin( allowedFsType ), end( allowedFsType ), s->mnt_type ) == end( allowedFsType ) )
            continue;
        auto deviceName = s->mnt_fsname;
        if ( res.count( deviceName ) == 0 )
        {
            LOG_INFO( "Discovered mountpoint ", deviceName, " mounted on ", s->mnt_dir, " (", s->mnt_type, ')' );
            res[deviceName] = s->mnt_dir;
        }
        else
            LOG_INFO( "Ignoring duplicated mountpoint (", s->mnt_dir, ") for device ", deviceName );
        errno = 0;
    }
    if ( errno != 0 )
    {
        LOG_ERROR( "Failed to read mountpoints: ", strerror( errno ) );
    }
    return res;
}

std::string DeviceLister::deviceFromDeviceMapper( const std::string& devicePath ) const
{
    if ( devicePath.find( "/dev/mapper" ) != 0 )
        return {};
    char linkPath[PATH_MAX];
    if ( readlink( devicePath.c_str(), linkPath, PATH_MAX ) < 0 )
    {
        std::stringstream err;
        err << "Failed to resolve device -> mapper link: "
            << devicePath << " (" << strerror(errno) << ')';
        throw std::runtime_error( err.str() );
    }
    LOG_INFO( "Resolved ", devicePath, " to ", linkPath, " device mapper" );
    const auto dmName = utils::file::fileName( linkPath );
    std::string dmSlavePath = "/sys/block/" + dmName + "/slaves";
    std::unique_ptr<DIR, int(*)(DIR*)> dir( opendir( dmSlavePath.c_str() ), &closedir );
    std::string res;
    if ( dir == nullptr )
        return {};
    dirent* result;
    while ( ( result = readdir( dir.get() ) ) != nullptr )
    {
        if ( strcmp( result->d_name, "." ) == 0 ||
             strcmp( result->d_name, ".." ) == 0 )
        {
            continue;
        }
        if ( res.empty() == true )
            res = result->d_name;
        else
            LOG_WARN( "More than one slave for device mapper ", linkPath );
    }
    LOG_INFO( "Device mapper ", dmName, " maps to ", res );
    return res;
}

bool DeviceLister::isRemovable( const std::string& deviceName, const std::string& mountpoint ) const
{
#ifndef TIZEN
    (void)mountpoint;
    std::stringstream removableFilePath;
    removableFilePath << "/sys/block/" << deviceName << "/removable";
    std::unique_ptr<FILE, int(*)(FILE*)> removableFile( fopen( removableFilePath.str().c_str(), "r" ), &fclose );
    // Assume the file isn't removable by default
    if ( removableFile != nullptr )
    {
        char buff;
        if ( fread(&buff, sizeof(buff), 1, removableFile.get() ) != 1 )
            return buff == '1';
        return false;
    }
#else
    (void)deviceName;
    static const std::vector<std::string> SDMountpoints = { "/opt/storage/sdcard" };
    auto it = std::find_if( begin( SDMountpoints ), end( SDMountpoints ), [mountpoint]( const std::string& pattern ) {
        return mountpoint.length() >= pattern.length() && mountpoint.find( pattern ) == 0;
    });
    if ( it != end( SDMountpoints ) )
    {
        LOG_INFO( "Considering mountpoint ", mountpoint, " a removable SDCard" );
        return true;
    }
#endif
    return false;
}

std::vector<std::tuple<std::string, std::string, bool>> medialibrary::fs::DeviceLister::devices() const
{
    std::vector<std::tuple<std::string, std::string, bool>> res;
    auto mountpoints = listMountpoints();
    if ( mountpoints.empty() == true )
    {
        LOG_WARN( "Failed to detect any mountpoint" );
        return res;
    }
    auto devices = listDevices();
    if ( devices.empty() == true )
    {
        LOG_WARN( "Failed to detect any device" );
        return res;
    }
    for ( const auto& p : mountpoints )
    {
        const auto& devicePath = p.first;
        auto deviceName = utils::file::fileName( devicePath );
        const auto& mountpoint = p.second;
        auto it = devices.find( deviceName );
        std::string uuid;
        if ( it != end( devices ) )
            uuid = it->second;
        else
        {
            LOG_INFO( "Failed to find device for mountpoint ", mountpoint, ". Attempting to resolve"
                      " using device mapper" );
            deviceName = deviceFromDeviceMapper( devicePath );
            it = devices.find( deviceName );
            if ( it != end( devices ) )
                uuid = it->second;
            else
            {
                LOG_ERROR( "Failed to resolve mountpoint ", mountpoint, " to any known device" );
                continue;
            }
        }
        auto removable = isRemovable( deviceName, mountpoint );
        res.emplace_back( std::make_tuple( uuid, mountpoint, removable ) );
    }
    return res;
}

}
}
<|endoftext|>


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

#include <string>
#include <iostream>
#include <iomanip>

#include "sky/compositor/statistics_layer.h"

namespace sky {
namespace compositor {

StatisticsLayer::StatisticsLayer(uint64_t enabledOptions)
    : options_(enabledOptions) {
}

static void PaintContext_DrawStatisticsText(SkCanvas& canvas,
                                            const std::string& string,
                                            int x,
                                            int y) {
  SkPaint paint;
  paint.setTextSize(14);
  paint.setLinearText(false);
  paint.setColor(SK_ColorRED);
  canvas.drawText(string.c_str(), string.size(), x, y, paint);
}

static void VisualizeStopWatch(SkCanvas& canvas,
                               const instrumentation::Stopwatch& stopwatch,
                               SkScalar width,
                               bool show_graph,
                               bool show_labels,
                               std::string label_prefix) {
  const int x = 8;
  const int y = 70;
  const int height = 80;

  if (show_graph) {
    SkRect visualizationRect = SkRect::MakeWH(width, height);
    stopwatch.visualize(canvas, visualizationRect);
  }

  if (show_labels) {
    double msPerFrame = stopwatch.lastLap().InMillisecondsF();
    double fps = 1e3 / msPerFrame;

    std::stringstream stream;
    stream.setf(std::ios::fixed | std::ios::showpoint);
    stream << std::setprecision(2);
    stream << label_prefix << " " << fps << " FPS | " << msPerFrame
           << "ms/frame";
    PaintContext_DrawStatisticsText(canvas, stream.str(), x, y);
  }

  if (show_labels || show_graph) {
    canvas.translate(0, height);
  }
}

void StatisticsLayer::Paint(PaintContext::ScopedFrame& frame) {
  if (!options_.anyEnabled()) {
    return;
  }

  using Opt = CompositorOptions::Option;

  SkScalar width = has_paint_bounds() ? paint_bounds().width() : 0;
  SkAutoCanvasRestore save(&frame.canvas(), false);

  VisualizeStopWatch(frame.canvas(), frame.context().frame_time(), width,
                     options_.isEnabled(Opt::VisualizeRasterizerStatistics),
                     options_.isEnabled(Opt::DisplayRasterizerStatistics),
                     "Rasterizer");

  VisualizeStopWatch(frame.canvas(), frame.context().engine_time(), width,
                     options_.isEnabled(Opt::VisualizeEngineStatistics),
                     options_.isEnabled(Opt::DisplayEngineStatistics),
                     "Engine");
}

}  // namespace compositor
}  // namespace sky
<commit_msg>StatisticsLayer was shifting subsequent paints.<commit_after>// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>
#include <iostream>
#include <iomanip>

#include "sky/compositor/statistics_layer.h"

namespace sky {
namespace compositor {

StatisticsLayer::StatisticsLayer(uint64_t enabledOptions)
    : options_(enabledOptions) {
}

static void PaintContext_DrawStatisticsText(SkCanvas& canvas,
                                            const std::string& string,
                                            int x,
                                            int y) {
  SkPaint paint;
  paint.setTextSize(14);
  paint.setLinearText(false);
  paint.setColor(SK_ColorRED);
  canvas.drawText(string.c_str(), string.size(), x, y, paint);
}

static void VisualizeStopWatch(SkCanvas& canvas,
                               const instrumentation::Stopwatch& stopwatch,
                               SkScalar width,
                               bool show_graph,
                               bool show_labels,
                               std::string label_prefix) {
  const int x = 8;
  const int y = 70;
  const int height = 80;

  if (show_graph) {
    SkRect visualizationRect = SkRect::MakeWH(width, height);
    stopwatch.visualize(canvas, visualizationRect);
  }

  if (show_labels) {
    double msPerFrame = stopwatch.lastLap().InMillisecondsF();
    double fps = 1e3 / msPerFrame;

    std::stringstream stream;
    stream.setf(std::ios::fixed | std::ios::showpoint);
    stream << std::setprecision(2);
    stream << label_prefix << " " << fps << " FPS | " << msPerFrame
           << "ms/frame";
    PaintContext_DrawStatisticsText(canvas, stream.str(), x, y);
  }

  if (show_labels || show_graph) {
    canvas.translate(0, height);
  }
}

void StatisticsLayer::Paint(PaintContext::ScopedFrame& frame) {
  if (!options_.anyEnabled()) {
    return;
  }

  using Opt = CompositorOptions::Option;

  SkScalar width = has_paint_bounds() ? paint_bounds().width() : 0;
  SkAutoCanvasRestore save(&frame.canvas(), true);

  VisualizeStopWatch(frame.canvas(), frame.context().frame_time(), width,
                     options_.isEnabled(Opt::VisualizeRasterizerStatistics),
                     options_.isEnabled(Opt::DisplayRasterizerStatistics),
                     "Rasterizer");

  VisualizeStopWatch(frame.canvas(), frame.context().engine_time(), width,
                     options_.isEnabled(Opt::VisualizeEngineStatistics),
                     options_.isEnabled(Opt::DisplayEngineStatistics),
                     "Engine");
}

}  // namespace compositor
}  // namespace sky
<|endoftext|>