<commit_before>#include "gen.h"
#include <cassert>
#include <cstdio>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#ifdef __clang__
#include "omp.h"
#else
#include <omp.h>
#endif

const weight_t MAX_WEIGHT = 1.0;

//
// Global data
//
vid_t vertexCount;
eid_t edgesCount;
eid_t *edgesIds;
Edge *edges;
bool *isCoolEdge;
int threadsCount;
int iterationNumber;

//
// BFS-reorder specific variable
//
bool *componentEnd;

//
// Edge comparators
//
bool EdgeDestCmp::operator()(const Edge& a, const Edge& b) const {
    if (a.dest != b.dest) return a.dest < b.dest;
    return a.weight < b.weight;
}

bool EdgeWeightCmp::operator()(const Edge& a, const Edge& b) const {
    return a.weight < b.weight;
}

//
// Reorder functions
//
void doReorderBfs() {
    stickThisThreadToCore(0);

    componentEnd = new bool[vertexCount];
    bool *visit = new bool[vertexCount];
    vid_t *que = static_cast<vid_t*>(malloc(sizeof(vid_t) * vertexCount));
    vid_t *rev = static_cast<vid_t*>(malloc(sizeof(vid_t) * vertexCount));
    vid_t fr = 0, bc = 0;
    for (vid_t i = 0; i < vertexCount; ++i) if (!visit[i]) {
        que[bc++] = i;
        while (fr < bc) {
            const vid_t v = que[fr++];
            visit[v] = true;
            for (eid_t e = edgesIds[v]; e < edgesIds[v + 1]; ++e) {
                const vid_t u = edges[e].dest;
                if (visit[u]) continue;
                visit[u] = true;
                que[bc++] = u;
            }
        }
        componentEnd[bc - 1] = true;
    }
    assert(bc == vertexCount);
    delete[] visit;

#pragma omp parallel for
    for (vid_t i = 0; i < vertexCount; ++i)
        rev[que[i]] = i;

    eid_t *nextEdgesIds = static_cast<eid_t*>(malloc(sizeof(eid_t) * (vertexCount + 1)));
    Edge *nextEdges = static_cast<Edge*>(malloc(sizeof(Edge) * edgesCount));
    nextEdgesIds[0] = 0;
    for (int i = 0; i < threadsCount; ++i) {
        stickThisThreadToCore(i);
        const vid_t vertexBegin = int64_t(vertexCount) * (i + 0) / threadsCount;
        const vid_t vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        for (vid_t v = vertexBegin; v < vertexEnd; ++v) {
            const vid_t nextv = que[v];
            nextEdgesIds[v + 1] = nextEdgesIds[v] + edgesIds[nextv + 1] - edgesIds[nextv];
        }
    }
#pragma omp parallel
    {
        const int i = omp_get_thread_num();
        stickThisThreadToCore(i);
        const vid_t vertexBegin = int64_t(vertexCount) * i / threadsCount;
        const vid_t vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        for (vid_t v = vertexBegin; v < vertexEnd; ++v) {
            const vid_t nextv = que[v];
            for (eid_t e = edgesIds[nextv]; e < edgesIds[nextv + 1]; ++e) {
                nextEdges[nextEdgesIds[v] + e - edgesIds[nextv]] = edges[e];
                nextEdges[nextEdgesIds[v] + e - edgesIds[nextv]].dest = rev[edges[e].dest];
            }
        }
    }

    free(que);
    free(rev);
    free(edges);
    free(edgesIds);
    edges = nextEdges;
    edgesIds = nextEdgesIds;
}

void doReorderSimple() {
    stickThisThreadToCore(0);

    bool *visit = new bool[vertexCount];
    vid_t *que = static_cast<vid_t*>(malloc(sizeof(vid_t) * vertexCount));
    vid_t *rev = static_cast<vid_t*>(malloc(sizeof(vid_t) * vertexCount));
    vid_t pos = 0;
    for (vid_t v = 0; v < vertexCount; ++v) if (!visit[v]) {
        visit[v] = true;
        que[pos++] = v;
        for (eid_t e = edgesIds[v]; e < edgesIds[v + 1]; ++e) {
            const vid_t u = edges[e].dest;
            if (visit[u]) continue;
            visit[u] = true;
            que[pos++] = u;
        }
    }
    assert(pos == vertexCount);
    delete[] visit;

#pragma omp parallel for
    for (vid_t i = 0; i < vertexCount; ++i)
        rev[que[i]] = i;

    eid_t *nextEdgesIds = static_cast<eid_t*>(malloc(sizeof(eid_t) * (vertexCount + 1)));
    Edge *nextEdges = static_cast<Edge*>(malloc(sizeof(Edge) * edgesCount));
    nextEdgesIds[0] = 0;
    for (int i = 0; i < threadsCount; ++i) {
        stickThisThreadToCore(i);
        const vid_t vertexBegin = int64_t(vertexCount) * (i + 0) / threadsCount;
        const vid_t vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        for (vid_t v = vertexBegin; v < vertexEnd; ++v) {
            const vid_t nextv = que[v];
            nextEdgesIds[v + 1] = nextEdgesIds[v] + edgesIds[nextv + 1] - edgesIds[nextv];
        }
    }
#pragma omp parallel
    {
        const int i = omp_get_thread_num();
        stickThisThreadToCore(i);
        const vid_t vertexBegin = int64_t(vertexCount) * i / threadsCount;
        const vid_t vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        for (vid_t v = vertexBegin; v < vertexEnd; ++v) {
            const vid_t nextv = que[v];
            for (eid_t e = edgesIds[nextv]; e < edgesIds[nextv + 1]; ++e) {
                nextEdges[nextEdgesIds[v] + e - edgesIds[nextv]] = edges[e];
                nextEdges[nextEdgesIds[v] + e - edgesIds[nextv]].dest = rev[edges[e].dest];
            }
        }
    }
    free(que);
    free(rev);
    free(edges);
    free(edgesIds);
    edges = nextEdges;
    edgesIds = nextEdgesIds;
}

//
// Read input data
//
void readAll(char *filename) {
    iterationNumber = 0;
#pragma omp parallel
    {
#pragma omp master
        {
            threadsCount = omp_get_num_threads();
        }
    }

    FILE *f = fopen(filename, "rb");
    assert(f);

    fread(&vertexCount, sizeof(vid_t), 1, f);
    fread(&edgesCount, sizeof(eid_t), 1, f);

    // NUMA-specific part
    // Each core allocate memory and read data, which will processed on this core
    edgesIds = (eid_t*)malloc(sizeof(eid_t) * (vertexCount + 1));
    edges = (Edge*)malloc(sizeof(Edge) * (edgesCount));

    for (int i = 0; i < threadsCount; ++i) {
        stickThisThreadToCore(i);
        const int vertexBegin = int64_t(vertexCount + 1) * i / threadsCount;
        const int vertexEnd   = int64_t(vertexCount + 1) * (i + 1) / threadsCount;
        fread(edgesIds + vertexBegin, sizeof(eid_t), vertexEnd - vertexBegin, f);
    }

    for (int i = 0; i < threadsCount; ++i) {
        stickThisThreadToCore(i);
        const int vertexBegin = int64_t(vertexCount) * i / threadsCount;
        const int vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        const int edgeBegin   = edgesIds[vertexBegin];
        const int edgeEnd     = edgesIds[vertexEnd];
        fread(edges + edgeBegin, sizeof(Edge), edgeEnd - edgeBegin, f);
    }
    fclose(f);
}

void convertAll(graph_t *G) {
    iterationNumber = 0;
#pragma omp parallel
    {
#pragma omp master
        {
            threadsCount = omp_get_num_threads();
        }
    }

    // TODO NUMA
    vertexCount = G->n;
    edgesCount = G->m;
    edgesIds = (eid_t*)malloc(sizeof(eid_t) * (vertexCount + 1));
    edges = (Edge*)malloc(sizeof(Edge) * (edgesCount));
    for (vid_t i = 0; i <= vertexCount; ++i)
        edgesIds[i] = static_cast<eid_t>(G->rowsIndices[i]);
    for (eid_t i = 0; i < edgesCount; ++i) {
        edges[i].dest = G->endV[i];
        edges[i].weight = G->weights[i];
    }
}

//
// Timer functions
//
int64_t currentNanoTime() {
    timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return int64_t(ts.tv_sec) * int64_t(1e9) + ts.tv_nsec;
}

RDTSC::RDTSC() {
    double t1, t2;
    t1 = get();
    sleep(1);
    t2 = get();
    oneSecond = (t2 - t1);
}

double RDTSC::get() {
    unsigned int time_edx, time_eax;

#ifdef ON_JSCC
    unsigned a, d;
    asm volatile("rdtsc" : "=a" (a), "=d" (d));
    return ((unsigned long long)a) | (((unsigned long long)d) << 32);
#endif

    asm volatile (  "rdtscp\n\t"
            "mov %%edx, %0\n\t"
            "mov %%eax, %1\n\t"
            //                    "cpuid\n\t"
            : "=r"(time_edx), "=r"(time_eax) ::
            "%rax", "%rbx", "%rcx", "%rdx");

    return (double)(((unsigned long long)time_edx) << 32 | (unsigned long long)time_eax);
}

void RDTSC::start(int timerId) {
    timers[timerId][0] = get();
}

double RDTSC::end(int timerId) {
    double res = (get() - timers[timerId][0]) / oneSecond;
    return res;
}

RDTSC rdtsc;

int stickThisThreadToCore(int coreId) {
    const int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
#ifdef ON_HOME
    coreId *= 2;
    coreId += 1;
#endif /* ON_HOME */
#ifdef USE_HYPERTHREADING
    int hardwareCoreId = coreId / 2;
    int htOffset = num_cores / 2;
    coreId = hardwareCoreId + htOffset * (coreId % 2);
#endif /* USE_HYPERTHREADING */
    if (coreId >= num_cores) return 0;

    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(coreId, &cpuset);

    pthread_t current_thread = pthread_self();
    return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
}
<commit_msg>Fix bool allocation.<commit_after>#include "gen.h"
#include <set>
#include <cassert>
#include <cstdio>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#ifdef __clang__
#include "omp.h"
#else
#include <omp.h>
#endif

const weight_t MAX_WEIGHT = 1.0;

//
// Global data
//
vid_t vertexCount;
eid_t edgesCount;
eid_t *edgesIds;
Edge *edges;
bool *isCoolEdge;
int threadsCount;
int iterationNumber;

//
// BFS-reorder specific variable
//
bool *componentEnd;

//
// Edge comparators
//
bool EdgeDestCmp::operator()(const Edge& a, const Edge& b) const {
    if (a.dest != b.dest) return a.dest < b.dest;
    return a.weight < b.weight;
}

bool EdgeWeightCmp::operator()(const Edge& a, const Edge& b) const {
    return a.weight < b.weight;
}

//
// Reorder functions
//
void doReorderBfs() {
    stickThisThreadToCore(0);

    componentEnd = new bool[vertexCount]();
    bool *visit = new bool[vertexCount]();
    vid_t *que = static_cast<vid_t*>(malloc(sizeof(vid_t) * vertexCount));
    vid_t *rev = static_cast<vid_t*>(malloc(sizeof(vid_t) * vertexCount));
    vid_t fr = 0, bc = 0;
    for (vid_t i = 0; i < vertexCount; ++i) if (!visit[i]) {
        que[bc++] = i;
        while (fr < bc) {
            const vid_t v = que[fr++];
            visit[v] = true;
            for (eid_t e = edgesIds[v]; e < edgesIds[v + 1]; ++e) {
                const vid_t u = edges[e].dest;
                if (visit[u]) continue;
                visit[u] = true;
                que[bc++] = u;
            }
        }
        componentEnd[bc - 1] = true;
    }
    assert(bc == vertexCount);
    delete[] visit;

#pragma omp parallel for
    for (vid_t i = 0; i < vertexCount; ++i)
        rev[que[i]] = i;

    eid_t *nextEdgesIds = static_cast<eid_t*>(malloc(sizeof(eid_t) * (vertexCount + 1)));
    Edge *nextEdges = static_cast<Edge*>(malloc(sizeof(Edge) * edgesCount));
    nextEdgesIds[0] = 0;
    for (int i = 0; i < threadsCount; ++i) {
        stickThisThreadToCore(i);
        const vid_t vertexBegin = int64_t(vertexCount) * (i + 0) / threadsCount;
        const vid_t vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        for (vid_t v = vertexBegin; v < vertexEnd; ++v) {
            const vid_t nextv = que[v];
            nextEdgesIds[v + 1] = nextEdgesIds[v] + edgesIds[nextv + 1] - edgesIds[nextv];
        }
    }
#pragma omp parallel
    {
        const int i = omp_get_thread_num();
        stickThisThreadToCore(i);
        const vid_t vertexBegin = int64_t(vertexCount) * i / threadsCount;
        const vid_t vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        for (vid_t v = vertexBegin; v < vertexEnd; ++v) {
            const vid_t nextv = que[v];
            for (eid_t e = edgesIds[nextv]; e < edgesIds[nextv + 1]; ++e) {
                nextEdges[nextEdgesIds[v] + e - edgesIds[nextv]] = edges[e];
                nextEdges[nextEdgesIds[v] + e - edgesIds[nextv]].dest = rev[edges[e].dest];
            }
        }
    }

    free(que);
    free(rev);
    free(edges);
    free(edgesIds);
    edges = nextEdges;
    edgesIds = nextEdgesIds;
}

void doReorderSimple() {
    stickThisThreadToCore(0);

    bool *visit = new bool[vertexCount]();
    vid_t *que = static_cast<vid_t*>(malloc(sizeof(vid_t) * vertexCount));
    vid_t *rev = static_cast<vid_t*>(malloc(sizeof(vid_t) * vertexCount));
    vid_t pos = 0;
    for (vid_t v = 0; v < vertexCount; ++v) if (!visit[v]) {
        visit[v] = true;
        que[pos++] = v;
        for (eid_t e = edgesIds[v]; e < edgesIds[v + 1]; ++e) {
            const vid_t u = edges[e].dest;
            if (visit[u]) continue;
            visit[u] = true;
            que[pos++] = u;
        }
    }
    assert(pos == vertexCount);
    delete[] visit;

#pragma omp parallel for
    for (vid_t i = 0; i < vertexCount; ++i)
        rev[que[i]] = i;

    eid_t *nextEdgesIds = static_cast<eid_t*>(malloc(sizeof(eid_t) * (vertexCount + 1)));
    Edge *nextEdges = static_cast<Edge*>(malloc(sizeof(Edge) * edgesCount));
    nextEdgesIds[0] = 0;
    for (int i = 0; i < threadsCount; ++i) {
        stickThisThreadToCore(i);
        const vid_t vertexBegin = int64_t(vertexCount) * (i + 0) / threadsCount;
        const vid_t vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        for (vid_t v = vertexBegin; v < vertexEnd; ++v) {
            const vid_t nextv = que[v];
            nextEdgesIds[v + 1] = nextEdgesIds[v] + edgesIds[nextv + 1] - edgesIds[nextv];
        }
    }
#pragma omp parallel
    {
        const int i = omp_get_thread_num();
        stickThisThreadToCore(i);
        const vid_t vertexBegin = int64_t(vertexCount) * i / threadsCount;
        const vid_t vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        for (vid_t v = vertexBegin; v < vertexEnd; ++v) {
            const vid_t nextv = que[v];
            for (eid_t e = edgesIds[nextv]; e < edgesIds[nextv + 1]; ++e) {
                nextEdges[nextEdgesIds[v] + e - edgesIds[nextv]] = edges[e];
                nextEdges[nextEdgesIds[v] + e - edgesIds[nextv]].dest = rev[edges[e].dest];
            }
        }
    }
    free(que);
    free(rev);
    free(edges);
    free(edgesIds);
    edges = nextEdges;
    edgesIds = nextEdgesIds;
}

//
// Read input data
//
void readAll(char *filename) {
    iterationNumber = 0;
#pragma omp parallel
    {
#pragma omp master
        {
            threadsCount = omp_get_num_threads();
        }
    }
    Eo(threadsCount);

    FILE *f = fopen(filename, "rb");
    assert(f);

    fread(&vertexCount, sizeof(vid_t), 1, f);
    fread(&edgesCount, sizeof(eid_t), 1, f);

    // NUMA-specific part
    // Each core allocate memory and read data, which will processed on this core
    edgesIds = (eid_t*)malloc(sizeof(eid_t) * (vertexCount + 1));
    edges = (Edge*)malloc(sizeof(Edge) * (edgesCount));

    for (int i = 0; i < threadsCount; ++i) {
        stickThisThreadToCore(i);
        const int vertexBegin = int64_t(vertexCount + 1) * i / threadsCount;
        const int vertexEnd   = int64_t(vertexCount + 1) * (i + 1) / threadsCount;
        fread(edgesIds + vertexBegin, sizeof(eid_t), vertexEnd - vertexBegin, f);
    }

    for (int i = 0; i < threadsCount; ++i) {
        stickThisThreadToCore(i);
        const int vertexBegin = int64_t(vertexCount) * i / threadsCount;
        const int vertexEnd   = int64_t(vertexCount) * (i + 1) / threadsCount;
        const int edgeBegin   = edgesIds[vertexBegin];
        const int edgeEnd     = edgesIds[vertexEnd];
        fread(edges + edgeBegin, sizeof(Edge), edgeEnd - edgeBegin, f);
    }
    fclose(f);
}

void convertAll(graph_t *G) {
    iterationNumber = 0;
#pragma omp parallel
    {
#pragma omp master
        {
            threadsCount = omp_get_num_threads();
        }
    }

    //std::set<weight_t> allWeight;

    // TODO NUMA
    vertexCount = G->n;
    edgesCount = G->m;
    edgesIds = (eid_t*)malloc(sizeof(eid_t) * (vertexCount + 1));
    edges = (Edge*)malloc(sizeof(Edge) * (edgesCount));
    for (vid_t i = 0; i <= vertexCount; ++i)
        edgesIds[i] = static_cast<eid_t>(G->rowsIndices[i]);
    for (eid_t i = 0; i < edgesCount; ++i) {
        edges[i].dest = G->endV[i];
        edges[i].weight = G->weights[i];
        //allWeight.insert(edges[i].weight);
    }
    //Eo(allWeight.size());
}

//
// Timer functions
//
int64_t currentNanoTime() {
    timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return int64_t(ts.tv_sec) * int64_t(1e9) + ts.tv_nsec;
}

RDTSC::RDTSC() {
    double t1, t2;
    t1 = get();
    sleep(1);
    t2 = get();
    oneSecond = (t2 - t1);
}

double RDTSC::get() {
    unsigned int time_edx, time_eax;

#ifdef ON_JSCC
    unsigned a, d;
    asm volatile("rdtsc" : "=a" (a), "=d" (d));
    return ((unsigned long long)a) | (((unsigned long long)d) << 32);
#endif

    asm volatile (  "rdtscp\n\t"
            "mov %%edx, %0\n\t"
            "mov %%eax, %1\n\t"
            //                    "cpuid\n\t"
            : "=r"(time_edx), "=r"(time_eax) ::
            "%rax", "%rbx", "%rcx", "%rdx");

    return (double)(((unsigned long long)time_edx) << 32 | (unsigned long long)time_eax);
}

void RDTSC::start(int timerId) {
    timers[timerId][0] = get();
}

double RDTSC::end(int timerId) {
    double res = (get() - timers[timerId][0]) / oneSecond;
    return res;
}

RDTSC rdtsc;

int stickThisThreadToCore(int coreId) {
    const int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
#ifdef ON_HOME
    coreId *= 2;
    coreId += 1;
#endif /* ON_HOME */
#ifdef USE_HYPERTHREADING
    int hardwareCoreId = coreId / 2;
    int htOffset = num_cores / 2;
    coreId = hardwareCoreId + htOffset * (coreId % 2);
#endif /* USE_HYPERTHREADING */
    if (coreId >= num_cores) return 0;

    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(coreId, &cpuset);

    pthread_t current_thread = pthread_self();
    return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
}
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <MScalableImage>
#include <MImageWidget>
#include <MLabel>
#include <MWidgetController>
#include <MWidgetView>
#include <MSeparator>

#include <QGraphicsGridLayout>
#include <QGraphicsLinearLayout>
#include <QGraphicsSceneEvent>

#include "mbubbleitem.h"
#include "mbubbleitemview.h"
#include "mbubbleitemview_p.h"
#include "mbubbleitembackground_p.h"

MBubbleItemViewPrivate::MBubbleItemViewPrivate()
        : avatar(0),
        speechBubble(0),
        timeStampLabel(0),
        messageComposition(0),
        separator(0),
        currentCentralWidget(0)
{
    layout = new QGraphicsGridLayout;
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);

    informationWidgetsLayout = new QGraphicsLinearLayout(Qt::Horizontal);
    informationWidgetsLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
    informationWidgetsLayout->setContentsMargins(0, 0, 0, 0);
    informationWidgetsLayout->setSpacing(0);

    informationWidgetsSpacer = new QGraphicsWidget;
    informationWidgetsSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);

    innerLayout = new QGraphicsLinearLayout(Qt::Vertical);
    innerLayout->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
    innerLayout->setContentsMargins(0, 0, 0, 0);
    innerLayout->setSpacing(0);

    timeStampLabel = new MLabel();
    timeStampLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

    messageComposition = new MLabel();
    messageComposition->setWordWrap(true);
    messageComposition->setAlignment(Qt::AlignLeft);
    messageComposition->setTextFormat(Qt::RichText);
}

MBubbleItemViewPrivate::~MBubbleItemViewPrivate()
{
    clearLayout();
}

void MBubbleItemViewPrivate::initLayout()
{
    clearLayout();

    replaceAvatar();

    if (controller->messageType() == MBubbleItem::Incoming) {
        if (controller->avatar()) {
            layout->addItem(controller->avatar(), 0, 0);
            layout->addItem(speechBubble, 0, 1);
        } else {
            layout->addItem(speechBubble, 0, 0);
        }
    } else if(controller->messageType() == MBubbleItem::Outgoing) {
        layout->addItem(speechBubble, 0, 0);
        if (controller->avatar())
            layout->addItem(controller->avatar(), 0, 1);
    }

    updateInformationWidgetsLayout();

    innerLayout->addItem(messageComposition);
    innerLayout->addItem(informationWidgetsLayout);

    setupCentralWidget();

    controller->connect(speechBubble, SIGNAL(clicked()), controller, SIGNAL(bubbleClicked()), Qt::UniqueConnection);
}

void MBubbleItemViewPrivate::clearLayout()
{
    while (layout->count())
        layout->removeAt(0);
    while (innerLayout->count())
        innerLayout->removeAt(0);
}

void MBubbleItemViewPrivate::replaceAvatar()
{
    Q_Q(MBubbleItemView);

    if (avatar) {
        for (int i = 0; i < layout->count(); i ++) {
            if (layout->itemAt(i) == avatar)
                layout->removeAt(i);
        }
        avatar = 0;
    }

    if (controller->avatar()) {
        if (controller->avatar()->objectName().isEmpty())
            controller->avatar()->setObjectName(q->style()->avatarObjectName());
        if (controller->messageType() == MBubbleItem::Incoming) {
            layout->addItem(controller->avatar(), 0, 0);
            layout->addItem(speechBubble, 0, 1);
        }
        else
            layout->addItem(controller->avatar(), 0, 1);
        avatar = controller->avatar();
    }
}

void MBubbleItemViewPrivate::setupCentralWidget()
{
    Q_Q(MBubbleItemView);

    if (q->model()->centralWidget() &&
        q->model()->centralWidget() != currentCentralWidget) {
        separator = new MSeparator;
        separator->setOrientation(Qt::Horizontal);
        innerLayout->addItem(separator);

        currentCentralWidget = q->model()->centralWidget();
        innerLayout->addItem(currentCentralWidget);
    } else {
        if (separator) {
            innerLayout->removeItem(separator);
            delete separator;
            separator = 0;
        }

        if (currentCentralWidget) {
            innerLayout->removeItem(currentCentralWidget);
            currentCentralWidget = 0;
        }
    }
}

void MBubbleItemViewPrivate::clearInformationWidgetsLayout()
{
    for (int i = 0; i < informationWidgetsLayout->count(); i++)
        informationWidgetsLayout->removeAt(0);
}

void MBubbleItemViewPrivate::updateInformationWidgetsLayout()
{
    Q_Q(MBubbleItemView);

    clearInformationWidgetsLayout();

    foreach (QGraphicsWidget *widget, q->model()->informationWidgets()) {
        informationWidgetsLayout->addItem(widget);
        informationWidgetsLayout->setAlignment(widget, Qt::AlignVCenter | Qt::AlignRight);
    }

    informationWidgetsLayout->addItem(informationWidgetsSpacer);
    informationWidgetsLayout->addItem(timeStampLabel);
}

void MBubbleItemViewPrivate::applyStyle()
{
    refreshStyleMode();
}

void MBubbleItemView::setGeometry(const QRectF &rect)
{
    MWidgetView::setGeometry(rect);

    Q_D(MBubbleItemView);
    d->updateMessageComposition();
}

void MBubbleItemViewPrivate::refreshStyleMode()
{
    Q_Q(MBubbleItemView);
    if (controller->messageType() == MBubbleItem::Incoming)
        q->style().setModeDefault();
    else
        q->style().setModeOutgoing();

    if (speechBubble)
        speechBubble->setObjectName(q->style()->bubbleObjectName());

    if (timeStampLabel) {
        timeStampLabel->setFont(q->style()->timestampFont());
        timeStampLabel->setColor(q->style()->timestampTextColor());
    }

    if (messageComposition) {
        messageComposition->setFont(q->style()->font());
        messageComposition->setColor(q->style()->textColor());
    }

    controller->setContentsMargins(q->style()->marginLeft(),
                                   q->style()->marginTop(),
                                   q->style()->marginRight(),
                                   q->style()->marginBottom());
}

void MBubbleItemViewPrivate::updateMessageComposition()
{
    Q_Q(MBubbleItemView);

    if (controller->messageType() == MBubbleItem::Incoming) {
        QString senderName = q->model()->senderName();
        if (senderName.isEmpty()) {
            messageComposition->setText(q->model()->message());
        } else {
            QFont boldFontForSendername( messageComposition->font() );
            boldFontForSendername.setBold(true);
            QFontMetrics fontMetrics(boldFontForSendername);

            if (fontMetrics.width(senderName) > messageComposition->size().width())
                senderName = fontMetrics.elidedText(senderName, Qt::ElideRight,
                                                    messageComposition->size().width()
                                                    - fontMetrics.size( Qt::TextSingleLine, "...:" ).width()
                                                    );

            messageComposition->setText( "" + senderName + ": " + q->model()->message());
        }
    } else if (controller->messageType() == MBubbleItem::Outgoing)
        messageComposition->setText(q->model()->message());

}
MBubbleItemView::MBubbleItemView(MBubbleItem *controller)
    : MWidgetView(* new MBubbleItemViewPrivate, controller)
{
    Q_D(MBubbleItemView);
    d->controller = controller;
    controller->setLayout(d->layout);
}

MBubbleItemView::MBubbleItemView(MBubbleItemViewPrivate &dd, MBubbleItem *controller)
    : MWidgetView(dd, controller)
{
    Q_D(MBubbleItemView);
    d->controller = controller;
    controller->setLayout(d->layout);
}

MBubbleItemView::~MBubbleItemView()
{
}

void MBubbleItemView::applyStyle()
{
    MWidgetView::applyStyle();

    Q_D(MBubbleItemView);
    d->applyStyle();
}

void MBubbleItemView::updateData(const QList<const char *> &modifications)
{
    Q_D(MBubbleItemView);

    MWidgetView::updateData(modifications);

    const char *member;
    for (int i = 0; i < modifications.count(); i++) {
        member = modifications[i];
        if (member == MBubbleItemModel::Avatar) {
            d->replaceAvatar();
        } else if (member == MBubbleItemModel::SenderName) {
            d->updateMessageComposition();
        } else if (member == MBubbleItemModel::TimeStamp) {
            d->timeStampLabel->setText(model()->timeStamp());
        } else if (member == MBubbleItemModel::Message) {
            d->updateMessageComposition();
        } else if (member == MBubbleItemModel::CentralWidget) {
            d->setupCentralWidget();
        } else if (member == MBubbleItemModel::MessageType) {
            d->speechBubble->setMessageType(static_cast<MBubbleItem::MessageType>(model()->messageType()));
            d->updateMessageComposition();
            d->initLayout();
            d->refreshStyleMode();
        } else if (member == MBubbleItemModel::InformationWidgets) {
            d->updateInformationWidgetsLayout();
        }
    }
}

void MBubbleItemView::setupModel()
{
    Q_D(MBubbleItemView);

    MWidgetView::setupModel();

    d->timeStampLabel->setText(model()->timeStamp());

    connect(d->messageComposition, SIGNAL(linkActivated(QString)), d->controller, SIGNAL(linkActivated(QString)));

    d->speechBubble = new MBubbleItemBackground(d->controller);
    d->speechBubble->setMessageType(static_cast<MBubbleItem::MessageType>(model()->messageType()));
    d->speechBubble->setObjectName(style()->bubbleObjectName());
    d->speechBubble->setLayout(d->innerLayout);
    d->speechBubble->setMinimumSize(0,0); //The background must always be smaller than our current geometry

    d->initLayout();
    d->refreshStyleMode();
}

void MBubbleItemView::setSelected(bool selected)
{
    Q_UNUSED(selected);
}

void MBubbleItemView::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void MBubbleItemView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

M_REGISTER_VIEW_NEW(MBubbleItemView, MBubbleItem)

<commit_msg>Changes: Fix a memory leak in MBubbleItemView<commit_after>/***************************************************************************
**
** Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <MScalableImage>
#include <MImageWidget>
#include <MLabel>
#include <MWidgetController>
#include <MWidgetView>
#include <MSeparator>

#include <QGraphicsGridLayout>
#include <QGraphicsLinearLayout>
#include <QGraphicsSceneEvent>

#include "mbubbleitem.h"
#include "mbubbleitemview.h"
#include "mbubbleitemview_p.h"
#include "mbubbleitembackground_p.h"

MBubbleItemViewPrivate::MBubbleItemViewPrivate()
        : avatar(0),
        speechBubble(0),
        timeStampLabel(0),
        messageComposition(0),
        separator(0),
        currentCentralWidget(0)
{
    layout = new QGraphicsGridLayout;
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);

    informationWidgetsLayout = new QGraphicsLinearLayout(Qt::Horizontal);
    informationWidgetsLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
    informationWidgetsLayout->setContentsMargins(0, 0, 0, 0);
    informationWidgetsLayout->setSpacing(0);

    informationWidgetsSpacer = new QGraphicsWidget;
    informationWidgetsSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);

    innerLayout = new QGraphicsLinearLayout(Qt::Vertical);
    innerLayout->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
    innerLayout->setContentsMargins(0, 0, 0, 0);
    innerLayout->setSpacing(0);

    timeStampLabel = new MLabel();
    timeStampLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

    messageComposition = new MLabel();
    messageComposition->setWordWrap(true);
    messageComposition->setAlignment(Qt::AlignLeft);
    messageComposition->setTextFormat(Qt::RichText);
}

MBubbleItemViewPrivate::~MBubbleItemViewPrivate()
{
}

void MBubbleItemViewPrivate::initLayout()
{
    clearLayout();

    replaceAvatar();

    if (controller->messageType() == MBubbleItem::Incoming) {
        if (controller->avatar()) {
            layout->addItem(controller->avatar(), 0, 0);
            layout->addItem(speechBubble, 0, 1);
        } else {
            layout->addItem(speechBubble, 0, 0);
        }
    } else if(controller->messageType() == MBubbleItem::Outgoing) {
        layout->addItem(speechBubble, 0, 0);
        if (controller->avatar())
            layout->addItem(controller->avatar(), 0, 1);
    }

    updateInformationWidgetsLayout();

    innerLayout->addItem(messageComposition);
    innerLayout->addItem(informationWidgetsLayout);

    setupCentralWidget();

    controller->connect(speechBubble, SIGNAL(clicked()), controller, SIGNAL(bubbleClicked()), Qt::UniqueConnection);
}

void MBubbleItemViewPrivate::clearLayout()
{
    while (layout->count())
        layout->removeAt(0);
    while (innerLayout->count())
        innerLayout->removeAt(0);
}

void MBubbleItemViewPrivate::replaceAvatar()
{
    Q_Q(MBubbleItemView);

    if (avatar) {
        for (int i = 0; i < layout->count(); i ++) {
            if (layout->itemAt(i) == avatar)
                layout->removeAt(i);
        }
        avatar = 0;
    }

    if (controller->avatar()) {
        if (controller->avatar()->objectName().isEmpty())
            controller->avatar()->setObjectName(q->style()->avatarObjectName());
        if (controller->messageType() == MBubbleItem::Incoming) {
            layout->addItem(controller->avatar(), 0, 0);
            layout->addItem(speechBubble, 0, 1);
        }
        else
            layout->addItem(controller->avatar(), 0, 1);
        avatar = controller->avatar();
    }
}

void MBubbleItemViewPrivate::setupCentralWidget()
{
    Q_Q(MBubbleItemView);

    if (q->model()->centralWidget() &&
        q->model()->centralWidget() != currentCentralWidget) {
        separator = new MSeparator;
        separator->setOrientation(Qt::Horizontal);
        innerLayout->addItem(separator);

        currentCentralWidget = q->model()->centralWidget();
        innerLayout->addItem(currentCentralWidget);
    } else {
        if (separator) {
            innerLayout->removeItem(separator);
            delete separator;
            separator = 0;
        }

        if (currentCentralWidget) {
            innerLayout->removeItem(currentCentralWidget);
            currentCentralWidget = 0;
        }
    }
}

void MBubbleItemViewPrivate::clearInformationWidgetsLayout()
{
    for (int i = 0; i < informationWidgetsLayout->count(); i++)
        informationWidgetsLayout->removeAt(0);
}

void MBubbleItemViewPrivate::updateInformationWidgetsLayout()
{
    Q_Q(MBubbleItemView);

    clearInformationWidgetsLayout();

    foreach (QGraphicsWidget *widget, q->model()->informationWidgets()) {
        informationWidgetsLayout->addItem(widget);
        informationWidgetsLayout->setAlignment(widget, Qt::AlignVCenter | Qt::AlignRight);
    }

    informationWidgetsLayout->addItem(informationWidgetsSpacer);
    informationWidgetsLayout->addItem(timeStampLabel);
}

void MBubbleItemViewPrivate::applyStyle()
{
    refreshStyleMode();
}

void MBubbleItemView::setGeometry(const QRectF &rect)
{
    MWidgetView::setGeometry(rect);

    Q_D(MBubbleItemView);
    d->updateMessageComposition();
}

void MBubbleItemViewPrivate::refreshStyleMode()
{
    Q_Q(MBubbleItemView);
    if (controller->messageType() == MBubbleItem::Incoming)
        q->style().setModeDefault();
    else
        q->style().setModeOutgoing();

    if (speechBubble)
        speechBubble->setObjectName(q->style()->bubbleObjectName());

    if (timeStampLabel) {
        timeStampLabel->setFont(q->style()->timestampFont());
        timeStampLabel->setColor(q->style()->timestampTextColor());
    }

    if (messageComposition) {
        messageComposition->setFont(q->style()->font());
        messageComposition->setColor(q->style()->textColor());
    }

    controller->setContentsMargins(q->style()->marginLeft(),
                                   q->style()->marginTop(),
                                   q->style()->marginRight(),
                                   q->style()->marginBottom());
}

void MBubbleItemViewPrivate::updateMessageComposition()
{
    Q_Q(MBubbleItemView);

    if (controller->messageType() == MBubbleItem::Incoming) {
        QString senderName = q->model()->senderName();
        if (senderName.isEmpty()) {
            messageComposition->setText(q->model()->message());
        } else {
            QFont boldFontForSendername( messageComposition->font() );
            boldFontForSendername.setBold(true);
            QFontMetrics fontMetrics(boldFontForSendername);

            if (fontMetrics.width(senderName) > messageComposition->size().width())
                senderName = fontMetrics.elidedText(senderName, Qt::ElideRight,
                                                    messageComposition->size().width()
                                                    - fontMetrics.size( Qt::TextSingleLine, "...:" ).width()
                                                    );

            messageComposition->setText( "" + senderName + ": " + q->model()->message());
        }
    } else if (controller->messageType() == MBubbleItem::Outgoing)
        messageComposition->setText(q->model()->message());

}
MBubbleItemView::MBubbleItemView(MBubbleItem *controller)
    : MWidgetView(* new MBubbleItemViewPrivate, controller)
{
    Q_D(MBubbleItemView);
    d->controller = controller;
    controller->setLayout(d->layout);
}

MBubbleItemView::MBubbleItemView(MBubbleItemViewPrivate &dd, MBubbleItem *controller)
    : MWidgetView(dd, controller)
{
    Q_D(MBubbleItemView);
    d->controller = controller;
    controller->setLayout(d->layout);
}

MBubbleItemView::~MBubbleItemView()
{
}

void MBubbleItemView::applyStyle()
{
    MWidgetView::applyStyle();

    Q_D(MBubbleItemView);
    d->applyStyle();
}

void MBubbleItemView::updateData(const QList<const char *> &modifications)
{
    Q_D(MBubbleItemView);

    MWidgetView::updateData(modifications);

    const char *member;
    for (int i = 0; i < modifications.count(); i++) {
        member = modifications[i];
        if (member == MBubbleItemModel::Avatar) {
            d->replaceAvatar();
        } else if (member == MBubbleItemModel::SenderName) {
            d->updateMessageComposition();
        } else if (member == MBubbleItemModel::TimeStamp) {
            d->timeStampLabel->setText(model()->timeStamp());
        } else if (member == MBubbleItemModel::Message) {
            d->updateMessageComposition();
        } else if (member == MBubbleItemModel::CentralWidget) {
            d->setupCentralWidget();
        } else if (member == MBubbleItemModel::MessageType) {
            d->speechBubble->setMessageType(static_cast<MBubbleItem::MessageType>(model()->messageType()));
            d->updateMessageComposition();
            d->initLayout();
            d->refreshStyleMode();
        } else if (member == MBubbleItemModel::InformationWidgets) {
            d->updateInformationWidgetsLayout();
        }
    }
}

void MBubbleItemView::setupModel()
{
    Q_D(MBubbleItemView);

    MWidgetView::setupModel();

    d->timeStampLabel->setText(model()->timeStamp());

    connect(d->messageComposition, SIGNAL(linkActivated(QString)), d->controller, SIGNAL(linkActivated(QString)));

    d->speechBubble = new MBubbleItemBackground(d->controller);
    d->speechBubble->setMessageType(static_cast<MBubbleItem::MessageType>(model()->messageType()));
    d->speechBubble->setObjectName(style()->bubbleObjectName());
    d->speechBubble->setLayout(d->innerLayout);
    d->speechBubble->setMinimumSize(0,0); //The background must always be smaller than our current geometry

    d->initLayout();
    d->refreshStyleMode();
}

void MBubbleItemView::setSelected(bool selected)
{
    Q_UNUSED(selected);
}

void MBubbleItemView::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

void MBubbleItemView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event);
}

M_REGISTER_VIEW_NEW(MBubbleItemView, MBubbleItem)

<|endoftext|>


<commit_before>#include "archivewidget.h"

WARNINGS_DISABLE
#include <QAction>
#include <QComboBox>
#include <QCursor>
#include <QDateTime>
#include <QEvent>
#include <QKeyEvent>
#include <QKeySequence>
#include <QLabel>
#include <QMenu>
#include <QModelIndex>
#include <QModelIndexList>
#include <QSortFilterProxyModel>
#include <QStringList>
#include <QTableView>
#include <QVariant>
#include <Qt>

#include "ui_archivewidget.h"
WARNINGS_ENABLE

#include "TElidedLabel.h"

#include "messages/archiverestoreoptions.h"

#include "basetask.h"
#include "elidedclickablelabel.h"
#include "filetablemodel.h"
#include "persistentmodel/archive.h"
#include "restoredialog.h"
#include "utils.h"

#define EMPTY_TAR_ARCHIVE_BYTES 2000

ArchiveDetailsWidget::ArchiveDetailsWidget(QWidget *parent)
    : QWidget(parent),
      _ui(new Ui::ArchiveDetailsWidget),
      _contentsModel(new FileTableModel(this)),
      _proxyModel(new QSortFilterProxyModel(_contentsModel)),
      _fileMenu(new QMenu(this))
{
    _ui->setupUi(this);
    updateUi();

    // Set up filter UI.
    _ui->filterComboBox->hide();
    _proxyModel->setDynamicSortFilter(false);
    _proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    _proxyModel->setSourceModel(_contentsModel);
    _ui->archiveContentsTableView->setModel(_proxyModel);
    _ui->archiveContentsTableView->setContextMenuPolicy(Qt::CustomContextMenu);

    // Set up other UI.
    _fileMenu->addAction(_ui->actionRestoreFiles);

    // Connections for UI functionality.
    connect(_ui->archiveContentsTableView,
            &QTableView::customContextMenuRequested, this,
            &ArchiveDetailsWidget::showContextMenu);
    connect(_ui->actionRestoreFiles, &QAction::triggered, this,
            &ArchiveDetailsWidget::restoreFiles);
    connect(_ui->archiveContentsTableView, &QTableView::activated, this,
            &ArchiveDetailsWidget::restoreFiles);
    connect(_ui->hideButton, &QPushButton::clicked, this,
            &ArchiveDetailsWidget::close);
    connect(_contentsModel, &FileTableModel::taskRequested, this,
            &ArchiveDetailsWidget::taskRequested);
    connect(_ui->archiveJobLabel, &ElidedClickableLabel::clicked,
            [this]() { emit jobClicked(_archive->jobRef()); });

    // Connection to reset the model.
    connect(_contentsModel, &FileTableModel::modelReset, [this]() {
        _ui->archiveContentsTableView->resizeColumnsToContents();
        _ui->archiveContentsLabel->setText(
            tr("Contents (%1)").arg(_contentsModel->rowCount()));
    });

    // Connections for filtering
    connect(_ui->filterComboBox, &QComboBox::editTextChanged, _proxyModel,
            &QSortFilterProxyModel::setFilterWildcard);
    connect(_ui->filterComboBox,
            static_cast<void (QComboBox::*)(int)>(
                &QComboBox::currentIndexChanged),
            [this]() { _ui->archiveContentsTableView->setFocus(); });
    connect(_ui->filterButton, &QPushButton::toggled,
            [this](const bool checked) {
                _ui->filterComboBox->setVisible(checked);
                if(checked)
                    _ui->filterComboBox->setFocus();
                else
                    _ui->filterComboBox->clearEditText();
            });
}

ArchiveDetailsWidget::~ArchiveDetailsWidget()
{
    delete _proxyModel;
    delete _contentsModel;
    delete _ui;
}

void ArchiveDetailsWidget::setArchive(ArchivePtr archive)
{
    // Remove previous connections (if applicable).
    if(_archive)
    {
        disconnect(_archive.data(), &Archive::changed, this,
                   &ArchiveDetailsWidget::updateDetails);
        disconnect(_archive.data(), &Archive::purged, this,
                   &ArchiveDetailsWidget::close);
    }

    // Store pointer.
    _archive = archive;

    // Set up new connections and refresh the display.
    if(_archive)
    {
        connect(_archive.data(), &Archive::changed, this,
                &ArchiveDetailsWidget::updateDetails);
        connect(_archive.data(), &Archive::purged, this,
                &ArchiveDetailsWidget::close);
        updateDetails();
    }
    else
    {
        // No need to store info about the previous Archive.
        _contentsModel->reset();
    }
}

void ArchiveDetailsWidget::updateDetails()
{
    // Bail (if applicable).
    if(!_archive)
        return;

    // Show basic archive info.
    _ui->archiveNameLabel->setText(_archive->name());
    _ui->archiveDateLabel->setText(
        _archive->timestamp().toString(Qt::DefaultLocaleLongDate));

    // Show info about a linked Job (if applicable).
    if(_archive->jobRef().isEmpty())
    {
        _ui->archiveJobLabel->hide();
        _ui->archiveJobLabelField->hide();
        _ui->archiveIconLabel->setStyleSheet(
            "image: url(:/logos/tarsnap-icon-big.png)");
    }
    else
    {
        _ui->archiveJobLabel->show();
        _ui->archiveJobLabelField->show();
        _ui->archiveJobLabel->setText(_archive->jobRef());
        _ui->archiveIconLabel->setStyleSheet(
            "image: url(:/icons/hard-drive-big.png)");
    }

    // Show size info about the archive.
    _ui->archiveSizeLabel->setText(Utils::humanBytes(_archive->sizeTotal()));
    _ui->archiveSizeLabel->setToolTip(_archive->archiveStats());
    _ui->archiveUniqueDataLabel->setText(
        Utils::humanBytes(_archive->sizeUniqueCompressed()));
    _ui->archiveUniqueDataLabel->setToolTip(_archive->archiveStats());

    // Show other info about the archive.
    _ui->archiveCommandLineEdit->setText(_archive->command());
    _ui->archiveCommandLineEdit->setToolTip(
        _archive->command().prepend("
").append("
"));
    _ui->archiveCommandLineEdit->setCursorPosition(0);

    // Warn about partial archives.
    if(_archive->truncated())
    {
        _ui->infoLabel->setText(tr("This archive is truncated,"
                                   " data may be incomplete"));
        _ui->infoLabel->setToolTip(_archive->truncatedInfo());
        _ui->infoLabel->show();
    }
    else if(_archive->contents().isEmpty()
            && (_archive->sizeTotal() < EMPTY_TAR_ARCHIVE_BYTES))
    {
        // Warn about a potentially empty archive.
        _ui->infoLabel->setText(tr("This archive looks empty,"
                                   " no file data may be contained"
                                   " besides the TAR header"));
        _ui->infoLabel->show();
    }
    else
        _ui->infoLabel->hide();

    // Show files in the archive.
    _contentsModel->setArchive(_archive);
}

void ArchiveDetailsWidget::closeEvent(QCloseEvent *event)
{
    Q_UNUSED(event)
    setArchive(ArchivePtr()); // Release memory held by the contents widget
    emit hidden();
}

void ArchiveDetailsWidget::keyPressEvent(QKeyEvent *event)
{
    // Special handling for Escape with filtering.
    if((event->key() == Qt::Key_Escape) && _ui->filterComboBox->isVisible())
    {
        if(_ui->filterComboBox->currentText().isEmpty())
        {
            _ui->filterButton->toggle();
        }
        else
        {
            _ui->filterComboBox->clearEditText();
            _ui->filterComboBox->setFocus();
        }
    }
    else
    {
        // Normal handling.
        QWidget::keyPressEvent(event);
    }
}

void ArchiveDetailsWidget::changeEvent(QEvent *event)
{
    if(event->type() == QEvent::LanguageChange)
    {
        _ui->retranslateUi(this);
        updateUi();
        updateDetails();
    }
    QWidget::changeEvent(event);
}

void ArchiveDetailsWidget::showContextMenu()
{
    _fileMenu->popup(QCursor::pos());
}

void ArchiveDetailsWidget::restoreFiles()
{
    // Get selected items, and bail if there's none.
    QModelIndexList indexes =
        _ui->archiveContentsTableView->selectionModel()->selectedRows();
    if(indexes.isEmpty())
        return;

    // Convert items to filenames.
    QStringList files;
    for(const QModelIndex &index : indexes)
        files << index.data().toString();

    // Launch RestoreDialog.
    RestoreDialog *restoreDialog = new RestoreDialog(this, _archive, files);
    restoreDialog->displayTarOption(false);
    restoreDialog->show();
    connect(restoreDialog, &RestoreDialog::accepted, [this, restoreDialog] {
        emit restoreArchive(restoreDialog->archive(),
                            restoreDialog->getOptions());
    });
}

void ArchiveDetailsWidget::updateUi()
{
    _ui->hideButton->setToolTip(_ui->hideButton->toolTip().arg(
        QKeySequence(Qt::Key_Escape).toString(QKeySequence::NativeText)));
    _ui->filterButton->setToolTip(_ui->filterButton->toolTip().arg(
        _ui->filterButton->shortcut().toString(QKeySequence::NativeText)));
}
<commit_msg>ArchiveDetailsWidget: don't show RestoreDialog until set up<commit_after>#include "archivewidget.h"

WARNINGS_DISABLE
#include <QAction>
#include <QComboBox>
#include <QCursor>
#include <QDateTime>
#include <QEvent>
#include <QKeyEvent>
#include <QKeySequence>
#include <QLabel>
#include <QMenu>
#include <QModelIndex>
#include <QModelIndexList>
#include <QSortFilterProxyModel>
#include <QStringList>
#include <QTableView>
#include <QVariant>
#include <Qt>

#include "ui_archivewidget.h"
WARNINGS_ENABLE

#include "TElidedLabel.h"

#include "messages/archiverestoreoptions.h"

#include "basetask.h"
#include "elidedclickablelabel.h"
#include "filetablemodel.h"
#include "persistentmodel/archive.h"
#include "restoredialog.h"
#include "utils.h"

#define EMPTY_TAR_ARCHIVE_BYTES 2000

ArchiveDetailsWidget::ArchiveDetailsWidget(QWidget *parent)
    : QWidget(parent),
      _ui(new Ui::ArchiveDetailsWidget),
      _contentsModel(new FileTableModel(this)),
      _proxyModel(new QSortFilterProxyModel(_contentsModel)),
      _fileMenu(new QMenu(this))
{
    _ui->setupUi(this);
    updateUi();

    // Set up filter UI.
    _ui->filterComboBox->hide();
    _proxyModel->setDynamicSortFilter(false);
    _proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
    _proxyModel->setSourceModel(_contentsModel);
    _ui->archiveContentsTableView->setModel(_proxyModel);
    _ui->archiveContentsTableView->setContextMenuPolicy(Qt::CustomContextMenu);

    // Set up other UI.
    _fileMenu->addAction(_ui->actionRestoreFiles);

    // Connections for UI functionality.
    connect(_ui->archiveContentsTableView,
            &QTableView::customContextMenuRequested, this,
            &ArchiveDetailsWidget::showContextMenu);
    connect(_ui->actionRestoreFiles, &QAction::triggered, this,
            &ArchiveDetailsWidget::restoreFiles);
    connect(_ui->archiveContentsTableView, &QTableView::activated, this,
            &ArchiveDetailsWidget::restoreFiles);
    connect(_ui->hideButton, &QPushButton::clicked, this,
            &ArchiveDetailsWidget::close);
    connect(_contentsModel, &FileTableModel::taskRequested, this,
            &ArchiveDetailsWidget::taskRequested);
    connect(_ui->archiveJobLabel, &ElidedClickableLabel::clicked,
            [this]() { emit jobClicked(_archive->jobRef()); });

    // Connection to reset the model.
    connect(_contentsModel, &FileTableModel::modelReset, [this]() {
        _ui->archiveContentsTableView->resizeColumnsToContents();
        _ui->archiveContentsLabel->setText(
            tr("Contents (%1)").arg(_contentsModel->rowCount()));
    });

    // Connections for filtering
    connect(_ui->filterComboBox, &QComboBox::editTextChanged, _proxyModel,
            &QSortFilterProxyModel::setFilterWildcard);
    connect(_ui->filterComboBox,
            static_cast<void (QComboBox::*)(int)>(
                &QComboBox::currentIndexChanged),
            [this]() { _ui->archiveContentsTableView->setFocus(); });
    connect(_ui->filterButton, &QPushButton::toggled,
            [this](const bool checked) {
                _ui->filterComboBox->setVisible(checked);
                if(checked)
                    _ui->filterComboBox->setFocus();
                else
                    _ui->filterComboBox->clearEditText();
            });
}

ArchiveDetailsWidget::~ArchiveDetailsWidget()
{
    delete _proxyModel;
    delete _contentsModel;
    delete _ui;
}

void ArchiveDetailsWidget::setArchive(ArchivePtr archive)
{
    // Remove previous connections (if applicable).
    if(_archive)
    {
        disconnect(_archive.data(), &Archive::changed, this,
                   &ArchiveDetailsWidget::updateDetails);
        disconnect(_archive.data(), &Archive::purged, this,
                   &ArchiveDetailsWidget::close);
    }

    // Store pointer.
    _archive = archive;

    // Set up new connections and refresh the display.
    if(_archive)
    {
        connect(_archive.data(), &Archive::changed, this,
                &ArchiveDetailsWidget::updateDetails);
        connect(_archive.data(), &Archive::purged, this,
                &ArchiveDetailsWidget::close);
        updateDetails();
    }
    else
    {
        // No need to store info about the previous Archive.
        _contentsModel->reset();
    }
}

void ArchiveDetailsWidget::updateDetails()
{
    // Bail (if applicable).
    if(!_archive)
        return;

    // Show basic archive info.
    _ui->archiveNameLabel->setText(_archive->name());
    _ui->archiveDateLabel->setText(
        _archive->timestamp().toString(Qt::DefaultLocaleLongDate));

    // Show info about a linked Job (if applicable).
    if(_archive->jobRef().isEmpty())
    {
        _ui->archiveJobLabel->hide();
        _ui->archiveJobLabelField->hide();
        _ui->archiveIconLabel->setStyleSheet(
            "image: url(:/logos/tarsnap-icon-big.png)");
    }
    else
    {
        _ui->archiveJobLabel->show();
        _ui->archiveJobLabelField->show();
        _ui->archiveJobLabel->setText(_archive->jobRef());
        _ui->archiveIconLabel->setStyleSheet(
            "image: url(:/icons/hard-drive-big.png)");
    }

    // Show size info about the archive.
    _ui->archiveSizeLabel->setText(Utils::humanBytes(_archive->sizeTotal()));
    _ui->archiveSizeLabel->setToolTip(_archive->archiveStats());
    _ui->archiveUniqueDataLabel->setText(
        Utils::humanBytes(_archive->sizeUniqueCompressed()));
    _ui->archiveUniqueDataLabel->setToolTip(_archive->archiveStats());

    // Show other info about the archive.
    _ui->archiveCommandLineEdit->setText(_archive->command());
    _ui->archiveCommandLineEdit->setToolTip(
        _archive->command().prepend("
").append("
"));
    _ui->archiveCommandLineEdit->setCursorPosition(0);

    // Warn about partial archives.
    if(_archive->truncated())
    {
        _ui->infoLabel->setText(tr("This archive is truncated,"
                                   " data may be incomplete"));
        _ui->infoLabel->setToolTip(_archive->truncatedInfo());
        _ui->infoLabel->show();
    }
    else if(_archive->contents().isEmpty()
            && (_archive->sizeTotal() < EMPTY_TAR_ARCHIVE_BYTES))
    {
        // Warn about a potentially empty archive.
        _ui->infoLabel->setText(tr("This archive looks empty,"
                                   " no file data may be contained"
                                   " besides the TAR header"));
        _ui->infoLabel->show();
    }
    else
        _ui->infoLabel->hide();

    // Show files in the archive.
    _contentsModel->setArchive(_archive);
}

void ArchiveDetailsWidget::closeEvent(QCloseEvent *event)
{
    Q_UNUSED(event)
    setArchive(ArchivePtr()); // Release memory held by the contents widget
    emit hidden();
}

void ArchiveDetailsWidget::keyPressEvent(QKeyEvent *event)
{
    // Special handling for Escape with filtering.
    if((event->key() == Qt::Key_Escape) && _ui->filterComboBox->isVisible())
    {
        if(_ui->filterComboBox->currentText().isEmpty())
        {
            _ui->filterButton->toggle();
        }
        else
        {
            _ui->filterComboBox->clearEditText();
            _ui->filterComboBox->setFocus();
        }
    }
    else
    {
        // Normal handling.
        QWidget::keyPressEvent(event);
    }
}

void ArchiveDetailsWidget::changeEvent(QEvent *event)
{
    if(event->type() == QEvent::LanguageChange)
    {
        _ui->retranslateUi(this);
        updateUi();
        updateDetails();
    }
    QWidget::changeEvent(event);
}

void ArchiveDetailsWidget::showContextMenu()
{
    _fileMenu->popup(QCursor::pos());
}

void ArchiveDetailsWidget::restoreFiles()
{
    // Get selected items, and bail if there's none.
    QModelIndexList indexes =
        _ui->archiveContentsTableView->selectionModel()->selectedRows();
    if(indexes.isEmpty())
        return;

    // Convert items to filenames.
    QStringList files;
    for(const QModelIndex &index : indexes)
        files << index.data().toString();

    // Launch RestoreDialog.
    RestoreDialog *restoreDialog = new RestoreDialog(this, _archive, files);
    restoreDialog->displayTarOption(false);
    connect(restoreDialog, &RestoreDialog::accepted, [this, restoreDialog] {
        emit restoreArchive(restoreDialog->archive(),
                            restoreDialog->getOptions());
    });
    restoreDialog->show();
}

void ArchiveDetailsWidget::updateUi()
{
    _ui->hideButton->setToolTip(_ui->hideButton->toolTip().arg(
        QKeySequence(Qt::Key_Escape).toString(QKeySequence::NativeText)));
    _ui->filterButton->setToolTip(_ui->filterButton->toolTip().arg(
        _ui->filterButton->shortcut().toString(QKeySequence::NativeText)));
}
<|endoftext|>


<commit_before>// Copyright 2014 Toggl Desktop developers.

#include "../src/window_change_recorder.h"

#include <sstream>

#include "./get_focused_window.h"
#include "./const.h"

#include "Poco/Logger.h"
#include "Poco/Thread.h"

namespace toggl {

Poco::Logger &WindowChangeRecorder::logger() {
    return Poco::Logger::get("WindowChangeRecorder");
}

bool WindowChangeRecorder::hasWindowChanged(
    const std::string &title,
    const std::string &filename) const {
    return ((title != last_title_) || (filename != last_filename_));
}

bool WindowChangeRecorder::hasIdlenessChanged(const bool &idle) const {
    return last_idle_ != idle;
}

void WindowChangeRecorder::inspectFocusedWindow() {
    std::string title("");
    std::string filename("");
    bool idle(false);

    int err = getFocusedWindowInfo(&title, &filename, &idle);
    if (err != 0) {
        std::stringstream ss;
        ss << "Failed to get focused window info, error code: " << err;
        logger().error(ss.str());
        return;
    }

    time_t now;
    time(&now);

    if (!hasIdlenessChanged(idle) && !hasWindowChanged(title, filename)) {
        return;
    }

    // We actually record the *previous* event. Meaning, when
    // you have "terminal" open and then switch to "skype",
    // then "terminal" gets recorded here:
    if (last_event_started_at_ > 0) {
        time_t time_delta = now - last_event_started_at_;

        if (time_delta >= kAutotrackerThresholdSeconds && !last_idle_
                && last_autotracker_title_ != title) {
            // Notify that the timeline event has started
            // we'll use this in auto tracking
            last_autotracker_title_ = title;

            TimelineEvent event;
            event.start_time = last_event_started_at_;
            event.end_time = now;
            event.filename = last_filename_;
            event.title = last_title_;
            event.idle = false;
            timeline_datasource_->StartAutotrackerEvent(event);
        }

        // if window was focussed at least X seconds, save it to timeline
        if (time_delta >= kWindowFocusThresholdSeconds && !last_idle_) {
            TimelineEvent event;
            event.start_time = last_event_started_at_;
            event.end_time = now;
            event.filename = last_filename_;
            event.title = last_title_;
            event.idle = false;

            error err = timeline_datasource_->StartTimelineEvent(&event);
            if (err != noError) {
                logger().error(err);
            }
        }
    }

    last_title_ = title;
    last_filename_ = filename;
    last_idle_ = idle;
    last_event_started_at_ = now;
}

void WindowChangeRecorder::recordLoop() {
    while (!recording_.isStopped()) {
        inspectFocusedWindow();

        if (recording_.isStopped()) {
            break;
        }

        Poco::Thread::sleep(250);

        if (recording_.isStopped()) {
            break;
        }

        Poco::Thread::sleep(250);
    }
}

error WindowChangeRecorder::Shutdown() {
    try {
        if (recording_.isRunning()) {
            recording_.stop();
            recording_.wait();
        }
    } catch(const Poco::Exception& exc) {
        return exc.displayText();
    } catch(const std::exception& ex) {
        return ex.what();
    } catch(const std::string& ex) {
        return ex;
    }
    return noError;
}

}  // namespace toggl
<commit_msg>finetune autotracker notification logic (lib)<commit_after>// Copyright 2014 Toggl Desktop developers.

#include "../src/window_change_recorder.h"

#include <sstream>

#include "./get_focused_window.h"
#include "./const.h"

#include "Poco/Logger.h"
#include "Poco/Thread.h"

namespace toggl {

Poco::Logger &WindowChangeRecorder::logger() {
    return Poco::Logger::get("WindowChangeRecorder");
}

bool WindowChangeRecorder::hasWindowChanged(
    const std::string &title,
    const std::string &filename) const {
    return ((title != last_title_) || (filename != last_filename_));
}

bool WindowChangeRecorder::hasIdlenessChanged(const bool &idle) const {
    return last_idle_ != idle;
}

void WindowChangeRecorder::inspectFocusedWindow() {
    std::string title("");
    std::string filename("");
    bool idle(false);

    int err = getFocusedWindowInfo(&title, &filename, &idle);
    if (err != 0) {
        std::stringstream ss;
        ss << "Failed to get focused window info, error code: " << err;
        logger().error(ss.str());
        return;
    }

    time_t now;
    time(&now);

    time_t time_delta = now - last_event_started_at_;

    if (last_event_started_at_ > 0) {
        if (time_delta >= kAutotrackerThresholdSeconds && !last_idle_
                && last_autotracker_title_ != title) {
            // Notify that the timeline event has started
            // we'll use this in auto tracking
            last_autotracker_title_ = title;

            TimelineEvent event;
            event.start_time = last_event_started_at_;
            event.end_time = now;
            event.title = title;
            event.idle = false;
            timeline_datasource_->StartAutotrackerEvent(event);
        }
    }

    if (!hasIdlenessChanged(idle) && !hasWindowChanged(title, filename)) {
        return;
    }

    // Since idle state or window has changed, reset autotracker state, too
    last_autotracker_title_ = "";

    // We actually record the *previous* event. Meaning, when
    // you have "terminal" open and then switch to "skype",
    // then "terminal" gets recorded here:
    if (last_event_started_at_ > 0) {
        // if window was focussed at least X seconds, save it to timeline
        if (time_delta >= kWindowFocusThresholdSeconds && !last_idle_) {
            TimelineEvent event;
            event.start_time = last_event_started_at_;
            event.end_time = now;
            event.filename = last_filename_;
            event.title = last_title_;
            event.idle = false;

            error err = timeline_datasource_->StartTimelineEvent(&event);
            if (err != noError) {
                logger().error(err);
            }
        }
    }

    last_title_ = title;
    last_filename_ = filename;
    last_idle_ = idle;
    last_event_started_at_ = now;
}

void WindowChangeRecorder::recordLoop() {
    while (!recording_.isStopped()) {
        inspectFocusedWindow();

        if (recording_.isStopped()) {
            break;
        }

        Poco::Thread::sleep(250);

        if (recording_.isStopped()) {
            break;
        }

        Poco::Thread::sleep(250);
    }
}

error WindowChangeRecorder::Shutdown() {
    try {
        if (recording_.isRunning()) {
            recording_.stop();
            recording_.wait();
        }
    } catch(const Poco::Exception& exc) {
        return exc.displayText();
    } catch(const std::exception& ex) {
        return ex.what();
    } catch(const std::string& ex) {
        return ex;
    }
    return noError;
}

}  // namespace toggl
<|endoftext|>


<commit_before>// Source : https://oj.leetcode.com/problems/word-search/
// Author : Hao Chen
// Date   : 2014-07-19

/**********************************************************************************
*
* Given a 2D board and a word, find if the word exists in the grid.
*
* The word can be constructed from letters of sequentially adjacent cell,
* where "adjacent" cells are those horizontally or vertically neighboring.
* The same letter cell may not be used more than once.
*
* For example,
* Given board =
*
* [
*   ["ABCE"],
*   ["SFCS"],
*   ["ADEE"]
* ]
*
* word = "ABCCED", -> returns true,
* word = "SEE", -> returns true,
* word = "ABCB", -> returns false.
*
*
**********************************************************************************/

#include <iostream>
#include <vector>
#include <string>
using namespace std;

//Recursive backtracking algorithm
bool exist(vector<vector<char> > &board, string word, int idx, int row, int col, vector< vector<int> > &mask) {
    int i = row;
    int j = col;
    if (board[i][j] == word[idx] && mask[i][j]==0 ) {
        mask[i][j]=1; //mark the current char is matched
        if (idx+1 == word.size()) return true;
        //checking the next char in `word` through the right, left, up, down four directions in the `board`.
        idx++;
        if (( i+1<board.size()    && exist(board, word, idx, i+1, j, mask) ) ||
            ( i>0                 && exist(board, word, idx, i-1, j, mask) ) ||
            ( j+1<board[i].size() && exist(board, word, idx, i, j+1, mask) ) ||
            ( j>0                 && exist(board, word, idx, i, j-1, mask) ) )
        {
             return true;
        }
        mask[i][j]=0; //cannot find any successful solution, clear the mark. (backtracking)
    }

    return false;
}

bool exist(vector<vector<char> > &board, string word) {
    if (board.size()<=0 || word.size()<=0) return false;
    int row = board.size();
    int col = board[0].size();
    //using a mask to mark which char has been selected.
    //do not use vector<bool>, it has big performance issue, could cause Time Limit Error
    vector< vector<int> > mask(row, vector<int> col);

    for(int i=0; i<board.size(); i++) {
        for(int j=0; j<board[i].size(); j++){
            if ( board[i][j]==word[0] ){
                vector< vector<int> > m = mask;
                if( exist(board, word, 0, i, j, m) ){
                    return true;
                }
            }
        }
    }
    return false;
}

vector< vector<char> > buildBoard(char b[][5], int r, int c) {
    vector< vector<char> > board;
    for (int i=0; i<r; i++){
        vector<char> v(b[i], b[i]+c);
        cout << b[i] << endl;
        board.push_back(v);
    }
    cout << "----------" << endl;
    return board;
}

int main(int argc, char** argv)
{
    string s;
    char b[3][5] ={ "ABCE", "SFCS", "ADEE" };
    vector< vector<char> > board = buildBoard(b, 3, 4);

    s = "SEE";
    cout << s << ":" << exist(board, s) << endl;

    s = "ABCCED";
    cout << s << ":" << exist(board, s) << endl;

    s = "ABCB";
    cout << s << ":" << exist(board, s) << endl;

    if (argc>1){
        s = argv[1];
        cout << s << ":" << exist(board, s) << endl;
    }

    cout << endl << "----------" << endl;
    char b1[3][5] ={ "CAA", "AAA", "BCD" };
    board = buildBoard(b1, 3, 3);

    s = "AAB";
    cout << s << ":" << exist(board, s) << endl;

    cout << endl << "----------" << endl;
    char b2[3][5] ={ "ABCE", "SFES", "ADEE" };
    board = buildBoard(b2, 3, 4);

    s = "ABCESEEEFS";
    cout << s << ":" << exist(board, s) << endl;

    cout << endl << "----------" << endl;
    char b3[3][5] ={ "aaaa", "aaaa", "aaaa" };
    board = buildBoard(b3, 3, 4);

    s = "aaaaaaaaaaaaa";
    cout << s << ":" << exist(board, s) << endl;

    return 0;
}
<commit_msg>modify wordSearch.cpp complile error<commit_after>// Source : https://oj.leetcode.com/problems/word-search/
// Author : Hao Chen
// Date   : 2014-07-19

/**********************************************************************************
*
* Given a 2D board and a word, find if the word exists in the grid.
*
* The word can be constructed from letters of sequentially adjacent cell,
* where "adjacent" cells are those horizontally or vertically neighboring.
* The same letter cell may not be used more than once.
*
* For example,
* Given board =
*
* [
*   ["ABCE"],
*   ["SFCS"],
*   ["ADEE"]
* ]
*
* word = "ABCCED", -> returns true,
* word = "SEE", -> returns true,
* word = "ABCB", -> returns false.
*
*
**********************************************************************************/

#include <iostream>
#include <vector>
#include <string>
using namespace std;

//Recursive backtracking algorithm
bool exist(vector<vector<char> > &board, string word, int idx, int row, int col, vector< vector<int> > &mask) {
    int i = row;
    int j = col;
    if (board[i][j] == word[idx] && mask[i][j]==0 ) {
        mask[i][j]=1; //mark the current char is matched
        if (idx+1 == word.size()) return true;
        //checking the next char in `word` through the right, left, up, down four directions in the `board`.
        idx++;
        if (( i+1<board.size()    && exist(board, word, idx, i+1, j, mask) ) ||
            ( i>0                 && exist(board, word, idx, i-1, j, mask) ) ||
            ( j+1<board[i].size() && exist(board, word, idx, i, j+1, mask) ) ||
            ( j>0                 && exist(board, word, idx, i, j-1, mask) ) )
        {
             return true;
        }
        mask[i][j]=0; //cannot find any successful solution, clear the mark. (backtracking)
    }

    return false;
}

bool exist(vector<vector<char> > &board, string word) {
    if (board.size()<=0 || word.size()<=0) return false;
    int row = board.size();
    int col = board[0].size();
    //using a mask to mark which char has been selected.
    //do not use vector<bool>, it has big performance issue, could cause Time Limit Error
    vector< vector<int> > mask(row, vector<int>(col, 0));

    for(int i=0; i<board.size(); i++) {
        for(int j=0; j<board[i].size(); j++){
            if ( board[i][j]==word[0] ){
                vector< vector<int> > m = mask;
                if( exist(board, word, 0, i, j, m) ){
                    return true;
                }
            }
        }
    }
    return false;
}

vector< vector<char> > buildBoard(char b[][5], int r, int c) {
    vector< vector<char> > board;
    for (int i=0; i<r; i++){
        vector<char> v(b[i], b[i]+c);
        cout << b[i] << endl;
        board.push_back(v);
    }
    cout << "----------" << endl;
    return board;
}

int main(int argc, char** argv)
{
    string s;
    char b[3][5] ={ "ABCE", "SFCS", "ADEE" };
    vector< vector<char> > board = buildBoard(b, 3, 4);

    s = "SEE";
    cout << s << ":" << exist(board, s) << endl;

    s = "ABCCED";
    cout << s << ":" << exist(board, s) << endl;

    s = "ABCB";
    cout << s << ":" << exist(board, s) << endl;

    if (argc>1){
        s = argv[1];
        cout << s << ":" << exist(board, s) << endl;
    }

    cout << endl << "----------" << endl;
    char b1[3][5] ={ "CAA", "AAA", "BCD" };
    board = buildBoard(b1, 3, 3);

    s = "AAB";
    cout << s << ":" << exist(board, s) << endl;

    cout << endl << "----------" << endl;
    char b2[3][5] ={ "ABCE", "SFES", "ADEE" };
    board = buildBoard(b2, 3, 4);

    s = "ABCESEEEFS";
    cout << s << ":" << exist(board, s) << endl;

    cout << endl << "----------" << endl;
    char b3[3][5] ={ "aaaa", "aaaa", "aaaa" };
    board = buildBoard(b3, 3, 4);

    s = "aaaaaaaaaaaaa";
    cout << s << ":" << exist(board, s) << endl;

    return 0;
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stx/util/Base64.h>
#include <stx/fnv.h>
#include <stx/protobuf/msg.h>
#include <stx/io/fileutil.h>
#include <sstable/sstablereader.h>
#include <zbase/core/TSDBService.h>
#include <zbase/core/PartitionState.pb.h>

using namespace stx;

namespace zbase {

TSDBService::TSDBService(
    PartitionMap* pmap,
    ReplicationScheme* repl,
    thread::EventLoop* ev) :
    pmap_(pmap),
    repl_(repl),
    http_(ev) {}

void TSDBService::createTable(const TableDefinition& table) {
  pmap_->configureTable(table);
}

void TSDBService::insertRecords(const RecordEnvelopeList& record_list) {
  Vector<RefPtr<Partition>> partition_refs;
  HashMap<String, Vector<RecordRef>> grouped;

  for (const auto& record : record_list.records()) {
    SHA1Hash partition_key;

    auto table = pmap_->findTable(
        record.tsdb_namespace(),
        record.table_name());

    if (table.isEmpty()) {
      RAISEF(kNotFoundError, "table not found: $0", record.table_name());
    }

    if (record.has_partition_sha1()) {
      partition_key = SHA1Hash::fromHexString(record.partition_sha1());
    } else {
      partition_key = table.get()->partitioner()->partitionKeyFor(
          record.partition_key());
    }

    auto record_data = record.record_data().data();
    auto record_size = record.record_data().size();

    auto group_key = StringUtil::format(
        "$0~$1~$2",
        record.tsdb_namespace(),
        record.table_name(),
        partition_key.toString());

    grouped[group_key].emplace_back(
        SHA1Hash::fromHexString(record.record_id()),
        Buffer(record_data, record_size));
  }

  for (const auto& group : grouped) {
    auto group_key = StringUtil::split(group.first, "~");
    if (group_key.size() != 3) {
      RAISE(kIllegalStateError);
    }

    insertRecords(
        group_key[0],
        group_key[1],
        SHA1Hash::fromHexString(group_key[2]),
        group.second);
  }
}

void TSDBService::insertRecord(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const SHA1Hash& record_id,
    const Buffer& record) {
  Vector<RecordRef> records;
  records.emplace_back(record_id, record);
  insertRecords(tsdb_namespace, table_name, partition_key, records);
}

void TSDBService::insertRecords(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const Vector<RecordRef>& records) {
  if (repl_->hasLocalReplica(partition_key)) {
    insertRecordsLocal(tsdb_namespace, table_name, partition_key, records);
  } else {
    insertRecordsRemote(tsdb_namespace, table_name, partition_key, records);
  }
}

void TSDBService::insertRecordsLocal(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const Vector<RecordRef>& records) {
  auto partition = pmap_->findOrCreatePartition(
      tsdb_namespace,
      table_name,
      partition_key);

  auto writer = partition->getWriter();

  bool dirty = false;
  for (const auto& r : records) {
    if (writer->insertRecord(r.record_id, r.record)) {
      dirty = true;
    }
  }

  if (dirty) {
    auto change = mkRef(new PartitionChangeNotification());
    change->partition = partition;
    pmap_->publishPartitionChange(change);
  }
}

void TSDBService::insertRecordsRemote(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const Vector<RecordRef>& records) {
  RecordEnvelopeList envelope;

  for (const auto& r : records) {
    auto record = envelope.add_records();
    record->set_tsdb_namespace(tsdb_namespace);
    record->set_table_name(table_name);
    record->set_partition_sha1(partition_key.toString());
    record->set_record_id(r.record_id.toString());
    record->set_record_data(r.record.toString());
  }

  Vector<String> errors;
  auto hosts = repl_->replicasFor(partition_key);
  for (const auto& host : hosts) {
    try {
      insertRecordsRemote(
          tsdb_namespace,
          table_name,
          partition_key,
          envelope,
          host.addr);

      return;
    } catch (const StandardException& e) {
      logError(
          "zbase",
          e,
          "TSDBService::insertRecordsRemote failed");

      errors.emplace_back(e.what());
    }
  }

  RAISEF(
      kRuntimeError,
      "TSDBService::insertRecordsRemote failed: $0",
      StringUtil::join(errors, ", "));
}

void TSDBService::insertRecordsRemote(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const RecordEnvelopeList& envelope,
    const InetAddr& host) {

  auto uri = URI(StringUtil::format("http://$0/tsdb/insert", host.ipAndPort()));

  http::HTTPRequest req(http::HTTPMessage::M_POST, uri.pathAndQuery());
  req.addHeader("Host", uri.hostAndPort());
  req.addBody(*msg::encode(envelope));

  auto res = http_.executeRequest(req);
  res.wait();

  const auto& r = res.get();
  if (r.statusCode() != 201) {
    RAISEF(kRuntimeError, "received non-201 response: $0", r.body().toString());
  }
}

void TSDBService::updatePartitionCSTable(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const String& tmpfile_path,
    uint64_t version) {
  auto partition = pmap_->findOrCreatePartition(
      tsdb_namespace,
      table_name,
      partition_key);

  auto writer = partition->getWriter();
  writer->updateCSTable(tmpfile_path, version);

  auto change = mkRef(new PartitionChangeNotification());
  change->partition = partition;
  pmap_->publishPartitionChange(change);
}

void TSDBService::fetchPartition(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    Function<void (const Buffer& record)> fn) {
  fetchPartitionWithSampling(
      tsdb_namespace,
      table_name,
      partition_key,
      0,
      0,
      fn);
}

void TSDBService::fetchPartitionWithSampling(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    size_t sample_modulo,
    size_t sample_index,
    Function<void (const Buffer& record)> fn) {
  auto partition = pmap_->findPartition(
      tsdb_namespace,
      table_name,
      partition_key);

  if (partition.isEmpty()) {
    return;
  }

  auto reader = partition.get()->getReader();
  reader->fetchRecordsWithSampling(sample_modulo, sample_index, fn);
}

Option<PartitionInfo> TSDBService::partitionInfo(
    const String& tsdb_namespace,
    const String& table_key,
    const SHA1Hash& partition_key) {
  auto partition = pmap_->findPartition(
      tsdb_namespace,
      table_key,
      partition_key);

  if (partition.isEmpty()) {
    return None<PartitionInfo>();
  } else {
    return Some(partition.get()->getInfo());
  }
}

Option<RefPtr<msg::MessageSchema>> TSDBService::tableSchema(
    const String& tsdb_namespace,
    const String& table_key) {
  auto table = pmap_->findTable(
      tsdb_namespace,
      table_key);

  if (table.isEmpty()) {
    return None<RefPtr<msg::MessageSchema>>();
  } else {
    return Some(table.get()->schema());
  }
}

Option<TableDefinition> TSDBService::tableConfig(
    const String& tsdb_namespace,
    const String& table_key) {
  auto table = pmap_->findTable(
      tsdb_namespace,
      table_key);

  if (table.isEmpty()) {
    return None<TableDefinition>();
  } else {
    return Some(table.get()->config());
  }
}

Option<RefPtr<TablePartitioner>> TSDBService::tablePartitioner(
    const String& tsdb_namespace,
    const String& table_key) {
  auto table = pmap_->findTable(
      tsdb_namespace,
      table_key);

  if (table.isEmpty()) {
    return None<RefPtr<TablePartitioner>>();
  } else {
    return Some(table.get()->partitioner());
  }
}

//const String& TSDBService::dbPath() const {
//  return db_path_;
//}

} // namespace tdsb

<commit_msg>logging...<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stx/util/Base64.h>
#include <stx/fnv.h>
#include <stx/protobuf/msg.h>
#include <stx/io/fileutil.h>
#include <sstable/sstablereader.h>
#include <zbase/core/TSDBService.h>
#include <zbase/core/PartitionState.pb.h>

using namespace stx;

namespace zbase {

TSDBService::TSDBService(
    PartitionMap* pmap,
    ReplicationScheme* repl,
    thread::EventLoop* ev) :
    pmap_(pmap),
    repl_(repl),
    http_(ev) {}

void TSDBService::createTable(const TableDefinition& table) {
  pmap_->configureTable(table);
}

void TSDBService::insertRecords(const RecordEnvelopeList& record_list) {
  Vector<RefPtr<Partition>> partition_refs;
  HashMap<String, Vector<RecordRef>> grouped;

  for (const auto& record : record_list.records()) {
    SHA1Hash partition_key;

    auto table = pmap_->findTable(
        record.tsdb_namespace(),
        record.table_name());

    if (table.isEmpty()) {
      RAISEF(kNotFoundError, "table not found: $0", record.table_name());
    }

    if (record.has_partition_sha1()) {
      partition_key = SHA1Hash::fromHexString(record.partition_sha1());
    } else {
      partition_key = table.get()->partitioner()->partitionKeyFor(
          record.partition_key());
    }

    auto record_data = record.record_data().data();
    auto record_size = record.record_data().size();

    auto group_key = StringUtil::format(
        "$0~$1~$2",
        record.tsdb_namespace(),
        record.table_name(),
        partition_key.toString());

    grouped[group_key].emplace_back(
        SHA1Hash::fromHexString(record.record_id()),
        Buffer(record_data, record_size));
  }

  for (const auto& group : grouped) {
    auto group_key = StringUtil::split(group.first, "~");
    if (group_key.size() != 3) {
      RAISE(kIllegalStateError);
    }

    insertRecords(
        group_key[0],
        group_key[1],
        SHA1Hash::fromHexString(group_key[2]),
        group.second);
  }
}

void TSDBService::insertRecord(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const SHA1Hash& record_id,
    const Buffer& record) {
  Vector<RecordRef> records;
  records.emplace_back(record_id, record);
  insertRecords(tsdb_namespace, table_name, partition_key, records);
}

void TSDBService::insertRecords(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const Vector<RecordRef>& records) {
  if (repl_->hasLocalReplica(partition_key)) {
    insertRecordsLocal(tsdb_namespace, table_name, partition_key, records);
  } else {
    insertRecordsRemote(tsdb_namespace, table_name, partition_key, records);
  }
}

void TSDBService::insertRecordsLocal(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const Vector<RecordRef>& records) {
  logDebug(
      "z1.core",
      "Inserting $0 records into tsdb://localhost/$1/$2/$3",
      records.size(),
      tsdb_namespace,
      table_name,
      partition_key.toString());

  auto partition = pmap_->findOrCreatePartition(
      tsdb_namespace,
      table_name,
      partition_key);

  auto writer = partition->getWriter();

  bool dirty = false;
  for (const auto& r : records) {
    if (writer->insertRecord(r.record_id, r.record)) {
      dirty = true;
    }
  }

  if (dirty) {
    auto change = mkRef(new PartitionChangeNotification());
    change->partition = partition;
    pmap_->publishPartitionChange(change);
  }
}

void TSDBService::insertRecordsRemote(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const Vector<RecordRef>& records) {
  RecordEnvelopeList envelope;

  for (const auto& r : records) {
    auto record = envelope.add_records();
    record->set_tsdb_namespace(tsdb_namespace);
    record->set_table_name(table_name);
    record->set_partition_sha1(partition_key.toString());
    record->set_record_id(r.record_id.toString());
    record->set_record_data(r.record.toString());
  }

  Vector<String> errors;
  auto hosts = repl_->replicasFor(partition_key);
  for (const auto& host : hosts) {
    try {
      logDebug(
          "z1.core",
          "Inserting $0 records into tsdb://$1/$2/$3/$4",
          records.size(),
          host.name,
          tsdb_namespace,
          table_name,
          partition_key.toString());

      insertRecordsRemote(
          tsdb_namespace,
          table_name,
          partition_key,
          envelope,
          host.addr);

      return;
    } catch (const StandardException& e) {
      logError(
          "zbase",
          e,
          "TSDBService::insertRecordsRemote failed");

      errors.emplace_back(e.what());
    }
  }

  RAISEF(
      kRuntimeError,
      "TSDBService::insertRecordsRemote failed: $0",
      StringUtil::join(errors, ", "));
}

void TSDBService::insertRecordsRemote(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const RecordEnvelopeList& envelope,
    const InetAddr& host) {

  auto uri = URI(StringUtil::format("http://$0/tsdb/insert", host.ipAndPort()));

  http::HTTPRequest req(http::HTTPMessage::M_POST, uri.pathAndQuery());
  req.addHeader("Host", uri.hostAndPort());
  req.addBody(*msg::encode(envelope));

  auto res = http_.executeRequest(req);
  res.wait();

  const auto& r = res.get();
  if (r.statusCode() != 201) {
    RAISEF(kRuntimeError, "received non-201 response: $0", r.body().toString());
  }
}

void TSDBService::updatePartitionCSTable(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    const String& tmpfile_path,
    uint64_t version) {
  auto partition = pmap_->findOrCreatePartition(
      tsdb_namespace,
      table_name,
      partition_key);

  auto writer = partition->getWriter();
  writer->updateCSTable(tmpfile_path, version);

  auto change = mkRef(new PartitionChangeNotification());
  change->partition = partition;
  pmap_->publishPartitionChange(change);
}

void TSDBService::fetchPartition(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    Function<void (const Buffer& record)> fn) {
  fetchPartitionWithSampling(
      tsdb_namespace,
      table_name,
      partition_key,
      0,
      0,
      fn);
}

void TSDBService::fetchPartitionWithSampling(
    const String& tsdb_namespace,
    const String& table_name,
    const SHA1Hash& partition_key,
    size_t sample_modulo,
    size_t sample_index,
    Function<void (const Buffer& record)> fn) {
  auto partition = pmap_->findPartition(
      tsdb_namespace,
      table_name,
      partition_key);

  if (partition.isEmpty()) {
    return;
  }

  auto reader = partition.get()->getReader();
  reader->fetchRecordsWithSampling(sample_modulo, sample_index, fn);
}

Option<PartitionInfo> TSDBService::partitionInfo(
    const String& tsdb_namespace,
    const String& table_key,
    const SHA1Hash& partition_key) {
  auto partition = pmap_->findPartition(
      tsdb_namespace,
      table_key,
      partition_key);

  if (partition.isEmpty()) {
    return None<PartitionInfo>();
  } else {
    return Some(partition.get()->getInfo());
  }
}

Option<RefPtr<msg::MessageSchema>> TSDBService::tableSchema(
    const String& tsdb_namespace,
    const String& table_key) {
  auto table = pmap_->findTable(
      tsdb_namespace,
      table_key);

  if (table.isEmpty()) {
    return None<RefPtr<msg::MessageSchema>>();
  } else {
    return Some(table.get()->schema());
  }
}

Option<TableDefinition> TSDBService::tableConfig(
    const String& tsdb_namespace,
    const String& table_key) {
  auto table = pmap_->findTable(
      tsdb_namespace,
      table_key);

  if (table.isEmpty()) {
    return None<TableDefinition>();
  } else {
    return Some(table.get()->config());
  }
}

Option<RefPtr<TablePartitioner>> TSDBService::tablePartitioner(
    const String& tsdb_namespace,
    const String& table_key) {
  auto table = pmap_->findTable(
      tsdb_namespace,
      table_key);

  if (table.isEmpty()) {
    return None<RefPtr<TablePartitioner>>();
  } else {
    return Some(table.get()->partitioner());
  }
}

//const String& TSDBService::dbPath() const {
//  return db_path_;
//}

} // namespace tdsb

<|endoftext|>


<commit_before>// C/C++ File

// Author:   Alexandre Tea <alexandre.qtea@gmail.com>
// File:     /Users/alexandretea/Work/ddti/srcs/master/InductionC4_5.hpp
// Purpose:  Induction algorithm based on Quinlan's C4.5
// Created:  2017-07-28 16:14:44
// Modified: 2017-08-24 02:34:45

#ifndef INDUCTIONC4_5_H
#define INDUCTIONC4_5_H

#include <map>
#include <armadillo>
#include "MasterNode.hpp"
#include "DecisionTree.hpp"
#include "MPIDatatypeManager.hpp"
#include "TaskC4_5.hpp"
#include "Dataset.hpp"
#include "ddti.hpp"
#include "utils/matrix.hpp"

namespace ddti {
namespace induction {

class C4_5
{
    public:
        struct Parameters
        {
            bool            debug;          // logs some debug info (i.e. IGR)
            unsigned int    min_leaf_size;  // min. number of instances per leaf

            Parameters() : debug(false), min_leaf_size(2)
            {}

            std::string
            to_string() const
            {
                return std::string("debug(") + (debug ? "true" : "false") + ")"
                       ", min_leaf_size(" + std::to_string(min_leaf_size) + ")";
            }
        };

        using ull_t = unsigned long long;
        template <typename T>
        using StdVecVec = std::vector<std::vector<T>>;

    public:
        C4_5(utils::mpi::Communicator const& comm);
        virtual ~C4_5();

        C4_5(C4_5 const& other) = delete;
        C4_5&           operator=(C4_5 const& other) = delete;

    public:
        std::unique_ptr<DecisionTree>
        operator()(CatDataset const& dataset,
                   Parameters conf = Parameters());
        // NOTE: conf is not received as a constant reference because the param
        // will be moved in a member variable

    protected:
        DecisionTree*   rec_train_node(arma::umat const& data,
                                       std::vector<size_t> const& attrs,
                                       int split_value = -1);
        void            send_task(int task_code) const;
        void            build_children(DecisionTree* node,
                                       arma::umat const& node_data,
                                       StdVecVec<ull_t> const& split_cols,
                                       std::vector<size_t> const& node_attrs);
        DecisionTree*   create_leaf(std::pair<size_t, size_t> const& label,
                                    int split_value, size_t nb_instances) const;
        bool            check_leaf_size(StdVecVec<ull_t> const& cols) const;
        void            debug(std::string const& s) const;

        std::pair<size_t, long double>   select_attribute(
            arma::umat const& data, std::vector<size_t> const& attrs,
            long double entropy
        );
        std::map<size_t, ContTable> count_contingencies(
            arma::umat const& data
        );
        StdVecVec<ull_t>            get_split_indices(
            arma::umat const& data, size_t attr
        ) const;

        // scatter matrix by column or by row
        // NOTE: we don't allow the scatter of subviews because they might
        // not be continuous in memory
        template <typename T>
        arma::Mat<T>
        scatter_matrix(arma::Mat<T> const& data, bool by_column = true)
        {
            MPI_Datatype   entry_type;
            size_t         chunk_size;
            size_t         nb_elems;
            T*             aux_mem;

            if (by_column) {    // armadillo matrices are column-major
                nb_elems = data.n_rows;
                chunk_size = data.n_cols / _comm.size();
                entry_type = _mpi_types.matrix_contiguous_entry<T>(data.n_rows);
            } else {
                nb_elems = data.n_cols;
                chunk_size = data.n_rows / _comm.size();
                entry_type =
                    _mpi_types.matrix_noncontiguous_entry<T>(nb_elems,
                                                             data.n_rows);
            }
            _comm.broadcast(nb_elems);   // nb elems
            _comm.broadcast(chunk_size); // nb entries
            aux_mem = _comm.scatter<T>(data.colptr(0), chunk_size, entry_type,
                                       chunk_size * nb_elems);
            return utils::matrix::load_arma_matrix(aux_mem, nb_elems,
                                                   chunk_size, by_column);
        }

        static long double
        compute_entropy(arma::subview_row<uword> const& dim,
                        std::pair<size_t, size_t>* majority_class = nullptr,
                        bool* is_only_class = nullptr);

    protected:
        utils::mpi::Communicator const& _comm;
        task::C4_5                      _tasks;
        utils::mpi::datatype::Manager   _mpi_types;

        // only used during training:
        CatDataset const*	_dataset;
        Parameters          _conf;
};

}   // end of namespace induction
}   // end of namespace ddti

#endif /* end of include guard: INDUCTIONC4_5_H */
<commit_msg>fix osx/linux include compatibility<commit_after>// C/C++ File

// Author:   Alexandre Tea <alexandre.qtea@gmail.com>
// File:     /Users/alexandretea/Work/ddti/srcs/master/InductionC4_5.hpp
// Purpose:  Induction algorithm based on Quinlan's C4.5
// Created:  2017-07-28 16:14:44
// Modified: 2017-09-10 11:47:05

#ifndef INDUCTIONC4_5_H
#define INDUCTIONC4_5_H

#include <map>
#include <armadillo>
#include "MasterNode.hpp"
#include "DecisionTree.hpp"
#include "MpiDatatypeManager.hpp"
#include "TaskC4_5.hpp"
#include "Dataset.hpp"
#include "ddti.hpp"
#include "utils/matrix.hpp"

namespace ddti {
namespace induction {

class C4_5
{
    public:
        struct Parameters
        {
            bool            debug;          // logs some debug info (i.e. IGR)
            unsigned int    min_leaf_size;  // min. number of instances per leaf

            Parameters() : debug(false), min_leaf_size(2)
            {}

            std::string
            to_string() const
            {
                return std::string("debug(") + (debug ? "true" : "false") + ")"
                       ", min_leaf_size(" + std::to_string(min_leaf_size) + ")";
            }
        };

        using ull_t = unsigned long long;
        template <typename T>
        using StdVecVec = std::vector<std::vector<T>>;

    public:
        C4_5(utils::mpi::Communicator const& comm);
        virtual ~C4_5();

        C4_5(C4_5 const& other) = delete;
        C4_5&           operator=(C4_5 const& other) = delete;

    public:
        std::unique_ptr<DecisionTree>
        operator()(CatDataset const& dataset,
                   Parameters conf = Parameters());
        // NOTE: conf is not received as a constant reference because the param
        // will be moved in a member variable

    protected:
        DecisionTree*   rec_train_node(arma::umat const& data,
                                       std::vector<size_t> const& attrs,
                                       int split_value = -1);
        void            send_task(int task_code) const;
        void            build_children(DecisionTree* node,
                                       arma::umat const& node_data,
                                       StdVecVec<ull_t> const& split_cols,
                                       std::vector<size_t> const& node_attrs);
        DecisionTree*   create_leaf(std::pair<size_t, size_t> const& label,
                                    int split_value, size_t nb_instances) const;
        bool            check_leaf_size(StdVecVec<ull_t> const& cols) const;
        void            debug(std::string const& s) const;

        std::pair<size_t, long double>   select_attribute(
            arma::umat const& data, std::vector<size_t> const& attrs,
            long double entropy
        );
        std::map<size_t, ContTable> count_contingencies(
            arma::umat const& data
        );
        StdVecVec<ull_t>            get_split_indices(
            arma::umat const& data, size_t attr
        ) const;

        // scatter matrix by column or by row
        // NOTE: we don't allow the scatter of subviews because they might
        // not be continuous in memory
        template <typename T>
        arma::Mat<T>
        scatter_matrix(arma::Mat<T> const& data, bool by_column = true)
        {
            MPI_Datatype   entry_type;
            size_t         chunk_size;
            size_t         nb_elems;
            T*             aux_mem;

            if (by_column) {    // armadillo matrices are column-major
                nb_elems = data.n_rows;
                chunk_size = data.n_cols / _comm.size();
                entry_type = _mpi_types.matrix_contiguous_entry<T>(data.n_rows);
            } else {
                nb_elems = data.n_cols;
                chunk_size = data.n_rows / _comm.size();
                entry_type =
                    _mpi_types.matrix_noncontiguous_entry<T>(nb_elems,
                                                             data.n_rows);
            }
            _comm.broadcast(nb_elems);   // nb elems
            _comm.broadcast(chunk_size); // nb entries
            aux_mem = _comm.scatter<T>(data.colptr(0), chunk_size, entry_type,
                                       chunk_size * nb_elems);
            return utils::matrix::load_arma_matrix(aux_mem, nb_elems,
                                                   chunk_size, by_column);
        }

        static long double
        compute_entropy(arma::subview_row<uword> const& dim,
                        std::pair<size_t, size_t>* majority_class = nullptr,
                        bool* is_only_class = nullptr);

    protected:
        utils::mpi::Communicator const& _comm;
        task::C4_5                      _tasks;
        utils::mpi::datatype::Manager   _mpi_types;

        // only used during training:
        CatDataset const*	_dataset;
        Parameters          _conf;
};

}   // end of namespace induction
}   // end of namespace ddti

#endif /* end of include guard: INDUCTIONC4_5_H */
<|endoftext|>