<commit_before>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> 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 EARLIER MENTIONED AUTHORS ``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 <copyright holder> 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.
 */
#include "CppUTest/TestHarness.h"
#include "CppUTest/FailableMemoryAllocator.h"
#include "CppUTest/TestTestingFixture.h"

// Allocator must be global. Otherwise, it does not exist when memory leak detector
// reports memory leaks.
static FailableMemoryAllocator failableMallocAllocator("Failable malloc");

TEST_GROUP(FailableMemoryAllocator)
{
    TestTestingFixture *fixture;

    void setup()
    {
        fixture = new TestTestingFixture;
        failableMallocAllocator.clearFailedAllocations();
        setCurrentMallocAllocator(&failableMallocAllocator);
    }
    void teardown()
    {
        setCurrentMallocAllocatorToDefault();
        delete fixture;
    }
};

TEST(FailableMemoryAllocator, MallocWorksNormallyIfNotAskedToFail)
{
    int *memory = (int*)malloc(sizeof(int));
    *memory = 1;
    CHECK(memory != NULL);
    free(memory);
}

TEST(FailableMemoryAllocator, FailFirstMalloc)
{
    failableMallocAllocator.failAllocNumber(1);
    LONGS_EQUAL(NULL, (int*)malloc(sizeof(int)));
}

TEST(FailableMemoryAllocator, FailSecondAndFourthMalloc)
{
    failableMallocAllocator.failAllocNumber(2);
    failableMallocAllocator.failAllocNumber(4);
    int *memory1 = (int*)malloc(sizeof(int));
    int *memory2 = (int*)malloc(sizeof(int));
    int *memory3 = (int*)malloc(sizeof(int));
    int *memory4 = (int*)malloc(sizeof(int));

    CHECK(NULL != memory1);
    LONGS_EQUAL(NULL, memory2);
    CHECK(NULL != memory3);
    LONGS_EQUAL(NULL, memory4);

    free(memory1);
    free(memory3);
}

static void setUpTooManyFailedMallocs()
{
    FailableMemoryAllocator allocator;
    for (int i = 0; i <= allocator.MAX_NUMBER_OF_FAILED_ALLOCS; i++)
        allocator.failAllocNumber(i + 1);
}

TEST(FailableMemoryAllocator, SettingUpTooManyFailedAllocsWillFail)
{
    fixture->setTestFunction(setUpTooManyFailedMallocs);
    fixture->runAllTests();
    LONGS_EQUAL(1, fixture->getFailureCount());
    fixture->assertPrintContains("Maximum number of failed memory allocations exceeded");
}

<commit_msg>Tests for new<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> 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 EARLIER MENTIONED AUTHORS ``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 <copyright holder> 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.
 */
#include "CppUTest/TestHarness.h"
#include "CppUTest/FailableMemoryAllocator.h"
#include "CppUTest/TestTestingFixture.h"

// Allocator must be global. Otherwise, it does not exist when memory leak detector
// reports memory leaks.
static FailableMemoryAllocator failableMallocAllocator("failable malloc", "malloc", "free");
static FailableMemoryAllocator failableNewAllocator("failable new", "new", "delete");

TEST_GROUP(FailableMemoryAllocator)
{
    TestTestingFixture *fixture;

    void setup()
    {
        fixture = new TestTestingFixture;
        failableMallocAllocator.clearFailedAllocations();
        failableNewAllocator.clearFailedAllocations();
        setCurrentMallocAllocator(&failableMallocAllocator);
        setCurrentNewAllocator(&failableNewAllocator);
    }
    void teardown()
    {
        setCurrentMallocAllocatorToDefault();
        setCurrentNewAllocatorToDefault();
        delete fixture;
    }
};

TEST(FailableMemoryAllocator, MallocWorksNormallyIfNotAskedToFail)
{
    int *memory = (int*)malloc(sizeof(int));
    *memory = 1;
    CHECK(memory != NULL);
    free(memory);
}

TEST(FailableMemoryAllocator, FailFirstMalloc)
{
    failableMallocAllocator.failAllocNumber(1);
    LONGS_EQUAL(NULL, (int*)malloc(sizeof(int)));
}

TEST(FailableMemoryAllocator, FailSecondAndFourthMalloc)
{
    failableMallocAllocator.failAllocNumber(2);
    failableMallocAllocator.failAllocNumber(4);
    int *memory1 = (int*)malloc(sizeof(int));
    int *memory2 = (int*)malloc(sizeof(int));
    int *memory3 = (int*)malloc(sizeof(int));
    int *memory4 = (int*)malloc(sizeof(int));

    CHECK(NULL != memory1);
    LONGS_EQUAL(NULL, memory2);
    CHECK(NULL != memory3);
    LONGS_EQUAL(NULL, memory4);

    free(memory1);
    free(memory3);
}

static void _setUpTooManyFailedMallocs()
{
    FailableMemoryAllocator allocator;
    for (int i = 0; i <= allocator.MAX_NUMBER_OF_FAILED_ALLOCS; i++)
        allocator.failAllocNumber(i + 1);
}

TEST(FailableMemoryAllocator, SettingUpTooManyFailedAllocsWillFail)
{
    fixture->setTestFunction(_setUpTooManyFailedMallocs);
    fixture->runAllTests();
    LONGS_EQUAL(1, fixture->getFailureCount());
    fixture->assertPrintContains("Maximum number of failed memory allocations exceeded");
}

TEST(FailableMemoryAllocator, NewWorksNormallyIfNotAskedToFail)
{
    int *memory = new int;
    *memory = 1;
    CHECK(memory != NULL);
    delete memory;
}

#if CPPUTEST_USE_STD_CPP_LIB

TEST(FailableMemoryAllocator, FailSecondRaisesException)
{
    failableNewAllocator.failAllocNumber(2);
    int *memory1 = new int;

    CHECK_THROWS(std::bad_alloc, new int);

    delete memory1;
}

#endif

TEST(FailableMemoryAllocator, FailSecondAndFourthNewNoThrow)
{
#undef new
    failableNewAllocator.failAllocNumber(2);
    failableNewAllocator.failAllocNumber(4);
    int *memory1 = new (std::nothrow) int;
    int *memory2 = new (std::nothrow) int;
    int *memory3 = new (std::nothrow) int;
    int *memory4 = new (std::nothrow) int;

    CHECK(NULL != memory1);
    LONGS_EQUAL(NULL, memory2);
    CHECK(NULL != memory3);
    LONGS_EQUAL(NULL, memory4);

    delete memory1;
    delete memory3;
}
<|endoftext|>


<commit_before>#include "himan_unit.h"
#include "metutil.h"

#define BOOST_TEST_MODULE metutil

using namespace std;
using namespace himan;

const double kEpsilon = 1e-3;

BOOST_AUTO_TEST_CASE(LCL_SLOW)
{

	// "slow" calculation of LCL

	lcl_t LCL = himan::metutil::LCL_(85000,273.15 + 16.5828, 273.15 + -1.45402);

	BOOST_CHECK_CLOSE(LCL.P, 64829.6, kEpsilon);
	BOOST_CHECK_CLOSE(LCL.T, 273.15 + -5.01719, kEpsilon);
}

BOOST_AUTO_TEST_CASE(LCL_FAST)
{

        // fast calculation of LCL

	lcl_t LCL = himan::metutil::LCL_(85000,273.15 + 16.6453, 273.15 + -1.29777);

	BOOST_CHECK_CLOSE(LCL.P, 64878.5986, kEpsilon);
	BOOST_CHECK_CLOSE(LCL.T, 273.15 + -4.90058, kEpsilon);
}

BOOST_AUTO_TEST_CASE(LCL_SMARTTOOL_COMPATIBILITY)
{
	// testing if himan LCL is compatible with smarttool LCL

	double T = 16.5828;
	double Td = -1.45402;
	double P = 850;

	lcl_t LCL = himan::metutil::LCL_(P*100, 273.15 + T, 273.15 + Td);

	BOOST_CHECK_CLOSE(LCL.P, 100*647.3825, 1);

}

BOOST_AUTO_TEST_CASE(MIXING_RATIO)
{
	double TD = 4.2;
	double P = 850;

	double ratio = metutil::MixingRatio_(273.15 + TD, 100 * P);

	BOOST_CHECK_CLOSE(ratio, 6.0955, kEpsilon);
}

BOOST_AUTO_TEST_CASE(SATURATED_MIXING_RATIO)
{

	// saturated mixing ratio

	double ratio = metutil::MixingRatio_(290, 98000);

	BOOST_CHECK_CLOSE(ratio, 12.4395, kEpsilon);

}

BOOST_AUTO_TEST_CASE(ES)
{

	// water vapour pressure

	double E = metutil::Es_(285);

	BOOST_CHECK_CLOSE(E, 1389.859, kEpsilon);

	// negative temperatures

	E = metutil::Es_(266);

	BOOST_CHECK_CLOSE(E, 333.356, kEpsilon);

}

<commit_msg>Unit tests for dewpoint<commit_after>#include "himan_unit.h"
#include "metutil.h"

#define BOOST_TEST_MODULE metutil

using namespace std;
using namespace himan;

const double kEpsilon = 1e-3;

BOOST_AUTO_TEST_CASE(LCL_SLOW)
{

	// "slow" calculation of LCL

	lcl_t LCL = himan::metutil::LCL_(85000,273.15 + 16.5828, 273.15 + -1.45402);

	BOOST_CHECK_CLOSE(LCL.P, 64829.6, kEpsilon);
	BOOST_CHECK_CLOSE(LCL.T, 273.15 + -5.01719, kEpsilon);
}

BOOST_AUTO_TEST_CASE(LCL_FAST)
{

        // fast calculation of LCL

	lcl_t LCL = himan::metutil::LCL_(85000,273.15 + 16.6453, 273.15 + -1.29777);

	BOOST_CHECK_CLOSE(LCL.P, 64878.5986, kEpsilon);
	BOOST_CHECK_CLOSE(LCL.T, 273.15 + -4.90058, kEpsilon);
}

BOOST_AUTO_TEST_CASE(LCL_SMARTTOOL_COMPATIBILITY)
{
	// testing if himan LCL is compatible with smarttool LCL

	double T = 16.5828;
	double Td = -1.45402;
	double P = 850;

	lcl_t LCL = himan::metutil::LCL_(P*100, 273.15 + T, 273.15 + Td);

	BOOST_CHECK_CLOSE(LCL.P, 100*647.3825, 1);

}

BOOST_AUTO_TEST_CASE(MIXING_RATIO)
{
	double TD = 4.2;
	double P = 850;

	double ratio = metutil::MixingRatio_(273.15 + TD, 100 * P);

	BOOST_CHECK_CLOSE(ratio, 6.0955, kEpsilon);
}

BOOST_AUTO_TEST_CASE(SATURATED_MIXING_RATIO)
{

	// saturated mixing ratio

	double ratio = metutil::MixingRatio_(290, 98000);

	BOOST_CHECK_CLOSE(ratio, 12.4395, kEpsilon);

}

BOOST_AUTO_TEST_CASE(ES)
{

	// water vapour pressure

	double E = metutil::Es_(285);

	BOOST_CHECK_CLOSE(E, 1389.859, kEpsilon);

	// negative temperatures

	E = metutil::Es_(266);

	BOOST_CHECK_CLOSE(E, 333.356, kEpsilon);

}

BOOST_AUTO_TEST_CASE(DEWPOINT_HIGH_RH)
{

	double TD = metutil::DewPointFromHighRH_(292.5, 92.1);

	BOOST_CHECK_CLOSE(TD, 290.9200, kEpsilon);

	// negative temperatures

	TD = metutil::DewPointFromHighRH_(264, 57.44);

	BOOST_CHECK_CLOSE(TD, 255.488, kEpsilon);

}

BOOST_AUTO_TEST_CASE(DEWPOINT_LOW_RH)
{

	double TD = metutil::DewPointFromLowRH_(292.5, 22);

	BOOST_CHECK_CLOSE(TD, 292.3959, kEpsilon);

	// negative temperatures

	TD = metutil::DewPointFromLowRH_(264, 42.0);

	BOOST_CHECK_CLOSE(TD, 263.9865, kEpsilon);

}

<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 10000000000000007;

struct edge {
  int to;
  ll cap;
  int rev;
};

vector<edge> G[100010];
bool used[100010];

void add_edge(int from, int to, ll cap) {
  G[from].push_back((edge){to, cap, (int)G[to].size()});
  G[to].push_back((edge){to, 0, (int)G[to].size()-1});
}

ll dfs(int v, int t, ll f) {
  if (v == t) return f;
  used[v] = true;
  for (auto& e : G[v]) {
    if (!used[e.to] && e.cap > 0) {
      ll d = dfs(e.to, t, min(f, e.cap));
      if (d > 0) {
        e.cap -= d;
        G[e.to][e.rev].cap += d;
        return d;
      }
    }
  }
  return 0;
}

ll max_flow(int s, int t) {
  ll flow = 0;
  while (true) {
    fill(used, used+100010, false);
    ll f = dfs(s, t, infty);
    if (f == 0) return flow;
    flow += f;
  }
}

int R, C;
string S[100];
int src, dst;
int vertex = 0;

bool valid(int i, int j) {
  return (0 <= i && i < R && 0 <= j && j < C && S[i][j] == '.');
}

int num(int i, int j) {
  return i * C + j;
}

void add_edge_grid(int i, int j) {
  if (!valid(i, j)) return;
  int now = num(i, j);
  vertex++;
  if ((i+j) % 2 == 0) {
    for (auto k = 0; k < 4; ++k) {
      int x = i + dx[k];
      int y = j + dy[k];
      if (valid(x, y)) {
        add_edge(now, num(x, y), 1);
#if DEBUG == 1
        cerr << "add_edge(" << now << ", " << num(x, y) << ", 1)" << endl;
#endif
      }
    }
    add_edge(src, now, 1);
  } else {
    add_edge(now, dst, 1);
  }
}

int main () {
  cin >> R >> C;
  for (auto i = 0; i < R; ++i) {
    cin >> S[i];
  }
  src = R * C;
  dst = R * C + 1;
  for (auto i = 0; i < R; ++i) {
    for (auto j = 0; j < C; ++j) {
      add_edge_grid(i, j);
    }
  }
  ll maxi = max_flow(src, dst);
#if DEBUG == 1
  cerr << "vertex = " << vertex << endl;
  cerr << "maxi = " << maxi << endl;
#endif
  cout << vertex - maxi << endl;
}
<commit_msg>tried C2.cpp to 'C'<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 1 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 10000000000000007;

struct edge {
  int to;
  ll cap;
  int rev;
};

vector<edge> G[100010];
bool used[100010];

void add_edge(int from, int to, ll cap) {
  G[from].push_back((edge){to, cap, (int)G[to].size()});
  G[to].push_back((edge){to, 0, (int)G[to].size()-1});
}

ll dfs(int v, int t, ll f) {
  if (v == t) return f;
  used[v] = true;
  for (auto& e : G[v]) {
    if (!used[e.to] && e.cap > 0) {
      ll d = dfs(e.to, t, min(f, e.cap));
      if (d > 0) {
        e.cap -= d;
        G[e.to][e.rev].cap += d;
        return d;
      }
    }
  }
  return 0;
}

ll max_flow(int s, int t) {
  ll flow = 0;
  while (true) {
    fill(used, used+100010, false);
    ll f = dfs(s, t, infty);
    if (f == 0) return flow;
    flow += f;
  }
}

int R, C;
string S[100];
int src, dst;
int vertex = 0;

bool valid(int i, int j) {
  return (0 <= i && i < R && 0 <= j && j < C && S[i][j] == '.');
}

int num(int i, int j) {
  return i * C + j;
}

void add_edge_grid(int i, int j) {
  if (!valid(i, j)) return;
  int now = num(i, j);
  vertex++;
  if ((i+j) % 2 == 0) {
    for (auto k = 0; k < 4; ++k) {
      int x = i + dx[k];
      int y = j + dy[k];
      if (valid(x, y)) {
        add_edge(now, num(x, y), 1);
#if DEBUG == 1
        cerr << "add_edge(" << now << ", " << num(x, y) << ", 1)" << endl;
#endif
      }
    }
    add_edge(src, now, 1);
  } else {
    add_edge(now, dst, 1);
  }
}

int main () {
  cin >> R >> C;
  for (auto i = 0; i < R; ++i) {
    cin >> S[i];
  }
  src = R * C;
  dst = R * C + 1;
  for (auto i = 0; i < R; ++i) {
    for (auto j = 0; j < C; ++j) {
      add_edge_grid(i, j);
    }
  }
  ll maxi = max_flow(src, dst);
#if DEBUG == 1
  cerr << "vertex = " << vertex << endl;
  cerr << "maxi = " << maxi << endl;
#endif
  cout << vertex - maxi << endl;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/common/node_bindings.h"

#include <string>
#include <vector>

#include "atom/common/api/event_emitter_caller.h"
#include "atom/common/api/locker.h"
#include "atom/common/atom_command_line.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/command_line.h"
#include "base/base_paths.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_paths.h"
#include "native_mate/dictionary.h"

#include "atom/common/node_includes.h"

using content::BrowserThread;

// Force all builtin modules to be referenced so they can actually run their
// DSO constructors, see http://git.io/DRIqCg.
#define REFERENCE_MODULE(name) \
  extern "C" void _register_ ## name(void); \
  void (*fp_register_ ## name)(void) = _register_ ## name
// Electron's builtin modules.
REFERENCE_MODULE(atom_browser_app);
REFERENCE_MODULE(atom_browser_auto_updater);
REFERENCE_MODULE(atom_browser_content_tracing);
REFERENCE_MODULE(atom_browser_dialog);
REFERENCE_MODULE(atom_browser_debugger);
REFERENCE_MODULE(atom_browser_desktop_capturer);
REFERENCE_MODULE(atom_browser_download_item);
REFERENCE_MODULE(atom_browser_menu);
REFERENCE_MODULE(atom_browser_power_monitor);
REFERENCE_MODULE(atom_browser_power_save_blocker);
REFERENCE_MODULE(atom_browser_protocol);
REFERENCE_MODULE(atom_browser_global_shortcut);
REFERENCE_MODULE(atom_browser_render_process_preferences);
REFERENCE_MODULE(atom_browser_session);
REFERENCE_MODULE(atom_browser_system_preferences);
REFERENCE_MODULE(atom_browser_tray);
REFERENCE_MODULE(atom_browser_web_contents);
REFERENCE_MODULE(atom_browser_web_view_manager);
REFERENCE_MODULE(atom_browser_window);
REFERENCE_MODULE(atom_common_asar);
REFERENCE_MODULE(atom_common_clipboard);
REFERENCE_MODULE(atom_common_crash_reporter);
REFERENCE_MODULE(atom_common_native_image);
REFERENCE_MODULE(atom_common_screen);
REFERENCE_MODULE(atom_common_shell);
REFERENCE_MODULE(atom_common_v8_util);
REFERENCE_MODULE(atom_renderer_ipc);
REFERENCE_MODULE(atom_renderer_web_frame);
#undef REFERENCE_MODULE

// The "v8::Function::kLineOffsetNotFound" is exported in node.dll, but the
// linker can not find it, could be a bug of VS.
#if defined(OS_WIN) && !defined(DEBUG)
namespace v8 {
const int Function::kLineOffsetNotFound = -1;
}
#endif

namespace atom {

namespace {

// Empty callback for async handle.
void UvNoOp(uv_async_t* handle) {
}

// Convert the given vector to an array of C-strings. The strings in the
// returned vector are only guaranteed valid so long as the vector of strings
// is not modified.
std::unique_ptr<const char*[]> StringVectorToArgArray(
    const std::vector<std::string>& vector) {
  std::unique_ptr<const char*[]> array(new const char*[vector.size()]);
  for (size_t i = 0; i < vector.size(); ++i) {
    array[i] = vector[i].c_str();
  }
  return array;
}

base::FilePath GetResourcesPath(bool is_browser) {
  auto command_line = base::CommandLine::ForCurrentProcess();
  base::FilePath exec_path(command_line->GetProgram());
  PathService::Get(base::FILE_EXE, &exec_path);

  base::FilePath resources_path =
#if defined(OS_MACOSX)
      is_browser ? exec_path.DirName().DirName().Append("Resources") :
                   exec_path.DirName().DirName().DirName().DirName().DirName()
                            .Append("Resources");
#else
      exec_path.DirName().Append(FILE_PATH_LITERAL("resources"));
#endif
  return resources_path;
}

}  // namespace

NodeBindings::NodeBindings(bool is_browser)
    : is_browser_(is_browser),
      message_loop_(nullptr),
      uv_loop_(uv_default_loop()),
      embed_closed_(false),
      uv_env_(nullptr),
      weak_factory_(this) {
}

NodeBindings::~NodeBindings() {
  // Quit the embed thread.
  embed_closed_ = true;
  uv_sem_post(&embed_sem_);
  WakeupEmbedThread();

  // Wait for everything to be done.
  uv_thread_join(&embed_thread_);

  // Clear uv.
  uv_sem_destroy(&embed_sem_);
}

void NodeBindings::Initialize() {
  // Open node's error reporting system for browser process.
  node::g_standalone_mode = is_browser_;
  node::g_upstream_node_mode = false;

#if defined(OS_LINUX)
  // Get real command line in renderer process forked by zygote.
  if (!is_browser_)
    AtomCommandLine::InitializeFromCommandLine();
#endif

  // Init node.
  // (we assume node::Init would not modify the parameters under embedded mode).
  node::Init(nullptr, nullptr, nullptr, nullptr);

#if defined(OS_WIN)
  // uv_init overrides error mode to suppress the default crash dialog, bring
  // it back if user wants to show it.
  std::unique_ptr<base::Environment> env(base::Environment::Create());
  if (env->HasVar("ELECTRON_DEFAULT_ERROR_MODE"))
    SetErrorMode(0);
#endif
}

node::Environment* NodeBindings::CreateEnvironment(
    v8::Handle<v8::Context> context) {
  auto args = AtomCommandLine::argv();

  // Feed node the path to initialization script.
  base::FilePath::StringType process_type = is_browser_ ?
      FILE_PATH_LITERAL("browser") : FILE_PATH_LITERAL("renderer");
  base::FilePath resources_path = GetResourcesPath(is_browser_);
  base::FilePath script_path =
      resources_path.Append(FILE_PATH_LITERAL("electron.asar"))
                    .Append(process_type)
                    .Append(FILE_PATH_LITERAL("init.js"));
  std::string script_path_str = script_path.AsUTF8Unsafe();
  args.insert(args.begin() + 1, script_path_str.c_str());

  std::unique_ptr<const char*[]> c_argv = StringVectorToArgArray(args);
  node::Environment* env = node::CreateEnvironment(
      context->GetIsolate(), uv_default_loop(), context,
      args.size(), c_argv.get(), 0, nullptr);

  // Node turns off AutorunMicrotasks, but we need it in web pages to match the
  // behavior of Chrome.
  if (!is_browser_)
    context->GetIsolate()->SetAutorunMicrotasks(true);

  mate::Dictionary process(context->GetIsolate(), env->process_object());
  process.Set("type", process_type);
  process.Set("resourcesPath", resources_path);
  // Do not set DOM globals for renderer process.
  if (!is_browser_)
    process.Set("_noBrowserGlobals", resources_path);
  // The path to helper app.
  base::FilePath helper_exec_path;
  PathService::Get(content::CHILD_PROCESS_EXE, &helper_exec_path);
  process.Set("helperExecPath", helper_exec_path);
  return env;
}

void NodeBindings::LoadEnvironment(node::Environment* env) {
  node::LoadEnvironment(env);
  mate::EmitEvent(env->isolate(), env->process_object(), "loaded");
}

void NodeBindings::PrepareMessageLoop() {
  DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI));

  // Add dummy handle for libuv, otherwise libuv would quit when there is
  // nothing to do.
  uv_async_init(uv_loop_, &dummy_uv_handle_, UvNoOp);

  // Start worker that will interrupt main loop when having uv events.
  uv_sem_init(&embed_sem_, 0);
  uv_thread_create(&embed_thread_, EmbedThreadRunner, this);
}

void NodeBindings::RunMessageLoop() {
  DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI));

  // The MessageLoop should have been created, remember the one in main thread.
  message_loop_ = base::MessageLoop::current();

  // Run uv loop for once to give the uv__io_poll a chance to add all events.
  UvRunOnce();
}

void NodeBindings::UvRunOnce() {
  DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI));

  node::Environment* env = uv_env();

  // Use Locker in browser process.
  mate::Locker locker(env->isolate());
  v8::HandleScope handle_scope(env->isolate());

  // Enter node context while dealing with uv events.
  v8::Context::Scope context_scope(env->context());

  // Perform microtask checkpoint after running JavaScript.
  v8::MicrotasksScope script_scope(env->isolate(),
                                   v8::MicrotasksScope::kRunMicrotasks);

  // Deal with uv events.
  int r = uv_run(uv_loop_, UV_RUN_NOWAIT);
  if (r == 0 || uv_loop_->stop_flag != 0)
    message_loop_->QuitWhenIdle();  // Quit from uv.

  // Tell the worker thread to continue polling.
  uv_sem_post(&embed_sem_);
}

void NodeBindings::WakeupMainThread() {
  DCHECK(message_loop_);
  message_loop_->PostTask(FROM_HERE, base::Bind(&NodeBindings::UvRunOnce,
                                                weak_factory_.GetWeakPtr()));
}

void NodeBindings::WakeupEmbedThread() {
  uv_async_send(&dummy_uv_handle_);
}

// static
void NodeBindings::EmbedThreadRunner(void *arg) {
  NodeBindings* self = static_cast<NodeBindings*>(arg);

  while (true) {
    // Wait for the main loop to deal with events.
    uv_sem_wait(&self->embed_sem_);
    if (self->embed_closed_)
      break;

    // Wait for something to happen in uv loop.
    // Note that the PollEvents() is implemented by derived classes, so when
    // this class is being destructed the PollEvents() would not be available
    // anymore. Because of it we must make sure we only invoke PollEvents()
    // when this class is alive.
    self->PollEvents();
    if (self->embed_closed_)
      break;

    // Deal with event in main thread.
    self->WakeupMainThread();
  }
}

}  // namespace atom
<commit_msg>Remove unneeded libuv callback<commit_after>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/common/node_bindings.h"

#include <string>
#include <vector>

#include "atom/common/api/event_emitter_caller.h"
#include "atom/common/api/locker.h"
#include "atom/common/atom_command_line.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/command_line.h"
#include "base/base_paths.h"
#include "base/environment.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_paths.h"
#include "native_mate/dictionary.h"

#include "atom/common/node_includes.h"

using content::BrowserThread;

// Force all builtin modules to be referenced so they can actually run their
// DSO constructors, see http://git.io/DRIqCg.
#define REFERENCE_MODULE(name) \
  extern "C" void _register_ ## name(void); \
  void (*fp_register_ ## name)(void) = _register_ ## name
// Electron's builtin modules.
REFERENCE_MODULE(atom_browser_app);
REFERENCE_MODULE(atom_browser_auto_updater);
REFERENCE_MODULE(atom_browser_content_tracing);
REFERENCE_MODULE(atom_browser_dialog);
REFERENCE_MODULE(atom_browser_debugger);
REFERENCE_MODULE(atom_browser_desktop_capturer);
REFERENCE_MODULE(atom_browser_download_item);
REFERENCE_MODULE(atom_browser_menu);
REFERENCE_MODULE(atom_browser_power_monitor);
REFERENCE_MODULE(atom_browser_power_save_blocker);
REFERENCE_MODULE(atom_browser_protocol);
REFERENCE_MODULE(atom_browser_global_shortcut);
REFERENCE_MODULE(atom_browser_render_process_preferences);
REFERENCE_MODULE(atom_browser_session);
REFERENCE_MODULE(atom_browser_system_preferences);
REFERENCE_MODULE(atom_browser_tray);
REFERENCE_MODULE(atom_browser_web_contents);
REFERENCE_MODULE(atom_browser_web_view_manager);
REFERENCE_MODULE(atom_browser_window);
REFERENCE_MODULE(atom_common_asar);
REFERENCE_MODULE(atom_common_clipboard);
REFERENCE_MODULE(atom_common_crash_reporter);
REFERENCE_MODULE(atom_common_native_image);
REFERENCE_MODULE(atom_common_screen);
REFERENCE_MODULE(atom_common_shell);
REFERENCE_MODULE(atom_common_v8_util);
REFERENCE_MODULE(atom_renderer_ipc);
REFERENCE_MODULE(atom_renderer_web_frame);
#undef REFERENCE_MODULE

// The "v8::Function::kLineOffsetNotFound" is exported in node.dll, but the
// linker can not find it, could be a bug of VS.
#if defined(OS_WIN) && !defined(DEBUG)
namespace v8 {
const int Function::kLineOffsetNotFound = -1;
}
#endif

namespace atom {

namespace {

// Convert the given vector to an array of C-strings. The strings in the
// returned vector are only guaranteed valid so long as the vector of strings
// is not modified.
std::unique_ptr<const char*[]> StringVectorToArgArray(
    const std::vector<std::string>& vector) {
  std::unique_ptr<const char*[]> array(new const char*[vector.size()]);
  for (size_t i = 0; i < vector.size(); ++i) {
    array[i] = vector[i].c_str();
  }
  return array;
}

base::FilePath GetResourcesPath(bool is_browser) {
  auto command_line = base::CommandLine::ForCurrentProcess();
  base::FilePath exec_path(command_line->GetProgram());
  PathService::Get(base::FILE_EXE, &exec_path);

  base::FilePath resources_path =
#if defined(OS_MACOSX)
      is_browser ? exec_path.DirName().DirName().Append("Resources") :
                   exec_path.DirName().DirName().DirName().DirName().DirName()
                            .Append("Resources");
#else
      exec_path.DirName().Append(FILE_PATH_LITERAL("resources"));
#endif
  return resources_path;
}

}  // namespace

NodeBindings::NodeBindings(bool is_browser)
    : is_browser_(is_browser),
      message_loop_(nullptr),
      uv_loop_(uv_default_loop()),
      embed_closed_(false),
      uv_env_(nullptr),
      weak_factory_(this) {
}

NodeBindings::~NodeBindings() {
  // Quit the embed thread.
  embed_closed_ = true;
  uv_sem_post(&embed_sem_);
  WakeupEmbedThread();

  // Wait for everything to be done.
  uv_thread_join(&embed_thread_);

  // Clear uv.
  uv_sem_destroy(&embed_sem_);
}

void NodeBindings::Initialize() {
  // Open node's error reporting system for browser process.
  node::g_standalone_mode = is_browser_;
  node::g_upstream_node_mode = false;

#if defined(OS_LINUX)
  // Get real command line in renderer process forked by zygote.
  if (!is_browser_)
    AtomCommandLine::InitializeFromCommandLine();
#endif

  // Init node.
  // (we assume node::Init would not modify the parameters under embedded mode).
  node::Init(nullptr, nullptr, nullptr, nullptr);

#if defined(OS_WIN)
  // uv_init overrides error mode to suppress the default crash dialog, bring
  // it back if user wants to show it.
  std::unique_ptr<base::Environment> env(base::Environment::Create());
  if (env->HasVar("ELECTRON_DEFAULT_ERROR_MODE"))
    SetErrorMode(0);
#endif
}

node::Environment* NodeBindings::CreateEnvironment(
    v8::Handle<v8::Context> context) {
  auto args = AtomCommandLine::argv();

  // Feed node the path to initialization script.
  base::FilePath::StringType process_type = is_browser_ ?
      FILE_PATH_LITERAL("browser") : FILE_PATH_LITERAL("renderer");
  base::FilePath resources_path = GetResourcesPath(is_browser_);
  base::FilePath script_path =
      resources_path.Append(FILE_PATH_LITERAL("electron.asar"))
                    .Append(process_type)
                    .Append(FILE_PATH_LITERAL("init.js"));
  std::string script_path_str = script_path.AsUTF8Unsafe();
  args.insert(args.begin() + 1, script_path_str.c_str());

  std::unique_ptr<const char*[]> c_argv = StringVectorToArgArray(args);
  node::Environment* env = node::CreateEnvironment(
      context->GetIsolate(), uv_default_loop(), context,
      args.size(), c_argv.get(), 0, nullptr);

  // Node turns off AutorunMicrotasks, but we need it in web pages to match the
  // behavior of Chrome.
  if (!is_browser_)
    context->GetIsolate()->SetAutorunMicrotasks(true);

  mate::Dictionary process(context->GetIsolate(), env->process_object());
  process.Set("type", process_type);
  process.Set("resourcesPath", resources_path);
  // Do not set DOM globals for renderer process.
  if (!is_browser_)
    process.Set("_noBrowserGlobals", resources_path);
  // The path to helper app.
  base::FilePath helper_exec_path;
  PathService::Get(content::CHILD_PROCESS_EXE, &helper_exec_path);
  process.Set("helperExecPath", helper_exec_path);
  return env;
}

void NodeBindings::LoadEnvironment(node::Environment* env) {
  node::LoadEnvironment(env);
  mate::EmitEvent(env->isolate(), env->process_object(), "loaded");
}

void NodeBindings::PrepareMessageLoop() {
  DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI));

  // Add dummy handle for libuv, otherwise libuv would quit when there is
  // nothing to do.
  uv_async_init(uv_loop_, &dummy_uv_handle_, nullptr);

  // Start worker that will interrupt main loop when having uv events.
  uv_sem_init(&embed_sem_, 0);
  uv_thread_create(&embed_thread_, EmbedThreadRunner, this);
}

void NodeBindings::RunMessageLoop() {
  DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI));

  // The MessageLoop should have been created, remember the one in main thread.
  message_loop_ = base::MessageLoop::current();

  // Run uv loop for once to give the uv__io_poll a chance to add all events.
  UvRunOnce();
}

void NodeBindings::UvRunOnce() {
  DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI));

  node::Environment* env = uv_env();

  // Use Locker in browser process.
  mate::Locker locker(env->isolate());
  v8::HandleScope handle_scope(env->isolate());

  // Enter node context while dealing with uv events.
  v8::Context::Scope context_scope(env->context());

  // Perform microtask checkpoint after running JavaScript.
  v8::MicrotasksScope script_scope(env->isolate(),
                                   v8::MicrotasksScope::kRunMicrotasks);

  // Deal with uv events.
  int r = uv_run(uv_loop_, UV_RUN_NOWAIT);
  if (r == 0 || uv_loop_->stop_flag != 0)
    message_loop_->QuitWhenIdle();  // Quit from uv.

  // Tell the worker thread to continue polling.
  uv_sem_post(&embed_sem_);
}

void NodeBindings::WakeupMainThread() {
  DCHECK(message_loop_);
  message_loop_->PostTask(FROM_HERE, base::Bind(&NodeBindings::UvRunOnce,
                                                weak_factory_.GetWeakPtr()));
}

void NodeBindings::WakeupEmbedThread() {
  uv_async_send(&dummy_uv_handle_);
}

// static
void NodeBindings::EmbedThreadRunner(void *arg) {
  NodeBindings* self = static_cast<NodeBindings*>(arg);

  while (true) {
    // Wait for the main loop to deal with events.
    uv_sem_wait(&self->embed_sem_);
    if (self->embed_closed_)
      break;

    // Wait for something to happen in uv loop.
    // Note that the PollEvents() is implemented by derived classes, so when
    // this class is being destructed the PollEvents() would not be available
    // anymore. Because of it we must make sure we only invoke PollEvents()
    // when this class is alive.
    self->PollEvents();
    if (self->embed_closed_)
      break;

    // Deal with event in main thread.
    self->WakeupMainThread();
  }
}

}  // namespace atom
<|endoftext|>


<commit_before>#include "Memory.h"

#include <vector>
#include <iostream>
#include <iomanip>
#include <cstdint>
#include <cassert>

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>

#include "Type.h"
#include "Runtime.h"
#include "GasMeter.h"
#include "Endianness.h"
#include "RuntimeManager.h"

namespace dev
{
namespace eth
{
namespace jit
{

Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
	RuntimeHelper(_runtimeManager),  // TODO: RuntimeHelper not needed
	m_gasMeter(_gasMeter)
{
	llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr};
	m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule());
	llvm::AttrBuilder attrBuilder;
	attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
	m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder));

	m_require = createRequireFunc(_gasMeter);
	m_loadWord = createFunc(false, Type::Word, _gasMeter);
	m_storeWord = createFunc(true, Type::Word, _gasMeter);
	m_storeByte = createFunc(true, Type::Byte,  _gasMeter);
}

llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter)
{
	llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word};
	auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
	auto rt = func->arg_begin();
	rt->setName("rt");
	auto offset = rt->getNextNode();
	offset->setName("offset");
	auto size = offset->getNextNode();
	size->setName("size");

	auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func);
	auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
	auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func);
	auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func);

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	// BB "Pre": Ignore checks with size 0
	m_builder.SetInsertPoint(preBB);
	auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0));
	m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB);

	// BB "Check"
	m_builder.SetInsertPoint(checkBB);
	auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word);
	auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res");
	auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq");
	auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1");
	auto rtPtr = getRuntimeManager().getRuntimePtr();
	auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4);
	auto currSize = m_builder.CreateLoad(sizePtr, "currSize");
	auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall");
	auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded");
	m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?

	// BB "Resize"
	m_builder.SetInsertPoint(resizeBB);
	// Check gas first
	uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res");
	auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0);
	auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2");
	auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow");
	wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired);
	wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq");
	sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq");
	auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words");	// size is always 32*k
	auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
	_gasMeter.countMemory(newWords);
	// Resize
	m_builder.CreateStore(sizeRequired, sizePtr);
	auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData");
	auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3);
	m_builder.CreateStore(newData, dataPtr);
	m_builder.CreateBr(returnBB);

	// BB "Return"
	m_builder.SetInsertPoint(returnBB);
	m_builder.CreateRetVoid();
	return func;
}

llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&)
{
	auto isWord = _valueType == Type::Word;

	llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType};
	llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word};
	auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
	auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false);
	auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
	auto rt = func->arg_begin();
	rt->setName("rt");
	auto index = rt->getNextNode();
	index->setName("index");

	auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
	this->require(index, Constant::get(valueSize));
	auto ptr = getBytePtr(index);
	if (isWord)
		ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
	if (_isStore)
	{
		llvm::Value* value = index->getNextNode();
		value->setName("value");
		if (isWord)
			value = Endianness::toBE(m_builder, value);
		m_builder.CreateStore(value, ptr);
		m_builder.CreateRetVoid();
	}
	else
	{
		llvm::Value* ret = m_builder.CreateLoad(ptr);
		ret = Endianness::toNative(m_builder, ret);
		m_builder.CreateRet(ret);
	}

	return func;
}

llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
	return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr});
}

void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
	createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word});
}

void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
	auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
	createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte});
}

llvm::Value* Memory::getData()
{
	auto rtPtr = getRuntimeManager().getRuntimePtr();
	auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3);
	return m_builder.CreateLoad(dataPtr, "data");
}

llvm::Value* Memory::getSize()
{
	auto rtPtr = getRuntimeManager().getRuntimePtr();
	auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4);
	return m_builder.CreateLoad(sizePtr, "size");
}

llvm::Value* Memory::getBytePtr(llvm::Value* _index)
{
	auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64
	return m_builder.CreateGEP(getData(), idx, "ptr");
}

void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
	createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size});
}

void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
					   llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
{
	require(_destMemIdx, _reqBytes);

	// Additional copy cost
	// TODO: This round ups to 32 happens in many places
	auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32));
	m_gasMeter.countCopy(copyWords);

	// Algorithm:
	// isOutsideData = idx256 >= size256
	// idx64  = trunc idx256
	// size64 = trunc size256
	// dataLeftSize = size64 - idx64  // safe if not isOutsideData
	// reqBytes64 = trunc _reqBytes   // require() handles large values
	// bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64)  // min
	// bytesToCopy = select(isOutsideData, 0, bytesToCopy0)

	auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize);
	auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision);
	auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision);
	auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64);
	auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision);
	auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize);
	auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64);
	auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0);	// TODO: Cache common constants
	auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner);

	auto src = m_builder.CreateGEP(_srcPtr, idx64, "src");
	auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64
	auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst");
	m_builder.CreateMemCpy(dst, src, bytesToCopy, 0);
}

}
}
}

extern "C"
{
	using namespace dev::eth::jit;

	EXPORT byte* mem_resize(Runtime* _rt, i256* _size)	// TODO: Use uint64 as size OR use realloc in LLVM IR
	{
		auto size = _size->a; // Trunc to 64-bit
		auto& memory = _rt->getMemory();
		memory.resize(size);
		return memory.data();
	}
}
<commit_msg>Do not check memory requirements when size is 0<commit_after>#include "Memory.h"

#include <vector>
#include <iostream>
#include <iomanip>
#include <cstdint>
#include <cassert>

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>

#include "Type.h"
#include "Runtime.h"
#include "GasMeter.h"
#include "Endianness.h"
#include "RuntimeManager.h"

namespace dev
{
namespace eth
{
namespace jit
{

Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
	RuntimeHelper(_runtimeManager),  // TODO: RuntimeHelper not needed
	m_gasMeter(_gasMeter)
{
	llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr};
	m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule());
	llvm::AttrBuilder attrBuilder;
	attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
	m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder));

	m_require = createRequireFunc(_gasMeter);
	m_loadWord = createFunc(false, Type::Word, _gasMeter);
	m_storeWord = createFunc(true, Type::Word, _gasMeter);
	m_storeByte = createFunc(true, Type::Byte,  _gasMeter);
}

llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter)
{
	llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word};
	auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
	auto rt = func->arg_begin();
	rt->setName("rt");
	auto offset = rt->getNextNode();
	offset->setName("offset");
	auto size = offset->getNextNode();
	size->setName("size");

	auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func);
	auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
	auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func);
	auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func);

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	// BB "Pre": Ignore checks with size 0
	m_builder.SetInsertPoint(preBB);
	auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0));
	m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB);

	// BB "Check"
	m_builder.SetInsertPoint(checkBB);
	auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word);
	auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res");
	auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq");
	auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1");
	auto rtPtr = getRuntimeManager().getRuntimePtr();
	auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4);
	auto currSize = m_builder.CreateLoad(sizePtr, "currSize");
	auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall");
	auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded");
	m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?

	// BB "Resize"
	m_builder.SetInsertPoint(resizeBB);
	// Check gas first
	uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res");
	auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0);
	auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2");
	auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow");
	wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired);
	wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq");
	sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq");
	auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words");	// size is always 32*k
	auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
	_gasMeter.countMemory(newWords);
	// Resize
	m_builder.CreateStore(sizeRequired, sizePtr);
	auto newData = m_builder.CreateCall2(m_resize, rt, sizePtr, "newData");
	auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3);
	m_builder.CreateStore(newData, dataPtr);
	m_builder.CreateBr(returnBB);

	// BB "Return"
	m_builder.SetInsertPoint(returnBB);
	m_builder.CreateRetVoid();
	return func;
}

llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&)
{
	auto isWord = _valueType == Type::Word;

	llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType};
	llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word};
	auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
	auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false);
	auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
	auto rt = func->arg_begin();
	rt->setName("rt");
	auto index = rt->getNextNode();
	index->setName("index");

	auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
	this->require(index, Constant::get(valueSize));
	auto ptr = getBytePtr(index);
	if (isWord)
		ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
	if (_isStore)
	{
		llvm::Value* value = index->getNextNode();
		value->setName("value");
		if (isWord)
			value = Endianness::toBE(m_builder, value);
		m_builder.CreateStore(value, ptr);
		m_builder.CreateRetVoid();
	}
	else
	{
		llvm::Value* ret = m_builder.CreateLoad(ptr);
		ret = Endianness::toNative(m_builder, ret);
		m_builder.CreateRet(ret);
	}

	return func;
}

llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
	return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr});
}

void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
	createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word});
}

void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
	auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
	createCall(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte});
}

llvm::Value* Memory::getData()
{
	auto rtPtr = getRuntimeManager().getRuntimePtr();
	auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3);
	return m_builder.CreateLoad(dataPtr, "data");
}

llvm::Value* Memory::getSize()
{
	auto rtPtr = getRuntimeManager().getRuntimePtr();
	auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4);
	return m_builder.CreateLoad(sizePtr, "size");
}

llvm::Value* Memory::getBytePtr(llvm::Value* _index)
{
	auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64
	return m_builder.CreateGEP(getData(), idx, "ptr");
}

void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
	if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(_size))
	{
		if (!constant->getValue())
			return;
	}
	createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size});
}

void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
					   llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
{
	require(_destMemIdx, _reqBytes);

	// Additional copy cost
	// TODO: This round ups to 32 happens in many places
	auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32));
	m_gasMeter.countCopy(copyWords);

	// Algorithm:
	// isOutsideData = idx256 >= size256
	// idx64  = trunc idx256
	// size64 = trunc size256
	// dataLeftSize = size64 - idx64  // safe if not isOutsideData
	// reqBytes64 = trunc _reqBytes   // require() handles large values
	// bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64)  // min
	// bytesToCopy = select(isOutsideData, 0, bytesToCopy0)

	auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize);
	auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision);
	auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision);
	auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64);
	auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision);
	auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize);
	auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64);
	auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0);	// TODO: Cache common constants
	auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner);

	auto src = m_builder.CreateGEP(_srcPtr, idx64, "src");
	auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64
	auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst");
	m_builder.CreateMemCpy(dst, src, bytesToCopy, 0);
}

}
}
}

extern "C"
{
	using namespace dev::eth::jit;

	EXPORT byte* mem_resize(Runtime* _rt, i256* _size)	// TODO: Use uint64 as size OR use realloc in LLVM IR
	{
		auto size = _size->a; // Trunc to 64-bit
		auto& memory = _rt->getMemory();
		memory.resize(size);
		return memory.data();
	}
}
<|endoftext|>


<commit_before>#define DEBUG 1

/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2019-6-1 22:04:14
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

typedef long long ll;

/*
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}

void No()
{
  cout << "No" << endl;
  exit(0);
}
*/

/*
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
*/

// const ll MOD = 1000000007;

class UnionFind
{
public:
  vector<long long> par;

  UnionFind() {}

  UnionFind(int n) : par(n, -1) {}

  void init(int n)
  {
    par.assign(n, -1);
  }

  int root(int x)
  {
    if (par[x] < 0)
    {
      return x;
    }
    return par[x] = root(par[x]);
  }

  bool is_same(int x, int y)
  {
    return root(x) == root(y);
  }

  bool merge(int x, int y)
  {
    x = root(x);
    y = root(y);
    if (x == y)
    {
      return false;
    }
    if (par[x] > par[y])
    {
      swap(x, y);
    }
    par[x] += par[y];
    par[y] = x;
    return true;
  }

  long long size(int x)
  {
    return -par[root(x)];
  }
};

int N;
bool A[2010][2010];
vector<int> V[2010];
vector<int> W[2010];
vector<int> X;
set<int> Y;
bool visited[2010];
UnionFind uf;

void dfs(int v)
{
  if (!visited[v])
  {
    visited[v] = true;
    for (auto x : V[v])
    {
      if (!visited[x])
      {
        dfs(x);
      }
    }
    X.push_back(v);
  }
}

void dfs2(int v)
{
  if (!visited[v])
  {
    visited[v] = true;
    for (auto x : W[v])
    {
      if (!visited[x])
      {
        dfs2(x);
        uf.merge(v, x);
      }
    }
  }
}

void dfs3(int v)
{
  if (!visited[v] && Y.find(v) != Y.end())
  {
    visited[v] = true;
    for (auto x : V[v])
    {
      if (!visited[x] && Y.find(v) != Y.end())
      {
        dfs3(x);
      }
    }
  }
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    string S;
    cin >> S;
    for (auto j = 0; j < i; j++)
    {
      A[i][j] = (S[j] == '1');
      if (A[i][j])
      {
        V[j].push_back(i);
        W[i].push_back(j);
      }
      else
      {
        V[i].push_back(j);
        W[j].push_back(i);
      }
    }
  }
  fill(visited, visited + N, false);
#if DEBUG == 1
  cerr << "dfs" << endl;
#endif
  for (auto i = 0; i < N; i++)
  {
    dfs(i);
  }
#if DEBUG == 1
  cerr << "dfs" << endl;
#endif
  uf = UnionFind(N);
  reverse(X.begin(), X.end());
  fill(visited, visited + N, false);
  for (auto x : X)
  {
    dfs2(x);
  }
  for (auto i = 0; i < N; i++)
  {
    bool ok = true;
    for (auto j = 0; j < N; j++)
    {
      if (uf.is_same(i, j))
      {
        ok = false;
        break;
      }
    }
    if (ok)
    {
      Y.insert(i);
    }
  }
  for (auto x : Y)
  {
    fill(visited, visited + N, false);
    dfs3(x);
    bool ok = true;
    for (auto y : Y)
    {
      if (!visited[y])
      {
        ok = false;
        break;
      }
    }
    if (ok)
    {
      cout << uf.size(x) << endl;
      return 0;
    }
  }
}<commit_msg>tried F.cpp to 'F'<commit_after>#define DEBUG 1

/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2019-6-1 22:04:14
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

typedef long long ll;

/*
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}

void No()
{
  cout << "No" << endl;
  exit(0);
}
*/

/*
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};
*/

// const ll MOD = 1000000007;

class UnionFind
{
public:
  vector<long long> par;

  UnionFind() {}

  UnionFind(int n) : par(n, -1) {}

  void init(int n)
  {
    par.assign(n, -1);
  }

  int root(int x)
  {
    if (par[x] < 0)
    {
      return x;
    }
    return par[x] = root(par[x]);
  }

  bool is_same(int x, int y)
  {
    return root(x) == root(y);
  }

  bool merge(int x, int y)
  {
    x = root(x);
    y = root(y);
    if (x == y)
    {
      return false;
    }
    if (par[x] > par[y])
    {
      swap(x, y);
    }
    par[x] += par[y];
    par[y] = x;
    return true;
  }

  long long size(int x)
  {
    return -par[root(x)];
  }
};

int N;
bool A[2010][2010];
vector<int> V[2010];
vector<int> W[2010];
vector<int> X;
set<int> Y;
bool visited[2010];
UnionFind uf;

void dfs(int v)
{
  if (!visited[v])
  {
    visited[v] = true;
    for (auto x : V[v])
    {
      if (!visited[x])
      {
        dfs(x);
      }
    }
    X.push_back(v);
  }
}

void dfs2(int v)
{
  if (!visited[v])
  {
    visited[v] = true;
    for (auto x : W[v])
    {
      if (!visited[x])
      {
        dfs2(x);
        uf.merge(v, x);
      }
    }
  }
}

void dfs3(int v)
{
  if (!visited[v] && Y.find(v) != Y.end())
  {
    visited[v] = true;
    for (auto x : V[v])
    {
      if (!visited[x] && Y.find(v) != Y.end())
      {
        dfs3(x);
      }
    }
  }
}

int main()
{
  cin >> N;
  for (auto i = 1; i < N; i++)
  {
    string S;
    cin >> S;
    for (auto j = 0; j < i; j++)
    {
      A[i][j] = (S[j] == '1');
      if (A[i][j])
      {
        V[j].push_back(i);
        W[i].push_back(j);
      }
      else
      {
        V[i].push_back(j);
        W[j].push_back(i);
      }
    }
  }
  fill(visited, visited + N, false);
#if DEBUG == 1
  cerr << "dfs" << endl;
#endif
  for (auto i = 0; i < N; i++)
  {
    dfs(i);
  }
#if DEBUG == 1
  cerr << "dfs" << endl;
#endif
  uf = UnionFind(N);
  reverse(X.begin(), X.end());
  fill(visited, visited + N, false);
  for (auto x : X)
  {
    dfs2(x);
  }
  for (auto i = 0; i < N; i++)
  {
    bool ok = true;
    for (auto j = 0; j < N; j++)
    {
      if (uf.is_same(i, j))
      {
        ok = false;
        break;
      }
    }
    if (ok)
    {
      Y.insert(i);
    }
  }
  for (auto x : Y)
  {
    fill(visited, visited + N, false);
    dfs3(x);
    bool ok = true;
    for (auto y : Y)
    {
      if (!visited[y])
      {
        ok = false;
        break;
      }
    }
    if (ok)
    {
      cout << uf.size(x) << endl;
      return 0;
    }
  }
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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 "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbStreamingStatisticsVectorImageFilter.h"
#include "otbEigenvalueLikelihoodMaximisation.h"
#include "otbVirtualDimensionality.h"

namespace otb
{
namespace Wrapper
{

class EndmemberNumberEstimation : public Application
{
public:
  /** Standard class typedefs. */
  typedef EndmemberNumberEstimation         Self;
  typedef Application                       Superclass;
  typedef itk::SmartPointer<Self>           Pointer;
  typedef itk::SmartPointer<const Self>     ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(EndmemberNumberEstimation, otb::Application);

  typedef otb::StreamingStatisticsVectorImageFilter<FloatVectorImageType, float> StreamingStatisticsVectorImageFilterType;
  typedef otb::VirtualDimensionality<float>                                      VirtualDimensionalityType;
  typedef otb::EigenvalueLikelihoodMaximisation<float>                           EigenvalueLikelihoodMaximisationType;

private:
  void DoInit() override
  {
    SetName("EndmemberNumberEstimation");
    SetDescription("Estimate the number of endmembers in a hyperspectral image");

    // Documentation
    SetDocName("Endmember Number Estimation");
    SetDocLongDescription("Estimate the number of endmembers "
    "in a hyperspectral image. First, compute statistics on the image and then "
    "apply an endmember number estimation algorithm using these statistics. Two "
    "algorithms are available:\n\n"

    "1. Virtual Dimensionality (VD) [1][2]\n"
    "2. Eigenvalue Likelihood Maximization (ELM) [3][4]\n\n"

    "The application then returns the estimated number of endmembers.\n\n"

    "[1] C.-I. Chang and Q. Du, Estimation of number of spectrally distinct signal "
    "sources in hyperspectral imagery, IEEE Transactions on Geoscience and Remote "
    "Sensing, vol. 43, no. 3, mar 2004.\n\n"

    "[2] J. Wang and C.-I. Chang, Applications of independent component analysis "
    "in endmember extraction and abundance quantification for hyperspectral imagery"
    ", IEEE Transactions on Geoscience and Remote Sensing, vol. 44, no. 9, pp. "
    "2601-1616, sep 2006.\n\n"

    "[3] Unsupervised Endmember Extraction of Martian Hyperspectral Images, B.Luo, "
    "J. Chanussot, S. Dout\'e and X. Ceamanos, IEEE Whispers 2009, Grenoble France, 2009\n\n"

    "[4] Unsupervised classification of hyperspectral images by using "
    "linear unmixing algorithm Luo, B. and Chanussot, J., IEEE Int. Conf. On Image"
    "Processing(ICIP) 2009, Cairo, Egypte, 2009"
    );

    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("VertexComponentAnalysis, HyperspectralUnmixing");

    AddDocTag(Tags::Hyperspectral);

    AddParameter(ParameterType_InputImage,  "in", "Input Image Filename");
    SetParameterDescription("in","The hyperspectral data cube input");

    AddParameter(ParameterType_Choice, "algo", "Unmixing algorithm");
    SetParameterDescription("algo", "The algorithm to use for the estimation");
    AddChoice("algo.elm", "Eigenvalue Likelihood Maximization");
    SetParameterDescription("algo.elm", "");
    AddChoice("algo.vd", "Virtual Dimensionality");
    SetParameterDescription("algo.vd", "");

    AddParameter( ParameterType_Float , "algo.vd.far" , "False alarm rate");
    SetMinimumParameterFloatValue("algo.vd.far", 0);
    SetMaximumParameterFloatValue("algo.vd.far", 1);
    SetDefaultParameterFloat( "algo.vd.far" , 1.0E-3 );
    SetParameterDescription( "algo.vd.far" ,
      "False alarm rate for the virtual dimensionality algorithm");

    AddParameter(ParameterType_Int,"number","Number of endmembers");
    SetParameterDescription("number", "Estimated number of endmembers");
    SetParameterRole("number", Role_Output);

    AddRAMParameter();

    // Doc example parameter settings
    SetDocExampleParameterValue("in", "cupriteSubHsi.tif");
    SetDocExampleParameterValue("algo", "vd");
    SetDocExampleParameterValue("algo.vd.far", "1.0E-3");

    SetOfficialDocLink();
  }

  void DoUpdateParameters() override
  {
    // Nothing to do here : all parameters are independent
  }

  void DoExecute() override
  {
    // Load input image
    auto inputImage = GetParameterImage("in");

    otbAppLogINFO("Computing statistics on input image...");
    auto statisticsFilter = StreamingStatisticsVectorImageFilterType::New();
    statisticsFilter->SetInput(inputImage);

    statisticsFilter->Update();

    auto correlationMatrix = statisticsFilter->GetCorrelation().GetVnlMatrix();
    auto covarianceMatrix = statisticsFilter->GetCovariance().GetVnlMatrix();
    auto numberOfPixels = inputImage->GetLargestPossibleRegion().GetNumberOfPixels();

    int numberOfEndmembers = 0;
    const std::string algorithm = GetParameterString("algo");
    if (algorithm=="elm")
      {
      otbAppLogINFO("Estimation algorithm: Eigenvalue Likelihood Maximization.");
      auto elm = EigenvalueLikelihoodMaximisationType::New();
      elm->SetCovariance(covarianceMatrix);
      elm->SetCorrelation(correlationMatrix);
      elm->SetNumberOfPixels(numberOfPixels);
      elm->Compute();
      numberOfEndmembers = elm->GetNumberOfEndmembers();
      }
    else if (algorithm=="vd")
      {
      otbAppLogINFO("Estimation algorithm: Virtual Dimensionality.");
      auto vd = VirtualDimensionalityType::New();
      vd->SetCovariance(covarianceMatrix);
      vd->SetCorrelation(correlationMatrix);
      vd->SetNumberOfPixels(numberOfPixels);
      vd->SetFAR(GetParameterFloat("algo.vd.far"));
      vd->Compute();
      numberOfEndmembers = vd->GetNumberOfEndmembers();
      }
    SetParameterInt("number", numberOfEndmembers);
  }

};

}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::EndmemberNumberEstimation)
<commit_msg>ENH: added progress reporting to the statistic estimation step<commit_after>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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 "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbStreamingStatisticsVectorImageFilter.h"
#include "otbEigenvalueLikelihoodMaximisation.h"
#include "otbVirtualDimensionality.h"

namespace otb
{
namespace Wrapper
{

class EndmemberNumberEstimation : public Application
{
public:
  /** Standard class typedefs. */
  typedef EndmemberNumberEstimation         Self;
  typedef Application                       Superclass;
  typedef itk::SmartPointer<Self>           Pointer;
  typedef itk::SmartPointer<const Self>     ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(EndmemberNumberEstimation, otb::Application);

  typedef otb::StreamingStatisticsVectorImageFilter<FloatVectorImageType, float> StreamingStatisticsVectorImageFilterType;
  typedef otb::VirtualDimensionality<float>                                      VirtualDimensionalityType;
  typedef otb::EigenvalueLikelihoodMaximisation<float>                           EigenvalueLikelihoodMaximisationType;

private:
  void DoInit() override
  {
    SetName("EndmemberNumberEstimation");
    SetDescription("Estimate the number of endmembers in a hyperspectral image");

    // Documentation
    SetDocName("Endmember Number Estimation");
    SetDocLongDescription("Estimate the number of endmembers "
    "in a hyperspectral image. First, compute statistics on the image and then "
    "apply an endmember number estimation algorithm using these statistics. Two "
    "algorithms are available:\n\n"

    "1. Virtual Dimensionality (VD) [1][2]\n"
    "2. Eigenvalue Likelihood Maximization (ELM) [3][4]\n\n"

    "The application then returns the estimated number of endmembers.\n\n"

    "[1] C.-I. Chang and Q. Du, Estimation of number of spectrally distinct signal "
    "sources in hyperspectral imagery, IEEE Transactions on Geoscience and Remote "
    "Sensing, vol. 43, no. 3, mar 2004.\n\n"

    "[2] J. Wang and C.-I. Chang, Applications of independent component analysis "
    "in endmember extraction and abundance quantification for hyperspectral imagery"
    ", IEEE Transactions on Geoscience and Remote Sensing, vol. 44, no. 9, pp. "
    "2601-1616, sep 2006.\n\n"

    "[3] Unsupervised Endmember Extraction of Martian Hyperspectral Images, B.Luo, "
    "J. Chanussot, S. Dout\'e and X. Ceamanos, IEEE Whispers 2009, Grenoble France, 2009\n\n"

    "[4] Unsupervised classification of hyperspectral images by using "
    "linear unmixing algorithm Luo, B. and Chanussot, J., IEEE Int. Conf. On Image"
    "Processing(ICIP) 2009, Cairo, Egypte, 2009"
    );

    SetDocLimitations("None");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("VertexComponentAnalysis, HyperspectralUnmixing");

    AddDocTag(Tags::Hyperspectral);

    AddParameter(ParameterType_InputImage,  "in", "Input Image Filename");
    SetParameterDescription("in","The hyperspectral data cube input");

    AddParameter(ParameterType_Choice, "algo", "Unmixing algorithm");
    SetParameterDescription("algo", "The algorithm to use for the estimation");
    AddChoice("algo.elm", "Eigenvalue Likelihood Maximization");
    SetParameterDescription("algo.elm", "");
    AddChoice("algo.vd", "Virtual Dimensionality");
    SetParameterDescription("algo.vd", "");

    AddParameter( ParameterType_Float , "algo.vd.far" , "False alarm rate");
    SetMinimumParameterFloatValue("algo.vd.far", 0);
    SetMaximumParameterFloatValue("algo.vd.far", 1);
    SetDefaultParameterFloat( "algo.vd.far" , 1.0E-3 );
    SetParameterDescription( "algo.vd.far" ,
      "False alarm rate for the virtual dimensionality algorithm");

    AddParameter(ParameterType_Int,"number","Number of endmembers");
    SetParameterDescription("number", "Estimated number of endmembers");
    SetParameterRole("number", Role_Output);

    AddRAMParameter();

    // Doc example parameter settings
    SetDocExampleParameterValue("in", "cupriteSubHsi.tif");
    SetDocExampleParameterValue("algo", "vd");
    SetDocExampleParameterValue("algo.vd.far", "1.0E-3");

    SetOfficialDocLink();
  }

  void DoUpdateParameters() override
  {
    // Nothing to do here : all parameters are independent
  }

  void DoExecute() override
  {
    // Load input image
    auto inputImage = GetParameterImage("in");

    otbAppLogINFO("Computing statistics on input image...");
    auto statisticsFilter = StreamingStatisticsVectorImageFilterType::New();
    statisticsFilter->SetInput(inputImage);
    AddProcess(statisticsFilter->GetStreamer(), "Statistic estimation step");

    statisticsFilter->Update();

    auto correlationMatrix = statisticsFilter->GetCorrelation().GetVnlMatrix();
    auto covarianceMatrix = statisticsFilter->GetCovariance().GetVnlMatrix();
    auto numberOfPixels = inputImage->GetLargestPossibleRegion().GetNumberOfPixels();

    int numberOfEndmembers = 0;
    const std::string algorithm = GetParameterString("algo");
    if (algorithm=="elm")
      {
      otbAppLogINFO("Estimation algorithm: Eigenvalue Likelihood Maximization.");
      auto elm = EigenvalueLikelihoodMaximisationType::New();
      elm->SetCovariance(covarianceMatrix);
      elm->SetCorrelation(correlationMatrix);
      elm->SetNumberOfPixels(numberOfPixels);
      elm->Compute();
      numberOfEndmembers = elm->GetNumberOfEndmembers();
      }
    else if (algorithm=="vd")
      {
      otbAppLogINFO("Estimation algorithm: Virtual Dimensionality.");
      auto vd = VirtualDimensionalityType::New();
      vd->SetCovariance(covarianceMatrix);
      vd->SetCorrelation(correlationMatrix);
      vd->SetNumberOfPixels(numberOfPixels);
      vd->SetFAR(GetParameterFloat("algo.vd.far"));
      vd->Compute();
      numberOfEndmembers = vd->GetNumberOfEndmembers();
      }
    SetParameterInt("number", numberOfEndmembers);
  }

};

}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::EndmemberNumberEstimation)
<|endoftext|>


<commit_before><commit_msg>Simplify expression to fix bool/sal_Bool ambiguity<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * 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 "src/trace_processor/importers/proto/heap_graph_tracker.h"

#include "perfetto/base/logging.h"
#include "test/gtest_and_gmock.h"

namespace perfetto {
namespace trace_processor {
namespace {

using ::testing::UnorderedElementsAre;

TEST(HeapGraphTrackerTest, PackageFromLocationApp) {
  TraceProcessorContext context;
  HeapGraphTracker tracker(&context);
  EXPECT_EQ(tracker.PackageFromLocation(
                "/data/app/~~ASDFGH1234QWerT==/"
                "com.twitter.android-MNBVCX7890SDTst6==/test.apk"),
            "com.twitter.android");
  EXPECT_EQ(tracker.PackageFromLocation(
                "/data/app/com.google.android.webview-6XfQhnaSkFwGK0sYL9is0G==/"
                "base.apk"),
            "com.google.android.webview");
}

TEST(HeapGraphTrackerTest, BuildFlamegraph) {
  //           4@A 5@B
  //             \ /
  //         2@Y 3@Y
  //           \ /
  //           1@X

  constexpr uint64_t kSeqId = 1;
  constexpr UniquePid kPid = 1;
  constexpr int64_t kTimestamp = 1;

  TraceProcessorContext context;
  context.storage.reset(new TraceStorage());

  HeapGraphTracker tracker(&context);

  constexpr uint64_t kField = 1;

  constexpr uint64_t kX = 1;
  constexpr uint64_t kY = 2;
  constexpr uint64_t kA = 3;
  constexpr uint64_t kB = 4;

  base::StringView field = base::StringView("foo");
  StringPool::Id x = context.storage->InternString("X");
  StringPool::Id y = context.storage->InternString("Y");
  StringPool::Id a = context.storage->InternString("A");
  StringPool::Id b = context.storage->InternString("B");

  tracker.AddInternedFieldName(kSeqId, kField, field);

  tracker.AddInternedTypeName(kSeqId, kX, x);
  tracker.AddInternedTypeName(kSeqId, kY, y);
  tracker.AddInternedTypeName(kSeqId, kA, a);
  tracker.AddInternedTypeName(kSeqId, kB, b);

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 1;
    obj.self_size = 1;
    obj.type_id = kX;
    HeapGraphTracker::SourceObject::Reference ref;
    ref.field_name_id = kField;
    ref.owned_object_id = 2;
    obj.references.emplace_back(std::move(ref));

    ref.field_name_id = kField;
    ref.owned_object_id = 3;
    obj.references.emplace_back(std::move(ref));

    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 2;
    obj.self_size = 2;
    obj.type_id = kY;
    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 3;
    obj.self_size = 3;
    obj.type_id = kY;
    HeapGraphTracker::SourceObject::Reference ref;
    ref.field_name_id = kField;
    ref.owned_object_id = 4;
    obj.references.emplace_back(std::move(ref));

    ref.field_name_id = kField;
    ref.owned_object_id = 5;
    obj.references.emplace_back(std::move(ref));

    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 4;
    obj.self_size = 4;
    obj.type_id = kA;
    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 5;
    obj.self_size = 5;
    obj.type_id = kB;
    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  HeapGraphTracker::SourceRoot root;
  root.root_type = context.storage->InternString("ROOT");
  root.object_ids.emplace_back(1);
  tracker.AddRoot(kSeqId, kPid, kTimestamp, root);

  tracker.FinalizeProfile(kSeqId);
  std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> flame =
      tracker.BuildFlamegraph(kPid, kTimestamp);
  ASSERT_NE(flame, nullptr);

  auto cumulative_sizes = flame->cumulative_size().ToVectorForTesting();
  EXPECT_THAT(cumulative_sizes, UnorderedElementsAre(15, 4, 14, 5));

  auto cumulative_counts = flame->cumulative_count().ToVectorForTesting();
  EXPECT_THAT(cumulative_counts, UnorderedElementsAre(5, 4, 1, 1));

  auto sizes = flame->size().ToVectorForTesting();
  EXPECT_THAT(sizes, UnorderedElementsAre(1, 5, 4, 5));

  auto counts = flame->count().ToVectorForTesting();
  EXPECT_THAT(counts, UnorderedElementsAre(1, 2, 1, 1));
}

static const char kArray[] = "X[]";
static const char kDoubleArray[] = "X[][]";
static const char kNoArray[] = "X";
static const char kLongNoArray[] = "ABCDE";
static const char kStaticClassNoArray[] = "java.lang.Class<abc>";
static const char kStaticClassArray[] = "java.lang.Class<abc[]>";

TEST(HeapGraphTrackerTest, NormalizeTypeName) {
  // sizeof(...) - 1 below to get rid of the null-byte.
  EXPECT_EQ(NormalizeTypeName(base::StringView(kArray, sizeof(kArray) - 1))
                .ToStdString(),
            "X");
  EXPECT_EQ(NormalizeTypeName(
                base::StringView(kDoubleArray, sizeof(kDoubleArray) - 1))
                .ToStdString(),
            "X");
  EXPECT_EQ(NormalizeTypeName(base::StringView(kNoArray, sizeof(kNoArray) - 1))
                .ToStdString(),
            "X");
  EXPECT_EQ(NormalizeTypeName(
                base::StringView(kLongNoArray, sizeof(kLongNoArray) - 1))
                .ToStdString(),
            "ABCDE");
  EXPECT_EQ(NormalizeTypeName(base::StringView(kStaticClassNoArray,
                                               sizeof(kStaticClassNoArray) - 1))
                .ToStdString(),
            "abc");
  EXPECT_EQ(NormalizeTypeName(base::StringView(kStaticClassArray,
                                               sizeof(kStaticClassArray) - 1))
                .ToStdString(),
            "abc");
}

TEST(HeapGraphTrackerTest, NumberOfArray) {
  // sizeof(...) - 1 below to get rid of the null-byte.
  EXPECT_EQ(NumberOfArrays(base::StringView(kArray, sizeof(kArray) - 1)), 1u);
  EXPECT_EQ(
      NumberOfArrays(base::StringView(kDoubleArray, sizeof(kDoubleArray) - 1)),
      2u);
  EXPECT_EQ(NumberOfArrays(base::StringView(kNoArray, sizeof(kNoArray) - 1)),
            0u);
  EXPECT_EQ(
      NumberOfArrays(base::StringView(kLongNoArray, sizeof(kLongNoArray) - 1)),
      0u);
}

}  // namespace
}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>Set TraceStorage for TraceProcessorContext.<commit_after>/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * 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 "src/trace_processor/importers/proto/heap_graph_tracker.h"

#include "perfetto/base/logging.h"
#include "test/gtest_and_gmock.h"

namespace perfetto {
namespace trace_processor {
namespace {

using ::testing::UnorderedElementsAre;

TEST(HeapGraphTrackerTest, PackageFromLocationApp) {
  TraceProcessorContext context;
  context.storage.reset(new TraceStorage);
  HeapGraphTracker tracker(&context);
  EXPECT_EQ(tracker.PackageFromLocation(
                "/data/app/~~ASDFGH1234QWerT==/"
                "com.twitter.android-MNBVCX7890SDTst6==/test.apk"),
            "com.twitter.android");
  EXPECT_EQ(tracker.PackageFromLocation(
                "/data/app/com.google.android.webview-6XfQhnaSkFwGK0sYL9is0G==/"
                "base.apk"),
            "com.google.android.webview");
}

TEST(HeapGraphTrackerTest, BuildFlamegraph) {
  //           4@A 5@B
  //             \ /
  //         2@Y 3@Y
  //           \ /
  //           1@X

  constexpr uint64_t kSeqId = 1;
  constexpr UniquePid kPid = 1;
  constexpr int64_t kTimestamp = 1;

  TraceProcessorContext context;
  context.storage.reset(new TraceStorage());

  HeapGraphTracker tracker(&context);

  constexpr uint64_t kField = 1;

  constexpr uint64_t kX = 1;
  constexpr uint64_t kY = 2;
  constexpr uint64_t kA = 3;
  constexpr uint64_t kB = 4;

  base::StringView field = base::StringView("foo");
  StringPool::Id x = context.storage->InternString("X");
  StringPool::Id y = context.storage->InternString("Y");
  StringPool::Id a = context.storage->InternString("A");
  StringPool::Id b = context.storage->InternString("B");

  tracker.AddInternedFieldName(kSeqId, kField, field);

  tracker.AddInternedTypeName(kSeqId, kX, x);
  tracker.AddInternedTypeName(kSeqId, kY, y);
  tracker.AddInternedTypeName(kSeqId, kA, a);
  tracker.AddInternedTypeName(kSeqId, kB, b);

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 1;
    obj.self_size = 1;
    obj.type_id = kX;
    HeapGraphTracker::SourceObject::Reference ref;
    ref.field_name_id = kField;
    ref.owned_object_id = 2;
    obj.references.emplace_back(std::move(ref));

    ref.field_name_id = kField;
    ref.owned_object_id = 3;
    obj.references.emplace_back(std::move(ref));

    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 2;
    obj.self_size = 2;
    obj.type_id = kY;
    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 3;
    obj.self_size = 3;
    obj.type_id = kY;
    HeapGraphTracker::SourceObject::Reference ref;
    ref.field_name_id = kField;
    ref.owned_object_id = 4;
    obj.references.emplace_back(std::move(ref));

    ref.field_name_id = kField;
    ref.owned_object_id = 5;
    obj.references.emplace_back(std::move(ref));

    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 4;
    obj.self_size = 4;
    obj.type_id = kA;
    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  {
    HeapGraphTracker::SourceObject obj;
    obj.object_id = 5;
    obj.self_size = 5;
    obj.type_id = kB;
    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
  }

  HeapGraphTracker::SourceRoot root;
  root.root_type = context.storage->InternString("ROOT");
  root.object_ids.emplace_back(1);
  tracker.AddRoot(kSeqId, kPid, kTimestamp, root);

  tracker.FinalizeProfile(kSeqId);
  std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> flame =
      tracker.BuildFlamegraph(kPid, kTimestamp);
  ASSERT_NE(flame, nullptr);

  auto cumulative_sizes = flame->cumulative_size().ToVectorForTesting();
  EXPECT_THAT(cumulative_sizes, UnorderedElementsAre(15, 4, 14, 5));

  auto cumulative_counts = flame->cumulative_count().ToVectorForTesting();
  EXPECT_THAT(cumulative_counts, UnorderedElementsAre(5, 4, 1, 1));

  auto sizes = flame->size().ToVectorForTesting();
  EXPECT_THAT(sizes, UnorderedElementsAre(1, 5, 4, 5));

  auto counts = flame->count().ToVectorForTesting();
  EXPECT_THAT(counts, UnorderedElementsAre(1, 2, 1, 1));
}

static const char kArray[] = "X[]";
static const char kDoubleArray[] = "X[][]";
static const char kNoArray[] = "X";
static const char kLongNoArray[] = "ABCDE";
static const char kStaticClassNoArray[] = "java.lang.Class<abc>";
static const char kStaticClassArray[] = "java.lang.Class<abc[]>";

TEST(HeapGraphTrackerTest, NormalizeTypeName) {
  // sizeof(...) - 1 below to get rid of the null-byte.
  EXPECT_EQ(NormalizeTypeName(base::StringView(kArray, sizeof(kArray) - 1))
                .ToStdString(),
            "X");
  EXPECT_EQ(NormalizeTypeName(
                base::StringView(kDoubleArray, sizeof(kDoubleArray) - 1))
                .ToStdString(),
            "X");
  EXPECT_EQ(NormalizeTypeName(base::StringView(kNoArray, sizeof(kNoArray) - 1))
                .ToStdString(),
            "X");
  EXPECT_EQ(NormalizeTypeName(
                base::StringView(kLongNoArray, sizeof(kLongNoArray) - 1))
                .ToStdString(),
            "ABCDE");
  EXPECT_EQ(NormalizeTypeName(base::StringView(kStaticClassNoArray,
                                               sizeof(kStaticClassNoArray) - 1))
                .ToStdString(),
            "abc");
  EXPECT_EQ(NormalizeTypeName(base::StringView(kStaticClassArray,
                                               sizeof(kStaticClassArray) - 1))
                .ToStdString(),
            "abc");
}

TEST(HeapGraphTrackerTest, NumberOfArray) {
  // sizeof(...) - 1 below to get rid of the null-byte.
  EXPECT_EQ(NumberOfArrays(base::StringView(kArray, sizeof(kArray) - 1)), 1u);
  EXPECT_EQ(
      NumberOfArrays(base::StringView(kDoubleArray, sizeof(kDoubleArray) - 1)),
      2u);
  EXPECT_EQ(NumberOfArrays(base::StringView(kNoArray, sizeof(kNoArray) - 1)),
            0u);
  EXPECT_EQ(
      NumberOfArrays(base::StringView(kLongNoArray, sizeof(kLongNoArray) - 1)),
      0u);
}

}  // namespace
}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>