<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file peer.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 * Peer Network test functions.
 */

#include <boost/test/unit_test.hpp>
#include <chrono>
#include <thread>
#include <libp2p/Host.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;

struct P2PFixture
{
	P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true; }
	~P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; }
};

BOOST_FIXTURE_TEST_SUITE(p2p, P2PFixture)

BOOST_AUTO_TEST_CASE(host)
{
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 10;

	NetworkPreferences host1prefs("127.0.0.1", 30301, false);
	NetworkPreferences host2prefs("127.0.0.1", 30302, false);

	Host host1("Test", host1prefs);
	host1.start();

	Host host2("Test", host2prefs);
	auto node2 = host2.id();
	host2.start();

	while (!host2.isStarted())
		this_thread::sleep_for(chrono::milliseconds(20));
	host1.addNode(node2, NodeIPEndpoint(bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort));

	this_thread::sleep_for(chrono::seconds(10));

	auto host1peerCount = host1.peerCount();
	auto host2peerCount = host2.peerCount();
	BOOST_REQUIRE_EQUAL(host1peerCount, 1);
	BOOST_REQUIRE_EQUAL(host2peerCount, 1);

	g_logVerbosity = oldLogVerbosity;
}

BOOST_AUTO_TEST_CASE(networkConfig)
{
	Host save("Test", NetworkPreferences(false));
	bytes store(save.saveNetwork());

	Host restore("Test", NetworkPreferences(false), bytesConstRef(&store));
	BOOST_REQUIRE(save.id() == restore.id());
}

BOOST_AUTO_TEST_CASE(save_nodes)
{
	std::list<Host*> hosts;
	for (auto i:{0,1,2,3,4,5})
	{
		Host* h = new Host("Test", NetworkPreferences("127.0.0.1", 30300 + i, false));
		h->setIdealPeerCount(10);
		// starting host is required so listenport is available
		h->start();
		while (!h->haveNetwork())
			this_thread::sleep_for(chrono::milliseconds(2));
		hosts.push_back(h);
	}

	Host& host = *hosts.front();
	for (auto const& h: hosts)
		host.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()));

	Host& host2 = *hosts.back();
	for (auto const& h: hosts)
		host2.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()));

	this_thread::sleep_for(chrono::milliseconds(2000));
	bytes firstHostNetwork(host.saveNetwork());
	bytes secondHostNetwork(host.saveNetwork());

	BOOST_REQUIRE_EQUAL(sha3(firstHostNetwork), sha3(secondHostNetwork));

	BOOST_CHECK_EQUAL(host.peerCount(), 5);
	BOOST_CHECK_EQUAL(host2.peerCount(), 5);

	RLP r(firstHostNetwork);
	BOOST_REQUIRE(r.itemCount() == 3);
	BOOST_REQUIRE(r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion);
	BOOST_REQUIRE_EQUAL(r[1].toBytes().size(), 32); // secret
	BOOST_REQUIRE(r[2].itemCount() >= 5);

	for (auto i: r[2])
	{
		BOOST_REQUIRE(i.itemCount() == 3 || i.itemCount() == 10);
		BOOST_REQUIRE(i[0].itemCount() == 4 || i[0].itemCount() == 16);
	}
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE(peerTypes)

BOOST_AUTO_TEST_CASE(emptySharedPeer)
{
	shared_ptr<Peer> p;
	BOOST_REQUIRE(!p);

	std::map<NodeId, std::shared_ptr<Peer>> peers;
	p = peers[NodeId()];
	BOOST_REQUIRE(!p);

	p.reset(new Peer(UnspecifiedNode));
	BOOST_REQUIRE(!p->id);
	BOOST_REQUIRE(!*p);

	p.reset(new Peer(Node(NodeId(EmptySHA3), UnspecifiedNodeIPEndpoint)));
	BOOST_REQUIRE(!(!*p));
	BOOST_REQUIRE(*p);
	BOOST_REQUIRE(p);
}

BOOST_AUTO_TEST_SUITE_END()

int peerTest(int argc, char** argv)
{
	Public remoteAlias;
	short listenPort = 30303;
	string remoteHost;
	short remotePort = 30303;

	for (int i = 1; i < argc; ++i)
	{
		string arg = argv[i];
		if (arg == "-l" && i + 1 < argc)
			listenPort = (short)atoi(argv[++i]);
		else if (arg == "-r" && i + 1 < argc)
			remoteHost = argv[++i];
		else if (arg == "-p" && i + 1 < argc)
			remotePort = (short)atoi(argv[++i]);
		else if (arg == "-ra" && i + 1 < argc)
			remoteAlias = Public(dev::fromHex(argv[++i]));
		else
			remoteHost = argv[i];
	}

	Host ph("Test", NetworkPreferences(listenPort));

	if (!remoteHost.empty() && !remoteAlias)
		ph.addNode(remoteAlias, NodeIPEndpoint(bi::address::from_string(remoteHost), remotePort, remotePort));

	this_thread::sleep_for(chrono::milliseconds(200));

	return 0;
}

<commit_msg>more test updates (v4 endpoints. #1557, #1558)<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file peer.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 * Peer Network test functions.
 */

#include <boost/test/unit_test.hpp>
#include <chrono>
#include <thread>
#include <libp2p/Host.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;

struct P2PFixture
{
	P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = true; }
	~P2PFixture() { dev::p2p::NodeIPEndpoint::test_allowLocal = false; }
};

BOOST_FIXTURE_TEST_SUITE(p2p, P2PFixture)

BOOST_AUTO_TEST_CASE(host)
{
	auto oldLogVerbosity = g_logVerbosity;
	g_logVerbosity = 10;

	NetworkPreferences host1prefs("127.0.0.1", 30301, false);
	NetworkPreferences host2prefs("127.0.0.1", 30302, false);

	Host host1("Test", host1prefs);
	host1.start();

	Host host2("Test", host2prefs);
	auto node2 = host2.id();
	host2.start();

	while (!host2.isStarted())
		this_thread::sleep_for(chrono::milliseconds(20));
	host1.addNode(node2, NodeIPEndpoint(bi::address::from_string("127.0.0.1"), host2prefs.listenPort, host2prefs.listenPort));

	this_thread::sleep_for(chrono::seconds(10));

	auto host1peerCount = host1.peerCount();
	auto host2peerCount = host2.peerCount();
	BOOST_REQUIRE_EQUAL(host1peerCount, 1);
	BOOST_REQUIRE_EQUAL(host2peerCount, 1);

	g_logVerbosity = oldLogVerbosity;
}

BOOST_AUTO_TEST_CASE(networkConfig)
{
	Host save("Test", NetworkPreferences(false));
	bytes store(save.saveNetwork());

	Host restore("Test", NetworkPreferences(false), bytesConstRef(&store));
	BOOST_REQUIRE(save.id() == restore.id());
}

BOOST_AUTO_TEST_CASE(saveNodes)
{
	std::list<Host*> hosts;
	for (auto i:{0,1,2,3,4,5})
	{
		Host* h = new Host("Test", NetworkPreferences("127.0.0.1", 30300 + i, false));
		h->setIdealPeerCount(10);
		// starting host is required so listenport is available
		h->start();
		while (!h->haveNetwork())
			this_thread::sleep_for(chrono::milliseconds(2));
		hosts.push_back(h);
	}

	Host& host = *hosts.front();
	for (auto const& h: hosts)
		host.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()));

	Host& host2 = *hosts.back();
	for (auto const& h: hosts)
		host2.addNode(h->id(), NodeIPEndpoint(bi::address::from_string("127.0.0.1"), h->listenPort(), h->listenPort()));

	this_thread::sleep_for(chrono::milliseconds(2000));
	bytes firstHostNetwork(host.saveNetwork());
	bytes secondHostNetwork(host.saveNetwork());

	BOOST_REQUIRE_EQUAL(sha3(firstHostNetwork), sha3(secondHostNetwork));

	BOOST_CHECK_EQUAL(host.peerCount(), 5);
	BOOST_CHECK_EQUAL(host2.peerCount(), 5);

	RLP r(firstHostNetwork);
	BOOST_REQUIRE(r.itemCount() == 3);
	BOOST_REQUIRE(r[0].toInt<unsigned>() == dev::p2p::c_protocolVersion);
	BOOST_REQUIRE_EQUAL(r[1].toBytes().size(), 32); // secret
	BOOST_REQUIRE(r[2].itemCount() >= 5);

	for (auto i: r[2])
	{
		BOOST_REQUIRE(i.itemCount() == 4 || i.itemCount() == 11);
		BOOST_REQUIRE(i[0].itemCount() == 4 || i[0].itemCount() == 16);
	}
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE(peerTypes)

BOOST_AUTO_TEST_CASE(emptySharedPeer)
{
	shared_ptr<Peer> p;
	BOOST_REQUIRE(!p);

	std::map<NodeId, std::shared_ptr<Peer>> peers;
	p = peers[NodeId()];
	BOOST_REQUIRE(!p);

	p.reset(new Peer(UnspecifiedNode));
	BOOST_REQUIRE(!p->id);
	BOOST_REQUIRE(!*p);

	p.reset(new Peer(Node(NodeId(EmptySHA3), UnspecifiedNodeIPEndpoint)));
	BOOST_REQUIRE(!(!*p));
	BOOST_REQUIRE(*p);
	BOOST_REQUIRE(p);
}

BOOST_AUTO_TEST_SUITE_END()

int peerTest(int argc, char** argv)
{
	Public remoteAlias;
	short listenPort = 30303;
	string remoteHost;
	short remotePort = 30303;

	for (int i = 1; i < argc; ++i)
	{
		string arg = argv[i];
		if (arg == "-l" && i + 1 < argc)
			listenPort = (short)atoi(argv[++i]);
		else if (arg == "-r" && i + 1 < argc)
			remoteHost = argv[++i];
		else if (arg == "-p" && i + 1 < argc)
			remotePort = (short)atoi(argv[++i]);
		else if (arg == "-ra" && i + 1 < argc)
			remoteAlias = Public(dev::fromHex(argv[++i]));
		else
			remoteHost = argv[i];
	}

	Host ph("Test", NetworkPreferences(listenPort));

	if (!remoteHost.empty() && !remoteAlias)
		ph.addNode(remoteAlias, NodeIPEndpoint(bi::address::from_string(remoteHost), remotePort, remotePort));

	this_thread::sleep_for(chrono::milliseconds(200));

	return 0;
}

<|endoftext|>


<commit_before>///
/// @file   prev_prime1.cpp
/// @brief  Test prev_prime() of primesieve::iterator.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve.hpp>

#include <stdint.h>
#include <cstdlib>
#include <exception>
#include <iostream>
#include <vector>

using namespace std;

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

int main()
{
  vector<uint64_t> primes;
  primesieve::generate_primes(100000, &primes);
  primesieve::iterator it;
  uint64_t back = primes.size() - 1;
  uint64_t prime;

  for (uint64_t i = back; i > 0; i--)
  {
    it.skipto(primes[i] + 1);
    prime = it.prev_prime();
    cout << "prev_prime(" << primes[i] + 1 << ") = " << prime;
    check(prime == primes[i]);

    it.skipto(primes[i]);
    prime = it.prev_prime();
    cout << "prev_prime(" << primes[i] << ") = " << prime;
    check(prime == primes[i - 1]);
  }

  it.skipto(100000000);
  prime = it.prev_prime();
  uint64_t sum = 0;

  // iterate over the primes below 10^8
  for (; prime > 0; prime = it.prev_prime())
    sum += prime;

  cout << "Sum of the primes below 10^8 = " << sum;
  check(sum == 279209790387276ull);

  for (uint64_t i = 0; i < 1000; i++)
  {
    prime = it.prev_prime();
    cout << "prev_prime(0) = " << prime;
    check(prime == 0);
  }

  for (uint64_t i = 0; i < 1000; i++)
  {
    uint64_t old = prime;
    prime = it.next_prime();
    cout << "next_prime(" << old << ") = " << prime;
    check(prime == primes.at(i));
  }

  it.skipto(primes.back());

  for (uint64_t i = 0; i < 1000; i++)
  {
    prime = it.prev_prime();
    uint64_t p1 = primes[primes.size() - (i + 1)];
    uint64_t p2 = primes[primes.size() - (i + 2)];
    cout << "prev_prime(" << p1 << ") = " << prime;
    check(prime == p2);
  }

  for (uint64_t i = 0; i < 1000; i++)
  {
    uint64_t old = prime;
    uint64_t j = primes.size() - 1000 + i;
    prime = it.next_prime();
    cout << "next_prime(" << old << ") = " << prime;
    check(prime == primes.at(j));
  }

  it.skipto(18446744073709551615ull, 18446744073709551557ull);
  prime = it.prev_prime();
  cout << "prev_prime(" << 18446744073709551615ull << ") = " << prime;
  check(prime == 18446744073709551557ull);

  cout << endl;
  cout << "All tests passed successfully!" << endl;

  return 0;
}
<commit_msg>Refactor<commit_after>///
/// @file   prev_prime1.cpp
/// @brief  Test prev_prime() of primesieve::iterator.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve.hpp>

#include <stdint.h>
#include <cstdlib>
#include <exception>
#include <iostream>
#include <vector>

using namespace std;

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

int main()
{
  vector<uint64_t> primes;
  primesieve::generate_primes(100000, &primes);
  primesieve::iterator it;
  uint64_t back = primes.size() - 1;
  uint64_t prime;

  for (uint64_t i = back; i > 0; i--)
  {
    it.skipto(primes[i] + 1);
    prime = it.prev_prime();
    cout << "prev_prime(" << primes[i] + 1 << ") = " << prime;
    check(prime == primes[i]);

    it.skipto(primes[i]);
    prime = it.prev_prime();
    cout << "prev_prime(" << primes[i] << ") = " << prime;
    check(prime == primes[i - 1]);
  }

  it.skipto(100000000);
  prime = it.prev_prime();
  uint64_t sum = 0;

  // iterate over the primes below 10^8
  for (; prime > 0; prime = it.prev_prime())
    sum += prime;

  cout << "Sum of the primes below 10^8 = " << sum;
  check(sum == 279209790387276ull);

  for (uint64_t i = 0; i < 1000; i++)
  {
    prime = it.prev_prime();
    cout << "prev_prime(0) = " << prime;
    check(prime == 0);
  }

  for (uint64_t i = 0; i < 1000; i++)
  {
    uint64_t old = prime;
    prime = it.next_prime();
    cout << "next_prime(" << old << ") = " << prime;
    check(prime == primes[i]);
  }

  it.skipto(primes.back());

  for (uint64_t i = 0; i < 1000; i++)
  {
    prime = it.prev_prime();
    uint64_t p1 = primes.size() - (i + 1);
    uint64_t p2 = primes.size() - (i + 2);
    cout << "prev_prime(" << primes[p1] << ") = " << prime;
    check(prime == primes[p2]);
  }

  for (uint64_t i = 0; i < 1000; i++)
  {
    uint64_t old = prime;
    uint64_t j = primes.size() - 1000 + i;
    prime = it.next_prime();
    cout << "next_prime(" << old << ") = " << prime;
    check(prime == primes[j]);
  }

  it.skipto(18446744073709551615ull, 18446744073709551557ull);
  prime = it.prev_prime();
  cout << "prev_prime(" << 18446744073709551615ull << ") = " << prime;
  check(prime == 18446744073709551557ull);

  cout << endl;
  cout << "All tests passed successfully!" << endl;

  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>

#include "../../src/character-stream.h"
#include "../../src/scanner.h"
#include "../../src/token.h"

using flora::FileCharacterStream;
using flora::Scanner;
using flora::Token;
using flora::Tokens;

int main(int argc, char const *argv[]) {
  const char *test_cases[] = {
    "test_case_all_tokens.txt",
    // "test_case_error_comments.txt",
    // "test_case_error_string.txt",
    // "test_case_error_character.txt",
    // "test_case_5.txt",
    // "test_case_6.txt"
  };
  for (int i = 0; i < sizeof(test_cases) / sizeof(const char*); i++) {
    std::cout << "Now testing " << test_cases[i] << std::endl;
    FileCharacterStream *stream = new FileCharacterStream(test_cases[i]);
    Scanner *scanner = new Scanner();
    scanner->Initialize(stream);
    std::cout << "Strat scanning..." << std::endl;
    while (true) {
      Token tok = scanner->Advance();
      std::cout << Tokens::Name(tok) << " (\"";
      if (scanner->GetTokenLiteral().size() > 0) {
        std::cout << scanner->GetTokenLiteral();
      } else {
        std::cout << Tokens::Literal(tok);
      }
      std::cout << "\")" << std::endl;
      if (tok == Token::EndOfSource || tok == Token::Illegal)
        break;
    }
    delete scanner;
    delete stream;
  }
  return 0;
}<commit_msg>Spelling error.<commit_after>#include <iostream>

#include "../../src/character-stream.h"
#include "../../src/scanner.h"
#include "../../src/token.h"

using flora::FileCharacterStream;
using flora::Scanner;
using flora::Token;
using flora::Tokens;

int main(int argc, char const *argv[]) {
  const char *test_cases[] = {
    "test_case_all_tokens.txt",
    // "test_case_error_comments.txt",
    // "test_case_error_string.txt",
    // "test_case_error_character.txt",
    // "test_case_5.txt",
    // "test_case_6.txt"
  };
  for (int i = 0; i < sizeof(test_cases) / sizeof(const char*); i++) {
    std::cout << "Now testing " << test_cases[i] << std::endl;
    FileCharacterStream *stream = new FileCharacterStream(test_cases[i]);
    Scanner *scanner = new Scanner();
    scanner->Initialize(stream);
    std::cout << "Start scanning..." << std::endl;
    while (true) {
      Token tok = scanner->Advance();
      std::cout << Tokens::Name(tok) << " (\"";
      if (scanner->GetTokenLiteral().size() > 0) {
        std::cout << scanner->GetTokenLiteral();
      } else {
        std::cout << Tokens::Literal(tok);
      }
      std::cout << "\")" << std::endl;
      if (tok == Token::EndOfSource || tok == Token::Illegal)
        break;
    }
    delete scanner;
    delete stream;
  }
  return 0;
}<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include "robots.h"

TEST(RobotsTest, DisallowFirst)
{
    // Disallow must be preceeded by a User-Agent line
    ASSERT_THROW(Rep::Robots("Disallow: /path"), std::invalid_argument);
}

TEST(RobotsTest, AllowFirst)
{
    // Allow must be preceeded by a User-Agent line
    ASSERT_THROW(Rep::Robots("Allow: /path"), std::invalid_argument);
}

TEST(RobotsTest, CrawlDelayFirst)
{
    // Crawl-delay must be preceeded by a User-Agent line
    ASSERT_THROW(Rep::Robots("Crawl-delay: 1"), std::invalid_argument);
}

TEST(RobotsTest, WellFormedCrawlDelay)
{
    std::string content =
        "User-agent: *\n"
        "Crawl-delay: 5.2\n";
    Rep::Robots robot(content);
    EXPECT_NEAR(robot.agent("any").delay(), 5.2, 0.000001);
}

TEST(RobotsTest, MalformedCrawlDelay)
{
    std::string content =
        "User-agent: *\n"
        "Crawl-delay: word\n";
    Rep::Robots robot(content);
    EXPECT_EQ(robot.agent("any").delay(), -1.0);
}

TEST(RobotsTest, HonorsDefaultAgent)
{
    std::string content =
        "User-agent: *\n"
        "Disallow: /tmp\n"
        "\n"
        "User-agent: other-agent\n"
        "Allow: /tmp\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed("/tmp", "agent"));
    EXPECT_TRUE(robot.allowed("/path", "agent"));
}

TEST(RobotsTest, HonorsSpecificAgent)
{
    std::string content =
        "User-agent: *\n"
        "Disallow: /tmp\n"
        "\n"
        "User-agent: agent\n"
        "Allow: /tmp\n";
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.allowed("/tmp", "agent"));
    EXPECT_TRUE(robot.allowed("/path", "agent"));
}

TEST(RobotsTest, Grouping)
{
    std::string content =
        "User-agent: one\n"
        "User-agent: two\n"
        "Disallow: /tmp\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed("/tmp", "one"));
    EXPECT_FALSE(robot.allowed("/tmp", "two"));
}

TEST(RobotsTest, GroupingUnknownKeys)
{
    // When we encounter unknown keys, we should disregard any grouping that may have
    // happened between user agent rules.
    //
    // This is an example from the wild. Despite `Noindex` not being a valid directive,
    // we'll not consider the "*" and "ia_archiver" rules together.
    std::string content =
        "User-agent: *\n"
        "Disallow: /content/2/\n"
        "User-agent: *\n"
        "Noindex: /gb.html\n"
        "Noindex: /content/2/\n"
        "User-agent: ia_archiver\n"
        "Disallow: /\n";
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.allowed("/foo", "agent"));
    EXPECT_FALSE(robot.allowed("/bar", "ia_archiver"));
}

TEST(RobotsTest, SeparatesAgents)
{
    std::string content =
        "User-agent: one\n"
        "Crawl-delay: 1\n"
        "\n"
        "User-agent: two\n"
        "Crawl-delay: 2\n";
    Rep::Robots robot(content);
    EXPECT_NE(robot.agent("one").delay(), robot.agent("two").delay());
}

TEST(RobotsTest, ExposesSitemaps)
{
    std::string content =
        "Sitemap: http://a.com/sitemap.xml\n"
        "Sitemap: http://b.com/sitemap.xml\n";
    Rep::Robots robot(content);
    std::vector<std::string> expected = {
        "http://a.com/sitemap.xml", "http://b.com/sitemap.xml"
    };
    EXPECT_EQ(robot.sitemaps(), expected);
}

TEST(RobotsTest, CaseInsensitivity)
{
    std::string content =
        "User-agent: Agent\n"
        "Disallow: /path\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed("/path", "agent"));
    EXPECT_FALSE(robot.allowed("/path", "aGeNt"));
}

TEST(RobotsTest, Empty)
{
    std::string content;
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.sitemaps().empty());
    EXPECT_TRUE(robot.allowed("/", "agent"));
}

TEST(RobotsTest, Comments)
{
    std::string content =
        "User-Agent: *  # comment saying it's the default agent\n"
        "Disallow: /\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed("/path", "agent"));
}

TEST(RobotsTest, AcceptsFullUrl)
{
    std::string content =
        "User-Agent: agent\n"
        "Disallow: /path;params?query\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed(
        "http://userinfo@exmaple.com:10/path;params?query#fragment", "agent"));
}

TEST(RobotsTest, SkipMalformedLine)
{
    std::string content =
        "User-Agent: agent\n"
        "Disallow /no/colon/in/this/line\n";
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.allowed("/no/colon/in/this/line", "agent"));
}

TEST(RobotsTest, RobotsUrlHttp)
{
    std::string url("http://user@example.com:80/path;params?query#fragment");
    std::string expected("http://example.com/robots.txt");
    EXPECT_EQ(expected, Rep::Robots::robotsUrl(url));
}

TEST(RobotsTest, RobotsUrlHttps)
{
    std::string url("https://user@example.com:443/path;params?query#fragment");
    std::string expected("https://example.com/robots.txt");
    EXPECT_EQ(expected, Rep::Robots::robotsUrl(url));
}

TEST(RobotsTest, RobotsUrlNonDefaultPort)
{
    std::string url("http://user@example.com:8080/path;params?query#fragment");
    std::string expected("http://example.com:8080/robots.txt");
    EXPECT_EQ(expected, Rep::Robots::robotsUrl(url));
}

TEST(RobotsTest, RfcExample)
{
    std::string content =
        "# /robots.txt for http://www.fict.org/\n"
        "# comments to webmaster@fict.org\n"
        "\n"
        "User-agent: unhipbot\n"
        "Disallow: /\n"
        "\n"
        "User-agent: webcrawler\n"
        "User-agent: excite\n"
        "Disallow:\n"
        "\n"
        "User-agent: *\n"
        "Disallow: /org/plans.html\n"
        "Allow: /org/\n"
        "Allow: /serv\n"
        "Allow: /~mak\n"
        "Disallow: /\n";
    Rep::Robots robot(content);

    // The unhip bot
    EXPECT_FALSE(robot.allowed("/", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/index.html", "unhipbot"));
    EXPECT_TRUE(robot.allowed("/robots.txt", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/server.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/services/fast.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/services/slow.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/orgo.gif", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/org/about.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/org/plans.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/%7Ejim/jim.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/%7Emak/mak.html", "unhipbot"));

    // The webcrawler agent
    EXPECT_TRUE(robot.allowed("/", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/index.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/robots.txt", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/server.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/services/fast.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/services/slow.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/orgo.gif", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/org/about.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/org/plans.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/%7Ejim/jim.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/%7Emak/mak.html", "webcrawler"));

    // The excite agent
    EXPECT_TRUE(robot.allowed("/", "excite"));
    EXPECT_TRUE(robot.allowed("/index.html", "excite"));
    EXPECT_TRUE(robot.allowed("/robots.txt", "excite"));
    EXPECT_TRUE(robot.allowed("/server.html", "excite"));
    EXPECT_TRUE(robot.allowed("/services/fast.html", "excite"));
    EXPECT_TRUE(robot.allowed("/services/slow.html", "excite"));
    EXPECT_TRUE(robot.allowed("/orgo.gif", "excite"));
    EXPECT_TRUE(robot.allowed("/org/about.html", "excite"));
    EXPECT_TRUE(robot.allowed("/org/plans.html", "excite"));
    EXPECT_TRUE(robot.allowed("/%7Ejim/jim.html", "excite"));
    EXPECT_TRUE(robot.allowed("/%7Emak/mak.html", "excite"));

    // All others
    EXPECT_FALSE(robot.allowed("/", "anything"));
    EXPECT_FALSE(robot.allowed("/index.html", "anything"));
    EXPECT_TRUE(robot.allowed("/robots.txt", "anything"));
    EXPECT_TRUE(robot.allowed("/server.html", "anything"));
    EXPECT_TRUE(robot.allowed("/services/fast.html", "anything"));
    EXPECT_TRUE(robot.allowed("/services/slow.html", "anything"));
    EXPECT_FALSE(robot.allowed("/orgo.gif", "anything"));
    EXPECT_TRUE(robot.allowed("/org/about.html", "anything"));
    EXPECT_FALSE(robot.allowed("/org/plans.html", "anything"));
    EXPECT_FALSE(robot.allowed("/%7Ejim/jim.html", "anything"));
    EXPECT_TRUE(robot.allowed("/%7Emak/mak.html", "anything"));
}

TEST(RobotsTest, IgnoreBOM)
{
    std::string content =
        "\xEF\xBB\xBFuser-agent: *\n"
        "disallow: /disallowed\n";
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.allowed("/", "bot"));
    EXPECT_FALSE(robot.allowed("/disallowed", "bot"));
}
<commit_msg>Failing test about assuming default user agent.<commit_after>#include <gtest/gtest.h>

#include "robots.h"

TEST(RobotsTest, NoLeadingUserAgent)
{
    // Assumed to be the default user agent
    std::string content =
        "Disallow: /path\n"
        "Allow: /path/exception\n"
        "Crawl-delay: 5.2\n";
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.allowed("/path/exception", "agent"));
    EXPECT_FALSE(robot.allowed("/path", "agent"));
    EXPECT_NEAR(robot.agent("agent").delay(), 5.2, 0.000001);
}

TEST(RobotsTest, WellFormedCrawlDelay)
{
    std::string content =
        "User-agent: *\n"
        "Crawl-delay: 5.2\n";
    Rep::Robots robot(content);
    EXPECT_NEAR(robot.agent("any").delay(), 5.2, 0.000001);
}

TEST(RobotsTest, MalformedCrawlDelay)
{
    std::string content =
        "User-agent: *\n"
        "Crawl-delay: word\n";
    Rep::Robots robot(content);
    EXPECT_EQ(robot.agent("any").delay(), -1.0);
}

TEST(RobotsTest, HonorsDefaultAgent)
{
    std::string content =
        "User-agent: *\n"
        "Disallow: /tmp\n"
        "\n"
        "User-agent: other-agent\n"
        "Allow: /tmp\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed("/tmp", "agent"));
    EXPECT_TRUE(robot.allowed("/path", "agent"));
}

TEST(RobotsTest, HonorsSpecificAgent)
{
    std::string content =
        "User-agent: *\n"
        "Disallow: /tmp\n"
        "\n"
        "User-agent: agent\n"
        "Allow: /tmp\n";
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.allowed("/tmp", "agent"));
    EXPECT_TRUE(robot.allowed("/path", "agent"));
}

TEST(RobotsTest, Grouping)
{
    std::string content =
        "User-agent: one\n"
        "User-agent: two\n"
        "Disallow: /tmp\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed("/tmp", "one"));
    EXPECT_FALSE(robot.allowed("/tmp", "two"));
}

TEST(RobotsTest, GroupingUnknownKeys)
{
    // When we encounter unknown keys, we should disregard any grouping that may have
    // happened between user agent rules.
    //
    // This is an example from the wild. Despite `Noindex` not being a valid directive,
    // we'll not consider the "*" and "ia_archiver" rules together.
    std::string content =
        "User-agent: *\n"
        "Disallow: /content/2/\n"
        "User-agent: *\n"
        "Noindex: /gb.html\n"
        "Noindex: /content/2/\n"
        "User-agent: ia_archiver\n"
        "Disallow: /\n";
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.allowed("/foo", "agent"));
    EXPECT_FALSE(robot.allowed("/bar", "ia_archiver"));
}

TEST(RobotsTest, SeparatesAgents)
{
    std::string content =
        "User-agent: one\n"
        "Crawl-delay: 1\n"
        "\n"
        "User-agent: two\n"
        "Crawl-delay: 2\n";
    Rep::Robots robot(content);
    EXPECT_NE(robot.agent("one").delay(), robot.agent("two").delay());
}

TEST(RobotsTest, ExposesSitemaps)
{
    std::string content =
        "Sitemap: http://a.com/sitemap.xml\n"
        "Sitemap: http://b.com/sitemap.xml\n";
    Rep::Robots robot(content);
    std::vector<std::string> expected = {
        "http://a.com/sitemap.xml", "http://b.com/sitemap.xml"
    };
    EXPECT_EQ(robot.sitemaps(), expected);
}

TEST(RobotsTest, CaseInsensitivity)
{
    std::string content =
        "User-agent: Agent\n"
        "Disallow: /path\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed("/path", "agent"));
    EXPECT_FALSE(robot.allowed("/path", "aGeNt"));
}

TEST(RobotsTest, Empty)
{
    std::string content;
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.sitemaps().empty());
    EXPECT_TRUE(robot.allowed("/", "agent"));
}

TEST(RobotsTest, Comments)
{
    std::string content =
        "User-Agent: *  # comment saying it's the default agent\n"
        "Disallow: /\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed("/path", "agent"));
}

TEST(RobotsTest, AcceptsFullUrl)
{
    std::string content =
        "User-Agent: agent\n"
        "Disallow: /path;params?query\n";
    Rep::Robots robot(content);
    EXPECT_FALSE(robot.allowed(
        "http://userinfo@exmaple.com:10/path;params?query#fragment", "agent"));
}

TEST(RobotsTest, SkipMalformedLine)
{
    std::string content =
        "User-Agent: agent\n"
        "Disallow /no/colon/in/this/line\n";
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.allowed("/no/colon/in/this/line", "agent"));
}

TEST(RobotsTest, RobotsUrlHttp)
{
    std::string url("http://user@example.com:80/path;params?query#fragment");
    std::string expected("http://example.com/robots.txt");
    EXPECT_EQ(expected, Rep::Robots::robotsUrl(url));
}

TEST(RobotsTest, RobotsUrlHttps)
{
    std::string url("https://user@example.com:443/path;params?query#fragment");
    std::string expected("https://example.com/robots.txt");
    EXPECT_EQ(expected, Rep::Robots::robotsUrl(url));
}

TEST(RobotsTest, RobotsUrlNonDefaultPort)
{
    std::string url("http://user@example.com:8080/path;params?query#fragment");
    std::string expected("http://example.com:8080/robots.txt");
    EXPECT_EQ(expected, Rep::Robots::robotsUrl(url));
}

TEST(RobotsTest, RfcExample)
{
    std::string content =
        "# /robots.txt for http://www.fict.org/\n"
        "# comments to webmaster@fict.org\n"
        "\n"
        "User-agent: unhipbot\n"
        "Disallow: /\n"
        "\n"
        "User-agent: webcrawler\n"
        "User-agent: excite\n"
        "Disallow:\n"
        "\n"
        "User-agent: *\n"
        "Disallow: /org/plans.html\n"
        "Allow: /org/\n"
        "Allow: /serv\n"
        "Allow: /~mak\n"
        "Disallow: /\n";
    Rep::Robots robot(content);

    // The unhip bot
    EXPECT_FALSE(robot.allowed("/", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/index.html", "unhipbot"));
    EXPECT_TRUE(robot.allowed("/robots.txt", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/server.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/services/fast.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/services/slow.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/orgo.gif", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/org/about.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/org/plans.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/%7Ejim/jim.html", "unhipbot"));
    EXPECT_FALSE(robot.allowed("/%7Emak/mak.html", "unhipbot"));

    // The webcrawler agent
    EXPECT_TRUE(robot.allowed("/", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/index.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/robots.txt", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/server.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/services/fast.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/services/slow.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/orgo.gif", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/org/about.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/org/plans.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/%7Ejim/jim.html", "webcrawler"));
    EXPECT_TRUE(robot.allowed("/%7Emak/mak.html", "webcrawler"));

    // The excite agent
    EXPECT_TRUE(robot.allowed("/", "excite"));
    EXPECT_TRUE(robot.allowed("/index.html", "excite"));
    EXPECT_TRUE(robot.allowed("/robots.txt", "excite"));
    EXPECT_TRUE(robot.allowed("/server.html", "excite"));
    EXPECT_TRUE(robot.allowed("/services/fast.html", "excite"));
    EXPECT_TRUE(robot.allowed("/services/slow.html", "excite"));
    EXPECT_TRUE(robot.allowed("/orgo.gif", "excite"));
    EXPECT_TRUE(robot.allowed("/org/about.html", "excite"));
    EXPECT_TRUE(robot.allowed("/org/plans.html", "excite"));
    EXPECT_TRUE(robot.allowed("/%7Ejim/jim.html", "excite"));
    EXPECT_TRUE(robot.allowed("/%7Emak/mak.html", "excite"));

    // All others
    EXPECT_FALSE(robot.allowed("/", "anything"));
    EXPECT_FALSE(robot.allowed("/index.html", "anything"));
    EXPECT_TRUE(robot.allowed("/robots.txt", "anything"));
    EXPECT_TRUE(robot.allowed("/server.html", "anything"));
    EXPECT_TRUE(robot.allowed("/services/fast.html", "anything"));
    EXPECT_TRUE(robot.allowed("/services/slow.html", "anything"));
    EXPECT_FALSE(robot.allowed("/orgo.gif", "anything"));
    EXPECT_TRUE(robot.allowed("/org/about.html", "anything"));
    EXPECT_FALSE(robot.allowed("/org/plans.html", "anything"));
    EXPECT_FALSE(robot.allowed("/%7Ejim/jim.html", "anything"));
    EXPECT_TRUE(robot.allowed("/%7Emak/mak.html", "anything"));
}

TEST(RobotsTest, IgnoreBOM)
{
    std::string content =
        "\xEF\xBB\xBFuser-agent: *\n"
        "disallow: /disallowed\n";
    Rep::Robots robot(content);
    EXPECT_TRUE(robot.allowed("/", "bot"));
    EXPECT_FALSE(robot.allowed("/disallowed", "bot"));
}
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd/string.hpp"
#include "flusspferd/string_io.hpp"
#include "flusspferd/exception.hpp"

#include <iostream>
#include <cstring>
#include <string>

#include "test_environment.hpp"

BOOST_FIXTURE_TEST_SUITE( with_context, context_fixture )

BOOST_AUTO_TEST_CASE( empty_string ) {
  flusspferd::string s, t;
  BOOST_CHECK(s.length() == 0);
  BOOST_CHECK(s.to_string().empty());
  BOOST_CHECK(std::strlen(s.c_str()) == 0);
  BOOST_CHECK_EQUAL(s, t);
}

BOOST_AUTO_TEST_CASE( cstring ) {
  char const * const test = "Hallo Welt!\n";
  flusspferd::string s(test);
  BOOST_CHECK_EQUAL(s.length(), std::strlen(test));
  BOOST_CHECK(std::strcmp(s.c_str(), test) == 0);
}

BOOST_AUTO_TEST_CASE( std_string ) {
  std::string test = "Hallo Welt!\n";
  flusspferd::string s(test);
  BOOST_CHECK_EQUAL(s.length(), test.length());
  BOOST_CHECK_EQUAL(s.to_string(), test);
  BOOST_CHECK(std::strcmp(s.c_str(), test.c_str()) == 0);
}

BOOST_AUTO_TEST_CASE( copy_op ) {
  flusspferd::string const a("Hallo Welt!\n");
  flusspferd::string b;
  b = a;
  BOOST_CHECK_EQUAL(a, b);
}

BOOST_AUTO_TEST_CASE( op_less ) {
  std::string const ss1 = "aaa";
  std::string const ss2 = "aab";
  flusspferd::string fs1 = ss1;
  flusspferd::string fs2 = ss2;

  BOOST_CHECK( (fs1 < fs2) == (ss1 < ss2) );
  BOOST_CHECK( (fs2 < fs1) == (ss2 < ss1) );
}

BOOST_AUTO_TEST_CASE( string_substr ) {
  std::string const str = "Ba bo bu bi bo bz";
  flusspferd::string s = str;
  BOOST_CHECK_EQUAL(s.substr(3, 5), str.substr(3, 5));
}

BOOST_AUTO_TEST_CASE( string_io ) {
  std::stringstream ss;
  flusspferd::string s("Hallo Welt!");
  ss << s;
  BOOST_CHECK_EQUAL(s.to_string(), ss.str());
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>tests: added unit test for string op!=<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd/string.hpp"
#include "flusspferd/string_io.hpp"
#include "flusspferd/exception.hpp"

#include <iostream>
#include <cstring>
#include <string>

#include "test_environment.hpp"

BOOST_FIXTURE_TEST_SUITE( with_context, context_fixture )

BOOST_AUTO_TEST_CASE( empty_string ) {
  flusspferd::string s, t;
  BOOST_CHECK(s.length() == 0);
  BOOST_CHECK(s.to_string().empty());
  BOOST_CHECK(std::strlen(s.c_str()) == 0);
  BOOST_CHECK_EQUAL(s, t);
}

BOOST_AUTO_TEST_CASE( cstring ) {
  char const * const test = "Hallo Welt!\n";
  flusspferd::string s(test);
  BOOST_CHECK_EQUAL(s.length(), std::strlen(test));
  BOOST_CHECK(std::strcmp(s.c_str(), test) == 0);
}

BOOST_AUTO_TEST_CASE( std_string ) {
  std::string test = "Hallo Welt!\n";
  flusspferd::string s(test);
  BOOST_CHECK_EQUAL(s.length(), test.length());
  BOOST_CHECK_EQUAL(s.to_string(), test);
  BOOST_CHECK(std::strcmp(s.c_str(), test.c_str()) == 0);
}

BOOST_AUTO_TEST_CASE( copy_op ) {
  flusspferd::string const a("Hallo Welt!\n");
  flusspferd::string b;
  b = a;
  BOOST_CHECK_EQUAL(a, b);
}

BOOST_AUTO_TEST_CASE( op_ne ) {
  flusspferd::string const a("Test String\n");
  flusspferd::string const b(a);
  BOOST_CHECK( !(a == b) == (a != b) );
  flusspferd::string const c("sth. completly different\n");
  BOOST_CHECK( !(a == c) == (a != c) );
}

BOOST_AUTO_TEST_CASE( op_less ) {
  std::string const ss1 = "aaa";
  std::string const ss2 = "aab";
  flusspferd::string fs1 = ss1;
  flusspferd::string fs2 = ss2;

  BOOST_CHECK( (fs1 < fs2) == (ss1 < ss2) );
  BOOST_CHECK( (fs2 < fs1) == (ss2 < ss1) );
}

BOOST_AUTO_TEST_CASE( string_substr ) {
  std::string const str = "Ba bo bu bi bo bz";
  flusspferd::string s = str;
  BOOST_CHECK_EQUAL(s.substr(3, 5), str.substr(3, 5));
}

BOOST_AUTO_TEST_CASE( string_io ) {
  std::stringstream ss;
  flusspferd::string s("Hallo Welt!");
  ss << s;
  BOOST_CHECK_EQUAL(s.to_string(), ss.str());
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include <config.h>

#include <gtest/gtest.h>
#include <primitiv/error.h>
#include <primitiv/model.h>
#include <primitiv/naive_device.h>
#include <primitiv/parameter.h>
#include <primitiv/trainer_impl.h>
#include <test_utils.h>

using std::vector;
using test_utils::vector_match;

namespace primitiv {

class TrainerTest : public testing::Test {
protected:
  devices::Naive dev;
};

TEST_F(TrainerTest, CheckAddParameter) {
  Device::set_default(dev);
  trainers::SGD trainer;
  Parameter param1({2, 2});
  Parameter param2({2, 2});
  Parameter param3({2, 2});

  EXPECT_NO_THROW(trainer.add_parameter(param1));
  EXPECT_THROW(trainer.add_parameter(param1), Error);

  EXPECT_NO_THROW(trainer.add_parameter(param2));
  EXPECT_THROW(trainer.add_parameter(param1), Error);
  EXPECT_THROW(trainer.add_parameter(param2), Error);

  EXPECT_NO_THROW(trainer.add_parameter(param3));
  EXPECT_THROW(trainer.add_parameter(param1), Error);
  EXPECT_THROW(trainer.add_parameter(param2), Error);
  EXPECT_THROW(trainer.add_parameter(param3), Error);
}

TEST_F(TrainerTest, CheckAddModel) {
  Device::set_default(dev);
  trainers::SGD trainer;
  Model m;
  Parameter param1({2, 2});
  Parameter param2({2, 2});
  Parameter param3({2, 2});
  m.add_parameter("param1", param1);
  m.add_parameter("param2", param2);
  m.add_parameter("param3", param3);

  EXPECT_NO_THROW(trainer.add_model(m));
  EXPECT_THROW(trainer.add_model(m), Error);
  EXPECT_THROW(trainer.add_parameter(param1), Error);
  EXPECT_THROW(trainer.add_parameter(param2), Error);
  EXPECT_THROW(trainer.add_parameter(param3), Error);
}

TEST_F(TrainerTest, CheckEpoch) {
  trainers::SGD trainer;
  ASSERT_EQ(0u, trainer.get_epoch());
  for (unsigned i = 1; i < 10; ++i) {
    trainer.update();
    EXPECT_EQ(i, trainer.get_epoch());
  }
  trainer.set_epoch(0);
  EXPECT_EQ(0u, trainer.get_epoch());
  trainer.set_epoch(100);
  EXPECT_EQ(100u, trainer.get_epoch());
}

TEST_F(TrainerTest, CheckLearningRateScaling) {
  trainers::SGD trainer;
  ASSERT_EQ(1.0f, trainer.get_learning_rate_scaling());

  trainer.set_learning_rate_scaling(.1);
  EXPECT_EQ(.1f, trainer.get_learning_rate_scaling());

  trainer.set_learning_rate_scaling(0);
  EXPECT_EQ(.0f, trainer.get_learning_rate_scaling());

  EXPECT_THROW(trainer.set_learning_rate_scaling(-1), Error);
}

TEST_F(TrainerTest, CheckWeightDecay) {
  Device::set_default(dev);
  trainers::SGD trainer;
  ASSERT_EQ(.0f, trainer.get_weight_decay());

  Parameter param({2, 2});
  trainer.add_parameter(param);

  struct TestCase {
    float strength;
    vector<float> in_value;
    vector<float> in_grad;
    vector<float> out_value;
    vector<float> out_grad;
  };
  const vector<TestCase> test_cases {
    {1, {1, 2, 3, 4}, {0, 0, 0, 0}, {.9, 1.8, 2.7, 3.6}, {1, 2, 3, 4}},
    {.1, {1, 2, 3, 4}, {0, 0, 0, 0}, {.99, 1.98, 2.97, 3.96}, {.1, .2, .3, .4}},
    {0, {1, 2, 3, 4}, {0, 0, 0, 0}, {1, 2, 3, 4}, {0, 0, 0, 0}},
  };

  for (const TestCase &tc : test_cases) {
    trainer.set_weight_decay(tc.strength);
    ASSERT_EQ(tc.strength, trainer.get_weight_decay());

    param.value().reset_by_vector(tc.in_value);
    param.gradient().reset_by_vector(tc.in_grad);
    trainer.update();
    EXPECT_TRUE(vector_match(tc.out_value, param.value().to_vector()));
    EXPECT_TRUE(vector_match(tc.out_grad, param.gradient().to_vector()));
  }

  EXPECT_THROW(trainer.set_weight_decay(-1), Error);
}

TEST_F(TrainerTest, CheckGradientClipping) {
  Device::set_default(dev);
  trainers::SGD trainer;
  ASSERT_EQ(.0f, trainer.get_gradient_clipping());

  Parameter param({2, 2});
  trainer.add_parameter(param);

  struct TestCase {
    float threshold;
    vector<float> in_value;
    vector<float> in_grad;
    vector<float> out_value;
    vector<float> out_grad;
  };
  const vector<TestCase> test_cases {
    {4, {1, 2, 3, 4}, {1, 1, -1, -1}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {4, {1, 2, 3, 4}, {2, 2, -2, -2}, {.8, 1.8, 3.2, 4.2}, {2, 2, -2, -2}},
    {4, {1, 2, 3, 4}, {3, 3, -3, -3}, {.8, 1.8, 3.2, 4.2}, {2, 2, -2, -2}},
    {2, {1, 2, 3, 4}, {1, 1, -1, -1}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {2, {1, 2, 3, 4}, {2, 2, -2, -2}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {2, {1, 2, 3, 4}, {3, 3, -3, -3}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {0, {1, 2, 3, 4}, {1, 1, -1, -1}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {0, {1, 2, 3, 4}, {2, 2, -2, -2}, {.8, 1.8, 3.2, 4.2}, {2, 2, -2, -2}},
    {0, {1, 2, 3, 4}, {3, 3, -3, -3}, {.7, 1.7, 3.3, 4.3}, {3, 3, -3, -3}},
  };

  for (const TestCase &tc : test_cases) {
    trainer.set_gradient_clipping(tc.threshold);
    ASSERT_EQ(tc.threshold, trainer.get_gradient_clipping());

    param.value().reset_by_vector(tc.in_value);
    param.gradient().reset_by_vector(tc.in_grad);
    trainer.update();
    EXPECT_TRUE(vector_match(tc.out_value, param.value().to_vector()));
    EXPECT_TRUE(vector_match(tc.out_grad, param.gradient().to_vector()));
  }

  EXPECT_THROW(trainer.set_gradient_clipping(-1), Error);
}

}  // namespace primitiv
<commit_msg>Add test cases with multiple models in TrainerTest.<commit_after>#include <config.h>

#include <gtest/gtest.h>
#include <primitiv/error.h>
#include <primitiv/model.h>
#include <primitiv/naive_device.h>
#include <primitiv/parameter.h>
#include <primitiv/trainer_impl.h>
#include <test_utils.h>

using std::vector;
using test_utils::vector_match;

namespace primitiv {

class TrainerTest : public testing::Test {
protected:
  devices::Naive dev;
};

TEST_F(TrainerTest, CheckAddParameter) {
  Device::set_default(dev);
  trainers::SGD trainer;
  Parameter param1({2, 2});
  Parameter param2({2, 2});
  Parameter param3({2, 2});

  EXPECT_NO_THROW(trainer.add_parameter(param1));
  EXPECT_THROW(trainer.add_parameter(param1), Error);

  EXPECT_NO_THROW(trainer.add_parameter(param2));
  EXPECT_THROW(trainer.add_parameter(param1), Error);
  EXPECT_THROW(trainer.add_parameter(param2), Error);

  EXPECT_NO_THROW(trainer.add_parameter(param3));
  EXPECT_THROW(trainer.add_parameter(param1), Error);
  EXPECT_THROW(trainer.add_parameter(param2), Error);
  EXPECT_THROW(trainer.add_parameter(param3), Error);
}

TEST_F(TrainerTest, CheckAddModel) {
  Device::set_default(dev);
  trainers::SGD trainer;
  Model m;
  Parameter param1({2, 2});
  Parameter param2({2, 2});
  Parameter param3({2, 2});
  m.add_parameter("param1", param1);
  m.add_parameter("param2", param2);
  m.add_parameter("param3", param3);

  EXPECT_NO_THROW(trainer.add_model(m));
  EXPECT_THROW(trainer.add_model(m), Error);
  EXPECT_THROW(trainer.add_parameter(param1), Error);
  EXPECT_THROW(trainer.add_parameter(param2), Error);
  EXPECT_THROW(trainer.add_parameter(param3), Error);
}

TEST_F(TrainerTest, CheckAddModelWithMultipleModels) {
  Device::set_default(dev);
  trainers::SGD trainer;
  Model m1, m2, m3;
  Parameter param1({2, 2});
  Parameter param2({2, 2});
  Parameter param3({2, 2});
  m1.add_parameter("param1", param1);
  m2.add_parameter("param2", param2);
  m3.add_parameter("param3", param3);

  EXPECT_NO_THROW(trainer.add_model(m1));
  EXPECT_NO_THROW(trainer.add_model(m2));
  EXPECT_NO_THROW(trainer.add_model(m3));
  EXPECT_THROW(trainer.add_model(m1), Error);
  EXPECT_THROW(trainer.add_model(m2), Error);
  EXPECT_THROW(trainer.add_model(m3), Error);
  EXPECT_THROW(trainer.add_parameter(param1), Error);
  EXPECT_THROW(trainer.add_parameter(param2), Error);
  EXPECT_THROW(trainer.add_parameter(param3), Error);
}

TEST_F(TrainerTest, CheckAddModelWithSubmodels) {
  Device::set_default(dev);
  trainers::SGD trainer;
  Model m, sm, ssm;
  Parameter param1({2, 2});
  Parameter param2({2, 2});
  Parameter param3({2, 2});
  m.add_parameter("param1", param1);
  sm.add_parameter("param2", param2);
  ssm.add_parameter("param3", param3);
  m.add_submodel("sm", sm);
  sm.add_submodel("ssm", ssm);

  EXPECT_NO_THROW(trainer.add_model(m));
  EXPECT_THROW(trainer.add_model(m), Error);
  EXPECT_THROW(trainer.add_model(sm), Error);
  EXPECT_THROW(trainer.add_model(ssm), Error);
  EXPECT_THROW(trainer.add_parameter(param1), Error);
  EXPECT_THROW(trainer.add_parameter(param2), Error);
  EXPECT_THROW(trainer.add_parameter(param3), Error);
}

TEST_F(TrainerTest, CheckEpoch) {
  trainers::SGD trainer;
  ASSERT_EQ(0u, trainer.get_epoch());
  for (unsigned i = 1; i < 10; ++i) {
    trainer.update();
    EXPECT_EQ(i, trainer.get_epoch());
  }
  trainer.set_epoch(0);
  EXPECT_EQ(0u, trainer.get_epoch());
  trainer.set_epoch(100);
  EXPECT_EQ(100u, trainer.get_epoch());
}

TEST_F(TrainerTest, CheckLearningRateScaling) {
  trainers::SGD trainer;
  ASSERT_EQ(1.0f, trainer.get_learning_rate_scaling());

  trainer.set_learning_rate_scaling(.1);
  EXPECT_EQ(.1f, trainer.get_learning_rate_scaling());

  trainer.set_learning_rate_scaling(0);
  EXPECT_EQ(.0f, trainer.get_learning_rate_scaling());

  EXPECT_THROW(trainer.set_learning_rate_scaling(-1), Error);
}

TEST_F(TrainerTest, CheckWeightDecay) {
  Device::set_default(dev);
  trainers::SGD trainer;
  ASSERT_EQ(.0f, trainer.get_weight_decay());

  Parameter param({2, 2});
  trainer.add_parameter(param);

  struct TestCase {
    float strength;
    vector<float> in_value;
    vector<float> in_grad;
    vector<float> out_value;
    vector<float> out_grad;
  };
  const vector<TestCase> test_cases {
    {1, {1, 2, 3, 4}, {0, 0, 0, 0}, {.9, 1.8, 2.7, 3.6}, {1, 2, 3, 4}},
    {.1, {1, 2, 3, 4}, {0, 0, 0, 0}, {.99, 1.98, 2.97, 3.96}, {.1, .2, .3, .4}},
    {0, {1, 2, 3, 4}, {0, 0, 0, 0}, {1, 2, 3, 4}, {0, 0, 0, 0}},
  };

  for (const TestCase &tc : test_cases) {
    trainer.set_weight_decay(tc.strength);
    ASSERT_EQ(tc.strength, trainer.get_weight_decay());

    param.value().reset_by_vector(tc.in_value);
    param.gradient().reset_by_vector(tc.in_grad);
    trainer.update();
    EXPECT_TRUE(vector_match(tc.out_value, param.value().to_vector()));
    EXPECT_TRUE(vector_match(tc.out_grad, param.gradient().to_vector()));
  }

  EXPECT_THROW(trainer.set_weight_decay(-1), Error);
}

TEST_F(TrainerTest, CheckGradientClipping) {
  Device::set_default(dev);
  trainers::SGD trainer;
  ASSERT_EQ(.0f, trainer.get_gradient_clipping());

  Parameter param({2, 2});
  trainer.add_parameter(param);

  struct TestCase {
    float threshold;
    vector<float> in_value;
    vector<float> in_grad;
    vector<float> out_value;
    vector<float> out_grad;
  };
  const vector<TestCase> test_cases {
    {4, {1, 2, 3, 4}, {1, 1, -1, -1}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {4, {1, 2, 3, 4}, {2, 2, -2, -2}, {.8, 1.8, 3.2, 4.2}, {2, 2, -2, -2}},
    {4, {1, 2, 3, 4}, {3, 3, -3, -3}, {.8, 1.8, 3.2, 4.2}, {2, 2, -2, -2}},
    {2, {1, 2, 3, 4}, {1, 1, -1, -1}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {2, {1, 2, 3, 4}, {2, 2, -2, -2}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {2, {1, 2, 3, 4}, {3, 3, -3, -3}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {0, {1, 2, 3, 4}, {1, 1, -1, -1}, {.9, 1.9, 3.1, 4.1}, {1, 1, -1, -1}},
    {0, {1, 2, 3, 4}, {2, 2, -2, -2}, {.8, 1.8, 3.2, 4.2}, {2, 2, -2, -2}},
    {0, {1, 2, 3, 4}, {3, 3, -3, -3}, {.7, 1.7, 3.3, 4.3}, {3, 3, -3, -3}},
  };

  for (const TestCase &tc : test_cases) {
    trainer.set_gradient_clipping(tc.threshold);
    ASSERT_EQ(tc.threshold, trainer.get_gradient_clipping());

    param.value().reset_by_vector(tc.in_value);
    param.gradient().reset_by_vector(tc.in_grad);
    trainer.update();
    EXPECT_TRUE(vector_match(tc.out_value, param.value().to_vector()));
    EXPECT_TRUE(vector_match(tc.out_grad, param.gradient().to_vector()));
  }

  EXPECT_THROW(trainer.set_gradient_clipping(-1), Error);
}

}  // namespace primitiv
<|endoftext|>


<commit_before>/* Copyright (C) 2011 by Massimo Gengarelli <massimo.gengarelli@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "SPlot.h"

#include <QtGui>
#include <QtCore>
#include <vector>

namespace Graphics {

SPlot::~SPlot() {

}

void SPlot::dragEnterEvent(QDragEnterEvent *event) {
	if (event->mimeData()->urls().isEmpty())
		return;

	foreach(QUrl url, event->mimeData()->urls()) {
		if (QFileInfo(url.toLocalFile()).suffix().toLower() == "sns") {
			event->acceptProposedAction();
			return;
		}
	}
}

void SPlot::dropEvent(QDropEvent *event) {
	if (event->mimeData()->urls().isEmpty())
		return;

	std::vector<std::pair<double, double> > *newCoords = new std::vector<std::pair<double, double> >();

	foreach(QUrl url, event->mimeData()->urls()) {
		QFileInfo fileInfo(url.toLocalFile());

		if (fileInfo.suffix().toLower() == "sns") {
			QFile file(url.toLocalFile());
			if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
				QTextStream stream(&file);

				/* Parse the file */
				while (!stream.atEnd()) {
					QString read = stream.readLine();
					QStringList coords = read.split(':');

					if (coords.size() != 2)
						continue;

					bool result_x, result_y;
					double x, y;

					x = coords.first().toDouble(&result_x);
					y = coords.last().toDouble(&result_y);

					if (result_x && result_y)
						newCoords->push_back(std::pair<double, double>(x, y));
				}

				file.close();
			}

		}
	}

	emit DropAccepted(newCoords);
	return;
}

}
<commit_msg>Ignore comments on sns files<commit_after>/* Copyright (C) 2011 by Massimo Gengarelli <massimo.gengarelli@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "SPlot.h"

#include <QtGui>
#include <QtCore>
#include <vector>

namespace Graphics {

SPlot::~SPlot() {

}

void SPlot::dragEnterEvent(QDragEnterEvent *event) {
	if (event->mimeData()->urls().isEmpty())
		return;

	foreach(QUrl url, event->mimeData()->urls()) {
		if (QFileInfo(url.toLocalFile()).suffix().toLower() == "sns") {
			event->acceptProposedAction();
			return;
		}
	}
}

void SPlot::dropEvent(QDropEvent *event) {
	if (event->mimeData()->urls().isEmpty())
		return;

	std::vector<std::pair<double, double> > *newCoords = new std::vector<std::pair<double, double> >();

	foreach(QUrl url, event->mimeData()->urls()) {
		QFileInfo fileInfo(url.toLocalFile());

		if (fileInfo.suffix().toLower() == "sns") {
			QFile file(url.toLocalFile());
			if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
				QTextStream stream(&file);

				/* Parse the file */
				while (!stream.atEnd()) {
					QString read = stream.readLine();
					if (read.startsWith('#'))
						continue;
					QStringList coords = read.split(':');

					if (coords.size() != 2)
						continue;

					bool result_x, result_y;
					double x, y;

					x = coords.first().toDouble(&result_x);
					y = coords.last().toDouble(&result_y);

					if (result_x && result_y)
						newCoords->push_back(std::pair<double, double>(x, y));
				}

				file.close();
			}

		}
	}

	emit DropAccepted(newCoords);
	return;
}

}
<|endoftext|>


<commit_before>#ifndef _SDD_DD_DEFINITION_HH_
#define _SDD_DD_DEFINITION_HH_

#include <initializer_list>
#include <type_traits> // is_integral

#include "sdd/dd/alpha.hh"
#include "sdd/dd/definition_fwd.hh"
#include "sdd/dd/node.hh"
#include "sdd/dd/terminal.hh"
#include "sdd/mem/ptr.hh"
#include "sdd/mem/ref_counted.hh"
#include "sdd/mem/variant.hh"
#include "sdd/order/order.hh"
#include "sdd/util/print_sizes_fwd.hh"

namespace sdd {

/*------------------------------------------------------------------------------------------------*/

/// @brief SDD at the deepest level.
template <typename C>
using flat_node = node<C, typename C::Values>;

/// @brief All but SDD at the deepest level.
template <typename C>
using hierarchical_node = node<C, SDD<C>>;

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Tag to describe the type of a node.
enum class node_tag {flat, hierarchical};

/// @internal
/// @brief Signature of the meta-function that returns the node's type corresponding to the
/// given tag.
template <typename C, enum node_tag>
struct node_for_tag;

/// @internal
/// @brief Specialization for flat node.
template <typename C>
struct node_for_tag<C, node_tag::flat>
{
  typedef flat_node<C> type;
};

/// @internal
/// @brief Specialization for hierarchical node.
template <typename C>
struct node_for_tag<C, node_tag::hierarchical>
{
  typedef hierarchical_node<C> type;
};

/*------------------------------------------------------------------------------------------------*/

/// @brief Hierarchical Set Decision Diagram.
template <typename C>
class SDD final
{

  static_assert( std::is_integral<typename C::Variable>::value
               , "A variable must be an integral type.");

private:

  /// @brief A canonized SDD.
  ///
  /// This is the real recursive definition of an SDD: it can be a |0| or |1| terminal, or it
  /// can be a flat or an hierachical node.
  typedef mem::variant<zero_terminal<C>, one_terminal<C>, flat_node<C>,hierarchical_node<C>>
          data_type;

public:

  /// @internal
  /// @brief A unified and canonized SDD, meant to be stored in a unique table.
  ///
  /// It is automatically erased when there is no more reference to it.
  typedef mem::ref_counted<data_type> unique_type;

  /// @internal
  /// @brief The type of the smart pointer around a unified SDD.
  ///
  /// It handles the reference counting as well as the deletion of the SDD when it is no longer
  /// referenced.
  typedef mem::ptr<unique_type> ptr_type;

  /// @brief The type of variables.
  typedef typename C::Variable variable_type;

  /// @brief The type of a set of values.
  typedef typename C::Values values_type;

  /// @brief The type of a value in a set of values.
  typedef typename C::Values::value_type value_type;

private:

  /// @brief The real smart pointer around a unified SDD.
  ptr_type ptr_;

public:

  /// @brief Copy constructor.
  ///
  /// O(1).
  SDD(const SDD&) noexcept = default;

  /// @brief Copy operator.
  ///
  /// O(1).
  SDD&
  operator=(const SDD&) noexcept = default;

  /// @brief Construct a hierarchical SDD.
  /// @param var  The SDD's variable.
  /// @param values  The SDD's valuation, a set of values constructed from an initialization list.
  /// @param succ The SDD's successor.
  ///
  /// O(1), for the creation of the SDD itself, but the complexity of the construction of the
  /// set of values depends on values_type.
  SDD(const variable_type& var, std::initializer_list<value_type> values, const SDD& succ)
    : ptr_(create_node(var, values_type(values), SDD(succ)))
  {}

  /// @brief Construct a flat SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, values_type&& val, const SDD& succ)
    : ptr_(create_node(var, std::move(val), succ))
  {}

  /// @brief Construct a flat SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, const values_type& val, const SDD& succ)
    : ptr_(create_node(var, val, succ))
  {}

  /// @brief Construct a hierarchical SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, an SDD in this case.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, const SDD& val, const SDD& succ)
    : ptr_(create_node(var, val, succ))
  {}

  /// @brief Construct an SDD with an order.
  template <typename Initializer>
  SDD(const order<C>& o, const Initializer& init)
    : ptr_(one_ptr())
  {
    if (o.empty())
    {
      return;
    }
    // flat
    else if (o.nested().empty())
    {
      ptr_ = create_node(o.variable(), init(o.identifier()), SDD(o.next(), init));
    }
    // hierarchical
    else
    {
      ptr_ = create_node(o.variable(), SDD(o.nested(), init), SDD(o.next(), init));
    }
  }

  /// @brief Indicate if the SDD is |0|.
  /// @return true if the SDD is |0|, false otherwise.
  ///
  /// O(1).
  bool
  empty()
  const noexcept
  {
    return ptr_ == zero_ptr();
  }

  /// @brief Swap two SDD.
  ///
  /// O(1).
  friend void
  swap(SDD& lhs, SDD& rhs)
  noexcept
  {
    using std::swap;
    swap(lhs.ptr_, rhs.ptr_);
  }

  /// @internal
  /// @brief Construct an SDD from a ptr.
  ///
  /// O(1).
  SDD(const ptr_type& ptr)
  noexcept
    : ptr_(ptr)
  {}

  /// @internal
  /// @brief  Construct an SDD, flat or hierarchical, with an alpha.
  /// \tparam Valuation If an SDD, constructs a hierarchical SDD; if a set of values,
  /// constructs a flat SDD.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  SDD(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
    : ptr_(create_node(var, std::move(builder)))
  {}

  /// @internal
  /// @brief Get the content of the SDD (an mem::ref_counted).
  ///
  /// O(1).
  const unique_type&
  operator*()
  const noexcept
  {
    return *ptr_;
  }

  /// @internal
  /// @brief Get a pointer to the content of the SDD (an mem::ref_counted).
  ///
  /// O(1).
  const unique_type*
  operator->()
  const noexcept
  {
    return ptr_.operator->();
  }

  /// @internal
  /// @brief Get the real smart pointer of the unified data.
  ///
  /// O(1).
  ptr_type
  ptr()
  const noexcept
  {
    return ptr_;
  }

  /// @internal
  /// @brief Return the globally cached |0| terminal.
  ///
  /// O(1).
  static
  ptr_type
  zero_ptr()
  {
    return global<C>().zero;
  }

  /// @internal
  /// @brief Return the globally cached |1| terminal.
  ///
  /// O(1).
  static
  ptr_type
  one_ptr()
  {
    return global<C>().one;
  }

private:

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, with only one arc.
  ///
  /// O(1).
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, Valuation&& val, const SDD& succ)
  {
    if (succ.empty() or val.empty())
    {
      return zero_ptr();
    }
    else
    {
      dd::alpha_builder<C, Valuation> builder;
      builder.add(std::move(val), succ);
      return ptr_type(unify_node<Valuation>(var, std::move(builder)));
    }
  }

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, with only one arc.
  ///
  /// O(1).
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, const Valuation& val, const SDD& succ)
  {
    if (succ.empty() or val.empty())
    {
      return zero_ptr();
    }
    else
    {
      dd::alpha_builder<C, Valuation> builder;
      builder.add(val, succ);
      return ptr_type(unify_node<Valuation>(var, std::move(builder)));
    }
  }

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, from an alpha.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
  {
    if (builder.empty())
    {
      return zero_ptr();
    }
    else
    {
      return ptr_type(unify_node<Valuation>(var, std::move(builder)));
    }
  }

  /// @internal
  /// @brief Helper function to unify a node, flat or hierarchical, from an alpha.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  static
  unique_type&
  unify_node(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
  {
    // Will be erased by the unicity table, either it's an already existing node or a deletion
    // is requested by ptr.
    // Note that the alpha function is allocated right behind the node, thus extra care must be
    // taken. This is also why we use Boost.Intrusive in order to be able to manage memory
    // exactly the way we want.
    auto& ut = global<C>().sdd_unique_table;
    char* addr = ut.allocate(builder.size_to_allocate());
    unique_type* u =
      new (addr) unique_type(mem::construct<node<C, Valuation>>(), var, builder);
    return ut(u);
  }

  friend void util::print_sizes<C>(std::ostream&);
};

/*------------------------------------------------------------------------------------------------*/

/// @brief   Equality of two SDD.
/// @related SDD
///
/// O(1).
template <typename C>
inline
bool
operator==(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return lhs.ptr() == rhs.ptr();
}

/// @brief   Inequality of two SDD.
/// @related SDD
///
/// O(1).
template <typename C>
inline
bool
operator!=(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return not (lhs.ptr() == rhs.ptr());
}

/// @brief   Comparison of two SDD.
/// @related SDD
///
/// O(1). The order of SDD is arbitrary and can change at each run.
template <typename C>
inline
bool
operator<(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return lhs.ptr() < rhs.ptr();
}

/// @brief   Export the textual representation of an SDD to a stream.
/// @related SDD
///
/// Use only with small SDD, output can be huge.
template <typename C>
std::ostream&
operator<<(std::ostream& os, const SDD<C>& x)
{
  return os << x->data();
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Return the |0| terminal.
/// @related SDD
///
/// O(1).
template <typename C>
inline
SDD<C>
zero()
noexcept
{
  return {SDD<C>::zero_ptr()};
}

/// @brief Return the |1| terminal.
/// @related SDD
///
/// O(1).
template <typename C>
inline
SDD<C>
one()
noexcept
{
  return {SDD<C>::one_ptr()};
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @brief Hash specialization for sdd::dd::SDD.
template <typename C>
struct hash<sdd::SDD<C>>
{
  std::size_t
  operator()(const sdd::SDD<C>& x)
  const noexcept
  {
    return std::hash<decltype(x.ptr())>()(x.ptr());
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_DD_DEFINITION_HH_
<commit_msg>noexcept specifications when getting zero and one ptrs.<commit_after>#ifndef _SDD_DD_DEFINITION_HH_
#define _SDD_DD_DEFINITION_HH_

#include <initializer_list>
#include <type_traits> // is_integral

#include "sdd/dd/alpha.hh"
#include "sdd/dd/definition_fwd.hh"
#include "sdd/dd/node.hh"
#include "sdd/dd/terminal.hh"
#include "sdd/mem/ptr.hh"
#include "sdd/mem/ref_counted.hh"
#include "sdd/mem/variant.hh"
#include "sdd/order/order.hh"
#include "sdd/util/print_sizes_fwd.hh"

namespace sdd {

/*------------------------------------------------------------------------------------------------*/

/// @brief SDD at the deepest level.
template <typename C>
using flat_node = node<C, typename C::Values>;

/// @brief All but SDD at the deepest level.
template <typename C>
using hierarchical_node = node<C, SDD<C>>;

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Tag to describe the type of a node.
enum class node_tag {flat, hierarchical};

/// @internal
/// @brief Signature of the meta-function that returns the node's type corresponding to the
/// given tag.
template <typename C, enum node_tag>
struct node_for_tag;

/// @internal
/// @brief Specialization for flat node.
template <typename C>
struct node_for_tag<C, node_tag::flat>
{
  typedef flat_node<C> type;
};

/// @internal
/// @brief Specialization for hierarchical node.
template <typename C>
struct node_for_tag<C, node_tag::hierarchical>
{
  typedef hierarchical_node<C> type;
};

/*------------------------------------------------------------------------------------------------*/

/// @brief Hierarchical Set Decision Diagram.
template <typename C>
class SDD final
{

  static_assert( std::is_integral<typename C::Variable>::value
               , "A variable must be an integral type.");

private:

  /// @brief A canonized SDD.
  ///
  /// This is the real recursive definition of an SDD: it can be a |0| or |1| terminal, or it
  /// can be a flat or an hierachical node.
  typedef mem::variant<zero_terminal<C>, one_terminal<C>, flat_node<C>,hierarchical_node<C>>
          data_type;

public:

  /// @internal
  /// @brief A unified and canonized SDD, meant to be stored in a unique table.
  ///
  /// It is automatically erased when there is no more reference to it.
  typedef mem::ref_counted<data_type> unique_type;

  /// @internal
  /// @brief The type of the smart pointer around a unified SDD.
  ///
  /// It handles the reference counting as well as the deletion of the SDD when it is no longer
  /// referenced.
  typedef mem::ptr<unique_type> ptr_type;

  /// @brief The type of variables.
  typedef typename C::Variable variable_type;

  /// @brief The type of a set of values.
  typedef typename C::Values values_type;

  /// @brief The type of a value in a set of values.
  typedef typename C::Values::value_type value_type;

private:

  /// @brief The real smart pointer around a unified SDD.
  ptr_type ptr_;

public:

  /// @brief Copy constructor.
  ///
  /// O(1).
  SDD(const SDD&) noexcept = default;

  /// @brief Copy operator.
  ///
  /// O(1).
  SDD&
  operator=(const SDD&) noexcept = default;

  /// @brief Construct a hierarchical SDD.
  /// @param var  The SDD's variable.
  /// @param values  The SDD's valuation, a set of values constructed from an initialization list.
  /// @param succ The SDD's successor.
  ///
  /// O(1), for the creation of the SDD itself, but the complexity of the construction of the
  /// set of values depends on values_type.
  SDD(const variable_type& var, std::initializer_list<value_type> values, const SDD& succ)
    : ptr_(create_node(var, values_type(values), SDD(succ)))
  {}

  /// @brief Construct a flat SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, values_type&& val, const SDD& succ)
    : ptr_(create_node(var, std::move(val), succ))
  {}

  /// @brief Construct a flat SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, a set of values.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, const values_type& val, const SDD& succ)
    : ptr_(create_node(var, val, succ))
  {}

  /// @brief Construct a hierarchical SDD.
  /// @param var  The SDD's variable.
  /// @param val  The SDD's valuation, an SDD in this case.
  /// @param succ The SDD's successor.
  ///
  /// O(1).
  SDD(const variable_type& var, const SDD& val, const SDD& succ)
    : ptr_(create_node(var, val, succ))
  {}

  /// @brief Construct an SDD with an order.
  template <typename Initializer>
  SDD(const order<C>& o, const Initializer& init)
    : ptr_(one_ptr())
  {
    if (o.empty())
    {
      return;
    }
    // flat
    else if (o.nested().empty())
    {
      ptr_ = create_node(o.variable(), init(o.identifier()), SDD(o.next(), init));
    }
    // hierarchical
    else
    {
      ptr_ = create_node(o.variable(), SDD(o.nested(), init), SDD(o.next(), init));
    }
  }

  /// @brief Indicate if the SDD is |0|.
  /// @return true if the SDD is |0|, false otherwise.
  ///
  /// O(1).
  bool
  empty()
  const noexcept
  {
    return ptr_ == zero_ptr();
  }

  /// @brief Swap two SDD.
  ///
  /// O(1).
  friend void
  swap(SDD& lhs, SDD& rhs)
  noexcept
  {
    using std::swap;
    swap(lhs.ptr_, rhs.ptr_);
  }

  /// @internal
  /// @brief Construct an SDD from a ptr.
  ///
  /// O(1).
  SDD(const ptr_type& ptr)
  noexcept
    : ptr_(ptr)
  {}

  /// @internal
  /// @brief  Construct an SDD, flat or hierarchical, with an alpha.
  /// \tparam Valuation If an SDD, constructs a hierarchical SDD; if a set of values,
  /// constructs a flat SDD.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  SDD(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
    : ptr_(create_node(var, std::move(builder)))
  {}

  /// @internal
  /// @brief Get the content of the SDD (an mem::ref_counted).
  ///
  /// O(1).
  const unique_type&
  operator*()
  const noexcept
  {
    return *ptr_;
  }

  /// @internal
  /// @brief Get a pointer to the content of the SDD (an mem::ref_counted).
  ///
  /// O(1).
  const unique_type*
  operator->()
  const noexcept
  {
    return ptr_.operator->();
  }

  /// @internal
  /// @brief Get the real smart pointer of the unified data.
  ///
  /// O(1).
  ptr_type
  ptr()
  const noexcept
  {
    return ptr_;
  }

  /// @internal
  /// @brief Return the globally cached |0| terminal.
  ///
  /// O(1).
  static
  ptr_type
  zero_ptr()
  noexcept
  {
    return global<C>().zero;
  }

  /// @internal
  /// @brief Return the globally cached |1| terminal.
  ///
  /// O(1).
  static
  ptr_type
  one_ptr()
  noexcept
  {
    return global<C>().one;
  }

private:

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, with only one arc.
  ///
  /// O(1).
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, Valuation&& val, const SDD& succ)
  {
    if (succ.empty() or val.empty())
    {
      return zero_ptr();
    }
    else
    {
      dd::alpha_builder<C, Valuation> builder;
      builder.add(std::move(val), succ);
      return ptr_type(unify_node<Valuation>(var, std::move(builder)));
    }
  }

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, with only one arc.
  ///
  /// O(1).
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, const Valuation& val, const SDD& succ)
  {
    if (succ.empty() or val.empty())
    {
      return zero_ptr();
    }
    else
    {
      dd::alpha_builder<C, Valuation> builder;
      builder.add(val, succ);
      return ptr_type(unify_node<Valuation>(var, std::move(builder)));
    }
  }

  /// @internal
  /// @brief Helper function to create a node, flat or hierarchical, from an alpha.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  static
  ptr_type
  create_node(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
  {
    if (builder.empty())
    {
      return zero_ptr();
    }
    else
    {
      return ptr_type(unify_node<Valuation>(var, std::move(builder)));
    }
  }

  /// @internal
  /// @brief Helper function to unify a node, flat or hierarchical, from an alpha.
  ///
  /// O(n) where n is the number of arcs in the builder.
  template <typename Valuation>
  static
  unique_type&
  unify_node(const variable_type& var, dd::alpha_builder<C, Valuation>&& builder)
  {
    // Will be erased by the unicity table, either it's an already existing node or a deletion
    // is requested by ptr.
    // Note that the alpha function is allocated right behind the node, thus extra care must be
    // taken. This is also why we use Boost.Intrusive in order to be able to manage memory
    // exactly the way we want.
    auto& ut = global<C>().sdd_unique_table;
    char* addr = ut.allocate(builder.size_to_allocate());
    unique_type* u =
      new (addr) unique_type(mem::construct<node<C, Valuation>>(), var, builder);
    return ut(u);
  }

  friend void util::print_sizes<C>(std::ostream&);
};

/*------------------------------------------------------------------------------------------------*/

/// @brief   Equality of two SDD.
/// @related SDD
///
/// O(1).
template <typename C>
inline
bool
operator==(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return lhs.ptr() == rhs.ptr();
}

/// @brief   Inequality of two SDD.
/// @related SDD
///
/// O(1).
template <typename C>
inline
bool
operator!=(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return not (lhs.ptr() == rhs.ptr());
}

/// @brief   Comparison of two SDD.
/// @related SDD
///
/// O(1). The order of SDD is arbitrary and can change at each run.
template <typename C>
inline
bool
operator<(const SDD<C>& lhs, const SDD<C>& rhs)
noexcept
{
  return lhs.ptr() < rhs.ptr();
}

/// @brief   Export the textual representation of an SDD to a stream.
/// @related SDD
///
/// Use only with small SDD, output can be huge.
template <typename C>
std::ostream&
operator<<(std::ostream& os, const SDD<C>& x)
{
  return os << x->data();
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Return the |0| terminal.
/// @related SDD
///
/// O(1).
template <typename C>
inline
SDD<C>
zero()
noexcept
{
  return {SDD<C>::zero_ptr()};
}

/// @brief Return the |1| terminal.
/// @related SDD
///
/// O(1).
template <typename C>
inline
SDD<C>
one()
noexcept
{
  return {SDD<C>::one_ptr()};
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @brief Hash specialization for sdd::dd::SDD.
template <typename C>
struct hash<sdd::SDD<C>>
{
  std::size_t
  operator()(const sdd::SDD<C>& x)
  const noexcept
  {
    return std::hash<decltype(x.ptr())>()(x.ptr());
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_DD_DEFINITION_HH_
<|endoftext|>


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

#include "remoting/client/chromoting_client.h"

#include "base/bind.h"
#include "remoting/client/chromoting_view.h"
#include "remoting/client/client_context.h"
#include "remoting/client/input_handler.h"
#include "remoting/client/rectangle_update_decoder.h"
#include "remoting/protocol/connection_to_host.h"
#include "remoting/protocol/session_config.h"

namespace remoting {

ChromotingClient::QueuedVideoPacket::QueuedVideoPacket(
    const VideoPacket* packet, const base::Closure& done)
    : packet(packet), done(done) {
}

ChromotingClient::QueuedVideoPacket::~QueuedVideoPacket() {
}

ChromotingClient::ChromotingClient(const ClientConfig& config,
                                   ClientContext* context,
                                   protocol::ConnectionToHost* connection,
                                   ChromotingView* view,
                                   RectangleUpdateDecoder* rectangle_decoder,
                                   InputHandler* input_handler,
                                   Task* client_done)
    : config_(config),
      context_(context),
      connection_(connection),
      view_(view),
      rectangle_decoder_(rectangle_decoder),
      input_handler_(input_handler),
      client_done_(client_done),
      packet_being_processed_(false),
      last_sequence_number_(0),
      thread_proxy_(context_->network_message_loop()) {
}

ChromotingClient::~ChromotingClient() {
}

void ChromotingClient::Start(scoped_refptr<XmppProxy> xmpp_proxy) {
  DCHECK(message_loop()->BelongsToCurrentThread());

  connection_->Connect(xmpp_proxy, config_.local_jid, config_.host_jid,
                       config_.host_public_key, config_.access_code,
                       this, this, this);

  if (!view_->Initialize()) {
    ClientDone();
  }
}

void ChromotingClient::Stop(const base::Closure& shutdown_task) {
  if (!message_loop()->BelongsToCurrentThread()) {
    message_loop()->PostTask(
        FROM_HERE, base::Bind(&ChromotingClient::Stop,
                              base::Unretained(this), shutdown_task));
    return;
  }

  connection_->Disconnect(base::Bind(&ChromotingClient::OnDisconnected,
                                     base::Unretained(this), shutdown_task));
}

void ChromotingClient::OnDisconnected(const base::Closure& shutdown_task) {
  view_->TearDown();

  shutdown_task.Run();
}

void ChromotingClient::ClientDone() {
  if (client_done_ != NULL) {
    message_loop()->PostTask(FROM_HERE, client_done_);
  }
}

ChromotingStats* ChromotingClient::GetStats() {
  return &stats_;
}

void ChromotingClient::Repaint() {
  DCHECK(message_loop()->BelongsToCurrentThread());
  view_->Paint();
}

void ChromotingClient::ProcessVideoPacket(const VideoPacket* packet,
                                          const base::Closure& done) {
  DCHECK(message_loop()->BelongsToCurrentThread());

  // If the video packet is empty then drop it. Empty packets are used to
  // maintain activity on the network.
  if (!packet->has_data() || packet->data().size() == 0) {
    done.Run();
    return;
  }

  // Add one frame to the counter.
  stats_.video_frame_rate()->Record(1);

  // Record other statistics received from host.
  stats_.video_bandwidth()->Record(packet->data().size());
  if (packet->has_capture_time_ms())
    stats_.video_capture_ms()->Record(packet->capture_time_ms());
  if (packet->has_encode_time_ms())
    stats_.video_encode_ms()->Record(packet->encode_time_ms());
  if (packet->has_client_sequence_number() &&
      packet->client_sequence_number() > last_sequence_number_) {
    last_sequence_number_ = packet->client_sequence_number();
    base::TimeDelta round_trip_latency =
        base::Time::Now() -
        base::Time::FromInternalValue(packet->client_sequence_number());
    stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds());
  }

  received_packets_.push_back(QueuedVideoPacket(packet, done));
  if (!packet_being_processed_)
    DispatchPacket();
}

int ChromotingClient::GetPendingPackets() {
  return received_packets_.size();
}

void ChromotingClient::DispatchPacket() {
  DCHECK(message_loop()->BelongsToCurrentThread());
  CHECK(!packet_being_processed_);

  if (received_packets_.empty()) {
    // Nothing to do!
    return;
  }

  const VideoPacket* packet = received_packets_.front().packet;
  packet_being_processed_ = true;

  // Measure the latency between the last packet being received and presented.
  bool last_packet = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
  base::Time decode_start;
  if (last_packet)
    decode_start = base::Time::Now();

  rectangle_decoder_->DecodePacket(
      packet, NewRunnableMethod(this, &ChromotingClient::OnPacketDone,
                                last_packet, decode_start));
}

void ChromotingClient::OnConnectionState(
    protocol::ConnectionToHost::State state,
    protocol::ConnectionToHost::Error error) {
  DCHECK(message_loop()->BelongsToCurrentThread());
  VLOG(1) << "ChromotingClient::OnConnectionState(" << state << ")";
  if (state == protocol::ConnectionToHost::CONNECTED ||
      state == protocol::ConnectionToHost::AUTHENTICATED)
    Initialize();
  view_->SetConnectionState(state, error);
}

base::MessageLoopProxy* ChromotingClient::message_loop() {
  return context_->network_message_loop();
}

void ChromotingClient::OnPacketDone(bool last_packet,
                                    base::Time decode_start) {
  if (!message_loop()->BelongsToCurrentThread()) {
    thread_proxy_.PostTask(FROM_HERE, base::Bind(
        &ChromotingClient::OnPacketDone, base::Unretained(this),
        last_packet, decode_start));
    return;
  }

  // Record the latency between the final packet being received and
  // presented.
  if (last_packet) {
    stats_.video_decode_ms()->Record(
        (base::Time::Now() - decode_start).InMilliseconds());
  }

  received_packets_.front().done.Run();
  received_packets_.pop_front();

  packet_being_processed_ = false;

  // Process the next video packet.
  DispatchPacket();
}

void ChromotingClient::Initialize() {
  if (!message_loop()->BelongsToCurrentThread()) {
    thread_proxy_.PostTask(FROM_HERE, base::Bind(
        &ChromotingClient::Initialize, base::Unretained(this)));
    return;
  }

  // Initialize the decoder.
  rectangle_decoder_->Initialize(connection_->config());

  // Schedule the input handler to process the event queue.
  input_handler_->Initialize();
}

}  // namespace remoting
<commit_msg>Fix intermittent CHECK in remoting client when shutting down.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/client/chromoting_client.h"

#include "base/bind.h"
#include "remoting/client/chromoting_view.h"
#include "remoting/client/client_context.h"
#include "remoting/client/input_handler.h"
#include "remoting/client/rectangle_update_decoder.h"
#include "remoting/protocol/connection_to_host.h"
#include "remoting/protocol/session_config.h"

namespace remoting {

ChromotingClient::QueuedVideoPacket::QueuedVideoPacket(
    const VideoPacket* packet, const base::Closure& done)
    : packet(packet), done(done) {
}

ChromotingClient::QueuedVideoPacket::~QueuedVideoPacket() {
}

ChromotingClient::ChromotingClient(const ClientConfig& config,
                                   ClientContext* context,
                                   protocol::ConnectionToHost* connection,
                                   ChromotingView* view,
                                   RectangleUpdateDecoder* rectangle_decoder,
                                   InputHandler* input_handler,
                                   Task* client_done)
    : config_(config),
      context_(context),
      connection_(connection),
      view_(view),
      rectangle_decoder_(rectangle_decoder),
      input_handler_(input_handler),
      client_done_(client_done),
      packet_being_processed_(false),
      last_sequence_number_(0),
      thread_proxy_(context_->network_message_loop()) {
}

ChromotingClient::~ChromotingClient() {
}

void ChromotingClient::Start(scoped_refptr<XmppProxy> xmpp_proxy) {
  DCHECK(message_loop()->BelongsToCurrentThread());

  connection_->Connect(xmpp_proxy, config_.local_jid, config_.host_jid,
                       config_.host_public_key, config_.access_code,
                       this, this, this);

  if (!view_->Initialize()) {
    ClientDone();
  }
}

void ChromotingClient::Stop(const base::Closure& shutdown_task) {
  if (!message_loop()->BelongsToCurrentThread()) {
    message_loop()->PostTask(
        FROM_HERE, base::Bind(&ChromotingClient::Stop,
                              base::Unretained(this), shutdown_task));
    return;
  }

  // Drop all pending packets.
  while(!received_packets_.empty()) {
    received_packets_.front().done.Run();
    received_packets_.pop_front();
  }

  connection_->Disconnect(base::Bind(&ChromotingClient::OnDisconnected,
                                     base::Unretained(this), shutdown_task));
}

void ChromotingClient::OnDisconnected(const base::Closure& shutdown_task) {
  view_->TearDown();

  shutdown_task.Run();
}

void ChromotingClient::ClientDone() {
  if (client_done_ != NULL) {
    message_loop()->PostTask(FROM_HERE, client_done_);
  }
}

ChromotingStats* ChromotingClient::GetStats() {
  return &stats_;
}

void ChromotingClient::Repaint() {
  DCHECK(message_loop()->BelongsToCurrentThread());
  view_->Paint();
}

void ChromotingClient::ProcessVideoPacket(const VideoPacket* packet,
                                          const base::Closure& done) {
  DCHECK(message_loop()->BelongsToCurrentThread());

  // If the video packet is empty then drop it. Empty packets are used to
  // maintain activity on the network.
  if (!packet->has_data() || packet->data().size() == 0) {
    done.Run();
    return;
  }

  // Add one frame to the counter.
  stats_.video_frame_rate()->Record(1);

  // Record other statistics received from host.
  stats_.video_bandwidth()->Record(packet->data().size());
  if (packet->has_capture_time_ms())
    stats_.video_capture_ms()->Record(packet->capture_time_ms());
  if (packet->has_encode_time_ms())
    stats_.video_encode_ms()->Record(packet->encode_time_ms());
  if (packet->has_client_sequence_number() &&
      packet->client_sequence_number() > last_sequence_number_) {
    last_sequence_number_ = packet->client_sequence_number();
    base::TimeDelta round_trip_latency =
        base::Time::Now() -
        base::Time::FromInternalValue(packet->client_sequence_number());
    stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds());
  }

  received_packets_.push_back(QueuedVideoPacket(packet, done));
  if (!packet_being_processed_)
    DispatchPacket();
}

int ChromotingClient::GetPendingPackets() {
  return received_packets_.size();
}

void ChromotingClient::DispatchPacket() {
  DCHECK(message_loop()->BelongsToCurrentThread());
  CHECK(!packet_being_processed_);

  if (received_packets_.empty()) {
    // Nothing to do!
    return;
  }

  const VideoPacket* packet = received_packets_.front().packet;
  packet_being_processed_ = true;

  // Measure the latency between the last packet being received and presented.
  bool last_packet = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
  base::Time decode_start;
  if (last_packet)
    decode_start = base::Time::Now();

  rectangle_decoder_->DecodePacket(
      packet, NewRunnableMethod(this, &ChromotingClient::OnPacketDone,
                                last_packet, decode_start));
}

void ChromotingClient::OnConnectionState(
    protocol::ConnectionToHost::State state,
    protocol::ConnectionToHost::Error error) {
  DCHECK(message_loop()->BelongsToCurrentThread());
  VLOG(1) << "ChromotingClient::OnConnectionState(" << state << ")";
  if (state == protocol::ConnectionToHost::CONNECTED ||
      state == protocol::ConnectionToHost::AUTHENTICATED)
    Initialize();
  view_->SetConnectionState(state, error);
}

base::MessageLoopProxy* ChromotingClient::message_loop() {
  return context_->network_message_loop();
}

void ChromotingClient::OnPacketDone(bool last_packet,
                                    base::Time decode_start) {
  if (!message_loop()->BelongsToCurrentThread()) {
    thread_proxy_.PostTask(FROM_HERE, base::Bind(
        &ChromotingClient::OnPacketDone, base::Unretained(this),
        last_packet, decode_start));
    return;
  }

  // Record the latency between the final packet being received and
  // presented.
  if (last_packet) {
    stats_.video_decode_ms()->Record(
        (base::Time::Now() - decode_start).InMilliseconds());
  }

  received_packets_.front().done.Run();
  received_packets_.pop_front();

  packet_being_processed_ = false;

  // Process the next video packet.
  DispatchPacket();
}

void ChromotingClient::Initialize() {
  if (!message_loop()->BelongsToCurrentThread()) {
    thread_proxy_.PostTask(FROM_HERE, base::Bind(
        &ChromotingClient::Initialize, base::Unretained(this)));
    return;
  }

  // Initialize the decoder.
  rectangle_decoder_->Initialize(connection_->config());

  // Schedule the input handler to process the event queue.
  input_handler_->Initialize();
}

}  // namespace remoting
<|endoftext|>


<commit_before>// Copyright (c) 2021 ASMlover. All rights reserved.
//
//  ______             __                  ___
// /\__  _\           /\ \                /\_ \
// \/_/\ \/    __     \_\ \  _____     ___\//\ \      __
//    \ \ \  /'__`\   /'_` \/\ '__`\  / __`\\ \ \   /'__`\
//     \ \ \/\ \L\.\_/\ \L\ \ \ \L\ \/\ \L\ \\_\ \_/\  __/
//      \ \_\ \__/.\_\ \___,_\ \ ,__/\ \____//\____\ \____\
//       \/_/\/__/\/_/\/__,_ /\ \ \/  \/___/ \/____/\/____/
//                             \ \_\
//                              \/_/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Object/Object.hh>
#include <Object/StringObject.hh>
#include <Object/NativeObject.hh>

namespace Tadpole::Object {

const char* BaseObject::type_asstr() const noexcept {
  switch (type_) {
  case ObjType::STRING: return "<string>";
  case ObjType::NATIVE: return "<native>";
  case ObjType::FUNCTION: return "<function>";
  case ObjType::UPVALUE: return "<upvalue>";
  case ObjType::CLOSURE: return "<closure>";
  default: break;
  }
  return "<unknown>";
}

StringObject* BaseObject::as_string() {
  return Common::as_down<StringObject>(this);
}

const char* BaseObject::as_cstring() {
  return Common::as_down<StringObject>(this)->cstr();
}

NativeObject* BaseObject::as_native() {
  return Common::as_down<NativeObject>(this);
}

FunctionObject* BaseObject::as_function() {
  // TODO:
  return nullptr;
}

UpvalueObject* BaseObject::as_upvalue() {
  // TODO:
  return nullptr;
}

ClosureObject* BaseObject::as_closure() {
  // TODO:
  return nullptr;
}

}
<commit_msg>:construction: chore(object): updated the object implementation<commit_after>// Copyright (c) 2021 ASMlover. All rights reserved.
//
//  ______             __                  ___
// /\__  _\           /\ \                /\_ \
// \/_/\ \/    __     \_\ \  _____     ___\//\ \      __
//    \ \ \  /'__`\   /'_` \/\ '__`\  / __`\\ \ \   /'__`\
//     \ \ \/\ \L\.\_/\ \L\ \ \ \L\ \/\ \L\ \\_\ \_/\  __/
//      \ \_\ \__/.\_\ \___,_\ \ ,__/\ \____//\____\ \____\
//       \/_/\/__/\/_/\/__,_ /\ \ \/  \/___/ \/____/\/____/
//                             \ \_\
//                              \/_/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Object/Object.hh>
#include <Object/StringObject.hh>
#include <Object/NativeObject.hh>
#include <Object/FunctionObject.hh>

namespace Tadpole::Object {

const char* BaseObject::type_asstr() const noexcept {
  switch (type_) {
  case ObjType::STRING: return "<string>";
  case ObjType::NATIVE: return "<native>";
  case ObjType::FUNCTION: return "<function>";
  case ObjType::UPVALUE: return "<upvalue>";
  case ObjType::CLOSURE: return "<closure>";
  default: break;
  }
  return "<unknown>";
}

StringObject* BaseObject::as_string() {
  return Common::as_down<StringObject>(this);
}

const char* BaseObject::as_cstring() {
  return Common::as_down<StringObject>(this)->cstr();
}

NativeObject* BaseObject::as_native() {
  return Common::as_down<NativeObject>(this);
}

FunctionObject* BaseObject::as_function() {
  return Common::as_down<FunctionObject>(this);
}

UpvalueObject* BaseObject::as_upvalue() {
  // TODO:
  return nullptr;
}

ClosureObject* BaseObject::as_closure() {
  // TODO:
  return nullptr;
}

}
<|endoftext|>