<commit_before>#include "World.hpp"

#include "json.hpp"

#include <fstream>

World::World(thor::ResourceHolder<sf::Texture, std::string>& textures)
: m_textures{textures}
{
    load_level("res/level01.json");

}

void World::load_level(const std::string& filename)
{
    nlohmann::json level;

    std::fstream file(filename, std::ios::in | std::ios::binary);

    if(!file.is_open())
        throw(std::runtime_error{"Failed to open animation file \"" + filename + "\"."});

    try
    {
        file >> level;
    }
    catch(std::exception& e)
    {
        throw(std::runtime_error{"The animation file \"" + filename + "\" contains invalid JSON data."});
    }

    // Load texture
    std::string texture = level["texture"];
    m_textures.acquire("level", thor::Resources::fromFile<sf::Texture>(texture));

    // Load base tiles
    m_tile_size = level["tile_size"];
    std::vector<Tile> base_tiles;

    for(auto& rect : level["tiles"])
    {
        base_tiles.emplace_back();
        base_tiles.back().texture(m_textures["level"], {rect[0], rect[1], m_tile_size, m_tile_size});
    }

    m_empty_tile.texture(m_textures["level"], {level["empty_tile"][0], level["empty_tile"][1], m_tile_size, m_tile_size});

    // Load board
    std::size_t x = 0;
    std::size_t y = 0;

    m_dimension = sf::Vector2u(level["board"].begin()->size(), level["board"].size());

    for(auto& line : level["board"])
    {
        for(std::size_t tile : line)
        {
            // First tile
            if(x == 0 && y == 0)
                m_tiles.resize(m_dimension.y * m_dimension.x);

            std::size_t index = y * m_dimension.x + x;

            // Copy base tile
            m_tiles[index] = base_tiles[tile];
            m_tiles[index].setPosition({x * m_tile_size, y * m_tile_size});

            ++x;
        };
        ++y;
        x = 0;
    }

    // Load logic part
    x = 0;
    y = 0;

    for(auto& line : level["logic"])
    {
        for(std::size_t tile : line)
        {
            // First tile
            if(x == 0 && y == 0)
                m_logic.resize(m_dimension.y * m_dimension.x);

            m_logic[y * m_dimension.x + x] = tile;

            if(tile == 1)
                m_spawn = {x * m_tile_size, y * m_tile_size};

            ++x;
        }
        ++y;
        x = 0;
    }
}

void World::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
    for(auto& tile : m_tiles)
        target.draw(tile, states);
}

std::size_t World::tile_size()
{
    return m_tile_size;
}

bool World::check_collision(sf::Vector2i direction, sf::Vector2f position)
{
    sf::Vector2i index = static_cast<sf::Vector2i>(position) / static_cast<int>(m_tile_size) + direction;

    return !check_bounds(index) || m_logic[index.y * m_dimension.x + index.x] >= 10;
}

sf::Vector2f World::player_spawn()
{
    return m_spawn;
}

bool World::check_action(std::size_t index, Synth::Type type, float frequency)
{
    switch(m_logic[index])
    {
        case 11:
            return type == Synth::SINE && frequency > 200.f && frequency <= 250.f;
        case 12:
            return type == Synth::SINE && frequency > 100.f && frequency <= 200.f;
        case 13:
            return type == Synth::SINE && frequency > 300.f && frequency <= 380.f;
        case 14:
            return type == Synth::SINE && frequency > 380.f && frequency <= 450.f;
        case 15:
            return type == Synth::SINE && frequency == 440.f;
        case 16:
            return type == Synth::SINE && frequency > 450.f && frequency <= 550.f;
        case 17:
            return type == Synth::SINE && frequency > 550.f && frequency <= 700.f;
        case 18:
            return type == Synth::SINE && frequency > 700.f && frequency <= 850.f;
        case 19:
            return type == Synth::SINE && frequency > 850.f && frequency <= 1000.f;

        case 21:
            return type == Synth::SAW && frequency > 200.f && frequency <= 250.f;
        case 22:
            return type == Synth::SAW && frequency > 100.f && frequency <= 200.f;
        case 23:
            return type == Synth::SAW && frequency > 300.f && frequency <= 380.f;
        case 24:
            return type == Synth::SAW && frequency > 380.f && frequency <= 450.f;
        case 25:
            return type == Synth::SAW && frequency == 440.f;
        case 26:
            return type == Synth::SAW && frequency > 450.f && frequency <= 550.f;
        case 27:
            return type == Synth::SAW && frequency > 550.f && frequency <= 700.f;
        case 28:
            return type == Synth::SAW && frequency > 700.f && frequency <= 850.f;
        case 29:
            return type == Synth::SAW && frequency > 850.f && frequency <= 1000.f;

        case 31:
            return type == Synth::TRIANGLE && frequency > 200.f && frequency <= 250.f;
        case 32:
            return type == Synth::TRIANGLE && frequency > 100.f && frequency <= 200.f;
        case 33:
            return type == Synth::TRIANGLE && frequency > 300.f && frequency <= 380.f;
        case 34:
            return type == Synth::TRIANGLE && frequency > 380.f && frequency <= 450.f;
        case 35:
            return type == Synth::TRIANGLE && frequency == 440.f;
        case 36:
            return type == Synth::TRIANGLE && frequency > 450.f && frequency <= 550.f;
        case 37:
            return type == Synth::TRIANGLE && frequency > 550.f && frequency <= 700.f;
        case 38:
            return type == Synth::TRIANGLE && frequency > 700.f && frequency <= 850.f;
        case 39:
            return type == Synth::TRIANGLE && frequency > 850.f && frequency <= 1000.f;

        case 41:
            return type == Synth::SQUARE && frequency > 200.f && frequency <= 250.f;
        case 42:
            return type == Synth::SQUARE && frequency > 100.f && frequency <= 200.f;
        case 43:
            return type == Synth::SQUARE && frequency > 300.f && frequency <= 380.f;
        case 44:
            return type == Synth::SQUARE && frequency > 380.f && frequency <= 450.f;
        case 45:
            return type == Synth::SQUARE && frequency == 440.f;
        case 46:
            return type == Synth::SQUARE && frequency > 450.f && frequency <= 550.f;
        case 47:
            return type == Synth::SQUARE && frequency > 550.f && frequency <= 700.f;
        case 48:
            return type == Synth::SQUARE && frequency > 700.f && frequency <= 850.f;
        case 49:
            return type == Synth::SQUARE && frequency > 850.f && frequency <= 1000.f;
    }

    return false;
}

bool World::check_walls(sf::Vector2f position, Synth::Type type, float frequency)
{
    sf::Vector2i index = static_cast<sf::Vector2i>(position) / static_cast<int>(m_tile_size);
    bool ret = false;

    if(check_bounds(index + sf::Vector2i(1, 0)) && check_action(index.y * m_dimension.x + index.x + 1, type, frequency))
    {
        m_empty_tile.setPosition((index.x + 1) * m_tile_size, index.y * m_tile_size);
        m_tiles[index.y * m_dimension.x + index.x + 1] = m_empty_tile;
        m_logic[index.y * m_dimension.x + index.x + 1] = 0;
        ret = true;
    }
    if(check_bounds(index + sf::Vector2i(-1, 0)) && check_action(index.y * m_dimension.x + index.x - 1, type, frequency))
    {
        m_empty_tile.setPosition((index.x - 1) * m_tile_size, index.y * m_tile_size);
        m_tiles[index.y * m_dimension.x + index.x - 1] = m_empty_tile;
        m_logic[index.y * m_dimension.x + index.x - 1] = 0;
        ret = true;
    }
    if(check_bounds(index + sf::Vector2i(0, 1)) && check_action((index.y + 1) * m_dimension.x + index.x, type, frequency))
    {
        m_empty_tile.setPosition(index.x * m_tile_size, (index.y + 1) * m_tile_size);
        m_tiles[(index.y + 1) * m_dimension.x + index.x] = m_empty_tile;
        m_logic[(index.y + 1) * m_dimension.x + index.x] = 0;
        ret = true;
    }
    if(check_bounds(index + sf::Vector2i(0, -1)) && check_action((index.y - 1) * m_dimension.x + index.x, type, frequency))
    {
        m_empty_tile.setPosition(index.x * m_tile_size, (index.y - 1) * m_tile_size);
        m_tiles[(index.y - 1) * m_dimension.x + index.x] = m_empty_tile;
        m_logic[(index.y - 1) * m_dimension.x + index.x] = 0;
        ret = true;
    }

    return ret;
}

bool World::check_bounds(sf::Vector2i index)
{
    return !(index.x < 0 || index.x > m_dimension.x - 1 || index.y < 0 || index.y > m_dimension.y - 1);
}

bool World::check_win(sf::Vector2f position)
{
    sf::Vector2i index = static_cast<sf::Vector2i>(position) / static_cast<int>(m_tile_size);
    return m_logic[index.y * m_dimension.x + index.x] == 2;
}

void World::next_level(const std::string& level)
{
    m_textures.release("level");
    load_level(level);
}
<commit_msg>Fixed some compiler warnings.<commit_after>#include "World.hpp"

#include "json.hpp"

#include <fstream>

World::World(thor::ResourceHolder<sf::Texture, std::string>& textures)
: m_textures{textures}
{
    load_level("res/level01.json");

}

void World::load_level(const std::string& filename)
{
    nlohmann::json level;

    std::fstream file(filename, std::ios::in | std::ios::binary);

    if(!file.is_open())
        throw(std::runtime_error{"Failed to open animation file \"" + filename + "\"."});

    try
    {
        file >> level;
    }
    catch(std::exception& e)
    {
        throw(std::runtime_error{"The animation file \"" + filename + "\" contains invalid JSON data."});
    }

    // Load texture
    std::string texture = level["texture"];
    m_textures.acquire("level", thor::Resources::fromFile<sf::Texture>(texture));

    // Load base tiles
    m_tile_size = level["tile_size"];
    std::vector<Tile> base_tiles;

    for(auto& rect : level["tiles"])
    {
        base_tiles.emplace_back();
        base_tiles.back().texture(m_textures["level"], {rect[0], rect[1], static_cast<int>(m_tile_size), static_cast<int>(m_tile_size)});
    }

    m_empty_tile.texture(m_textures["level"], {level["empty_tile"][0], level["empty_tile"][1],static_cast<int>( m_tile_size), static_cast<int>(m_tile_size)});

    // Load board
    std::size_t x = 0;
    std::size_t y = 0;

    m_dimension = sf::Vector2u(level["board"].begin()->size(), level["board"].size());

    for(auto& line : level["board"])
    {
        for(std::size_t tile : line)
        {
            // First tile
            if(x == 0 && y == 0)
                m_tiles.resize(m_dimension.y * m_dimension.x);

            std::size_t index = y * m_dimension.x + x;

            // Copy base tile
            m_tiles[index] = base_tiles[tile];
            m_tiles[index].setPosition({static_cast<float>(x * m_tile_size), static_cast<float>(y * m_tile_size)});

            ++x;
        };
        ++y;
        x = 0;
    }

    // Load logic part
    x = 0;
    y = 0;

    for(auto& line : level["logic"])
    {
        for(std::size_t tile : line)
        {
            // First tile
            if(x == 0 && y == 0)
                m_logic.resize(m_dimension.y * m_dimension.x);

            m_logic[y * m_dimension.x + x] = tile;

            if(tile == 1)
                m_spawn = {static_cast<float>(x * m_tile_size), static_cast<float>(y * m_tile_size)};

            ++x;
        }
        ++y;
        x = 0;
    }
}

void World::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
    for(auto& tile : m_tiles)
        target.draw(tile, states);
}

std::size_t World::tile_size()
{
    return m_tile_size;
}

bool World::check_collision(sf::Vector2i direction, sf::Vector2f position)
{
    sf::Vector2i index = static_cast<sf::Vector2i>(position) / static_cast<int>(m_tile_size) + direction;

    return !check_bounds(index) || m_logic[index.y * m_dimension.x + index.x] >= 10;
}

sf::Vector2f World::player_spawn()
{
    return m_spawn;
}

bool World::check_action(std::size_t index, Synth::Type type, float frequency)
{
    switch(m_logic[index])
    {
        case 11:
            return type == Synth::SINE && frequency > 200.f && frequency <= 250.f;
        case 12:
            return type == Synth::SINE && frequency > 100.f && frequency <= 200.f;
        case 13:
            return type == Synth::SINE && frequency > 300.f && frequency <= 380.f;
        case 14:
            return type == Synth::SINE && frequency > 380.f && frequency <= 450.f;
        case 15:
            return type == Synth::SINE && frequency == 440.f;
        case 16:
            return type == Synth::SINE && frequency > 450.f && frequency <= 550.f;
        case 17:
            return type == Synth::SINE && frequency > 550.f && frequency <= 700.f;
        case 18:
            return type == Synth::SINE && frequency > 700.f && frequency <= 850.f;
        case 19:
            return type == Synth::SINE && frequency > 850.f && frequency <= 1000.f;

        case 21:
            return type == Synth::SAW && frequency > 200.f && frequency <= 250.f;
        case 22:
            return type == Synth::SAW && frequency > 100.f && frequency <= 200.f;
        case 23:
            return type == Synth::SAW && frequency > 300.f && frequency <= 380.f;
        case 24:
            return type == Synth::SAW && frequency > 380.f && frequency <= 450.f;
        case 25:
            return type == Synth::SAW && frequency == 440.f;
        case 26:
            return type == Synth::SAW && frequency > 450.f && frequency <= 550.f;
        case 27:
            return type == Synth::SAW && frequency > 550.f && frequency <= 700.f;
        case 28:
            return type == Synth::SAW && frequency > 700.f && frequency <= 850.f;
        case 29:
            return type == Synth::SAW && frequency > 850.f && frequency <= 1000.f;

        case 31:
            return type == Synth::TRIANGLE && frequency > 200.f && frequency <= 250.f;
        case 32:
            return type == Synth::TRIANGLE && frequency > 100.f && frequency <= 200.f;
        case 33:
            return type == Synth::TRIANGLE && frequency > 300.f && frequency <= 380.f;
        case 34:
            return type == Synth::TRIANGLE && frequency > 380.f && frequency <= 450.f;
        case 35:
            return type == Synth::TRIANGLE && frequency == 440.f;
        case 36:
            return type == Synth::TRIANGLE && frequency > 450.f && frequency <= 550.f;
        case 37:
            return type == Synth::TRIANGLE && frequency > 550.f && frequency <= 700.f;
        case 38:
            return type == Synth::TRIANGLE && frequency > 700.f && frequency <= 850.f;
        case 39:
            return type == Synth::TRIANGLE && frequency > 850.f && frequency <= 1000.f;

        case 41:
            return type == Synth::SQUARE && frequency > 200.f && frequency <= 250.f;
        case 42:
            return type == Synth::SQUARE && frequency > 100.f && frequency <= 200.f;
        case 43:
            return type == Synth::SQUARE && frequency > 300.f && frequency <= 380.f;
        case 44:
            return type == Synth::SQUARE && frequency > 380.f && frequency <= 450.f;
        case 45:
            return type == Synth::SQUARE && frequency == 440.f;
        case 46:
            return type == Synth::SQUARE && frequency > 450.f && frequency <= 550.f;
        case 47:
            return type == Synth::SQUARE && frequency > 550.f && frequency <= 700.f;
        case 48:
            return type == Synth::SQUARE && frequency > 700.f && frequency <= 850.f;
        case 49:
            return type == Synth::SQUARE && frequency > 850.f && frequency <= 1000.f;
    }

    return false;
}

bool World::check_walls(sf::Vector2f position, Synth::Type type, float frequency)
{
    sf::Vector2i index = static_cast<sf::Vector2i>(position) / static_cast<int>(m_tile_size);
    bool ret = false;

    if(check_bounds(index + sf::Vector2i(1, 0)) && check_action(index.y * m_dimension.x + index.x + 1, type, frequency))
    {
        m_empty_tile.setPosition((index.x + 1) * m_tile_size, index.y * m_tile_size);
        m_tiles[index.y * m_dimension.x + index.x + 1] = m_empty_tile;
        m_logic[index.y * m_dimension.x + index.x + 1] = 0;
        ret = true;
    }
    if(check_bounds(index + sf::Vector2i(-1, 0)) && check_action(index.y * m_dimension.x + index.x - 1, type, frequency))
    {
        m_empty_tile.setPosition((index.x - 1) * m_tile_size, index.y * m_tile_size);
        m_tiles[index.y * m_dimension.x + index.x - 1] = m_empty_tile;
        m_logic[index.y * m_dimension.x + index.x - 1] = 0;
        ret = true;
    }
    if(check_bounds(index + sf::Vector2i(0, 1)) && check_action((index.y + 1) * m_dimension.x + index.x, type, frequency))
    {
        m_empty_tile.setPosition(index.x * m_tile_size, (index.y + 1) * m_tile_size);
        m_tiles[(index.y + 1) * m_dimension.x + index.x] = m_empty_tile;
        m_logic[(index.y + 1) * m_dimension.x + index.x] = 0;
        ret = true;
    }
    if(check_bounds(index + sf::Vector2i(0, -1)) && check_action((index.y - 1) * m_dimension.x + index.x, type, frequency))
    {
        m_empty_tile.setPosition(index.x * m_tile_size, (index.y - 1) * m_tile_size);
        m_tiles[(index.y - 1) * m_dimension.x + index.x] = m_empty_tile;
        m_logic[(index.y - 1) * m_dimension.x + index.x] = 0;
        ret = true;
    }

    return ret;
}

bool World::check_bounds(sf::Vector2i index)
{
    return !(index.x < 0 || index.x > m_dimension.x - 1 || index.y < 0 || index.y > m_dimension.y - 1);
}

bool World::check_win(sf::Vector2f position)
{
    sf::Vector2i index = static_cast<sf::Vector2i>(position) / static_cast<int>(m_tile_size);
    return m_logic[index.y * m_dimension.x + index.x] == 2;
}

void World::next_level(const std::string& level)
{
    m_textures.release("level");
    load_level(level);
}
<|endoftext|>


<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/bind.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/scoped_temp_dir.h"
#include "base/test/thread_test_helper.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/in_process_webkit/indexed_db_context.h"
#include "content/browser/in_process_webkit/webkit_context.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/public/common/content_switches.h"
#include "webkit/database/database_util.h"
#include "webkit/quota/mock_special_storage_policy.h"
#include "webkit/quota/quota_manager.h"
#include "webkit/quota/special_storage_policy.h"

using content::BrowserThread;
using quota::QuotaManager;
using webkit_database::DatabaseUtil;

// This browser test is aimed towards exercising the IndexedDB bindings and
// the actual implementation that lives in the browser side (in_process_webkit).
class IndexedDBBrowserTest : public InProcessBrowserTest {
 public:
  IndexedDBBrowserTest() {
    EnableDOMAutomation();
  }

  GURL testUrl(const FilePath& file_path) {
    const FilePath kTestDir(FILE_PATH_LITERAL("indexeddb"));
    return ui_test_utils::GetTestUrl(kTestDir, file_path);
  }

  void SimpleTest(const GURL& test_url, bool incognito = false) {
    // The test page will perform tests on IndexedDB, then navigate to either
    // a #pass or #fail ref.
    Browser* the_browser = incognito ? CreateIncognitoBrowser() : browser();

    LOG(INFO) << "Navigating to URL and blocking.";
    ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
        the_browser, test_url, 2);
    LOG(INFO) << "Navigation done.";
    std::string result = the_browser->GetSelectedTabContents()->GetURL().ref();
    if (result != "pass") {
      std::string js_result;
      ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
          the_browser->GetSelectedTabContents()->render_view_host(), L"",
          L"window.domAutomationController.send(getLog())", &js_result));
      FAIL() << "Failed: " << js_result;
    }
  }
};

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("cursor_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("cursor_test.html"))),
             true /* incognito */);
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_IndexTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("index_test.html"))));
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_KeyPathTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("key_path_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_get_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyTypesTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("key_types_test.html"))));
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_ObjectStoreTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("object_store_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("database_test.html"))));
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_TransactionTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_DoesntHangTest) {
  SimpleTest(testUrl(FilePath(
      FILE_PATH_LITERAL("transaction_run_forever.html"))));
  ui_test_utils::CrashTab(browser()->GetSelectedTabContents());
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug84933Test) {
  const GURL url = testUrl(FilePath(FILE_PATH_LITERAL("bug_84933.html")));

  // Just navigate to the URL. Test will crash if it fails.
  ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(), url, 1);
}

// In proc browser test is needed here because ClearLocalState indirectly calls
// WebKit's isMainThread through WebSecurityOrigin->SecurityOrigin.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ClearLocalState) {
  ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());

  FilePath protected_path;
  FilePath unprotected_path;

  // Create the scope which will ensure we run the destructor of the webkit
  // context which should trigger the clean up.
  {
    TestingProfile profile;

    // Test our assumptions about what is protected and what is not.
    const GURL kProtectedOrigin("chrome-extension://foo/");
    const GURL kUnprotectedOrigin("http://foo/");
    quota::SpecialStoragePolicy* policy = profile.GetSpecialStoragePolicy();
    ASSERT_TRUE(policy->IsStorageProtected(kProtectedOrigin));
    ASSERT_FALSE(policy->IsStorageProtected(kUnprotectedOrigin));

    // Create some indexedDB paths.
    // With the levelDB backend, these are directories.
    WebKitContext *webkit_context = profile.GetWebKitContext();
    IndexedDBContext* idb_context = webkit_context->indexed_db_context();
    idb_context->set_data_path_for_testing(temp_dir.path());
    protected_path = idb_context->GetIndexedDBFilePath(
        DatabaseUtil::GetOriginIdentifier(kProtectedOrigin));
    unprotected_path = idb_context->GetIndexedDBFilePath(
        DatabaseUtil::GetOriginIdentifier(kUnprotectedOrigin));
    ASSERT_TRUE(file_util::CreateDirectory(protected_path));
    ASSERT_TRUE(file_util::CreateDirectory(unprotected_path));

    // Setup to clear all unprotected origins on exit.
    webkit_context->set_clear_local_state_on_exit(true);
  }

  // Make sure we wait until the destructor has run.
  scoped_refptr<base::ThreadTestHelper> helper(
      new base::ThreadTestHelper(
          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::WEBKIT)));
  ASSERT_TRUE(helper->Run());

  ASSERT_TRUE(file_util::DirectoryExists(protected_path));
  ASSERT_FALSE(file_util::DirectoryExists(unprotected_path));
}

// In proc browser test is needed here because ClearLocalState indirectly calls
// WebKit's isMainThread through WebSecurityOrigin->SecurityOrigin.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ClearSessionOnlyDatabases) {
  ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());

  FilePath normal_path;
  FilePath session_only_path;

  // Create the scope which will ensure we run the destructor of the webkit
  // context which should trigger the clean up.
  {
    TestingProfile profile;

    const GURL kNormalOrigin("http://normal/");
    const GURL kSessionOnlyOrigin("http://session-only/");
    scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
        new quota::MockSpecialStoragePolicy;
    special_storage_policy->AddSessionOnly(kSessionOnlyOrigin);

    // Create some indexedDB paths.
    // With the levelDB backend, these are directories.
    WebKitContext *webkit_context = profile.GetWebKitContext();
    IndexedDBContext* idb_context = webkit_context->indexed_db_context();

    // Override the storage policy with our own.
    idb_context->special_storage_policy_ = special_storage_policy;
    idb_context->set_data_path_for_testing(temp_dir.path());

    normal_path = idb_context->GetIndexedDBFilePath(
        DatabaseUtil::GetOriginIdentifier(kNormalOrigin));
    session_only_path = idb_context->GetIndexedDBFilePath(
        DatabaseUtil::GetOriginIdentifier(kSessionOnlyOrigin));
    ASSERT_TRUE(file_util::CreateDirectory(normal_path));
    ASSERT_TRUE(file_util::CreateDirectory(session_only_path));
  }

  // Make sure we wait until the destructor has run.
  scoped_refptr<base::ThreadTestHelper> helper(
      new base::ThreadTestHelper(
          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::WEBKIT)));
  ASSERT_TRUE(helper->Run());

  EXPECT_TRUE(file_util::DirectoryExists(normal_path));
  EXPECT_FALSE(file_util::DirectoryExists(session_only_path));
}

class IndexedDBBrowserTestWithLowQuota : public IndexedDBBrowserTest {
 public:
  virtual void SetUpOnMainThread() {
    const int kInitialQuotaKilobytes = 5000;
    const int kTemporaryStorageQuotaMaxSize = kInitialQuotaKilobytes
        * 1024 * QuotaManager::kPerHostTemporaryPortion;
    SetTempQuota(
        kTemporaryStorageQuotaMaxSize, browser()->profile()->GetQuotaManager());
  }

  static void SetTempQuota(int64 bytes, scoped_refptr<QuotaManager> qm) {
    if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
      BrowserThread::PostTask(
          BrowserThread::IO, FROM_HERE,
          base::Bind(&IndexedDBBrowserTestWithLowQuota::SetTempQuota, bytes,
                     qm));
      return;
    }
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    qm->SetTemporaryGlobalOverrideQuota(bytes, quota::QuotaCallback());
    // Don't return until the quota has been set.
    scoped_refptr<base::ThreadTestHelper> helper(
        new base::ThreadTestHelper(
            BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
    ASSERT_TRUE(helper->Run());
  }

};

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithLowQuota, QuotaTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("quota_test.html"))));
}

class IndexedDBBrowserTestWithGCExposed : public IndexedDBBrowserTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
  }
};

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed,
                       DatabaseCallbacksTest) {
  SimpleTest(
      testUrl(FilePath(FILE_PATH_LITERAL("database_callbacks_first.html"))));
}
<commit_msg>Mark IndexedDBBrowserTest.KeyTypesTest flaky on Windows.<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/bind.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/scoped_temp_dir.h"
#include "base/test/thread_test_helper.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/in_process_webkit/indexed_db_context.h"
#include "content/browser/in_process_webkit/webkit_context.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/public/common/content_switches.h"
#include "webkit/database/database_util.h"
#include "webkit/quota/mock_special_storage_policy.h"
#include "webkit/quota/quota_manager.h"
#include "webkit/quota/special_storage_policy.h"

using content::BrowserThread;
using quota::QuotaManager;
using webkit_database::DatabaseUtil;

// This browser test is aimed towards exercising the IndexedDB bindings and
// the actual implementation that lives in the browser side (in_process_webkit).
class IndexedDBBrowserTest : public InProcessBrowserTest {
 public:
  IndexedDBBrowserTest() {
    EnableDOMAutomation();
  }

  GURL testUrl(const FilePath& file_path) {
    const FilePath kTestDir(FILE_PATH_LITERAL("indexeddb"));
    return ui_test_utils::GetTestUrl(kTestDir, file_path);
  }

  void SimpleTest(const GURL& test_url, bool incognito = false) {
    // The test page will perform tests on IndexedDB, then navigate to either
    // a #pass or #fail ref.
    Browser* the_browser = incognito ? CreateIncognitoBrowser() : browser();

    LOG(INFO) << "Navigating to URL and blocking.";
    ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
        the_browser, test_url, 2);
    LOG(INFO) << "Navigation done.";
    std::string result = the_browser->GetSelectedTabContents()->GetURL().ref();
    if (result != "pass") {
      std::string js_result;
      ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
          the_browser->GetSelectedTabContents()->render_view_host(), L"",
          L"window.domAutomationController.send(getLog())", &js_result));
      FAIL() << "Failed: " << js_result;
    }
  }
};

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("cursor_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("cursor_test.html"))),
             true /* incognito */);
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_IndexTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("index_test.html"))));
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_KeyPathTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("key_path_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_get_test.html"))));
}

#if defined(OS_WIN)
// http://crbug.com/104306
#define KeyTypesTest FLAKY_KeyTypesTest
#endif
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyTypesTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("key_types_test.html"))));
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_ObjectStoreTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("object_store_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("database_test.html"))));
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_TransactionTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
}

// Flaky: http://crbug.com/70773
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_DoesntHangTest) {
  SimpleTest(testUrl(FilePath(
      FILE_PATH_LITERAL("transaction_run_forever.html"))));
  ui_test_utils::CrashTab(browser()->GetSelectedTabContents());
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug84933Test) {
  const GURL url = testUrl(FilePath(FILE_PATH_LITERAL("bug_84933.html")));

  // Just navigate to the URL. Test will crash if it fails.
  ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(), url, 1);
}

// In proc browser test is needed here because ClearLocalState indirectly calls
// WebKit's isMainThread through WebSecurityOrigin->SecurityOrigin.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ClearLocalState) {
  ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());

  FilePath protected_path;
  FilePath unprotected_path;

  // Create the scope which will ensure we run the destructor of the webkit
  // context which should trigger the clean up.
  {
    TestingProfile profile;

    // Test our assumptions about what is protected and what is not.
    const GURL kProtectedOrigin("chrome-extension://foo/");
    const GURL kUnprotectedOrigin("http://foo/");
    quota::SpecialStoragePolicy* policy = profile.GetSpecialStoragePolicy();
    ASSERT_TRUE(policy->IsStorageProtected(kProtectedOrigin));
    ASSERT_FALSE(policy->IsStorageProtected(kUnprotectedOrigin));

    // Create some indexedDB paths.
    // With the levelDB backend, these are directories.
    WebKitContext *webkit_context = profile.GetWebKitContext();
    IndexedDBContext* idb_context = webkit_context->indexed_db_context();
    idb_context->set_data_path_for_testing(temp_dir.path());
    protected_path = idb_context->GetIndexedDBFilePath(
        DatabaseUtil::GetOriginIdentifier(kProtectedOrigin));
    unprotected_path = idb_context->GetIndexedDBFilePath(
        DatabaseUtil::GetOriginIdentifier(kUnprotectedOrigin));
    ASSERT_TRUE(file_util::CreateDirectory(protected_path));
    ASSERT_TRUE(file_util::CreateDirectory(unprotected_path));

    // Setup to clear all unprotected origins on exit.
    webkit_context->set_clear_local_state_on_exit(true);
  }

  // Make sure we wait until the destructor has run.
  scoped_refptr<base::ThreadTestHelper> helper(
      new base::ThreadTestHelper(
          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::WEBKIT)));
  ASSERT_TRUE(helper->Run());

  ASSERT_TRUE(file_util::DirectoryExists(protected_path));
  ASSERT_FALSE(file_util::DirectoryExists(unprotected_path));
}

// In proc browser test is needed here because ClearLocalState indirectly calls
// WebKit's isMainThread through WebSecurityOrigin->SecurityOrigin.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ClearSessionOnlyDatabases) {
  ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());

  FilePath normal_path;
  FilePath session_only_path;

  // Create the scope which will ensure we run the destructor of the webkit
  // context which should trigger the clean up.
  {
    TestingProfile profile;

    const GURL kNormalOrigin("http://normal/");
    const GURL kSessionOnlyOrigin("http://session-only/");
    scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy =
        new quota::MockSpecialStoragePolicy;
    special_storage_policy->AddSessionOnly(kSessionOnlyOrigin);

    // Create some indexedDB paths.
    // With the levelDB backend, these are directories.
    WebKitContext *webkit_context = profile.GetWebKitContext();
    IndexedDBContext* idb_context = webkit_context->indexed_db_context();

    // Override the storage policy with our own.
    idb_context->special_storage_policy_ = special_storage_policy;
    idb_context->set_data_path_for_testing(temp_dir.path());

    normal_path = idb_context->GetIndexedDBFilePath(
        DatabaseUtil::GetOriginIdentifier(kNormalOrigin));
    session_only_path = idb_context->GetIndexedDBFilePath(
        DatabaseUtil::GetOriginIdentifier(kSessionOnlyOrigin));
    ASSERT_TRUE(file_util::CreateDirectory(normal_path));
    ASSERT_TRUE(file_util::CreateDirectory(session_only_path));
  }

  // Make sure we wait until the destructor has run.
  scoped_refptr<base::ThreadTestHelper> helper(
      new base::ThreadTestHelper(
          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::WEBKIT)));
  ASSERT_TRUE(helper->Run());

  EXPECT_TRUE(file_util::DirectoryExists(normal_path));
  EXPECT_FALSE(file_util::DirectoryExists(session_only_path));
}

class IndexedDBBrowserTestWithLowQuota : public IndexedDBBrowserTest {
 public:
  virtual void SetUpOnMainThread() {
    const int kInitialQuotaKilobytes = 5000;
    const int kTemporaryStorageQuotaMaxSize = kInitialQuotaKilobytes
        * 1024 * QuotaManager::kPerHostTemporaryPortion;
    SetTempQuota(
        kTemporaryStorageQuotaMaxSize, browser()->profile()->GetQuotaManager());
  }

  static void SetTempQuota(int64 bytes, scoped_refptr<QuotaManager> qm) {
    if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
      BrowserThread::PostTask(
          BrowserThread::IO, FROM_HERE,
          base::Bind(&IndexedDBBrowserTestWithLowQuota::SetTempQuota, bytes,
                     qm));
      return;
    }
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    qm->SetTemporaryGlobalOverrideQuota(bytes, quota::QuotaCallback());
    // Don't return until the quota has been set.
    scoped_refptr<base::ThreadTestHelper> helper(
        new base::ThreadTestHelper(
            BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
    ASSERT_TRUE(helper->Run());
  }

};

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithLowQuota, QuotaTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("quota_test.html"))));
}

class IndexedDBBrowserTestWithGCExposed : public IndexedDBBrowserTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
  }
};

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed,
                       DatabaseCallbacksTest) {
  SimpleTest(
      testUrl(FilePath(FILE_PATH_LITERAL("database_callbacks_first.html"))));
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include<iostream>
#include<thread>

#include<cstdio>
#include<cstring>

#include<sys/socket.h>
#include<sys/un.h>
#include<sys/types.h>
#include<unistd.h>

#include <wiringPi.h>

namespace {

static const std::size_t UNIX_PATH_MAX = 108;

char buffer[4096];

void connection_handler(int connection_fd){
    std::cout << "asgard: New connection received" << std::endl;

    int nbytes;
    while((nbytes = read(connection_fd, buffer, 4096)) > 0){
        buffer[nbytes] = 0;
        std::cout << "asgard: Received message: " << buffer << std::endl;
    }

    close(connection_fd);
}

} //end of anonymous namespace

int main(){
    wiringPiSetup();
    pinMode(1, OUTPUT);
    digitalWrite(1, HIGH);

    //Open the socket
    auto socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if(socket_fd < 0){
        printf("socket() failed\n");
        return 1;
    }

    unlink("/tmp/asgard_socket");

    //Init the address
    struct sockaddr_un address;
    memset(&address, 0, sizeof(struct sockaddr_un));
    address.sun_family = AF_UNIX;
    snprintf(address.sun_path, UNIX_PATH_MAX, "/tmp/asgard_socket");

    //Bind
    if(bind(socket_fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0){
        printf("bind() failed\n");
        return 1;
    }

    if(listen(socket_fd, 5) != 0){
        printf("listen() failed\n");
        return 1;
    }

    int connection_fd;
    socklen_t address_length;
    while((connection_fd = accept(socket_fd, (struct sockaddr *) &address, &address_length)) > -1){
        std::thread(connection_handler, connection_fd).detach();
    }

    close(socket_fd);
    unlink("/tmp/asgard_socket");
    return 0;
}
<commit_msg>Better shutdown<commit_after>//=======================================================================
// Copyright (c) 2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include<iostream>
#include<thread>

#include<cstdio>
#include<cstring>

#include<sys/socket.h>
#include<sys/un.h>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>

#include <wiringPi.h>

namespace {

int socket_fd;
const std::size_t UNIX_PATH_MAX = 108;

char buffer[4096];

void connection_handler(int connection_fd){
    std::cout << "asgard: New connection received" << std::endl;

    int nbytes;
    while((nbytes = read(connection_fd, buffer, 4096)) > 0){
        buffer[nbytes] = 0;
        std::cout << "asgard: Received message: " << buffer << std::endl;
    }

    close(connection_fd);
}

void terminate(int /*signo*/){
    digitalWrite(1, LOW);

    close(socket_fd);
    unlink("/tmp/asgard_socket");

    abort();
}

} //end of anonymous namespace

int main(){
    //Register signals for "proper" shutdown
    signal(SIGTERM, terminate);
    signal(SIGINT, terminate);

    wiringPiSetup();
    pinMode(1, OUTPUT);
    digitalWrite(1, HIGH);

    //Open the socket
    socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if(socket_fd < 0){
        printf("socket() failed\n");
        return 1;
    }

    unlink("/tmp/asgard_socket");

    //Init the address
    struct sockaddr_un address;
    memset(&address, 0, sizeof(struct sockaddr_un));
    address.sun_family = AF_UNIX;
    snprintf(address.sun_path, UNIX_PATH_MAX, "/tmp/asgard_socket");

    //Bind
    if(bind(socket_fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0){
        printf("bind() failed\n");
        return 1;
    }

    if(listen(socket_fd, 5) != 0){
        printf("listen() failed\n");
        return 1;
    }

    int connection_fd;
    socklen_t address_length;
    while((connection_fd = accept(socket_fd, (struct sockaddr *) &address, &address_length)) > -1){
        std::thread(connection_handler, connection_fd).detach();
    }

    close(socket_fd);
    unlink("/tmp/asgard_socket");

    return 0;
}
<|endoftext|>


<commit_before>#include "Logger.h"

#include <signal.h>
#include <execinfo.h>

Logger::Logger()
{

}

void Logger::Log(std::string stg)
{
#ifndef RELEASE
    PRINT(stg);
#endif
    logFile << stg << std::endl;
}

void Logger::CreateLogFile()
{
    logFile.open(LOGFILE,std::ios_base::out);
    if(!logFile.is_open())
    {
        PRINT("Couldn't not create the log file! Exiting!");
        exit(1);
    }
	instanceSignalCallbacks();
}

void Logger::CloseLogFile()
{
    LOG("Fechando log");
    logFile.close();
}

Logger::~Logger()
{

}

void Logger::instanceSignalCallbacks()
{
	signal(SIGSEGV,signalCallbackHandler);
}

void Logger::generateBackTrace(std::vector<char *> &vec)
{

	const int maxbtsize = 64;
	int logsize = 0;
	void *bt[maxbtsize];
	char ** logTrace;
	logsize = backtrace(bt,maxbtsize);
	logTrace = backtrace_symbols(bt,maxbtsize);
	for(int i = 0; i < logsize; ++i)
		vec.push_back(logTrace[i]);

}

void Logger::signalCallbackHandler(int signum)
{
	std::vector<char *> vec;
    std::string logString;

	PRINT("Signal Number Received: " << signum << " \nClosing");
	generateBackTrace(vec);
    LOG("***** BACKTRACE *****");
	for(auto bt : vec)
    {
        LOG(bt);
        logString += bt;
    }
    LOG("***** END *****");
	for(auto bt : vec)
		delete bt;

}
<commit_msg>comentarios no logger<commit_after>#include "Logger.h"

#ifndef WIN32
//if not Windows
#include <signal.h>
#include <execinfo.h>

#endif
Logger::Logger()
{

}

void Logger::Log(std::string stg)
{
#ifndef RELEASE
    PRINT(stg);
#endif
    logFile << stg << std::endl;
}

void Logger::CreateLogFile()
{
    logFile.open(LOGFILE,std::ios_base::out);
    if(!logFile.is_open())
    {
        PRINT("Couldn't not create the log file! Exiting!");
        exit(1);
    }
	instanceSignalCallbacks();
}

void Logger::CloseLogFile()
{
    LOG("Fechando log");
    logFile.close();
}

Logger::~Logger()
{

}

void Logger::instanceSignalCallbacks()
{
#ifndef WIN32
	signal(SIGSEGV,signalCallbackHandler);
#endif
}

void Logger::generateBackTrace(std::vector<char *> &vec)
{
#ifndef WIN32
	const int maxbtsize = 64;
	int logsize = 0;
	void *bt[maxbtsize];
	char ** logTrace;
	logsize = backtrace(bt,maxbtsize);
	logTrace = backtrace_symbols(bt,maxbtsize);
	for(int i = 0; i < logsize; ++i)
		vec.push_back(logTrace[i]);
#endif

}

void Logger::signalCallbackHandler(int signum)
{
	std::vector<char *> vec;
    std::string logString;

	PRINT("Signal Number Received: " << signum << " \nClosing");
	generateBackTrace(vec);
    LOG("***** BACKTRACE *****");
	for(auto bt : vec)
    {
        LOG(bt);
        logString += bt;
        logString += "\n";
    }
    LOG("***** END *****");
	for(auto bt : vec)
		delete bt;

}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "ECSE/Common.h"

TEST(LerpTest, GeneralTest)
{
    ASSERT_EQ(5.0f, ECSE::lerp(0.f, 10.f, 0.5f));
}

TEST(LerpTest, ZeroTest)
{
    ASSERT_EQ(50.0f, ECSE::lerp(50.f, 100.f, 0.f));
}

TEST(LerpTest, OneTest)
{
    ASSERT_EQ(42.0f, ECSE::lerp(12.f, 42.f, 1.f));
}

TEST(LerpTest, NegativeTest)
{
    ASSERT_EQ(-12.0f, ECSE::lerp(-20.f, -10.f, 0.8f));
}

TEST(LerpTest, NegativeAlphaTest)
{
    ASSERT_EQ(-15.0f, ECSE::lerp(-5.f, 5.f, -1.f));
}

TEST(LerpTest, LargePositiveAlphaTest)
{
    ASSERT_EQ(15.0f, ECSE::lerp(-5.f, 5.f, 2.f));
}

TEST(ClampTest, MinTest)
{
    ASSERT_EQ(-10, ECSE::clamp(-10, 10, -50));
}

TEST(ClampTest, MaxTest)
{
    ASSERT_EQ(150, ECSE::clamp(50, 150, 200));
}

TEST(ClampTest, MiddleTest)
{
    ASSERT_EQ(-50, ECSE::clamp(-100, -10, -50));
}

TEST(WrapDifferenceTest, LeftTest)
{
    ASSERT_EQ(-1.f, ECSE::wrapDifference(0.5f, 2.5f, 3.f));
}

TEST(WrapDifferenceTest, RightTest)
{
    ASSERT_EQ(1.f, ECSE::wrapDifference(2.5f, 0.5f, 3.f));
}

TEST(WrapDifferenceTest, NegativeLeftTest)
{
    ASSERT_EQ(1.f, ECSE::wrapDifference(-0.5f, -2.5f, -3.f));
}

TEST(WrapDifferenceTest, NegativeRightTest)
{
    ASSERT_EQ(-1.f, ECSE::wrapDifference(-2.5f, -0.5f, -3.f));
}

TEST(WrapDifferenceTest, BothLeftTest)
{
    ASSERT_EQ(1.f, ECSE::wrapDifference(-2.5f, 1.5f, -3.f));
}

TEST(WrapDifferenceTest, BothRightTest)
{
    ASSERT_EQ(-1.f, ECSE::wrapDifference(1.5f, -2.5f, -3.f));
}<commit_msg>Added a few tests for intervalMod<commit_after>#include "gtest/gtest.h"
#include "ECSE/Common.h"

TEST(IntervalModTest, PositivePositiveTest)
{
    ASSERT_FLOAT_EQ(2.0f, ECSE::intervalMod(6.0f, 4.0f));
}

TEST(IntervalModTest, PositiveNegativeTest)
{
    ASSERT_FLOAT_EQ(-2.0f, ECSE::intervalMod(6.0f, -4.0f));
}

TEST(IntervalModTest, NegativePositiveTest)
{
    ASSERT_FLOAT_EQ(2.0f, ECSE::intervalMod(-6.0f, 4.0f));
}

TEST(IntervalModTest, NegativeNegativeTest)
{
    ASSERT_FLOAT_EQ(-2.0f, ECSE::intervalMod(-6.0f, -4.0f));
}

TEST(LerpTest, GeneralTest)
{
    ASSERT_EQ(5.0f, ECSE::lerp(0.f, 10.f, 0.5f));
}

TEST(LerpTest, ZeroTest)
{
    ASSERT_EQ(50.0f, ECSE::lerp(50.f, 100.f, 0.f));
}

TEST(LerpTest, OneTest)
{
    ASSERT_EQ(42.0f, ECSE::lerp(12.f, 42.f, 1.f));
}

TEST(LerpTest, NegativeTest)
{
    ASSERT_EQ(-12.0f, ECSE::lerp(-20.f, -10.f, 0.8f));
}

TEST(LerpTest, NegativeAlphaTest)
{
    ASSERT_EQ(-15.0f, ECSE::lerp(-5.f, 5.f, -1.f));
}

TEST(LerpTest, LargePositiveAlphaTest)
{
    ASSERT_EQ(15.0f, ECSE::lerp(-5.f, 5.f, 2.f));
}

TEST(ClampTest, MinTest)
{
    ASSERT_EQ(-10, ECSE::clamp(-10, 10, -50));
}

TEST(ClampTest, MaxTest)
{
    ASSERT_EQ(150, ECSE::clamp(50, 150, 200));
}

TEST(ClampTest, MiddleTest)
{
    ASSERT_EQ(-50, ECSE::clamp(-100, -10, -50));
}

TEST(WrapDifferenceTest, LeftTest)
{
    ASSERT_EQ(-1.f, ECSE::wrapDifference(0.5f, 2.5f, 3.f));
}

TEST(WrapDifferenceTest, RightTest)
{
    ASSERT_EQ(1.f, ECSE::wrapDifference(2.5f, 0.5f, 3.f));
}

TEST(WrapDifferenceTest, NegativeLeftTest)
{
    ASSERT_EQ(1.f, ECSE::wrapDifference(-0.5f, -2.5f, -3.f));
}

TEST(WrapDifferenceTest, NegativeRightTest)
{
    ASSERT_EQ(-1.f, ECSE::wrapDifference(-2.5f, -0.5f, -3.f));
}

TEST(WrapDifferenceTest, BothLeftTest)
{
    ASSERT_EQ(1.f, ECSE::wrapDifference(-2.5f, 1.5f, -3.f));
}

TEST(WrapDifferenceTest, BothRightTest)
{
    ASSERT_EQ(-1.f, ECSE::wrapDifference(1.5f, -2.5f, -3.f));
}<|endoftext|>


<commit_before>#ifndef RDB_PROTOCOL_SCOPE_HPP_
#define RDB_PROTOCOL_SCOPE_HPP_

#include <deque>
#include <map>
#include <set>
#include <string>
#include <vector>

template <class T>
inline void assert_T(const T &) { }

template <>
inline void assert_T<boost::shared_ptr<scoped_cJSON_t> >(const boost::shared_ptr<scoped_cJSON_t> &j) {
    rassert(j);
}

template <class T>
class variable_scope_t {
public:
    void put_in_scope(const std::string &name, const T &t) {
        assert_T(t);
        rassert(!scopes.empty());
        scopes.front()[name] = t;
    }

    T get(const std::string &name) {
        for (typename scopes_t::iterator it  = scopes.begin();
                                         it != scopes.end();
                                         ++it) {
            typename std::map<std::string, T>::iterator jt = it->find(name);
            if (jt != it->end()) {
                return jt->second;
            }
        }

        unreachable("Variable not in scope, probably because the code fails to call is_in_scope().");
    }

    // Calling this only makes sense in the typechecker. All variables
    // are guranteed by the typechecker to be present at runtime.
    bool is_in_scope(const std::string &name) {
        for (typename scopes_t::iterator it  = scopes.begin();
                                         it != scopes.end();
                                         ++it) {
            typename std::map<std::string, T>::iterator jt = it->find(name);
            if (jt != it->end()) {
                return true;
            }
        }
        return false;
    }

    void push() {
        scopes.push_front(std::map<std::string, T>());
    }

    void pop() {
        scopes.pop_front();
    }

    // TODO(rntz): find a better way to do this.
    void dump(std::vector<std::string> *argnames, std::vector<T> *argvals) {
        std::set<std::string> seen;

        if (argnames) argnames->clear();
        argvals->clear();

        // Most recent scope is at front of deque, so we iterate in-order.
        for (typename std::list<std::map<std::string, T> >::iterator sit = scopes.begin(); sit != scopes.end(); ++sit) {
            for (typename std::map<std::string, T>::iterator it = sit->begin(); it != sit->end(); ++it) {
                // Earlier bindings take precedence over later ones.
                if (seen.count(it->first)) continue;

                seen.insert(it->first);
                if (argnames) argnames->push_back(it->first);
                argvals->push_back(it->second);
            }
        }
    }

    struct new_scope_t {
        explicit new_scope_t(variable_scope_t<T> *_parent)
            : parent(_parent)
        {
            parent->push();
        }
        new_scope_t(variable_scope_t<T> *_parent, const std::string &name, const T &t)
            : parent(_parent)
        {
            parent->push();
            parent->put_in_scope(name, t);
        }
        ~new_scope_t() {
            parent->pop();
        }

        variable_scope_t<T> *parent;
    };

    RDB_MAKE_ME_SERIALIZABLE_1(scopes);
private:
    typedef std::list<std::map<std::string, T> > scopes_t;
    scopes_t scopes;
};

/* an implicit_value_t allows for a specific implicit value to exist at certain
 * points in execution for example the argument to get attr is implicitly
 * defined to be the value of the row upon entering a filter,map etc.
 * implicit_value_t supports scopes for its values but does not allow looking
 * up values in any scope to the current one. */
template <class T>
class implicit_value_t {
public:
    implicit_value_t() {
        push();
    }

    void push() {
        scopes.push_front(boost::optional<T>());
    }

    void push(const T &t) {
        scopes.push_front(t);
    }

    void pop() {
        scopes.pop_front();
    }

    class impliciter_t {
    public:
        explicit impliciter_t(implicit_value_t *_parent)
            : parent(_parent)
        {
            parent->push();
        }

        impliciter_t(implicit_value_t *_parent, const T& t)
            : parent(_parent)
        {
            parent->push(t);
        }

        ~impliciter_t() {
            parent->pop();
        }
    private:
        implicit_value_t *parent;
    };

    bool has_value() {
        return scopes.front();
    }

    T get_value() {
        return *scopes.front();
    }

    RDB_MAKE_ME_SERIALIZABLE_1(scopes);
private:
    typedef std::list<boost::optional<T> > scopes_t;
    scopes_t scopes;
};

#endif  // RDB_PROTOCOL_SCOPE_HPP_
<commit_msg>fixing release build<commit_after>#ifndef RDB_PROTOCOL_SCOPE_HPP_
#define RDB_PROTOCOL_SCOPE_HPP_

#include <deque>
#include <map>
#include <set>
#include <string>
#include <vector>

template <class T>
inline void assert_T(const T &) { }

template <>
inline void assert_T<boost::shared_ptr<scoped_cJSON_t> >(DEBUG_VAR const boost::shared_ptr<scoped_cJSON_t> &j) {
    rassert(j);
}

template <class T>
class variable_scope_t {
public:
    void put_in_scope(const std::string &name, const T &t) {
        assert_T(t);
        rassert(!scopes.empty());
        scopes.front()[name] = t;
    }

    T get(const std::string &name) {
        for (typename scopes_t::iterator it  = scopes.begin();
                                         it != scopes.end();
                                         ++it) {
            typename std::map<std::string, T>::iterator jt = it->find(name);
            if (jt != it->end()) {
                return jt->second;
            }
        }

        unreachable("Variable not in scope, probably because the code fails to call is_in_scope().");
    }

    // Calling this only makes sense in the typechecker. All variables
    // are guranteed by the typechecker to be present at runtime.
    bool is_in_scope(const std::string &name) {
        for (typename scopes_t::iterator it  = scopes.begin();
                                         it != scopes.end();
                                         ++it) {
            typename std::map<std::string, T>::iterator jt = it->find(name);
            if (jt != it->end()) {
                return true;
            }
        }
        return false;
    }

    void push() {
        scopes.push_front(std::map<std::string, T>());
    }

    void pop() {
        scopes.pop_front();
    }

    // TODO(rntz): find a better way to do this.
    void dump(std::vector<std::string> *argnames, std::vector<T> *argvals) {
        std::set<std::string> seen;

        if (argnames) argnames->clear();
        argvals->clear();

        // Most recent scope is at front of deque, so we iterate in-order.
        for (typename std::list<std::map<std::string, T> >::iterator sit = scopes.begin(); sit != scopes.end(); ++sit) {
            for (typename std::map<std::string, T>::iterator it = sit->begin(); it != sit->end(); ++it) {
                // Earlier bindings take precedence over later ones.
                if (seen.count(it->first)) continue;

                seen.insert(it->first);
                if (argnames) argnames->push_back(it->first);
                argvals->push_back(it->second);
            }
        }
    }

    struct new_scope_t {
        explicit new_scope_t(variable_scope_t<T> *_parent)
            : parent(_parent)
        {
            parent->push();
        }
        new_scope_t(variable_scope_t<T> *_parent, const std::string &name, const T &t)
            : parent(_parent)
        {
            parent->push();
            parent->put_in_scope(name, t);
        }
        ~new_scope_t() {
            parent->pop();
        }

        variable_scope_t<T> *parent;
    };

    RDB_MAKE_ME_SERIALIZABLE_1(scopes);
private:
    typedef std::list<std::map<std::string, T> > scopes_t;
    scopes_t scopes;
};

/* an implicit_value_t allows for a specific implicit value to exist at certain
 * points in execution for example the argument to get attr is implicitly
 * defined to be the value of the row upon entering a filter,map etc.
 * implicit_value_t supports scopes for its values but does not allow looking
 * up values in any scope to the current one. */
template <class T>
class implicit_value_t {
public:
    implicit_value_t() {
        push();
    }

    void push() {
        scopes.push_front(boost::optional<T>());
    }

    void push(const T &t) {
        scopes.push_front(t);
    }

    void pop() {
        scopes.pop_front();
    }

    class impliciter_t {
    public:
        explicit impliciter_t(implicit_value_t *_parent)
            : parent(_parent)
        {
            parent->push();
        }

        impliciter_t(implicit_value_t *_parent, const T& t)
            : parent(_parent)
        {
            parent->push(t);
        }

        ~impliciter_t() {
            parent->pop();
        }
    private:
        implicit_value_t *parent;
    };

    bool has_value() {
        return scopes.front();
    }

    T get_value() {
        return *scopes.front();
    }

    RDB_MAKE_ME_SERIALIZABLE_1(scopes);
private:
    typedef std::list<boost::optional<T> > scopes_t;
    scopes_t scopes;
};

#endif  // RDB_PROTOCOL_SCOPE_HPP_
<|endoftext|>


<commit_before>/*Copyright 2011 George Karagoulis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

#include <QtCore/QString>
#include <QtTest/QtTest>
#include "BinarySearchTree.h"
#include <iostream>
#include <vector>
GUTIL_USING_CORE_NAMESPACE(DataObjects);
using namespace std;

class BST_TestTest :
        public QObject
{
    Q_OBJECT

public:
    BST_TestTest();

private Q_SLOTS:

    void test_iterators();
    void test_basic_function();

    void test_compare();

    void test_insertions();
    void test_deletions();

    void test_pointers();

    void test_load();

private:
    static void show_depth_first_tree(const BinarySearchTree<int> &);

    static void show_breadth_first_tree(const BinarySearchTree<int> &);
    static void show_breadth_first_pointerTree(const BinarySearchTree<int *> &);

    static QString get_bft_string(const BST_NodeIterator<int> &iter);
    static QString get_bft_pointer_string(const BST_NodeIterator<int *> &);

    // You can feed in your own manual breadth-first description to test if
    //  the tree looks like you expect
    static bool tree_matches(const BinarySearchTree<int> &, const QString &);
    static bool tree_matches(const BinarySearchTree<int *> &, const QString &);

    static int backwards_compare(const int &, const int &);

    static int pointer_compare(int* const &, int* const &);

    static void verify_tree(const BinarySearchTree<int> &);

    static vector<int> export_df_tree(const BinarySearchTree<int> &);
};

void BST_TestTest::verify_tree(const BinarySearchTree<int> &bst)
{
    int mycnt(0);
    int mem(-1);
    for(BinarySearchTree<int>::const_iterator iter(bst.begin());
        iter != bst.end();
        iter++, mycnt++)
    {
        // Make sure all items are in order
        QVERIFY(mem < *iter);
        mem = *iter;
    }
    QVERIFY(mycnt == bst.size());
}

BST_TestTest::BST_TestTest()
{
    qsrand(QDateTime::currentDateTime().time().msec());
}

void BST_TestTest::test_iterators()
{
    BinarySearchTree<int> bst;
    bst.Add(3);
    bst.Add(5);
    bst.Add(1);
    QVERIFY(bst.size() == 3);
    QVERIFY(bst.min() == 1);
    QVERIFY(bst.max() == 5);

    verify_tree(bst);

    // Try iterating backwards
    int mem = INT_MAX;
    for(BinarySearchTree<int>::const_iterator iter(--bst.end());
        iter >= bst.begin();
        iter--)
    {
        // Make sure all items are in order
        QVERIFY(mem > *iter);
        mem = *iter;
    }
}

void BST_TestTest::test_basic_function()
{
    BinarySearchTree<int> bst;
    for(int i(1); i < 10; i++)
    {
        bst.Add(i);
        //cout<<"Step "<<i<<": ";
        //show_breadth_first_tree(bst);
    }
    show_depth_first_tree(bst);
    show_breadth_first_tree(bst);

    // Verify that the numbers are sorted
    vector<int> df( export_df_tree(bst) );
    QVERIFY(df.size() == 9);
    for(int i(0); i < (int)df.size(); i++)
        QVERIFY(df.at(i) == i + 1);

    bst.Clear();

    for(int i(9); i >= 1; i--)
        bst.Add(i);
    show_depth_first_tree(bst);
    show_breadth_first_tree(bst);

    // Verify that the numbers are sorted
    df = export_df_tree(bst);
    QVERIFY(df.size() == 9);
    for(int i(0); i < (int)df.size(); i++)
        QVERIFY(df.at(i) == i + 1);

    bst.Clear();

    // Add random numbers
    for(int i(0); i < 20; i++)
    {
        int new_num(qrand() % 1000);
        while(bst.Contains(new_num)) new_num = qrand() % 100;
        bst.Add(new_num);
    }

    show_depth_first_tree(bst);
}

class backwards_comparer : public GUtil::Core::Interfaces::IComparer<int>
{
    int Compare(const int &lhs, const int &rhs) const{
        if(lhs < rhs)
            return 1;
        else if(rhs < lhs)
            return -1;
        return 0;
    }
};

void BST_TestTest::test_compare()
{
    BinarySearchTree<int> backwards_tree(new backwards_comparer);
    for(int i(1); i < 10; i++)
        backwards_tree.Add(i);

    show_depth_first_tree(backwards_tree);
    show_breadth_first_tree(backwards_tree);

    // Verify that it sorted the numbers backwards
    vector<int> df( export_df_tree(backwards_tree) );
    QVERIFY(df.size() == 9);
    for(int i(0); i < (int)df.size(); i++)
        QVERIFY(df.at(i) == 9 - i);
}

void BST_TestTest::show_depth_first_tree(const BinarySearchTree<int> &t)
{
    cout<<"DF: ";
    vector<int> sorted_values(export_df_tree(t));
    for(int i(0); i < (int)sorted_values.size(); i++)
        cout<<sorted_values[i]<<" ";
    cout<<endl;
}

void BST_TestTest::show_breadth_first_tree(const BinarySearchTree<int> &t)
{
    cout<<"BF: ";
    cout<<get_bft_string(BST_NodeIterator<int>(t)).toStdString();
    cout<<endl;
}

void BST_TestTest::show_breadth_first_pointerTree(const BinarySearchTree<int *> &t)
{
    cout<<"BF: ";
    cout<<get_bft_pointer_string(BST_NodeIterator<int *>(t)).toStdString();
    cout<<endl;
}

QString BST_TestTest::get_bft_string(const BST_NodeIterator<int> &i)
{
    QString ret;
    BST_NodeIterator<int> iter(i);

    ret.append(QString("(%1, ").arg(iter.Value()));
    if(iter.CanDescendLeft())
    {
        iter.DescendLeft();
        ret.append(get_bft_string(iter));
        iter.Ascend();
    }
    ret.append(", ");
    if(iter.CanDescendRight())
    {
        iter.DescendRight();
        ret.append(get_bft_string(iter));
        iter.Ascend();
    }
    ret.append(")");

    return ret;
}

QString BST_TestTest::get_bft_pointer_string(const BST_NodeIterator<int *> &i)
{
    QString ret;
    BST_NodeIterator<int *> iter(i);

    ret.append(QString("(%1, ").arg(*iter.Value()));
    if(iter.CanDescendLeft())
    {
        iter.DescendLeft();
        ret.append(get_bft_pointer_string(iter));
        iter.Ascend();
    }
    ret.append(", ");
    if(iter.CanDescendRight())
    {
        iter.DescendRight();
        ret.append(get_bft_pointer_string(iter));
        iter.Ascend();
    }
    ret.append(")");

    return ret;
}

bool BST_TestTest::tree_matches(const BinarySearchTree<int *> &t, const QString &s)
{
    bool ret = get_bft_pointer_string(BST_NodeIterator<int *>(t)) == s;
    if(!ret)
    {
        cout<< get_bft_pointer_string(BST_NodeIterator<int *>(t)).toStdString() <<"\tNot equal to:"<<endl<<s.toStdString()<<endl;
    }
    return ret;
}

bool BST_TestTest::tree_matches(const BinarySearchTree<int> &t, const QString &s)
{
    bool ret = get_bft_string(BST_NodeIterator<int>(t)) == s;
    if(!ret)
    {
        cout<< get_bft_string(BST_NodeIterator<int>(t)).toStdString() <<"\tNot equal to:"<<endl<<s.toStdString()<<endl;
    }
    return ret;
}

void BST_TestTest::test_insertions()
{
    // Test the 4 cases of rebalancing:  LL, RR, LR, RL
    BinarySearchTree<int> bst;

    // This tests the RR condition twice (Rotate left)
    bst.Add(5);
    bst.Add(10);
    bst.Add(15);
    bst.Add(20);
    bst.Add(25);
    QVERIFY(tree_matches(bst, "(10, (5, , ), (20, (15, , ), (25, , )))"));
    verify_tree(bst);

    // Then LL (Rotate Right)
    bst.Add(2);
    bst.Add(1);
    QVERIFY(tree_matches(bst, "(10, (2, (1, , ), (5, , )), (20, (15, , ), (25, , )))"));
    verify_tree(bst);

    // Then RL
    bst.Clear();
    bst.Add(5);
    bst.Add(10);
    bst.Add(9);
    QVERIFY(tree_matches(bst, "(9, (5, , ), (10, , ))"));
    verify_tree(bst);

    // Then LR
    bst.Clear();
    bst.Add(5);
    bst.Add(3);
    bst.Add(4);
    QVERIFY(tree_matches(bst, "(4, (3, , ), (5, , ))"));
    verify_tree(bst);
}

void BST_TestTest::test_deletions()
{
    BinarySearchTree<int> bst;

    // Test root node deletion first
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Remove(2);
    verify_tree(bst);
    QVERIFY(bst.size() == 2);

    // Delete LChild of root
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Remove(1);
    verify_tree(bst);
    QVERIFY(bst.size() == 2);

    // Delete RChild of root
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Remove(3);
    verify_tree(bst);
    QVERIFY(bst.size() == 2);

    // Delete root, replacement has no child
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(4);
    bst.Add(3);
    bst.Remove(2);
    show_breadth_first_tree(bst);
    verify_tree(bst);

    // Delete root, replacement has child
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Add(4);
    bst.Remove(2);
    verify_tree(bst);

    // Delete root, replacement (left) has no child
    bst.Clear();
    bst.Add(0);
    bst.Add(2);
    bst.Add(3);
    bst.Add(1);
    bst.Remove(2);
    verify_tree(bst);

    // Delete root, replacement (left) has child
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Add(0);
    bst.Remove(2);
    verify_tree(bst);

    bst.Clear();
    const int cnt(50);
    const int max(5000);
    QList<int> record;
    for(int i = 0; i < cnt; i++)
    {
        int tmp(qrand() % max);
        while(bst.Contains(tmp))
            tmp = qrand() % max;
        record.append(tmp);
        bst.Add(tmp);
    }
    verify_tree(bst);

    for(int i = 0; i < cnt; i++)
    {
        show_breadth_first_tree(bst);
        bst.Remove(record[i]);
        verify_tree(bst);
        QVERIFY(bst.size() == cnt - i - 1);
    }
}

class pointer_comparer : public GUtil::Core::Interfaces::IComparer<int *>
{
    int Compare(int *const&lhs, int *const&rhs) const{
        if(*lhs < *rhs)
            return -1;
        else if(*rhs < *lhs)
            return 1;
        return 0;
    }
};

void BST_TestTest::test_pointers()
{
    BinarySearchTree<int *> pointer_tree(new pointer_comparer);
    int a(1), b(2), c(3);
    pointer_tree.Add(&a);
    pointer_tree.Add(&b);
    pointer_tree.Add(&c);

    show_breadth_first_pointerTree(pointer_tree);
    QVERIFY(tree_matches(pointer_tree, "(2, (1, , ), (3, , ))"));

    // Update the data pointed to and see if the tree data was also updated.
    a = 500;
    QVERIFY(tree_matches(pointer_tree, "(2, (500, , ), (3, , ))"));
    show_breadth_first_pointerTree(pointer_tree);
}

void BST_TestTest::test_load()
{
    BinarySearchTree<int> bst;
    const int num_items(1000000);

    cout<<QString("Inserting %1 items...").arg(num_items).toStdString()<<endl;
    for(int i(0); i < num_items; i++)
        bst.Add(i);
    cout<<"Finished inserting"<<endl;

    cout<<"Iterating through all values and checking that they're in sequence..."<<endl;
    verify_tree(bst);
    cout<<"Finished iterating"<<endl;
}

vector<int> BST_TestTest::export_df_tree(const BinarySearchTree<int> &t)
{
    vector<int> ret;
    for(BinarySearchTree<int>::const_iterator iter(t.begin()); iter != t.end(); iter++)
        ret.push_back(*iter);
    return ret;
}

QTEST_APPLESS_MAIN(BST_TestTest);

#include "tst_bst_testtest.moc"
<commit_msg>Suppressed the output on the test functions.  This is a solid test suite for now<commit_after>/*Copyright 2011 George Karagoulis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

#include <QtCore/QString>
#include <QtTest/QtTest>
#include "BinarySearchTree.h"
#include <iostream>
#include <vector>
GUTIL_USING_CORE_NAMESPACE(DataObjects);
using namespace std;

class BST_TestTest :
        public QObject
{
    Q_OBJECT

public:
    BST_TestTest();

private Q_SLOTS:

    void test_iterators();
    void test_basic_function();

    void test_compare();

    void test_insertions();
    void test_deletions();

    void test_pointers();

    void test_load();

private:
    static void show_depth_first_tree(const BinarySearchTree<int> &);

    static void show_breadth_first_tree(const BinarySearchTree<int> &);
    static void show_breadth_first_pointerTree(const BinarySearchTree<int *> &);

    static QString get_bft_string(const BST_NodeIterator<int> &iter);
    static QString get_bft_pointer_string(const BST_NodeIterator<int *> &);

    // You can feed in your own manual breadth-first description to test if
    //  the tree looks like you expect
    static bool tree_matches(const BinarySearchTree<int> &, const QString &);
    static bool tree_matches(const BinarySearchTree<int *> &, const QString &);

    static int backwards_compare(const int &, const int &);

    static int pointer_compare(int* const &, int* const &);

    static void verify_tree(const BinarySearchTree<int> &);

    static vector<int> export_df_tree(const BinarySearchTree<int> &);
};

void BST_TestTest::verify_tree(const BinarySearchTree<int> &bst)
{
    int mycnt(0);
    int mem(-1);
    for(BinarySearchTree<int>::const_iterator iter(bst.begin());
        iter != bst.end();
        iter++, mycnt++)
    {
        // Make sure all items are in order
        QVERIFY(mem < *iter);
        mem = *iter;
    }
    QVERIFY(mycnt == bst.size());
}

BST_TestTest::BST_TestTest()
{
    qsrand(QDateTime::currentDateTime().time().msec());
}

void BST_TestTest::test_iterators()
{
    BinarySearchTree<int> bst;
    bst.Add(3);
    bst.Add(5);
    bst.Add(1);
    QVERIFY(bst.size() == 3);
    QVERIFY(bst.min() == 1);
    QVERIFY(bst.max() == 5);

    verify_tree(bst);

    // Try iterating backwards
    int mem = INT_MAX;
    for(BinarySearchTree<int>::const_iterator iter(--bst.end());
        iter >= bst.begin();
        iter--)
    {
        // Make sure all items are in order
        QVERIFY(mem > *iter);
        mem = *iter;
    }
}

void BST_TestTest::test_basic_function()
{
    BinarySearchTree<int> bst;
    for(int i(1); i < 10; i++)
    {
        bst.Add(i);
        //cout<<"Step "<<i<<": ";
        //show_breadth_first_tree(bst);
    }
    //show_depth_first_tree(bst);
    //show_breadth_first_tree(bst);

    // Verify that the numbers are sorted
    verify_tree(bst);

    bst.Clear();

    for(int i(9); i >= 1; i--)
        bst.Add(i);
    verify_tree(bst);

    bst.Clear();

    // Add random numbers
    for(int i(0); i < 20; i++)
    {
        int new_num(qrand() % 1000);
        while(bst.Contains(new_num)) new_num = qrand() % 100;
        bst.Add(new_num);
    }
    verify_tree(bst);

    //show_depth_first_tree(bst);
}

class backwards_comparer : public GUtil::Core::Interfaces::IComparer<int>
{
    int Compare(const int &lhs, const int &rhs) const{
        if(lhs < rhs)
            return 1;
        else if(rhs < lhs)
            return -1;
        return 0;
    }
};

void BST_TestTest::test_compare()
{
    BinarySearchTree<int> backwards_tree(new backwards_comparer);
    for(int i(1); i < 10; i++)
        backwards_tree.Add(i);

    //show_depth_first_tree(backwards_tree);
    //show_breadth_first_tree(backwards_tree);

    // Verify that it sorted the numbers backwards
    vector<int> df( export_df_tree(backwards_tree) );
    QVERIFY(df.size() == 9);
    for(int i(0); i < (int)df.size(); i++)
        QVERIFY(df.at(i) == 9 - i);
}

void BST_TestTest::show_depth_first_tree(const BinarySearchTree<int> &t)
{
    cout<<"DF: ";
    vector<int> sorted_values(export_df_tree(t));
    for(int i(0); i < (int)sorted_values.size(); i++)
        cout<<sorted_values[i]<<" ";
    cout<<endl;
}

void BST_TestTest::show_breadth_first_tree(const BinarySearchTree<int> &t)
{
    cout<<"BF: ";
    cout<<get_bft_string(BST_NodeIterator<int>(t)).toStdString();
    cout<<endl;
}

void BST_TestTest::show_breadth_first_pointerTree(const BinarySearchTree<int *> &t)
{
    cout<<"BF: ";
    cout<<get_bft_pointer_string(BST_NodeIterator<int *>(t)).toStdString();
    cout<<endl;
}

QString BST_TestTest::get_bft_string(const BST_NodeIterator<int> &i)
{
    QString ret;
    BST_NodeIterator<int> iter(i);

    ret.append(QString("(%1, ").arg(iter.Value()));
    if(iter.CanDescendLeft())
    {
        iter.DescendLeft();
        ret.append(get_bft_string(iter));
        iter.Ascend();
    }
    ret.append(", ");
    if(iter.CanDescendRight())
    {
        iter.DescendRight();
        ret.append(get_bft_string(iter));
        iter.Ascend();
    }
    ret.append(")");

    return ret;
}

QString BST_TestTest::get_bft_pointer_string(const BST_NodeIterator<int *> &i)
{
    QString ret;
    BST_NodeIterator<int *> iter(i);

    ret.append(QString("(%1, ").arg(*iter.Value()));
    if(iter.CanDescendLeft())
    {
        iter.DescendLeft();
        ret.append(get_bft_pointer_string(iter));
        iter.Ascend();
    }
    ret.append(", ");
    if(iter.CanDescendRight())
    {
        iter.DescendRight();
        ret.append(get_bft_pointer_string(iter));
        iter.Ascend();
    }
    ret.append(")");

    return ret;
}

bool BST_TestTest::tree_matches(const BinarySearchTree<int *> &t, const QString &s)
{
    bool ret = get_bft_pointer_string(BST_NodeIterator<int *>(t)) == s;
    if(!ret)
    {
        cout<< get_bft_pointer_string(BST_NodeIterator<int *>(t)).toStdString() <<"\tNot equal to:"<<endl<<s.toStdString()<<endl;
    }
    return ret;
}

bool BST_TestTest::tree_matches(const BinarySearchTree<int> &t, const QString &s)
{
    bool ret = get_bft_string(BST_NodeIterator<int>(t)) == s;
    if(!ret)
    {
        cout<< get_bft_string(BST_NodeIterator<int>(t)).toStdString() <<"\tNot equal to:"<<endl<<s.toStdString()<<endl;
    }
    return ret;
}

void BST_TestTest::test_insertions()
{
    // Test the 4 cases of rebalancing:  LL, RR, LR, RL
    BinarySearchTree<int> bst;

    // This tests the RR condition twice (Rotate left)
    bst.Add(5);
    bst.Add(10);
    bst.Add(15);
    bst.Add(20);
    bst.Add(25);
    QVERIFY(tree_matches(bst, "(10, (5, , ), (20, (15, , ), (25, , )))"));
    verify_tree(bst);

    // Then LL (Rotate Right)
    bst.Add(2);
    bst.Add(1);
    QVERIFY(tree_matches(bst, "(10, (2, (1, , ), (5, , )), (20, (15, , ), (25, , )))"));
    verify_tree(bst);

    // Then RL
    bst.Clear();
    bst.Add(5);
    bst.Add(10);
    bst.Add(9);
    QVERIFY(tree_matches(bst, "(9, (5, , ), (10, , ))"));
    verify_tree(bst);

    // Then LR
    bst.Clear();
    bst.Add(5);
    bst.Add(3);
    bst.Add(4);
    QVERIFY(tree_matches(bst, "(4, (3, , ), (5, , ))"));
    verify_tree(bst);
}

void BST_TestTest::test_deletions()
{
    BinarySearchTree<int> bst;

    // Test root node deletion first
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Remove(2);
    verify_tree(bst);
    QVERIFY(bst.size() == 2);

    // Delete LChild of root
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Remove(1);
    verify_tree(bst);
    QVERIFY(bst.size() == 2);

    // Delete RChild of root
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Remove(3);
    verify_tree(bst);
    QVERIFY(bst.size() == 2);

    // Delete root, replacement has no child
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(4);
    bst.Add(3);
    bst.Remove(2);
    //show_breadth_first_tree(bst);
    verify_tree(bst);

    // Delete root, replacement has child, and replacement is child of root
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Add(4);
    bst.Remove(2);
    verify_tree(bst);

    // Delete root, replacement has child, and replacement is not child of root
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(10);
    bst.Add(11);
    bst.Add(0);
    bst.Add(8);
    bst.Add(9);
    //show_breadth_first_tree(bst);
    bst.Remove(2);
    //show_breadth_first_tree(bst);
    verify_tree(bst);

    // Delete root, replacement (left) has no child
    bst.Clear();
    bst.Add(0);
    bst.Add(2);
    bst.Add(3);
    bst.Add(1);
    bst.Remove(2);
    verify_tree(bst);

    // Delete root, replacement (left) has child, and replacement is child of root
    bst.Clear();
    bst.Add(1);
    bst.Add(2);
    bst.Add(3);
    bst.Add(0);
    bst.Remove(2);
    verify_tree(bst);

    // Delete root, replacement has child, and replacement is not child of root
    bst.Clear();
    bst.Add(2);
    bst.Add(6);
    bst.Add(7);
    bst.Add(8);
    bst.Add(0);
    bst.Add(5);
    bst.Add(4);
    //show_breadth_first_tree(bst);
    bst.Remove(6);
    //show_breadth_first_tree(bst);
    verify_tree(bst);

    bst.Clear();
    const int cnt(50);
    const int max(5000);
    QList<int> record;
    for(int i = 0; i < cnt; i++)
    {
        int tmp(qrand() % max);
        while(bst.Contains(tmp))
            tmp = qrand() % max;
        record.append(tmp);
        bst.Add(tmp);
    }
    verify_tree(bst);

    for(int i = 0; i < cnt; i++)
    {
        //show_breadth_first_tree(bst);
        bst.Remove(record[i]);
        verify_tree(bst);
        QVERIFY(bst.size() == cnt - i - 1);
    }
}

class pointer_comparer : public GUtil::Core::Interfaces::IComparer<int *>
{
    int Compare(int *const&lhs, int *const&rhs) const{
        if(*lhs < *rhs)
            return -1;
        else if(*rhs < *lhs)
            return 1;
        return 0;
    }
};

void BST_TestTest::test_pointers()
{
    BinarySearchTree<int *> pointer_tree(new pointer_comparer);
    int a(1), b(2), c(3);
    pointer_tree.Add(&a);
    pointer_tree.Add(&b);
    pointer_tree.Add(&c);

    //show_breadth_first_pointerTree(pointer_tree);
    QVERIFY(tree_matches(pointer_tree, "(2, (1, , ), (3, , ))"));

    // Update the data pointed to and see if the tree data was also updated.
    a = 500;
    QVERIFY(tree_matches(pointer_tree, "(2, (500, , ), (3, , ))"));
    //show_breadth_first_pointerTree(pointer_tree);
}

void BST_TestTest::test_load()
{
    BinarySearchTree<int> bst;
    const int num_items(1000000);

    cout<<QString("Inserting %1 items...").arg(num_items).toStdString()<<endl;
    for(int i(0); i < num_items; i++)
        bst.Add(i);
    cout<<"Finished inserting"<<endl;

    cout<<"Iterating through all values and checking that they're in sequence..."<<endl;
    verify_tree(bst);
    cout<<"Finished iterating"<<endl;

    cout<<"Removing each value one by one..."<<endl;
    for(int i(0); i < num_items; i++)
        bst.Remove(i);
    cout<<"Finished removing"<<endl;
}

vector<int> BST_TestTest::export_df_tree(const BinarySearchTree<int> &t)
{
    vector<int> ret;
    for(BinarySearchTree<int>::const_iterator iter(t.begin()); iter != t.end(); iter++)
        ret.push_back(*iter);
    return ret;
}

QTEST_APPLESS_MAIN(BST_TestTest);

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


<commit_before>#ifndef __MUTEX_HPP__
#define __MUTEX_HPP__

struct mutex {
 private:
    uint8_t nr;
 public:
    mutex();
    void give();
    void take();
    void take(uint32_t timeout);
};

#endif /* __MUTEX_HPP__ */
<commit_msg>mutex function signature change<commit_after>#ifndef __MUTEX_HPP__
#define __MUTEX_HPP__

struct mutex {
 private:
    uint8_t nr;
 public:
    mutex();
    void give();
    void take();
    bool take(uint32_t timeout_ms);
};

#endif /* __MUTEX_HPP__ */
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2015 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder 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 HOLDER 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.
 */

#ifndef __TLB_COALESCER_HH__
#define __TLB_COALESCER_HH__

#include <list>
#include <queue>
#include <string>
#include <vector>

#include "arch/generic/tlb.hh"
#include "arch/x86/isa.hh"
#include "arch/x86/pagetable.hh"
#include "arch/x86/regs/segment.hh"
#include "base/logging.hh"
#include "base/statistics.hh"
#include "gpu-compute/gpu_tlb.hh"
#include "mem/port.hh"
#include "mem/request.hh"
#include "params/TLBCoalescer.hh"
#include "sim/clocked_object.hh"

namespace gem5
{

class BaseTLB;
class Packet;
class ThreadContext;

/**
 * The TLBCoalescer is a ClockedObject sitting on the front side (CPUSide) of
 * each TLB. It receives packets and issues coalesced requests to the
 * TLB below it. It controls how requests are coalesced (the rules)
 * and the permitted number of TLB probes per cycle (i.e., how many
 * coalesced requests it feeds the TLB per cycle).
 */
class TLBCoalescer : public ClockedObject
{
  public:
    typedef TLBCoalescerParams Params;
    TLBCoalescer(const Params &p);
    ~TLBCoalescer() { }

    // Number of TLB probes per cycle. Parameterizable - default 2.
    int TLBProbesPerCycle;

    // Consider coalescing across that many ticks.
    // Paraemterizable - default 1.
    int coalescingWindow;

    // Each coalesced request consists of multiple packets
    // that all fall within the same virtual page
    typedef std::vector<PacketPtr> coalescedReq;

    // disables coalescing when true
    bool disableCoalescing;

    /*
     * This is a hash map with <tick_index> as a key.
     * It contains a vector of coalescedReqs per <tick_index>.
     * Requests are buffered here until they can be issued to
     * the TLB, at which point they are copied to the
     * issuedTranslationsTable hash map.
     *
     * In terms of coalescing, we coalesce requests in a given
     * window of x cycles by using tick_index = issueTime/x as a
     * key, where x = coalescingWindow. issueTime is the issueTime
     * of the pkt from the ComputeUnit's perspective, but another
     * option is to change it to curTick(), so we coalesce based
     * on the receive time.
     */
    typedef std::unordered_map<int64_t, std::vector<coalescedReq>>
        CoalescingFIFO;

    CoalescingFIFO coalescerFIFO;

    /*
     * issuedTranslationsTabler: a hash_map indexed by virtual page
     * address. Each hash_map entry has a vector of PacketPtr associated
     * with it denoting the different packets that share an outstanding
     * coalesced translation request for the same virtual page.
     *
     * The rules that determine which requests we can coalesce are
     * specified in the canCoalesce() method.
     */
    typedef std::unordered_map<Addr, coalescedReq> CoalescingTable;

    CoalescingTable issuedTranslationsTable;

    bool canCoalesce(PacketPtr pkt1, PacketPtr pkt2);
    void updatePhysAddresses(PacketPtr pkt);

    class CpuSidePort : public ResponsePort
    {
      public:
        CpuSidePort(const std::string &_name, TLBCoalescer *tlb_coalescer,
                    PortID _index)
            : ResponsePort(_name, tlb_coalescer), coalescer(tlb_coalescer),
              index(_index) { }

      protected:
        TLBCoalescer *coalescer;
        int index;

        virtual bool recvTimingReq(PacketPtr pkt);
        virtual Tick recvAtomic(PacketPtr pkt) { return 0; }
        virtual void recvFunctional(PacketPtr pkt);
        virtual void recvRangeChange() { }
        virtual void recvReqRetry();

        virtual void
        recvRespRetry()
        {
            fatal("recvRespRetry() is not implemented in the TLB "
                "coalescer.\n");
        }

        virtual AddrRangeList getAddrRanges() const;
    };

    class MemSidePort : public RequestPort
    {
      public:
        MemSidePort(const std::string &_name, TLBCoalescer *tlb_coalescer,
                    PortID _index)
            : RequestPort(_name, tlb_coalescer), coalescer(tlb_coalescer),
              index(_index) { }

        std::deque<PacketPtr> retries;

      protected:
        TLBCoalescer *coalescer;
        int index;

        virtual bool recvTimingResp(PacketPtr pkt);
        virtual Tick recvAtomic(PacketPtr pkt) { return 0; }
        virtual void recvFunctional(PacketPtr pkt);
        virtual void recvRangeChange() { }
        virtual void recvReqRetry();

        virtual void
        recvRespRetry()
        {
            fatal("recvRespRetry() not implemented in TLB coalescer");
        }
    };

    // Coalescer response ports on the cpu Side
    std::vector<CpuSidePort*> cpuSidePort;
    // Coalescer request ports on the memory side
    std::vector<MemSidePort*> memSidePort;

    Port &getPort(const std::string &if_name,
                  PortID idx=InvalidPortID) override;

    void processProbeTLBEvent();
    /// This event issues the TLB probes
    EventFunctionWrapper probeTLBEvent;

    void processCleanupEvent();
    /// The cleanupEvent is scheduled after a TLBEvent triggers
    /// in order to free memory and do the required clean-up
    EventFunctionWrapper cleanupEvent;

    // this FIFO queue keeps track of the virt. page
    // addresses that are pending cleanup
    std::queue<Addr> cleanupQueue;

  protected:
    struct TLBCoalescerStats : public statistics::Group
    {
        TLBCoalescerStats(statistics::Group *parent);

        // number of packets the coalescer receives
        statistics::Scalar uncoalescedAccesses;
        // number packets the coalescer send to the TLB
        statistics::Scalar coalescedAccesses;

        // Number of cycles the coalesced requests spend waiting in
        // coalescerFIFO. For each packet the coalescer receives we take into
        // account the number of all uncoalesced requests this pkt "represents"
        statistics::Scalar queuingCycles;

        // On average how much time a request from the
        // uncoalescedAccesses that reaches the TLB
        // spends waiting?
        statistics::Scalar localqueuingCycles;
        // localqueuingCycles/uncoalescedAccesses
        statistics::Formula localLatency;
    } stats;
};

} // namespace gem5

#endif // __TLB_COALESCER_HH__
<commit_msg>gpu-compute: Fix TLB coalescer starvation<commit_after>/*
 * Copyright (c) 2011-2015 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder 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 HOLDER 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.
 */

#ifndef __TLB_COALESCER_HH__
#define __TLB_COALESCER_HH__

#include <list>
#include <queue>
#include <string>
#include <vector>

#include "arch/generic/tlb.hh"
#include "arch/x86/isa.hh"
#include "arch/x86/pagetable.hh"
#include "arch/x86/regs/segment.hh"
#include "base/logging.hh"
#include "base/statistics.hh"
#include "gpu-compute/gpu_tlb.hh"
#include "mem/port.hh"
#include "mem/request.hh"
#include "params/TLBCoalescer.hh"
#include "sim/clocked_object.hh"

namespace gem5
{

class BaseTLB;
class Packet;
class ThreadContext;

/**
 * The TLBCoalescer is a ClockedObject sitting on the front side (CPUSide) of
 * each TLB. It receives packets and issues coalesced requests to the
 * TLB below it. It controls how requests are coalesced (the rules)
 * and the permitted number of TLB probes per cycle (i.e., how many
 * coalesced requests it feeds the TLB per cycle).
 */
class TLBCoalescer : public ClockedObject
{
  public:
    typedef TLBCoalescerParams Params;
    TLBCoalescer(const Params &p);
    ~TLBCoalescer() { }

    // Number of TLB probes per cycle. Parameterizable - default 2.
    int TLBProbesPerCycle;

    // Consider coalescing across that many ticks.
    // Paraemterizable - default 1.
    int coalescingWindow;

    // Each coalesced request consists of multiple packets
    // that all fall within the same virtual page
    typedef std::vector<PacketPtr> coalescedReq;

    // disables coalescing when true
    bool disableCoalescing;

    /*
     * This is a hash map with <tick_index> as a key.
     * It contains a vector of coalescedReqs per <tick_index>.
     * Requests are buffered here until they can be issued to
     * the TLB, at which point they are copied to the
     * issuedTranslationsTable hash map.
     *
     * In terms of coalescing, we coalesce requests in a given
     * window of x cycles by using tick_index = issueTime/x as a
     * key, where x = coalescingWindow. issueTime is the issueTime
     * of the pkt from the ComputeUnit's perspective, but another
     * option is to change it to curTick(), so we coalesce based
     * on the receive time.
     */
    typedef std::map<int64_t, std::vector<coalescedReq>>
        CoalescingFIFO;

    CoalescingFIFO coalescerFIFO;

    /*
     * issuedTranslationsTabler: a hash_map indexed by virtual page
     * address. Each hash_map entry has a vector of PacketPtr associated
     * with it denoting the different packets that share an outstanding
     * coalesced translation request for the same virtual page.
     *
     * The rules that determine which requests we can coalesce are
     * specified in the canCoalesce() method.
     */
    typedef std::unordered_map<Addr, coalescedReq> CoalescingTable;

    CoalescingTable issuedTranslationsTable;

    bool canCoalesce(PacketPtr pkt1, PacketPtr pkt2);
    void updatePhysAddresses(PacketPtr pkt);

    class CpuSidePort : public ResponsePort
    {
      public:
        CpuSidePort(const std::string &_name, TLBCoalescer *tlb_coalescer,
                    PortID _index)
            : ResponsePort(_name, tlb_coalescer), coalescer(tlb_coalescer),
              index(_index) { }

      protected:
        TLBCoalescer *coalescer;
        int index;

        virtual bool recvTimingReq(PacketPtr pkt);
        virtual Tick recvAtomic(PacketPtr pkt) { return 0; }
        virtual void recvFunctional(PacketPtr pkt);
        virtual void recvRangeChange() { }
        virtual void recvReqRetry();

        virtual void
        recvRespRetry()
        {
            fatal("recvRespRetry() is not implemented in the TLB "
                "coalescer.\n");
        }

        virtual AddrRangeList getAddrRanges() const;
    };

    class MemSidePort : public RequestPort
    {
      public:
        MemSidePort(const std::string &_name, TLBCoalescer *tlb_coalescer,
                    PortID _index)
            : RequestPort(_name, tlb_coalescer), coalescer(tlb_coalescer),
              index(_index) { }

        std::deque<PacketPtr> retries;

      protected:
        TLBCoalescer *coalescer;
        int index;

        virtual bool recvTimingResp(PacketPtr pkt);
        virtual Tick recvAtomic(PacketPtr pkt) { return 0; }
        virtual void recvFunctional(PacketPtr pkt);
        virtual void recvRangeChange() { }
        virtual void recvReqRetry();

        virtual void
        recvRespRetry()
        {
            fatal("recvRespRetry() not implemented in TLB coalescer");
        }
    };

    // Coalescer response ports on the cpu Side
    std::vector<CpuSidePort*> cpuSidePort;
    // Coalescer request ports on the memory side
    std::vector<MemSidePort*> memSidePort;

    Port &getPort(const std::string &if_name,
                  PortID idx=InvalidPortID) override;

    void processProbeTLBEvent();
    /// This event issues the TLB probes
    EventFunctionWrapper probeTLBEvent;

    void processCleanupEvent();
    /// The cleanupEvent is scheduled after a TLBEvent triggers
    /// in order to free memory and do the required clean-up
    EventFunctionWrapper cleanupEvent;

    // this FIFO queue keeps track of the virt. page
    // addresses that are pending cleanup
    std::queue<Addr> cleanupQueue;

  protected:
    struct TLBCoalescerStats : public statistics::Group
    {
        TLBCoalescerStats(statistics::Group *parent);

        // number of packets the coalescer receives
        statistics::Scalar uncoalescedAccesses;
        // number packets the coalescer send to the TLB
        statistics::Scalar coalescedAccesses;

        // Number of cycles the coalesced requests spend waiting in
        // coalescerFIFO. For each packet the coalescer receives we take into
        // account the number of all uncoalesced requests this pkt "represents"
        statistics::Scalar queuingCycles;

        // On average how much time a request from the
        // uncoalescedAccesses that reaches the TLB
        // spends waiting?
        statistics::Scalar localqueuingCycles;
        // localqueuingCycles/uncoalescedAccesses
        statistics::Formula localLatency;
    } stats;
};

} // namespace gem5

#endif // __TLB_COALESCER_HH__
<|endoftext|>