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

#include "sandbox/linux/services/libc_urandom_override.h"

#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/rand_util.h"

// Note: this file is used by the zygote and nacl_helper.

#if !defined(HAVE_XSTAT) && defined(LIBC_GLIBC)
#define HAVE_XSTAT 1
#endif

namespace sandbox {

static bool g_override_urandom = false;

// TODO(sergeyu): Currently InitLibcUrandomOverrides() doesn't work properly
// under ASAN - it crashes content_unittests. Make sure it works properly and
// enable it here. http://crbug.com/123263
#if !defined(ADDRESS_SANITIZER)
static void InitLibcFileIOFunctions();
static pthread_once_t g_libc_file_io_funcs_guard = PTHREAD_ONCE_INIT;
#endif

void InitLibcUrandomOverrides() {
  // Make sure /dev/urandom is open.
  base::GetUrandomFD();
  g_override_urandom = true;

#if !defined(ADDRESS_SANITIZER)
  CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                           InitLibcFileIOFunctions));
#endif
}

#if !defined(ADDRESS_SANITIZER)

static const char kUrandomDevPath[] = "/dev/urandom";

typedef FILE* (*FopenFunction)(const char* path, const char* mode);

static FopenFunction g_libc_fopen = NULL;
static FopenFunction g_libc_fopen64 = NULL;

#if HAVE_XSTAT
typedef int (*XstatFunction)(int version, const char *path, struct stat *buf);
typedef int (*Xstat64Function)(int version, const char *path,
                               struct stat64 *buf);

static XstatFunction g_libc_xstat = NULL;
static Xstat64Function g_libc_xstat64 = NULL;
#else
typedef int (*StatFunction)(const char *path, struct stat *buf);
typedef int (*Stat64Function)(const char *path, struct stat64 *buf);

static StatFunction g_libc_stat = NULL;
static Stat64Function g_libc_stat64 = NULL;
#endif  // HAVE_XSTAT

// Find the libc's real fopen* and *stat* functions. This should only be
// called once, and should be guarded by g_libc_file_io_funcs_guard.
static void InitLibcFileIOFunctions() {
  g_libc_fopen = reinterpret_cast<FopenFunction>(
      dlsym(RTLD_NEXT, "fopen"));
  g_libc_fopen64 = reinterpret_cast<FopenFunction>(
      dlsym(RTLD_NEXT, "fopen64"));

  if (!g_libc_fopen) {
    LOG(FATAL) << "Failed to get fopen() from libc.";
  } else if (!g_libc_fopen64) {
#if !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
    LOG(WARNING) << "Failed to get fopen64() from libc. Using fopen() instead.";
#endif  // !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
    g_libc_fopen64 = g_libc_fopen;
  }

#if HAVE_XSTAT
  g_libc_xstat = reinterpret_cast<XstatFunction>(
      dlsym(RTLD_NEXT, "__xstat"));
  g_libc_xstat64 = reinterpret_cast<Xstat64Function>(
      dlsym(RTLD_NEXT, "__xstat64"));

  if (!g_libc_xstat) {
    LOG(FATAL) << "Failed to get __xstat() from libc.";
  }
  if (!g_libc_xstat64) {
    LOG(FATAL) << "Failed to get __xstat64() from libc.";
  }
#else
  g_libc_stat = reinterpret_cast<StatFunction>(
      dlsym(RTLD_NEXT, "stat"));
  g_libc_stat64 = reinterpret_cast<Stat64Function>(
      dlsym(RTLD_NEXT, "stat64"));

  if (!g_libc_stat) {
    LOG(FATAL) << "Failed to get stat() from libc.";
  }
  if (!g_libc_stat64) {
    LOG(FATAL) << "Failed to get stat64() from libc.";
  }
#endif  // HAVE_XSTAT
}

// fopen() and fopen64() are intercepted here so that NSS can open
// /dev/urandom to seed its random number generator. NSS is used by
// remoting in the sendbox.

// fopen() call may be redirected to fopen64() in stdio.h using
// __REDIRECT(), which sets asm name for fopen() to "fopen64". This
// means that we cannot override fopen() directly here. Instead the
// the code below defines fopen_override() function with asm name
// "fopen", so that all references to fopen() will resolve to this
// function.
__attribute__ ((__visibility__("default")))
FILE* fopen_override(const char* path, const char* mode)  __asm__ ("fopen");

__attribute__ ((__visibility__("default")))
FILE* fopen_override(const char* path, const char* mode) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
    if (fd < 0) {
      PLOG(ERROR) << "dup() failed.";
      return NULL;
    }
    return fdopen(fd, mode);
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_fopen(path, mode);
  }
}

__attribute__ ((__visibility__("default")))
FILE* fopen64(const char* path, const char* mode) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
    if (fd < 0) {
      PLOG(ERROR) << "dup() failed.";
      return NULL;
    }
    return fdopen(fd, mode);
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_fopen64(path, mode);
  }
}

// The stat() family of functions are subject to the same problem as
// fopen(), so we have to use the same trick to override them.

#if HAVE_XSTAT

__attribute__ ((__visibility__("default")))
int xstat_override(int version,
                   const char *path,
                   struct stat *buf)  __asm__ ("__xstat");

__attribute__ ((__visibility__("default")))
int xstat_override(int version, const char *path, struct stat *buf) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int result = __fxstat(version, base::GetUrandomFD(), buf);
    return result;
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_xstat(version, path, buf);
  }
}

__attribute__ ((__visibility__("default")))
int xstat64_override(int version,
                     const char *path,
                     struct stat64 *buf)  __asm__ ("__xstat64");

__attribute__ ((__visibility__("default")))
int xstat64_override(int version, const char *path, struct stat64 *buf) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int result = __fxstat64(version, base::GetUrandomFD(), buf);
    return result;
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_xstat64(version, path, buf);
  }
}

#else

__attribute__ ((__visibility__("default")))
int stat_override(const char *path,
                  struct stat *buf)  __asm__ ("stat");

__attribute__ ((__visibility__("default")))
int stat_override(const char *path, struct stat *buf) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int result = fstat(base::GetUrandomFD(), buf);
    return result;
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_stat(path, buf);
  }
}

__attribute__ ((__visibility__("default")))
int stat64_override(const char *path,
                    struct stat64 *buf)  __asm__ ("stat64");

__attribute__ ((__visibility__("default")))
int stat64_override(const char *path, struct stat64 *buf) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int result = fstat64(base::GetUrandomFD(), buf);
    return result;
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_stat64(path, buf);
  }
}

#endif  // HAVE_XSTAT

#endif  // !defined(ADDRESS_SANITIZER)

}  // namespace content
<commit_msg>Disable libc urandom overrides under MSan.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sandbox/linux/services/libc_urandom_override.h"

#include <dlfcn.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/rand_util.h"

// Note: this file is used by the zygote and nacl_helper.

#if !defined(HAVE_XSTAT) && defined(LIBC_GLIBC)
#define HAVE_XSTAT 1
#endif

namespace sandbox {

static bool g_override_urandom = false;

// TODO(sergeyu): Currently InitLibcUrandomOverrides() doesn't work properly
// under ASan or MSan - it crashes content_unittests. Make sure it works
// properly and enable it here. http://crbug.com/123263
#if !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
static void InitLibcFileIOFunctions();
static pthread_once_t g_libc_file_io_funcs_guard = PTHREAD_ONCE_INIT;
#endif

void InitLibcUrandomOverrides() {
  // Make sure /dev/urandom is open.
  base::GetUrandomFD();
  g_override_urandom = true;

#if !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
  CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                           InitLibcFileIOFunctions));
#endif
}

#if !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))

static const char kUrandomDevPath[] = "/dev/urandom";

typedef FILE* (*FopenFunction)(const char* path, const char* mode);

static FopenFunction g_libc_fopen = NULL;
static FopenFunction g_libc_fopen64 = NULL;

#if HAVE_XSTAT
typedef int (*XstatFunction)(int version, const char *path, struct stat *buf);
typedef int (*Xstat64Function)(int version, const char *path,
                               struct stat64 *buf);

static XstatFunction g_libc_xstat = NULL;
static Xstat64Function g_libc_xstat64 = NULL;
#else
typedef int (*StatFunction)(const char *path, struct stat *buf);
typedef int (*Stat64Function)(const char *path, struct stat64 *buf);

static StatFunction g_libc_stat = NULL;
static Stat64Function g_libc_stat64 = NULL;
#endif  // HAVE_XSTAT

// Find the libc's real fopen* and *stat* functions. This should only be
// called once, and should be guarded by g_libc_file_io_funcs_guard.
static void InitLibcFileIOFunctions() {
  g_libc_fopen = reinterpret_cast<FopenFunction>(
      dlsym(RTLD_NEXT, "fopen"));
  g_libc_fopen64 = reinterpret_cast<FopenFunction>(
      dlsym(RTLD_NEXT, "fopen64"));

  if (!g_libc_fopen) {
    LOG(FATAL) << "Failed to get fopen() from libc.";
  } else if (!g_libc_fopen64) {
#if !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
    LOG(WARNING) << "Failed to get fopen64() from libc. Using fopen() instead.";
#endif  // !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
    g_libc_fopen64 = g_libc_fopen;
  }

#if HAVE_XSTAT
  g_libc_xstat = reinterpret_cast<XstatFunction>(
      dlsym(RTLD_NEXT, "__xstat"));
  g_libc_xstat64 = reinterpret_cast<Xstat64Function>(
      dlsym(RTLD_NEXT, "__xstat64"));

  if (!g_libc_xstat) {
    LOG(FATAL) << "Failed to get __xstat() from libc.";
  }
  if (!g_libc_xstat64) {
    LOG(FATAL) << "Failed to get __xstat64() from libc.";
  }
#else
  g_libc_stat = reinterpret_cast<StatFunction>(
      dlsym(RTLD_NEXT, "stat"));
  g_libc_stat64 = reinterpret_cast<Stat64Function>(
      dlsym(RTLD_NEXT, "stat64"));

  if (!g_libc_stat) {
    LOG(FATAL) << "Failed to get stat() from libc.";
  }
  if (!g_libc_stat64) {
    LOG(FATAL) << "Failed to get stat64() from libc.";
  }
#endif  // HAVE_XSTAT
}

// fopen() and fopen64() are intercepted here so that NSS can open
// /dev/urandom to seed its random number generator. NSS is used by
// remoting in the sendbox.

// fopen() call may be redirected to fopen64() in stdio.h using
// __REDIRECT(), which sets asm name for fopen() to "fopen64". This
// means that we cannot override fopen() directly here. Instead the
// the code below defines fopen_override() function with asm name
// "fopen", so that all references to fopen() will resolve to this
// function.
__attribute__ ((__visibility__("default")))
FILE* fopen_override(const char* path, const char* mode)  __asm__ ("fopen");

__attribute__ ((__visibility__("default")))
FILE* fopen_override(const char* path, const char* mode) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
    if (fd < 0) {
      PLOG(ERROR) << "dup() failed.";
      return NULL;
    }
    return fdopen(fd, mode);
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_fopen(path, mode);
  }
}

__attribute__ ((__visibility__("default")))
FILE* fopen64(const char* path, const char* mode) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
    if (fd < 0) {
      PLOG(ERROR) << "dup() failed.";
      return NULL;
    }
    return fdopen(fd, mode);
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_fopen64(path, mode);
  }
}

// The stat() family of functions are subject to the same problem as
// fopen(), so we have to use the same trick to override them.

#if HAVE_XSTAT

__attribute__ ((__visibility__("default")))
int xstat_override(int version,
                   const char *path,
                   struct stat *buf)  __asm__ ("__xstat");

__attribute__ ((__visibility__("default")))
int xstat_override(int version, const char *path, struct stat *buf) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int result = __fxstat(version, base::GetUrandomFD(), buf);
    return result;
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_xstat(version, path, buf);
  }
}

__attribute__ ((__visibility__("default")))
int xstat64_override(int version,
                     const char *path,
                     struct stat64 *buf)  __asm__ ("__xstat64");

__attribute__ ((__visibility__("default")))
int xstat64_override(int version, const char *path, struct stat64 *buf) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int result = __fxstat64(version, base::GetUrandomFD(), buf);
    return result;
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_xstat64(version, path, buf);
  }
}

#else

__attribute__ ((__visibility__("default")))
int stat_override(const char *path,
                  struct stat *buf)  __asm__ ("stat");

__attribute__ ((__visibility__("default")))
int stat_override(const char *path, struct stat *buf) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int result = fstat(base::GetUrandomFD(), buf);
    return result;
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_stat(path, buf);
  }
}

__attribute__ ((__visibility__("default")))
int stat64_override(const char *path,
                    struct stat64 *buf)  __asm__ ("stat64");

__attribute__ ((__visibility__("default")))
int stat64_override(const char *path, struct stat64 *buf) {
  if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    int result = fstat64(base::GetUrandomFD(), buf);
    return result;
  } else {
    CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
                             InitLibcFileIOFunctions));
    return g_libc_stat64(path, buf);
  }
}

#endif  // HAVE_XSTAT

#endif  // !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))

}  // namespace content
<|endoftext|>


<commit_before>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2015 Taras Kushnir <kushnirTV@gmail.com>
 *
 * Xpiks is distributed under the GNU General Public License, version 3.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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 "filteredartitemsproxymodel.h"
#include "artitemsmodel.h"
#include "artworkmetadata.h"
#include "artworksrepository.h"
#include "artiteminfo.h"
#include "../Commands/commandmanager.h"

namespace Models {
    FilteredArtItemsProxyModel::FilteredArtItemsProxyModel(QObject *parent) :
        QSortFilterProxyModel(parent),
        Common::BaseEntity(),
        m_SelectedArtworksCount(0)
    {
    }

    void FilteredArtItemsProxyModel::setSearchTerm(const QString &value) {
        if (value != m_SearchTerm) {
            m_SearchTerm = value;
            emit searchTermChanged(value);
            invalidateFilter();
            forceUnselectAllItems();
            emit afterInvalidateFilter();
        }
    }

    int FilteredArtItemsProxyModel::getOriginalIndex(int index) {
        QModelIndex originalIndex = mapToSource(this->index(index, 0));
        int row = originalIndex.row();
        return row;
    }

    void FilteredArtItemsProxyModel::selectDirectory(int directoryIndex) {
        QList<int> directoryItems;
        ArtItemsModel *artItemsModel = getArtItemsModel();
        const ArtworksRepository *artworksRepository = m_CommandManager->getArtworksRepository();
        const QString directory = artworksRepository->getDirectory(directoryIndex);

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);
            Q_ASSERT(metadata != NULL);

            if (metadata->isInDirectory(directory)) {
                directoryItems.append(row);
                metadata->setIsSelected(!metadata->getIsSelected());
            }
        }

        artItemsModel->updateItems(directoryItems, QVector<int>() << ArtItemsModel::IsSelectedRole);
    }

    void FilteredArtItemsProxyModel::combineSelectedArtworks() {
        QList<ArtItemInfo *> artworksList = getSelectedOriginalItemsWithIndices();
        m_CommandManager->combineArtworks(artworksList);
    }

    void FilteredArtItemsProxyModel::setSelectedItemsSaved() {
        QList<int> indices = getSelectedOriginalIndices();
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->setSelectedItemsSaved(indices);
    }

    void FilteredArtItemsProxyModel::removeSelectedArtworks() {
        QList<int> indices = getSelectedOriginalIndices();
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->removeSelectedArtworks(indices);
    }

    void FilteredArtItemsProxyModel::updateSelectedArtworks() {
        QList<int> indices = getSelectedOriginalIndices();
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->updateSelectedArtworks(indices);
    }

    void FilteredArtItemsProxyModel::saveSelectedArtworks() {
        // former patchSelectedArtworks
        QList<int> indices = getSelectedOriginalIndices();
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->saveSelectedArtworks(indices);
    }

    void FilteredArtItemsProxyModel::setSelectedForUpload() {
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        m_CommandManager->setArtworksForUpload(selectedArtworks);
        emit needCheckItemsForWarnings(selectedArtworks);
    }

    void FilteredArtItemsProxyModel::setSelectedForZipping() {
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        m_CommandManager->setArtworksForZipping(selectedArtworks);
    }

    bool FilteredArtItemsProxyModel::areSelectedArtworksSaved() {
        int modifiedSelectedCount = getModifiedSelectedCount();
        return modifiedSelectedCount == 0;
    }

    int FilteredArtItemsProxyModel::getModifiedSelectedCount() const {
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        int modifiedCount = 0;

        foreach (const ArtworkMetadata *metadata, selectedArtworks) {
            if (metadata->isModified()) {
                modifiedCount++;
            }
        }

        return modifiedCount;
    }

    void FilteredArtItemsProxyModel::removeArtworksDirectory(int index) {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->removeArtworksDirectory(index);
        emit selectedArtworksCountChanged();
    }

    void FilteredArtItemsProxyModel::checkForWarnings() {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        artItemsModel->checkForWarnings(selectedArtworks);
    }

    void FilteredArtItemsProxyModel::reimportMetadataForSelected() {
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        m_CommandManager->setArtworksForIPTCProcessing(selectedArtworks);
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->raiseArtworksAdded(selectedArtworks.count());
    }

    int FilteredArtItemsProxyModel::findSelectedItemIndex() const {
        int index = -1;
        QList<int> indices = getSelectedOriginalIndices();
        if (indices.length() == 1) {
            index = indices.first();
        }

        return index;
    }

    void FilteredArtItemsProxyModel::itemSelectedChanged(bool value) {
        int plus = value ? +1 : -1;
        m_SelectedArtworksCount += plus;
        emit selectedArtworksCountChanged();
    }

    void FilteredArtItemsProxyModel::onSelectedArtworksRemoved() {
        m_SelectedArtworksCount--;
        emit selectedArtworksCountChanged();
    }

    void FilteredArtItemsProxyModel::setFilteredItemsSelected(bool selected) {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<int> indices;

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);
            Q_ASSERT(metadata != NULL);
            metadata->setIsSelected(selected);
            indices << index;
        }

        artItemsModel->updateItems(indices, QVector<int>() << ArtItemsModel::IsSelectedRole);
    }

    QList<ArtworkMetadata *> FilteredArtItemsProxyModel::getSelectedOriginalItems() const {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<ArtworkMetadata *> selectedArtworks;

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);

            if (metadata != NULL && metadata->getIsSelected()) {
                selectedArtworks.append(metadata);
            }
        }

        return selectedArtworks;
    }

    QList<ArtItemInfo *> FilteredArtItemsProxyModel::getSelectedOriginalItemsWithIndices() const {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<ArtItemInfo *> selectedArtworks;

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);

            if (metadata != NULL && metadata->getIsSelected()) {
                ArtItemInfo *info = new ArtItemInfo(metadata, index);
                selectedArtworks.append(info);
            }
        }

        return selectedArtworks;
    }

    QList<int> FilteredArtItemsProxyModel::getSelectedOriginalIndices() const {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<int> selectedIndices;

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);

            if (metadata != NULL && metadata->getIsSelected()) {
                selectedIndices.append(index);
            }
        }

        return selectedIndices;
    }

    void FilteredArtItemsProxyModel::forceUnselectAllItems() {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->forceUnselectAllItems();
        m_SelectedArtworksCount = 0;
        emit selectedArtworksCountChanged();
    }

    ArtItemsModel *FilteredArtItemsProxyModel::getArtItemsModel() const {
        QAbstractItemModel *sourceItemModel = sourceModel();
        ArtItemsModel *artItemsModel = dynamic_cast<ArtItemsModel *>(sourceItemModel);
        return artItemsModel;
    }

    bool FilteredArtItemsProxyModel::fitsSpecialKeywords(const ArtworkMetadata *metadata) const {
        if (m_SearchTerm == "x:modified" && metadata->isModified()) {
            return true;
        }

        if (m_SearchTerm == "x:empty" && metadata->isEmpty()) {
            return true;
        }

        if (m_SearchTerm == "x:selected" && metadata->getIsSelected()) {
            return true;
        }

        return false;
    }

    bool FilteredArtItemsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
        Q_UNUSED(sourceParent);

        ArtItemsModel *artItemsModel = getArtItemsModel();
        ArtworkMetadata *metadata = artItemsModel->getArtwork(sourceRow);

        if (fitsSpecialKeywords(metadata)) { return true; }

        bool hasMatch = false;

        hasMatch = metadata->getDescription().contains(m_SearchTerm, Qt::CaseInsensitive);

        if (!hasMatch) {
            hasMatch = metadata->getTitle().contains(m_SearchTerm, Qt::CaseInsensitive);
        }

        if (!hasMatch) {
            hasMatch = metadata->getFilepath().contains(m_SearchTerm, Qt::CaseInsensitive);
        }

        if (!hasMatch) {
            const QStringList &keywords = metadata->getKeywords();
            foreach (const QString &keyword, keywords) {
                if (keyword.contains(m_SearchTerm, Qt::CaseInsensitive)) {
                    hasMatch = true;
                    break;
                }
            }
        }

        return hasMatch;
    }
}
<commit_msg>Enabled multiple words for filtering<commit_after>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2015 Taras Kushnir <kushnirTV@gmail.com>
 *
 * Xpiks is distributed under the GNU General Public License, version 3.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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 "filteredartitemsproxymodel.h"
#include "artitemsmodel.h"
#include "artworkmetadata.h"
#include "artworksrepository.h"
#include "artiteminfo.h"
#include "../Commands/commandmanager.h"

namespace Models {
    FilteredArtItemsProxyModel::FilteredArtItemsProxyModel(QObject *parent) :
        QSortFilterProxyModel(parent),
        Common::BaseEntity(),
        m_SelectedArtworksCount(0)
    {
    }

    void FilteredArtItemsProxyModel::setSearchTerm(const QString &value) {
        if (value != m_SearchTerm) {
            m_SearchTerm = value;
            emit searchTermChanged(value);
            invalidateFilter();
            forceUnselectAllItems();
            emit afterInvalidateFilter();
        }
    }

    int FilteredArtItemsProxyModel::getOriginalIndex(int index) {
        QModelIndex originalIndex = mapToSource(this->index(index, 0));
        int row = originalIndex.row();
        return row;
    }

    void FilteredArtItemsProxyModel::selectDirectory(int directoryIndex) {
        QList<int> directoryItems;
        ArtItemsModel *artItemsModel = getArtItemsModel();
        const ArtworksRepository *artworksRepository = m_CommandManager->getArtworksRepository();
        const QString directory = artworksRepository->getDirectory(directoryIndex);

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);
            Q_ASSERT(metadata != NULL);

            if (metadata->isInDirectory(directory)) {
                directoryItems.append(row);
                metadata->setIsSelected(!metadata->getIsSelected());
            }
        }

        artItemsModel->updateItems(directoryItems, QVector<int>() << ArtItemsModel::IsSelectedRole);
    }

    void FilteredArtItemsProxyModel::combineSelectedArtworks() {
        QList<ArtItemInfo *> artworksList = getSelectedOriginalItemsWithIndices();
        m_CommandManager->combineArtworks(artworksList);
    }

    void FilteredArtItemsProxyModel::setSelectedItemsSaved() {
        QList<int> indices = getSelectedOriginalIndices();
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->setSelectedItemsSaved(indices);
    }

    void FilteredArtItemsProxyModel::removeSelectedArtworks() {
        QList<int> indices = getSelectedOriginalIndices();
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->removeSelectedArtworks(indices);
    }

    void FilteredArtItemsProxyModel::updateSelectedArtworks() {
        QList<int> indices = getSelectedOriginalIndices();
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->updateSelectedArtworks(indices);
    }

    void FilteredArtItemsProxyModel::saveSelectedArtworks() {
        // former patchSelectedArtworks
        QList<int> indices = getSelectedOriginalIndices();
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->saveSelectedArtworks(indices);
    }

    void FilteredArtItemsProxyModel::setSelectedForUpload() {
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        m_CommandManager->setArtworksForUpload(selectedArtworks);
        emit needCheckItemsForWarnings(selectedArtworks);
    }

    void FilteredArtItemsProxyModel::setSelectedForZipping() {
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        m_CommandManager->setArtworksForZipping(selectedArtworks);
    }

    bool FilteredArtItemsProxyModel::areSelectedArtworksSaved() {
        int modifiedSelectedCount = getModifiedSelectedCount();
        return modifiedSelectedCount == 0;
    }

    int FilteredArtItemsProxyModel::getModifiedSelectedCount() const {
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        int modifiedCount = 0;

        foreach (const ArtworkMetadata *metadata, selectedArtworks) {
            if (metadata->isModified()) {
                modifiedCount++;
            }
        }

        return modifiedCount;
    }

    void FilteredArtItemsProxyModel::removeArtworksDirectory(int index) {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->removeArtworksDirectory(index);
        emit selectedArtworksCountChanged();
    }

    void FilteredArtItemsProxyModel::checkForWarnings() {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        artItemsModel->checkForWarnings(selectedArtworks);
    }

    void FilteredArtItemsProxyModel::reimportMetadataForSelected() {
        QList<ArtworkMetadata *> selectedArtworks = getSelectedOriginalItems();
        m_CommandManager->setArtworksForIPTCProcessing(selectedArtworks);
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->raiseArtworksAdded(selectedArtworks.count());
    }

    int FilteredArtItemsProxyModel::findSelectedItemIndex() const {
        int index = -1;
        QList<int> indices = getSelectedOriginalIndices();
        if (indices.length() == 1) {
            index = indices.first();
        }

        return index;
    }

    void FilteredArtItemsProxyModel::itemSelectedChanged(bool value) {
        int plus = value ? +1 : -1;
        m_SelectedArtworksCount += plus;
        emit selectedArtworksCountChanged();
    }

    void FilteredArtItemsProxyModel::onSelectedArtworksRemoved() {
        m_SelectedArtworksCount--;
        emit selectedArtworksCountChanged();
    }

    void FilteredArtItemsProxyModel::setFilteredItemsSelected(bool selected) {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<int> indices;

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);
            Q_ASSERT(metadata != NULL);
            metadata->setIsSelected(selected);
            indices << index;
        }

        artItemsModel->updateItems(indices, QVector<int>() << ArtItemsModel::IsSelectedRole);
    }

    QList<ArtworkMetadata *> FilteredArtItemsProxyModel::getSelectedOriginalItems() const {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<ArtworkMetadata *> selectedArtworks;

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);

            if (metadata != NULL && metadata->getIsSelected()) {
                selectedArtworks.append(metadata);
            }
        }

        return selectedArtworks;
    }

    QList<ArtItemInfo *> FilteredArtItemsProxyModel::getSelectedOriginalItemsWithIndices() const {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<ArtItemInfo *> selectedArtworks;

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);

            if (metadata != NULL && metadata->getIsSelected()) {
                ArtItemInfo *info = new ArtItemInfo(metadata, index);
                selectedArtworks.append(info);
            }
        }

        return selectedArtworks;
    }

    QList<int> FilteredArtItemsProxyModel::getSelectedOriginalIndices() const {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        QList<int> selectedIndices;

        int size = this->rowCount();
        for (int row = 0; row < size; ++row) {
            QModelIndex proxyIndex = this->index(row, 0);
            QModelIndex originalIndex = this->mapToSource(proxyIndex);

            int index = originalIndex.row();
            ArtworkMetadata *metadata = artItemsModel->getArtwork(index);

            if (metadata != NULL && metadata->getIsSelected()) {
                selectedIndices.append(index);
            }
        }

        return selectedIndices;
    }

    void FilteredArtItemsProxyModel::forceUnselectAllItems() {
        ArtItemsModel *artItemsModel = getArtItemsModel();
        artItemsModel->forceUnselectAllItems();
        m_SelectedArtworksCount = 0;
        emit selectedArtworksCountChanged();
    }

    ArtItemsModel *FilteredArtItemsProxyModel::getArtItemsModel() const {
        QAbstractItemModel *sourceItemModel = sourceModel();
        ArtItemsModel *artItemsModel = dynamic_cast<ArtItemsModel *>(sourceItemModel);
        return artItemsModel;
    }

    bool FilteredArtItemsProxyModel::fitsSpecialKeywords(const ArtworkMetadata *metadata) const {
        if (m_SearchTerm.isEmpty()) {
            return true;
        }

        if (m_SearchTerm == "x:modified" && metadata->isModified()) {
            return true;
        }

        if (m_SearchTerm == "x:empty" && metadata->isEmpty()) {
            return true;
        }

        if (m_SearchTerm == "x:selected" && metadata->getIsSelected()) {
            return true;
        }

        return false;
    }

    bool FilteredArtItemsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
        Q_UNUSED(sourceParent);

        ArtItemsModel *artItemsModel = getArtItemsModel();
        ArtworkMetadata *metadata = artItemsModel->getArtwork(sourceRow);

        if (fitsSpecialKeywords(metadata)) { return true; }

        bool hasMatch = false;

        QStringList searchTerms = m_SearchTerm.split(QChar::Space, QString::SkipEmptyParts);

        foreach (const QString &searchTerm, searchTerms) {
            hasMatch = metadata->getDescription().contains(searchTerm, Qt::CaseInsensitive);

            if (!hasMatch) {
                hasMatch = metadata->getTitle().contains(searchTerm, Qt::CaseInsensitive);
            }

            if (!hasMatch) {
                hasMatch = metadata->getFilepath().contains(searchTerm, Qt::CaseInsensitive);
            }

            if (!hasMatch) {
                const QStringList &keywords = metadata->getKeywords();
                foreach (const QString &keyword, keywords) {
                    if (keyword.contains(searchTerm, Qt::CaseInsensitive)) {
                        hasMatch = true;
                        break;
                    }
                }
            }

            if (hasMatch) {
                break;
            }
        }

        return hasMatch;
    }
}
<|endoftext|>


<commit_before>// This is a work in progress.
// C.M.Cantalupo

#include <algorithm>
#ifdef _OPENMP
#include "omp.h"
#endif
#include "sorter_threaded.hpp"
#include "partition.hpp"
#include "splinter.hpp"
#include "sorter_threaded_exception.hpp"

using namespace SorterThreadedHelper;

void SorterThreaded::sort(std::vector<double>::iterator begin,
                          std::vector<double>::iterator end) {
  // To achieve parallelism here we will choose a set of pivots from
  // the list to be sorted.  Here we will just choose the first elements
  // in the vector.  The number of pivots will determine the number of
  // tasks to be done: one more task than the number of pivots.
  //
  // For simplicity here we will choose the number of tasks to be
  // a factor of the number of threads.  This will be determined
  // by the class attribute taskFactor_.
  //
  // We need to break down the main scaling dimension of the problem,
  // the length of the input vector.  The first thing that we want to
  // do with the input is to partition it into intervals bounded by
  // the pivots.  This can be done with the std::set.upper_bound() to
  // partition the input vector.  In the end we want taskFactor_ times
  // the number of threads jobs and we need one fewer pivot than that
  // to do so.  Bundle up the pivots with a stack and put them in a
  // std::set along with a dummy pivot for the end.  We will
  // call this class "PartitionWall." The set provides a upper_bound
  // bound function so we need to overload less than.
  //

#ifndef _OPENMP
  std::sort(begin, end);
#else
  if (numThreads_ == -1) {
    numThreads_ = omp_get_max_threads();
  }

  size_t numTasks = numThreads_ * taskFactor_;
  std::vector<double>::iterator chunkBegin;
  std::vector<double>::iterator chunkEnd;
  std::set<double> pivots;

  // Create a set of pivots by going through the vector
  for (std::vector<double>::iterator it = begin;
       it != end && pivots.size() < numThreads_*taskFactor_ - 1;
       ++it) {
      pivots.insert(*it);
  }
  // Check that there were as many unique values as we need
  if (pivots.size() < numThreads_ * taskFactor_ - 1) {
    std::sort(begin, end);
    return;
  }

  Splinter splinter(begin, end);
  std::vector<std::vector<double>::iterator> chunks;

  splinter.even(numThreads_, chunks);

  std::vector<std::vector<double>::iterator> taskOffsets(numTasks);
#pragma omp parallel default (shared) private (none) shared (splinter, chunks, taskOffsets, pivots, numThreads_)
{
  int threadID = omp_get_thread_num();
  Partition partition(pivots);
  partition.fill(chunks[threadID], chunks[threadID+1]);
#pragma  omp barrier;
  std::vector<size_t> mySizes;
  partition.taskSizes(mySizes);

  for (size_t i = 0; i < numThreads_; ++i) {
    if (i == threadID) {
      splinter.addSizes(mySizes);
    }
#pragma omp barrier
  }

  std::vector<std::vector<double>::iterator> offsets;
  for (size_t i = 0; i < numThreads_; ++i) {
    if (i == threadID) {
      splinter.getOffsets(mySizes, offsets);
    }
#pragma omp barrier
  }

  for (size_t i = 0; i < numTasks; ++i) {
    partition.popTask(offsets[i]);
  }

  if (threadID == numThreads_ - 1) {
    // cannot use vector assignment otherwise taskOffsets' data is no longer shared
    for (size_t i = 0; i < numTasks; ++i) {
      taskOffsets[i] = offsets[i];
    }
  }
#pragma omp barrier

#pragma omp parallel for schedule (dynamic)
  for (size_t i = 0; i < numTasks - 1; ++i) {
    std::sort(taskOffsets[i], taskOffsets[i+1]);
  }
#pragma omp critical
{
  if (taskOffsets[numTasks-1] != end) {
    std::sort(taskOffsets[numTasks - 1], end);
  }
} //end omp critical region
} //end omp parallel region
#endif
}

SorterThreaded::SorterThreaded(int taskFactor, int numThreads) :
  taskFactor_(taskFactor),
  numThreads_(numThreads) {}

<commit_msg>size_t -> int for loops and end and begin omp shared<commit_after>// This is a work in progress.
// C.M.Cantalupo

#include <algorithm>
#ifdef _OPENMP
#include "omp.h"
#endif
#include "sorter_threaded.hpp"
#include "partition.hpp"
#include "splinter.hpp"
#include "sorter_threaded_exception.hpp"

using namespace SorterThreadedHelper;

void SorterThreaded::sort(std::vector<double>::iterator begin,
                          std::vector<double>::iterator end) {
  // To achieve parallelism here we will choose a set of pivots from
  // the list to be sorted.  Here we will just choose the first elements
  // in the vector.  The number of pivots will determine the number of
  // tasks to be done: one more task than the number of pivots.
  //
  // For simplicity here we will choose the number of tasks to be
  // a factor of the number of threads.  This will be determined
  // by the class attribute taskFactor_.
  //
  // We need to break down the main scaling dimension of the problem,
  // the length of the input vector.  The first thing that we want to
  // do with the input is to partition it into intervals bounded by
  // the pivots.  This can be done with the std::set.upper_bound() to
  // partition the input vector.  In the end we want taskFactor_ times
  // the number of threads jobs and we need one fewer pivot than that
  // to do so.  Bundle up the pivots with a stack and put them in a
  // std::set along with a dummy pivot for the end.  We will
  // call this class "PartitionWall." The set provides a upper_bound
  // bound function so we need to overload less than.
  //

#ifndef _OPENMP
  std::sort(begin, end);
#else
  if (numThreads_ == -1) {
    numThreads_ = omp_get_max_threads();
  }

  size_t numTasks = numThreads_ * taskFactor_;
  std::vector<double>::iterator chunkBegin;
  std::vector<double>::iterator chunkEnd;
  std::set<double> pivots;

  // Create a set of pivots by going through the vector
  for (std::vector<double>::iterator it = begin;
       it != end && pivots.size() < numThreads_*taskFactor_ - 1;
       ++it) {
      pivots.insert(*it);
  }
  // Check that there were as many unique values as we need
  if (pivots.size() < numThreads_ * taskFactor_ - 1) {
    std::sort(begin, end);
    return;
  }

  Splinter splinter(begin, end);
  std::vector<std::vector<double>::iterator> chunks;

  splinter.even(numThreads_, chunks);

  std::vector<std::vector<double>::iterator> taskOffsets(numTasks);
#pragma omp parallel default (shared) private (none) shared (begin, end, splinter, chunks, taskOffsets, pivots, numThreads_)
{
  int threadID = omp_get_thread_num();
  Partition partition(pivots);
  partition.fill(chunks[threadID], chunks[threadID+1]);
#pragma  omp barrier;
  std::vector<size_t> mySizes;
  partition.taskSizes(mySizes);

  for (int i = 0; i < numThreads_; ++i) {
    if (i == threadID) {
      splinter.addSizes(mySizes);
    }
#pragma omp barrier
  }

  std::vector<std::vector<double>::iterator> offsets;
  for (int i = 0; i < numThreads_; ++i) {
    if (i == threadID) {
      splinter.getOffsets(mySizes, offsets);
    }
#pragma omp barrier
  }

  for (int i = 0; i < numTasks; ++i) {
    partition.popTask(offsets[i]);
  }

  if (threadID == numThreads_ - 1) {
    // cannot use vector assignment otherwise taskOffsets' data is no longer shared
    for (int i = 0; i < numTasks; ++i) {
      taskOffsets[i] = offsets[i];
    }
  }
#pragma omp barrier

#pragma omp parallel for schedule (dynamic)
  for (int i = 0; i < numTasks - 1; ++i) {
    std::sort(taskOffsets[i], taskOffsets[i+1]);
  }
#pragma omp critical
{
  if (taskOffsets[numTasks-1] != end) {
    std::sort(taskOffsets[numTasks - 1], end);
  }
} //end omp critical region
} //end omp parallel region
#endif
}

SorterThreaded::SorterThreaded(int taskFactor, int numThreads) :
  taskFactor_(taskFactor),
  numThreads_(numThreads) {}

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*
	File is modified to include Ring Keywords and Ignore the Case
	Updated by : Mahmoud Fayed <msfclipper@yahoo.com>
	Date	    : 2016.09.14
*/

#include "highlighter.h"

Highlighter::Highlighter(QTextDocument *parent)
    : QSyntaxHighlighter(parent)
{
    setColors(Qt::darkBlue,Qt::darkMagenta,Qt::red,Qt::darkGreen,Qt::blue);
}

void Highlighter::highlightBlock(const QString &text)
{

    foreach (const HighlightingRule &rule, highlightingRules) {
        QRegExp expression(rule.pattern);
        int index = expression.indexIn(text);
        while (index >= 0) {
            int length = expression.matchedLength();
            setFormat(index, length, rule.format);
            index = expression.indexIn(text, index + length);
        }
    }
    setCurrentBlockState(0);
    int startIndex = 0;
    if (previousBlockState() != 1)
        startIndex = commentStartExpression.indexIn(text);

    while (startIndex >= 0) {
        int endIndex = commentEndExpression.indexIn(text, startIndex);
        int commentLength;
        if (endIndex == -1) {
            setCurrentBlockState(1);
            commentLength = text.length() - startIndex;
        } else {
            commentLength = endIndex - startIndex
                            + commentEndExpression.matchedLength();
        }
        setFormat(startIndex, commentLength, multiLineCommentFormat);
        startIndex = commentStartExpression.indexIn(text, startIndex + commentLength);
    }
}

void Highlighter::setColors(QColor c1,QColor c2,QColor c3,QColor c4,QColor c5) {

    HighlightingRule rule;
    highlightingRules.remove(0,highlightingRules.count());
    keywordFormat.setForeground(c1);
    if (this->nKeywordsBold)
	    keywordFormat.setFontWeight(QFont::Bold);
    QStringList keywordPatterns;
    keywordPatterns << "\\bagain\\b" << "\\band\\b" << "\\bbut\\b"
                    << "\\bbye\\b" << "\\bcall\\b" << "\\bcase\\b"
                    << "\\bcatch\\b" << "\\bclass\\b" << "\\bdef\\b"
                    << "\\bdo\\b" << "\\bdone\\b" << "\\belse\\b"
                    << "\\belseif\\b" << "\\bend\\b" << "\\bexit\\b"
                    << "\\bfor\\b" << "\\bfrom\\b" << "\\bfunc\\b"
                    << "\\bget\\b" << "\\bgive\\b" << "\\bif\\b"
                    << "\\bimport\\b" << "\\bin\\b" << "\\bload\\b"
                    << "\\bloop\\b" << "\\bnew\\b" << "\\bnext\\b"
					<< "\\bnot\\b" << "\\boff\\b" << "\\bok\\b"
					<< "\\bon\\b" << "\\bor\\b" << "\\bother\\b"
					<< "\\bpackage\\b" << "\\bprivate\\b" << "\\bput\\b"
					<< "\\breturn\\b" << "\\bsee\\b" << "\\bstep\\b"
					<< "\\bswitch\\b" << "\\bto\\b" << "\\btry\\b"
					<< "\\bwhile\\b" << "\\bchangeringkeyword\\b"
					<< "\\bchangeringoperator\\b" << "\\bloadsyntax\\b";

    foreach (const QString &pattern, keywordPatterns) {
        rule.pattern = QRegExp(pattern,Qt::CaseInsensitive);
        rule.format = keywordFormat;
        highlightingRules.append(rule);
    }

    if (this->nKeywordsBold)
    	classFormat.setFontWeight(QFont::Bold);
    classFormat.setForeground(c2);
    rule.pattern = QRegExp("\\bQ[A-Za-z]+\\b");
    rule.format = classFormat;
    highlightingRules.append(rule);

    singleLineCommentFormat.setForeground(c3);
    rule.pattern = QRegExp("//[^\n]*");
    rule.format = singleLineCommentFormat;
    highlightingRules.append(rule);

    singleLineCommentFormat.setForeground(c3);
    rule.pattern = QRegExp("#[^\n]*");
    rule.format = singleLineCommentFormat;
    highlightingRules.append(rule);

    multiLineCommentFormat.setForeground(c3);

    quotationFormat.setForeground(c4);
    rule.pattern = QRegExp("\".*\"");
    rule.format = quotationFormat;
    highlightingRules.append(rule);

    functionFormat.setFontItalic(true);
    functionFormat.setForeground(c5);
    rule.pattern = QRegExp("\\b[A-Za-z0-9_]+(?=\\()");
    rule.format = functionFormat;
    highlightingRules.append(rule);

    commentStartExpression = QRegExp("/\\*");
    commentEndExpression = QRegExp("\\*/");

}

void Highlighter::setKeywordsBold(int nStatus) {
	this->nKeywordsBold = nStatus;
}
<commit_msg>Update Ring For Android.<commit_after>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

/*
	File is modified to include Ring Keywords and Ignore the Case
	Updated by : Mahmoud Fayed <msfclipper@yahoo.com>
	Date	    : 2016.09.14
*/

#include "highlighter.h"

Highlighter::Highlighter(QTextDocument *parent)
    : QSyntaxHighlighter(parent)
{
    setColors(Qt::darkBlue,Qt::darkMagenta,Qt::red,Qt::darkGreen,Qt::blue);
}

void Highlighter::highlightBlock(const QString &text)
{

    foreach (const HighlightingRule &rule, highlightingRules) {
        QRegExp expression(rule.pattern);
        int index = expression.indexIn(text);
        while (index >= 0) {
            int length = expression.matchedLength();
            setFormat(index, length, rule.format);
            index = expression.indexIn(text, index + length);
        }
    }
    setCurrentBlockState(0);
    int startIndex = 0;
    if (previousBlockState() != 1)
        startIndex = commentStartExpression.indexIn(text);

    while (startIndex >= 0) {
        int endIndex = commentEndExpression.indexIn(text, startIndex);
        int commentLength;
        if (endIndex == -1) {
            setCurrentBlockState(1);
            commentLength = text.length() - startIndex;
        } else {
            commentLength = endIndex - startIndex
                            + commentEndExpression.matchedLength();
        }
        setFormat(startIndex, commentLength, multiLineCommentFormat);
        startIndex = commentStartExpression.indexIn(text, startIndex + commentLength);
    }
}

void Highlighter::setColors(QColor c1,QColor c2,QColor c3,QColor c4,QColor c5) {

    HighlightingRule rule;
    highlightingRules.remove(0,highlightingRules.count());
    keywordFormat.setForeground(c1);
    if (this->nKeywordsBold)
	    keywordFormat.setFontWeight(QFont::Bold);
    QStringList keywordPatterns;
    keywordPatterns << "\\bagain\\b" << "\\band\\b" << "\\bbut\\b"
                    << "\\bbye\\b" << "\\bcall\\b" << "\\bcase\\b"
                    << "\\bcatch\\b" << "\\bclass\\b" << "\\bdef\\b"
                    << "\\bdo\\b" << "\\bdone\\b" << "\\belse\\b"
                    << "\\belseif\\b" << "\\bend\\b" << "\\bexit\\b"
                    << "\\bfor\\b" << "\\bfrom\\b" << "\\bfunc\\b"
                    << "\\bget\\b" << "\\bgive\\b" << "\\bif\\b"
                    << "\\bimport\\b" << "\\bin\\b" << "\\bload\\b"
                    << "\\bloop\\b" << "\\bnew\\b" << "\\bnext\\b"
					<< "\\bnot\\b" << "\\boff\\b" << "\\bok\\b"
					<< "\\bon\\b" << "\\bor\\b" << "\\bother\\b"
					<< "\\bpackage\\b" << "\\bprivate\\b" << "\\bput\\b"
					<< "\\breturn\\b" << "\\bsee\\b" << "\\bstep\\b"
					<< "\\bswitch\\b" << "\\bto\\b" << "\\btry\\b"
					<< "\\bendfunc\\b" << "\\bendclass\\b" << "\\bendpackage\\b"
					<< "\\bwhile\\b" << "\\bchangeringkeyword\\b"
					<< "\\bchangeringoperator\\b" << "\\bloadsyntax\\b";

    foreach (const QString &pattern, keywordPatterns) {
        rule.pattern = QRegExp(pattern,Qt::CaseInsensitive);
        rule.format = keywordFormat;
        highlightingRules.append(rule);
    }

    if (this->nKeywordsBold)
    	classFormat.setFontWeight(QFont::Bold);
    classFormat.setForeground(c2);
    rule.pattern = QRegExp("\\bQ[A-Za-z]+\\b");
    rule.format = classFormat;
    highlightingRules.append(rule);

    singleLineCommentFormat.setForeground(c3);
    rule.pattern = QRegExp("//[^\n]*");
    rule.format = singleLineCommentFormat;
    highlightingRules.append(rule);

    singleLineCommentFormat.setForeground(c3);
    rule.pattern = QRegExp("#[^\n]*");
    rule.format = singleLineCommentFormat;
    highlightingRules.append(rule);

    multiLineCommentFormat.setForeground(c3);

    quotationFormat.setForeground(c4);
    rule.pattern = QRegExp("\".*\"");
    rule.format = quotationFormat;
    highlightingRules.append(rule);

    functionFormat.setFontItalic(true);
    functionFormat.setForeground(c5);
    rule.pattern = QRegExp("\\b[A-Za-z0-9_]+(?=\\()");
    rule.format = functionFormat;
    highlightingRules.append(rule);

    commentStartExpression = QRegExp("/\\*");
    commentEndExpression = QRegExp("\\*/");

}

void Highlighter::setKeywordsBold(int nStatus) {
	this->nKeywordsBold = nStatus;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** This file is a modified version of part of an example program for Qt.
** This file may be used, distributed and modified without limitation.
**
** Don Sanders <sanders@kde.org>
**
*****************************************************************************/

#include "smtp.h"

#include <qtextstream.h>
#include <qsocket.h>
#include <qtimer.h>
#include <kapp.h>
#include <kmessagebox.h>
#include <klocale.h>

Smtp::Smtp( const QString &from, const QStringList &to,
	    const QString &aMessage,
	    const QString &server,
	    unsigned short int port )
{
    skipReadResponse = false;
    mSocket = new QSocket( this );
    connect ( mSocket, SIGNAL( readyRead() ),
	      this, SLOT( readyRead() ) );
    connect ( mSocket, SIGNAL( connected() ),
	      this, SLOT( connected() ) );
    connect ( mSocket, SIGNAL( error(int) ),
	      this, SLOT( socketError(int) ) );

    message = aMessage;

    this->from = from;
    rcpt = to;
    state = smtpInit;
    command = "";

    emit status( i18n( "Connecting to %1" ).arg( server ) );

    mSocket->connectToHost( server, port );
    t = new QTextStream( mSocket );
    t->setEncoding(QTextCoding::Latin1);
}

Smtp::~Smtp()
{
    if (t)
	delete t;
    if (mSocket)
	delete mSocket;
}

void Smtp::send( const QString &from, const QStringList &to,
	    const QString &aMessage )
{
    skipReadResponse = true;
    message = aMessage;
    this->from = from;
    rcpt = to;

    state = smtpMail;
    command = "";
    readyRead();
}

void Smtp::quit()
{
    skipReadResponse = true;
    state = smtpQuit;
    command = "";
    readyRead();
}

void Smtp::connected()
{
    emit status( i18n( "Connected to %1" ).arg( mSocket->peerName() ) );
}

void Smtp::socketError(int errorCode)
{
    command = "CONNECT";
    switch ( errorCode ) {
        case QSocket::ErrConnectionRefused:
	    responseLine = i18n( "Connection refused." );
	    break;
        case QSocket::ErrHostNotFound:
	    responseLine = i18n( "Host Not Found." );
	    break;
        case QSocket::ErrSocketRead:
	    responseLine = i18n( "Error reading socket." );
	    break;
        default:
	    responseLine = i18n( "Internal error, unrecognized error." );
    }
    QTimer::singleShot( 0, this, SLOT(emitError()) );
}

void Smtp::emitError() {
    error( command, responseLine );
}

void Smtp::readyRead()
{
    if (!skipReadResponse) {
	// SMTP is line-oriented
	if ( !mSocket->canReadLine() )
	    return;

	do {
	    responseLine = mSocket->readLine();
	    response += responseLine;
	} while( mSocket->canReadLine() && responseLine[3] != ' ' );
	responseLine.truncate( 3 );
    }
    skipReadResponse = false;

    if ( state == smtpInit && responseLine[0] == '2' ) {
	// banner was okay, let's go on
	command = "HELO there";
	*t << "HELO there\r\n";
	state = smtpMail;
    } else if ( state == smtpMail && responseLine[0] == '2' ) {
	// HELO response was okay (well, it has to be)
	command = "MAIL";
	*t << "MAIL FROM: <" << from << ">\r\n";
	state = smtpRcpt;
    } else if ( state == smtpRcpt && responseLine[0] == '2' && (rcpt.begin() != rcpt.end())) {
	command = "RCPT";
	*t << "RCPT TO: <" << *(rcpt.begin()) << ">\r\n";
	rcpt.remove( rcpt.begin() );
	if (rcpt.begin() == rcpt.end())
	    state = smtpData;
    } else if ( state == smtpData && responseLine[0] == '2' ) {
	command = "DATA";
	*t << "DATA\r\n";
	state = smtpBody;
    } else if ( state == smtpBody && responseLine[0] == '3' ) {
	command = "DATA";
	QString seperator = "";
	if (message[message.length() - 1] != '\n')
	    seperator = "\r\n";
	*t << message << seperator << ".\r\n";
	state = smtpSuccess;
    } else if ( state == smtpSuccess && responseLine[0] == '2' ) {
	QTimer::singleShot( 0, this, SIGNAL(success()) );
    } else if ( state == smtpQuit && responseLine[0] == '2' ) {
	command = "QUIT";
	*t << "QUIT\r\n";
	// here, we just close.
	state = smtpClose;
	emit status( tr( "Message sent" ) );
    } else if ( state == smtpClose ) {
	// we ignore it
    } else { // error occurred
	QTimer::singleShot( 0, this, SLOT(emitError()) );
	state = smtpClose;
    }

    response = "";

    if ( state == smtpClose ) {
	delete t;
	t = 0;
	delete mSocket;
	mSocket = 0;
	QTimer::singleShot( 0, this, SLOT(deleteMe()) );
    }
}

void Smtp::deleteMe()
{
    delete this;
}

#include "smtp.moc"
<commit_msg>Hi RM, it is nice, if you try to fix bugs in KMail, but it would be even nicer, if you wouldn't break compilation and I had to fix the bugs in your bugfix. -    t->setEncoding(QTextCoding::Latin1); +    t->setEncoding(QTextStream::Latin1);<commit_after>/****************************************************************************
**
** This file is a modified version of part of an example program for Qt.
** This file may be used, distributed and modified without limitation.
**
** Don Sanders <sanders@kde.org>
**
*****************************************************************************/

#include "smtp.h"

#include <qtextstream.h>
#include <qsocket.h>
#include <qtimer.h>
#include <kapp.h>
#include <kmessagebox.h>
#include <klocale.h>

Smtp::Smtp( const QString &from, const QStringList &to,
	    const QString &aMessage,
	    const QString &server,
	    unsigned short int port )
{
    skipReadResponse = false;
    mSocket = new QSocket( this );
    connect ( mSocket, SIGNAL( readyRead() ),
	      this, SLOT( readyRead() ) );
    connect ( mSocket, SIGNAL( connected() ),
	      this, SLOT( connected() ) );
    connect ( mSocket, SIGNAL( error(int) ),
	      this, SLOT( socketError(int) ) );

    message = aMessage;

    this->from = from;
    rcpt = to;
    state = smtpInit;
    command = "";

    emit status( i18n( "Connecting to %1" ).arg( server ) );

    mSocket->connectToHost( server, port );
    t = new QTextStream( mSocket );
    t->setEncoding(QTextStream::Latin1);
}

Smtp::~Smtp()
{
    if (t)
	delete t;
    if (mSocket)
	delete mSocket;
}

void Smtp::send( const QString &from, const QStringList &to,
	    const QString &aMessage )
{
    skipReadResponse = true;
    message = aMessage;
    this->from = from;
    rcpt = to;

    state = smtpMail;
    command = "";
    readyRead();
}

void Smtp::quit()
{
    skipReadResponse = true;
    state = smtpQuit;
    command = "";
    readyRead();
}

void Smtp::connected()
{
    emit status( i18n( "Connected to %1" ).arg( mSocket->peerName() ) );
}

void Smtp::socketError(int errorCode)
{
    command = "CONNECT";
    switch ( errorCode ) {
        case QSocket::ErrConnectionRefused:
	    responseLine = i18n( "Connection refused." );
	    break;
        case QSocket::ErrHostNotFound:
	    responseLine = i18n( "Host Not Found." );
	    break;
        case QSocket::ErrSocketRead:
	    responseLine = i18n( "Error reading socket." );
	    break;
        default:
	    responseLine = i18n( "Internal error, unrecognized error." );
    }
    QTimer::singleShot( 0, this, SLOT(emitError()) );
}

void Smtp::emitError() {
    error( command, responseLine );
}

void Smtp::readyRead()
{
    if (!skipReadResponse) {
	// SMTP is line-oriented
	if ( !mSocket->canReadLine() )
	    return;

	do {
	    responseLine = mSocket->readLine();
	    response += responseLine;
	} while( mSocket->canReadLine() && responseLine[3] != ' ' );
	responseLine.truncate( 3 );
    }
    skipReadResponse = false;

    if ( state == smtpInit && responseLine[0] == '2' ) {
	// banner was okay, let's go on
	command = "HELO there";
	*t << "HELO there\r\n";
	state = smtpMail;
    } else if ( state == smtpMail && responseLine[0] == '2' ) {
	// HELO response was okay (well, it has to be)
	command = "MAIL";
	*t << "MAIL FROM: <" << from << ">\r\n";
	state = smtpRcpt;
    } else if ( state == smtpRcpt && responseLine[0] == '2' && (rcpt.begin() != rcpt.end())) {
	command = "RCPT";
	*t << "RCPT TO: <" << *(rcpt.begin()) << ">\r\n";
	rcpt.remove( rcpt.begin() );
	if (rcpt.begin() == rcpt.end())
	    state = smtpData;
    } else if ( state == smtpData && responseLine[0] == '2' ) {
	command = "DATA";
	*t << "DATA\r\n";
	state = smtpBody;
    } else if ( state == smtpBody && responseLine[0] == '3' ) {
	command = "DATA";
	QString seperator = "";
	if (message[message.length() - 1] != '\n')
	    seperator = "\r\n";
	*t << message << seperator << ".\r\n";
	state = smtpSuccess;
    } else if ( state == smtpSuccess && responseLine[0] == '2' ) {
	QTimer::singleShot( 0, this, SIGNAL(success()) );
    } else if ( state == smtpQuit && responseLine[0] == '2' ) {
	command = "QUIT";
	*t << "QUIT\r\n";
	// here, we just close.
	state = smtpClose;
	emit status( tr( "Message sent" ) );
    } else if ( state == smtpClose ) {
	// we ignore it
    } else { // error occurred
	QTimer::singleShot( 0, this, SLOT(emitError()) );
	state = smtpClose;
    }

    response = "";

    if ( state == smtpClose ) {
	delete t;
	t = 0;
	delete mSocket;
	mSocket = 0;
	QTimer::singleShot( 0, this, SLOT(deleteMe()) );
    }
}

void Smtp::deleteMe()
{
    delete this;
}

#include "smtp.moc"
<|endoftext|>


<commit_before>#include <QDebug>
#include <QList>
#include <QSharedPointer>
#include <QTimer>

#include <QtDBus>
#include <QtTest>

#include <TelepathyQt4/Client/Connection>
#include <TelepathyQt4/Client/Contact>
#include <TelepathyQt4/Client/ContactManager>
#include <TelepathyQt4/Client/PendingContacts>
#include <TelepathyQt4/Client/PendingVoidMethodCall>
#include <TelepathyQt4/Client/ReferencedHandles>
#include <TelepathyQt4/Debug>
#include <TelepathyQt4/Types>

#include <telepathy-glib/debug.h>

#include <tests/lib/contacts-conn.h>
#include <tests/lib/test.h>

using namespace Telepathy::Client;

class TestContacts : public Test
{
    Q_OBJECT

public:
    TestContacts(QObject *parent = 0)
        : Test(parent), mConnService(0), mConn(0)
    {
    }

protected Q_SLOTS:
    void expectConnReady(uint newStatus, uint newStatusReason);
    void expectConnInvalidated();
    void expectPendingContactsFinished(Telepathy::Client::PendingOperation *);

private Q_SLOTS:
    void initTestCase();
    void init();

    void testForHandles();

    void cleanup();
    void cleanupTestCase();

private:
    QString mConnName, mConnPath;
    ContactsConnection *mConnService;
    Connection *mConn;
    QList<QSharedPointer<Contact> > mContacts;
};

void TestContacts::expectConnReady(uint newStatus, uint newStatusReason)
{
    switch (newStatus) {
    case Connection::StatusDisconnected:
        qWarning() << "Disconnected";
        mLoop->exit(1);
        break;
    case Connection::StatusConnecting:
        /* do nothing */
        break;
    case Connection::StatusConnected:
        qDebug() << "Ready";
        mLoop->exit(0);
        break;
    default:
        qWarning().nospace() << "What sort of status is "
            << newStatus << "?!";
        mLoop->exit(2);
        break;
    }
}

void TestContacts::expectConnInvalidated()
{
    mLoop->exit(0);
}

void TestContacts::expectPendingContactsFinished(PendingOperation *op)
{
    if (!op->isFinished()) {
        qWarning() << "unfinished";
        mLoop->exit(1);
        return;
    }

    if (op->isError()) {
        qWarning().nospace() << op->errorName()
            << ": " << op->errorMessage();
        mLoop->exit(2);
        return;
    }

    if (!op->isValid()) {
        qWarning() << "inconsistent results";
        mLoop->exit(3);
        return;
    }

    qDebug() << "finished";
    PendingContacts *pending = qobject_cast<PendingContacts *>(op);
    mContacts = pending->contacts();
    mLoop->exit(0);
}
void TestContacts::initTestCase()
{
    initTestCaseImpl();

    g_type_init();
    g_set_prgname("contacts");
    tp_debug_set_flags("all");

    gchar *name;
    gchar *connPath;
    GError *error = 0;

    mConnService = CONTACTS_CONNECTION(g_object_new(
            CONTACTS_TYPE_CONNECTION,
            "account", "me@example.com",
            "protocol", "simple",
            0));
    QVERIFY(mConnService != 0);
    QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService), "simple", &name,
                &connPath, &error));
    QVERIFY(error == 0);

    QVERIFY(name != 0);
    QVERIFY(connPath != 0);

    mConnName = name;
    mConnPath = connPath;

    g_free(name);
    g_free(connPath);

    mConn = new Connection(mConnName, mConnPath);
    QCOMPARE(mConn->isReady(), false);

    mConn->requestConnect();

    QVERIFY(connect(mConn->becomeReady(),
                SIGNAL(finished(Telepathy::Client::PendingOperation*)),
                SLOT(expectSuccessfulCall(Telepathy::Client::PendingOperation*))));
    QCOMPARE(mLoop->exec(), 0);
    QCOMPARE(mConn->isReady(), true);

    if (mConn->status() != Connection::StatusConnected) {
        QVERIFY(connect(mConn,
                        SIGNAL(statusChanged(uint, uint)),
                        SLOT(expectConnReady(uint, uint))));
        QCOMPARE(mLoop->exec(), 0);
        QVERIFY(disconnect(mConn,
                           SIGNAL(statusChanged(uint, uint)),
                           this,
                           SLOT(expectConnReady(uint, uint))));
        QCOMPARE(mConn->status(), static_cast<uint>(Connection::StatusConnected));
    }
}

void TestContacts::init()
{
    initImpl();
}

void TestContacts::testForHandles()
{
    Telepathy::UIntList handles;
    TpHandleRepoIface *serviceRepo =
        tp_base_connection_get_handles(TP_BASE_CONNECTION(mConnService), TP_HANDLE_TYPE_CONTACT);

    // Set up a few valid handles
    handles << tp_handle_ensure(serviceRepo, "alice", NULL, NULL);
    QVERIFY(handles[0] != 0);
    handles << tp_handle_ensure(serviceRepo, "bob", NULL, NULL);
    QVERIFY(handles[1] != 0);
    // Put one probably invalid one in between
    handles << 31337;
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[2], NULL));
    // Then another valid one
    handles << tp_handle_ensure(serviceRepo, "chris", NULL, NULL);
    QVERIFY(handles[3] != 0);
    // And yet another invalid one
    handles << 12345;
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[4], NULL));

    // Get contacts for the mixture of valid and invalid handles
    PendingContacts *pending = mConn->contactManager()->contactsForHandles(handles);

    // Test the closure accessors
    QCOMPARE(pending->contactManager(), mConn->contactManager());
    QCOMPARE(pending->features(), QSet<Contact::Feature>());

    QVERIFY(pending->isForHandles());
    QVERIFY(!pending->isForIdentifiers());

    QCOMPARE(pending->handles(), handles);

    // Wait for the contacts to be built
    QVERIFY(connect(pending,
                SIGNAL(finished(Telepathy::Client::PendingOperation*)),
                SLOT(expectPendingContactsFinished(Telepathy::Client::PendingOperation*))));
    QCOMPARE(mLoop->exec(), 0);

    // There should be 3 resulting contacts
    QCOMPARE(mContacts.size(), 3);

    QVERIFY(mContacts[0] != NULL);
    QVERIFY(mContacts[1] != NULL);
    QVERIFY(mContacts[2] != NULL);

    QCOMPARE(mContacts[0]->handle()[0], handles[0]);
    QCOMPARE(mContacts[1]->handle()[0], handles[1]);
    QCOMPARE(mContacts[2]->handle()[0], handles[3]);

    QCOMPARE(mContacts[0]->id(), QString("alice"));
    QCOMPARE(mContacts[1]->id(), QString("bob"));
    QCOMPARE(mContacts[2]->id(), QString("chris"));

    // Make the contacts go out of scope, starting releasing their handles, and finish that
    mContacts.clear();
    mLoop->processEvents();
    processDBusQueue(mConn);

    // Unref the handles we created service-side
    tp_handle_unref(serviceRepo, handles[0]);
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[0], NULL));
    tp_handle_unref(serviceRepo, handles[1]);
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[0], NULL));
    tp_handle_unref(serviceRepo, handles[3]);
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[0], NULL));
}

void TestContacts::cleanup()
{
    cleanupImpl();
}

void TestContacts::cleanupTestCase()
{
    if (!mContacts.isEmpty()) {
        mContacts.clear();
    }

    if (mConn) {
        // Disconnect and wait for the readiness change
        QVERIFY(connect(mConn->requestDisconnect(),
                    SIGNAL(finished(Telepathy::Client::PendingOperation*)),
                    SLOT(expectSuccessfulCall(Telepathy::Client::PendingOperation*))));
        QCOMPARE(mLoop->exec(), 0);

        if (mConn->isValid()) {
            QVERIFY(connect(mConn,
                        SIGNAL(invalidated(Telepathy::Client::DBusProxy *, QString, QString)),
                        SLOT(expectConnInvalidated())));
            QCOMPARE(mLoop->exec(), 0);
        }

        delete mConn;
        mConn = 0;
    }

    if (mConnService != 0) {
        g_object_unref(mConnService);
        mConnService = 0;
    }

    cleanupTestCaseImpl();
}

QTEST_MAIN(TestContacts)
#include "_gen/contacts.cpp.moc.hpp"
<commit_msg>Test the Contact::connection() accessor<commit_after>#include <QDebug>
#include <QList>
#include <QSharedPointer>
#include <QTimer>

#include <QtDBus>
#include <QtTest>

#include <TelepathyQt4/Client/Connection>
#include <TelepathyQt4/Client/Contact>
#include <TelepathyQt4/Client/ContactManager>
#include <TelepathyQt4/Client/PendingContacts>
#include <TelepathyQt4/Client/PendingVoidMethodCall>
#include <TelepathyQt4/Client/ReferencedHandles>
#include <TelepathyQt4/Debug>
#include <TelepathyQt4/Types>

#include <telepathy-glib/debug.h>

#include <tests/lib/contacts-conn.h>
#include <tests/lib/test.h>

using namespace Telepathy::Client;

class TestContacts : public Test
{
    Q_OBJECT

public:
    TestContacts(QObject *parent = 0)
        : Test(parent), mConnService(0), mConn(0)
    {
    }

protected Q_SLOTS:
    void expectConnReady(uint newStatus, uint newStatusReason);
    void expectConnInvalidated();
    void expectPendingContactsFinished(Telepathy::Client::PendingOperation *);

private Q_SLOTS:
    void initTestCase();
    void init();

    void testForHandles();

    void cleanup();
    void cleanupTestCase();

private:
    QString mConnName, mConnPath;
    ContactsConnection *mConnService;
    Connection *mConn;
    QList<QSharedPointer<Contact> > mContacts;
};

void TestContacts::expectConnReady(uint newStatus, uint newStatusReason)
{
    switch (newStatus) {
    case Connection::StatusDisconnected:
        qWarning() << "Disconnected";
        mLoop->exit(1);
        break;
    case Connection::StatusConnecting:
        /* do nothing */
        break;
    case Connection::StatusConnected:
        qDebug() << "Ready";
        mLoop->exit(0);
        break;
    default:
        qWarning().nospace() << "What sort of status is "
            << newStatus << "?!";
        mLoop->exit(2);
        break;
    }
}

void TestContacts::expectConnInvalidated()
{
    mLoop->exit(0);
}

void TestContacts::expectPendingContactsFinished(PendingOperation *op)
{
    if (!op->isFinished()) {
        qWarning() << "unfinished";
        mLoop->exit(1);
        return;
    }

    if (op->isError()) {
        qWarning().nospace() << op->errorName()
            << ": " << op->errorMessage();
        mLoop->exit(2);
        return;
    }

    if (!op->isValid()) {
        qWarning() << "inconsistent results";
        mLoop->exit(3);
        return;
    }

    qDebug() << "finished";
    PendingContacts *pending = qobject_cast<PendingContacts *>(op);
    mContacts = pending->contacts();
    mLoop->exit(0);
}
void TestContacts::initTestCase()
{
    initTestCaseImpl();

    g_type_init();
    g_set_prgname("contacts");
    tp_debug_set_flags("all");

    gchar *name;
    gchar *connPath;
    GError *error = 0;

    mConnService = CONTACTS_CONNECTION(g_object_new(
            CONTACTS_TYPE_CONNECTION,
            "account", "me@example.com",
            "protocol", "simple",
            0));
    QVERIFY(mConnService != 0);
    QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService), "simple", &name,
                &connPath, &error));
    QVERIFY(error == 0);

    QVERIFY(name != 0);
    QVERIFY(connPath != 0);

    mConnName = name;
    mConnPath = connPath;

    g_free(name);
    g_free(connPath);

    mConn = new Connection(mConnName, mConnPath);
    QCOMPARE(mConn->isReady(), false);

    mConn->requestConnect();

    QVERIFY(connect(mConn->becomeReady(),
                SIGNAL(finished(Telepathy::Client::PendingOperation*)),
                SLOT(expectSuccessfulCall(Telepathy::Client::PendingOperation*))));
    QCOMPARE(mLoop->exec(), 0);
    QCOMPARE(mConn->isReady(), true);

    if (mConn->status() != Connection::StatusConnected) {
        QVERIFY(connect(mConn,
                        SIGNAL(statusChanged(uint, uint)),
                        SLOT(expectConnReady(uint, uint))));
        QCOMPARE(mLoop->exec(), 0);
        QVERIFY(disconnect(mConn,
                           SIGNAL(statusChanged(uint, uint)),
                           this,
                           SLOT(expectConnReady(uint, uint))));
        QCOMPARE(mConn->status(), static_cast<uint>(Connection::StatusConnected));
    }
}

void TestContacts::init()
{
    initImpl();
}

void TestContacts::testForHandles()
{
    Telepathy::UIntList handles;
    TpHandleRepoIface *serviceRepo =
        tp_base_connection_get_handles(TP_BASE_CONNECTION(mConnService), TP_HANDLE_TYPE_CONTACT);

    // Set up a few valid handles
    handles << tp_handle_ensure(serviceRepo, "alice", NULL, NULL);
    QVERIFY(handles[0] != 0);
    handles << tp_handle_ensure(serviceRepo, "bob", NULL, NULL);
    QVERIFY(handles[1] != 0);
    // Put one probably invalid one in between
    handles << 31337;
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[2], NULL));
    // Then another valid one
    handles << tp_handle_ensure(serviceRepo, "chris", NULL, NULL);
    QVERIFY(handles[3] != 0);
    // And yet another invalid one
    handles << 12345;
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[4], NULL));

    // Get contacts for the mixture of valid and invalid handles
    PendingContacts *pending = mConn->contactManager()->contactsForHandles(handles);

    // Test the closure accessors
    QCOMPARE(pending->contactManager(), mConn->contactManager());
    QCOMPARE(pending->features(), QSet<Contact::Feature>());

    QVERIFY(pending->isForHandles());
    QVERIFY(!pending->isForIdentifiers());

    QCOMPARE(pending->handles(), handles);

    // Wait for the contacts to be built
    QVERIFY(connect(pending,
                SIGNAL(finished(Telepathy::Client::PendingOperation*)),
                SLOT(expectPendingContactsFinished(Telepathy::Client::PendingOperation*))));
    QCOMPARE(mLoop->exec(), 0);

    // There should be 3 resulting contacts
    QCOMPARE(mContacts.size(), 3);

    QVERIFY(mContacts[0] != NULL);
    QVERIFY(mContacts[1] != NULL);
    QVERIFY(mContacts[2] != NULL);

    QCOMPARE(mContacts[0]->connection(), mConn);
    QCOMPARE(mContacts[1]->connection(), mConn);
    QCOMPARE(mContacts[2]->connection(), mConn);

    QCOMPARE(mContacts[0]->handle()[0], handles[0]);
    QCOMPARE(mContacts[1]->handle()[0], handles[1]);
    QCOMPARE(mContacts[2]->handle()[0], handles[3]);

    QCOMPARE(mContacts[0]->id(), QString("alice"));
    QCOMPARE(mContacts[1]->id(), QString("bob"));
    QCOMPARE(mContacts[2]->id(), QString("chris"));

    // Make the contacts go out of scope, starting releasing their handles, and finish that
    mContacts.clear();
    mLoop->processEvents();
    processDBusQueue(mConn);

    // Unref the handles we created service-side
    tp_handle_unref(serviceRepo, handles[0]);
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[0], NULL));
    tp_handle_unref(serviceRepo, handles[1]);
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[0], NULL));
    tp_handle_unref(serviceRepo, handles[3]);
    QVERIFY(!tp_handle_is_valid(serviceRepo, handles[0], NULL));
}

void TestContacts::cleanup()
{
    cleanupImpl();
}

void TestContacts::cleanupTestCase()
{
    if (!mContacts.isEmpty()) {
        mContacts.clear();
    }

    if (mConn) {
        // Disconnect and wait for the readiness change
        QVERIFY(connect(mConn->requestDisconnect(),
                    SIGNAL(finished(Telepathy::Client::PendingOperation*)),
                    SLOT(expectSuccessfulCall(Telepathy::Client::PendingOperation*))));
        QCOMPARE(mLoop->exec(), 0);

        if (mConn->isValid()) {
            QVERIFY(connect(mConn,
                        SIGNAL(invalidated(Telepathy::Client::DBusProxy *, QString, QString)),
                        SLOT(expectConnInvalidated())));
            QCOMPARE(mLoop->exec(), 0);
        }

        delete mConn;
        mConn = 0;
    }

    if (mConnService != 0) {
        g_object_unref(mConnService);
        mConnService = 0;
    }

    cleanupTestCaseImpl();
}

QTEST_MAIN(TestContacts)
#include "_gen/contacts.cpp.moc.hpp"
<|endoftext|>


<commit_before>#include "mmapPerfectHashTable.h"
#include <algorithm>
#include <cerrno>
#include <memory>
#include <string.h>

using namespace std;
using namespace hal;

/* Fixed values to use for hash function generation */
static const size_t DEFAULT_PHF_LAMBDA = 1;  // keys per bucket
static const size_t DEFAULT_PHF_ALPHA = 80;  // load factor
static const phf_seed_t DEFAULT_PHF_SEED = 0;
static const bool DEFAULT_PHF_NODIV = true;

/* get relative offset of displacement map */
size_t hal::MMapPerfectHashTable::displacementMapRelOffset() const {
    return MMapFile::alignRound(sizeof(PerfectHashTableData));
}

/* get relative offset of hash table */
size_t hal::MMapPerfectHashTable::hashTableRelOffset(const struct phf* phf) const {
    return MMapFile::alignRound(sizeof(PerfectHashTableData))
        + MMapFile::alignRound(phf->r * sizeof(uint32_t));
}

/* compute require space for storing hash given contents of _phf */
size_t hal::MMapPerfectHashTable::calcRequiredSpace(const struct phf* phf) const {
    return MMapFile::alignRound(sizeof(PerfectHashTableData))
        + MMapFile::alignRound(phf->r * sizeof(uint32_t))
        + MMapFile::alignRound(phf->m * sizeof(size_t));
}

/* initialize phf object and this object from file */
void hal::MMapPerfectHashTable::readPhf(size_t phtOffset) {
    // FIXME: change this to do only two prefetches by specifying full length
    _phtOffset = phtOffset;
    _data = static_cast<PerfectHashTableData*>(_file->toPtr(phtOffset, _file->alignRound(sizeof(PerfectHashTableData))));
    _phf.nodiv = _data->_phf_nodiv;
    _phf.seed = _data->_phf_seed;
    _phf.r = _data->_phf_r;
    _phf.m = _data->_phf_m;
    _phf.g = static_cast<uint32_t*>(_file->toPtr(_data->_gOffset, _data->_phf_r * sizeof(uint32_t)));
    _phf.d_max = _data->_phf_d_max;
    _phf.g_op = static_cast<enum phf::g_op_t>(_data->_phf_g_op);
    _hashTable = static_cast<hal_index_t*>(_file->toPtr(_data->_hashTableOffset, _data->_phf_m * sizeof(size_t)));
}

/* Write a phf object fields to file */
void hal::MMapPerfectHashTable::writePhf(size_t phtOffset,
                                         struct phf* phf) {
    _data->_phf_nodiv = phf->nodiv;
    _data->_phf_seed = phf->seed;
    _data->_phf_r = phf->r;
    _data->_phf_m = phf->m;
    _data->_phf_d_max = phf->d_max;
    _data->_phf_g_op = phf->g_op;
    _data->_gOffset = phtOffset + displacementMapRelOffset();
    _data->_hashTableOffset = phtOffset + hashTableRelOffset(phf);
    uint32_t* g = static_cast<uint32_t*>(_file->toPtr(_data->_gOffset, _data->_phf_r * sizeof(uint32_t)));
    memcpy(g, phf->g, phf->r * sizeof(uint32_t));

    // initialize hash table to NULL_INDEX
    _hashTable = static_cast<hal_index_t*>(_file->toPtr(_data->_hashTableOffset, _data->_phf_m * sizeof(size_t)));
    uninitialized_fill(_hashTable, _hashTable +  _data->_phf_m, NULL_INDEX);
}

vector<hal_index_t> hal::MMapPerfectHashTable::readExistingIndexes(const vector<string>& existingKeys) const {
    vector<hal_index_t> existingIndexes;
    for (auto const& key: existingKeys) {
        existingIndexes.push_back(getIndex(key));
    }
    return  existingIndexes;
}

void hal::MMapPerfectHashTable::writeExistingIndexes(const vector<string>& existingKeys,
                                                    const vector<hal_index_t>& existingIndexes) {
    for (int i = 0; i < existingKeys.size(); i++) {
        setIndex(existingKeys[i], existingIndexes[i]);
    }
}

/* Initial or reinitialize space in HAL file. Allocate space if needed,
possibly relocating */
void hal::MMapPerfectHashTable::setupSpace(const struct phf *newPhf) {
    size_t currentUsedSpace = 0;
    size_t currentAllocatedSpace = 0;
    if (_data != NULL) {
        currentUsedSpace = calcRequiredSpace(&_phf);
        currentAllocatedSpace = _data->_allocatedSpace;
    }

    // clear current space, even if moving, so unused is always zero.
    if (_data != NULL) {
        memset(_data, 0, currentUsedSpace);
    }

    // allocate new space if needed
    size_t newNeededSpace = calcRequiredSpace(newPhf);
    if ((_data == NULL) || (newNeededSpace > currentAllocatedSpace)) {
        size_t newAllocatedSpace = newNeededSpace + (2 * _growthFactor * newNeededSpace);
        _phtOffset = _file->allocMem(newAllocatedSpace);
        _data = static_cast<hal::PerfectHashTableData*>(_file->toPtr(_phtOffset, newAllocatedSpace));
        _data->_allocatedSpace = newAllocatedSpace;
    } else {
        _data->_allocatedSpace = currentAllocatedSpace;
    }

    _data->_gOffset = displacementMapRelOffset();
    _data->_hashTableOffset = hashTableRelOffset(newPhf);
}

void hal::MMapPerfectHashTable::buildHash(const vector<string>& newKeys,
                                          const vector<string>& existingKeys) {
    vector<string> allKeys;
    std::move(existingKeys.begin(), existingKeys.end(), std::back_inserter(allKeys));
    std::move(newKeys.begin(), newKeys.end(), std::back_inserter(allKeys));

    // build new function in heap
    struct phf newPhf;
    memset(&newPhf, 0, sizeof(newPhf));
    phf_error_t err = PHF::init<string, DEFAULT_PHF_NODIV>(&newPhf, &allKeys[0], allKeys.size(), DEFAULT_PHF_LAMBDA, DEFAULT_PHF_ALPHA, DEFAULT_PHF_SEED);
    if (err != 0) {
        throw hal_exception("can't create perfect hash function: " + string(strerror(err)));
    }
    PHF::compact(&newPhf);

    // store in file
    setupSpace(&newPhf);
    writePhf(_phtOffset, &newPhf);

    // reload cached fields
    readPhf(_phtOffset);
    PHF::destroy(&newPhf);
}

size_t hal::MMapPerfectHashTable::addKeys(const vector<string>& newKeys,
                                          const vector<string>& existingKeys) {
    vector<hal_index_t> existingIndexes = readExistingIndexes(existingKeys);
    buildHash(newKeys, existingKeys);
    writeExistingIndexes(existingKeys, existingIndexes);
    return _phtOffset;
}
<commit_msg>Fix a bug in my PHF memcpy bug fix<commit_after>#include "mmapPerfectHashTable.h"
#include <algorithm>
#include <cerrno>
#include <memory>
#include <string.h>

using namespace std;
using namespace hal;

/* Fixed values to use for hash function generation */
static const size_t DEFAULT_PHF_LAMBDA = 1;  // keys per bucket
static const size_t DEFAULT_PHF_ALPHA = 80;  // load factor
static const phf_seed_t DEFAULT_PHF_SEED = 0;
static const bool DEFAULT_PHF_NODIV = true;

/* get relative offset of displacement map */
size_t hal::MMapPerfectHashTable::displacementMapRelOffset() const {
    return MMapFile::alignRound(sizeof(PerfectHashTableData));
}

/* get relative offset of hash table */
size_t hal::MMapPerfectHashTable::hashTableRelOffset(const struct phf* phf) const {
    return MMapFile::alignRound(sizeof(PerfectHashTableData))
        + MMapFile::alignRound(phf->r * sizeof(uint32_t));
}

/* compute require space for storing hash given contents of _phf */
size_t hal::MMapPerfectHashTable::calcRequiredSpace(const struct phf* phf) const {
    return MMapFile::alignRound(sizeof(PerfectHashTableData))
        + MMapFile::alignRound(phf->r * sizeof(uint32_t))
        + MMapFile::alignRound(phf->m * sizeof(size_t));
}

/* initialize phf object and this object from file */
void hal::MMapPerfectHashTable::readPhf(size_t phtOffset) {
    // FIXME: change this to do only two prefetches by specifying full length
    _phtOffset = phtOffset;
    _data = static_cast<PerfectHashTableData*>(_file->toPtr(phtOffset, _file->alignRound(sizeof(PerfectHashTableData))));
    _phf.nodiv = _data->_phf_nodiv;
    _phf.seed = _data->_phf_seed;
    _phf.r = _data->_phf_r;
    _phf.m = _data->_phf_m;
    _phf.g = static_cast<uint32_t*>(_file->toPtr(_data->_gOffset, _data->_phf_r * sizeof(uint32_t)));
    _phf.d_max = _data->_phf_d_max;
    _phf.g_op = static_cast<enum phf::g_op_t>(_data->_phf_g_op);
    _hashTable = static_cast<hal_index_t*>(_file->toPtr(_data->_hashTableOffset, _data->_phf_m * sizeof(size_t)));
}

/* Write a phf object fields to file */
void hal::MMapPerfectHashTable::writePhf(size_t phtOffset,
                                         struct phf* phf) {
    _data->_phf_nodiv = phf->nodiv;
    _data->_phf_seed = phf->seed;
    _data->_phf_r = phf->r;
    _data->_phf_m = phf->m;
    _data->_phf_d_max = phf->d_max;
    _data->_phf_g_op = phf->g_op;
    _data->_gOffset = phtOffset + displacementMapRelOffset();
    _data->_hashTableOffset = phtOffset + hashTableRelOffset(phf);

    // Calculate the size of the allocated region (the element size is
    // different under different conditions). Keep in sync with
    // PHF::compact().
    size_t size = _data->_phf_r;
    if (_data->_phf_d_max <= 255) {
        size *= sizeof(uint8_t);
    } else if (_data->_phf_d_max <= 65535) {
        size *= sizeof(uint16_t);
    } else {
        size *= sizeof(uint32_t);
    }

    uint32_t* g = static_cast<uint32_t*>(_file->toPtr(_data->_gOffset, size));
    memcpy(g, phf->g, size);

    // initialize hash table to NULL_INDEX
    _hashTable = static_cast<hal_index_t*>(_file->toPtr(_data->_hashTableOffset, _data->_phf_m * sizeof(size_t)));
    uninitialized_fill(_hashTable, _hashTable +  _data->_phf_m, NULL_INDEX);
}

vector<hal_index_t> hal::MMapPerfectHashTable::readExistingIndexes(const vector<string>& existingKeys) const {
    vector<hal_index_t> existingIndexes;
    for (auto const& key: existingKeys) {
        existingIndexes.push_back(getIndex(key));
    }
    return  existingIndexes;
}

void hal::MMapPerfectHashTable::writeExistingIndexes(const vector<string>& existingKeys,
                                                    const vector<hal_index_t>& existingIndexes) {
    for (int i = 0; i < existingKeys.size(); i++) {
        setIndex(existingKeys[i], existingIndexes[i]);
    }
}

/* Initial or reinitialize space in HAL file. Allocate space if needed,
possibly relocating */
void hal::MMapPerfectHashTable::setupSpace(const struct phf *newPhf) {
    size_t currentUsedSpace = 0;
    size_t currentAllocatedSpace = 0;
    if (_data != NULL) {
        currentUsedSpace = calcRequiredSpace(&_phf);
        currentAllocatedSpace = _data->_allocatedSpace;
    }

    // clear current space, even if moving, so unused is always zero.
    if (_data != NULL) {
        memset(_data, 0, currentUsedSpace);
    }

    // allocate new space if needed
    size_t newNeededSpace = calcRequiredSpace(newPhf);
    if ((_data == NULL) || (newNeededSpace > currentAllocatedSpace)) {
        size_t newAllocatedSpace = newNeededSpace + (2 * _growthFactor * newNeededSpace);
        _phtOffset = _file->allocMem(newAllocatedSpace);
        _data = static_cast<hal::PerfectHashTableData*>(_file->toPtr(_phtOffset, newAllocatedSpace));
        _data->_allocatedSpace = newAllocatedSpace;
    } else {
        _data->_allocatedSpace = currentAllocatedSpace;
    }

    _data->_gOffset = displacementMapRelOffset();
    _data->_hashTableOffset = hashTableRelOffset(newPhf);
}

void hal::MMapPerfectHashTable::buildHash(const vector<string>& newKeys,
                                          const vector<string>& existingKeys) {
    vector<string> allKeys;
    std::move(existingKeys.begin(), existingKeys.end(), std::back_inserter(allKeys));
    std::move(newKeys.begin(), newKeys.end(), std::back_inserter(allKeys));

    // build new function in heap
    struct phf newPhf;
    memset(&newPhf, 0, sizeof(newPhf));
    phf_error_t err = PHF::init<string, DEFAULT_PHF_NODIV>(&newPhf, &allKeys[0], allKeys.size(), DEFAULT_PHF_LAMBDA, DEFAULT_PHF_ALPHA, DEFAULT_PHF_SEED);
    if (err != 0) {
        throw hal_exception("can't create perfect hash function: " + string(strerror(err)));
    }
    PHF::compact(&newPhf);

    // store in file
    setupSpace(&newPhf);
    writePhf(_phtOffset, &newPhf);

    // reload cached fields
    readPhf(_phtOffset);
    PHF::destroy(&newPhf);
}

size_t hal::MMapPerfectHashTable::addKeys(const vector<string>& newKeys,
                                          const vector<string>& existingKeys) {
    vector<hal_index_t> existingIndexes = readExistingIndexes(existingKeys);
    buildHash(newKeys, existingKeys);
    writeExistingIndexes(existingKeys, existingIndexes);
    return _phtOffset;
}
<|endoftext|>


<commit_before>#include <iostream>
#include "../src/Trie.h"

using namespace std;

int main() {
  Trie* trie = new Trie();
  trie->add("asparagus");
  trie->add("aspen");
  cout << "This should be true: " << (trie->search("asparagus") != 0) << endl;
  cout << "This should be false: " << trie->search("aaragus") << endl;
  cout << "This should be false: " << trie->search("asparaguse") << endl;
  cout << "This should be false: " << trie->search("asparagu") << endl;
  cout << "Removal should be false: " << trie->remove("asparagu") << endl;
  cout << "Removal should be true: " << trie->remove("asparagus") << endl;
  cout << "This should now be false: " << (trie->search("asparagus") != 0) << endl;
}
<commit_msg>Add aspen truth test<commit_after>#include <iostream>
#include "../src/Trie.h"

using namespace std;

int main() {
  Trie* trie = new Trie();
  trie->add("asparagus");
  trie->add("aspen");
  cout << "This should be true: " << (trie->search("asparagus") != 0) << endl;
  cout << "This should be true: " << (trie->search("aspen") != 0) << endl;
  cout << "This should be false: " << trie->search("aaragus") << endl;
  cout << "This should be false: " << trie->search("asparaguse") << endl;
  cout << "This should be false: " << trie->search("asparagu") << endl;
  cout << "Removal should be false: " << trie->remove("asparagu") << endl;
  cout << "Removal should be true: " << trie->remove("asparagus") << endl;
  cout << "This should now be false: " << (trie->search("asparagus") != 0) << endl;
}
<|endoftext|>