<commit_before>// Benchmark.cpp : Defines the entry point for the console application.
//

#include <string>
#include <iomanip>
#include <iostream>
#include <chrono>
#include <vector>
#include "../TestBinStream/SimpleBinStream.h"
#include "OldSimpleBinStream.h"

#ifdef WIN32

#pragma optimize("", off)
template <class T>
void do_not_optimize_away(T&& datum) {
	datum = datum;
}
#pragma optimize("", on)

#else
static void do_not_optimize_away(const char* p) {
	asm volatile("" : : "g"(p) : "memory");
}
#endif

class timer
{
public:
	timer() = default;
	void start_timing(const std::string& text_)
	{
		text = text_;
		begin = std::chrono::high_resolution_clock::now();
	}
	void stop_timing()
	{
		auto end = std::chrono::high_resolution_clock::now();
		auto dur = end - begin;
		auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
		std::cout << std::setw(30) << text << ":" << std::setw(5) << ms << "ms" << std::endl;
	}

private:
	std::string text;
	std::chrono::high_resolution_clock::time_point begin;
};

struct Product
{
	Product() : name(""), qty(0), price(0.0f) {}
	Product(std::string name_, int qty_, float price_) : name(name_), qty(qty_), price(price_) {}
	std::string name;
	int qty;
	float price;
};

void init(std::vector<Product>& vec);

int main(int argc, char *argv[])
{
	const std::string old_file = "F:\\old_products.txt";
	const std::string new_file = "F:\\new_products.txt";
	const std::string mem_file = "F:\\mem_products.txt";

	const size_t MAX_LOOP = (argc == 2) ? atoi(argv[1]) : 100000;

	std::vector<Product> vec;
	init(vec);

	std::string result = "";
	const std::string trimChars = "\"";
	timer stopwatch;

	// file stream benchmark
	//=========================
	{
		using namespace old;

		file_ostream<std::true_type> os(old_file.c_str());

		if (os.is_open())
		{
			stopwatch.start_timing("old::file_ostream");
			for (size_t k = 0; k < MAX_LOOP; ++k)
			{
				for (size_t i = 0; i < vec.size(); ++i)
				{
					const Product& product = vec[i];
					os << product.name << product.qty << product.price;
					do_not_optimize_away(result.c_str());
				}
			}
			stopwatch.stop_timing();
		}
		os.flush();
		os.close();

		file_istream<std::true_type> is(old_file.c_str());

		if (is.is_open())
		{
			Product product;
			stopwatch.start_timing("old::file_istream");
			try
			{
				while (!is.eof())
				{
					is >> product.name >> product.qty >> product.price;
				}
			}
			catch (std::runtime_error& e)
			{
				fprintf(stderr, "%s\n", e.what());
			}
			stopwatch.stop_timing();
		}
	}
	{
		using namespace simple;

		file_ostream<std::true_type> os(new_file.c_str());

		if (os.is_open())
		{
			stopwatch.start_timing("new::file_ostream");
			for (size_t k = 0; k < MAX_LOOP; ++k)
			{
				for (size_t i = 0; i < vec.size(); ++i)
				{
					const Product& product = vec[i];
					os << product.name << product.qty << product.price;
					do_not_optimize_away(result.c_str());
				}
			}
			stopwatch.stop_timing();
		}
		os.flush();
		os.close();

		file_istream<std::true_type> is(new_file.c_str());

		if (is.is_open())
		{
			Product product;
			stopwatch.start_timing("new::file_istream");
			try
			{
				while (!is.eof())
				{
					is >> product.name >> product.qty >> product.price;
				}
			}
			catch (std::runtime_error& e)
			{
				fprintf(stderr, "%s\n", e.what());
			}
			stopwatch.stop_timing();
		}

		is.close();
	}
	{
		using namespace simple;

		memfile_ostream<std::true_type> os;

		stopwatch.start_timing("new::memfile_ostream");
		for (size_t k = 0; k < MAX_LOOP; ++k)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				const Product& product = vec[i];
				os << product.name << product.qty << product.price;
				do_not_optimize_away(result.c_str());
			}
		}
		os.write_to_file(mem_file.c_str());
		stopwatch.stop_timing();

		memfile_istream<std::true_type> is_copy(mem_file.c_str());

		if (is_copy.is_open())
		{
			Product product;
			stopwatch.start_timing("new::memfile_istream");
			try
			{
				while (!is_copy.eof())
				{
					is_copy >> product.name >> product.qty >> product.price;
				}
			}
			catch (std::runtime_error& e)
			{
				fprintf(stderr, "%s\n", e.what());
			}
			stopwatch.stop_timing();
		}
		is_copy.close();
	}

	{
		using namespace simple;

		mem_ostream<std::true_type> os;

		stopwatch.start_timing("new::mem_ostream");
		for (size_t k = 0; k < MAX_LOOP; ++k)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				const Product& product = vec[i];
				os << product.name << product.qty << product.price;
				do_not_optimize_away(result.c_str());
			}
		}
		stopwatch.stop_timing();

		mem_istream<std::true_type> is(os.get_internal_vec());

		Product product;
		stopwatch.start_timing("new::mem_istream");
		try
		{
			while (!is.eof())
			{
				is >> product.name >> product.qty >> product.price;
			}
		}
		catch (std::runtime_error& e)
		{
			fprintf(stderr, "%s\n", e.what());
		}
		stopwatch.stop_timing();

		ptr_istream<std::true_type> ptr_is(os.get_internal_vec());

		stopwatch.start_timing("new::ptr_istream");
		try
		{
			while (!ptr_is.eof())
			{
				ptr_is >> product.name >> product.qty >> product.price;
			}
		}
		catch (std::runtime_error& e)
		{
			fprintf(stderr, "%s\n", e.what());
		}
		stopwatch.stop_timing();
	}

	return 0;
}

void init(std::vector<Product>& vec)
{
	vec.push_back(Product("Apples", 5, 2.5f));
	vec.push_back(Product("Shampoo", 125, 12.5f));
	vec.push_back(Product("Soap", 250, 30.25f));
	vec.push_back(Product("Instant Ramen", 125, 12.5f));
	vec.push_back(Product("Canned Sardines", 20, 50.7f));
	vec.push_back(Product("Color Book", 10, 10.5f));
	vec.push_back(Product("Speakers", 40, 1089.75f));
	vec.push_back(Product("Photo Holder", 34, 56.85f));
	vec.push_back(Product("Microphone", 12, 572.43f));
	vec.push_back(Product("Sound card", 8, 1250.62f));

	/*
	// mostly long strings
	vec.push_back(Product("Apples and Oranges", 5, 2.5f));
	vec.push_back(Product("Shampoo and Conditioners", 125, 12.5f));
	vec.push_back(Product("Soap / body foam", 250, 30.25f));
	vec.push_back(Product("Instant Ramen / Udon", 125, 12.5f));
	vec.push_back(Product("Canned Sardines", 20, 50.7f));
	vec.push_back(Product("Color Book / Color pencils / Drawing Paper", 10, 10.5f));
	vec.push_back(Product("Audio Speakers / Subwoofer", 40, 1089.75f));
	vec.push_back(Product("Camera and Photo Holder", 34, 56.85f));
	vec.push_back(Product("Classic Microphone", 12, 572.43f));
	vec.push_back(Product("Sound card", 8, 1250.62f));
	*/
}
<commit_msg>Rename start_timing/stop_timing to start/stop<commit_after>// Benchmark.cpp : Defines the entry point for the console application.
//

#include <string>
#include <iomanip>
#include <iostream>
#include <chrono>
#include <vector>
#include "../TestBinStream/SimpleBinStream.h"
#include "OldSimpleBinStream.h"

#ifdef WIN32

#pragma optimize("", off)
template <class T>
void do_not_optimize_away(T&& datum) {
	datum = datum;
}
#pragma optimize("", on)

#else
static void do_not_optimize_away(const char* p) {
	asm volatile("" : : "g"(p) : "memory");
}
#endif

class timer
{
public:
	timer() = default;
	void start(const std::string& text_)
	{
		text = text_;
		begin = std::chrono::high_resolution_clock::now();
	}
	void stop()
	{
		auto end = std::chrono::high_resolution_clock::now();
		auto dur = end - begin;
		auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
		std::cout << std::setw(30) << text << ":" << std::setw(5) << ms << "ms" << std::endl;
	}

private:
	std::string text;
	std::chrono::high_resolution_clock::time_point begin;
};

struct Product
{
	Product() : name(""), qty(0), price(0.0f) {}
	Product(std::string name_, int qty_, float price_) : name(name_), qty(qty_), price(price_) {}
	std::string name;
	int qty;
	float price;
};

void init(std::vector<Product>& vec);

int main(int argc, char *argv[])
{
	const std::string old_file = "F:\\old_products.txt";
	const std::string new_file = "F:\\new_products.txt";
	const std::string mem_file = "F:\\mem_products.txt";

	const size_t MAX_LOOP = (argc == 2) ? atoi(argv[1]) : 100000;

	std::vector<Product> vec;
	init(vec);

	std::string result = "";
	const std::string trimChars = "\"";
	timer stopwatch;

	// file stream benchmark
	//=========================
	{
		using namespace old;

		file_ostream<std::true_type> os(old_file.c_str());

		if (os.is_open())
		{
			stopwatch.start("old::file_ostream");
			for (size_t k = 0; k < MAX_LOOP; ++k)
			{
				for (size_t i = 0; i < vec.size(); ++i)
				{
					const Product& product = vec[i];
					os << product.name << product.qty << product.price;
					do_not_optimize_away(result.c_str());
				}
			}
			stopwatch.stop();
		}
		os.flush();
		os.close();

		file_istream<std::true_type> is(old_file.c_str());

		if (is.is_open())
		{
			Product product;
			stopwatch.start("old::file_istream");
			try
			{
				while (!is.eof())
				{
					is >> product.name >> product.qty >> product.price;
				}
			}
			catch (std::runtime_error& e)
			{
				fprintf(stderr, "%s\n", e.what());
			}
			stopwatch.stop();
		}
	}
	{
		using namespace simple;

		file_ostream<std::true_type> os(new_file.c_str());

		if (os.is_open())
		{
			stopwatch.start("new::file_ostream");
			for (size_t k = 0; k < MAX_LOOP; ++k)
			{
				for (size_t i = 0; i < vec.size(); ++i)
				{
					const Product& product = vec[i];
					os << product.name << product.qty << product.price;
					do_not_optimize_away(result.c_str());
				}
			}
			stopwatch.stop();
		}
		os.flush();
		os.close();

		file_istream<std::true_type> is(new_file.c_str());

		if (is.is_open())
		{
			Product product;
			stopwatch.start("new::file_istream");
			try
			{
				while (!is.eof())
				{
					is >> product.name >> product.qty >> product.price;
				}
			}
			catch (std::runtime_error& e)
			{
				fprintf(stderr, "%s\n", e.what());
			}
			stopwatch.stop();
		}

		is.close();
	}
	{
		using namespace simple;

		memfile_ostream<std::true_type> os;

		stopwatch.start("new::memfile_ostream");
		for (size_t k = 0; k < MAX_LOOP; ++k)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				const Product& product = vec[i];
				os << product.name << product.qty << product.price;
				do_not_optimize_away(result.c_str());
			}
		}
		os.write_to_file(mem_file.c_str());
		stopwatch.stop();

		memfile_istream<std::true_type> is_copy(mem_file.c_str());

		if (is_copy.is_open())
		{
			Product product;
			stopwatch.start("new::memfile_istream");
			try
			{
				while (!is_copy.eof())
				{
					is_copy >> product.name >> product.qty >> product.price;
				}
			}
			catch (std::runtime_error& e)
			{
				fprintf(stderr, "%s\n", e.what());
			}
			stopwatch.stop();
		}
		is_copy.close();
	}

	{
		using namespace simple;

		mem_ostream<std::true_type> os;

		stopwatch.start("new::mem_ostream");
		for (size_t k = 0; k < MAX_LOOP; ++k)
		{
			for (size_t i = 0; i < vec.size(); ++i)
			{
				const Product& product = vec[i];
				os << product.name << product.qty << product.price;
				do_not_optimize_away(result.c_str());
			}
		}
		stopwatch.stop();

		mem_istream<std::true_type> is(os.get_internal_vec());

		Product product;
		stopwatch.start("new::mem_istream");
		try
		{
			while (!is.eof())
			{
				is >> product.name >> product.qty >> product.price;
			}
		}
		catch (std::runtime_error& e)
		{
			fprintf(stderr, "%s\n", e.what());
		}
		stopwatch.stop();

		ptr_istream<std::true_type> ptr_is(os.get_internal_vec());

		stopwatch.start("new::ptr_istream");
		try
		{
			while (!ptr_is.eof())
			{
				ptr_is >> product.name >> product.qty >> product.price;
			}
		}
		catch (std::runtime_error& e)
		{
			fprintf(stderr, "%s\n", e.what());
		}
		stopwatch.stop();
	}

	return 0;
}

void init(std::vector<Product>& vec)
{
	vec.push_back(Product("Apples", 5, 2.5f));
	vec.push_back(Product("Shampoo", 125, 12.5f));
	vec.push_back(Product("Soap", 250, 30.25f));
	vec.push_back(Product("Instant Ramen", 125, 12.5f));
	vec.push_back(Product("Canned Sardines", 20, 50.7f));
	vec.push_back(Product("Color Book", 10, 10.5f));
	vec.push_back(Product("Speakers", 40, 1089.75f));
	vec.push_back(Product("Photo Holder", 34, 56.85f));
	vec.push_back(Product("Microphone", 12, 572.43f));
	vec.push_back(Product("Sound card", 8, 1250.62f));

	/*
	// mostly long strings
	vec.push_back(Product("Apples and Oranges", 5, 2.5f));
	vec.push_back(Product("Shampoo and Conditioners", 125, 12.5f));
	vec.push_back(Product("Soap / body foam", 250, 30.25f));
	vec.push_back(Product("Instant Ramen / Udon", 125, 12.5f));
	vec.push_back(Product("Canned Sardines", 20, 50.7f));
	vec.push_back(Product("Color Book / Color pencils / Drawing Paper", 10, 10.5f));
	vec.push_back(Product("Audio Speakers / Subwoofer", 40, 1089.75f));
	vec.push_back(Product("Camera and Photo Holder", 34, 56.85f));
	vec.push_back(Product("Classic Microphone", 12, 572.43f));
	vec.push_back(Product("Sound card", 8, 1250.62f));
	*/
}
<|endoftext|>


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

#include "chrome/browser/browser_process.h"

#include "atom/browser/api/atom_api_app.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/path_service.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "brave/browser/component_updater/brave_component_updater_configurator.h"
#include "brightray/browser/brightray_paths.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/component_updater/component_updater_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "ppapi/features/features.h"
#include "ui/base/idle/idle.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/message_center.h"

#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "atom/browser/extensions/atom_extensions_browser_client.h"
#include "chrome/browser/extensions/event_router_forwarder.h"
#include "chrome/common/extensions/extension_process_policy.h"
#include "chrome/common/extensions/chrome_extensions_client.h"
#include "extensions/common/constants.h"
#include "extensions/common/features/feature_provider.h"
#include "ui/base/resource/resource_bundle.h"
#endif

#if BUILDFLAG(ENABLE_PLUGINS)
#include "brave/browser/plugins/brave_plugin_service_filter.h"
#include "chrome/browser/plugins/plugin_finder.h"
#include "content/public/browser/plugin_service.h"
#endif

using content::ChildProcessSecurityPolicy;
using content::PluginService;

BrowserProcess* g_browser_process = NULL;

BrowserProcess::BrowserProcess()
    : tearing_down_(false),
      created_profile_manager_(false) {
  g_browser_process = this;

  print_job_manager_.reset(new printing::PrintJobManager);

#if defined(OS_MACOSX)
  ui::InitIdleMonitor();
#endif

#if BUILDFLAG(ENABLE_EXTENSIONS)
  extension_event_router_forwarder_ = new extensions::EventRouterForwarder;

  extensions::ExtensionsClient::Set(
      extensions::ChromeExtensionsClient::GetInstance());
  extensions_browser_client_.reset(
      new extensions::AtomExtensionsBrowserClient());
  extensions::ExtensionsBrowserClient::Set(extensions_browser_client_.get());
#endif

  message_center::MessageCenter::Initialize();
}

BrowserProcess::~BrowserProcess() {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  extensions::ExtensionsBrowserClient::Set(nullptr);
#endif
  g_browser_process = NULL;
}

void BrowserProcess::CreateProfileManager() {
  DCHECK(!created_profile_manager_ && !profile_manager_);
  created_profile_manager_ = true;

  base::FilePath user_data_dir;
  PathService::Get(brightray::DIR_USER_DATA, &user_data_dir);
  profile_manager_.reset(new ProfileManager(user_data_dir));
}

ProfileManager* BrowserProcess::profile_manager() {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!created_profile_manager_)
    CreateProfileManager();
  return profile_manager_.get();
}

rappor::RapporService* BrowserProcess::rappor_service() {
  return nullptr;
}

component_updater::ComponentUpdateService*
BrowserProcess::component_updater(
    std::unique_ptr<component_updater::ComponentUpdateService> &component_updater,
    bool use_brave_server) {
  if (!component_updater.get()) {
    if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI))
      return NULL;
    auto browser_context = atom::AtomBrowserContext::From("", false);
    scoped_refptr<update_client::Configurator> configurator =
        component_updater::MakeBraveComponentUpdaterConfigurator(
            base::CommandLine::ForCurrentProcess(),
            browser_context->GetRequestContext(),
            use_brave_server);
    // Creating the component updater does not do anything, components
    // need to be registered and Start() needs to be called.
    component_updater.reset(component_updater::ComponentUpdateServiceFactory(
                                 configurator).release());
  }
  return component_updater.get();
}

component_updater::ComponentUpdateService*
BrowserProcess::brave_component_updater() {
  return component_updater(brave_component_updater_, true);
}

component_updater::ComponentUpdateService*
BrowserProcess::component_updater() {
  return component_updater(component_updater_, false);
}

extensions::EventRouterForwarder*
BrowserProcess::extension_event_router_forwarder() {
  return extension_event_router_forwarder_.get();
}

void BrowserProcess::StartTearDown() {
  tearing_down_ = true;
  print_job_manager_->Shutdown();

  profile_manager_.reset();

  message_center::MessageCenter::Shutdown();
}

std::string BrowserProcess::GetApplicationLocale() {
  return l10n_util::GetApplicationLocale("");
}

printing::PrintJobManager* BrowserProcess::print_job_manager() {
  return print_job_manager_.get();
}

bool BrowserProcess::IsShuttingDown() {
  return tearing_down_;
}

void BrowserProcess::ResourceDispatcherHostCreated() {
  resource_dispatcher_host_delegate_.reset(
      new atom::AtomResourceDispatcherHostDelegate);
  content::ResourceDispatcherHost::Get()->SetDelegate(
      resource_dispatcher_host_delegate_.get());
}

void BrowserProcess::PreCreateThreads() {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  // Register the chrome-extension scheme to reflect the extension process
  // model. Controlled by a field trial, so we can't do this earlier.
  base::FieldTrialList::FindFullName("SiteIsolationExtensions");
  if (extensions::IsIsolateExtensionsEnabled()) {
    // chrome-extension:// URLs are safe to request anywhere, but may only
    // commit (including in iframes) in extension processes.
    ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeIsolatedScheme(
        extensions::kExtensionScheme, true);
  } else {
    ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(
        extensions::kExtensionScheme);
  }
#endif
}

void BrowserProcess::PreMainMessageLoopRun() {
#if BUILDFLAG(ENABLE_PLUGINS)
  PluginService* plugin_service = PluginService::GetInstance();
  plugin_service->SetFilter(BravePluginServiceFilter::GetInstance());

  // Triggers initialization of the singleton instance on UI thread.
  PluginFinder::GetInstance()->Init();

#endif  // BUILDFLAG(ENABLE_PLUGINS)
}
<commit_msg>request close of any remaining renderer processes (background, etc…) on exit auditors @bbondy @darkdh<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/browser_process.h"

#include "atom/browser/api/atom_api_app.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/path_service.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "brave/browser/component_updater/brave_component_updater_configurator.h"
#include "brightray/browser/brightray_paths.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/component_updater/component_updater_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "ppapi/features/features.h"
#include "ui/base/idle/idle.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/message_center.h"

#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "atom/browser/extensions/atom_extensions_browser_client.h"
#include "chrome/browser/extensions/event_router_forwarder.h"
#include "chrome/common/extensions/extension_process_policy.h"
#include "chrome/common/extensions/chrome_extensions_client.h"
#include "extensions/common/constants.h"
#include "extensions/common/features/feature_provider.h"
#include "ui/base/resource/resource_bundle.h"
#endif

#if BUILDFLAG(ENABLE_PLUGINS)
#include "brave/browser/plugins/brave_plugin_service_filter.h"
#include "chrome/browser/plugins/plugin_finder.h"
#include "content/public/browser/plugin_service.h"
#endif

using content::ChildProcessSecurityPolicy;
using content::PluginService;

BrowserProcess* g_browser_process = NULL;

BrowserProcess::BrowserProcess()
    : tearing_down_(false),
      created_profile_manager_(false) {
  g_browser_process = this;

  print_job_manager_.reset(new printing::PrintJobManager);

#if defined(OS_MACOSX)
  ui::InitIdleMonitor();
#endif

#if BUILDFLAG(ENABLE_EXTENSIONS)
  extension_event_router_forwarder_ = new extensions::EventRouterForwarder;

  extensions::ExtensionsClient::Set(
      extensions::ChromeExtensionsClient::GetInstance());
  extensions_browser_client_.reset(
      new extensions::AtomExtensionsBrowserClient());
  extensions::ExtensionsBrowserClient::Set(extensions_browser_client_.get());
#endif

  message_center::MessageCenter::Initialize();
}

BrowserProcess::~BrowserProcess() {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  extensions::ExtensionsBrowserClient::Set(nullptr);
#endif
  g_browser_process = NULL;
}

void BrowserProcess::CreateProfileManager() {
  DCHECK(!created_profile_manager_ && !profile_manager_);
  created_profile_manager_ = true;

  base::FilePath user_data_dir;
  PathService::Get(brightray::DIR_USER_DATA, &user_data_dir);
  profile_manager_.reset(new ProfileManager(user_data_dir));
}

ProfileManager* BrowserProcess::profile_manager() {
  DCHECK(thread_checker_.CalledOnValidThread());
  if (!created_profile_manager_)
    CreateProfileManager();
  return profile_manager_.get();
}

rappor::RapporService* BrowserProcess::rappor_service() {
  return nullptr;
}

component_updater::ComponentUpdateService*
BrowserProcess::component_updater(
    std::unique_ptr<component_updater::ComponentUpdateService> &component_updater,
    bool use_brave_server) {
  if (!component_updater.get()) {
    if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI))
      return NULL;
    auto browser_context = atom::AtomBrowserContext::From("", false);
    scoped_refptr<update_client::Configurator> configurator =
        component_updater::MakeBraveComponentUpdaterConfigurator(
            base::CommandLine::ForCurrentProcess(),
            browser_context->GetRequestContext(),
            use_brave_server);
    // Creating the component updater does not do anything, components
    // need to be registered and Start() needs to be called.
    component_updater.reset(component_updater::ComponentUpdateServiceFactory(
                                 configurator).release());
  }
  return component_updater.get();
}

component_updater::ComponentUpdateService*
BrowserProcess::brave_component_updater() {
  return component_updater(brave_component_updater_, true);
}

component_updater::ComponentUpdateService*
BrowserProcess::component_updater() {
  return component_updater(component_updater_, false);
}

extensions::EventRouterForwarder*
BrowserProcess::extension_event_router_forwarder() {
  return extension_event_router_forwarder_.get();
}

void BrowserProcess::StartTearDown() {
  tearing_down_ = true;

  for (content::RenderProcessHost::iterator i(
          content::RenderProcessHost::AllHostsIterator());
       !i.IsAtEnd(); i.Advance()) {
    i.GetCurrentValue()->FastShutdownIfPossible();
  }

  print_job_manager_->Shutdown();

  profile_manager_.reset();

  message_center::MessageCenter::Shutdown();
}

std::string BrowserProcess::GetApplicationLocale() {
  return l10n_util::GetApplicationLocale("");
}

printing::PrintJobManager* BrowserProcess::print_job_manager() {
  return print_job_manager_.get();
}

bool BrowserProcess::IsShuttingDown() {
  return tearing_down_;
}

void BrowserProcess::ResourceDispatcherHostCreated() {
  resource_dispatcher_host_delegate_.reset(
      new atom::AtomResourceDispatcherHostDelegate);
  content::ResourceDispatcherHost::Get()->SetDelegate(
      resource_dispatcher_host_delegate_.get());
}

void BrowserProcess::PreCreateThreads() {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  // Register the chrome-extension scheme to reflect the extension process
  // model. Controlled by a field trial, so we can't do this earlier.
  base::FieldTrialList::FindFullName("SiteIsolationExtensions");
  if (extensions::IsIsolateExtensionsEnabled()) {
    // chrome-extension:// URLs are safe to request anywhere, but may only
    // commit (including in iframes) in extension processes.
    ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeIsolatedScheme(
        extensions::kExtensionScheme, true);
  } else {
    ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(
        extensions::kExtensionScheme);
  }
#endif
}

void BrowserProcess::PreMainMessageLoopRun() {
#if BUILDFLAG(ENABLE_PLUGINS)
  PluginService* plugin_service = PluginService::GetInstance();
  plugin_service->SetFilter(BravePluginServiceFilter::GetInstance());

  // Triggers initialization of the singleton instance on UI thread.
  PluginFinder::GetInstance()->Init();

#endif  // BUILDFLAG(ENABLE_PLUGINS)
}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief Source for leaf plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

#include "leaf.hpp"

#include <kdbhelper.h>

using std::exception;

using elektra::LeafDelegate;

using CppKey = kdb::Key;
using CppKeySet = kdb::KeySet;

namespace
{

/**
 * @brief This function returns a key set containing the plugin contract.
 *
 * @return A key set specifying the capabilities of the plugin
 */
CppKeySet getContract ()
{
	return CppKeySet{ 30,
			  keyNew ("system/elektra/modules/leaf", KEY_VALUE, "leaf plugin waits for your orders", KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports", KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports/open", KEY_FUNC, elektraLeafOpen, KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports/close", KEY_FUNC, elektraLeafClose, KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports/get", KEY_FUNC, elektraLeafGet, KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports/set", KEY_FUNC, elektraLeafSet, KEY_END),
#include ELEKTRA_README (leaf)
			  keyNew ("system/elektra/modules/leaf/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END),
			  KS_END };
}

} // end namespace

extern "C" {

typedef Delegator<LeafDelegate> delegator;

/** @see elektraDocOpen */
int elektraLeafOpen (Plugin * handle, Key * key)
{
	// After the call to `delegator::open` you can retrieve a pointer to the delegate via `coderDelegator::get (handle)`
	return delegator::open (handle, key);
}

/** @see elektraDocClose */
int elektraLeafClose (Plugin * handle, Key * key)
{
	return delegator::close (handle, key);
}

/** @see elektraDocGet */
int elektraLeafGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
{
	CppKeySet keys{ returned };
	CppKey parent{ parentKey };

	if (parent.getName () == "system/elektra/modules/leaf")
	{
		keys.append (getContract ());
		parent.release ();
		keys.release ();
		return ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}

	int status = ELEKTRA_PLUGIN_STATUS_ERROR;
	try
	{
		status = delegator::get (handle)->convertToDirectories (keys);
	}
	catch (exception const & error)
	{
		ELEKTRA_SET_ERROR (ELEKTRA_ERROR_UNCAUGHT_EXCEPTION, *parent, error.what ());
	}

	parent.release ();
	keys.release ();
	return status;
}

/** @see elektraDocSet */
int elektraLeafSet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	CppKeySet keys{ returned };
	CppKey parent{ parentKey };

	int status = ELEKTRA_PLUGIN_STATUS_ERROR;
	try
	{
		status = delegator::get (handle)->convertToLeaves (keys);
	}
	catch (exception const & error)
	{
		ELEKTRA_SET_ERROR (ELEKTRA_ERROR_UNCAUGHT_EXCEPTION, *parent, error.what ());
	}

	parent.release ();
	keys.release ();
	return status;
}

Plugin * ELEKTRA_PLUGIN_EXPORT (leaf)
{
	// clang-format off
	return elektraPluginExport ("leaf",
		ELEKTRA_PLUGIN_OPEN,	&elektraLeafOpen,
		ELEKTRA_PLUGIN_CLOSE,	&elektraLeafClose,
		ELEKTRA_PLUGIN_GET,	&elektraLeafGet,
		ELEKTRA_PLUGIN_SET,	&elektraLeafSet,
		ELEKTRA_PLUGIN_END);
}

} // end extern "C"
<commit_msg>Leaf: Catch range errors in `get`/`set` direction<commit_after>/**
 * @file
 *
 * @brief Source for leaf plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

#include "leaf.hpp"

#include <kdbhelper.h>

using std::exception;
using std::range_error;

using elektra::LeafDelegate;

using CppKey = kdb::Key;
using CppKeySet = kdb::KeySet;

namespace
{

/**
 * @brief This function returns a key set containing the plugin contract.
 *
 * @return A key set specifying the capabilities of the plugin
 */
CppKeySet getContract ()
{
	return CppKeySet{ 30,
			  keyNew ("system/elektra/modules/leaf", KEY_VALUE, "leaf plugin waits for your orders", KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports", KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports/open", KEY_FUNC, elektraLeafOpen, KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports/close", KEY_FUNC, elektraLeafClose, KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports/get", KEY_FUNC, elektraLeafGet, KEY_END),
			  keyNew ("system/elektra/modules/leaf/exports/set", KEY_FUNC, elektraLeafSet, KEY_END),
#include ELEKTRA_README (leaf)
			  keyNew ("system/elektra/modules/leaf/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END),
			  KS_END };
}

} // end namespace

extern "C" {

typedef Delegator<LeafDelegate> delegator;

/** @see elektraDocOpen */
int elektraLeafOpen (Plugin * handle, Key * key)
{
	// After the call to `delegator::open` you can retrieve a pointer to the delegate via `coderDelegator::get (handle)`
	return delegator::open (handle, key);
}

/** @see elektraDocClose */
int elektraLeafClose (Plugin * handle, Key * key)
{
	return delegator::close (handle, key);
}

/** @see elektraDocGet */
int elektraLeafGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
{
	CppKeySet keys{ returned };
	CppKey parent{ parentKey };

	if (parent.getName () == "system/elektra/modules/leaf")
	{
		keys.append (getContract ());
		parent.release ();
		keys.release ();
		return ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}

	int status = ELEKTRA_PLUGIN_STATUS_ERROR;
	try
	{
		status = delegator::get (handle)->convertToDirectories (keys);
	}
	catch (range_error const & error)
	{
		ELEKTRA_SET_ERROR (ELEKTRA_ERROR_DIRECTORY_VALUE_ARRAY, *parent, error.what ());
	}
	catch (exception const & error)
	{
		ELEKTRA_SET_ERROR (ELEKTRA_ERROR_UNCAUGHT_EXCEPTION, *parent, error.what ());
	}

	parent.release ();
	keys.release ();
	return status;
}

/** @see elektraDocSet */
int elektraLeafSet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	CppKeySet keys{ returned };
	CppKey parent{ parentKey };

	int status = ELEKTRA_PLUGIN_STATUS_ERROR;
	try
	{
		status = delegator::get (handle)->convertToLeaves (keys);
	}
	catch (range_error const & error)
	{
		ELEKTRA_SET_ERROR (ELEKTRA_ERROR_DIRECTORY_VALUE_ARRAY, *parent, error.what ());
	}
	catch (exception const & error)
	{
		ELEKTRA_SET_ERROR (ELEKTRA_ERROR_UNCAUGHT_EXCEPTION, *parent, error.what ());
	}

	parent.release ();
	keys.release ();
	return status;
}

Plugin * ELEKTRA_PLUGIN_EXPORT (leaf)
{
	// clang-format off
	return elektraPluginExport ("leaf",
		ELEKTRA_PLUGIN_OPEN,	&elektraLeafOpen,
		ELEKTRA_PLUGIN_CLOSE,	&elektraLeafClose,
		ELEKTRA_PLUGIN_GET,	&elektraLeafGet,
		ELEKTRA_PLUGIN_SET,	&elektraLeafSet,
		ELEKTRA_PLUGIN_END);
}

} // end extern "C"
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include <cling/UserInterface/UserInterface.h>

#include <cling/MetaProcessor/MetaProcessor.h>
#include "textinput/TextInput.h"
#include "textinput/StreamReader.h"
#include "textinput/TerminalDisplay.h"

#include "llvm/Support/raw_ostream.h"

//---------------------------------------------------------------------------
// Construct an interface for an interpreter
//---------------------------------------------------------------------------
cling::UserInterface::UserInterface(Interpreter& interp,
                                    const char* prompt /*= "[cling] $"*/):
m_MetaProcessor(new MetaProcessor(interp))
{
}

//---------------------------------------------------------------------------
// Destruct the interface
//---------------------------------------------------------------------------
cling::UserInterface::~UserInterface()
{
  delete m_MetaProcessor;
}

//---------------------------------------------------------------------------
// Interact with the user using a prompt
//---------------------------------------------------------------------------
void cling::UserInterface::runInteractively(bool nologo /* = false */)
{
  if (!nologo) {
    PrintLogo();
  }
  static const char* histfile = ".cling_history";
  std::string Prompt("[cling]$ ");

  using namespace textinput;
  StreamReader* R = StreamReader::Create();
  TerminalDisplay* D = TerminalDisplay::Create();
  TextInput TI(*R, *D, histfile);
  TI.SetPrompt(Prompt.c_str());
  std::string line;
  MetaProcessorOpts& MPOpts = m_MetaProcessor->getMetaProcessorOpts();

  while (!MPOpts.Quitting) {
    TextInput::EReadResult RR = TI.ReadInput();
    TI.TakeInput(line);
    if (RR == TextInput::kRREOF) {
      MPOpts.Quitting = true;
      continue;
    }

    int indent = m_MetaProcessor->process(line.c_str());
    Prompt = "[cling]";
    if (MPOpts.RawInput)
      Prompt.append("! ");
    else
      Prompt.append("$ ");

    if (indent > 0)
      // Continuation requested.
      Prompt.append('?' + std::string(indent * 3, ' '));

    TI.SetPrompt(Prompt.c_str());

  }
}

void cling::UserInterface::PrintLogo() {
  llvm::outs() << "\n";
  llvm::outs() << "****************** CLING ******************" << "\n";
  llvm::outs() << "* Type C++ code and press enter to run it *" << "\n";
  llvm::outs() << "*             Type .q to exit             *" << "\n";
  llvm::outs() << "*******************************************" << "\n";
}
<commit_msg>Fix Savannah #95065: flush llvm::outs() before TextInput interaction.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include <cling/UserInterface/UserInterface.h>

#include <cling/MetaProcessor/MetaProcessor.h>
#include "textinput/TextInput.h"
#include "textinput/StreamReader.h"
#include "textinput/TerminalDisplay.h"

#include "llvm/Support/raw_ostream.h"

//---------------------------------------------------------------------------
// Construct an interface for an interpreter
//---------------------------------------------------------------------------
cling::UserInterface::UserInterface(Interpreter& interp,
                                    const char* prompt /*= "[cling] $"*/):
m_MetaProcessor(new MetaProcessor(interp))
{
}

//---------------------------------------------------------------------------
// Destruct the interface
//---------------------------------------------------------------------------
cling::UserInterface::~UserInterface()
{
  delete m_MetaProcessor;
}

//---------------------------------------------------------------------------
// Interact with the user using a prompt
//---------------------------------------------------------------------------
void cling::UserInterface::runInteractively(bool nologo /* = false */)
{
  if (!nologo) {
    PrintLogo();
  }
  static const char* histfile = ".cling_history";
  std::string Prompt("[cling]$ ");

  using namespace textinput;
  StreamReader* R = StreamReader::Create();
  TerminalDisplay* D = TerminalDisplay::Create();
  TextInput TI(*R, *D, histfile);
  TI.SetPrompt(Prompt.c_str());
  std::string line;
  MetaProcessorOpts& MPOpts = m_MetaProcessor->getMetaProcessorOpts();

  while (!MPOpts.Quitting) {
    llvm::outs().flush();
    TextInput::EReadResult RR = TI.ReadInput();
    TI.TakeInput(line);
    if (RR == TextInput::kRREOF) {
      MPOpts.Quitting = true;
      continue;
    }

    int indent = m_MetaProcessor->process(line.c_str());
    Prompt = "[cling]";
    if (MPOpts.RawInput)
      Prompt.append("! ");
    else
      Prompt.append("$ ");

    if (indent > 0)
      // Continuation requested.
      Prompt.append('?' + std::string(indent * 3, ' '));

    TI.SetPrompt(Prompt.c_str());

  }
}

void cling::UserInterface::PrintLogo() {
  llvm::outs() << "\n";
  llvm::outs() << "****************** CLING ******************" << "\n";
  llvm::outs() << "* Type C++ code and press enter to run it *" << "\n";
  llvm::outs() << "*             Type .q to exit             *" << "\n";
  llvm::outs() << "*******************************************" << "\n";
}
<|endoftext|>


<commit_before>//===--- ParentVirtualCallCheck.cpp - clang-tidy---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ParentVirtualCallCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/FixIt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include <algorithm>
#include <cctype>

using namespace clang::ast_matchers;

namespace clang {
namespace tidy {
namespace bugprone {

using BasesVector = llvm::SmallVector<const CXXRecordDecl *, 5>;

static bool isParentOf(const CXXRecordDecl &Parent,
                       const CXXRecordDecl &ThisClass) {
  if (Parent.getCanonicalDecl() == ThisClass.getCanonicalDecl())
    return true;
  const CXXRecordDecl *ParentCanonicalDecl = Parent.getCanonicalDecl();
  return ThisClass.bases_end() !=
         llvm::find_if(ThisClass.bases(), [=](const CXXBaseSpecifier &Base) {
           auto *BaseDecl = Base.getType()->getAsCXXRecordDecl();
           assert(BaseDecl);
           return ParentCanonicalDecl == BaseDecl->getCanonicalDecl();
         });
}

static BasesVector getParentsByGrandParent(const CXXRecordDecl &GrandParent,
                                           const CXXRecordDecl &ThisClass,
                                           const CXXMethodDecl &MemberDecl) {
  BasesVector Result;
  for (const auto &Base : ThisClass.bases()) {
    const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl();
    const CXXMethodDecl *ActualMemberDecl =
        MemberDecl.getCorrespondingMethodInClass(BaseDecl);
    if (!ActualMemberDecl)
      continue;
    // TypePtr is the nearest base class to ThisClass between ThisClass and
    // GrandParent, where MemberDecl is overridden. TypePtr is the class the
    // check proposes to fix to.
    const Type *TypePtr =
        ActualMemberDecl->getThisType(ActualMemberDecl->getASTContext())
            .getTypePtr();
    const CXXRecordDecl *RecordDeclType = TypePtr->getPointeeCXXRecordDecl();
    assert(RecordDeclType && "TypePtr is not a pointer to CXXRecordDecl!");
    if (RecordDeclType->getCanonicalDecl()->isDerivedFrom(&GrandParent))
      Result.emplace_back(RecordDeclType);
  }

  return Result;
}

static std::string getNameAsString(const NamedDecl *Decl) {
  std::string QualName;
  llvm::raw_string_ostream OS(QualName);
  PrintingPolicy PP(Decl->getASTContext().getPrintingPolicy());
  PP.SuppressUnwrittenScope = true;
  Decl->printQualifiedName(OS, PP);
  return OS.str();
}

// Returns E as written in the source code. Used to handle 'using' and
// 'typedef'ed names of grand-parent classes.
static std::string getExprAsString(const clang::Expr &E,
                                   clang::ASTContext &AC) {
  std::string Text = tooling::fixit::getText(E, AC).str();
  Text.erase(
      llvm::remove_if(
          Text,
          [](char C) { return std::isspace(static_cast<unsigned char>(C)); }),
      Text.end());
  return Text;
}

void ParentVirtualCallCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(
      cxxMemberCallExpr(
          callee(memberExpr(hasDescendant(implicitCastExpr(
                                hasImplicitDestinationType(pointsTo(
                                    type(anything()).bind("castToType"))),
                                hasSourceExpression(cxxThisExpr(hasType(
                                    type(anything()).bind("thisType")))))))
                     .bind("member")),
          callee(cxxMethodDecl(isVirtual()))),
      this);
}

void ParentVirtualCallCheck::check(const MatchFinder::MatchResult &Result) {
  const auto *Member = Result.Nodes.getNodeAs<MemberExpr>("member");
  assert(Member);

  if (!Member->getQualifier())
    return;

  const auto *MemberDecl = cast<CXXMethodDecl>(Member->getMemberDecl());

  const auto *ThisTypePtr = Result.Nodes.getNodeAs<PointerType>("thisType");
  assert(ThisTypePtr);

  const auto *ThisType = ThisTypePtr->getPointeeCXXRecordDecl();
  assert(ThisType);

  const auto *CastToTypePtr = Result.Nodes.getNodeAs<Type>("castToType");
  assert(CastToTypePtr);

  const auto *CastToType = CastToTypePtr->getAsCXXRecordDecl();
  assert(CastToType);

  if (isParentOf(*CastToType, *ThisType))
    return;

  const BasesVector Parents =
      getParentsByGrandParent(*CastToType, *ThisType, *MemberDecl);

  if (Parents.empty())
    return;

  std::string ParentsStr;
  ParentsStr.reserve(30 * Parents.size());
  for (const CXXRecordDecl *Parent : Parents) {
    if (!ParentsStr.empty())
      ParentsStr.append(" or ");
    ParentsStr.append("'").append(getNameAsString(Parent)).append("'");
  }

  assert(Member->getQualifierLoc().getSourceRange().getBegin().isValid());
  auto Diag = diag(Member->getQualifierLoc().getSourceRange().getBegin(),
                   "qualified name '%0' refers to a member overridden "
                   "in subclass%1; did you mean %2?")
              << getExprAsString(*Member, *Result.Context)
              << (Parents.size() > 1 ? "es" : "") << ParentsStr;

  // Propose a fix if there's only one parent class...
  if (Parents.size() == 1 &&
      // ...unless parent class is templated
      !isa<ClassTemplateSpecializationDecl>(Parents.front()))
    Diag << FixItHint::CreateReplacement(
        Member->getQualifierLoc().getSourceRange(),
        getNameAsString(Parents.front()) + "::");
}

} // namespace bugprone
} // namespace tidy
} // namespace clang
<commit_msg>Adapt to CXXMethodDecl::getThisType change (NFC)<commit_after>//===--- ParentVirtualCallCheck.cpp - clang-tidy---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ParentVirtualCallCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/FixIt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include <algorithm>
#include <cctype>

using namespace clang::ast_matchers;

namespace clang {
namespace tidy {
namespace bugprone {

using BasesVector = llvm::SmallVector<const CXXRecordDecl *, 5>;

static bool isParentOf(const CXXRecordDecl &Parent,
                       const CXXRecordDecl &ThisClass) {
  if (Parent.getCanonicalDecl() == ThisClass.getCanonicalDecl())
    return true;
  const CXXRecordDecl *ParentCanonicalDecl = Parent.getCanonicalDecl();
  return ThisClass.bases_end() !=
         llvm::find_if(ThisClass.bases(), [=](const CXXBaseSpecifier &Base) {
           auto *BaseDecl = Base.getType()->getAsCXXRecordDecl();
           assert(BaseDecl);
           return ParentCanonicalDecl == BaseDecl->getCanonicalDecl();
         });
}

static BasesVector getParentsByGrandParent(const CXXRecordDecl &GrandParent,
                                           const CXXRecordDecl &ThisClass,
                                           const CXXMethodDecl &MemberDecl) {
  BasesVector Result;
  for (const auto &Base : ThisClass.bases()) {
    const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl();
    const CXXMethodDecl *ActualMemberDecl =
        MemberDecl.getCorrespondingMethodInClass(BaseDecl);
    if (!ActualMemberDecl)
      continue;
    // TypePtr is the nearest base class to ThisClass between ThisClass and
    // GrandParent, where MemberDecl is overridden. TypePtr is the class the
    // check proposes to fix to.
    const Type *TypePtr = ActualMemberDecl->getThisType().getTypePtr();
    const CXXRecordDecl *RecordDeclType = TypePtr->getPointeeCXXRecordDecl();
    assert(RecordDeclType && "TypePtr is not a pointer to CXXRecordDecl!");
    if (RecordDeclType->getCanonicalDecl()->isDerivedFrom(&GrandParent))
      Result.emplace_back(RecordDeclType);
  }

  return Result;
}

static std::string getNameAsString(const NamedDecl *Decl) {
  std::string QualName;
  llvm::raw_string_ostream OS(QualName);
  PrintingPolicy PP(Decl->getASTContext().getPrintingPolicy());
  PP.SuppressUnwrittenScope = true;
  Decl->printQualifiedName(OS, PP);
  return OS.str();
}

// Returns E as written in the source code. Used to handle 'using' and
// 'typedef'ed names of grand-parent classes.
static std::string getExprAsString(const clang::Expr &E,
                                   clang::ASTContext &AC) {
  std::string Text = tooling::fixit::getText(E, AC).str();
  Text.erase(
      llvm::remove_if(
          Text,
          [](char C) { return std::isspace(static_cast<unsigned char>(C)); }),
      Text.end());
  return Text;
}

void ParentVirtualCallCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(
      cxxMemberCallExpr(
          callee(memberExpr(hasDescendant(implicitCastExpr(
                                hasImplicitDestinationType(pointsTo(
                                    type(anything()).bind("castToType"))),
                                hasSourceExpression(cxxThisExpr(hasType(
                                    type(anything()).bind("thisType")))))))
                     .bind("member")),
          callee(cxxMethodDecl(isVirtual()))),
      this);
}

void ParentVirtualCallCheck::check(const MatchFinder::MatchResult &Result) {
  const auto *Member = Result.Nodes.getNodeAs<MemberExpr>("member");
  assert(Member);

  if (!Member->getQualifier())
    return;

  const auto *MemberDecl = cast<CXXMethodDecl>(Member->getMemberDecl());

  const auto *ThisTypePtr = Result.Nodes.getNodeAs<PointerType>("thisType");
  assert(ThisTypePtr);

  const auto *ThisType = ThisTypePtr->getPointeeCXXRecordDecl();
  assert(ThisType);

  const auto *CastToTypePtr = Result.Nodes.getNodeAs<Type>("castToType");
  assert(CastToTypePtr);

  const auto *CastToType = CastToTypePtr->getAsCXXRecordDecl();
  assert(CastToType);

  if (isParentOf(*CastToType, *ThisType))
    return;

  const BasesVector Parents =
      getParentsByGrandParent(*CastToType, *ThisType, *MemberDecl);

  if (Parents.empty())
    return;

  std::string ParentsStr;
  ParentsStr.reserve(30 * Parents.size());
  for (const CXXRecordDecl *Parent : Parents) {
    if (!ParentsStr.empty())
      ParentsStr.append(" or ");
    ParentsStr.append("'").append(getNameAsString(Parent)).append("'");
  }

  assert(Member->getQualifierLoc().getSourceRange().getBegin().isValid());
  auto Diag = diag(Member->getQualifierLoc().getSourceRange().getBegin(),
                   "qualified name '%0' refers to a member overridden "
                   "in subclass%1; did you mean %2?")
              << getExprAsString(*Member, *Result.Context)
              << (Parents.size() > 1 ? "es" : "") << ParentsStr;

  // Propose a fix if there's only one parent class...
  if (Parents.size() == 1 &&
      // ...unless parent class is templated
      !isa<ClassTemplateSpecializationDecl>(Parents.front()))
    Diag << FixItHint::CreateReplacement(
        Member->getQualifierLoc().getSourceRange(),
        getNameAsString(Parents.front()) + "::");
}

} // namespace bugprone
} // namespace tidy
} // namespace clang
<|endoftext|>


<commit_before>#ifndef ATL_PRIMITIVE_CALLABLE_HH
#define ATL_PRIMITIVE_CALLABLE_HH
/**
 * @file /home/ryan/programming/atl/primitive_callable.hpp
 * @author Ryan Domigan <ryan_domigan@sutdents@uml.edu>
 * Created on Dec 12, 2013
 *
 * Playing around with integrating type info with the function primitives.
 */
#include <fstream>

#include "./type.hpp"
#include "./environment.hpp"
#include "./interface_helpers.hpp"

#include "ffi.hpp"

namespace atl
{

	Any nullP(Any a) { return is<Null>(a) ? atl_true() : atl_false();  }

	void export_recursive_defs(Environment& env)
	{
		using namespace primitives;

		env.lexical.define("\\", wrap<Lambda>());
		env.lexical.define("quote", wrap<Quote>());
		env.lexical.define("if", wrap<If>());
		env.lexical.define("#f", atl_false());
		env.lexical.define("#t", atl_true());
		env.lexical.define("define-value", wrap<Define>());

		// for debugging (I still need a more general printing
		// mechanism)
		wrap_function<long (long)>
			(env.lexical,
			 "print-int",
			 [&env](long a)
			 {
				 (*env.stdout) << a << std::endl;
				 return a;
			 });

		auto alloc_ast_type = new abstract_type::Type(abstract_type::make_concrete({tag<Ast>::value}));
		env.lexical.define
			("__alloc_ast__",
			 wrap
			 (env.gc.make<CxxFunctor>
			  ([&](vm_stack::iterator begin, vm_stack::iterator end) -> void
			  {
				  auto range = make_range(begin, end);
				  auto stack = env.gc.dynamic_seq(range.size() + 2);
				  auto seq = stack->end();
				  stack->push_back(Any(tag<AstData>::value,
				                       0));

				  for(auto pair = begin; pair < end; pair += 2)
					  stack->push_back(Any(pair[1],
					                       reinterpret_cast<void*>(pair[0])));

				  seq->value = stack->end();
				  *begin = reinterpret_cast<vm_stack::value_type>(seq);
			  },
				  "__alloc_ast__",
				  alloc_ast_type)));

		auto cc = primitives::Constructor(env.lexical);
		mpl::for_each<TypesVec, wrap_t_arg< mpl::placeholders::_1> >(cc);

		wrap_function<Any* (AstData*, long)>
			(env.lexical,
			 "nth",
			 [](AstData *ast, long n) -> Any*
			{
				return &Ast(ast)[n];
			});

		// (: A a) declares a to be of type A
		wrap_macro(env.lexical, ":",
		           [](Eval &eval, PrimitiveMacro::Input const& ast)
		           {
			           // requires a type-expr followed by an expr.
			           // The whole shooting match is given the
			           // Type.value as its type.
			           tag_t rval;
			           {
				           auto frame = eval.compile->save_excursion();

				           // TODO: I this should actually evauate,
				           // and should return an abstract_type::Type
				           rval = eval.compile->any(ast[0]);
			           }
			           eval.compile->any(ast[1]);
			           return rval;
		           });

		static auto fn_construct_params = abstract_type::make_concrete({tag<Type>::value, tag<Type>::value});
		fn_construct_params.front().count = abstract_type::Node::CountType::at_least_one;
		auto fn_construct
			= env.gc.make<CxxFunctor>([&env](vm_stack::iterator begin, vm_stack::iterator end)
			                      {
				                      auto type = env.gc.make<abstract_type::Type>();
				                      for(auto& vv : make_range(begin, end))
					                      type->values.emplace_back(*reinterpret_cast<Type::value_type*>(vv));
				                      *begin = reinterpret_cast<vm_stack::value_type>(type);
			                      }, "->", &fn_construct_params);

		env.lexical.define("->", wrap(fn_construct));

		/***********************************************************/
		/**     _         _ _   _                     _   _       **/
		/**    / \   _ __(_) |_| |__  _ __ ___   __ _| |_(_) ___  **/
		/**   / _ \ | '__| | __| '_ \| '_ ` _ \ / _` | __| |/ __| **/
		/**  / ___ \| |  | | |_| | | | | | | | | (_| | |_| | (__  **/
		/** /_/   \_\_|  |_|\__|_| |_|_| |_| |_|\__,_|\__|_|\___| **/
		/***********************************************************/
		wrap_function<long (long, long)>(env.lexical, "add2", [](long a, long b) { return a + b;});
		wrap_function<long (long, long)>(env.lexical, "sub2", [](long a, long b) { return a - b;});
		wrap_function<bool (long, long)>(env.lexical, "=", [](long a, long b) { return a = b;});
		wrap_function<bool (long, long)>(env.lexical, "<", [](long a, long b) { return a < b;});
		wrap_function<bool (long, long)>(env.lexical, ">", [](long a, long b) { return a > b;});
		wrap_function<bool (long, long)>(env.lexical, "<=", [](long a, long b) { return a <= b;});
		wrap_function<bool (long, long)>(env.lexical, ">=", [](long a, long b) { return a >= b;});

		/////////////////////////////////////////////////////////////////////
		//  ___       _                                 _   _              //
		// |_ _|_ __ | |_ _ __ ___  ___ _ __   ___  ___| |_(_) ___  _ __   //
		//  | || '_ \| __| '__/ _ \/ __| '_ \ / _ \/ __| __| |/ _ \| '_ \  //
		//  | || | | | |_| | | (_) \__ \ |_) |  __/ (__| |_| | (_) | | | | //
		// |___|_| |_|\__|_|  \___/|___/ .__/ \___|\___|\__|_|\___/|_| |_| //
		//                             |_|                                 //
		/////////////////////////////////////////////////////////////////////
		// introspection

		wrap_function<long ()>(env.lexical, "print-bytecode",
		                       [&env]() {
			                       if(env.pcode)
				                       dbg_code(*env.pcode->output);
			                       else
				                       cout << "environment pcode is not set." << endl;
			                       return 0;
		                       });

		/***************************/
		/**  _     _     _        **/
		/** | |   (_)___| |_ ___  **/
		/** | |   | / __| __/ __| **/
		/** | |___| \__ \ |_\__ \ **/
		/** |_____|_|___/\__|___/ **/
		/***************************/
		wrap_macro
			(env.lexical,
			 "Ast",
			 [&](Eval& eval, PrimitiveMacro::Input const& ast) -> tag_t
			 {
				 for(auto& vv : ast)
					 eval.compile->push_value(eval.compile->any(vv));

				 eval.compile->wrapped.std_function(&unwrap<CxxFunctor>(env.lexical.toplevel.value("__alloc_ast__")).fn,
				                                    ast.size() * 2);

				 return tag<Ast>::value;
			 });

		auto cons_ast = WrapStdFunction<AstData* (vm_stack::value_type, vm_stack::value_type, AstData*)>::a
			([&env](vm_stack::value_type value, vm_stack::value_type type, AstData *raw) -> AstData*
			 {
				 using namespace ast_iterator;
				 Ast seq(raw);

				 auto output = env.gc.dynamic_seq();
				 auto vec = output->end();
				 output->push_back(Any(tag<AstData>::value, nullptr));

				 output->push_back(Any(type,
				                       reinterpret_cast<void*>(value)));
				 std::copy(seq.begin(), seq.end(),
				           std::back_insert_iterator<memory_pool::DynamicVector>(*output));

				 vec->value = output->end();
				 return reinterpret_cast<AstData*>(vec);
			 }
			 , env.gc
			 , "cons-ast");

		wrap_macro
			(env.lexical,
			 "cons",
			 [&, cons_ast](Eval& eval, PrimitiveMacro::Input const& ast) -> tag_t
			 {
				 // push car's (value type)
				 eval.compile->push_value(eval.compile->any(ast[0]));
				 auto seq_type = eval.compile->any(ast[1]);

				 switch(seq_type)
					 {
					 case tag<Ast>::value:
						 eval.compile->wrapped.std_function(&cons_ast->fn, 3);
						 return tag<Ast>::value;
					 default:
						 throw WrongTypeError
							 (std::string("cons not defined for ").append(type_name(seq_type)));
					 }
			 });

		wrap_function<Slice* (AstData*, long)>(env.lexical, "slice",
		                                   [&env](AstData* raw, long nn) -> Slice*
			{
				Ast ast(raw);
				auto out = env.gc.make<Slice>(ast.begin() + nn, ast.end());
				return out;
			});

		///////////////////////////////////////////
		//  __  __                       _       //
		// |  \/  | ___  _ __   __ _  __| |___   //
		// | |\/| |/ _ \| '_ \ / _` |/ _` / __|  //
		// | |  | | (_) | | | | (_| | (_| \__ \  //
		// |_|  |_|\___/|_| |_|\__,_|\__,_|___/  //
		///////////////////////////////////////////
		// Monads

		// env.wrap_fn<Any (Any, Any)>
		//     (">>=",
		//      [env](Any fn, Any monad) {
		//     });

		// // `return` in Haskell
		// env.wrap_fn<Any (Any)>
		//     ("unit",
		//      [env](Any vv) {
		// 	return
		//     });
	}

	static bool _setup_interpreter = false;
	void setup_interpreter(Environment &env)
	{
		if(!_setup_interpreter)
			{
				_setup_interpreter = true;
				init_types();
			}
		export_recursive_defs(env);
	}
}

#endif
<commit_msg>Remove commented out code<commit_after>#ifndef ATL_PRIMITIVE_CALLABLE_HH
#define ATL_PRIMITIVE_CALLABLE_HH
/**
 * @file /home/ryan/programming/atl/primitive_callable.hpp
 * @author Ryan Domigan <ryan_domigan@sutdents@uml.edu>
 * Created on Dec 12, 2013
 *
 * Playing around with integrating type info with the function primitives.
 */
#include <fstream>

#include "./type.hpp"
#include "./environment.hpp"
#include "./interface_helpers.hpp"

#include "ffi.hpp"

namespace atl
{

	Any nullP(Any a) { return is<Null>(a) ? atl_true() : atl_false();  }

	void export_recursive_defs(Environment& env)
	{
		using namespace primitives;

		env.lexical.define("\\", wrap<Lambda>());
		env.lexical.define("quote", wrap<Quote>());
		env.lexical.define("if", wrap<If>());
		env.lexical.define("#f", atl_false());
		env.lexical.define("#t", atl_true());
		env.lexical.define("define-value", wrap<Define>());

		// for debugging (I still need a more general printing
		// mechanism)
		wrap_function<long (long)>
			(env.lexical,
			 "print-int",
			 [&env](long a)
			 {
				 (*env.stdout) << a << std::endl;
				 return a;
			 });

		auto alloc_ast_type = new abstract_type::Type(abstract_type::make_concrete({tag<Ast>::value}));
		env.lexical.define
			("__alloc_ast__",
			 wrap
			 (env.gc.make<CxxFunctor>
			  ([&](vm_stack::iterator begin, vm_stack::iterator end) -> void
			  {
				  auto range = make_range(begin, end);
				  auto stack = env.gc.dynamic_seq(range.size() + 2);
				  auto seq = stack->end();
				  stack->push_back(Any(tag<AstData>::value,
				                       0));

				  for(auto pair = begin; pair < end; pair += 2)
					  stack->push_back(Any(pair[1],
					                       reinterpret_cast<void*>(pair[0])));

				  seq->value = stack->end();
				  *begin = reinterpret_cast<vm_stack::value_type>(seq);
			  },
				  "__alloc_ast__",
				  alloc_ast_type)));

		auto cc = primitives::Constructor(env.lexical);
		mpl::for_each<TypesVec, wrap_t_arg< mpl::placeholders::_1> >(cc);

		wrap_function<Any* (AstData*, long)>
			(env.lexical,
			 "nth",
			 [](AstData *ast, long n) -> Any*
			{
				return &Ast(ast)[n];
			});

		// (: A a) declares a to be of type A
		wrap_macro(env.lexical, ":",
		           [](Eval &eval, PrimitiveMacro::Input const& ast)
		           {
			           // requires a type-expr followed by an expr.
			           // The whole shooting match is given the
			           // Type.value as its type.
			           tag_t rval;
			           {
				           auto frame = eval.compile->save_excursion();

				           // TODO: I this should actually evauate,
				           // and should return an abstract_type::Type
				           rval = eval.compile->any(ast[0]);
			           }
			           eval.compile->any(ast[1]);
			           return rval;
		           });

		static auto fn_construct_params = abstract_type::make_concrete({tag<Type>::value, tag<Type>::value});
		fn_construct_params.front().count = abstract_type::Node::CountType::at_least_one;
		auto fn_construct
			= env.gc.make<CxxFunctor>([&env](vm_stack::iterator begin, vm_stack::iterator end)
			                      {
				                      auto type = env.gc.make<abstract_type::Type>();
				                      for(auto& vv : make_range(begin, end))
					                      type->values.emplace_back(*reinterpret_cast<Type::value_type*>(vv));
				                      *begin = reinterpret_cast<vm_stack::value_type>(type);
			                      }, "->", &fn_construct_params);

		env.lexical.define("->", wrap(fn_construct));

		/***********************************************************/
		/**     _         _ _   _                     _   _       **/
		/**    / \   _ __(_) |_| |__  _ __ ___   __ _| |_(_) ___  **/
		/**   / _ \ | '__| | __| '_ \| '_ ` _ \ / _` | __| |/ __| **/
		/**  / ___ \| |  | | |_| | | | | | | | | (_| | |_| | (__  **/
		/** /_/   \_\_|  |_|\__|_| |_|_| |_| |_|\__,_|\__|_|\___| **/
		/***********************************************************/
		wrap_function<long (long, long)>(env.lexical, "add2", [](long a, long b) { return a + b;});
		wrap_function<long (long, long)>(env.lexical, "sub2", [](long a, long b) { return a - b;});
		wrap_function<bool (long, long)>(env.lexical, "=", [](long a, long b) { return a = b;});
		wrap_function<bool (long, long)>(env.lexical, "<", [](long a, long b) { return a < b;});
		wrap_function<bool (long, long)>(env.lexical, ">", [](long a, long b) { return a > b;});
		wrap_function<bool (long, long)>(env.lexical, "<=", [](long a, long b) { return a <= b;});
		wrap_function<bool (long, long)>(env.lexical, ">=", [](long a, long b) { return a >= b;});

		/////////////////////////////////////////////////////////////////////
		//  ___       _                                 _   _              //
		// |_ _|_ __ | |_ _ __ ___  ___ _ __   ___  ___| |_(_) ___  _ __   //
		//  | || '_ \| __| '__/ _ \/ __| '_ \ / _ \/ __| __| |/ _ \| '_ \  //
		//  | || | | | |_| | | (_) \__ \ |_) |  __/ (__| |_| | (_) | | | | //
		// |___|_| |_|\__|_|  \___/|___/ .__/ \___|\___|\__|_|\___/|_| |_| //
		//                             |_|                                 //
		/////////////////////////////////////////////////////////////////////
		// introspection

		wrap_function<long ()>(env.lexical, "print-bytecode",
		                       [&env]() {
			                       if(env.pcode)
				                       dbg_code(*env.pcode->output);
			                       else
				                       cout << "environment pcode is not set." << endl;
			                       return 0;
		                       });

		/***************************/
		/**  _     _     _        **/
		/** | |   (_)___| |_ ___  **/
		/** | |   | / __| __/ __| **/
		/** | |___| \__ \ |_\__ \ **/
		/** |_____|_|___/\__|___/ **/
		/***************************/
		wrap_macro
			(env.lexical,
			 "Ast",
			 [&](Eval& eval, PrimitiveMacro::Input const& ast) -> tag_t
			 {
				 for(auto& vv : ast)
					 eval.compile->push_value(eval.compile->any(vv));

				 eval.compile->wrapped.std_function(&unwrap<CxxFunctor>(env.lexical.toplevel.value("__alloc_ast__")).fn,
				                                    ast.size() * 2);

				 return tag<Ast>::value;
			 });

		auto cons_ast = WrapStdFunction<AstData* (vm_stack::value_type, vm_stack::value_type, AstData*)>::a
			([&env](vm_stack::value_type value, vm_stack::value_type type, AstData *raw) -> AstData*
			 {
				 using namespace ast_iterator;
				 Ast seq(raw);

				 auto output = env.gc.dynamic_seq();
				 auto vec = output->end();
				 output->push_back(Any(tag<AstData>::value, nullptr));

				 output->push_back(Any(type,
				                       reinterpret_cast<void*>(value)));
				 std::copy(seq.begin(), seq.end(),
				           std::back_insert_iterator<memory_pool::DynamicVector>(*output));

				 vec->value = output->end();
				 return reinterpret_cast<AstData*>(vec);
			 }
			 , env.gc
			 , "cons-ast");

		wrap_macro
			(env.lexical,
			 "cons",
			 [&, cons_ast](Eval& eval, PrimitiveMacro::Input const& ast) -> tag_t
			 {
				 // push car's (value type)
				 eval.compile->push_value(eval.compile->any(ast[0]));
				 auto seq_type = eval.compile->any(ast[1]);

				 switch(seq_type)
					 {
					 case tag<Ast>::value:
						 eval.compile->wrapped.std_function(&cons_ast->fn, 3);
						 return tag<Ast>::value;
					 default:
						 throw WrongTypeError
							 (std::string("cons not defined for ").append(type_name(seq_type)));
					 }
			 });

		wrap_function<Slice* (AstData*, long)>(env.lexical, "slice",
		                                   [&env](AstData* raw, long nn) -> Slice*
			{
				Ast ast(raw);
				auto out = env.gc.make<Slice>(ast.begin() + nn, ast.end());
				return out;
			});

	}

	static bool _setup_interpreter = false;
	void setup_interpreter(Environment &env)
	{
		if(!_setup_interpreter)
			{
				_setup_interpreter = true;
				init_types();
			}
		export_recursive_defs(env);
	}
}

#endif
<|endoftext|>


<commit_before>#include "TimelineView.hpp"

#include <sstream>
#include <iomanip>
#include <ctime>

#include <QDebug>
#include <QScrollBar>
#include <QPainter>

#include "matrix/Session.hpp"

const static QColor text_color = Qt::black;
const static QColor primary_bg(245, 245, 245);
const static QColor secondary_bg = Qt::white;
const static QColor header_color(96, 96, 96);
constexpr static int BACKLOG_BATCH_SIZE = 50;

static auto to_time_point(uint64_t ts) {
  return std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::from_time_t(0))
      + std::chrono::duration<uint64_t, std::milli>(ts);
}

TimelineView::Event::Event(const TimelineView &view, const matrix::proto::Event &e)
    : time(to_time_point(e.origin_server_ts)) {
  auto lines = e.content["body"].toString().split('\n');
  layouts = std::vector<QTextLayout>(lines.size());
  QTextOption body_options;
  body_options.setAlignment(Qt::AlignLeft | Qt::AlignTop);
  body_options.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
  for(int i = 0; i < lines.size(); ++i) {
    layouts[i].setFont(view.font());
    layouts[i].setTextOption(body_options);
    layouts[i].setCacheEnabled(true);
    layouts[i].setText(lines[i]);
  }
}

TimelineView::Block::Block(TimelineView &view, const matrix::RoomState &state, const matrix::proto::Event &e)
    : sender_id_(e.sender) {
  events_.emplace_back(view, e);

  auto sender = state.member(e.sender);

  if(sender && !sender->avatar_url().isEmpty()) {
    try {
      avatar_ = matrix::Content(sender->avatar_url());
    } catch(const std::invalid_argument &e) {
      qDebug() << "invalid avatar URL:" << e.what() << ":" << sender->avatar_url();
    }

    if(avatar_) {
      auto result = view.avatars_.emplace(std::piecewise_construct,
                                          std::forward_as_tuple(*avatar_),
                                          std::forward_as_tuple());
      if(result.second) {
        auto reply = view.room_.session().get_thumbnail(result.first->first, QSize(view.avatar_size(), view.avatar_size()));
        connect(reply, &matrix::ContentFetch::finished, &view, &TimelineView::set_avatar);
        connect(reply, &matrix::ContentFetch::error, &view.room_, &matrix::Room::error);
      }
      ++result.first->second.references;
    }
  }

  {
    QTextOption options;
    options.setAlignment(Qt::AlignLeft | Qt::AlignTop);
    options.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    name_layout_.setFont(view.font());
    name_layout_.setTextOption(options);
    name_layout_.setCacheEnabled(true);
    if(sender) {
      name_layout_.setText(state.member_name(*sender));
    } else {
      name_layout_.setText(sender_id_);
    }
  }

  {
    QTextOption options;
    options.setAlignment(Qt::AlignRight | Qt::AlignTop);
    options.setWrapMode(QTextOption::NoWrap);
    timestamp_layout_.setFont(view.font());
    timestamp_layout_.setTextOption(options);
    timestamp_layout_.setCacheEnabled(true);

    auto time = std::chrono::system_clock::to_time_t(events_.front().time);
    auto tm = std::localtime(&time);
    std::ostringstream s;
    s << std::put_time(tm, "%H:%M");

    timestamp_layout_.setText(QString::fromStdString(s.str()));
  }

  update_layout(view);
}

void TimelineView::Block::update_layout(const TimelineView &view) {
  auto metrics = view.fontMetrics();
  const int margin = view.block_margin();
  const int avatar_size = view.avatar_size();
  qreal height = 0;

  const int line_start = avatar_size + 2*margin;
  const int line_width = view.visible_width() - (line_start + margin);

  {
    name_layout_.beginLayout();
    while(true) {
      auto line = name_layout_.createLine();
      if(!line.isValid()) break;
      line.setLineWidth(line_width);
      line.setPosition(QPointF(line_start, height));
      height += metrics.lineSpacing();
    }
    name_layout_.endLayout();
  }

  {
    timestamp_layout_.beginLayout();
    auto line = timestamp_layout_.createLine();
    line.setLineWidth(line_width);
    line.setPosition(QPointF(line_start, 0));
    timestamp_layout_.endLayout();
    if(metrics.boundingRect(name_layout_.text()).width() > line_width - metrics.boundingRect(timestamp_layout_.text()).width()) {
      timestamp_layout_.clearLayout();
    }
  }

  for(auto &event : events_) {
    for(auto &layout : event.layouts) {
      layout.beginLayout();
      while(true) {
        auto line = layout.createLine();
        if(!line.isValid()) break;
        line.setLineWidth(line_width);
        line.setPosition(QPointF(line_start, height));
        height += metrics.lineSpacing();
      }
      layout.endLayout();
    }
  }
}

QRectF TimelineView::Block::bounding_rect(const TimelineView &view) const {
  auto margin = view.block_margin();
  auto av_size = view.avatar_size();
  QRectF rect(margin, margin, view.visible_width() - margin, av_size);
  rect |= name_layout_.boundingRect();
  for(const auto &event : events_) {
    for(const auto &layout : event.layouts) {
      rect |= layout.boundingRect();
    }
  }
  return rect;
}

void TimelineView::Block::draw(const TimelineView &view, QPainter &p, QPointF offset) const {
  auto metrics = view.fontMetrics();
  auto margin = view.block_margin();

  QPixmap avatar_pixmap;
  const auto size = view.avatar_size();
  if(avatar_) {
    auto a = view.avatars_.at(*avatar_);
    if(a.pixmap.isNull()) {
      avatar_pixmap = view.avatar_loading_.pixmap(size, size);
    } else {
      avatar_pixmap = a.pixmap;
    }
  } else {
    avatar_pixmap = view.avatar_missing_.pixmap(size, size);
  }
  p.drawPixmap(QPoint(offset.x() + margin + (size - avatar_pixmap.width()) / 2,
                      offset.y() + (size - avatar_pixmap.height()) / 2),
               avatar_pixmap);

  p.save();
  p.setPen(header_color);
  name_layout_.draw(&p, offset);
  timestamp_layout_.draw(&p, offset);
  p.restore();

  for(const auto &event : events_) {
    for(const auto &layout : event.layouts) {
      layout.draw(&p, offset);
    }
  }
}

size_t TimelineView::Block::size() const {
  return events_.size();
}

size_t TimelineView::Batch::size() const {
  size_t result = 0;
  for(const auto &block : blocks) {
    result += block.size();
  }
  return result;
}

TimelineView::TimelineView(matrix::Room &room, QWidget *parent)
    : QAbstractScrollArea(parent), room_(room), initial_state_(room.initial_state()), total_events_(0),
      head_color_alternate_(true), backlog_growing_(false), backlog_growable_(true), min_backlog_size_(256),
      content_height_(0),
      avatar_missing_(QIcon::fromTheme("unknown")),
      avatar_loading_(QIcon::fromTheme("image-loading")) {
  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  verticalScrollBar()->setSingleStep(20);  // Taken from QScrollArea
  setFocusPolicy(Qt::NoFocus);

  connect(verticalScrollBar(), &QAbstractSlider::valueChanged, [this](int value) {
      (void)value;
      grow_backlog();
    });
}

int TimelineView::visible_width() const {
  return viewport()->contentsRect().width();
}

void TimelineView::push_back(const matrix::RoomState &state, const matrix::proto::Event &in) {
  backlog_growable_ &= in.type != "m.room.create";

  batches_.back().blocks.emplace_back(*this, state, in);
  head_color_alternate_ = !head_color_alternate_;

  content_height_ += block_spacing();
  content_height_ += batches_.back().blocks.back().bounding_rect(*this).height();
  total_events_ += 1;

  prune_backlog();

  update_scrollbar();

  viewport()->update();
}

void TimelineView::end_batch(const QString &token) {
  if(batches_.empty()) {
    prev_batch_ = token;
  } else {
    batches_.back().token = token;
  }
  batches_.emplace_back();  // Next batch
}

int TimelineView::block_margin() const { return fontMetrics().lineSpacing()/3; }
int TimelineView::block_spacing() const { return fontMetrics().lineSpacing()/3; }
int TimelineView::avatar_size() const {
  auto metrics = fontMetrics();
  return metrics.height() * 2 + metrics.leading();
}
int TimelineView::scrollback_trigger_size() const {
  return viewport()->contentsRect().height()/2;
}

void TimelineView::update_scrollbar(bool for_prepend) {
  auto &scroll = *verticalScrollBar();
  const bool initially_at_bottom = scroll.value() == scroll.maximum();
  auto view_height = viewport()->contentsRect().height();
  const int old_maximum = scroll.maximum();
  const int fake_height = content_height_ + scrollback_trigger_size();
  scroll.setMaximum(view_height > fake_height ? 0 : fake_height - view_height);
  if(initially_at_bottom) {
    scroll.setValue(scroll.maximum());
  } else if(for_prepend) {
    scroll.setValue(scroll.value() + (scroll.maximum() - old_maximum));
  }
}

void TimelineView::paintEvent(QPaintEvent *) {
  QRectF view_rect = viewport()->contentsRect();
  view_rect.setWidth(view_rect.width());
  QPainter painter(viewport());
  painter.fillRect(view_rect, Qt::lightGray);
  painter.setPen(Qt::black);
  auto &scroll = *verticalScrollBar();
  QPointF offset(0, view_rect.height() - (scroll.value() - scroll.maximum()));
  auto s = block_spacing();
  bool alternate = head_color_alternate_;
  const int margin = block_margin();
  for(auto batch_it = batches_.crbegin(); batch_it != batches_.crend(); ++batch_it) {
    for(auto it = batch_it->blocks.crbegin(); it != batch_it->blocks.crend(); ++it) {
      const auto bounds = it->bounding_rect(*this);
      offset.ry() -= bounds.height();
      if((offset.y() + bounds.height()) < view_rect.top()) {
        // No further drawing possible
        break;
      }
      if(offset.y() < view_rect.bottom()) {
        {
          QRectF outline(offset.x() + 0.5, offset.y() - (0.5 + s/2.0),
                         view_rect.width() - 1,
                         bounds.translated(offset).height() + (1 + s/2.0));
          painter.save();
          painter.setRenderHint(QPainter::Antialiasing);
          QPainterPath path;
          path.addRoundedRect(outline, margin*2, margin*2);
          painter.fillPath(path, alternate ? secondary_bg : primary_bg);
          painter.restore();
        }
        it->draw(*this, painter, offset);
      }
      offset.ry() -= s;
      alternate = !alternate;
    }
  }
}

void TimelineView::resizeEvent(QResizeEvent *e) {
  {
    const int unit = avatar_size() + block_spacing();
    const int window_height = viewport()->contentsRect().height();
    const int window_units = window_height / unit;

    verticalScrollBar()->setPageStep((window_units - 1) * unit);
  }

  if(e->size().width() != e->oldSize().width()) {
    // Linebreaks may have changed, so we need to lay everything out again
    content_height_ = 0;
    const auto s = block_spacing();
    for(auto &batch : batches_) {
      for(auto &block : batch.blocks) {
        block.update_layout(*this);
        content_height_ += block.bounding_rect(*this).height() + s;
      }
    }
  }

  update_scrollbar();
  // Required uncondtionally since height *and* width matter due to text wrapping. Placed after content_height_ changes
  // to ensure they're accounted for.
}

void TimelineView::grow_backlog() {
  if(verticalScrollBar()->value() >= scrollback_trigger_size() || backlog_growing_ || !backlog_growable_) return;
  backlog_growing_ = true;
  auto reply = room_.get_messages(matrix::Room::Direction::BACKWARD, prev_batch_, BACKLOG_BATCH_SIZE);
  connect(reply, &matrix::MessageFetch::finished, this, &TimelineView::prepend_batch);
  connect(reply, &matrix::MessageFetch::finished, this, &TimelineView::prepend_batch);
  connect(reply, &matrix::MessageFetch::error, &room_, &matrix::Room::error);
}

void TimelineView::prepend_batch(QString start, QString end, gsl::span<const matrix::proto::Event> events) {
  backlog_growing_ = false;
  prev_batch_ = end;
  batches_.emplace_front();
  auto &batch = batches_.front();
  batch.token = start;  // FIXME: Verify that this is correct
  for(const auto &e : events) {  // Events is in reverse order
    batch.blocks.emplace_front(*this, initial_state_, e);
    content_height_ += batch.blocks.front().bounding_rect(*this).height() + block_spacing();
    initial_state_.revert(e);
    backlog_growable_ &= e.type != "m.room.create";
  }

  total_events_ += events.size();

  update_scrollbar(true);

  grow_backlog();  // Check if the user is still seeing blank space.
}

void TimelineView::prune_backlog() {
  // Only prune if the user's looking the bottom.
  const int scroll_pos = verticalScrollBar()->value();
  if(scroll_pos != verticalScrollBar()->maximum()) return;

  // We prune at least 2 events to ensure we don't hit a steady-state above the target
  size_t events_removed = 0;
  while(events_removed < 2) {
    const size_t front_size = batches_.front().size();
    int batch_height = 0;
    for(const auto &block : batches_.front().blocks) {
      batch_height += block.bounding_rect(*this).height() + block_spacing();
    }
    if((total_events_ - front_size < min_backlog_size_)
       || (batch_height + scrollback_trigger_size() > scroll_pos)) {
      // If removing the earliest batch would cause us to fall under the minimum, or the user could see the removed
      // batch, bail out.
      return;
    }

    // GC avatars
    for(auto &block : batches_.front().blocks) {
      if(!block.avatar()) continue;
      auto it = avatars_.find(*block.avatar());
      --it->second.references;
      if(it->second.references == 0) {
        avatars_.erase(it);
      }
    }

    total_events_ -= front_size;
    content_height_ -= batch_height;
    events_removed += front_size;
    batches_.pop_front();
    backlog_growable_ = true;
  }
}

void TimelineView::set_avatar(const matrix::Content &content, const QString &type, const QString &disposition,
                              const QByteArray &data) {
  (void)disposition;
  QPixmap pixmap;
  pixmap.loadFromData(data);
  const auto size = avatar_size();
  if(pixmap.width() > size || pixmap.height() > size)
    pixmap = pixmap.scaled(avatar_size(), avatar_size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
  avatars_.at(content).pixmap = pixmap;
  viewport()->update();
}
<commit_msg>Fix infinite backlog doubling<commit_after>#include "TimelineView.hpp"

#include <sstream>
#include <iomanip>
#include <ctime>

#include <QDebug>
#include <QScrollBar>
#include <QPainter>

#include "matrix/Session.hpp"

const static QColor text_color = Qt::black;
const static QColor primary_bg(245, 245, 245);
const static QColor secondary_bg = Qt::white;
const static QColor header_color(96, 96, 96);
constexpr static int BACKLOG_BATCH_SIZE = 50;

static auto to_time_point(uint64_t ts) {
  return std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::from_time_t(0))
      + std::chrono::duration<uint64_t, std::milli>(ts);
}

TimelineView::Event::Event(const TimelineView &view, const matrix::proto::Event &e)
    : time(to_time_point(e.origin_server_ts)) {
  auto lines = e.content["body"].toString().split('\n');
  layouts = std::vector<QTextLayout>(lines.size());
  QTextOption body_options;
  body_options.setAlignment(Qt::AlignLeft | Qt::AlignTop);
  body_options.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
  for(int i = 0; i < lines.size(); ++i) {
    layouts[i].setFont(view.font());
    layouts[i].setTextOption(body_options);
    layouts[i].setCacheEnabled(true);
    layouts[i].setText(lines[i]);
  }
}

TimelineView::Block::Block(TimelineView &view, const matrix::RoomState &state, const matrix::proto::Event &e)
    : sender_id_(e.sender) {
  events_.emplace_back(view, e);

  auto sender = state.member(e.sender);

  if(sender && !sender->avatar_url().isEmpty()) {
    try {
      avatar_ = matrix::Content(sender->avatar_url());
    } catch(const std::invalid_argument &e) {
      qDebug() << "invalid avatar URL:" << e.what() << ":" << sender->avatar_url();
    }

    if(avatar_) {
      auto result = view.avatars_.emplace(std::piecewise_construct,
                                          std::forward_as_tuple(*avatar_),
                                          std::forward_as_tuple());
      if(result.second) {
        auto reply = view.room_.session().get_thumbnail(result.first->first, QSize(view.avatar_size(), view.avatar_size()));
        connect(reply, &matrix::ContentFetch::finished, &view, &TimelineView::set_avatar);
        connect(reply, &matrix::ContentFetch::error, &view.room_, &matrix::Room::error);
      }
      ++result.first->second.references;
    }
  }

  {
    QTextOption options;
    options.setAlignment(Qt::AlignLeft | Qt::AlignTop);
    options.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    name_layout_.setFont(view.font());
    name_layout_.setTextOption(options);
    name_layout_.setCacheEnabled(true);
    if(sender) {
      name_layout_.setText(state.member_name(*sender));
    } else {
      name_layout_.setText(sender_id_);
    }
  }

  {
    QTextOption options;
    options.setAlignment(Qt::AlignRight | Qt::AlignTop);
    options.setWrapMode(QTextOption::NoWrap);
    timestamp_layout_.setFont(view.font());
    timestamp_layout_.setTextOption(options);
    timestamp_layout_.setCacheEnabled(true);

    auto time = std::chrono::system_clock::to_time_t(events_.front().time);
    auto tm = std::localtime(&time);
    std::ostringstream s;
    s << std::put_time(tm, "%H:%M");

    timestamp_layout_.setText(QString::fromStdString(s.str()));
  }

  update_layout(view);
}

void TimelineView::Block::update_layout(const TimelineView &view) {
  auto metrics = view.fontMetrics();
  const int margin = view.block_margin();
  const int avatar_size = view.avatar_size();
  qreal height = 0;

  const int line_start = avatar_size + 2*margin;
  const int line_width = view.visible_width() - (line_start + margin);

  {
    name_layout_.beginLayout();
    while(true) {
      auto line = name_layout_.createLine();
      if(!line.isValid()) break;
      line.setLineWidth(line_width);
      line.setPosition(QPointF(line_start, height));
      height += metrics.lineSpacing();
    }
    name_layout_.endLayout();
  }

  {
    timestamp_layout_.beginLayout();
    auto line = timestamp_layout_.createLine();
    line.setLineWidth(line_width);
    line.setPosition(QPointF(line_start, 0));
    timestamp_layout_.endLayout();
    if(metrics.boundingRect(name_layout_.text()).width() > line_width - metrics.boundingRect(timestamp_layout_.text()).width()) {
      timestamp_layout_.clearLayout();
    }
  }

  for(auto &event : events_) {
    for(auto &layout : event.layouts) {
      layout.beginLayout();
      while(true) {
        auto line = layout.createLine();
        if(!line.isValid()) break;
        line.setLineWidth(line_width);
        line.setPosition(QPointF(line_start, height));
        height += metrics.lineSpacing();
      }
      layout.endLayout();
    }
  }
}

QRectF TimelineView::Block::bounding_rect(const TimelineView &view) const {
  auto margin = view.block_margin();
  auto av_size = view.avatar_size();
  QRectF rect(margin, margin, view.visible_width() - margin, av_size);
  rect |= name_layout_.boundingRect();
  for(const auto &event : events_) {
    for(const auto &layout : event.layouts) {
      rect |= layout.boundingRect();
    }
  }
  return rect;
}

void TimelineView::Block::draw(const TimelineView &view, QPainter &p, QPointF offset) const {
  auto metrics = view.fontMetrics();
  auto margin = view.block_margin();

  QPixmap avatar_pixmap;
  const auto size = view.avatar_size();
  if(avatar_) {
    auto a = view.avatars_.at(*avatar_);
    if(a.pixmap.isNull()) {
      avatar_pixmap = view.avatar_loading_.pixmap(size, size);
    } else {
      avatar_pixmap = a.pixmap;
    }
  } else {
    avatar_pixmap = view.avatar_missing_.pixmap(size, size);
  }
  p.drawPixmap(QPoint(offset.x() + margin + (size - avatar_pixmap.width()) / 2,
                      offset.y() + (size - avatar_pixmap.height()) / 2),
               avatar_pixmap);

  p.save();
  p.setPen(header_color);
  name_layout_.draw(&p, offset);
  timestamp_layout_.draw(&p, offset);
  p.restore();

  for(const auto &event : events_) {
    for(const auto &layout : event.layouts) {
      layout.draw(&p, offset);
    }
  }
}

size_t TimelineView::Block::size() const {
  return events_.size();
}

size_t TimelineView::Batch::size() const {
  size_t result = 0;
  for(const auto &block : blocks) {
    result += block.size();
  }
  return result;
}

TimelineView::TimelineView(matrix::Room &room, QWidget *parent)
    : QAbstractScrollArea(parent), room_(room), initial_state_(room.initial_state()), total_events_(0),
      head_color_alternate_(true), backlog_growing_(false), backlog_growable_(true), min_backlog_size_(256),
      content_height_(0),
      avatar_missing_(QIcon::fromTheme("unknown")),
      avatar_loading_(QIcon::fromTheme("image-loading")) {
  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  verticalScrollBar()->setSingleStep(20);  // Taken from QScrollArea
  setFocusPolicy(Qt::NoFocus);

  connect(verticalScrollBar(), &QAbstractSlider::valueChanged, [this](int value) {
      (void)value;
      grow_backlog();
    });
}

int TimelineView::visible_width() const {
  return viewport()->contentsRect().width();
}

void TimelineView::push_back(const matrix::RoomState &state, const matrix::proto::Event &in) {
  backlog_growable_ &= in.type != "m.room.create";

  batches_.back().blocks.emplace_back(*this, state, in);
  head_color_alternate_ = !head_color_alternate_;

  content_height_ += block_spacing();
  content_height_ += batches_.back().blocks.back().bounding_rect(*this).height();
  total_events_ += 1;

  prune_backlog();

  update_scrollbar();

  viewport()->update();
}

void TimelineView::end_batch(const QString &token) {
  if(batches_.empty()) {
    prev_batch_ = token;
  } else {
    batches_.back().token = token;
  }
  batches_.emplace_back();  // Next batch
}

int TimelineView::block_margin() const { return fontMetrics().lineSpacing()/3; }
int TimelineView::block_spacing() const { return fontMetrics().lineSpacing()/3; }
int TimelineView::avatar_size() const {
  auto metrics = fontMetrics();
  return metrics.height() * 2 + metrics.leading();
}
int TimelineView::scrollback_trigger_size() const {
  return viewport()->contentsRect().height()/2;
}

void TimelineView::update_scrollbar(bool for_prepend) {
  auto &scroll = *verticalScrollBar();
  const bool initially_at_bottom = scroll.value() == scroll.maximum();
  auto view_height = viewport()->contentsRect().height();
  const int old_maximum = scroll.maximum();
  const int fake_height = content_height_ + scrollback_trigger_size();
  scroll.setMaximum(view_height > fake_height ? 0 : fake_height - view_height);
  if(initially_at_bottom) {
    scroll.setValue(scroll.maximum());
  } else if(for_prepend) {
    scroll.setValue(scroll.value() + (scroll.maximum() - old_maximum));
  }
}

void TimelineView::paintEvent(QPaintEvent *) {
  QRectF view_rect = viewport()->contentsRect();
  view_rect.setWidth(view_rect.width());
  QPainter painter(viewport());
  painter.fillRect(view_rect, Qt::lightGray);
  painter.setPen(Qt::black);
  auto &scroll = *verticalScrollBar();
  QPointF offset(0, view_rect.height() - (scroll.value() - scroll.maximum()));
  auto s = block_spacing();
  bool alternate = head_color_alternate_;
  const int margin = block_margin();
  for(auto batch_it = batches_.crbegin(); batch_it != batches_.crend(); ++batch_it) {
    for(auto it = batch_it->blocks.crbegin(); it != batch_it->blocks.crend(); ++it) {
      const auto bounds = it->bounding_rect(*this);
      offset.ry() -= bounds.height();
      if((offset.y() + bounds.height()) < view_rect.top()) {
        // No further drawing possible
        break;
      }
      if(offset.y() < view_rect.bottom()) {
        {
          QRectF outline(offset.x() + 0.5, offset.y() - (0.5 + s/2.0),
                         view_rect.width() - 1,
                         bounds.translated(offset).height() + (1 + s/2.0));
          painter.save();
          painter.setRenderHint(QPainter::Antialiasing);
          QPainterPath path;
          path.addRoundedRect(outline, margin*2, margin*2);
          painter.fillPath(path, alternate ? secondary_bg : primary_bg);
          painter.restore();
        }
        it->draw(*this, painter, offset);
      }
      offset.ry() -= s;
      alternate = !alternate;
    }
  }
}

void TimelineView::resizeEvent(QResizeEvent *e) {
  {
    const int unit = avatar_size() + block_spacing();
    const int window_height = viewport()->contentsRect().height();
    const int window_units = window_height / unit;

    verticalScrollBar()->setPageStep((window_units - 1) * unit);
  }

  if(e->size().width() != e->oldSize().width()) {
    // Linebreaks may have changed, so we need to lay everything out again
    content_height_ = 0;
    const auto s = block_spacing();
    for(auto &batch : batches_) {
      for(auto &block : batch.blocks) {
        block.update_layout(*this);
        content_height_ += block.bounding_rect(*this).height() + s;
      }
    }
  }

  update_scrollbar();
  // Required uncondtionally since height *and* width matter due to text wrapping. Placed after content_height_ changes
  // to ensure they're accounted for.
}

void TimelineView::grow_backlog() {
  if(verticalScrollBar()->value() >= scrollback_trigger_size() || backlog_growing_ || !backlog_growable_) return;
  backlog_growing_ = true;
  auto reply = room_.get_messages(matrix::Room::Direction::BACKWARD, prev_batch_, BACKLOG_BATCH_SIZE);
  connect(reply, &matrix::MessageFetch::finished, this, &TimelineView::prepend_batch);
  connect(reply, &matrix::MessageFetch::error, &room_, &matrix::Room::error);
}

void TimelineView::prepend_batch(QString start, QString end, gsl::span<const matrix::proto::Event> events) {
  backlog_growing_ = false;
  prev_batch_ = end;
  batches_.emplace_front();
  auto &batch = batches_.front();
  batch.token = start;  // FIXME: Verify that this is correct
  for(const auto &e : events) {  // Events is in reverse order
    batch.blocks.emplace_front(*this, initial_state_, e);
    content_height_ += batch.blocks.front().bounding_rect(*this).height() + block_spacing();
    initial_state_.revert(e);
    backlog_growable_ &= e.type != "m.room.create";
  }

  total_events_ += events.size();

  update_scrollbar(true);

  grow_backlog();  // Check if the user is still seeing blank space.
}

void TimelineView::prune_backlog() {
  // Only prune if the user's looking the bottom.
  const int scroll_pos = verticalScrollBar()->value();
  if(scroll_pos != verticalScrollBar()->maximum()) return;

  // We prune at least 2 events to ensure we don't hit a steady-state above the target
  size_t events_removed = 0;
  while(events_removed < 2) {
    const size_t front_size = batches_.front().size();
    int batch_height = 0;
    for(const auto &block : batches_.front().blocks) {
      batch_height += block.bounding_rect(*this).height() + block_spacing();
    }
    if((total_events_ - front_size < min_backlog_size_)
       || (batch_height + scrollback_trigger_size() > scroll_pos)) {
      // If removing the earliest batch would cause us to fall under the minimum, or the user could see the removed
      // batch, bail out.
      return;
    }

    // GC avatars
    for(auto &block : batches_.front().blocks) {
      if(!block.avatar()) continue;
      auto it = avatars_.find(*block.avatar());
      --it->second.references;
      if(it->second.references == 0) {
        avatars_.erase(it);
      }
    }

    total_events_ -= front_size;
    content_height_ -= batch_height;
    events_removed += front_size;
    batches_.pop_front();
    backlog_growable_ = true;
  }
}

void TimelineView::set_avatar(const matrix::Content &content, const QString &type, const QString &disposition,
                              const QByteArray &data) {
  (void)disposition;
  QPixmap pixmap;
  pixmap.loadFromData(data);
  const auto size = avatar_size();
  if(pixmap.width() > size || pixmap.height() > size)
    pixmap = pixmap.scaled(avatar_size(), avatar_size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
  avatars_.at(content).pixmap = pixmap;
  viewport()->update();
}
<|endoftext|>


<commit_before>/*
 * NPG-explorer, Nucleotide PanGenome explorer
 * Copyright (C) 2012-2015 Boris Nagaev
 *
 * See the LICENSE file for terms of use.
 */

#include <cmath>
#include <cstring>
#include <algorithm>
#include <iterator>
#include <boost/scoped_array.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include "model.hpp"
#include "throw_assert.hpp"
#include "cast.hpp"

namespace npge {

typedef boost::scoped_array<char> Buffer;

Sequence::Sequence() {
}

SequencePtr Sequence::make(const std::string& name,
                           const std::string& description,
                           const char* text, int len) {
    Buffer b(new char[len]);
    int b_len = toAtgcn(b.get(), text, len);
    ASSERT_GT(name.length(), 0);
    ASSERT_GT(b_len, 0);
    SequencePtr seq(new Sequence);
    seq->text_.assign(b.get(), b_len);
    seq->name_ = name;
    seq->description_ = description;
    return seq;
}

const std::string& Sequence::name() const {
    return name_;
}

const std::string& Sequence::description() const {
    return description_;
}

std::string Sequence::genome() const {
    using namespace boost::algorithm;
    Strings parts;
    split(parts, name(), is_any_of("&"));
    if (parts.size() == 3) {
        return parts[0];
    } else {
        return "";
    }
}

std::string Sequence::chromosome() const {
    using namespace boost::algorithm;
    Strings parts;
    split(parts, name(), is_any_of("&"));
    if (parts.size() == 3) {
        return parts[1];
    } else {
        return "";
    }
}

bool Sequence::circular() const {
    using namespace boost::algorithm;
    Strings parts;
    split(parts, name(), is_any_of("&"));
    return (parts.size() == 3 && parts[2].length() >= 1 &&
            parts[2][0] == 'c');
}

int Sequence::length() const {
    return text_.length();
}

const std::string& Sequence::text() const {
    return text_;
}

std::string Sequence::sub(int min, int max) const {
    ASSERT_LTE(0, min);
    ASSERT_LTE(min, max);
    ASSERT_LT(max, length());
    int len = max - min + 1;
    return text_.substr(min, 1);
}

std::string Sequence::tostring() const {
    return "Sequence " + name() +
           " of length " + TO_S(length());
}

bool Sequence::operator==(const Sequence& other) const {
    return name() == other.name();
}

}
<commit_msg>model.cpp/Sequence/sub: fix error<commit_after>/*
 * NPG-explorer, Nucleotide PanGenome explorer
 * Copyright (C) 2012-2015 Boris Nagaev
 *
 * See the LICENSE file for terms of use.
 */

#include <cmath>
#include <cstring>
#include <algorithm>
#include <iterator>
#include <boost/scoped_array.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include "model.hpp"
#include "throw_assert.hpp"
#include "cast.hpp"

namespace npge {

typedef boost::scoped_array<char> Buffer;

Sequence::Sequence() {
}

SequencePtr Sequence::make(const std::string& name,
                           const std::string& description,
                           const char* text, int len) {
    Buffer b(new char[len]);
    int b_len = toAtgcn(b.get(), text, len);
    ASSERT_GT(name.length(), 0);
    ASSERT_GT(b_len, 0);
    SequencePtr seq(new Sequence);
    seq->text_.assign(b.get(), b_len);
    seq->name_ = name;
    seq->description_ = description;
    return seq;
}

const std::string& Sequence::name() const {
    return name_;
}

const std::string& Sequence::description() const {
    return description_;
}

std::string Sequence::genome() const {
    using namespace boost::algorithm;
    Strings parts;
    split(parts, name(), is_any_of("&"));
    if (parts.size() == 3) {
        return parts[0];
    } else {
        return "";
    }
}

std::string Sequence::chromosome() const {
    using namespace boost::algorithm;
    Strings parts;
    split(parts, name(), is_any_of("&"));
    if (parts.size() == 3) {
        return parts[1];
    } else {
        return "";
    }
}

bool Sequence::circular() const {
    using namespace boost::algorithm;
    Strings parts;
    split(parts, name(), is_any_of("&"));
    return (parts.size() == 3 && parts[2].length() >= 1 &&
            parts[2][0] == 'c');
}

int Sequence::length() const {
    return text_.length();
}

const std::string& Sequence::text() const {
    return text_;
}

std::string Sequence::sub(int min, int max) const {
    ASSERT_LTE(0, min);
    ASSERT_LTE(min, max);
    ASSERT_LT(max, length());
    int len = max - min + 1;
    return text_.substr(min, len);
}

std::string Sequence::tostring() const {
    return "Sequence " + name() +
           " of length " + TO_S(length());
}

bool Sequence::operator==(const Sequence& other) const {
    return name() == other.name();
}

}
<|endoftext|>