<commit_before>/*
	Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin
	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of Rasterbar Software nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <cassert>
#include <iostream>
#include <vector>
#include <utility>
#include <set>

#include "libtorrent/buffer.hpp"
#include "libtorrent/chained_buffer.hpp"
#include "libtorrent/socket.hpp"

#include "test.hpp"

using namespace libtorrent;

/*
template<class T>
T const& min_(T const& x, T const& y)
{
	return x < y ? x : y;
}

void test_speed()
{
	buffer b;

	char data[32];

	srand(0);

	boost::timer t;

	int const iterations = 5000000;
	int const step = iterations / 20;

	for (int i = 0; i < iterations; ++i)
	{
		int x = rand();

		if (i % step == 0) std::cerr << ".";

		std::size_t n = rand() % 32;
		n = 32;

		if (x % 2)
		{
			b.insert(data, data + n);
		}
		else
		{
			b.erase(min_(b.size(), n));
		}
	}

	float t1 = t.elapsed();
	std::cerr << "buffer elapsed: " << t.elapsed() << "\n";

	std::vector<char> v;

	srand(0);
	t.restart();

	for (int i = 0; i < iterations; ++i)
	{
		int x = rand();

		if (i % step == 0) std::cerr << ".";

		std::size_t n = rand() % 32;
		n = 32;

		if (x % 2)
		{
			v.insert(v.end(), data, data + n);
		}
		else
		{
			v.erase(v.begin(), v.begin() + min_(v.size(), n));
		}
	}

	float t2 = t.elapsed();
	std::cerr << "std::vector elapsed: " << t.elapsed() << "\n";

	assert(t1 < t2);
}
*/

// -- test buffer --

void test_buffer()
{
	char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

	buffer b;

	TEST_CHECK(b.size() == 0);
	TEST_CHECK(b.capacity() == 0);
	TEST_CHECK(b.empty());

	b.resize(10);
	TEST_CHECK(b.size() == 10);
	TEST_CHECK(b.capacity() == 10);

	std::memcpy(b.begin(), data, 10);
	b.reserve(50);
	TEST_CHECK(std::memcmp(b.begin(), data, 10) == 0);
	TEST_CHECK(b.capacity() == 50);

	b.erase(b.begin() + 6, b.end());
	TEST_CHECK(std::memcmp(b.begin(), data, 6) == 0);
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 6);

	b.insert(b.begin(), data + 5, data + 10);
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 11);
	TEST_CHECK(std::memcmp(b.begin(), data + 5, 5) == 0);

	b.clear();
	TEST_CHECK(b.size() == 0);
	TEST_CHECK(b.capacity() == 50);

	b.insert(b.end(), data, data + 10);
	TEST_CHECK(b.size() == 10);
	TEST_CHECK(std::memcmp(b.begin(), data, 10) == 0);

	b.erase(b.begin(), b.end());
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 0);

	buffer().swap(b);
	TEST_CHECK(b.capacity() == 0);

}

// -- test chained buffer --

std::set<char*> buffer_list;

void free_buffer(char* m)
{
	std::set<char*>::iterator i = buffer_list.find(m);
	TEST_CHECK(i != buffer_list.end());

	buffer_list.erase(i);
	std::free(m);
}

char* allocate_buffer(int size)
{
	char* mem = (char*)std::malloc(size);
	buffer_list.insert(mem);
	return mem;
}

template <class T>
int copy_buffers(T const& b, char* target)
{
	int copied = 0;
	for (typename T::const_iterator i = b.begin()
		, end(b.end()); i != end; ++i)
	{
		memcpy(target, libtorrent::asio::buffer_cast<char const*>(*i), libtorrent::asio::buffer_size(*i));
		target += libtorrent::asio::buffer_size(*i);
		copied += libtorrent::asio::buffer_size(*i);
	}
	return copied;
}

bool compare_chained_buffer(chained_buffer& b, char const* mem, int size)
{
	if (size == 0) return true;
	std::vector<char> flat(size);
	std::list<libtorrent::asio::const_buffer> const& iovec2 = b.build_iovec(size);
	int copied = copy_buffers(iovec2, &flat[0]);
	TEST_CHECK(copied == size);
	return std::memcmp(&flat[0], mem, size) == 0;
}

void test_chained_buffer()
{
	char data[] = "foobar";
	{
		chained_buffer b;

		TEST_CHECK(b.empty());
		TEST_CHECK(b.capacity() == 0);
		TEST_CHECK(b.size() == 0);
		TEST_CHECK(b.space_in_last_buffer() == 0);
		TEST_CHECK(buffer_list.empty());

		char* b1 = allocate_buffer(512);
		std::memcpy(b1, data, 6);
		b.append_buffer(b1, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 1);

		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 6);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		b.pop_front(3);

		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 3);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		bool ret = b.append(data, 6);

		TEST_CHECK(ret == true);
		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 9);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 12);

		ret = b.append(data, 1024);

		TEST_CHECK(ret == false);

		char* b2 = allocate_buffer(512);
		std::memcpy(b2, data, 6);
		b.append_buffer(b2, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 2);

		char* b3 = allocate_buffer(512);
		std::memcpy(b3, data, 6);
		b.append_buffer(b3, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 3);

		TEST_CHECK(b.capacity() == 512 * 3);
		TEST_CHECK(b.size() == 21);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		TEST_CHECK(compare_chained_buffer(b, "barfoobar", 9));

		for (int i = 1; i < 21; ++i)
			TEST_CHECK(compare_chained_buffer(b, "barfoobarfoobarfoobar", i));

		b.pop_front(5 + 6);

		TEST_CHECK(buffer_list.size() == 2);
		TEST_CHECK(b.capacity() == 512 * 2);
		TEST_CHECK(b.size() == 10);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		char const* str = "obarfooba";
		TEST_CHECK(compare_chained_buffer(b, str, 9));

		for (int i = 0; i < 9; ++i)
		{
			b.pop_front(1);
			++str;
			TEST_CHECK(compare_chained_buffer(b, str, 8 - i));
			TEST_CHECK(b.size() == 9 - i);
		}

		char* b4 = allocate_buffer(20);
		std::memcpy(b4, data, 6);
		std::memcpy(b4 + 6, data, 6);
		b.append_buffer(b4, 20, 12, (void(*)(char*))&free_buffer);
		TEST_CHECK(b.space_in_last_buffer() == 8);

		ret = b.append(data, 6);
		TEST_CHECK(ret == true);
		TEST_CHECK(b.space_in_last_buffer() == 2);
		std::cout << b.space_in_last_buffer() << std::endl;
		ret = b.append(data, 2);
		TEST_CHECK(ret == true);
		TEST_CHECK(b.space_in_last_buffer() == 0);
		std::cout << b.space_in_last_buffer() << std::endl;

		char* b5 = allocate_buffer(20);
		std::memcpy(b4, data, 6);
		b.append_buffer(b5, 20, 6, (void(*)(char*))&free_buffer);

		b.pop_front(22);
		TEST_CHECK(b.size() == 5);
	}
	TEST_CHECK(buffer_list.empty());
}

int test_main()
{
	test_buffer();
	test_chained_buffer();
	return 0;
}

<commit_msg>fix potential buffer overrun in unit test<commit_after>/*
	Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin
	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of Rasterbar Software nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <cassert>
#include <iostream>
#include <vector>
#include <utility>
#include <set>

#include "libtorrent/buffer.hpp"
#include "libtorrent/chained_buffer.hpp"
#include "libtorrent/socket.hpp"

#include "test.hpp"

using namespace libtorrent;

/*
template<class T>
T const& min_(T const& x, T const& y)
{
	return x < y ? x : y;
}

void test_speed()
{
	buffer b;

	char data[32];

	srand(0);

	boost::timer t;

	int const iterations = 5000000;
	int const step = iterations / 20;

	for (int i = 0; i < iterations; ++i)
	{
		int x = rand();

		if (i % step == 0) std::cerr << ".";

		std::size_t n = rand() % 32;
		n = 32;

		if (x % 2)
		{
			b.insert(data, data + n);
		}
		else
		{
			b.erase(min_(b.size(), n));
		}
	}

	float t1 = t.elapsed();
	std::cerr << "buffer elapsed: " << t.elapsed() << "\n";

	std::vector<char> v;

	srand(0);
	t.restart();

	for (int i = 0; i < iterations; ++i)
	{
		int x = rand();

		if (i % step == 0) std::cerr << ".";

		std::size_t n = rand() % 32;
		n = 32;

		if (x % 2)
		{
			v.insert(v.end(), data, data + n);
		}
		else
		{
			v.erase(v.begin(), v.begin() + min_(v.size(), n));
		}
	}

	float t2 = t.elapsed();
	std::cerr << "std::vector elapsed: " << t.elapsed() << "\n";

	assert(t1 < t2);
}
*/

// -- test buffer --

void test_buffer()
{
	char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

	buffer b;

	TEST_CHECK(b.size() == 0);
	TEST_CHECK(b.capacity() == 0);
	TEST_CHECK(b.empty());

	b.resize(10);
	TEST_CHECK(b.size() == 10);
	TEST_CHECK(b.capacity() == 10);

	std::memcpy(b.begin(), data, 10);
	b.reserve(50);
	TEST_CHECK(std::memcmp(b.begin(), data, 10) == 0);
	TEST_CHECK(b.capacity() == 50);

	b.erase(b.begin() + 6, b.end());
	TEST_CHECK(std::memcmp(b.begin(), data, 6) == 0);
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 6);

	b.insert(b.begin(), data + 5, data + 10);
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 11);
	TEST_CHECK(std::memcmp(b.begin(), data + 5, 5) == 0);

	b.clear();
	TEST_CHECK(b.size() == 0);
	TEST_CHECK(b.capacity() == 50);

	b.insert(b.end(), data, data + 10);
	TEST_CHECK(b.size() == 10);
	TEST_CHECK(std::memcmp(b.begin(), data, 10) == 0);

	b.erase(b.begin(), b.end());
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 0);

	buffer().swap(b);
	TEST_CHECK(b.capacity() == 0);

}

// -- test chained buffer --

std::set<char*> buffer_list;

void free_buffer(char* m)
{
	std::set<char*>::iterator i = buffer_list.find(m);
	TEST_CHECK(i != buffer_list.end());

	buffer_list.erase(i);
	std::free(m);
}

char* allocate_buffer(int size)
{
	char* mem = (char*)std::malloc(size);
	buffer_list.insert(mem);
	return mem;
}

template <class T>
int copy_buffers(T const& b, char* target)
{
	int copied = 0;
	for (typename T::const_iterator i = b.begin()
		, end(b.end()); i != end; ++i)
	{
		memcpy(target, libtorrent::asio::buffer_cast<char const*>(*i), libtorrent::asio::buffer_size(*i));
		target += libtorrent::asio::buffer_size(*i);
		copied += libtorrent::asio::buffer_size(*i);
	}
	return copied;
}

bool compare_chained_buffer(chained_buffer& b, char const* mem, int size)
{
	if (size == 0) return true;
	std::vector<char> flat(size);
	std::list<libtorrent::asio::const_buffer> const& iovec2 = b.build_iovec(size);
	int copied = copy_buffers(iovec2, &flat[0]);
	TEST_CHECK(copied == size);
	return std::memcmp(&flat[0], mem, size) == 0;
}

void test_chained_buffer()
{
	char data[] = "foobar";
	{
		chained_buffer b;

		TEST_CHECK(b.empty());
		TEST_CHECK(b.capacity() == 0);
		TEST_CHECK(b.size() == 0);
		TEST_CHECK(b.space_in_last_buffer() == 0);
		TEST_CHECK(buffer_list.empty());

		char* b1 = allocate_buffer(512);
		std::memcpy(b1, data, 6);
		b.append_buffer(b1, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 1);

		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 6);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		b.pop_front(3);

		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 3);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		bool ret = b.append(data, 6);

		TEST_CHECK(ret == true);
		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 9);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 12);

		char data2[1024];
		ret = b.append(data2, 1024);

		TEST_CHECK(ret == false);

		char* b2 = allocate_buffer(512);
		std::memcpy(b2, data, 6);
		b.append_buffer(b2, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 2);

		char* b3 = allocate_buffer(512);
		std::memcpy(b3, data, 6);
		b.append_buffer(b3, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 3);

		TEST_CHECK(b.capacity() == 512 * 3);
		TEST_CHECK(b.size() == 21);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		TEST_CHECK(compare_chained_buffer(b, "barfoobar", 9));

		for (int i = 1; i < 21; ++i)
			TEST_CHECK(compare_chained_buffer(b, "barfoobarfoobarfoobar", i));

		b.pop_front(5 + 6);

		TEST_CHECK(buffer_list.size() == 2);
		TEST_CHECK(b.capacity() == 512 * 2);
		TEST_CHECK(b.size() == 10);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		char const* str = "obarfooba";
		TEST_CHECK(compare_chained_buffer(b, str, 9));

		for (int i = 0; i < 9; ++i)
		{
			b.pop_front(1);
			++str;
			TEST_CHECK(compare_chained_buffer(b, str, 8 - i));
			TEST_CHECK(b.size() == 9 - i);
		}

		char* b4 = allocate_buffer(20);
		std::memcpy(b4, data, 6);
		std::memcpy(b4 + 6, data, 6);
		b.append_buffer(b4, 20, 12, (void(*)(char*))&free_buffer);
		TEST_CHECK(b.space_in_last_buffer() == 8);

		ret = b.append(data, 6);
		TEST_CHECK(ret == true);
		TEST_CHECK(b.space_in_last_buffer() == 2);
		std::cout << b.space_in_last_buffer() << std::endl;
		ret = b.append(data, 2);
		TEST_CHECK(ret == true);
		TEST_CHECK(b.space_in_last_buffer() == 0);
		std::cout << b.space_in_last_buffer() << std::endl;

		char* b5 = allocate_buffer(20);
		std::memcpy(b4, data, 6);
		b.append_buffer(b5, 20, 6, (void(*)(char*))&free_buffer);

		b.pop_front(22);
		TEST_CHECK(b.size() == 5);
	}
	TEST_CHECK(buffer_list.empty());
}

int test_main()
{
	test_buffer();
	test_chained_buffer();
	return 0;
}

<|endoftext|>


<commit_before>// Copyright (c)2008-2012, Preferred Infrastructure Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//
//     * Neither the name of Preferred Infrastructure nor the names of other
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER 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 "parser.h"

#include <iostream>
#include <new>
#include <stack>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>

#include "../../lang/exception.h"

namespace pfi {
namespace text {
namespace json {

class json_builder : public json_parser::callback {
public:
  const json& get() const {
    if (stk.size() != 1)
      throw pfi::lang::parse_error();
    return stk[0];
  }

  void null() {
    stk.push_back(new json_null());
  }

  void boolean(bool val) {
    stk.push_back(new json_bool(val));
  }

  void integer(int64_t val) {
    stk.push_back(new json_integer(val));
  }

  void number(double val) {
    stk.push_back(new json_float(val));
  }

  void string(const char* val, size_t len) {
    stk.push_back(new json_string(std::string(val, val+len)));
  }

  void start_object() {
    ixs.push(stk.size());
  }
  void object_key(const char* val, size_t len) {
    key.push_back(std::string(val, val+len));
  }
  void end_object() {
    json obj(new json_object());
    int ix = ixs.top();
    int jx = stk.size();
    int sz = jx - ix;
    for (int i = 0; i < sz; i++)
      obj.add(key[key.size() - sz + i], stk[ix + i]);
    stk.push_back(obj);
    stk.erase(stk.end() - sz - 1, stk.end() - 1);
    key.erase(key.end() - sz, key.end());
    ixs.pop();
  }

  void start_array() {
    ixs.push(stk.size());
  }
  void end_array() {
    json obj(new json_array());
    int ix = ixs.top();
    int jx = stk.size();
    int sz = jx - ix;
    for (int i = 0; i < sz; i++)
      obj.add(stk[ix + i]);
    stk.push_back(obj);
    stk.erase(stk.end() - sz - 1, stk.end() - 1);
    ixs.pop();
  }

  std::vector<json> stk;
  std::vector<std::string> key;

  std::stack<int> ixs;
};

json_parser::json_parser(std::istream& is)
  : is(is), it(is), end(), lineno(1), charno(1), cbuf(-1)
{
  buf_len = 256;
  if ((buf = static_cast<char*>(malloc(buf_len))) == 0)
    throw std::bad_alloc();
}

json_parser::~json_parser()
{
  free(buf);
}

json json_parser::parse()
{
  json_builder jb;
  parse_stream(jb);
  return jb.get();
}

void json_parser::parse_stream(callback& cb)
{
  ss();
  if (it == end)
    throw lang::end_of_data("json_parser reached end of data");
  return parse_impl(cb);
}

void json_parser::parse_impl(callback& cb)
{
  ss();
  switch(peek()) {
  case '{':
    parse_object(cb);
    return;

  case '[':
    parse_array(cb);
    return;

  case '0': case '1': case '2': case '3': case '4':
  case '5': case '6': case '7': case '8': case '9':
  case '-':
    parse_number(cb);
    return;

  case '\"':
    parse_string(cb);
    return;

  case 'f':
    parse_false(cb);
    return;
  case 'n':
    parse_null(cb);
    return;
  case 't':
    parse_true(cb);
    return;

  default: {
    char err_msg[64];
    snprintf(err_msg, sizeof(err_msg),
             "invalid char: \'%s\' (U+%04X)",
             pfi::data::string::uchar_to_string(peek()).c_str(), peek());
    error(err_msg);
  }

  }
  return; // dmy for supressing warning
}

void json_parser::parse_object(callback& cb)
{
  cb.start_object();

  smatch('{');

  for (int i = 0; ; i++) {
    if (speek() == '}')
      break;
    if (i > 0)
      smatch(',');

    ss();
    int len = 0;
    parse_string_prim(buf, buf_len, len);
    cb.object_key(buf, len);
    smatch(':');
    parse_impl(cb);
  }

  smatch('}');

  cb.end_object();
}

void json_parser::parse_array(callback& cb)
{
  cb.start_array();

  smatch('[');

  for (int i = 0; ; i++) {
    if (speek() == ']')
      break;
    if (i > 0)
      smatch(',');

    parse_impl(cb);
  }

  smatch(']');

  cb.end_array();
}

void json_parser::parse_number(callback& cb)
{
  int sign = 1;
  if (peek() == '-') {
    incr();
    sign=-1;
  }

  int64_t num = 0;
  while(safe_isdigit(peek())) {
    num = num*10 + peek() - '0';
    incr();
  }

  bool is_frac = false;
  double frac = num;

  if (peek() == '.') {
    is_frac = true;
    incr();

    double keta = 0.1;
    if (!safe_isdigit(peek()))
      error("after decimal-point, digit required.");

    while (safe_isdigit(peek())) {
      frac += (peek()-'0') * keta;
      incr();
      keta *= 0.1;
    }
  }

  if (peek() == 'e' || peek() == 'E') {
    is_frac = true;
    incr();

    int exp_sign = 1;

    if (peek() == '+') {
      incr();
    }
    else if (peek() == '-') {
      exp_sign = -1;
      incr();
    }

    int exp = 0;

    if (!safe_isdigit(peek()))
      error("after exp, digit required.");

    while (safe_isdigit(peek())) {
      exp = exp*10 + peek() - '0';
      incr();
    }

    frac *= std::pow(10.0, (double)exp_sign*exp);
  }

  if (is_frac)
    cb.number(sign*frac);
  else
    cb.integer(sign*num);
}

void json_parser::parse_string(callback& cb)
{
  int len = 0;
  parse_string_prim(buf, buf_len, len);
  cb.string(buf, len);
}

void json_parser::parse_string_prim(char*& buf, int& buf_len, int& str_len)
{
  char* p = buf;

  match('\"');

  for (;;) {
    if (p+8 >= buf+buf_len) {
      size_t adv = p - buf;
      if (char* newbuf = static_cast<char*>(realloc(buf, 2*buf_len)))
        buf = newbuf;
      else
        throw std::bad_alloc();
      buf_len *= 2;
      p = buf + adv;
    }

    if (peek() == '\"')
      break;

    if (peek() == '\\') {
      incr();

      int c = incr();

      switch (c) {
      case '\"': *p++ = '\"'; break;
      case '\\': *p++ = '\\'; break;
      case '/':  *p++ = '/';  break;
      case 'b':  *p++ = '\b'; break;
      case 'f':  *p++ = '\f'; break;
      case 'n':  *p++ = '\n'; break;
      case 'r':  *p++ = '\r'; break;
      case 't':  *p++ = '\t'; break;

      case 'u': {
        int a = parse_hex();
        int b = parse_hex();
        int c = parse_hex();
        int d = parse_hex();
        pfi::data::string::uchar_to_chars((a<<12)|(b<<8)|(c<<4)|d, p);
        break;
      }

      default: {
        char err_msg[64];
        snprintf(err_msg, sizeof(err_msg),
                 "unexpected unescaped char: \'%s\' (U+%04X)",
                 pfi::data::string::uchar_to_string(c).c_str(), c);
        error(err_msg);
      }

      }
    }
    else {
      int c = incr();

      if ((c>=0x20 && c<=0x21) ||
          (c>=0x23 && c<=0x5B) ||
          (c>=0x5D && c<=0x10FFFF))
        pfi::data::string::uchar_to_chars(c, p);
      else {
        char err_msg[64];
        snprintf(err_msg, sizeof(err_msg),
                 "unexpected unescaped char: \'%s\' (U+%04X)",
                 pfi::data::string::uchar_to_string(c).c_str(), c);
        error(err_msg);
      }
    }
  }

  match('\"');

  str_len = p - buf;
}

void json_parser::parse_false(callback& cb)
{
  match('f');
  match('a');
  match('l');
  match('s');
  match('e');
  cb.boolean(false);
}

void json_parser::parse_null(callback& cb)
{
  match('n');
  match('u');
  match('l');
  match('l');
  cb.null();
}

void json_parser::parse_true(callback& cb)
{
  match('t');
  match('r');
  match('u');
  match('e');
  cb.boolean(true);
}

void json_parser::error(const std::string& msg)
{
  std::string filename="<istream>";

  throw pfi::lang::parse_error(filename, lineno, charno, msg);
}

} // json
} // text
} // pfi
<commit_msg>Removed a C style cast.<commit_after>// Copyright (c)2008-2012, Preferred Infrastructure Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//
//     * Neither the name of Preferred Infrastructure nor the names of other
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER 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 "parser.h"

#include <iostream>
#include <new>
#include <stack>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>

#include "../../lang/exception.h"

namespace pfi {
namespace text {
namespace json {

class json_builder : public json_parser::callback {
public:
  const json& get() const {
    if (stk.size() != 1)
      throw pfi::lang::parse_error();
    return stk[0];
  }

  void null() {
    stk.push_back(new json_null());
  }

  void boolean(bool val) {
    stk.push_back(new json_bool(val));
  }

  void integer(int64_t val) {
    stk.push_back(new json_integer(val));
  }

  void number(double val) {
    stk.push_back(new json_float(val));
  }

  void string(const char* val, size_t len) {
    stk.push_back(new json_string(std::string(val, val+len)));
  }

  void start_object() {
    ixs.push(stk.size());
  }
  void object_key(const char* val, size_t len) {
    key.push_back(std::string(val, val+len));
  }
  void end_object() {
    json obj(new json_object());
    int ix = ixs.top();
    int jx = stk.size();
    int sz = jx - ix;
    for (int i = 0; i < sz; i++)
      obj.add(key[key.size() - sz + i], stk[ix + i]);
    stk.push_back(obj);
    stk.erase(stk.end() - sz - 1, stk.end() - 1);
    key.erase(key.end() - sz, key.end());
    ixs.pop();
  }

  void start_array() {
    ixs.push(stk.size());
  }
  void end_array() {
    json obj(new json_array());
    int ix = ixs.top();
    int jx = stk.size();
    int sz = jx - ix;
    for (int i = 0; i < sz; i++)
      obj.add(stk[ix + i]);
    stk.push_back(obj);
    stk.erase(stk.end() - sz - 1, stk.end() - 1);
    ixs.pop();
  }

  std::vector<json> stk;
  std::vector<std::string> key;

  std::stack<int> ixs;
};

json_parser::json_parser(std::istream& is)
  : is(is), it(is), end(), lineno(1), charno(1), cbuf(-1)
{
  buf_len = 256;
  if ((buf = static_cast<char*>(malloc(buf_len))) == 0)
    throw std::bad_alloc();
}

json_parser::~json_parser()
{
  free(buf);
}

json json_parser::parse()
{
  json_builder jb;
  parse_stream(jb);
  return jb.get();
}

void json_parser::parse_stream(callback& cb)
{
  ss();
  if (it == end)
    throw lang::end_of_data("json_parser reached end of data");
  return parse_impl(cb);
}

void json_parser::parse_impl(callback& cb)
{
  ss();
  switch(peek()) {
  case '{':
    parse_object(cb);
    return;

  case '[':
    parse_array(cb);
    return;

  case '0': case '1': case '2': case '3': case '4':
  case '5': case '6': case '7': case '8': case '9':
  case '-':
    parse_number(cb);
    return;

  case '\"':
    parse_string(cb);
    return;

  case 'f':
    parse_false(cb);
    return;
  case 'n':
    parse_null(cb);
    return;
  case 't':
    parse_true(cb);
    return;

  default: {
    char err_msg[64];
    snprintf(err_msg, sizeof(err_msg),
             "invalid char: \'%s\' (U+%04X)",
             pfi::data::string::uchar_to_string(peek()).c_str(), peek());
    error(err_msg);
  }

  }
  return; // dmy for supressing warning
}

void json_parser::parse_object(callback& cb)
{
  cb.start_object();

  smatch('{');

  for (int i = 0; ; i++) {
    if (speek() == '}')
      break;
    if (i > 0)
      smatch(',');

    ss();
    int len = 0;
    parse_string_prim(buf, buf_len, len);
    cb.object_key(buf, len);
    smatch(':');
    parse_impl(cb);
  }

  smatch('}');

  cb.end_object();
}

void json_parser::parse_array(callback& cb)
{
  cb.start_array();

  smatch('[');

  for (int i = 0; ; i++) {
    if (speek() == ']')
      break;
    if (i > 0)
      smatch(',');

    parse_impl(cb);
  }

  smatch(']');

  cb.end_array();
}

void json_parser::parse_number(callback& cb)
{
  int sign = 1;
  if (peek() == '-') {
    incr();
    sign=-1;
  }

  int64_t num = 0;
  while(safe_isdigit(peek())) {
    num = num*10 + peek() - '0';
    incr();
  }

  bool is_frac = false;
  double frac = num;

  if (peek() == '.') {
    is_frac = true;
    incr();

    double keta = 0.1;
    if (!safe_isdigit(peek()))
      error("after decimal-point, digit required.");

    while (safe_isdigit(peek())) {
      frac += (peek()-'0') * keta;
      incr();
      keta *= 0.1;
    }
  }

  if (peek() == 'e' || peek() == 'E') {
    is_frac = true;
    incr();

    int exp_sign = 1;

    if (peek() == '+') {
      incr();
    }
    else if (peek() == '-') {
      exp_sign = -1;
      incr();
    }

    int exp = 0;

    if (!safe_isdigit(peek()))
      error("after exp, digit required.");

    while (safe_isdigit(peek())) {
      exp = exp*10 + peek() - '0';
      incr();
    }

    frac *= std::pow(10.0, exp_sign*exp);
  }

  if (is_frac)
    cb.number(sign*frac);
  else
    cb.integer(sign*num);
}

void json_parser::parse_string(callback& cb)
{
  int len = 0;
  parse_string_prim(buf, buf_len, len);
  cb.string(buf, len);
}

void json_parser::parse_string_prim(char*& buf, int& buf_len, int& str_len)
{
  char* p = buf;

  match('\"');

  for (;;) {
    if (p+8 >= buf+buf_len) {
      size_t adv = p - buf;
      if (char* newbuf = static_cast<char*>(realloc(buf, 2*buf_len)))
        buf = newbuf;
      else
        throw std::bad_alloc();
      buf_len *= 2;
      p = buf + adv;
    }

    if (peek() == '\"')
      break;

    if (peek() == '\\') {
      incr();

      int c = incr();

      switch (c) {
      case '\"': *p++ = '\"'; break;
      case '\\': *p++ = '\\'; break;
      case '/':  *p++ = '/';  break;
      case 'b':  *p++ = '\b'; break;
      case 'f':  *p++ = '\f'; break;
      case 'n':  *p++ = '\n'; break;
      case 'r':  *p++ = '\r'; break;
      case 't':  *p++ = '\t'; break;

      case 'u': {
        int a = parse_hex();
        int b = parse_hex();
        int c = parse_hex();
        int d = parse_hex();
        pfi::data::string::uchar_to_chars((a<<12)|(b<<8)|(c<<4)|d, p);
        break;
      }

      default: {
        char err_msg[64];
        snprintf(err_msg, sizeof(err_msg),
                 "unexpected unescaped char: \'%s\' (U+%04X)",
                 pfi::data::string::uchar_to_string(c).c_str(), c);
        error(err_msg);
      }

      }
    }
    else {
      int c = incr();

      if ((c>=0x20 && c<=0x21) ||
          (c>=0x23 && c<=0x5B) ||
          (c>=0x5D && c<=0x10FFFF))
        pfi::data::string::uchar_to_chars(c, p);
      else {
        char err_msg[64];
        snprintf(err_msg, sizeof(err_msg),
                 "unexpected unescaped char: \'%s\' (U+%04X)",
                 pfi::data::string::uchar_to_string(c).c_str(), c);
        error(err_msg);
      }
    }
  }

  match('\"');

  str_len = p - buf;
}

void json_parser::parse_false(callback& cb)
{
  match('f');
  match('a');
  match('l');
  match('s');
  match('e');
  cb.boolean(false);
}

void json_parser::parse_null(callback& cb)
{
  match('n');
  match('u');
  match('l');
  match('l');
  cb.null();
}

void json_parser::parse_true(callback& cb)
{
  match('t');
  match('r');
  match('u');
  match('e');
  cb.boolean(true);
}

void json_parser::error(const std::string& msg)
{
  std::string filename="<istream>";

  throw pfi::lang::parse_error(filename, lineno, charno, msg);
}

} // json
} // text
} // pfi
<|endoftext|>


<commit_before>/*
	Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin
	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of Rasterbar Software nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <cassert>
#include <boost/timer.hpp>
#include <iostream>
#include <vector>
#include <utility>
#include <set>

#include "libtorrent/buffer.hpp"
#include "libtorrent/chained_buffer.hpp"
#include "libtorrent/socket.hpp"

#include "test.hpp"

using libtorrent::buffer;
using libtorrent::chained_buffer;

/*
template<class T>
T const& min_(T const& x, T const& y)
{
	return x < y ? x : y;
}

void test_speed()
{
	buffer b;

	char data[32];

	srand(0);

	boost::timer t;

	int const iterations = 5000000;
	int const step = iterations / 20;

	for (int i = 0; i < iterations; ++i)
	{
		int x = rand();

		if (i % step == 0) std::cerr << ".";

		std::size_t n = rand() % 32;
		n = 32;

		if (x % 2)
		{
			b.insert(data, data + n);
		}
		else
		{
			b.erase(min_(b.size(), n));
		}
	}

	float t1 = t.elapsed();
	std::cerr << "buffer elapsed: " << t.elapsed() << "\n";

	std::vector<char> v;

	srand(0);
	t.restart();

	for (int i = 0; i < iterations; ++i)
	{
		int x = rand();

		if (i % step == 0) std::cerr << ".";

		std::size_t n = rand() % 32;
		n = 32;

		if (x % 2)
		{
			v.insert(v.end(), data, data + n);
		}
		else
		{
			v.erase(v.begin(), v.begin() + min_(v.size(), n));
		}
	}

	float t2 = t.elapsed();
	std::cerr << "std::vector elapsed: " << t.elapsed() << "\n";

	assert(t1 < t2);
}
*/

// -- test buffer --

void test_buffer()
{
	char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

	buffer b;

	TEST_CHECK(b.size() == 0);
	TEST_CHECK(b.capacity() == 0);
	TEST_CHECK(b.empty());

	b.resize(10);
	TEST_CHECK(b.size() == 10);
	TEST_CHECK(b.capacity() == 10);

	std::memcpy(b.begin(), data, 10);
	b.reserve(50);
	TEST_CHECK(std::memcmp(b.begin(), data, 10) == 0);
	TEST_CHECK(b.capacity() == 50);

	b.erase(b.begin() + 6, b.end());
	TEST_CHECK(std::memcmp(b.begin(), data, 6) == 0);
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 6);

	b.insert(b.begin(), data + 5, data + 10);
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 11);
	TEST_CHECK(std::memcmp(b.begin(), data + 5, 5) == 0);

	b.clear();
	TEST_CHECK(b.size() == 0);
	TEST_CHECK(b.capacity() == 50);

	b.insert(b.end(), data, data + 10);
	TEST_CHECK(b.size() == 10);
	TEST_CHECK(std::memcmp(b.begin(), data, 10) == 0);

	b.erase(b.begin(), b.end());
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 0);

	buffer().swap(b);
	TEST_CHECK(b.capacity() == 0);

}

// -- test chained buffer --

std::set<char*> buffer_list;

void free_buffer(char* m)
{
	std::set<char*>::iterator i = buffer_list.find(m);
	TEST_CHECK(i != buffer_list.end());

	buffer_list.erase(i);
	std::free(m);
}

char* allocate_buffer(int size)
{
	char* mem = (char*)std::malloc(size);
	buffer_list.insert(mem);
	return mem;
}

template <class T>
int copy_buffers(T const& b, char* target)
{
	int copied = 0;
	for (typename T::const_iterator i = b.begin()
		, end(b.end()); i != end; ++i)
	{
		memcpy(target, asio::buffer_cast<char const*>(*i), asio::buffer_size(*i));
		target += asio::buffer_size(*i);
		copied += asio::buffer_size(*i);
	}
	return copied;
}

bool compare_chained_buffer(chained_buffer& b, char const* mem, int size)
{
	if (size == 0) return true;
	std::vector<char> flat(size);
	std::list<asio::const_buffer> const& iovec2 = b.build_iovec(size);
	int copied = copy_buffers(iovec2, &flat[0]);
	TEST_CHECK(copied == size);
	return std::memcmp(&flat[0], mem, size) == 0;
}

void test_chained_buffer()
{
	char data[] = "foobar";
	{
		chained_buffer b;

		TEST_CHECK(b.empty());
		TEST_CHECK(b.capacity() == 0);
		TEST_CHECK(b.size() == 0);
		TEST_CHECK(b.space_in_last_buffer() == 0);
		TEST_CHECK(buffer_list.empty());

		char* b1 = allocate_buffer(512);
		std::memcpy(b1, data, 6);
		b.append_buffer(b1, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 1);

		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 6);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		b.pop_front(3);

		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 3);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		bool ret = b.append(data, 6);

		TEST_CHECK(ret == true);
		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 9);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 12);

		ret = b.append(data, 1024);

		TEST_CHECK(ret == false);

		char* b2 = allocate_buffer(512);
		std::memcpy(b2, data, 6);
		b.append_buffer(b2, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 2);

		char* b3 = allocate_buffer(512);
		std::memcpy(b3, data, 6);
		b.append_buffer(b3, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 3);

		TEST_CHECK(b.capacity() == 512 * 3);
		TEST_CHECK(b.size() == 21);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		TEST_CHECK(compare_chained_buffer(b, "barfoobar", 9));

		for (int i = 1; i < 21; ++i)
			TEST_CHECK(compare_chained_buffer(b, "barfoobarfoobarfoobar", i));

		b.pop_front(5 + 6);

		TEST_CHECK(buffer_list.size() == 2);
		TEST_CHECK(b.capacity() == 512 * 2);
		TEST_CHECK(b.size() == 10);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		char const* str = "obarfooba";
		TEST_CHECK(compare_chained_buffer(b, str, 9));

		for (int i = 0; i < 9; ++i)
		{
			b.pop_front(1);
			++str;
			TEST_CHECK(compare_chained_buffer(b, str, 8 - i));
			TEST_CHECK(b.size() == 9 - i);
		}

		char* b4 = allocate_buffer(20);
		std::memcpy(b4, data, 6);
		std::memcpy(b4 + 6, data, 6);
		b.append_buffer(b4, 20, 12, (void(*)(char*))&free_buffer);
		TEST_CHECK(b.space_in_last_buffer() == 8);

		ret = b.append(data, 6);
		TEST_CHECK(ret == true);
		TEST_CHECK(b.space_in_last_buffer() == 2);
		std::cout << b.space_in_last_buffer() << std::endl;
		ret = b.append(data, 2);
		TEST_CHECK(ret == true);
		TEST_CHECK(b.space_in_last_buffer() == 0);
		std::cout << b.space_in_last_buffer() << std::endl;

		char* b5 = allocate_buffer(20);
		std::memcpy(b4, data, 6);
		b.append_buffer(b5, 20, 6, (void(*)(char*))&free_buffer);

		b.pop_front(22);
		TEST_CHECK(b.size() == 5);
	}
	TEST_CHECK(buffer_list.empty());
}

int test_main()
{
	test_buffer();
	test_chained_buffer();
	return 0;
}

<commit_msg>boost 1.35 fix in test_buffer<commit_after>/*
	Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin
	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions
	are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of Rasterbar Software nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <cassert>
#include <boost/timer.hpp>
#include <iostream>
#include <vector>
#include <utility>
#include <set>

#include "libtorrent/buffer.hpp"
#include "libtorrent/chained_buffer.hpp"
#include "libtorrent/socket.hpp"

#include "test.hpp"

using namespace libtorrent;

/*
template<class T>
T const& min_(T const& x, T const& y)
{
	return x < y ? x : y;
}

void test_speed()
{
	buffer b;

	char data[32];

	srand(0);

	boost::timer t;

	int const iterations = 5000000;
	int const step = iterations / 20;

	for (int i = 0; i < iterations; ++i)
	{
		int x = rand();

		if (i % step == 0) std::cerr << ".";

		std::size_t n = rand() % 32;
		n = 32;

		if (x % 2)
		{
			b.insert(data, data + n);
		}
		else
		{
			b.erase(min_(b.size(), n));
		}
	}

	float t1 = t.elapsed();
	std::cerr << "buffer elapsed: " << t.elapsed() << "\n";

	std::vector<char> v;

	srand(0);
	t.restart();

	for (int i = 0; i < iterations; ++i)
	{
		int x = rand();

		if (i % step == 0) std::cerr << ".";

		std::size_t n = rand() % 32;
		n = 32;

		if (x % 2)
		{
			v.insert(v.end(), data, data + n);
		}
		else
		{
			v.erase(v.begin(), v.begin() + min_(v.size(), n));
		}
	}

	float t2 = t.elapsed();
	std::cerr << "std::vector elapsed: " << t.elapsed() << "\n";

	assert(t1 < t2);
}
*/

// -- test buffer --

void test_buffer()
{
	char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

	buffer b;

	TEST_CHECK(b.size() == 0);
	TEST_CHECK(b.capacity() == 0);
	TEST_CHECK(b.empty());

	b.resize(10);
	TEST_CHECK(b.size() == 10);
	TEST_CHECK(b.capacity() == 10);

	std::memcpy(b.begin(), data, 10);
	b.reserve(50);
	TEST_CHECK(std::memcmp(b.begin(), data, 10) == 0);
	TEST_CHECK(b.capacity() == 50);

	b.erase(b.begin() + 6, b.end());
	TEST_CHECK(std::memcmp(b.begin(), data, 6) == 0);
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 6);

	b.insert(b.begin(), data + 5, data + 10);
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 11);
	TEST_CHECK(std::memcmp(b.begin(), data + 5, 5) == 0);

	b.clear();
	TEST_CHECK(b.size() == 0);
	TEST_CHECK(b.capacity() == 50);

	b.insert(b.end(), data, data + 10);
	TEST_CHECK(b.size() == 10);
	TEST_CHECK(std::memcmp(b.begin(), data, 10) == 0);

	b.erase(b.begin(), b.end());
	TEST_CHECK(b.capacity() == 50);
	TEST_CHECK(b.size() == 0);

	buffer().swap(b);
	TEST_CHECK(b.capacity() == 0);

}

// -- test chained buffer --

std::set<char*> buffer_list;

void free_buffer(char* m)
{
	std::set<char*>::iterator i = buffer_list.find(m);
	TEST_CHECK(i != buffer_list.end());

	buffer_list.erase(i);
	std::free(m);
}

char* allocate_buffer(int size)
{
	char* mem = (char*)std::malloc(size);
	buffer_list.insert(mem);
	return mem;
}

template <class T>
int copy_buffers(T const& b, char* target)
{
	int copied = 0;
	for (typename T::const_iterator i = b.begin()
		, end(b.end()); i != end; ++i)
	{
		memcpy(target, asio::buffer_cast<char const*>(*i), asio::buffer_size(*i));
		target += asio::buffer_size(*i);
		copied += asio::buffer_size(*i);
	}
	return copied;
}

bool compare_chained_buffer(chained_buffer& b, char const* mem, int size)
{
	if (size == 0) return true;
	std::vector<char> flat(size);
	std::list<asio::const_buffer> const& iovec2 = b.build_iovec(size);
	int copied = copy_buffers(iovec2, &flat[0]);
	TEST_CHECK(copied == size);
	return std::memcmp(&flat[0], mem, size) == 0;
}

void test_chained_buffer()
{
	char data[] = "foobar";
	{
		chained_buffer b;

		TEST_CHECK(b.empty());
		TEST_CHECK(b.capacity() == 0);
		TEST_CHECK(b.size() == 0);
		TEST_CHECK(b.space_in_last_buffer() == 0);
		TEST_CHECK(buffer_list.empty());

		char* b1 = allocate_buffer(512);
		std::memcpy(b1, data, 6);
		b.append_buffer(b1, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 1);

		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 6);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		b.pop_front(3);

		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 3);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		bool ret = b.append(data, 6);

		TEST_CHECK(ret == true);
		TEST_CHECK(b.capacity() == 512);
		TEST_CHECK(b.size() == 9);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 12);

		ret = b.append(data, 1024);

		TEST_CHECK(ret == false);

		char* b2 = allocate_buffer(512);
		std::memcpy(b2, data, 6);
		b.append_buffer(b2, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 2);

		char* b3 = allocate_buffer(512);
		std::memcpy(b3, data, 6);
		b.append_buffer(b3, 512, 6, (void(*)(char*))&free_buffer);
		TEST_CHECK(buffer_list.size() == 3);

		TEST_CHECK(b.capacity() == 512 * 3);
		TEST_CHECK(b.size() == 21);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		TEST_CHECK(compare_chained_buffer(b, "barfoobar", 9));

		for (int i = 1; i < 21; ++i)
			TEST_CHECK(compare_chained_buffer(b, "barfoobarfoobarfoobar", i));

		b.pop_front(5 + 6);

		TEST_CHECK(buffer_list.size() == 2);
		TEST_CHECK(b.capacity() == 512 * 2);
		TEST_CHECK(b.size() == 10);
		TEST_CHECK(!b.empty());
		TEST_CHECK(b.space_in_last_buffer() == 512 - 6);

		char const* str = "obarfooba";
		TEST_CHECK(compare_chained_buffer(b, str, 9));

		for (int i = 0; i < 9; ++i)
		{
			b.pop_front(1);
			++str;
			TEST_CHECK(compare_chained_buffer(b, str, 8 - i));
			TEST_CHECK(b.size() == 9 - i);
		}

		char* b4 = allocate_buffer(20);
		std::memcpy(b4, data, 6);
		std::memcpy(b4 + 6, data, 6);
		b.append_buffer(b4, 20, 12, (void(*)(char*))&free_buffer);
		TEST_CHECK(b.space_in_last_buffer() == 8);

		ret = b.append(data, 6);
		TEST_CHECK(ret == true);
		TEST_CHECK(b.space_in_last_buffer() == 2);
		std::cout << b.space_in_last_buffer() << std::endl;
		ret = b.append(data, 2);
		TEST_CHECK(ret == true);
		TEST_CHECK(b.space_in_last_buffer() == 0);
		std::cout << b.space_in_last_buffer() << std::endl;

		char* b5 = allocate_buffer(20);
		std::memcpy(b4, data, 6);
		b.append_buffer(b5, 20, 6, (void(*)(char*))&free_buffer);

		b.pop_front(22);
		TEST_CHECK(b.size() == 5);
	}
	TEST_CHECK(buffer_list.empty());
}

int test_main()
{
	test_buffer();
	test_chained_buffer();
	return 0;
}

<|endoftext|>


<commit_before><commit_msg>astyle - switch cases should not be indented<commit_after><|endoftext|>


<commit_before>/**
 * Copyright (c) 2007-2012, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _top_status_source_hh
#define _top_status_source_hh

#include <string>

#include "logfile_sub_source.hh"
#include "statusview_curses.hh"

class top_status_source
    : public status_data_source {
public:

    typedef listview_curses::action::mem_functor_t<
            top_status_source> lv_functor_t;

    typedef enum {
        TSF_TIME,
        TSF_PARTITION_NAME,
        TSF_VIEW_NAME,
        TSF_STITCH_VIEW_FORMAT,
        TSF_FORMAT,
        TSF_STITCH_FORMAT_FILENAME,
        TSF_FILENAME,

        TSF__MAX
    } field_t;

    top_status_source()
        : filename_wire(*this, &top_status_source::update_filename)
    {
        this->tss_fields[TSF_TIME].set_width(24);
        this->tss_fields[TSF_PARTITION_NAME].set_width(30);
        this->tss_fields[TSF_VIEW_NAME].set_width(6);
        this->tss_fields[TSF_VIEW_NAME].right_justify(true);
        this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_width(2);
        this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_stitch_value(
            view_colors::ansi_color_pair_index(COLOR_CYAN, COLOR_BLUE));
        this->tss_fields[TSF_STITCH_VIEW_FORMAT].right_justify(true);
        this->tss_fields[TSF_FORMAT].set_width(13);
        this->tss_fields[TSF_FORMAT].right_justify(true);
        this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_width(2);
        this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_stitch_value(
            view_colors::ansi_color_pair_index(COLOR_WHITE, COLOR_CYAN));
        this->tss_fields[TSF_STITCH_FORMAT_FILENAME].right_justify(true);
        this->tss_fields[TSF_FILENAME].set_min_width(35); /* XXX */
        this->tss_fields[TSF_FILENAME].set_share(1);
        this->tss_fields[TSF_FILENAME].right_justify(true);
    };

    lv_functor_t filename_wire;

    size_t statusview_fields(void) { return TSF__MAX; };

    status_field &statusview_value_for_field(int field)
    {
        return this->tss_fields[field];
    };

    void update_time(void)
    {
        status_field &sf           = this->tss_fields[TSF_TIME];
        time_t        current_time = time(NULL);
        char          buffer[32];

        strftime(buffer, sizeof(buffer),
                 "%a %b %d %H:%M:%S %Z",
                 localtime(&current_time));
        sf.set_value(buffer);
    };

    void update_filename(listview_curses *lc)
    {
        status_field &    sf_partition = this->tss_fields[TSF_PARTITION_NAME];
        status_field &    sf_format   = this->tss_fields[TSF_FORMAT];
        status_field &    sf_filename = this->tss_fields[TSF_FILENAME];
        struct line_range lr(0);

        if (lc->get_inner_height() > 0) {
            string_attrs_t::const_iterator line_attr;
            attr_line_t           al;

            lc->get_data_source()->
            listview_value_for_row(*lc, lc->get_top(), al);
            string_attrs_t &sa = al.get_attrs();
            line_attr = find_string_attr(sa, &logline::L_FILE);
            if (line_attr != sa.end()) {
                logfile *lf = (logfile *)line_attr->sa_value.sav_ptr;

                if (lf->get_format()) {
                    sf_format.set_value("% 13s",
                                        lf->get_format()->get_name().c_str());
                }
                else if (!lf->get_filename().empty()) {
                    sf_format.set_value("% 13s", "plain text");
                }
                else{
                    sf_format.clear();
                }

                sf_filename.set_value(lf->get_filename());
            }
            else {
                sf_format.clear();
                sf_filename.clear();
            }

            line_attr = find_string_attr(sa, &logline::L_PARTITION);
            if (line_attr != sa.end()) {
                bookmark_metadata *bm = (bookmark_metadata *)line_attr->sa_value.sav_ptr;

                sf_partition.set_value(bm->bm_name.c_str());
            }
            else {
                sf_partition.clear();
            }
        }
        else {
            sf_format.clear();
            if (lc->get_data_source() != NULL) {
                sf_filename.set_value(lc->get_data_source()->listview_source_name(*lc));
            }
        }
        sf_format.get_value().get_attrs().push_back(
            string_attr(lr, &view_curses::VC_STYLE,
                A_REVERSE | view_colors::ansi_color_pair(COLOR_CYAN, COLOR_BLACK)));
    };

private:
    status_field tss_fields[TSF__MAX];
};
#endif
<commit_msg>[top_status_view] Increase the format name column width<commit_after>/**
 * Copyright (c) 2007-2012, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _top_status_source_hh
#define _top_status_source_hh

#include <string>

#include "logfile_sub_source.hh"
#include "statusview_curses.hh"

class top_status_source
    : public status_data_source {
public:

    typedef listview_curses::action::mem_functor_t<
            top_status_source> lv_functor_t;

    typedef enum {
        TSF_TIME,
        TSF_PARTITION_NAME,
        TSF_VIEW_NAME,
        TSF_STITCH_VIEW_FORMAT,
        TSF_FORMAT,
        TSF_STITCH_FORMAT_FILENAME,
        TSF_FILENAME,

        TSF__MAX
    } field_t;

    top_status_source()
        : filename_wire(*this, &top_status_source::update_filename)
    {
        this->tss_fields[TSF_TIME].set_width(24);
        this->tss_fields[TSF_PARTITION_NAME].set_width(30);
        this->tss_fields[TSF_VIEW_NAME].set_width(6);
        this->tss_fields[TSF_VIEW_NAME].right_justify(true);
        this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_width(2);
        this->tss_fields[TSF_STITCH_VIEW_FORMAT].set_stitch_value(
            view_colors::ansi_color_pair_index(COLOR_CYAN, COLOR_BLUE));
        this->tss_fields[TSF_STITCH_VIEW_FORMAT].right_justify(true);
        this->tss_fields[TSF_FORMAT].set_width(20);
        this->tss_fields[TSF_FORMAT].right_justify(true);
        this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_width(2);
        this->tss_fields[TSF_STITCH_FORMAT_FILENAME].set_stitch_value(
            view_colors::ansi_color_pair_index(COLOR_WHITE, COLOR_CYAN));
        this->tss_fields[TSF_STITCH_FORMAT_FILENAME].right_justify(true);
        this->tss_fields[TSF_FILENAME].set_min_width(35); /* XXX */
        this->tss_fields[TSF_FILENAME].set_share(1);
        this->tss_fields[TSF_FILENAME].right_justify(true);
    };

    lv_functor_t filename_wire;

    size_t statusview_fields(void) { return TSF__MAX; };

    status_field &statusview_value_for_field(int field)
    {
        return this->tss_fields[field];
    };

    void update_time(void)
    {
        status_field &sf           = this->tss_fields[TSF_TIME];
        time_t        current_time = time(NULL);
        char          buffer[32];

        strftime(buffer, sizeof(buffer),
                 "%a %b %d %H:%M:%S %Z",
                 localtime(&current_time));
        sf.set_value(buffer);
    };

    void update_filename(listview_curses *lc)
    {
        status_field &    sf_partition = this->tss_fields[TSF_PARTITION_NAME];
        status_field &    sf_format   = this->tss_fields[TSF_FORMAT];
        status_field &    sf_filename = this->tss_fields[TSF_FILENAME];
        struct line_range lr(0);

        if (lc->get_inner_height() > 0) {
            string_attrs_t::const_iterator line_attr;
            attr_line_t           al;

            lc->get_data_source()->
            listview_value_for_row(*lc, lc->get_top(), al);
            string_attrs_t &sa = al.get_attrs();
            line_attr = find_string_attr(sa, &logline::L_FILE);
            if (line_attr != sa.end()) {
                logfile *lf = (logfile *)line_attr->sa_value.sav_ptr;

                if (lf->get_format()) {
                    sf_format.set_value("% 13s",
                                        lf->get_format()->get_name().c_str());
                }
                else if (!lf->get_filename().empty()) {
                    sf_format.set_value("% 13s", "plain text");
                }
                else{
                    sf_format.clear();
                }

                sf_filename.set_value(lf->get_filename());
            }
            else {
                sf_format.clear();
                sf_filename.clear();
            }

            line_attr = find_string_attr(sa, &logline::L_PARTITION);
            if (line_attr != sa.end()) {
                bookmark_metadata *bm = (bookmark_metadata *)line_attr->sa_value.sav_ptr;

                sf_partition.set_value(bm->bm_name.c_str());
            }
            else {
                sf_partition.clear();
            }
        }
        else {
            sf_format.clear();
            if (lc->get_data_source() != NULL) {
                sf_filename.set_value(lc->get_data_source()->listview_source_name(*lc));
            }
        }
        sf_format.get_value().get_attrs().push_back(
            string_attr(lr, &view_curses::VC_STYLE,
                A_REVERSE | view_colors::ansi_color_pair(COLOR_CYAN, COLOR_BLACK)));
    };

private:
    status_field tss_fields[TSF__MAX];
};
#endif
<|endoftext|>


<commit_before><commit_msg>Add bubblesort implementation<commit_after><|endoftext|>


<commit_before><commit_msg>am 760f0994: am c0f18b9d: am c4c77d63: Merge "Add property for background GC type"<commit_after><|endoftext|>


<commit_before>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * trans/auto_impls.cpp
 * - Automatic trait/method impls
 *
 * Handles implementing Clone (when in 1.29 mode)
 */
#include "main_bindings.hpp"
#include "trans_list.hpp"
#include <hir/hir.hpp>
#include <mir/mir.hpp>
#include <hir_typeck/common.hpp>    // monomorph
#include <hir_typeck/static.hpp>    // StaticTraitResolve
#include <deque>
#include <algorithm>    // find_if

namespace {
    struct State
    {
        ::HIR::Crate&   crate;
        StaticTraitResolve resolve;
        const TransList& trans_list;
        ::std::deque<::HIR::TypeRef>    todo_list;
        ::std::set<::HIR::TypeRef>  done_list;

        ::HIR::SimplePath  lang_Clone;

        State(::HIR::Crate& crate, const TransList& trans_list):
            crate(crate),
            resolve( crate ),
            trans_list(trans_list)
        {
            lang_Clone = crate.get_lang_item_path(Span(), "clone");
        }

        void enqueue_type(const ::HIR::TypeRef& ty) {
            if( this->trans_list.auto_clone_impls.count(ty) == 0 && this->done_list.count(ty) == 0 ) {
                this->done_list.insert( ty.clone() );
                this->todo_list.push_back( ty.clone() );
            }
        }
    };
}

void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty)
{
    Span    sp;
    TRACE_FUNCTION_F(ty);

    // Create MIR
    ::MIR::Function mir_fcn;
    if( state.resolve.type_is_copy(sp, ty) )
    {
        ::MIR::BasicBlock   bb;
        bb.statements.push_back(::MIR::Statement::make_Assign({
            ::MIR::LValue::make_Return({}),
            ::MIR::RValue::make_Use( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) }) )
            }));
        bb.terminator = ::MIR::Terminator::make_Return({});
        mir_fcn.blocks.push_back(::std::move( bb ));
    }
    else
    {
        const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone");
        TU_MATCH_HDRA( (ty.m_data), {)
        default:
            TODO(sp, "auto Clone for " << ty << " - Not Copy");
        TU_ARMA(Tuple, te) {
            assert(te.size() > 0);

            ::std::vector< ::MIR::Param>   values;
            // For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone)
            for(const auto& subty : te)
            {
                auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast<unsigned>(values.size()) });
                if( state.resolve.type_is_copy(sp, subty) )
                {
                    values.push_back( ::std::move(fld_lvalue) );
                }
                else
                {
                    // Allocate to locals (one for the `&T`, the other for the cloned `T`)
                    auto borrow_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() );
                    mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone()));
                    auto res_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() );
                    mir_fcn.locals.push_back(subty.clone());

                    // Call `<T as Clone>::clone`, passing a borrow of the field
                    ::MIR::BasicBlock   bb;
                    bb.statements.push_back(::MIR::Statement::make_Assign({
                            borrow_lv.clone(),
                            ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) })
                            }));
                    bb.terminator = ::MIR::Terminator::make_Call({
                            static_cast<unsigned>(mir_fcn.blocks.size() + 2),  // return block (after the panic block below)
                            static_cast<unsigned>(mir_fcn.blocks.size() + 1),  // panic block (next block)
                            res_lv.clone(),
                            ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ),
                            ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) )
                            });
                    mir_fcn.blocks.push_back(::std::move( bb ));

                    // Stub panic handling (TODO: Make this iterate `values` and drop all of them)
                    ::MIR::BasicBlock   panic_bb;
                    bb.terminator = ::MIR::Terminator::make_Diverge({});
                    mir_fcn.blocks.push_back(::std::move( panic_bb ));

                    // Save the output of the `clone` call
                    values.push_back( ::std::move(res_lv) );
                }
            }

            // Construct the result tuple
            ::MIR::BasicBlock   bb;
            bb.statements.push_back(::MIR::Statement::make_Assign({
                ::MIR::LValue::make_Return({}),
                ::MIR::RValue::make_Tuple({ mv$(values) })
                }));
            bb.terminator = ::MIR::Terminator::make_Return({});
            mir_fcn.blocks.push_back(::std::move( bb ));
            }
        }
    }

    // Function
    ::HIR::Function fcn {
        /*m_save_code=*/false,
        ::HIR::Linkage {},
        ::HIR::Function::Receiver::BorrowShared,
        /*m_abi=*/ABI_RUST,
        /*m_unsafe =*/false,
        /*m_const=*/false,
        ::HIR::GenericParams {},
        /*m_args=*/::make_vec1(::std::make_pair(
            ::HIR::Pattern( ::HIR::PatternBinding(false, ::HIR::PatternBinding::Type::Move, "self", 0), ::HIR::Pattern::Data::make_Any({}) ),
            ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone())
            )),
        /*m_variadic=*/false,
        /*m_return=*/ty.clone(),
        ::HIR::ExprPtr {}
        };
    fcn.m_code.m_mir = ::MIR::FunctionPointer( new ::MIR::Function(mv$(mir_fcn)) );

    // Impl
    ::HIR::TraitImpl    impl;
    impl.m_type = mv$(ty);
    impl.m_methods.insert(::std::make_pair( ::std::string("clone"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::std::move(fcn) } ));

    // Add impl to the crate
    state.crate.m_trait_impls.insert(::std::make_pair( state.lang_Clone, ::std::move(impl) ));
}

void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list)
{
    if( TARGETVER_1_19 )
        return ;

    State   state { crate, trans_list };

    // Generate for all
    for(const auto& ty : trans_list.auto_clone_impls)
    {
        state.done_list.insert( ty.clone() );
        Trans_AutoImpl_Clone(state, ty.clone());
    }

    while( !state.todo_list.empty() )
    {
        auto ty = ::std::move(state.todo_list.front());
        state.todo_list.pop_back();

        Trans_AutoImpl_Clone(state, mv$(ty));
    }

    const auto impl_range = crate.m_trait_impls.equal_range( state.lang_Clone );
    for(const auto& ty : state.done_list)
    {
        // TODO: Find a way of turning a set into a vector so items can be erased.

        auto p = ::HIR::Path(ty.clone(), ::HIR::GenericPath(state.lang_Clone), "clone");
        //DEBUG("add_function(" << p << ")");
        auto e = trans_list.add_function(::std::move(p));

        auto it = ::std::find_if( impl_range.first, impl_range.second, [&](const auto& i){ return i.second.m_type == ty; });
        assert( it->second.m_methods.size() == 1 );
        e->ptr = &it->second.m_methods.begin()->second.data;
    }
}

<commit_msg>Trans Auto Impls - Clone for closures<commit_after>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * trans/auto_impls.cpp
 * - Automatic trait/method impls
 *
 * Handles implementing Clone (when in 1.29 mode)
 */
#include "main_bindings.hpp"
#include "trans_list.hpp"
#include <hir/hir.hpp>
#include <mir/mir.hpp>
#include <hir_typeck/common.hpp>    // monomorph
#include <hir_typeck/static.hpp>    // StaticTraitResolve
#include <deque>
#include <algorithm>    // find_if

namespace {
    struct State
    {
        ::HIR::Crate&   crate;
        StaticTraitResolve resolve;
        const TransList& trans_list;
        ::std::deque<::HIR::TypeRef>    todo_list;
        ::std::set<::HIR::TypeRef>  done_list;

        ::HIR::SimplePath  lang_Clone;

        State(::HIR::Crate& crate, const TransList& trans_list):
            crate(crate),
            resolve( crate ),
            trans_list(trans_list)
        {
            lang_Clone = crate.get_lang_item_path(Span(), "clone");
        }

        void enqueue_type(const ::HIR::TypeRef& ty) {
            if( this->trans_list.auto_clone_impls.count(ty) == 0 && this->done_list.count(ty) == 0 ) {
                this->done_list.insert( ty.clone() );
                this->todo_list.push_back( ty.clone() );
            }
        }
    };
}

namespace {
    ::MIR::Param clone_field(const State& state, const Span& sp, ::MIR::Function& mir_fcn, const ::HIR::TypeRef& subty, ::MIR::LValue fld_lvalue)
    {
        if( state.resolve.type_is_copy(sp, subty) )
        {
            return ::std::move(fld_lvalue);
        }
        else
        {
            const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone");
            // Allocate to locals (one for the `&T`, the other for the cloned `T`)
            auto borrow_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() );
            mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone()));
            auto res_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() );
            mir_fcn.locals.push_back(subty.clone());

            // Call `<T as Clone>::clone`, passing a borrow of the field
            ::MIR::BasicBlock   bb;
            bb.statements.push_back(::MIR::Statement::make_Assign({
                    borrow_lv.clone(),
                    ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(fld_lvalue) })
                    }));
            bb.terminator = ::MIR::Terminator::make_Call({
                    static_cast<unsigned>(mir_fcn.blocks.size() + 2),  // return block (after the panic block below)
                    static_cast<unsigned>(mir_fcn.blocks.size() + 1),  // panic block (next block)
                    res_lv.clone(),
                    ::MIR::CallTarget( ::HIR::Path(subty.clone(), lang_Clone, "clone") ),
                    ::make_vec1<::MIR::Param>( ::std::move(borrow_lv) )
                    });
            mir_fcn.blocks.push_back(::std::move( bb ));

            // Stub panic handling (TODO: Make this iterate `values` and drop all of them)
            ::MIR::BasicBlock   panic_bb;
            bb.terminator = ::MIR::Terminator::make_Diverge({});
            mir_fcn.blocks.push_back(::std::move( panic_bb ));

            // Save the output of the `clone` call
            return ::std::move(res_lv);
        }
    }
}

void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty)
{
    Span    sp;
    TRACE_FUNCTION_F(ty);

    // Create MIR
    ::MIR::Function mir_fcn;
    if( state.resolve.type_is_copy(sp, ty) )
    {
        ::MIR::BasicBlock   bb;
        bb.statements.push_back(::MIR::Statement::make_Assign({
            ::MIR::LValue::make_Return({}),
            ::MIR::RValue::make_Use( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) }) )
            }));
        bb.terminator = ::MIR::Terminator::make_Return({});
        mir_fcn.blocks.push_back(::std::move( bb ));
    }
    else
    {
        TU_MATCH_HDRA( (ty.m_data), {)
        default:
            TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy");
        TU_ARMA(Path, te) {
            // closures are identified by the name starting with 'closure#'
            if( TU_TEST1(te.path.m_data, Generic, .m_path.m_components.back().compare(0, 8, "closure#") == 0) ) {
                const auto& gp = te.path.m_data.as_Generic();
                const auto& str = state.resolve.m_crate.get_struct_by_path(sp, gp.m_path);
                Trans_Params p;
                p.sp = sp;
                p.pp_impl = gp.m_params.clone();
                ::std::vector< ::MIR::Param>   values; values.reserve( str.m_data.as_Tuple().size() );
                for(const auto& fld : str.m_data.as_Tuple())
                {
                    ::HIR::TypeRef  tmp;
                    const auto& ty_m = monomorphise_type_needed(fld.ent) ? (tmp = p.monomorph(state.resolve, fld.ent)) : fld.ent;
                    auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast<unsigned>(values.size()) });
                    values.push_back( clone_field(state, sp, mir_fcn, ty_m, mv$(fld_lvalue)) );
                }
                // Construct the result value
                ::MIR::BasicBlock   bb;
                bb.statements.push_back(::MIR::Statement::make_Assign({
                    ::MIR::LValue::make_Return({}),
                    ::MIR::RValue::make_Struct({ gp.clone(), mv$(values) })
                    }));
                bb.terminator = ::MIR::Terminator::make_Return({});
                mir_fcn.blocks.push_back(::std::move( bb ));
            }
            else {
                TODO(sp, "auto Clone for " << ty << " - Unknown and not Copy");
            }
            }
        TU_ARMA(Array, te) {
            ASSERT_BUG(sp, te.size_val < 256, "TODO: Is more than 256 elements sane for auto-generated non-Copy Clone impl? " << ty);
            ::std::vector< ::MIR::Param>   values; values.reserve(te.size_val);
            for(size_t i = 0; i < te.size_val; i ++)
            {
                auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast<unsigned>(i) });
                values.push_back( clone_field(state, sp, mir_fcn, *te.inner, mv$(fld_lvalue)) );
            }
            // Construct the result
            ::MIR::BasicBlock   bb;
            bb.statements.push_back(::MIR::Statement::make_Assign({
                ::MIR::LValue::make_Return({}),
                ::MIR::RValue::make_Array({ mv$(values) })
                }));
            bb.terminator = ::MIR::Terminator::make_Return({});
            mir_fcn.blocks.push_back(::std::move( bb ));
            }
        TU_ARMA(Tuple, te) {
            assert(te.size() > 0);

            ::std::vector< ::MIR::Param>   values; values.reserve(te.size());
            // For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone)
            for(const auto& subty : te)
            {
                auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast<unsigned>(values.size()) });
                values.push_back( clone_field(state, sp, mir_fcn, subty, mv$(fld_lvalue)) );
            }

            // Construct the result tuple
            ::MIR::BasicBlock   bb;
            bb.statements.push_back(::MIR::Statement::make_Assign({
                ::MIR::LValue::make_Return({}),
                ::MIR::RValue::make_Tuple({ mv$(values) })
                }));
            bb.terminator = ::MIR::Terminator::make_Return({});
            mir_fcn.blocks.push_back(::std::move( bb ));
            }
        }
    }

    // Function
    ::HIR::Function fcn {
        /*m_save_code=*/false,
        ::HIR::Linkage {},
        ::HIR::Function::Receiver::BorrowShared,
        /*m_abi=*/ABI_RUST,
        /*m_unsafe =*/false,
        /*m_const=*/false,
        ::HIR::GenericParams {},
        /*m_args=*/::make_vec1(::std::make_pair(
            ::HIR::Pattern( ::HIR::PatternBinding(false, ::HIR::PatternBinding::Type::Move, "self", 0), ::HIR::Pattern::Data::make_Any({}) ),
            ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone())
            )),
        /*m_variadic=*/false,
        /*m_return=*/ty.clone(),
        ::HIR::ExprPtr {}
        };
    fcn.m_code.m_mir = ::MIR::FunctionPointer( new ::MIR::Function(mv$(mir_fcn)) );

    // Impl
    ::HIR::TraitImpl    impl;
    impl.m_type = mv$(ty);
    impl.m_methods.insert(::std::make_pair( ::std::string("clone"), ::HIR::TraitImpl::ImplEnt< ::HIR::Function> { false, ::std::move(fcn) } ));

    // Add impl to the crate
    state.crate.m_trait_impls.insert(::std::make_pair( state.lang_Clone, ::std::move(impl) ));
}

void Trans_AutoImpls(::HIR::Crate& crate, TransList& trans_list)
{
    if( TARGETVER_1_19 )
        return ;

    State   state { crate, trans_list };

    // Generate for all
    for(const auto& ty : trans_list.auto_clone_impls)
    {
        state.done_list.insert( ty.clone() );
        Trans_AutoImpl_Clone(state, ty.clone());
    }

    while( !state.todo_list.empty() )
    {
        auto ty = ::std::move(state.todo_list.front());
        state.todo_list.pop_back();

        Trans_AutoImpl_Clone(state, mv$(ty));
    }

    const auto impl_range = crate.m_trait_impls.equal_range( state.lang_Clone );
    for(const auto& ty : state.done_list)
    {
        // TODO: Find a way of turning a set into a vector so items can be erased.

        auto p = ::HIR::Path(ty.clone(), ::HIR::GenericPath(state.lang_Clone), "clone");
        //DEBUG("add_function(" << p << ")");
        auto e = trans_list.add_function(::std::move(p));

        auto it = ::std::find_if( impl_range.first, impl_range.second, [&](const auto& i){ return i.second.m_type == ty; });
        assert( it->second.m_methods.size() == 1 );
        e->ptr = &it->second.m_methods.begin()->second.data;
    }
}

<|endoftext|>


<commit_before><commit_msg>[SQUASH] Make windows happy?<commit_after><|endoftext|>


<commit_before>#ifndef HMLIB_MEMORY_INC
#define HMLIB_MEMORY_INC 100
#
namespace hmLib{
	template<typename T,typename D = default_deleter<const T>>
	class clone_ptr{
	private:
		typedef T* pointer;
		typedef D deleter;
		typedef clone_ptr<T, D> my_type;
		typedef rvalue_reference<my_type> rvalue_reference;
	private:
		pointer ptr;
		deleter dlt;
	public:
		clone_ptr()
			:ptr(0)
			,dlt(){
		}
		explicit clone_ptr(pointer ptr_)
			:ptr(ptr_)
			,dlt(){
		}
		clone_ptr(pointer ptr_,deleter dlt_)
			:ptr(ptr_)
			,dlt(dlt_){
		}
		explicit clone_ptr(rvalue_reference mptr_)
			:ptr(mptr_.ref.get())
			,dlt(mptr_.ref.get_deleter()) {
			mptr_.ref.release();
		}
		const my_type& operator=(rvalue_reference mptr_) {
			if(this!=&(mptr_.ref)) {
				if(ptr)dlt(ptr);
				ptr=mptr_.ref.get();
				dlt=mptr_.ref.get_deleter();
				mptr_.ref.release();
			}
			return *this;
		}
		template<typename U>
		explicit clone_ptr(hmLib::rvalue_reference<clone_ptr<U, D> > mptr_)
			: ptr(mptr_.ref.get())
			, dlt(mptr_.ref.get_deleter()) {
			mptr_.ref.release();
		}
		template<typename U>
		const my_type& operator=(hmLib::rvalue_reference<clone_ptr<U, D> > mptr_) {
			if(ptr!=mptr_.ref.get()) {
				if(ptr)dlt(ptr);
				ptr=mptr_.ref.get();
				dlt=mptr_.ref.get_deleter();
				mptr_.ref.release();
			}
			return *this;
		}
		~clone_ptr() {
			if(ptr)dlt(ptr);
		}
		void swap(my_type& My_) {
			if(this==&My_)return;

			pointer tmp_ptr=ptr;
			deleter tmp_dlt=dlt;
			ptr=My_.ptr;
			dlt=My_.dlt;
			My_.ptr=tmp_ptr;
			My_.dlt=tmp_dlt;
		}
	private:
		//copy disable
		clone_ptr(const my_type&);
		const my_type& operator=(const my_type& My_);
	public:
		pointer get()const { return ptr; }
		deleter get_deleter()const { return dlt; }
		pointer release() {
			pointer ans=ptr;
			ptr=0;
			return ptr;
		}
		void reset(pointer ptr_=0) {
			if(ptr)dlt(ptr);
			ptr=ptr_;
			dlt=deleter();
		}
		void reset(pointer ptr_, deleter dlt_) {
			if(ptr)dlt(ptr);
			ptr=ptr_;
			dlt=dlt_;
		}
		operator bool() { return ptr!=0; }
		T& operator*() { return *ptr; }
		T* operator->() { return ptr; }
		const T& operator*() const { return *ptr; }
		const T* operator->() const { return ptr; }
	};
	template<typename T, typename D>
	class clone_ptr<T[],D>{
public:
	typedef clone_ptr<_Ty[], _Dx> _Myt;
	typedef _clone_ptr_base<_Ty, _Dx> _Mybase;
	typedef typename _Mybase::pointer pointer;
	typedef _Ty element_type;
	typedef _Dx deleter_type;

	using _Mybase::get_deleter;

	_CONST_FUN clone_ptr() _NOEXCEPT
		: _Mybase(pointer())
		{	// default construct
		static_assert(!is_pointer<_Dx>::value,
			"clone_ptr constructed with null deleter pointer");
		}

	template<class _Uty>
		using _Enable_ctor_reset = enable_if_t<
			is_same<_Uty, pointer>::value
			|| (is_same<pointer, element_type *>::value
			&& is_pointer<_Uty>::value
			&& is_convertible<
				remove_pointer_t<_Uty>(*)[],
				element_type(*)[]
			>::value)>;

	template<class _Uty,
		class = _Enable_ctor_reset<_Uty> >
	explicit clone_ptr(_Uty _Ptr) _NOEXCEPT
		: _Mybase(_Ptr)
		{	// construct with pointer
		static_assert(!is_pointer<_Dx>::value,
			"clone_ptr constructed with null deleter pointer");
		}

	template<class _Uty,
		class = _Enable_ctor_reset<_Uty> >
	clone_ptr(_Uty _Ptr,
		typename _If<is_reference<_Dx>::value, _Dx,
			const typename remove_reference<_Dx>::type&>::type _Dt) _NOEXCEPT
		: _Mybase(_Ptr, _Dt)
		{	// construct with pointer and (maybe const) deleter&
		}

	template<class _Uty,
		class = _Enable_ctor_reset<_Uty> >
	clone_ptr(_Uty _Ptr,
		typename remove_reference<_Dx>::type&& _Dt) _NOEXCEPT
		: _Mybase(_Ptr, _STD move(_Dt))
		{	// construct by moving deleter
		static_assert(!is_reference<_Dx>::value,
			"clone_ptr constructed with reference to rvalue deleter");
		}

	clone_ptr(clone_ptr&& _Right) _NOEXCEPT
		: _Mybase(_Right.release(),
			_STD forward<_Dx>(_Right.get_deleter()))
		{	// construct by moving _Right
		}

	_Myt& operator=(_Myt&& _Right) _NOEXCEPT
		{	// assign by moving _Right
		if (this != &_Right)
			{	// different, do the swap
			reset(_Right.release());
			this->get_deleter() = _STD move(_Right.get_deleter());
			}
		return (*this);
		}

	template<class _Uty,
		class _Ex,
		bool _More,
		class _UP_pointer = typename clone_ptr<_Uty, _Ex>::pointer,
		class _UP_element_type = typename clone_ptr<_Uty, _Ex>::element_type>
		using _Enable_conversion = enable_if_t<
			is_array<_Uty>::value
			&& is_same<pointer, element_type *>::value
			&& is_same<_UP_pointer, _UP_element_type *>::value
			&& is_convertible<_UP_element_type(*)[], element_type(*)[]>::value
			&& _More>;

	template<class _Uty,
		class _Ex,
		class = _Enable_conversion<_Uty, _Ex,
			is_reference<_Dx>::value
			? is_same<_Ex, _Dx>::value
			: is_convertible<_Ex, _Dx>::value> >
		clone_ptr(clone_ptr<_Uty, _Ex>&& _Right) _NOEXCEPT
			: _Mybase(_Right.release(),
				_STD forward<_Ex>(_Right.get_deleter()))
		{	// construct by moving _Right
		}

	template<class _Uty,
		class _Ex,
		class = _Enable_conversion<_Uty, _Ex,
			is_assignable<_Dx&, _Ex&&>::value> >
		_Myt& operator=(clone_ptr<_Uty, _Ex>&& _Right) _NOEXCEPT
		{	// assign by moving _Right
		reset(_Right.release());
		this->get_deleter() = _STD forward<_Ex>(_Right.get_deleter());
		return (*this);
		}

	_CONST_FUN clone_ptr(nullptr_t) _NOEXCEPT
		: _Mybase(pointer())
		{	// null pointer construct
		static_assert(!is_pointer<_Dx>::value,
			"clone_ptr constructed with null deleter pointer");
		}

	_Myt& operator=(nullptr_t) _NOEXCEPT
		{	// assign a null pointer
		reset();
		return (*this);
		}

	void reset(nullptr_t = nullptr_t()) _NOEXCEPT
		{	// establish new null pointer
		reset(pointer());
		}

	void swap(_Myt& _Right) _NOEXCEPT
		{	// swap elements
		_Swap_adl(this->_Myptr(), _Right._Myptr());
		_Swap_adl(this->get_deleter(), _Right.get_deleter());
		}

	~clone_ptr() _NOEXCEPT
		{	// destroy the object
		_Delete();
		}

	_Ty& operator[](size_t _Idx) const
		{	// return reference to object
		return (get()[_Idx]);
		}

	pointer get() const _NOEXCEPT
		{	// return pointer to object
		return (this->_Myptr());
		}

	explicit operator bool() const _NOEXCEPT
		{	// test for non-null pointer
		return (get() != pointer());
		}

	pointer release() _NOEXCEPT
		{	// yield ownership of pointer
		pointer _Ans = get();
		this->_Myptr() = pointer();
		return (_Ans);
		}

	template<class _Uty,
		class = _Enable_ctor_reset<_Uty> >
	void reset(_Uty _Ptr) _NOEXCEPT
		{	// establish new pointer
		pointer _Old = get();
		this->_Myptr() = _Ptr;
		if (_Old != pointer())
			this->get_deleter()(_Old);
	}

	clone_ptr(const _Myt&) = delete;

	_Myt& operator=(const _Myt&) = delete;

	private:
		void _Delete(){	// delete the pointer
		if (get() != pointer())
			this->get_deleter()(get());
		}
	};
}
#ifdef HMLIB_MEMORY_STD
namespace std{

}
#endif
#
#endif
<commit_msg>Remove memory.hpp<commit_after><|endoftext|>


<commit_before><commit_msg>important fix in conversion function<commit_after><|endoftext|>


<commit_before>#include <iostream>

int main() {

  int sum, n1, n2;

  std::cout << "Enter n1: ";
  std::cin >> n1;

  std::cout << "Enter n2: ";
  std::cin >> n2;

  sum = n1+n2;

  std::cout << std::endl;
  std::cout << "The sum is: " << sum << std::endl;

  return 0;
}
<commit_msg>redundant<commit_after><|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "MockupNetworkManager.hpp"
#include "MockupNetworkEventListener.hpp"

using namespace rd;

//-- Class for the setup of each test
//--------------------------------------------------------------------------------------
class MockupNetworkManagerTest : public testing::Test
{
    public:
        virtual void SetUp()
        {
            MockupNetworkManager::RegisterManager();
            networkManager = (MockupNetworkManager *) RdNetworkManager::getNetworkManager(MockupNetworkManager::id);

            me = RdPlayer(0, "me", 100, 100, 0, 0);
            other_player = RdPlayer(1, "dummy", 100, 100, 1, 0);
        }

        virtual void TearDown()
        {
            RdNetworkManager::destroyNetworkManager();
        }

    protected:
        MockupNetworkManager * networkManager;
        RdPlayer me, other_player;
};

//-- Things that are being tested
//-----------------------------------------------------------------------------------------------------
TEST_F(MockupNetworkManagerTest, PlayerCreatedWhenLogin)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    std::vector<RdPlayer> players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, ErrorLoginTwice)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    std::vector<RdPlayer> players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_FALSE(networkManager->login(other_player));
    ASSERT_TRUE(networkManager->isLoggedIn());

    players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, PlayerRemovedOnLogout)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    std::vector<RdPlayer> players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->logout(me));
    EXPECT_FALSE(networkManager->isLoggedIn());

    players = networkManager->getPlayerData();
    ASSERT_EQ(0, players.size());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, ErrorLogoutTwice)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    std::vector<RdPlayer> players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->logout(me));
    EXPECT_FALSE(networkManager->isLoggedIn());

    players = networkManager->getPlayerData();
    ASSERT_EQ(0, players.size());

    EXPECT_FALSE(networkManager->logout(me));
    EXPECT_FALSE(networkManager->isLoggedIn());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, SetPlayerAddsPlayer)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    std::vector<RdPlayer> players;
    players.push_back(me);
    players.push_back(other_player);

    EXPECT_TRUE(networkManager->setPlayerData(players));

    players = networkManager->getPlayerData();
    ASSERT_EQ(2, players.size());
    EXPECT_EQ(0, players[0].getId());
    EXPECT_EQ(1, players[1].getId());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, PlayerDamagedWhenShot)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    std::vector<RdPlayer> players;
    players.push_back(me);
    players.push_back(other_player);

    EXPECT_TRUE(networkManager->setPlayerData(players));
    ASSERT_TRUE(networkManager->setLoggedIn(true));

    players = networkManager->getPlayerData();
    ASSERT_EQ(2, players.size());

    ASSERT_TRUE(networkManager->sendPlayerHit(other_player, 100));

    players = networkManager->getPlayerData();
    ASSERT_EQ(2, players.size());
    EXPECT_EQ(0, players[1].getHealth());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, ListenersNotifiedOnEvent)
{
    MockupNetworkEventListener listener;
    RdNetworkEventListener * plistener = (RdNetworkEventListener *) &listener;
    ASSERT_TRUE(((RdNetworkManager*)networkManager)->addNetworkEventListener(plistener));

    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    /* Check that data > 0 and check contents */
    std::vector<RdPlayer> players = listener.getStoredPlayers();

    EXPECT_EQ(1, listener.getDataArrived());
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}
<commit_msg>Add new test case for MockupNetworkManager (integration with mentalMap)<commit_after>#include "gtest/gtest.h"
#include "MockupNetworkManager.hpp"
#include "MockupNetworkEventListener.hpp"

using namespace rd;

//-- Class for the setup of each test
//--------------------------------------------------------------------------------------
class MockupNetworkManagerTest : public testing::Test
{
    public:
        virtual void SetUp()
        {
            MockupNetworkManager::RegisterManager();
            networkManager = (MockupNetworkManager *) RdNetworkManager::getNetworkManager(MockupNetworkManager::id);

            me = RdPlayer(0, "me", 100, 100, 0, 0);
            other_player = RdPlayer(1, "dummy", 100, 100, 1, 0);
        }

        virtual void TearDown()
        {
            RdNetworkManager::destroyNetworkManager();
        }

    protected:
        MockupNetworkManager * networkManager;
        RdPlayer me, other_player;
};

//-- Things that are being tested
//-----------------------------------------------------------------------------------------------------
TEST_F(MockupNetworkManagerTest, PlayerCreatedWhenLogin)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    std::vector<RdPlayer> players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, ErrorLoginTwice)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    std::vector<RdPlayer> players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_FALSE(networkManager->login(other_player));
    ASSERT_TRUE(networkManager->isLoggedIn());

    players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, PlayerRemovedOnLogout)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    std::vector<RdPlayer> players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->logout(me));
    EXPECT_FALSE(networkManager->isLoggedIn());

    players = networkManager->getPlayerData();
    ASSERT_EQ(0, players.size());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, ErrorLogoutTwice)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    std::vector<RdPlayer> players = networkManager->getPlayerData();
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->logout(me));
    EXPECT_FALSE(networkManager->isLoggedIn());

    players = networkManager->getPlayerData();
    ASSERT_EQ(0, players.size());

    EXPECT_FALSE(networkManager->logout(me));
    EXPECT_FALSE(networkManager->isLoggedIn());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, SetPlayerAddsPlayer)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    std::vector<RdPlayer> players;
    players.push_back(me);
    players.push_back(other_player);

    EXPECT_TRUE(networkManager->setPlayerData(players));

    players = networkManager->getPlayerData();
    ASSERT_EQ(2, players.size());
    EXPECT_EQ(0, players[0].getId());
    EXPECT_EQ(1, players[1].getId());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, PlayerDamagedWhenShot)
{
    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    std::vector<RdPlayer> players;
    players.push_back(me);
    players.push_back(other_player);

    EXPECT_TRUE(networkManager->setPlayerData(players));
    ASSERT_TRUE(networkManager->setLoggedIn(true));

    players = networkManager->getPlayerData();
    ASSERT_EQ(2, players.size());

    ASSERT_TRUE(networkManager->sendPlayerHit(other_player, 100));

    players = networkManager->getPlayerData();
    ASSERT_EQ(2, players.size());
    EXPECT_EQ(0, players[1].getHealth());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, ListenersNotifiedOnEvent)
{
    MockupNetworkEventListener listener;
    RdNetworkEventListener * plistener = (RdNetworkEventListener *) &listener;
    ASSERT_TRUE(((RdNetworkManager*)networkManager)->addNetworkEventListener(plistener));

    ASSERT_TRUE(networkManager->start());
    ASSERT_FALSE(networkManager->isStopped());

    ASSERT_TRUE(networkManager->login(me));
    ASSERT_TRUE(networkManager->isLoggedIn());

    /* Check that data > 0 and check contents */
    std::vector<RdPlayer> players = listener.getStoredPlayers();

    EXPECT_EQ(1, listener.getDataArrived());
    ASSERT_EQ(1, players.size());
    EXPECT_EQ(0, players[0].getId());

    ASSERT_TRUE(networkManager->stop());
    ASSERT_TRUE(networkManager->isStopped());
}

TEST_F(MockupNetworkManagerTest, ManagerIsIntegratedWithMentalMap)
{
    ASSERT_FALSE(true);
}
<|endoftext|>


<commit_before>// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

int Global;

void *Thread1(void *x) {
  sleep(1);
  Global++;
  return NULL;
}

void *Thread2(void *x) {
  pthread_mutex_t mtx;
  pthread_mutex_init(&mtx, 0);
  pthread_mutex_lock(&mtx);
  Global--;
  pthread_mutex_unlock(&mtx);
  pthread_mutex_destroy(&mtx);
  return NULL;
}

int main() {
  pthread_t t[2];
  pthread_create(&t[0], NULL, Thread1, NULL);
  pthread_create(&t[1], NULL, Thread2, NULL);
  pthread_join(t[0], NULL);
  pthread_join(t[1], NULL);
}

// CHECK: WARNING: ThreadSanitizer: data race
// CHECK: Write of size 4 at {{.*}} by thread T1:
// CHECK: Previous write of size 4 at {{.*}} by thread T2
// CHECK:                                      (mutexes: write [[M1:M[0-9]+]]):
// CHECK: Mutex [[M1]] is already destroyed
// CHECK-NOT: Mutex {{.*}} created at

<commit_msg>tsan: fix flaky test<commit_after>// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

int Global;
__thread int huge[1024*1024];

void *Thread1(void *x) {
  sleep(1);
  Global++;
  return NULL;
}

void *Thread2(void *x) {
  pthread_mutex_t mtx;
  pthread_mutex_init(&mtx, 0);
  pthread_mutex_lock(&mtx);
  Global--;
  pthread_mutex_unlock(&mtx);
  pthread_mutex_destroy(&mtx);
  return NULL;
}

int main() {
  pthread_t t[2];
  pthread_create(&t[0], NULL, Thread1, NULL);
  pthread_create(&t[1], NULL, Thread2, NULL);
  pthread_join(t[0], NULL);
  pthread_join(t[1], NULL);
}

// CHECK: WARNING: ThreadSanitizer: data race
// CHECK: Write of size 4 at {{.*}} by thread T1:
// CHECK: Previous write of size 4 at {{.*}} by thread T2
// CHECK:                                      (mutexes: write [[M1:M[0-9]+]]):
// CHECK: Mutex [[M1]] is already destroyed
// CHECK-NOT: Mutex {{.*}} created at

<|endoftext|>