<commit_before>// Copyright (c) 2011 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 "base/file_path.h"
#include "base/file_util.h"
#include "base/test/test_timeouts.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_layout_test.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/net_util.h"

static const char* kRootFiles[] = {
  "clear.html",
//  "complex-keys.html",  // Output too big for a cookie.  crbug.com/33472
//  "complex-values.html",  // crbug.com/33472
  "quota.html",
  "remove-item.html",
  "window-attributes-exist.html",
  NULL
};

static const char* kEventsFiles[] = {
//  "basic-body-attribute.html",  // crbug.com/33472
//  "basic.html",  // crbug.com/33472
//  "basic-setattribute.html",  // crbug.com/33472
  "case-sensitive.html",
  "documentURI.html",
  NULL
};

static const char* kStorageFiles[] = {
  "delete-removal.html",
  "enumerate-storage.html",
  "enumerate-with-length-and-key.html",
  "index-get-and-set.html",
  "simple-usage.html",
  "string-conversion.html",
//  "window-open.html", // TODO(jorlow): Fix
  NULL
};

class DOMStorageTest : public UILayoutTest {
 protected:
  DOMStorageTest()
      : UILayoutTest(),
        test_dir_(FilePath().
                  AppendASCII("storage").AppendASCII("domstorage")) {
  }

  virtual ~DOMStorageTest() { }

  virtual void SetUp() {
    launch_arguments_.AppendSwitch(switches::kDisablePopupBlocking);
    UILayoutTest::SetUp();
  }

  // We require fast/js/resources for most of the DOM Storage layout tests.
  // Add those to the list to be copied.
  void AddJSTestResources() {
    // Add other paths our tests require.
    FilePath js_dir = FilePath().
                      AppendASCII("fast").AppendASCII("js");
    AddResourceForLayoutTest(js_dir, FilePath().AppendASCII("resources"));
  }

  // This is somewhat of a hack because we're running a real browser that
  // actually persists the LocalStorage state vs. DRT and TestShell which don't.
  // The correct fix is to fix the LayoutTests, but similar patches have been
  // rejected in the past.
  void ClearDOMStorage() {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());

    const FilePath dir(FILE_PATH_LITERAL("layout_tests"));
    const FilePath file(FILE_PATH_LITERAL("clear_dom_storage.html"));
    GURL url = ui_test_utils::GetTestUrl(dir, file);
    ASSERT_TRUE(tab->SetCookie(url, ""));
    ASSERT_TRUE(tab->NavigateToURL(url));

    WaitUntilCookieNonEmpty(tab.get(), url, "cleared",
                            TestTimeouts::action_max_timeout_ms());
  }

  // Runs each test in an array of strings until it hits a NULL.
  void RunTests(const char** files) {
    while (*files) {
      ClearDOMStorage();
      RunLayoutTest(*files, kNoHttpPort);
      ++files;
    }
  }

  FilePath test_dir_;
};

TEST_F(DOMStorageTest, RootLayoutTests) {
  InitializeForLayoutTest(test_dir_, FilePath(), kNoHttpPort);
  AddJSTestResources();
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("script-tests"));
  RunTests(kRootFiles);
}

TEST_F(DOMStorageTest, EventLayoutTests) {
  InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("events"),
                          kNoHttpPort);
  AddJSTestResources();
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("events").
                                      AppendASCII("resources"));
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("events").
                                      AppendASCII("script-tests"));
  RunTests(kEventsFiles);
}

TEST_F(DOMStorageTest, LocalStorageLayoutTests) {
  InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("localstorage"),
                          kNoHttpPort);
  AddJSTestResources();
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("localstorage").
                                      AppendASCII("resources"));
  RunTests(kStorageFiles);
}

TEST_F(DOMStorageTest, SessionStorageLayoutTests) {
  InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("sessionstorage"),
                          kNoHttpPort);
  AddJSTestResources();
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("sessionstorage").
                                      AppendASCII("resources"));
  RunTests(kStorageFiles);
}

class DomStorageEmptyDatabaseTest : public UITest {
 protected:
  FilePath StorageDir() const {
    FilePath storage_dir = user_data_dir();
    storage_dir = storage_dir.AppendASCII("Default");
    storage_dir = storage_dir.AppendASCII("Local Storage");
    return storage_dir;
  }

  bool StorageDirIsEmpty() const {
    FilePath storage_dir = StorageDir();
    if (!file_util::DirectoryExists(storage_dir))
      return true;
    return file_util::IsDirectoryEmpty(storage_dir);
  }

  GURL TestUrl() const {
    FilePath test_dir = test_data_directory_;
    FilePath test_file = test_dir.AppendASCII("dom_storage_empty_db.html");
    return net::FilePathToFileURL(test_file);
  }
};

// Fails, see http://crbug.com/76008
TEST_F(DomStorageEmptyDatabaseTest, FAILS_EmptyDirAfterClear) {
  NavigateToURL(TestUrl());
  ASSERT_TRUE(StorageDirIsEmpty());

  NavigateToURL(GURL("javascript:set()"));
  NavigateToURL(GURL("javascript:clear()"));
  QuitBrowser();
  EXPECT_TRUE(StorageDirIsEmpty());
}

TEST_F(DomStorageEmptyDatabaseTest, EmptyDirAfterGet) {
  NavigateToURL(TestUrl());
  ASSERT_TRUE(StorageDirIsEmpty());

  NavigateToURL(GURL("javascript:get()"));
  QuitBrowser();
  EXPECT_TRUE(StorageDirIsEmpty());
}

// Flaky, see http://crbug.com/73776
TEST_F(DomStorageEmptyDatabaseTest, FLAKY_NonEmptyDirAfterSet) {
  NavigateToURL(TestUrl());
  ASSERT_TRUE(StorageDirIsEmpty());

  NavigateToURL(GURL("javascript:set()"));
  QuitBrowser();
  EXPECT_FALSE(StorageDirIsEmpty());

  LaunchBrowserAndServer();
  NavigateToURL(TestUrl());
  NavigateToURL(GURL("javascript:clear()"));
  QuitBrowser();
  EXPECT_TRUE(StorageDirIsEmpty());
}
<commit_msg>Remove "FAILS" from DomStorageEmptyDatabaseTest.EmptyDirAfterClear.<commit_after>// Copyright (c) 2011 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 "base/file_path.h"
#include "base/file_util.h"
#include "base/test/test_timeouts.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_layout_test.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/net_util.h"

static const char* kRootFiles[] = {
  "clear.html",
//  "complex-keys.html",  // Output too big for a cookie.  crbug.com/33472
//  "complex-values.html",  // crbug.com/33472
  "quota.html",
  "remove-item.html",
  "window-attributes-exist.html",
  NULL
};

static const char* kEventsFiles[] = {
//  "basic-body-attribute.html",  // crbug.com/33472
//  "basic.html",  // crbug.com/33472
//  "basic-setattribute.html",  // crbug.com/33472
  "case-sensitive.html",
  "documentURI.html",
  NULL
};

static const char* kStorageFiles[] = {
  "delete-removal.html",
  "enumerate-storage.html",
  "enumerate-with-length-and-key.html",
  "index-get-and-set.html",
  "simple-usage.html",
  "string-conversion.html",
//  "window-open.html", // TODO(jorlow): Fix
  NULL
};

class DOMStorageTest : public UILayoutTest {
 protected:
  DOMStorageTest()
      : UILayoutTest(),
        test_dir_(FilePath().
                  AppendASCII("storage").AppendASCII("domstorage")) {
  }

  virtual ~DOMStorageTest() { }

  virtual void SetUp() {
    launch_arguments_.AppendSwitch(switches::kDisablePopupBlocking);
    UILayoutTest::SetUp();
  }

  // We require fast/js/resources for most of the DOM Storage layout tests.
  // Add those to the list to be copied.
  void AddJSTestResources() {
    // Add other paths our tests require.
    FilePath js_dir = FilePath().
                      AppendASCII("fast").AppendASCII("js");
    AddResourceForLayoutTest(js_dir, FilePath().AppendASCII("resources"));
  }

  // This is somewhat of a hack because we're running a real browser that
  // actually persists the LocalStorage state vs. DRT and TestShell which don't.
  // The correct fix is to fix the LayoutTests, but similar patches have been
  // rejected in the past.
  void ClearDOMStorage() {
    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_TRUE(tab.get());

    const FilePath dir(FILE_PATH_LITERAL("layout_tests"));
    const FilePath file(FILE_PATH_LITERAL("clear_dom_storage.html"));
    GURL url = ui_test_utils::GetTestUrl(dir, file);
    ASSERT_TRUE(tab->SetCookie(url, ""));
    ASSERT_TRUE(tab->NavigateToURL(url));

    WaitUntilCookieNonEmpty(tab.get(), url, "cleared",
                            TestTimeouts::action_max_timeout_ms());
  }

  // Runs each test in an array of strings until it hits a NULL.
  void RunTests(const char** files) {
    while (*files) {
      ClearDOMStorage();
      RunLayoutTest(*files, kNoHttpPort);
      ++files;
    }
  }

  FilePath test_dir_;
};

TEST_F(DOMStorageTest, RootLayoutTests) {
  InitializeForLayoutTest(test_dir_, FilePath(), kNoHttpPort);
  AddJSTestResources();
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("script-tests"));
  RunTests(kRootFiles);
}

TEST_F(DOMStorageTest, EventLayoutTests) {
  InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("events"),
                          kNoHttpPort);
  AddJSTestResources();
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("events").
                                      AppendASCII("resources"));
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("events").
                                      AppendASCII("script-tests"));
  RunTests(kEventsFiles);
}

TEST_F(DOMStorageTest, LocalStorageLayoutTests) {
  InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("localstorage"),
                          kNoHttpPort);
  AddJSTestResources();
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("localstorage").
                                      AppendASCII("resources"));
  RunTests(kStorageFiles);
}

TEST_F(DOMStorageTest, SessionStorageLayoutTests) {
  InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("sessionstorage"),
                          kNoHttpPort);
  AddJSTestResources();
  AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("sessionstorage").
                                      AppendASCII("resources"));
  RunTests(kStorageFiles);
}

class DomStorageEmptyDatabaseTest : public UITest {
 protected:
  FilePath StorageDir() const {
    FilePath storage_dir = user_data_dir();
    storage_dir = storage_dir.AppendASCII("Default");
    storage_dir = storage_dir.AppendASCII("Local Storage");
    return storage_dir;
  }

  bool StorageDirIsEmpty() const {
    FilePath storage_dir = StorageDir();
    if (!file_util::DirectoryExists(storage_dir))
      return true;
    return file_util::IsDirectoryEmpty(storage_dir);
  }

  GURL TestUrl() const {
    FilePath test_dir = test_data_directory_;
    FilePath test_file = test_dir.AppendASCII("dom_storage_empty_db.html");
    return net::FilePathToFileURL(test_file);
  }
};

TEST_F(DomStorageEmptyDatabaseTest, EmptyDirAfterClear) {
  NavigateToURL(TestUrl());
  ASSERT_TRUE(StorageDirIsEmpty());

  NavigateToURL(GURL("javascript:set()"));
  NavigateToURL(GURL("javascript:clear()"));
  QuitBrowser();
  EXPECT_TRUE(StorageDirIsEmpty());
}

TEST_F(DomStorageEmptyDatabaseTest, EmptyDirAfterGet) {
  NavigateToURL(TestUrl());
  ASSERT_TRUE(StorageDirIsEmpty());

  NavigateToURL(GURL("javascript:get()"));
  QuitBrowser();
  EXPECT_TRUE(StorageDirIsEmpty());
}

// Flaky, see http://crbug.com/73776
TEST_F(DomStorageEmptyDatabaseTest, FLAKY_NonEmptyDirAfterSet) {
  NavigateToURL(TestUrl());
  ASSERT_TRUE(StorageDirIsEmpty());

  NavigateToURL(GURL("javascript:set()"));
  QuitBrowser();
  EXPECT_FALSE(StorageDirIsEmpty());

  LaunchBrowserAndServer();
  NavigateToURL(TestUrl());
  NavigateToURL(GURL("javascript:clear()"));
  QuitBrowser();
  EXPECT_TRUE(StorageDirIsEmpty());
}
<|endoftext|>


<commit_before>/*
 *   Copyright (C) 2011 Ivan Cukic <ivan.cukic(at)kde.org>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License version 2,
 *   or (at your option) any later version, as published by the Free
 *   Software Foundation
 *
 *   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, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "Documents.h"
#include "Documents_p.h"
#include "rankingsclientadaptor.h"

#include <QList>
#include <QDBusConnection>
#include <QDesktopServices>

#include <Nepomuk/Resource>
#include <Nepomuk/Variant>

#include <KDebug>
#include <KUrl>
#include <KFileItem>

#include "nfo.h"
#include "nie.h"
#include "kext.h"

#define KAMD_DBUS_ADDRESS "org.kde.kactivitymanagerd"

using namespace Nepomuk::Vocabulary;

// Private

DocumentsEnginePrivate::DocumentsEnginePrivate(DocumentsEngine * parent)
    : q(parent)
{
    activitymanager = new KActivities::Consumer(this);

    QDBusConnection dbus = QDBusConnection::sessionBus();

    // Making us visible on d-bus
    new RankingsClientAdaptor(this);
    // kDebug() << "registering the client" <<
    dbus.registerObject("/RankingsClient", this);

    if (dbus.interface()->isServiceRegistered(KAMD_DBUS_ADDRESS)) {
        serviceOnline();
    }

    QDBusServiceWatcher * watcher = new QDBusServiceWatcher(
            KAMD_DBUS_ADDRESS, dbus,
            QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration,
            this
        );
    connect(watcher, SIGNAL(serviceRegistered(QString)),
            this, SLOT(serviceOnline()));
    connect(watcher, SIGNAL(serviceUnregistered(QString)),
            this, SLOT(serviceOffline()));
}

void DocumentsEnginePrivate::serviceOnline()
{
    kDebug() << KAMD_DBUS_ADDRESS << "went online";

    QDBusInterface rankingsservice(KAMD_DBUS_ADDRESS,
            "/Rankings", "org.kde.ActivityManager.Rankings");

    rankingsservice.asyncCall("registerClient", "org.kde.Contour", QString(), "nao:Document");
}

void DocumentsEnginePrivate::serviceOffline()
{
    kDebug() << KAMD_DBUS_ADDRESS << "went offline";

    q->recommendationsUpdated(QList<Contour::RecommendationItem>());
}

DocumentsEnginePrivate::~DocumentsEnginePrivate()
{
}

void DocumentsEnginePrivate::updated(const QVariantList & data)
{
    kDebug() << "@@@@@@@@@@@@@@@@@@" << data;
    recommendations.clear();

    double score = 1.0;

    foreach (const QVariant & item, data) {
        Nepomuk::Resource resource(KUrl(item.toString()));

        // The problem is when the resource has no particular type set (web page)
        // if (!resource.hasType(Nepomuk::Vocabulary::NFO::FileDataObject())) continue;

        Nepomuk::Resource currentActivityResource(activitymanager->currentActivity(), KEXT::Activity());

        // TODO: See ActivityManager.coo
        // I'd like a resource isRelated activity more than vice-versa
        // but the active models are checking for the other way round.
        // It is defined in the ontologies as a symmetric relation, but
        // Nepomuk doesn't care about that.

        // if (resource.isRelateds().contains(currentActivityResource)) continue;
        if (currentActivityResource.isRelateds().contains(resource)) continue;

        Contour::RecommendationItem recommendation;

        recommendation.score       = score;
        recommendation.id          = item.toString();
        score /= 2;

        recommendation.title       = resource.genericLabel();
        recommendation.description = i18n("Open and add to the current activity");
        recommendation.icon        = resource.genericIcon();

        if (recommendation.icon.isEmpty()) {
            KFileItem fileItem(KFileItem::Unknown, KFileItem::Unknown,
                    KUrl(resource.property(Nepomuk::Vocabulary::NIE::url()).toString()));
            recommendation.icon = fileItem.iconName();
        }

        kDebug() << recommendation;

        recommendations << recommendation;

        if (recommendations.size() >= 10) break;

    }

    q->recommendationsUpdated(recommendations);

}

void DocumentsEnginePrivate::removeRecommendation(const QString & id)
{
    for (int i = 0; i < recommendations.size(); i++) {
        if (recommendations[i].id == id) {
            recommendations.removeAt(i);
            break;
        }
    }
}

void DocumentsEnginePrivate::inserted(int position, const QVariantList & item)
{
}

void DocumentsEnginePrivate::removed(int position)
{
}

void DocumentsEnginePrivate::changed(int position, const QVariantList & item)
{
}

// DocumentsEngine

DocumentsEngine::DocumentsEngine(QObject * parent, const QVariantList & args)
    : Contour::RecommendationEngine(parent), d(new DocumentsEnginePrivate(this))
{
}

DocumentsEngine::~DocumentsEngine()
{
    delete d;
}

void DocumentsEngine::init()
{
    Contour::RecommendationEngine::init();

    emit recommendationsUpdated(d->recommendations);
}

void DocumentsEngine::activate(const QString & id, const QString & action)
{
    KUrl url(id);

    d->removeRecommendation(id);

    d->activitymanager->linkResourceToActivity(url);

    QDesktopServices::openUrl(url);

}

RECOMMENDATION_EXPORT_PLUGIN(DocumentsEngine, "contour_recommendationengine_documents")

<commit_msg>Removing selected recommendation<commit_after>/*
 *   Copyright (C) 2011 Ivan Cukic <ivan.cukic(at)kde.org>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License version 2,
 *   or (at your option) any later version, as published by the Free
 *   Software Foundation
 *
 *   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, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "Documents.h"
#include "Documents_p.h"
#include "rankingsclientadaptor.h"

#include <QList>
#include <QDBusConnection>
#include <QDesktopServices>

#include <Nepomuk/Resource>
#include <Nepomuk/Variant>

#include <KDebug>
#include <KUrl>
#include <KFileItem>

#include "nfo.h"
#include "nie.h"
#include "kext.h"

#define KAMD_DBUS_ADDRESS "org.kde.kactivitymanagerd"

using namespace Nepomuk::Vocabulary;

// Private

DocumentsEnginePrivate::DocumentsEnginePrivate(DocumentsEngine * parent)
    : q(parent)
{
    activitymanager = new KActivities::Consumer(this);

    QDBusConnection dbus = QDBusConnection::sessionBus();

    // Making us visible on d-bus
    new RankingsClientAdaptor(this);
    // kDebug() << "registering the client" <<
    dbus.registerObject("/RankingsClient", this);

    if (dbus.interface()->isServiceRegistered(KAMD_DBUS_ADDRESS)) {
        serviceOnline();
    }

    QDBusServiceWatcher * watcher = new QDBusServiceWatcher(
            KAMD_DBUS_ADDRESS, dbus,
            QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration,
            this
        );
    connect(watcher, SIGNAL(serviceRegistered(QString)),
            this, SLOT(serviceOnline()));
    connect(watcher, SIGNAL(serviceUnregistered(QString)),
            this, SLOT(serviceOffline()));
}

void DocumentsEnginePrivate::serviceOnline()
{
    kDebug() << KAMD_DBUS_ADDRESS << "went online";

    QDBusInterface rankingsservice(KAMD_DBUS_ADDRESS,
            "/Rankings", "org.kde.ActivityManager.Rankings");

    rankingsservice.asyncCall("registerClient", "org.kde.Contour", QString(), "nao:Document");
}

void DocumentsEnginePrivate::serviceOffline()
{
    kDebug() << KAMD_DBUS_ADDRESS << "went offline";

    q->recommendationsUpdated(QList<Contour::RecommendationItem>());
}

DocumentsEnginePrivate::~DocumentsEnginePrivate()
{
}

void DocumentsEnginePrivate::updated(const QVariantList & data)
{
    kDebug() << "@@@@@@@@@@@@@@@@@@" << data;
    recommendations.clear();

    double score = 1.0;

    foreach (const QVariant & item, data) {
        Nepomuk::Resource resource(KUrl(item.toString()));

        // The problem is when the resource has no particular type set (web page)
        // if (!resource.hasType(Nepomuk::Vocabulary::NFO::FileDataObject())) continue;

        Nepomuk::Resource currentActivityResource(activitymanager->currentActivity(), KEXT::Activity());

        // TODO: See ActivityManager.coo
        // I'd like a resource isRelated activity more than vice-versa
        // but the active models are checking for the other way round.
        // It is defined in the ontologies as a symmetric relation, but
        // Nepomuk doesn't care about that.

        // if (resource.isRelateds().contains(currentActivityResource)) continue;
        if (currentActivityResource.isRelateds().contains(resource)) continue;

        Contour::RecommendationItem recommendation;

        recommendation.score       = score;
        recommendation.id          = item.toString();
        score /= 2;

        recommendation.title       = resource.genericLabel();
        recommendation.description = i18n("Open and add to the current activity");
        recommendation.icon        = resource.genericIcon();

        if (recommendation.icon.isEmpty()) {
            KFileItem fileItem(KFileItem::Unknown, KFileItem::Unknown,
                    KUrl(resource.property(Nepomuk::Vocabulary::NIE::url()).toString()));
            recommendation.icon = fileItem.iconName();
        }

        kDebug()
            << "score:" << recommendation.score
            << "id:" << recommendation.id
            << "title:" << recommendation.title
            << "description:" << recommendation.description
            ;

        recommendations << recommendation;

        if (recommendations.size() >= 10) break;

    }

    q->recommendationsUpdated(recommendations);

}

void DocumentsEnginePrivate::removeRecommendation(const QString & id)
{
    // kDebug() << "removing" << id;

    for (int i = 0; i < recommendations.size(); i++) {
        if (recommendations[i].id == id) {
            // kDebug() << "before removal:" << recommendations;
            recommendations.removeAt(i);
            // kDebug() << "after removal:" << recommendations;
            break;
        }
    }
}

void DocumentsEnginePrivate::inserted(int position, const QVariantList & item)
{
}

void DocumentsEnginePrivate::removed(int position)
{
}

void DocumentsEnginePrivate::changed(int position, const QVariantList & item)
{
}

// DocumentsEngine

DocumentsEngine::DocumentsEngine(QObject * parent, const QVariantList & args)
    : Contour::RecommendationEngine(parent), d(new DocumentsEnginePrivate(this))
{
}

DocumentsEngine::~DocumentsEngine()
{
    delete d;
}

void DocumentsEngine::init()
{
    Contour::RecommendationEngine::init();

    emit recommendationsUpdated(d->recommendations);
}

void DocumentsEngine::activate(const QString & id, const QString & action)
{
    KUrl url(id);

    d->removeRecommendation(id);

    d->activitymanager->linkResourceToActivity(url);

    QDesktopServices::openUrl(url);

    recommendationsUpdated(d->recommendations);
}

RECOMMENDATION_EXPORT_PLUGIN(DocumentsEngine, "contour_recommendationengine_documents")

<|endoftext|>


<commit_before>#include <mos/gfx/assets.hpp>
#include <cstring>
#include <filesystem/path.h>
#include <fstream>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/io.hpp>
#include <glm/gtx/matrix_decompose.hpp>
#include <mos/util.hpp>
#include <iostream>

namespace mos {
namespace gfx {
using namespace nlohmann;

Assets::Assets(const std::string directory) : directory_(directory) {}

Assets::~Assets() {}

Model Assets::model_value(const std::string &base_path, const json &value, const glm::mat4 &parent_transform) {
  auto name = value.value("name", "");
  auto mesh_name = std::string("");
  if (!value["mesh"].is_null()) {
    mesh_name = value.value("mesh", "");
  }
  std::string material_name = "";
  if (!value["material"].is_null()) {
    material_name = value.value("material", "");
  }

  auto transform = parent_transform * jsonarray_to_mat4(value["transform"]);

  auto created_model = Model(
      name, mesh(base_path + mesh_name),
      transform,
      material(base_path + material_name));

  for (auto &m : value["children"]) {
    filesystem::path t = std::string(m);
    if(t.extension() == "model") {
      created_model.models.push_back(model(base_path + t.str()));
    }
  }
  return created_model;
}

Model Assets::model(const std::string &path, const glm::mat4 &parent_transform) {
  std::cout << "Loading: " << path << std::endl;
  filesystem::path fpath = path;
  auto doc = json::parse(mos::text(directory_ + path));

  return model_value(fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/", doc, parent_transform);
}

Animation Assets::animation(const std::string &path) {
  auto doc = json::parse(mos::text(directory_ + path));
  auto frame_rate = doc["frame_rate"];
  std::map<unsigned int, std::shared_ptr<Mesh const>> keyframes;

  for (auto &keyframe : doc["keyframes"]) {
    auto key = keyframe["key"];
    auto mesh_path = keyframe["mesh"];
    keyframes.insert({key, mesh(mesh_path)});
  }
  Animation animation(keyframes, frame_rate);
  return animation;
}

std::shared_ptr<Mesh> Assets::mesh(const std::string &path) {
  if (meshes_.find(path) == meshes_.end()) {
    meshes_.insert(MeshPair(path, Mesh::load(directory_ + path)));
  }
  return meshes_.at(path);
}

std::shared_ptr<Texture2D>
Assets::texture(const std::string &path,
                      const bool color_data,
                      const bool mipmaps,
                      const Texture2D::Wrap &wrap) {
  if (!path.empty()) {
    if (textures_.find(path) == textures_.end()) {
      textures_.insert(TexturePair(path, Texture2D::load(directory_ + path, color_data, mipmaps, wrap)));
    }
    return textures_.at(path);
  } else {
    return std::shared_ptr<Texture2D>(nullptr);
  }
}

Material Assets::material(const std::string &path) {
  if (path.empty()) {
    return Material();
  } else {
    filesystem::path fpath = path;
    auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

    if (fpath.extension() == "material") {
      auto value = json::parse(mos::text(directory_ + fpath.str()));

      auto read_texture = [&](const std::string &name, const bool color_data = true) {
        std::string file_name = "";
        if (!value[name].is_null()) {
          file_name = value[name];
        }
        auto tex = file_name.empty() ? texture("") : texture(base_path + file_name, color_data);
        return tex;
      };

      auto albedo_map = read_texture("albedo_map");
      auto emission_map = read_texture("emission_map");
      auto normal_map = read_texture("normal_map");
      if (normal_map) {
        if (normal_map->format == Texture::Format::SRGB){
          normal_map->format = Texture::Format::RGB;
        }
        else if (normal_map->format == Texture::Format::SRGBA){
          normal_map->format = Texture::Format::RGBA;
        }
        //normal_map->format = normal_map->format == Texture::Format::SRGB ? Texture::Format::RGB : Texture::Format::RGBA;
      }
      auto metallic_map = read_texture("metallic_map");
      auto roughness_map = read_texture("roughness_map");
      auto ambient_occlusion_map = read_texture("ambient_occlusion_map");

      auto diffuse = glm::vec3(value["albedo"][0], value["albedo"][1], value["albedo"][2]);
      auto opacity = value["opacity"];
      auto roughness = value["roughness"];
      auto metallic = value["metallic"];
      auto emission = glm::vec3(value["emission"][0], value["emission"][1], value["emission"][2]);
      auto ambient_occlusion = value["ambient_occlusion"];
      return Material(albedo_map,
                      emission_map,
                      normal_map,
                      metallic_map,
                      roughness_map,
                      ambient_occlusion_map,
                      diffuse,
                      opacity,
                      roughness,
                      metallic,
                      emission);
    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}

Light Assets::light(const std::string &path, const glm::mat4 &parent_transform) {
  if (path.empty()) {
    return Light();
  } else {
    filesystem::path fpath = path;
    auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

    if (fpath.extension() == "light") {
      auto value = json::parse(mos::text(directory_ + fpath.str()));

      auto transform = parent_transform * jsonarray_to_mat4(value["transform"]);
      auto position = glm::vec3(transform[3]);
      auto center = position + glm::vec3(transform * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));

	  std::string t = value["light"];
      auto data_value = json::parse(mos::text(directory_ + t));

      auto color = glm::vec3(data_value["color"][0],
                             data_value["color"][1],
                             data_value["color"][2]);
      auto strength = data_value["strength"];
      auto size = data_value["size"];
      auto blend = value["blend"];

      return Light(position,
                      center,
                      size,
                      color,
                      strength);
    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}

EnvironmentLight Assets::environment_light(const std::string &path, const glm::mat4 &parent_transform) {
  filesystem::path fpath = path;
  auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

  if (fpath.extension() == "environment_light") {
    auto value = json::parse(mos::text(directory_ + fpath.str()));

    auto transform = parent_transform * jsonarray_to_mat4(value["transform"]);

    auto position = glm::vec3(transform[3]);

    glm::vec3 scale;
    glm::quat rotation;
    glm::vec3 translation;
    glm::vec3 skew;
    glm::vec4 perspective;
    glm::decompose(transform, scale, rotation, translation, skew, perspective);

    auto extent = float(value["extent"]) * scale;
    auto strength = value.value("strength", 1.0f);
    auto resolution = value.value("resolution", 128.0f);

    return EnvironmentLight(position,
                 extent,
                 strength);
  } else {
    throw std::runtime_error(path.substr(path.find_last_of(".")) +
        " file format is not supported.");
  }
}

void Assets::clear_unused() {
  for (auto it = textures_.begin(); it != textures_.end();) {
    if (it->second.use_count() <= 1) {
      textures_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = meshes_.begin(); it != meshes_.end();) {
    if (it->second.use_count() <= 1) {
      meshes_.erase(it++);
    } else {
      ++it;
    }
  }
}
std::string Assets::directory() const {
  return directory_;
}

}
}
<commit_msg>Nullptr<commit_after>#include <mos/gfx/assets.hpp>
#include <cstring>
#include <filesystem/path.h>
#include <fstream>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/io.hpp>
#include <glm/gtx/matrix_decompose.hpp>
#include <mos/util.hpp>
#include <iostream>

namespace mos {
namespace gfx {
using namespace nlohmann;

Assets::Assets(const std::string directory) : directory_(directory) {}

Assets::~Assets() {}

Model Assets::model_value(const std::string &base_path, const json &value, const glm::mat4 &parent_transform) {
  auto name = value.value("name", "");
  auto mesh_name = std::string("");
  if (!value["mesh"].is_null()) {
    mesh_name = value.value("mesh", "");
  }
  std::string material_name = "";
  if (!value["material"].is_null()) {
    material_name = value.value("material", "");
  }

  auto transform = parent_transform * jsonarray_to_mat4(value["transform"]);

  auto created_model = Model(
      name, mesh(base_path + mesh_name),
      transform,
      material(base_path + material_name));

  for (auto &m : value["children"]) {
    filesystem::path t = std::string(m);
    if(t.extension() == "model") {
      created_model.models.push_back(model(base_path + t.str()));
    }
  }
  return created_model;
}

Model Assets::model(const std::string &path, const glm::mat4 &parent_transform) {
  std::cout << "Loading: " << path << std::endl;
  filesystem::path fpath = path;
  auto doc = json::parse(mos::text(directory_ + path));

  return model_value(fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/", doc, parent_transform);
}

Animation Assets::animation(const std::string &path) {
  auto doc = json::parse(mos::text(directory_ + path));
  auto frame_rate = doc["frame_rate"];
  std::map<unsigned int, std::shared_ptr<Mesh const>> keyframes;

  for (auto &keyframe : doc["keyframes"]) {
    auto key = keyframe["key"];
    auto mesh_path = keyframe["mesh"];
    keyframes.insert({key, mesh(mesh_path)});
  }
  Animation animation(keyframes, frame_rate);
  return animation;
}

std::shared_ptr<Mesh> Assets::mesh(const std::string &path) {
  if (path.empty()){
    return SharedMesh(nullptr);
  }
  if (meshes_.find(path) == meshes_.end()) {
    meshes_.insert(MeshPair(path, Mesh::load(directory_ + path)));
  }
  return meshes_.at(path);
}

std::shared_ptr<Texture2D>
Assets::texture(const std::string &path,
                      const bool color_data,
                      const bool mipmaps,
                      const Texture2D::Wrap &wrap) {
  if (!path.empty()) {
    if (textures_.find(path) == textures_.end()) {
      textures_.insert(TexturePair(path, Texture2D::load(directory_ + path, color_data, mipmaps, wrap)));
    }
    return textures_.at(path);
  } else {
    return SharedTexture2D(nullptr);
  }
}

Material Assets::material(const std::string &path) {
  if (path.empty()) {
    return Material();
  } else {
    filesystem::path fpath = path;
    auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

    if (fpath.extension() == "material") {
      auto value = json::parse(mos::text(directory_ + fpath.str()));

      auto read_texture = [&](const std::string &name, const bool color_data = true) {
        std::string file_name = "";
        if (!value[name].is_null()) {
          file_name = value[name];
        }
        auto tex = file_name.empty() ? texture("") : texture(base_path + file_name, color_data);
        return tex;
      };

      auto albedo_map = read_texture("albedo_map");
      auto emission_map = read_texture("emission_map");
      auto normal_map = read_texture("normal_map");
      if (normal_map) {
        if (normal_map->format == Texture::Format::SRGB){
          normal_map->format = Texture::Format::RGB;
        }
        else if (normal_map->format == Texture::Format::SRGBA){
          normal_map->format = Texture::Format::RGBA;
        }
        //normal_map->format = normal_map->format == Texture::Format::SRGB ? Texture::Format::RGB : Texture::Format::RGBA;
      }
      auto metallic_map = read_texture("metallic_map");
      auto roughness_map = read_texture("roughness_map");
      auto ambient_occlusion_map = read_texture("ambient_occlusion_map");

      auto diffuse = glm::vec3(value["albedo"][0], value["albedo"][1], value["albedo"][2]);
      auto opacity = value["opacity"];
      auto roughness = value["roughness"];
      auto metallic = value["metallic"];
      auto emission = glm::vec3(value["emission"][0], value["emission"][1], value["emission"][2]);
      auto ambient_occlusion = value["ambient_occlusion"];
      return Material(albedo_map,
                      emission_map,
                      normal_map,
                      metallic_map,
                      roughness_map,
                      ambient_occlusion_map,
                      diffuse,
                      opacity,
                      roughness,
                      metallic,
                      emission);
    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}

Light Assets::light(const std::string &path, const glm::mat4 &parent_transform) {
  if (path.empty()) {
    return Light();
  } else {
    filesystem::path fpath = path;
    auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

    if (fpath.extension() == "light") {
      auto value = json::parse(mos::text(directory_ + fpath.str()));

      auto transform = parent_transform * jsonarray_to_mat4(value["transform"]);
      auto position = glm::vec3(transform[3]);
      auto center = position + glm::vec3(transform * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));

	  std::string t = value["light"];
      auto data_value = json::parse(mos::text(directory_ + t));

      auto color = glm::vec3(data_value["color"][0],
                             data_value["color"][1],
                             data_value["color"][2]);
      auto strength = data_value["strength"];
      auto size = data_value["size"];
      auto blend = value["blend"];

      return Light(position,
                      center,
                      size,
                      color,
                      strength);
    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}

EnvironmentLight Assets::environment_light(const std::string &path, const glm::mat4 &parent_transform) {
  filesystem::path fpath = path;
  auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

  if (fpath.extension() == "environment_light") {
    auto value = json::parse(mos::text(directory_ + fpath.str()));

    auto transform = parent_transform * jsonarray_to_mat4(value["transform"]);

    auto position = glm::vec3(transform[3]);

    glm::vec3 scale;
    glm::quat rotation;
    glm::vec3 translation;
    glm::vec3 skew;
    glm::vec4 perspective;
    glm::decompose(transform, scale, rotation, translation, skew, perspective);

    auto extent = float(value["extent"]) * scale;
    auto strength = value.value("strength", 1.0f);
    auto resolution = value.value("resolution", 128.0f);

    return EnvironmentLight(position,
                 extent,
                 strength);
  } else {
    throw std::runtime_error(path.substr(path.find_last_of(".")) +
        " file format is not supported.");
  }
}

void Assets::clear_unused() {
  for (auto it = textures_.begin(); it != textures_.end();) {
    if (it->second.use_count() <= 1) {
      textures_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = meshes_.begin(); it != meshes_.end();) {
    if (it->second.use_count() <= 1) {
      meshes_.erase(it++);
    } else {
      ++it;
    }
  }
}
std::string Assets::directory() const {
  return directory_;
}

}
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <memory>
#include <thread>

#include "VisitorUtils.hpp"
#include "Options.hpp"
#include "PerfsTimer.hpp"
#include "iterators.hpp"
#include "likely.hpp"
#include "logging.hpp"

#include "mtac/Utils.hpp"
#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/Printer.hpp"
#include "mtac/TemporaryAllocator.hpp"

//The custom optimizations
#include "mtac/VariableOptimizations.hpp"
#include "mtac/FunctionOptimizations.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/BasicBlockOptimizations.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/ConcatReduction.hpp"
#include "mtac/inlining.hpp"
#include "mtac/loop_optimizations.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/RemoveAssign.hpp"
#include "mtac/RemoveMultipleAssign.hpp"
#include "mtac/MathPropagation.hpp"
#include "mtac/PointerPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

using namespace eddic;

namespace {

const unsigned int MAX_THREADS = 2;

template<typename Visitor>
bool apply_to_all(std::shared_ptr<mtac::Function> function){
    Visitor visitor;

    mtac::visit_all_statements(visitor, function);

    return visitor.optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks_two_pass(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visitor.pass = mtac::Pass::DATA_MINING;

        visit_each(visitor, block->statements);

        visitor.pass = mtac::Pass::OPTIMIZE;

        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Problem, typename... Args>
bool data_flow_optimization(std::shared_ptr<mtac::Function> function, Args... args){
    bool optimized = false;

    Problem problem(args...);

    auto results = mtac::data_flow(function, problem);

    //Once the data-flow problem is fixed, statements can be optimized
    for(auto& block : function->getBasicBlocks()){
        for(auto& statement : block->statements){
            optimized |= problem.optimize(statement, results);
        }
    }

    return optimized;
}

bool debug(const std::string& name, bool b, std::shared_ptr<mtac::Function> function){
    if(log::enabled<Debug>()){
        if(b){
            log::emit<Debug>("Optimizer") << "Optimization" << name << " returned true" << log::endl;

            //Print the function
            print(function);
        } else {
            log::emit<Debug>("Optimizer") << "Optimization" << name << " returned false" << log::endl;
        }
    }

    return b;
}

template<typename Functor, typename... Args>
bool debug(const std::string& name, Functor functor, std::shared_ptr<mtac::Function> function, Args... args){
    bool b;
    {
        PerfsTimer timer(name);

        b = functor(function, args...);
    }

    return debug(name, b, function);
}

void remove_nop(std::shared_ptr<mtac::Function> function){
    for(auto& block : function->getBasicBlocks()){
        auto it = iterate(block->statements);

        while(it.has_next()){
            if(unlikely(boost::get<std::shared_ptr<mtac::NoOp>>(&*it))){
                it.erase();
                continue;
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&*it)){
                if((*ptr)->op == mtac::Operator::NOP){
                    it.erase();
                    continue;
                }
            }

            ++it;
        }
    }
}

void optimize_function(std::shared_ptr<mtac::Function> function, std::shared_ptr<StringPool> pool, Platform platform){
    if(log::enabled<Debug>()){
        log::emit<Debug>("Optimizer") << "Start optimizations on " << function->getName() << log::endl;

        print(function);
    }

    bool optimized;
    do {
        optimized = false;

        optimized |= debug("Aritmetic Identities", &apply_to_all<mtac::ArithmeticIdentities>, function);
        optimized |= debug("Reduce in Strength", &apply_to_all<mtac::ReduceInStrength>, function);
        optimized |= debug("Constant folding", &apply_to_all<mtac::ConstantFolding>, function);

        optimized |= debug("Constant propagation", &data_flow_optimization<mtac::ConstantPropagationProblem>, function);
        optimized |= debug("Offset Constant Propagation", &data_flow_optimization<mtac::OffsetConstantPropagationProblem, std::shared_ptr<StringPool>, Platform>, function, pool, platform);

        //If there was optimizations here, better to try again before perfoming common subexpression
        if(optimized){
            continue;
        }

        optimized |= debug("Common Subexpression Elimination", &data_flow_optimization<mtac::CommonSubexpressionElimination>, function);

        optimized |= debug("Pointer Propagation", &apply_to_basic_blocks<mtac::PointerPropagation>, function);
        optimized |= debug("Math Propagation", &apply_to_basic_blocks_two_pass<mtac::MathPropagation>, function);

        optimized |= debug("Optimize Branches", &mtac::optimize_branches, function);
        optimized |= debug("Optimize Concat", &mtac::optimize_concat, function, pool);
        optimized |= debug("Remove dead basic block", &mtac::remove_dead_basic_blocks, function);
        optimized |= debug("Merge basic block", &mtac::merge_basic_blocks, function);

        remove_nop(function);
        optimized |= debug("Dead-Code Elimination", &mtac::dead_code_elimination, function);

        optimized |= debug("Remove aliases", &mtac::remove_aliases, function);

        optimized |= debug("Loop Invariant Code Motion", &mtac::loop_invariant_code_motion, function);
    } while (optimized);

    //Remove variables that are not used after optimizations
    clean_variables(function);
}

void basic_optimize_function(std::shared_ptr<mtac::Function> function){
    if(log::enabled<Debug>()){
        log::emit<Debug>("Optimizer") << "Start basic optimizations on " << function->getName() << log::endl;

        print(function);
    }

    debug("Constant folding", apply_to_all<mtac::ConstantFolding>(function), function);
}

void optimize_all_functions(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration){
    PerfsTimer timer("Whole optimizations");

    auto& functions = program->functions;

    if(configuration->option_defined("dev")){
        for(auto& function : functions){
            optimize_function(function, string_pool, platform);
        }
    } else {
        //Find a better heuristic to configure the number of threads
        std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

        std::vector<std::thread> pool;
        for(std::size_t tid = 0; tid < threads; ++tid){
            pool.push_back(std::thread([tid, threads, &string_pool, platform, &functions](){
                std::size_t i = tid;

                while(i < functions.size()){
                    optimize_function(functions[i], string_pool, platform);

                    i += threads;
                }
            }));
        }

        //Wait for all the threads to finish
        std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
    }
}

} //end of anonymous namespace

void mtac::Optimizer::optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration) const {
    //Allocate storage for the temporaries that need to be stored
    allocate_temporary(program, platform);

    if(configuration->option_defined("fglobal-optimization")){
        bool optimized = false;
        do{
            mtac::remove_unused_functions(program);

            optimize_all_functions(program, string_pool, platform, configuration);

            optimized = mtac::remove_empty_functions(program);
            optimized = mtac::inline_functions(program, configuration);
        } while(optimized);
    } else {
        //Even if global optimizations are disabled, perform basic optimization (only constant folding)
        basic_optimize(program, string_pool, configuration);
    }

    //Allocate storage for the temporaries that need to be stored
    allocate_temporary(program, platform);
}

void mtac::Optimizer::basic_optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> /*string_pool*/, std::shared_ptr<Configuration> configuration) const {
    PerfsTimer timer("Whole basic optimizations");

    auto& functions = program->functions;

    if(configuration->option_defined("dev")){
        for(auto& function : functions){
            basic_optimize_function(function);
        }
    } else {
        //Find a better heuristic to configure the number of threads
        std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

        std::vector<std::thread> pool;
        for(std::size_t tid = 0; tid < threads; ++tid){
            pool.push_back(std::thread([tid, threads, &functions](){
                std::size_t i = tid;

                while(i < functions.size()){
                    basic_optimize_function(functions[i]);

                    i += threads;
                }
            }));
        }

        //Wait for all the threads to finish
        std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
    }
}
<commit_msg>Activate loop strength reduction<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <memory>
#include <thread>

#include "VisitorUtils.hpp"
#include "Options.hpp"
#include "PerfsTimer.hpp"
#include "iterators.hpp"
#include "likely.hpp"
#include "logging.hpp"

#include "mtac/Utils.hpp"
#include "mtac/Pass.hpp"
#include "mtac/Optimizer.hpp"
#include "mtac/Program.hpp"
#include "mtac/Printer.hpp"
#include "mtac/TemporaryAllocator.hpp"

//The custom optimizations
#include "mtac/VariableOptimizations.hpp"
#include "mtac/FunctionOptimizations.hpp"
#include "mtac/DeadCodeElimination.hpp"
#include "mtac/BasicBlockOptimizations.hpp"
#include "mtac/BranchOptimizations.hpp"
#include "mtac/ConcatReduction.hpp"
#include "mtac/inlining.hpp"
#include "mtac/loop_optimizations.hpp"

//The optimization visitors
#include "mtac/ArithmeticIdentities.hpp"
#include "mtac/ReduceInStrength.hpp"
#include "mtac/ConstantFolding.hpp"
#include "mtac/RemoveAssign.hpp"
#include "mtac/RemoveMultipleAssign.hpp"
#include "mtac/MathPropagation.hpp"
#include "mtac/PointerPropagation.hpp"

//The data-flow problems
#include "mtac/GlobalOptimizations.hpp"
#include "mtac/ConstantPropagationProblem.hpp"
#include "mtac/OffsetConstantPropagationProblem.hpp"
#include "mtac/CommonSubexpressionElimination.hpp"

using namespace eddic;

namespace {

const unsigned int MAX_THREADS = 2;

template<typename Visitor>
bool apply_to_all(std::shared_ptr<mtac::Function> function){
    Visitor visitor;

    mtac::visit_all_statements(visitor, function);

    return visitor.optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Visitor>
bool apply_to_basic_blocks_two_pass(std::shared_ptr<mtac::Function> function){
    bool optimized = false;

    for(auto& block : function->getBasicBlocks()){
        Visitor visitor;
        visitor.pass = mtac::Pass::DATA_MINING;

        visit_each(visitor, block->statements);

        visitor.pass = mtac::Pass::OPTIMIZE;

        visit_each(visitor, block->statements);

        optimized |= visitor.optimized;
    }

    return optimized;
}

template<typename Problem, typename... Args>
bool data_flow_optimization(std::shared_ptr<mtac::Function> function, Args... args){
    bool optimized = false;

    Problem problem(args...);

    auto results = mtac::data_flow(function, problem);

    //Once the data-flow problem is fixed, statements can be optimized
    for(auto& block : function->getBasicBlocks()){
        for(auto& statement : block->statements){
            optimized |= problem.optimize(statement, results);
        }
    }

    return optimized;
}

bool debug(const std::string& name, bool b, std::shared_ptr<mtac::Function> function){
    if(log::enabled<Debug>()){
        if(b){
            log::emit<Debug>("Optimizer") << "Optimization" << name << " returned true" << log::endl;

            //Print the function
            print(function);
        } else {
            log::emit<Debug>("Optimizer") << "Optimization" << name << " returned false" << log::endl;
        }
    }

    return b;
}

template<typename Functor, typename... Args>
bool debug(const std::string& name, Functor functor, std::shared_ptr<mtac::Function> function, Args... args){
    bool b;
    {
        PerfsTimer timer(name);

        b = functor(function, args...);
    }

    return debug(name, b, function);
}

void remove_nop(std::shared_ptr<mtac::Function> function){
    for(auto& block : function->getBasicBlocks()){
        auto it = iterate(block->statements);

        while(it.has_next()){
            if(unlikely(boost::get<std::shared_ptr<mtac::NoOp>>(&*it))){
                it.erase();
                continue;
            } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&*it)){
                if((*ptr)->op == mtac::Operator::NOP){
                    it.erase();
                    continue;
                }
            }

            ++it;
        }
    }
}

void optimize_function(std::shared_ptr<mtac::Function> function, std::shared_ptr<StringPool> pool, Platform platform){
    if(log::enabled<Debug>()){
        log::emit<Debug>("Optimizer") << "Start optimizations on " << function->getName() << log::endl;

        print(function);
    }

    bool optimized;
    do {
        optimized = false;

        optimized |= debug("Aritmetic Identities", &apply_to_all<mtac::ArithmeticIdentities>, function);
        optimized |= debug("Reduce in Strength", &apply_to_all<mtac::ReduceInStrength>, function);
        optimized |= debug("Constant folding", &apply_to_all<mtac::ConstantFolding>, function);

        optimized |= debug("Constant propagation", &data_flow_optimization<mtac::ConstantPropagationProblem>, function);
        optimized |= debug("Offset Constant Propagation", &data_flow_optimization<mtac::OffsetConstantPropagationProblem, std::shared_ptr<StringPool>, Platform>, function, pool, platform);

        //If there was optimizations here, better to try again before perfoming common subexpression
        if(optimized){
            continue;
        }

        optimized |= debug("Common Subexpression Elimination", &data_flow_optimization<mtac::CommonSubexpressionElimination>, function);

        optimized |= debug("Pointer Propagation", &apply_to_basic_blocks<mtac::PointerPropagation>, function);
        optimized |= debug("Math Propagation", &apply_to_basic_blocks_two_pass<mtac::MathPropagation>, function);

        optimized |= debug("Optimize Branches", &mtac::optimize_branches, function);
        optimized |= debug("Optimize Concat", &mtac::optimize_concat, function, pool);
        optimized |= debug("Remove dead basic block", &mtac::remove_dead_basic_blocks, function);
        optimized |= debug("Merge basic block", &mtac::merge_basic_blocks, function);

        remove_nop(function);
        optimized |= debug("Dead-Code Elimination", &mtac::dead_code_elimination, function);

        optimized |= debug("Remove aliases", &mtac::remove_aliases, function);

        optimized |= debug("Loop Invariant Code Motion", &mtac::loop_invariant_code_motion, function);
        optimized |= debug("Loop Strength Reduction", &mtac::loop_strength_reduction, function);
    } while (optimized);

    //Remove variables that are not used after optimizations
    clean_variables(function);
}

void basic_optimize_function(std::shared_ptr<mtac::Function> function){
    if(log::enabled<Debug>()){
        log::emit<Debug>("Optimizer") << "Start basic optimizations on " << function->getName() << log::endl;

        print(function);
    }

    debug("Constant folding", apply_to_all<mtac::ConstantFolding>(function), function);
}

void optimize_all_functions(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration){
    PerfsTimer timer("Whole optimizations");

    auto& functions = program->functions;

    if(configuration->option_defined("dev")){
        for(auto& function : functions){
            optimize_function(function, string_pool, platform);
        }
    } else {
        //Find a better heuristic to configure the number of threads
        std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

        std::vector<std::thread> pool;
        for(std::size_t tid = 0; tid < threads; ++tid){
            pool.push_back(std::thread([tid, threads, &string_pool, platform, &functions](){
                std::size_t i = tid;

                while(i < functions.size()){
                    optimize_function(functions[i], string_pool, platform);

                    i += threads;
                }
            }));
        }

        //Wait for all the threads to finish
        std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
    }
}

} //end of anonymous namespace

void mtac::Optimizer::optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> string_pool, Platform platform, std::shared_ptr<Configuration> configuration) const {
    //Allocate storage for the temporaries that need to be stored
    allocate_temporary(program, platform);

    if(configuration->option_defined("fglobal-optimization")){
        bool optimized = false;
        do{
            mtac::remove_unused_functions(program);

            optimize_all_functions(program, string_pool, platform, configuration);

            optimized = mtac::remove_empty_functions(program);
            optimized = mtac::inline_functions(program, configuration);
        } while(optimized);
    } else {
        //Even if global optimizations are disabled, perform basic optimization (only constant folding)
        basic_optimize(program, string_pool, configuration);
    }

    //Allocate storage for the temporaries that need to be stored
    allocate_temporary(program, platform);
}

void mtac::Optimizer::basic_optimize(std::shared_ptr<mtac::Program> program, std::shared_ptr<StringPool> /*string_pool*/, std::shared_ptr<Configuration> configuration) const {
    PerfsTimer timer("Whole basic optimizations");

    auto& functions = program->functions;

    if(configuration->option_defined("dev")){
        for(auto& function : functions){
            basic_optimize_function(function);
        }
    } else {
        //Find a better heuristic to configure the number of threads
        std::size_t threads = std::min(functions.size(), static_cast<std::size_t>(MAX_THREADS));

        std::vector<std::thread> pool;
        for(std::size_t tid = 0; tid < threads; ++tid){
            pool.push_back(std::thread([tid, threads, &functions](){
                std::size_t i = tid;

                while(i < functions.size()){
                    basic_optimize_function(functions[i]);

                    i += threads;
                }
            }));
        }

        //Wait for all the threads to finish
        std::for_each(pool.begin(), pool.end(), [](std::thread& thread){thread.join();});
    }
}
<|endoftext|>


<commit_before><commit_msg>Fan spinning wrong way<commit_after><|endoftext|>


<commit_before>/************************************************************************
*
* Flood Project  (2008-201x)
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/

#pragma once

#include "Engine/API.h"
#include "Engine/Texture/TextureAtlas.h"

NAMESPACE_ENGINE_BEGIN

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

static const MaxRectsBinPack::FreeRectChoiceHeuristic gs_heuristic =
             MaxRectsBinPack::FreeRectChoiceHeuristic::RectBestAreaFit;

TextureAtlas::TextureAtlas(uint maxSize)
{
    atlasMaxSize = maxSize;
    atlasSize = std::min(maxSize, DefaultSize);
    rectanglePacker.Init(atlasSize,atlasSize);
    atlasImageHandle = ImageCreate(AllocatorGetHeap(),atlasSize,atlasSize,PixelFormat::R8G8B8A8);
}

static const int RBLOCK = 96;

// We use this function to rotate images in-place since sometimes
// the packing algorithm will rotate the image to have a better fit.
static void RotateImage(Image* srcImage, Image* dstImage, Vector2i dstOffset)
{
    assert(srcImage->getPixelFormat() == dstImage->getPixelFormat());

    int bpp = srcImage->getPixelSize();

    int srcWidth = srcImage->getWidth();
    int srcHeight = srcImage->getHeight();
    int dstWidth = srcHeight;
    int dstHeight = srcWidth;

    // get src and dst scan width
    int srcPitch  = srcWidth*bpp;
    int dstPitch  = dstImage->getWidth()*bpp;

    byte* bsrc = srcImage->getBuffer().data();
    byte* bdst = dstImage->getBuffer().data();

    for(int xs = 0; xs < dstWidth; xs += RBLOCK) {    // for all image blocks of RBLOCK*RBLOCK pixels
        for(int ys = 0; ys < dstHeight; ys += RBLOCK) {
            for(int y = ys; y < std::min(dstHeight, ys + RBLOCK); y++) {    // do rotation
                int y2 = dstHeight - y - 1;
                // point to src pixel at (y2, xs)
                byte* src_bits = bsrc + (xs * srcPitch) + (y2 * bpp);
                // point to dst pixel at (xs, y)
                byte* dst_bits = bdst + (( y + dstOffset.y) * dstPitch) + ((xs + dstOffset.x) * bpp);
                for (int x = xs; x < std::min(dstWidth, xs + RBLOCK); x++) {
                    // dst.SetPixel(x, y, src.GetPixel(y2, x));
                    for(int j = 0; j < bpp; j++) {
                        dst_bits[j] = src_bits[j];
                    }
                    dst_bits += bpp;
                    src_bits += srcPitch;
                }
            }
        }
    }
}

bool TextureAtlas::addImage(const ImageHandle& newImageHandle)
{
    if(imageSubTextures.find( newImageHandle ) != imageSubTextures.end())
        return true;

    Image* newImage = newImageHandle.Resolve();

    Rect newRect = rectanglePacker.Insert(newImage->getWidth(), newImage->getHeight(), gs_heuristic);

    if (newRect.height == 0 || newRect.width == 0){
        if (atlasSize >= atlasMaxSize)
            return false;

        atlasSize = std::min(atlasSize*2, atlasMaxSize);
        resizeAtlas(atlasSize);

        return addImage(newImageHandle);
    }

    addImage(newImageHandle,newRect);

    return true;
}

bool TextureAtlas::getImageSubTexture(const ImageHandle& imageHandle, SubTexture& subTexture)
{
    if(imageSubTextures.find( imageHandle ) == imageSubTextures.end())
        return false;

    subTexture = imageSubTextures[imageHandle];
    return true;
}

ImageHandle TextureAtlas::getAtlasImageHandle() const
{
    return atlasImageHandle;
}

void TextureAtlas::resizeAtlas(uint newSize)
{
    rectanglePacker.Init(newSize,newSize);

    std::vector<Vector2i> rectSizes;
    std::vector<Rect> newRects;

    Image* atlasImage = atlasImageHandle.Resolve();

    std::map<ImageHandle, SubTexture>::iterator iter;
    for (iter = imageSubTextures.begin(); iter != imageSubTextures.end(); ++iter) {
        Vector2i rectSize;
        int width = (iter->second.rightBottomUV.x - iter->second.leftTopUV.x)*width;
        int height = (iter->second.rightBottomUV.y - iter->second.leftTopUV.y)*height;
        rectSize.x = width;
        rectSize.y = height;
        rectSizes.push_back(rectSize);
    }

    rectanglePacker.Insert(rectSizes, newRects, gs_heuristic);

    assert(newRects.size() == imageSubTextures.size());

    int i;
    for (i = 0, iter = imageSubTextures.begin(); iter != imageSubTextures.end(); ++iter, ++i)
    {
        ImageHandle newImageHandle = iter->first;
        Rect newRect = newRects[i];

        addImage(newImageHandle, newRect);
    }
}

void TextureAtlas::addImage(ImageHandle newImageHandle, Rect newRect)
{
    Image* newImage = newImageHandle.Resolve();

    bool wasRotated = newImage->getWidth() == newRect.height &&
                      newImage->getHeight() == newRect.width;

    Image* atlasImage = atlasImageHandle.Resolve();
    if (newImage->getPixelFormat() == atlasImage->getPixelFormat())
    {
        atlasImage->setBuffer(newImage,Vector2i(newRect.x,newRect.y));
    }
    else
    {
         assert(newImage->getPixelFormat() == PixelFormat::Depth &&
                atlasImage->getPixelFormat() == PixelFormat::R8G8B8A8);

         Image tmpImage(newImage->getWidth(),newImage->getHeight(),PixelFormat::R8G8B8A8);

         int newImageSize = newImage->getSize();
         std::vector<byte>& buffer = tmpImage.getBuffer();
         buffer.resize(newImageSize*4,0);

         for (int i = 0; i < newImageSize; i++)
         {
             buffer[i*4+3] = newImage->getBuffer()[i]; //A
         }

         if (wasRotated)
            RotateImage(&tmpImage,atlasImage,Vector2i(newRect.x,newRect.y));
         else
            atlasImage->setBuffer(&tmpImage,Vector2i(newRect.x,newRect.y));
    }

    SubTexture subTexture;
    subTexture.atlas = this;

    float bottom = (float)(newRect.y+newRect.height)/atlasSize;
    float top = (float)newRect.y/atlasSize;
    float right = (float)(newRect.x+newRect.width)/atlasSize;
    float left = (float)newRect.x/atlasSize;

    if(!wasRotated)
    {
        subTexture.leftTopUV = Vector2(left,top);
        subTexture.rightTopUV = Vector2(right,top);
        subTexture.rightBottomUV = Vector2(right,bottom);
        subTexture.leftBottomUV = Vector2(left,bottom);
    }
    else
    {
        subTexture.rightTopUV = Vector2(left,top);
        subTexture.rightBottomUV = Vector2(right,top);
        subTexture.leftBottomUV = Vector2(right,bottom);
        subTexture.leftTopUV = Vector2(left,bottom);
    }

    imageSubTextures[newImageHandle] = subTexture;
}

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

NAMESPACE_ENGINE_END<commit_msg>TextureAtlas now converts added images with PixelFormat::Depth to PixelFormat::R8G8B8A8 white images instead of black so vertex color can be applied<commit_after>/************************************************************************
*
* Flood Project  (2008-201x)
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/

#pragma once

#include "Engine/API.h"
#include "Engine/Texture/TextureAtlas.h"

NAMESPACE_ENGINE_BEGIN

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

static const MaxRectsBinPack::FreeRectChoiceHeuristic gs_heuristic =
             MaxRectsBinPack::FreeRectChoiceHeuristic::RectBestAreaFit;

TextureAtlas::TextureAtlas(uint maxSize)
{
    atlasMaxSize = maxSize;
    atlasSize = std::min(maxSize, DefaultSize);
    rectanglePacker.Init(atlasSize,atlasSize);
    atlasImageHandle = ImageCreate(AllocatorGetHeap(),atlasSize,atlasSize,PixelFormat::R8G8B8A8);
}

static const int RBLOCK = 96;

// We use this function to rotate images in-place since sometimes
// the packing algorithm will rotate the image to have a better fit.
static void RotateImage(Image* srcImage, Image* dstImage, Vector2i dstOffset)
{
    assert(srcImage->getPixelFormat() == dstImage->getPixelFormat());

    int bpp = srcImage->getPixelSize();

    int srcWidth = srcImage->getWidth();
    int srcHeight = srcImage->getHeight();
    int dstWidth = srcHeight;
    int dstHeight = srcWidth;

    // get src and dst scan width
    int srcPitch  = srcWidth*bpp;
    int dstPitch  = dstImage->getWidth()*bpp;

    byte* bsrc = srcImage->getBuffer().data();
    byte* bdst = dstImage->getBuffer().data();

    for(int xs = 0; xs < dstWidth; xs += RBLOCK) {    // for all image blocks of RBLOCK*RBLOCK pixels
        for(int ys = 0; ys < dstHeight; ys += RBLOCK) {
            for(int y = ys; y < std::min(dstHeight, ys + RBLOCK); y++) {    // do rotation
                int y2 = dstHeight - y - 1;
                // point to src pixel at (y2, xs)
                byte* src_bits = bsrc + (xs * srcPitch) + (y2 * bpp);
                // point to dst pixel at (xs, y)
                byte* dst_bits = bdst + (( y + dstOffset.y) * dstPitch) + ((xs + dstOffset.x) * bpp);
                for (int x = xs; x < std::min(dstWidth, xs + RBLOCK); x++) {
                    // dst.SetPixel(x, y, src.GetPixel(y2, x));
                    for(int j = 0; j < bpp; j++) {
                        dst_bits[j] = src_bits[j];
                    }
                    dst_bits += bpp;
                    src_bits += srcPitch;
                }
            }
        }
    }
}

bool TextureAtlas::addImage(const ImageHandle& newImageHandle)
{
    if(imageSubTextures.find( newImageHandle ) != imageSubTextures.end())
        return true;

    Image* newImage = newImageHandle.Resolve();

    Rect newRect = rectanglePacker.Insert(newImage->getWidth(), newImage->getHeight(), gs_heuristic);

    if (newRect.height == 0 || newRect.width == 0){
        if (atlasSize >= atlasMaxSize)
            return false;

        atlasSize = std::min(atlasSize*2, atlasMaxSize);
        resizeAtlas(atlasSize);

        return addImage(newImageHandle);
    }

    addImage(newImageHandle,newRect);

    return true;
}

bool TextureAtlas::getImageSubTexture(const ImageHandle& imageHandle, SubTexture& subTexture)
{
    if(imageSubTextures.find( imageHandle ) == imageSubTextures.end())
        return false;

    subTexture = imageSubTextures[imageHandle];
    return true;
}

ImageHandle TextureAtlas::getAtlasImageHandle() const
{
    return atlasImageHandle;
}

void TextureAtlas::resizeAtlas(uint newSize)
{
    rectanglePacker.Init(newSize,newSize);

    std::vector<Vector2i> rectSizes;
    std::vector<Rect> newRects;

    Image* atlasImage = atlasImageHandle.Resolve();

    std::map<ImageHandle, SubTexture>::iterator iter;
    for (iter = imageSubTextures.begin(); iter != imageSubTextures.end(); ++iter) {
        Vector2i rectSize;
        int width = (iter->second.rightBottomUV.x - iter->second.leftTopUV.x)*width;
        int height = (iter->second.rightBottomUV.y - iter->second.leftTopUV.y)*height;
        rectSize.x = width;
        rectSize.y = height;
        rectSizes.push_back(rectSize);
    }

    rectanglePacker.Insert(rectSizes, newRects, gs_heuristic);

    assert(newRects.size() == imageSubTextures.size());

    int i;
    for (i = 0, iter = imageSubTextures.begin(); iter != imageSubTextures.end(); ++iter, ++i)
    {
        ImageHandle newImageHandle = iter->first;
        Rect newRect = newRects[i];

        addImage(newImageHandle, newRect);
    }
}

void TextureAtlas::addImage(ImageHandle newImageHandle, Rect newRect)
{
    Image* newImage = newImageHandle.Resolve();

    bool wasRotated = newImage->getWidth() == newRect.height &&
                      newImage->getHeight() == newRect.width;

    Image* atlasImage = atlasImageHandle.Resolve();
    if (newImage->getPixelFormat() == atlasImage->getPixelFormat())
    {
        atlasImage->setBuffer(newImage,Vector2i(newRect.x,newRect.y));
    }
    else
    {
         assert(newImage->getPixelFormat() == PixelFormat::Depth &&
                atlasImage->getPixelFormat() == PixelFormat::R8G8B8A8);

         Image tmpImage(newImage->getWidth(),newImage->getHeight(),PixelFormat::R8G8B8A8);

         int newImageSize = newImage->getSize();
         std::vector<byte>& buffer = tmpImage.getBuffer();
         buffer.resize(newImageSize*4);

         for (int i = 0; i < newImageSize; i++)
         {
             int p = i*4;
             buffer[p+0] = 255; //R
             buffer[p+1] = 255; //G
             buffer[p+2] = 255; //B
             buffer[p+3] = newImage->getBuffer()[i]; //A
         }

         if (wasRotated)
            RotateImage(&tmpImage,atlasImage,Vector2i(newRect.x,newRect.y));
         else
            atlasImage->setBuffer(&tmpImage,Vector2i(newRect.x,newRect.y));
    }

    SubTexture subTexture;
    subTexture.atlas = this;

    float bottom = (float)(newRect.y+newRect.height)/atlasSize;
    float top = (float)newRect.y/atlasSize;
    float right = (float)(newRect.x+newRect.width)/atlasSize;
    float left = (float)newRect.x/atlasSize;

    if(!wasRotated)
    {
        subTexture.leftTopUV = Vector2(left,top);
        subTexture.rightTopUV = Vector2(right,top);
        subTexture.rightBottomUV = Vector2(right,bottom);
        subTexture.leftBottomUV = Vector2(left,bottom);
    }
    else
    {
        subTexture.rightTopUV = Vector2(left,top);
        subTexture.rightBottomUV = Vector2(right,top);
        subTexture.leftBottomUV = Vector2(right,bottom);
        subTexture.leftTopUV = Vector2(left,bottom);
    }

    imageSubTextures[newImageHandle] = subTexture;
}

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

NAMESPACE_ENGINE_END<|endoftext|>


<commit_before><commit_msg>Fixes two bugs in tree view: . Invoking SetRootShown before the tree was created resulted in   updating internal structures with wrong info. This caused problems   if you later tried to delete. I've added a DCHECK to make sure we   don't hit this again. . Adding a node to the root when the root wasn't shown silently   failed.<commit_after><|endoftext|>


<commit_before>#ifndef UTENSOR_SDTENSOR_H
#define UTENSOR_SDTENSOR_H
#include "tensor.hpp"
#include "tensorIdxImporter.hpp"
template <class T>
class SDTensor : public Tensor {
  public:
    SDTensor(TName _name, std::string filename) : Tensor(_name) {
        _filename = filename;
        cursor = 0;
        dirty = false;
    }

    SDTensor(std::initializer_list<uint32_t> l, TName _name, std::string file) : Tensor(_name) {
      std::vector<uint32_t> v;
      for (auto i : l) {
         v.push_back(i);
      }
      Tensor::init<T>(v);
      _filename = file;
      cursor = 0;
      setIdxType();
      data_importer.load_data<T>(_filename, type, unit_size(), s->total_size, cursor, (T*)s->data);
      dirty = false;
    }

    SDTensor(std::vector<uint32_t> v, TName _name, std::string file) : Tensor(_name) {
      Tensor::init<T>(v);
      _filename = file;
      cursor = 0;
      setIdxType();
      data_importer.load_data<T>(_filename, type, unit_size(), s->total_size, cursor, (T*)s->data);
      dirty = false;
    }
    void setIdxType() {
      if (std::is_same<T, unsigned char>::value) {
          type = idx_ubyte;
      } else if (std::is_same<T, char>::value) {
          type = idx_byte;
      } else if (std::is_same<T, short>::value) {
          type = idx_short;
      } else if (std::is_same<T, int>::value) {
          type = idx_int;
      } else if (std::is_same<T, float>::value) {
          type = idx_float;
      } else if (std::is_same<T, double>::value) {
          type = idx_double;
      } else {
          ERR_EXIT("idx type not supported");
      }
    }
    virtual void* read(size_t offset, size_t ele) override {
      if (ele > s->total_size) {
        ERR_EXIT("data overflow");
      }
      if (offset + ele < cursor + s->total_size && !dirty) {
        return (void *)((T*)s->data + offset - cursor);
      } else if (offset + ele >= cursor + s->total_size || dirty) {
        data_importer.flush_data<T>(_filename, type, unit_size(), s->total_size, cursor, (T*)s->data);
        dirty = false;
        data_importer.load_data<T>(_filename, type, unit_size(), ele, offset, (T*)s->data);
        cursor = offset;
      }
      return (void *)((T*)s->data);
    }
    virtual void* write(size_t offset, size_t ele) override {
      if (ele > s->total_size) {
        ERR_EXIT("data overflow");
      }
      dirty = true;
      if (offset + ele < cursor + s->total_size) {
        return (void *)((T*)s->data + offset - cursor);
      } else if (offset + ele >= cursor + s->total_size) {
        data_importer.flush_data<T>(_filename, type, unit_size(), cursor, s->total_size, (T*)s->data);
        data_importer.load_data<T>(_filename, type, unit_size(), offset, ele, (T*)s->data);
        cursor = offset;
      }
      return (void*)((T*)s->data + offset);
    }

  // virtual void* read(size_t offset, size_t ele) override{};
  virtual uint16_t unit_size(void) override {
    return sizeof(T);
  }
  ~SDTensor() {}
 private:
  SDTensor(const SDTensor&);
  TensorIdxImporter data_importer;
  std::string _filename;
  bool dirty;
  long int cursor;
  SDTensor& operator=(const SDTensor&);
  IDX_DTYPE type;

};
#endif
<commit_msg>  1. complete the cache mechanism and add some comment for readable   2. it include three states:     1. shared state: the memory is read and shared with same value in sd card     2. dirty state: the memory is changed and should be writed back     3. miss state: the request memory address is not in the memory<commit_after>#ifndef UTENSOR_SDTENSOR_H
#define UTENSOR_SDTENSOR_H
#include "tensor.hpp"
#include "tensorIdxImporter.hpp"
template <class T>
class SDTensor : public Tensor {
  public:
    SDTensor(TName _name, std::string filename) : Tensor(_name) {
        _filename = filename;
        cursor = 0;
        dirty = false;
    }

    SDTensor(std::initializer_list<uint32_t> l, TName _name, std::string file) : Tensor(_name) {
      std::vector<uint32_t> v;
      for (auto i : l) {
         v.push_back(i);
      }
      Tensor::init<T>(v);
      _filename = file;
      cursor = 0;
      setIdxType();
      data_importer.load_data<T>(_filename, type, unit_size(), s->total_size, cursor, (T*)s->data);
      dirty = false;
    }

    SDTensor(std::vector<uint32_t> v, TName _name, std::string file) : Tensor(_name) {
      Tensor::init<T>(v);
      _filename = file;
      cursor = 0;
      setIdxType();
      data_importer.load_data<T>(_filename, type, unit_size(), s->total_size, cursor, (T*)s->data);
      dirty = false;
    }
    void setIdxType() {
      if (std::is_same<T, unsigned char>::value) {
          type = idx_ubyte;
      } else if (std::is_same<T, char>::value) {
          type = idx_byte;
      } else if (std::is_same<T, short>::value) {
          type = idx_short;
      } else if (std::is_same<T, int>::value) {
          type = idx_int;
      } else if (std::is_same<T, float>::value) {
          type = idx_float;
      } else if (std::is_same<T, double>::value) {
          type = idx_double;
      } else {
          ERR_EXIT("idx type not supported");
      }
    }
    virtual void* read(size_t offset, size_t ele) override {
      if (ele > s->total_size) {
        ERR_EXIT("data overflow");
      }
      if (offset + ele < cursor + s->total_size) {
        //1. shared && not miss state
        //2. dirty && not miss state
        dirty = false;
        return (void *)((T*)s->data + offset - cursor);
      } else if (dirty && offset + ele >= cursor + s->total_size) {
        //1. dirty && miss state
        data_importer.flush_data<T>(_filename, type, unit_size(), s->total_size, cursor, (T*)s->data);
        data_importer.load_data<T>(_filename, type, unit_size(), ele, offset, (T*)s->data);
        cursor = offset;
        dirty = false;
      } else if (!dirty && offset + ele >= cursor + s->total_size) {
        //1. shared && miss state
        data_importer.load_data<T>(_filename, type, unit_size(), ele, offset, (T*)s->data);
        cursor = offset;
      }
      return (void *)((T*)s->data);
    }
    virtual void* write(size_t offset, size_t ele) override {
      if (ele > s->total_size) {
        ERR_EXIT("data overflow");
      }
      if (offset + ele < cursor + s->total_size) {
        //1. dirty && not miss state
        //2. shared && not miss state
        dirty = true;
        return (void *)((T*)s->data + offset - cursor);
      } else if (dirty && offset + ele >= cursor + s->total_size) {
        //1. dirty && miss state
        data_importer.flush_data<T>(_filename, type, unit_size(), cursor, s->total_size, (T*)s->data);
        data_importer.load_data<T>(_filename, type, unit_size(), offset, ele, (T*)s->data);
        cursor = offset;
      } else if (!dirty && offset + ele >= cursor + s->total_size) {
        //1. shared && miss state
        data_importer.load_data<T>(_filename, type, unit_size(), offset, ele, (T*)s->data);
        cursor = offset;
        dirty = true;
      }
      return (void*)((T*)s->data + offset);
    }

  // virtual void* read(size_t offset, size_t ele) override{};
  virtual uint16_t unit_size(void) override {
    return sizeof(T);
  }
  ~SDTensor() {}
 private:
  SDTensor(const SDTensor&);
  TensorIdxImporter data_importer;
  std::string _filename;
  bool dirty;
  long int cursor;
  SDTensor& operator=(const SDTensor&);
  IDX_DTYPE type;

};
#endif
<|endoftext|>