<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 "libtorrent/pch.hpp"

#include <algorithm>
#include <iostream>
#include <iomanip>
#include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp"

#if defined(_MSC_VER)
namespace std
{
	using ::isprint;
}
#define for if (false) {} else for
#endif

namespace
{
	template <class T>
	void call_destructor(T* o)
	{
		TORRENT_ASSERT(o);
		o->~T();
	}

	struct compare_string
	{
		compare_string(char const* s): m_str(s)  {}

		bool operator()(
			std::pair<std::string
			, libtorrent::entry> const& e) const
		{
			return m_str && e.first == m_str;
		}
		char const* m_str;
	};
}

namespace libtorrent
{
	namespace detail
	{
		TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val)
		{
			int sign = 0;
			if (val < 0)
			{
				sign = 1;
				val = -val;
			}
			buf[--size] = '\0';
			if (val == 0) buf[--size] = '0';
			for (; size > sign && val != 0;)
			{
				buf[--size] = '0' + char(val % 10);
				val /= 10;
			}
			if (sign) buf[--size] = '-';
			return buf + size;
		}
	}

	entry& entry::operator[](char const* key)
	{
		dictionary_type::iterator i = dict().find(key);
		if (i != dict().end()) return i->second;
		dictionary_type::iterator ret = dict().insert(
			dict().begin()
			, std::make_pair(std::string(key), entry()));
		return ret->second;
	}

	entry& entry::operator[](std::string const& key)
	{
		return (*this)[key.c_str()];
	}

	entry* entry::find_key(char const* key)
	{
		dictionary_type::iterator i = std::find_if(
			dict().begin()
			, dict().end()
			, compare_string(key));
		if (i == dict().end()) return 0;
		return &i->second;

	}

	entry const* entry::find_key(char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) return 0;
		return &i->second;
	}

#ifndef BOOST_NO_EXCEPTIONS
	const entry& entry::operator[](char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) throw type_error(
			(std::string("key not found: ") + key).c_str());
		return i->second;
	}

	const entry& entry::operator[](std::string const& key) const
	{
		return (*this)[key.c_str()];
	}
#endif

	entry::entry(): m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(data_type t): m_type(t)
	{
		construct(t);
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(const entry& e)
	{
		copy(e);
#ifndef NDEBUG
		m_type_queried = e.m_type_queried;
#endif
	}

	entry::entry(dictionary_type const& v)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	entry::entry(string_type const& v)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) string_type(v);
		m_type = string_t;
	}

	entry::entry(list_type const& v)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) list_type(v);
		m_type = list_t;
	}

	entry::entry(integer_type const& v)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) integer_type(v);
		m_type = int_t;
	}

	void entry::operator=(dictionary_type const& v)
	{
		destruct();
		new(data) dictionary_type(v);
		m_type = dictionary_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(string_type const& v)
	{
		destruct();
		new(data) string_type(v);
		m_type = string_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(list_type const& v)
	{
		destruct();
		new(data) list_type(v);
		m_type = list_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(integer_type const& v)
	{
		destruct();
		new(data) integer_type(v);
		m_type = int_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	bool entry::operator==(entry const& e) const
	{
		if (m_type != e.m_type) return false;

		switch(m_type)
		{
		case int_t:
			return integer() == e.integer();
		case string_t:
			return string() == e.string();
		case list_t:
			return list() == e.list();
		case dictionary_t:
			return dict() == e.dict();
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			return true;
		}
	}

	void entry::construct(data_type t)
	{
		m_type = t;
		switch(m_type)
		{
		case int_t:
			new(data) integer_type;
			break;
		case string_t:
			new(data) string_type;
			break;
		case list_t:
			new(data) list_type;
			break;
		case dictionary_t:
			new (data) dictionary_type;
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			m_type = undefined_t;
		}
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::copy(entry const& e)
	{
		m_type = e.type();
		switch(m_type)
		{
		case int_t:
			new(data) integer_type(e.integer());
			break;
		case string_t:
			new(data) string_type(e.string());
			break;
		case list_t:
			new(data) list_type(e.list());
			break;
		case dictionary_t:
			new (data) dictionary_type(e.dict());
			break;
		default:
			m_type = undefined_t;
		}
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::destruct()
	{
		switch(m_type)
		{
		case int_t:
			call_destructor(reinterpret_cast<integer_type*>(data));
			break;
		case string_t:
			call_destructor(reinterpret_cast<string_type*>(data));
			break;
		case list_t:
			call_destructor(reinterpret_cast<list_type*>(data));
			break;
		case dictionary_t:
			call_destructor(reinterpret_cast<dictionary_type*>(data));
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			break;
		}
#ifndef NDEBUG
		m_type_queried = false;
#endif
	}

	void entry::swap(entry& e)
	{
		// not implemented
		TORRENT_ASSERT(false);
	}

	void entry::print(std::ostream& os, int indent) const
	{
		TORRENT_ASSERT(indent >= 0);
		for (int i = 0; i < indent; ++i) os << " ";
		switch (m_type)
		{
		case int_t:
			os << integer() << "\n";
			break;
		case string_t:
			{
				bool binary_string = false;
				for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
				{
					if (!std::isprint(static_cast<unsigned char>(*i)))
					{
						binary_string = true;
						break;
					}
				}
				if (binary_string)
				{
					os.unsetf(std::ios_base::dec);
					os.setf(std::ios_base::hex);
					for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
						os << std::setfill('0') << std::setw(2)
							<< static_cast<unsigned int>((unsigned char)*i);
					os.unsetf(std::ios_base::hex);
					os.setf(std::ios_base::dec);
					os << "\n";
				}
				else
				{
					os << string() << "\n";
				}
			} break;
		case list_t:
			{
				os << "list\n";
				for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
				{
					i->print(os, indent+1);
				}
			} break;
		case dictionary_t:
			{
				os << "dictionary\n";
				for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
				{
					for (int j = 0; j < indent+1; ++j) os << " ";
					os << "[" << i->first << "]";
					if (i->second.type() != entry::string_t
						&& i->second.type() != entry::int_t)
						os << "\n";
					else os << " ";
					i->second.print(os, indent+2);
				}
			} break;
		default:
			os << "<uninitialized>\n";
		}
	}
}

<commit_msg>exception safety fixes to entry.cpp<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author 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 "libtorrent/pch.hpp"

#include <algorithm>
#include <iostream>
#include <iomanip>
#include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp"

#if defined(_MSC_VER)
namespace std
{
	using ::isprint;
}
#define for if (false) {} else for
#endif

namespace
{
	template <class T>
	void call_destructor(T* o)
	{
		TORRENT_ASSERT(o);
		o->~T();
	}

	struct compare_string
	{
		compare_string(char const* s): m_str(s)  {}

		bool operator()(
			std::pair<std::string
			, libtorrent::entry> const& e) const
		{
			return m_str && e.first == m_str;
		}
		char const* m_str;
	};
}

namespace libtorrent
{
	namespace detail
	{
		TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val)
		{
			int sign = 0;
			if (val < 0)
			{
				sign = 1;
				val = -val;
			}
			buf[--size] = '\0';
			if (val == 0) buf[--size] = '0';
			for (; size > sign && val != 0;)
			{
				buf[--size] = '0' + char(val % 10);
				val /= 10;
			}
			if (sign) buf[--size] = '-';
			return buf + size;
		}
	}

	entry& entry::operator[](char const* key)
	{
		dictionary_type::iterator i = dict().find(key);
		if (i != dict().end()) return i->second;
		dictionary_type::iterator ret = dict().insert(
			dict().begin()
			, std::make_pair(std::string(key), entry()));
		return ret->second;
	}

	entry& entry::operator[](std::string const& key)
	{
		return (*this)[key.c_str()];
	}

	entry* entry::find_key(char const* key)
	{
		dictionary_type::iterator i = std::find_if(
			dict().begin()
			, dict().end()
			, compare_string(key));
		if (i == dict().end()) return 0;
		return &i->second;

	}

	entry const* entry::find_key(char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) return 0;
		return &i->second;
	}

#ifndef BOOST_NO_EXCEPTIONS
	const entry& entry::operator[](char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) throw type_error(
			(std::string("key not found: ") + key).c_str());
		return i->second;
	}

	const entry& entry::operator[](std::string const& key) const
	{
		return (*this)[key.c_str()];
	}
#endif

	entry::entry()
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(data_type t)
		: m_type(undefined_t)
	{
		construct(t);
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	entry::entry(const entry& e)
		: m_type(undefined_t)
	{
		copy(e);
#ifndef NDEBUG
		m_type_queried = e.m_type_queried;
#endif
	}

	entry::entry(dictionary_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	entry::entry(string_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) string_type(v);
		m_type = string_t;
	}

	entry::entry(list_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) list_type(v);
		m_type = list_t;
	}

	entry::entry(integer_type const& v)
		: m_type(undefined_t)
	{
#ifndef NDEBUG
		m_type_queried = true;
#endif
		new(data) integer_type(v);
		m_type = int_t;
	}

	void entry::operator=(dictionary_type const& v)
	{
		destruct();
		new(data) dictionary_type(v);
		m_type = dictionary_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(string_type const& v)
	{
		destruct();
		new(data) string_type(v);
		m_type = string_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(list_type const& v)
	{
		destruct();
		new(data) list_type(v);
		m_type = list_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::operator=(integer_type const& v)
	{
		destruct();
		new(data) integer_type(v);
		m_type = int_t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	bool entry::operator==(entry const& e) const
	{
		if (m_type != e.m_type) return false;

		switch(m_type)
		{
		case int_t:
			return integer() == e.integer();
		case string_t:
			return string() == e.string();
		case list_t:
			return list() == e.list();
		case dictionary_t:
			return dict() == e.dict();
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			return true;
		}
	}

	void entry::construct(data_type t)
	{
		switch(t)
		{
		case int_t:
			new(data) integer_type;
			break;
		case string_t:
			new(data) string_type;
			break;
		case list_t:
			new(data) list_type;
			break;
		case dictionary_t:
			new (data) dictionary_type;
			break;
		default:
			TORRENT_ASSERT(t == undefined_t);
		}
		m_type = t;
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::copy(entry const& e)
	{
		switch (e.type())
		{
		case int_t:
			new(data) integer_type(e.integer());
			break;
		case string_t:
			new(data) string_type(e.string());
			break;
		case list_t:
			new(data) list_type(e.list());
			break;
		case dictionary_t:
			new (data) dictionary_type(e.dict());
			break;
		default:
			TORRENT_ASSERT(e.type() == undefined_t);
		}
		m_type = e.type();
#ifndef NDEBUG
		m_type_queried = true;
#endif
	}

	void entry::destruct()
	{
		switch(m_type)
		{
		case int_t:
			call_destructor(reinterpret_cast<integer_type*>(data));
			break;
		case string_t:
			call_destructor(reinterpret_cast<string_type*>(data));
			break;
		case list_t:
			call_destructor(reinterpret_cast<list_type*>(data));
			break;
		case dictionary_t:
			call_destructor(reinterpret_cast<dictionary_type*>(data));
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			break;
		}
		m_type = undefined_t;
#ifndef NDEBUG
		m_type_queried = false;
#endif
	}

	void entry::swap(entry& e)
	{
		// not implemented
		TORRENT_ASSERT(false);
	}

	void entry::print(std::ostream& os, int indent) const
	{
		TORRENT_ASSERT(indent >= 0);
		for (int i = 0; i < indent; ++i) os << " ";
		switch (m_type)
		{
		case int_t:
			os << integer() << "\n";
			break;
		case string_t:
			{
				bool binary_string = false;
				for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
				{
					if (!std::isprint(static_cast<unsigned char>(*i)))
					{
						binary_string = true;
						break;
					}
				}
				if (binary_string)
				{
					os.unsetf(std::ios_base::dec);
					os.setf(std::ios_base::hex);
					for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
						os << std::setfill('0') << std::setw(2)
							<< static_cast<unsigned int>((unsigned char)*i);
					os.unsetf(std::ios_base::hex);
					os.setf(std::ios_base::dec);
					os << "\n";
				}
				else
				{
					os << string() << "\n";
				}
			} break;
		case list_t:
			{
				os << "list\n";
				for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
				{
					i->print(os, indent+1);
				}
			} break;
		case dictionary_t:
			{
				os << "dictionary\n";
				for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
				{
					for (int j = 0; j < indent+1; ++j) os << " ";
					os << "[" << i->first << "]";
					if (i->second.type() != entry::string_t
						&& i->second.type() != entry::int_t)
						os << "\n";
					else os << " ";
					i->second.print(os, indent+2);
				}
			} break;
		default:
			os << "<uninitialized>\n";
		}
	}
}

<|endoftext|>


<commit_before>#include "mmap_reader.hpp"

#include "../std/target_os.hpp"
#include "../std/memcpy.hpp"

// @TODO we don't support windows at the moment
#ifndef OMIM_OS_WINDOWS
  #include <sys/mman.h>
  #include <sys/stat.h>
  #include <sys/fcntl.h>
  #include <unistd.h>
#endif

class MmapReader::MmapData
{
  int m_fd;

public:
  uint8_t * m_memory;
  uint64_t m_size;

  MmapData(string const & fileName)
  {
    // @TODO add windows support
#ifndef OMIM_OS_WINDOWS
    m_fd = open(fileName.c_str(), O_RDONLY | O_NONBLOCK);
    if (m_fd == -1)
      MYTHROW(OpenException, ("open failed for file", fileName));

    struct stat s;
    if (-1 == fstat(m_fd, &s))
      MYTHROW(OpenException, ("fstat failed for file", fileName));
    m_size = s.st_size;

    m_memory = (uint8_t *)mmap(0, m_size, PROT_READ, MAP_SHARED, m_fd, 0);
    if (m_memory == MAP_FAILED)
    {
      close(m_fd);
      MYTHROW(OpenException, ("mmap failed for file", fileName));
    }
#endif
  }

  ~MmapData()
  {
    // @TODO add windows support
#ifndef OMIM_OS_WINDOWS
    munmap(m_memory, m_size);
    close(m_fd);
#endif
  }
};

MmapReader::MmapReader(string const & fileName)
  : base_type(fileName), m_offset(0)
{
  m_data = shared_ptr<MmapData>(new MmapData(fileName));
  m_size = m_data->m_size;
}

MmapReader::MmapReader(MmapReader const & reader, uint64_t offset, uint64_t size)
  : base_type(reader.GetName()), m_data(reader.m_data),
    m_offset(offset), m_size(size)
{
}

uint64_t MmapReader::Size() const
{
  return m_size;
}

void MmapReader::Read(uint64_t pos, void * p, size_t size) const
{
  ASSERT_LESS_OR_EQUAL(pos + size, Size(), (pos, size));
  memcpy(p, m_data->m_memory + m_offset + pos, size);
}

MmapReader * MmapReader::CreateSubReader(uint64_t pos, uint64_t size) const
{
  ASSERT_LESS_OR_EQUAL(pos + size, Size(), (pos, size));
  return new MmapReader(*this, m_offset + pos, size);
}

uint8_t * MmapReader::Data() const
{
  return m_data->m_memory;
}
<commit_msg>[android] Compilation fixes<commit_after>#include "mmap_reader.hpp"

#include "../std/target_os.hpp"
#include "../std/memcpy.hpp"

// @TODO we don't support windows at the moment
#ifndef OMIM_OS_WINDOWS
  #include <unistd.h>
  #include <sys/mman.h>
  #include <sys/stat.h>
  #ifdef OMIM_OS_ANDROID
    #include <fcntl.h>
  #else
    #include <sys/fcntl.h>
  #endif
#endif

class MmapReader::MmapData
{
  int m_fd;

public:
  uint8_t * m_memory;
  uint64_t m_size;

  MmapData(string const & fileName)
  {
    // @TODO add windows support
#ifndef OMIM_OS_WINDOWS
    m_fd = open(fileName.c_str(), O_RDONLY | O_NONBLOCK);
    if (m_fd == -1)
      MYTHROW(OpenException, ("open failed for file", fileName));

    struct stat s;
    if (-1 == fstat(m_fd, &s))
      MYTHROW(OpenException, ("fstat failed for file", fileName));
    m_size = s.st_size;

    m_memory = (uint8_t *)mmap(0, m_size, PROT_READ, MAP_SHARED, m_fd, 0);
    if (m_memory == MAP_FAILED)
    {
      close(m_fd);
      MYTHROW(OpenException, ("mmap failed for file", fileName));
    }
#endif
  }

  ~MmapData()
  {
    // @TODO add windows support
#ifndef OMIM_OS_WINDOWS
    munmap(m_memory, m_size);
    close(m_fd);
#endif
  }
};

MmapReader::MmapReader(string const & fileName)
  : base_type(fileName), m_offset(0)
{
  m_data = shared_ptr<MmapData>(new MmapData(fileName));
  m_size = m_data->m_size;
}

MmapReader::MmapReader(MmapReader const & reader, uint64_t offset, uint64_t size)
  : base_type(reader.GetName()), m_data(reader.m_data),
    m_offset(offset), m_size(size)
{
}

uint64_t MmapReader::Size() const
{
  return m_size;
}

void MmapReader::Read(uint64_t pos, void * p, size_t size) const
{
  ASSERT_LESS_OR_EQUAL(pos + size, Size(), (pos, size));
  memcpy(p, m_data->m_memory + m_offset + pos, size);
}

MmapReader * MmapReader::CreateSubReader(uint64_t pos, uint64_t size) const
{
  ASSERT_LESS_OR_EQUAL(pos + size, Size(), (pos, size));
  return new MmapReader(*this, m_offset + pos, size);
}

uint8_t * MmapReader::Data() const
{
  return m_data->m_memory;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Script Generator project on Qt Labs.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "setupgenerator.h"
#include "shellgenerator.h"
#include "reporthandler.h"
#include "fileout.h"

//#define Q_SCRIPT_LAZY_GENERATOR

void SetupGenerator::addClass(const QString& package, const AbstractMetaClass *cls)
{
  packHash[package].append(cls);
}

void maybeDeclareMetaType(QTextStream &stream, const QString &typeName,
                          QSet<QString> &registeredTypeNames);
bool hasDefaultConstructor(const AbstractMetaClass *meta_class);

static QStringList getOperatorCodes(const AbstractMetaClass* cls) {
  QSet<QString> operatorCodes;
  AbstractMetaFunctionList returned;
  AbstractMetaFunctionList functions = cls->functions();
  foreach (AbstractMetaFunction *function, functions) {
    if (function->originalName().startsWith("operator")) {
      QString op = function->originalName().mid(8);
      operatorCodes.insert(op);
    }
  }
  QSet<QString> r;
  foreach(QString op, operatorCodes.toList()) {
    if (op == ">" || op == "<" || op == ">=" || op == "<=" || op == "==" || op == "!=") {
      r.insert("PythonQt::Type_RichCompare");
    } else if (op == "+") {
      r.insert("PythonQt::Type_Add");
    } else if (op == "-") {
      r.insert("PythonQt::Type_Subtract");
    } else if (op == "/") {
      r.insert("PythonQt::Type_Divide");
    } else if (op == "*") {
      r.insert("PythonQt::Type_Multiply");
    } else if (op == "%") {
      r.insert("PythonQt::Type_Mod");
    } else if (op == "&") {
      r.insert("PythonQt::Type_And");
    } else if (op == "|") {
      r.insert("PythonQt::Type_Or");
    } else if (op == "^") {
      r.insert("PythonQt::Type_Xor");
    } else if (op == "~") {
      r.insert("PythonQt::Type_Invert");

    } else if (op == "+=") {
      r.insert("PythonQt::Type_InplaceAdd");
    } else if (op == "-=") {
      r.insert("PythonQt::Type_InplaceSubtract");
    } else if (op == "/=") {
      r.insert("PythonQt::Type_InplaceDivide");
    } else if (op == "*=") {
      r.insert("PythonQt::Type_InplaceMultiply");
    } else if (op == "%=") {
      r.insert("PythonQt::Type_InplaceMod");
    } else if (op == "&=") {
      r.insert("PythonQt::Type_InplaceAnd");
    } else if (op == "|=") {
      r.insert("PythonQt::Type_InplaceOr");
    } else if (op == "^=") {
      r.insert("PythonQt::Type_InplaceXor");
    }
  }
  if (cls->hasDefaultIsNull()) {
    r.insert("PythonQt::Type_NonZero");
  }
  QStringList result = r.toList();
  qSort(result);
  return result;
}

static bool class_less_than(const AbstractMetaClass *a, const AbstractMetaClass *b)
{
  return a->name() < b->name();
}

void SetupGenerator::generate()
{
  AbstractMetaClassList classes_with_polymorphic_id;
  {
    QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash);
    while (pack.hasNext()) {
      pack.next();
      QList<const AbstractMetaClass*> list = pack.value();
      foreach (const AbstractMetaClass *cls, list) {
        if (cls->typeEntry()->isPolymorphicBase()) {
          classes_with_polymorphic_id.append((AbstractMetaClass*)cls);
        }
      }
    }
  }
  qSort(classes_with_polymorphic_id.begin(), classes_with_polymorphic_id.end(), class_less_than);

  QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash);
  while (pack.hasNext()) {
    pack.next();
    QList<const AbstractMetaClass*> list = pack.value();
    if (list.isEmpty())
      continue;
    qSort(list.begin(), list.end(), class_less_than);

    QString packKey = pack.key();
    QString packName = pack.key();
    QStringList components = packName.split("_");
    if ((components.size() > 2) && (components.at(0) == "com")
      && (components.at(1) == "trolltech")) {
        // kill com.trolltech in key
        components.removeAt(0);
        components.removeAt(0);
    }

    QString shortPackName;
    foreach (QString comp, components) {
      comp[0] = comp[0].toUpper();
      shortPackName += comp;
    }
    // add missing camel case (workaround..)
    if (shortPackName == "QtWebkit") {
      shortPackName = "QtWebKit";
    } else if (shortPackName == "QtXmlpatterns") {
      shortPackName = "QtXmlPatterns";
    } else if (shortPackName == "QtOpengl") {
      shortPackName = "QtOpenGL";
    } else if (shortPackName == "QtUitools") {
      shortPackName = "QtUiTools";
    }

    {
      QString fileName(packName + "/" + packKey + "_init.cpp");
      FileOut initFile(m_out_dir + "/generated_cpp/" + fileName);
      ReportHandler::debugSparse(QString("generating: %1").arg(fileName));
      QTextStream &s = initFile.stream;

      s << "#include <PythonQt.h>" << endl;

      for (int i=0; i<(list.count()+MAX_CLASSES_PER_FILE-1) / MAX_CLASSES_PER_FILE; i++) {
        s << "#include \"" << packKey << QString::number(i) << ".h\"" << endl;
      }
      s << endl;

      QStringList polymorphicHandlers;
      if (!packName.endsWith("_builtin")) {
        polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id, list);
        s << endl;
      }

      // declare individual class creation functions
      s << "void PythonQt_init_" << shortPackName << "(PyObject* module) {" << endl;

      if (shortPackName.endsWith("Builtin")) {
        shortPackName = shortPackName.mid(0, shortPackName.length()-strlen("builtin"));
      }

      QStringList cppClassNames;
      foreach (const AbstractMetaClass *cls, list) {
        if (cls->qualifiedCppName().contains("Ssl")) {
          s << "#ifndef QT_NO_OPENSSL"  << endl;
        }
        AbstractMetaFunctionList ctors = cls->queryFunctions(AbstractMetaClass::Constructors
          | AbstractMetaClass::WasVisible
          | AbstractMetaClass::NotRemovedFromTargetLang);

        QString shellCreator;
        if (cls->generateShellClass() && !ctors.isEmpty()) {
          shellCreator = ", PythonQtSetInstanceWrapperOnShell<" + ShellGenerator::shellClassName(cls) + ">";
        } else {
          shellCreator = ", NULL";
        }
        QString operatorCodes = getOperatorCodes(cls).join("|");
        if (operatorCodes.isEmpty()) {
          operatorCodes = "0";
        }
        if (cls->isQObject()) {
          s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;
        } else {
          QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():"";
          s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;
        }
        foreach(AbstractMetaClass* interface, cls->interfaces()) {
          // the interface might be our own class... (e.g. QPaintDevice)
          if (interface->qualifiedCppName() != cls->qualifiedCppName()) {
            s << "PythonQt::self()->addParentClass(\""<< cls->qualifiedCppName() << "\", \"" << interface->qualifiedCppName() << "\",PythonQtUpcastingOffset<" << cls->qualifiedCppName() <<","<<interface->qualifiedCppName()<<">());" << endl;
          }
        }
        if (cls->qualifiedCppName().contains("Ssl")) {
          s << "#endif"  << endl;
        }
      }
      s << endl;
      foreach (QString handler, polymorphicHandlers) {
        s << "PythonQt::self()->addPolymorphicHandler(\""<< handler << "\", polymorphichandler_" << handler << ");" << endl;
      }

      s << "}";
      s << endl;
    }
  }
}

QStringList SetupGenerator::writePolymorphicHandler(QTextStream &s, const QString &package,
                                                    const AbstractMetaClassList &polybase, QList<const AbstractMetaClass*>& allClasses)
{
  QStringList handlers;
  foreach (AbstractMetaClass *cls, polybase) {
    const ComplexTypeEntry *centry = cls->typeEntry();
    if (!centry->isPolymorphicBase())
      continue;
    bool isGraphicsItem = (cls->qualifiedCppName()=="QGraphicsItem");

    bool first = true;
    foreach (const AbstractMetaClass *clazz, allClasses) {
      bool inherits = false;
      if (isGraphicsItem) {
        const AbstractMetaClass *currentClazz = clazz;
        while (!inherits && currentClazz) {
          foreach(AbstractMetaClass* interfaze, currentClazz->interfaces()) {
            if (interfaze->qualifiedCppName()=="QGraphicsItem") {
              inherits = true;
              break;
            }
          }
          currentClazz = currentClazz->baseClass();
        }
      } else {
        inherits = clazz->inheritsFrom(cls);
      }
      if (clazz->package() == package && inherits) {
        if (!clazz->typeEntry()->polymorphicIdValue().isEmpty()) {
          // On first find, open the function
          if (first) {
            first = false;

            QString handler = cls->name();
            handlers.append(handler);

            s << "static void* polymorphichandler_" << handler
              << "(const void *ptr, const char **class_name)" << endl
              << "{" << endl
              << "    Q_ASSERT(ptr != 0);" << endl
              << "    " << cls->qualifiedCppName() << " *object = ("
              << cls->qualifiedCppName() << " *)ptr;" << endl;
          }

          // For each, add case label
          QString polyId = clazz->typeEntry()->polymorphicIdValue();
          s << "    if ("
            << polyId.replace("%1", "object")
            << ") {" << endl
            << "        *class_name = \"" << clazz->name() << "\";" << endl
            << "        return (" << clazz->qualifiedCppName() << "*)object;" << endl
            << "    }" << endl;
        } else {
          QString warning = QString("class '%1' inherits from polymorphic class '%2', but has no polymorphic id set")
            .arg(clazz->name())
            .arg(cls->name());

          ReportHandler::warning(warning);
        }
      }
    }

    // Close the function if it has been opened
    if (!first) {
      s << "    return NULL;" << endl
        << "}" << endl;
    }
  }

  return handlers;
}
<commit_msg>added support for registering QList/QVector template converters for non-pointer types that are used register aliases for QList/QVector<enum> -> QList<int> <commit_after>/****************************************************************************
**
** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Script Generator project on Qt Labs.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "setupgenerator.h"
#include "shellgenerator.h"
#include "reporthandler.h"
#include "fileout.h"

void SetupGenerator::addClass(const QString& package, const AbstractMetaClass *cls)
{
  packHash[package].append(cls);
}

void maybeDeclareMetaType(QTextStream &stream, const QString &typeName,
                          QSet<QString> &registeredTypeNames);
bool hasDefaultConstructor(const AbstractMetaClass *meta_class);

static QStringList getOperatorCodes(const AbstractMetaClass* cls) {
  QSet<QString> operatorCodes;
  AbstractMetaFunctionList returned;
  AbstractMetaFunctionList functions = cls->functions();
  foreach (AbstractMetaFunction *function, functions) {
    if (function->originalName().startsWith("operator")) {
      QString op = function->originalName().mid(8);
      operatorCodes.insert(op);
    }
  }
  QSet<QString> r;
  foreach(QString op, operatorCodes.toList()) {
    if (op == ">" || op == "<" || op == ">=" || op == "<=" || op == "==" || op == "!=") {
      r.insert("PythonQt::Type_RichCompare");
    } else if (op == "+") {
      r.insert("PythonQt::Type_Add");
    } else if (op == "-") {
      r.insert("PythonQt::Type_Subtract");
    } else if (op == "/") {
      r.insert("PythonQt::Type_Divide");
    } else if (op == "*") {
      r.insert("PythonQt::Type_Multiply");
    } else if (op == "%") {
      r.insert("PythonQt::Type_Mod");
    } else if (op == "&") {
      r.insert("PythonQt::Type_And");
    } else if (op == "|") {
      r.insert("PythonQt::Type_Or");
    } else if (op == "^") {
      r.insert("PythonQt::Type_Xor");
    } else if (op == "~") {
      r.insert("PythonQt::Type_Invert");

    } else if (op == "+=") {
      r.insert("PythonQt::Type_InplaceAdd");
    } else if (op == "-=") {
      r.insert("PythonQt::Type_InplaceSubtract");
    } else if (op == "/=") {
      r.insert("PythonQt::Type_InplaceDivide");
    } else if (op == "*=") {
      r.insert("PythonQt::Type_InplaceMultiply");
    } else if (op == "%=") {
      r.insert("PythonQt::Type_InplaceMod");
    } else if (op == "&=") {
      r.insert("PythonQt::Type_InplaceAnd");
    } else if (op == "|=") {
      r.insert("PythonQt::Type_InplaceOr");
    } else if (op == "^=") {
      r.insert("PythonQt::Type_InplaceXor");
    }
  }
  if (cls->hasDefaultIsNull()) {
    r.insert("PythonQt::Type_NonZero");
  }
  QStringList result = r.toList();
  qSort(result);
  return result;
}

static bool class_less_than(const AbstractMetaClass *a, const AbstractMetaClass *b)
{
  return a->name() < b->name();
}

static QSet<QString> _builtinListTypes = QSet<QString>() << "QByteArray"
<< "QDate"
<< "QTime"
<< "QDateTime"
<< "QUrl"
<< "QLocale"
<< "QRect"
<< "QRectF"
<< "QSize"
<< "QSizeF"
<< "QLine"
<< "QLineF"
<< "QPoint"
<< "QPointF"
<< "QRegExp"
<< "QFont"
<< "QPixmap"
<< "QBrush"
<< "QColor"
<< "QPalette"
<< "QIcon"
<< "QImage"
<< "QPolygon"
<< "QRegion"
<< "QBitmap"
<< "QCursor"
<< "QSizePolicy"
<< "QKeySequence"
<< "QPen"
<< "QTextLength"
<< "QTextFormat"
<< "QMatrix"
<< "QVariant";

static void addListRegistration(AbstractMetaType* type, QSet<QString>& output) {
  if (type->instantiations().size() > 0) {
    QList<AbstractMetaType *> args = type->instantiations();

    /*
    QString debugStr;
    Q_FOREACH(AbstractMetaType* arg, args) {
      debugStr += QString(arg->typeEntry()->isEnum()?"ENUM ":"") + arg->typeEntry()->qualifiedCppName() + ",";
      if (arg->typeEntry()->qualifiedCppName() == "QPair") {
        debugStr += "(" + arg->instantiations().at(0)->typeEntry()->qualifiedCppName() + ",";
        debugStr += arg->instantiations().at(1)->typeEntry()->qualifiedCppName() + ")";
      }
    }
    output.insert(QString("// TEMPLATEARG: ") + type->typeEntry()->qualifiedCppName() + " " + debugStr);
    */

    if (args.count() == 1) {
      if (args.at(0)->indirections() > 0) {
        return;
      }
      QString typeName = type->typeEntry()->qualifiedCppName();
      QString innerName = args.at(0)->typeEntry()->qualifiedCppName();

      if (typeName == "QStringList") {
        return;
      }
      if (typeName.startsWith("QVector") || typeName.startsWith("QList")) {
        if (args.at(0)->isEnum()) {
          output.insert(QString("PythonQtMethodInfo::addParameterTypeAlias(\"") + typeName + "<" + innerName + ">\", \"" + typeName + "<int>\");");
        } else if (args.at(0)->instantiations().isEmpty() && innerName.startsWith("Q") && !_builtinListTypes.contains(innerName)) {
          QString result = "PythonQtRegisterListTemplateConverterForKnownClass(" + typeName + ", " + innerName + ");";
          output.insert(result);
        }
        if (!innerName.startsWith("Q")) {
          // for debugging:
          //output.insert(QString("// POD: ") + typeName + " " + innerName);
        }
      }
    }
  }
}

void SetupGenerator::generate()
{
  AbstractMetaClassList classes_with_polymorphic_id;
  {
    QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash);
    while (pack.hasNext()) {
      pack.next();
      QList<const AbstractMetaClass*> list = pack.value();
      foreach (const AbstractMetaClass *cls, list) {
        if (cls->typeEntry()->isPolymorphicBase()) {
          classes_with_polymorphic_id.append((AbstractMetaClass*)cls);
        }
      }
    }
  }
  qSort(classes_with_polymorphic_id.begin(), classes_with_polymorphic_id.end(), class_less_than);

  QHashIterator<QString, QList<const AbstractMetaClass*> > pack(packHash);
  while (pack.hasNext()) {
    pack.next();
    QList<const AbstractMetaClass*> list = pack.value();
    if (list.isEmpty())
      continue;
    qSort(list.begin(), list.end(), class_less_than);

    QString packKey = pack.key();
    QString packName = pack.key();
    QStringList components = packName.split("_");
    if ((components.size() > 2) && (components.at(0) == "com")
      && (components.at(1) == "trolltech")) {
        // kill com.trolltech in key
        components.removeAt(0);
        components.removeAt(0);
    }

    QString shortPackName;
    foreach (QString comp, components) {
      comp[0] = comp[0].toUpper();
      shortPackName += comp;
    }
    // add missing camel case (workaround..)
    if (shortPackName == "QtWebkit") {
      shortPackName = "QtWebKit";
    } else if (shortPackName == "QtXmlpatterns") {
      shortPackName = "QtXmlPatterns";
    } else if (shortPackName == "QtOpengl") {
      shortPackName = "QtOpenGL";
    } else if (shortPackName == "QtUitools") {
      shortPackName = "QtUiTools";
    }

    {
      QString fileName(packName + "/" + packKey + "_init.cpp");
      FileOut initFile(m_out_dir + "/generated_cpp/" + fileName);
      ReportHandler::debugSparse(QString("generating: %1").arg(fileName));
      QTextStream &s = initFile.stream;

      s << "#include <PythonQt.h>" << endl;
      s << "#include <PythonQtConversion.h>" << endl;

      for (int i=0; i<(list.count()+MAX_CLASSES_PER_FILE-1) / MAX_CLASSES_PER_FILE; i++) {
        s << "#include \"" << packKey << QString::number(i) << ".h\"" << endl;
      }
      s << endl;

      QStringList polymorphicHandlers;
      if (!packName.endsWith("_builtin")) {
        polymorphicHandlers = writePolymorphicHandler(s, list.at(0)->package(), classes_with_polymorphic_id, list);
        s << endl;
      }

      QSet<QString> listRegistration;
      foreach(const AbstractMetaClass *cls, list) {
        Q_FOREACH(const AbstractMetaFunction* func, cls->functions()) {
          if (func->type() && func->type()->isContainer()) {
            addListRegistration(func->type(), listRegistration);
          }
          Q_FOREACH(const AbstractMetaArgument* arg, func->arguments()) {
            if (arg->type() && arg->type()->isContainer()) {
              addListRegistration(arg->type(), listRegistration);
            }
          }
        }
      }

      // declare individual class creation functions
      s << "void PythonQt_init_" << shortPackName << "(PyObject* module) {" << endl;

      if (shortPackName.endsWith("Builtin")) {
        shortPackName = shortPackName.mid(0, shortPackName.length()-strlen("builtin"));
      }

      foreach (const AbstractMetaClass *cls, list) {
        if (cls->qualifiedCppName().contains("Ssl")) {
          s << "#ifndef QT_NO_OPENSSL"  << endl;
        }
        AbstractMetaFunctionList ctors = cls->queryFunctions(AbstractMetaClass::Constructors
          | AbstractMetaClass::WasVisible
          | AbstractMetaClass::NotRemovedFromTargetLang);

        QString shellCreator;
        if (cls->generateShellClass() && !ctors.isEmpty()) {
          shellCreator = ", PythonQtSetInstanceWrapperOnShell<" + ShellGenerator::shellClassName(cls) + ">";
        } else {
          shellCreator = ", NULL";
        }
        QString operatorCodes = getOperatorCodes(cls).join("|");
        if (operatorCodes.isEmpty()) {
          operatorCodes = "0";
        }
        if (cls->isQObject()) {
          s << "PythonQt::priv()->registerClass(&" << cls->qualifiedCppName() << "::staticMetaObject, \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;
        } else {
          QString baseName = cls->baseClass()?cls->baseClass()->qualifiedCppName():"";
          s << "PythonQt::priv()->registerCPPClass(\""<< cls->qualifiedCppName() << "\", \"" << baseName << "\", \"" << shortPackName <<"\", PythonQtCreateObject<PythonQtWrapper_" << cls->name() << ">" << shellCreator << ", module, " << operatorCodes <<");" << endl;
        }
        foreach(AbstractMetaClass* interface, cls->interfaces()) {
          // the interface might be our own class... (e.g. QPaintDevice)
          if (interface->qualifiedCppName() != cls->qualifiedCppName()) {
            s << "PythonQt::self()->addParentClass(\""<< cls->qualifiedCppName() << "\", \"" << interface->qualifiedCppName() << "\",PythonQtUpcastingOffset<" << cls->qualifiedCppName() <<","<<interface->qualifiedCppName()<<">());" << endl;
          }
        }
        if (cls->qualifiedCppName().contains("Ssl")) {
          s << "#endif"  << endl;
        }
      }
      s << endl;
      foreach (QString handler, polymorphicHandlers) {
        s << "PythonQt::self()->addPolymorphicHandler(\""<< handler << "\", polymorphichandler_" << handler << ");" << endl;
      }
      s << endl;

      QStringList list = listRegistration.toList();
      list.sort();
      Q_FOREACH(QString name, list) {
        if (name.contains("Ssl")) {
          s << "#ifndef QT_NO_OPENSSL" << endl;
        }
        s << name << endl;
        if (name.contains("Ssl")) {
          s << "#endif" << endl;
        }
      }

      s << "}";
      s << endl;
    }
  }
}

QStringList SetupGenerator::writePolymorphicHandler(QTextStream &s, const QString &package,
                                                    const AbstractMetaClassList &polybase, QList<const AbstractMetaClass*>& allClasses)
{
  QStringList handlers;
  foreach (AbstractMetaClass *cls, polybase) {
    const ComplexTypeEntry *centry = cls->typeEntry();
    if (!centry->isPolymorphicBase())
      continue;
    bool isGraphicsItem = (cls->qualifiedCppName()=="QGraphicsItem");

    bool first = true;
    foreach (const AbstractMetaClass *clazz, allClasses) {
      bool inherits = false;
      if (isGraphicsItem) {
        const AbstractMetaClass *currentClazz = clazz;
        while (!inherits && currentClazz) {
          foreach(AbstractMetaClass* interfaze, currentClazz->interfaces()) {
            if (interfaze->qualifiedCppName()=="QGraphicsItem") {
              inherits = true;
              break;
            }
          }
          currentClazz = currentClazz->baseClass();
        }
      } else {
        inherits = clazz->inheritsFrom(cls);
      }
      if (clazz->package() == package && inherits) {
        if (!clazz->typeEntry()->polymorphicIdValue().isEmpty()) {
          // On first find, open the function
          if (first) {
            first = false;

            QString handler = cls->name();
            handlers.append(handler);

            s << "static void* polymorphichandler_" << handler
              << "(const void *ptr, const char **class_name)" << endl
              << "{" << endl
              << "    Q_ASSERT(ptr != 0);" << endl
              << "    " << cls->qualifiedCppName() << " *object = ("
              << cls->qualifiedCppName() << " *)ptr;" << endl;
          }

          // For each, add case label
          QString polyId = clazz->typeEntry()->polymorphicIdValue();
          s << "    if ("
            << polyId.replace("%1", "object")
            << ") {" << endl
            << "        *class_name = \"" << clazz->name() << "\";" << endl
            << "        return (" << clazz->qualifiedCppName() << "*)object;" << endl
            << "    }" << endl;
        } else {
          QString warning = QString("class '%1' inherits from polymorphic class '%2', but has no polymorphic id set")
            .arg(clazz->name())
            .arg(cls->name());

          ReportHandler::warning(warning);
        }
      }
    }

    // Close the function if it has been opened
    if (!first) {
      s << "    return NULL;" << endl
        << "}" << endl;
    }
  }

  return handlers;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Script Generator project on Qt Labs.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "shellgenerator.h"
#include "reporthandler.h"

#include "metaqtscript.h"

bool ShellGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const
{
    uint cg = meta_class->typeEntry()->codeGeneration();
    if (meta_class->name().startsWith("QtScript")) return false;
    if (meta_class->name().startsWith("QFuture")) return false;
    if (meta_class->name().startsWith("Global")) return false;
    if (meta_class->name().startsWith("QStyleOptionComplex")) return false;
    if (meta_class->name().startsWith("QTextLayout")) return false;
    //if (meta_class->name().startsWith("QTextStream")) return false; // because of >> operators
    //if (meta_class->name().startsWith("QDataStream")) return false; // "
    return ((cg & TypeEntry::GenerateCode) != 0);
}

void ShellGenerator::writeTypeInfo(QTextStream &s, const AbstractMetaType *type, Option options)
{
    if ((options & OriginalTypeDescription) && !type->originalTypeDescription().isEmpty()) {
        s << type->originalTypeDescription();
        return;
    }

    if (type->isArray()) {
        writeTypeInfo(s, type->arrayElementType(), options);
        if (options & ArrayAsPointer) {
            s << "*";
        } else {
            s << "[" << type->arrayElementCount() << "]";
        }
        return;
    }

    const TypeEntry *te = type->typeEntry();

    if (type->isConstant() && !(options & ExcludeConst))
        s << "const ";

    if ((options & EnumAsInts) && (te->isEnum() || te->isFlags())) {
        s << "int";
    } else if (te->isFlags()) {
        s << ((FlagsTypeEntry *) te)->originalName();
    } else {
        s << fixCppTypeName(te->qualifiedCppName());
    }

    if (type->instantiations().size() > 0
        && (!type->isContainer()
            || (static_cast<const ContainerTypeEntry *>(te))->type() != ContainerTypeEntry::StringListContainer)) {
        s << '<';
        QList<AbstractMetaType *> args = type->instantiations();
        bool nested_template = false;
        for (int i=0; i<args.size(); ++i) {
            if (i != 0)
                s << ", ";
            nested_template |= args.at(i)->isContainer();
            writeTypeInfo(s, args.at(i));
        }
        if (nested_template)
            s << ' ';
        s << '>';
    }

    s << QString(type->indirections(), '*');

    if (type->isReference() && !(options & ExcludeReference) && !(options & ConvertReferenceToPtr))
        s << "&";

    if (type->isReference() && (options & ConvertReferenceToPtr)) {
      s << "*";
    }

    if (!(options & SkipName))
        s << ' ';
}

void ShellGenerator::writeFunctionArguments(QTextStream &s, const AbstractMetaClass* owner,
                                          const AbstractMetaArgumentList &arguments,
                                          Option option,
                                          int numArguments)
{
    if (numArguments < 0) numArguments = arguments.size();

    for (int i=0; i<numArguments; ++i) {
        if (i != 0)
            s << ", ";
        AbstractMetaArgument *arg = arguments.at(i);
        writeTypeInfo(s, arg->type(), option);
        if (!(option & SkipName))
            s << " " << arg->argumentName();
        if ((option & IncludeDefaultExpression) && !arg->originalDefaultValueExpression().isEmpty()) {
            s << " = ";

          QString expr = arg->originalDefaultValueExpression();
          if (expr != "0") {
            QString qualifier;
            if (arg->type()->typeEntry()->isEnum() && expr.indexOf("::") < 0) {
              qualifier =  ((EnumTypeEntry *)arg->type()->typeEntry())->qualifier();
            } else if (arg->type()->typeEntry()->isFlags() && expr.indexOf("::") < 0) {
              qualifier = ((FlagsTypeEntry *)arg->type()->typeEntry())->originator()->qualifier();
            }
            if (!qualifier.isEmpty()) {
              s << qualifier << "::";
            }
          }
          if (expr.contains("defaultConnection")) {
            expr.replace("defaultConnection","QSqlDatabase::defaultConnection");
          }
          if (expr == "MediaSource()") {
            expr = "Phonon::MediaSource()";
          }
          s << expr;
        }
    }
}

/*!
 * Writes the function \a meta_function signature to the textstream \a s.
 *
 * The \a name_prefix can be used to give the function name a prefix,
 * like "__public_" or "__override_" and \a classname_prefix can
 * be used to give the class name a prefix.
 *
 * The \a option flags can be used to tweak various parameters, such as
 * showing static, original vs renamed name, underscores for space etc.
 *
 * The \a extra_arguments list is a list of extra arguments on the
 * form "bool static_call".
 */

void ShellGenerator::writeFunctionSignature(QTextStream &s,
                                          const AbstractMetaFunction *meta_function,
                                          const AbstractMetaClass *implementor,
                                          const QString &name_prefix,
                                          Option option,
                                          const QString &classname_prefix,
                                          const QStringList &extra_arguments,
                                          int numArguments)
{
// ### remove the implementor
    AbstractMetaType *function_type = meta_function->type();

    if ((option & SkipReturnType) == 0) {
        if (function_type) {
            writeTypeInfo(s, function_type, option);
            s << " ";
        } else if (!meta_function->isConstructor()) {
            s << "void ";
        }
    }

    if (implementor) {
        if (classname_prefix.isEmpty())
            s << wrapperClassName(implementor) << "::";
        else
            s << classname_prefix << implementor->name() << "::";
    }

    QString function_name;
    if (option & OriginalName)
        function_name = meta_function->originalName();
    else
        function_name = meta_function->name();

    if (option & UnderscoreSpaces)
        function_name = function_name.replace(' ', '_');

    if (meta_function->isConstructor())
        function_name = meta_function->ownerClass()->name();

    if (meta_function->isStatic() && (option & ShowStatic)) {
      function_name = "static_" + meta_function->ownerClass()->name() + "_" + function_name;
    }

    if (function_name.startsWith("operator")) {
      function_name = meta_function->name();
    }

    s << name_prefix << function_name;

    if (meta_function->attributes() & AbstractMetaAttributes::SetterFunction)
        s << "_setter";
    else if (meta_function->attributes() & AbstractMetaAttributes::GetterFunction)
        s << "_getter";

    s << "(";

  if ((option & FirstArgIsWrappedObject) && meta_function->ownerClass() && !meta_function->isConstructor() && !meta_function->isStatic()) {
    s << meta_function->ownerClass()->qualifiedCppName() << "* theWrappedObject";
    if (meta_function->arguments().size() != 0) {
      s << ", ";
    }
  }

   writeFunctionArguments(s, meta_function->ownerClass(), meta_function->arguments(), Option(option & Option(~ConvertReferenceToPtr)), numArguments);

    // The extra arguments...
    for (int i=0; i<extra_arguments.size(); ++i) {
        if (i > 0 || meta_function->arguments().size() != 0)
            s << ", ";
        s << extra_arguments.at(i);
    }

    s << ")";
    if (meta_function->isConstant())
        s << " const";
}

AbstractMetaFunctionList ShellGenerator::getFunctionsToWrap(const AbstractMetaClass* meta_class)
{
  AbstractMetaFunctionList functions = meta_class->queryFunctions(
    AbstractMetaClass::NormalFunctions | AbstractMetaClass::WasPublic
    | AbstractMetaClass::NotRemovedFromTargetLang | AbstractMetaClass::ClassImplements
    );
  AbstractMetaFunctionList functions2 = meta_class->queryFunctions(
    AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible
    | AbstractMetaClass::NotRemovedFromTargetLang | AbstractMetaClass::ClassImplements
    );
  QSet<AbstractMetaFunction*> set1 = QSet<AbstractMetaFunction*>::fromList(functions);
  foreach(AbstractMetaFunction* func, functions2) {
    set1.insert(func);
  }

  AbstractMetaFunctionList resultFunctions;

  foreach(AbstractMetaFunction* func, set1.toList()) {
    if (!func->isAbstract() && func->implementingClass()==meta_class) {
      resultFunctions << func;
    }
  }
  return resultFunctions;
}

AbstractMetaFunctionList ShellGenerator::getVirtualFunctionsForShell(const AbstractMetaClass* meta_class)
{
  AbstractMetaFunctionList functions = meta_class->queryFunctions(
    AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible
//    | AbstractMetaClass::NotRemovedFromTargetLang
    );
  return functions;
}

AbstractMetaFunctionList ShellGenerator::getProtectedFunctionsThatNeedPromotion(const AbstractMetaClass* meta_class)
{
  AbstractMetaFunctionList functions;
  AbstractMetaFunctionList functions1 = getFunctionsToWrap(meta_class);
  foreach(AbstractMetaFunction* func, functions1) {
    if (!func->isPublic() || func->isVirtual()) {
      functions << func;
    }
  }
  return functions;
}

/*!
Writes the include defined by \a inc to \a stream.
*/
void ShellGenerator::writeInclude(QTextStream &stream, const Include &inc)
{
  if (inc.name.isEmpty())
    return;
  if (inc.type == Include::TargetLangImport)
    return;
  stream << "#include ";
  if (inc.type == Include::IncludePath)
    stream << "<";
  else
    stream << "\"";
  stream << inc.name;
  if (inc.type == Include::IncludePath)
    stream << ">";
  else
    stream << "\"";
  stream << endl;
}

/*!
Returns true if the given function \a fun is operator>>() or
operator<<() that streams from/to a Q{Data,Text}Stream, false
otherwise.
*/
bool ShellGenerator::isSpecialStreamingOperator(const AbstractMetaFunction *fun)
{
  return ((fun->functionType() == AbstractMetaFunction::GlobalScopeFunction)
    && (fun->arguments().size() == 1)
    && (((fun->originalName() == "operator>>") && (fun->modifiedName() == "readFrom"))
    || ((fun->originalName() == "operator<<") && (fun->modifiedName() == "writeTo"))));
}

bool ShellGenerator::isBuiltIn(const QString& name) {

  static QSet<QString> builtIn;
  if (builtIn.isEmpty()) {
    builtIn.insert("Qt");
    builtIn.insert("QFont");
    builtIn.insert("QPixmap");
    builtIn.insert("QBrush");
    builtIn.insert("QBitArray");
    builtIn.insert("QPalette");
    builtIn.insert("QPen");
    builtIn.insert("QIcon");
    builtIn.insert("QImage");
    builtIn.insert("QPolygon");
    builtIn.insert("QRegion");
    builtIn.insert("QBitmap");
    builtIn.insert("QCursor");
    builtIn.insert("QColor");
    builtIn.insert("QSizePolicy");
    builtIn.insert("QKeySequence");
    builtIn.insert("QTextLength");
    builtIn.insert("QTextFormat");
    builtIn.insert("QMatrix");
    builtIn.insert("QDate");
    builtIn.insert("QTime");
    builtIn.insert("QDateTime");
    builtIn.insert("QUrl");
    builtIn.insert("QLocale");
    builtIn.insert("QRect");
    builtIn.insert("QRectF");
    builtIn.insert("QSize");
    builtIn.insert("QSizeF");
    builtIn.insert("QLine");
    builtIn.insert("QLineF");
    builtIn.insert("QPoint");
    builtIn.insert("QPointF");
    builtIn.insert("QRegExp");
  }
  return builtIn.contains(name);
}

<commit_msg>added alphabetic sorting<commit_after>/****************************************************************************
**
** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Script Generator project on Qt Labs.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "shellgenerator.h"
#include "reporthandler.h"

#include "metaqtscript.h"

bool ShellGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const
{
    uint cg = meta_class->typeEntry()->codeGeneration();
    if (meta_class->name().startsWith("QtScript")) return false;
    if (meta_class->name().startsWith("QFuture")) return false;
    if (meta_class->name().startsWith("Global")) return false;
    if (meta_class->name().startsWith("QStyleOptionComplex")) return false;
    if (meta_class->name().startsWith("QTextLayout")) return false;
    //if (meta_class->name().startsWith("QTextStream")) return false; // because of >> operators
    //if (meta_class->name().startsWith("QDataStream")) return false; // "
    return ((cg & TypeEntry::GenerateCode) != 0);
}

void ShellGenerator::writeTypeInfo(QTextStream &s, const AbstractMetaType *type, Option options)
{
    if ((options & OriginalTypeDescription) && !type->originalTypeDescription().isEmpty()) {
        s << type->originalTypeDescription();
        return;
    }

    if (type->isArray()) {
        writeTypeInfo(s, type->arrayElementType(), options);
        if (options & ArrayAsPointer) {
            s << "*";
        } else {
            s << "[" << type->arrayElementCount() << "]";
        }
        return;
    }

    const TypeEntry *te = type->typeEntry();

    if (type->isConstant() && !(options & ExcludeConst))
        s << "const ";

    if ((options & EnumAsInts) && (te->isEnum() || te->isFlags())) {
        s << "int";
    } else if (te->isFlags()) {
        s << ((FlagsTypeEntry *) te)->originalName();
    } else {
        s << fixCppTypeName(te->qualifiedCppName());
    }

    if (type->instantiations().size() > 0
        && (!type->isContainer()
            || (static_cast<const ContainerTypeEntry *>(te))->type() != ContainerTypeEntry::StringListContainer)) {
        s << '<';
        QList<AbstractMetaType *> args = type->instantiations();
        bool nested_template = false;
        for (int i=0; i<args.size(); ++i) {
            if (i != 0)
                s << ", ";
            nested_template |= args.at(i)->isContainer();
            writeTypeInfo(s, args.at(i));
        }
        if (nested_template)
            s << ' ';
        s << '>';
    }

    s << QString(type->indirections(), '*');

    if (type->isReference() && !(options & ExcludeReference) && !(options & ConvertReferenceToPtr))
        s << "&";

    if (type->isReference() && (options & ConvertReferenceToPtr)) {
      s << "*";
    }

    if (!(options & SkipName))
        s << ' ';
}

void ShellGenerator::writeFunctionArguments(QTextStream &s, const AbstractMetaClass* owner,
                                          const AbstractMetaArgumentList &arguments,
                                          Option option,
                                          int numArguments)
{
    if (numArguments < 0) numArguments = arguments.size();

    for (int i=0; i<numArguments; ++i) {
        if (i != 0)
            s << ", ";
        AbstractMetaArgument *arg = arguments.at(i);
        writeTypeInfo(s, arg->type(), option);
        if (!(option & SkipName))
            s << " " << arg->argumentName();
        if ((option & IncludeDefaultExpression) && !arg->originalDefaultValueExpression().isEmpty()) {
            s << " = ";

          QString expr = arg->originalDefaultValueExpression();
          if (expr != "0") {
            QString qualifier;
            if (arg->type()->typeEntry()->isEnum() && expr.indexOf("::") < 0) {
              qualifier =  ((EnumTypeEntry *)arg->type()->typeEntry())->qualifier();
            } else if (arg->type()->typeEntry()->isFlags() && expr.indexOf("::") < 0) {
              qualifier = ((FlagsTypeEntry *)arg->type()->typeEntry())->originator()->qualifier();
            }
            if (!qualifier.isEmpty()) {
              s << qualifier << "::";
            }
          }
          if (expr.contains("defaultConnection")) {
            expr.replace("defaultConnection","QSqlDatabase::defaultConnection");
          }
          if (expr == "MediaSource()") {
            expr = "Phonon::MediaSource()";
          }
          s << expr;
        }
    }
}

/*!
 * Writes the function \a meta_function signature to the textstream \a s.
 *
 * The \a name_prefix can be used to give the function name a prefix,
 * like "__public_" or "__override_" and \a classname_prefix can
 * be used to give the class name a prefix.
 *
 * The \a option flags can be used to tweak various parameters, such as
 * showing static, original vs renamed name, underscores for space etc.
 *
 * The \a extra_arguments list is a list of extra arguments on the
 * form "bool static_call".
 */

void ShellGenerator::writeFunctionSignature(QTextStream &s,
                                          const AbstractMetaFunction *meta_function,
                                          const AbstractMetaClass *implementor,
                                          const QString &name_prefix,
                                          Option option,
                                          const QString &classname_prefix,
                                          const QStringList &extra_arguments,
                                          int numArguments)
{
// ### remove the implementor
    AbstractMetaType *function_type = meta_function->type();

    if ((option & SkipReturnType) == 0) {
        if (function_type) {
            writeTypeInfo(s, function_type, option);
            s << " ";
        } else if (!meta_function->isConstructor()) {
            s << "void ";
        }
    }

    if (implementor) {
        if (classname_prefix.isEmpty())
            s << wrapperClassName(implementor) << "::";
        else
            s << classname_prefix << implementor->name() << "::";
    }

    QString function_name;
    if (option & OriginalName)
        function_name = meta_function->originalName();
    else
        function_name = meta_function->name();

    if (option & UnderscoreSpaces)
        function_name = function_name.replace(' ', '_');

    if (meta_function->isConstructor())
        function_name = meta_function->ownerClass()->name();

    if (meta_function->isStatic() && (option & ShowStatic)) {
      function_name = "static_" + meta_function->ownerClass()->name() + "_" + function_name;
    }

    if (function_name.startsWith("operator")) {
      function_name = meta_function->name();
    }

    s << name_prefix << function_name;

    if (meta_function->attributes() & AbstractMetaAttributes::SetterFunction)
        s << "_setter";
    else if (meta_function->attributes() & AbstractMetaAttributes::GetterFunction)
        s << "_getter";

    s << "(";

  if ((option & FirstArgIsWrappedObject) && meta_function->ownerClass() && !meta_function->isConstructor() && !meta_function->isStatic()) {
    s << meta_function->ownerClass()->qualifiedCppName() << "* theWrappedObject";
    if (meta_function->arguments().size() != 0) {
      s << ", ";
    }
  }

   writeFunctionArguments(s, meta_function->ownerClass(), meta_function->arguments(), Option(option & Option(~ConvertReferenceToPtr)), numArguments);

    // The extra arguments...
    for (int i=0; i<extra_arguments.size(); ++i) {
        if (i > 0 || meta_function->arguments().size() != 0)
            s << ", ";
        s << extra_arguments.at(i);
    }

    s << ")";
    if (meta_function->isConstant())
        s << " const";
}

AbstractMetaFunctionList ShellGenerator::getFunctionsToWrap(const AbstractMetaClass* meta_class)
{
  AbstractMetaFunctionList functions = meta_class->queryFunctions(
    AbstractMetaClass::NormalFunctions | AbstractMetaClass::WasPublic
    | AbstractMetaClass::NotRemovedFromTargetLang | AbstractMetaClass::ClassImplements
    );
  AbstractMetaFunctionList functions2 = meta_class->queryFunctions(
    AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible
    | AbstractMetaClass::NotRemovedFromTargetLang | AbstractMetaClass::ClassImplements
    );
  QSet<AbstractMetaFunction*> set1 = QSet<AbstractMetaFunction*>::fromList(functions);
  foreach(AbstractMetaFunction* func, functions2) {
    set1.insert(func);
  }

  AbstractMetaFunctionList resultFunctions;

  foreach(AbstractMetaFunction* func, set1.toList()) {
    if (!func->isAbstract() && func->implementingClass()==meta_class) {
      resultFunctions << func;
    }
  }
  qStableSort(resultFunctions);
  return resultFunctions;
}

AbstractMetaFunctionList ShellGenerator::getVirtualFunctionsForShell(const AbstractMetaClass* meta_class)
{
  AbstractMetaFunctionList functions = meta_class->queryFunctions(
    AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible
//    | AbstractMetaClass::NotRemovedFromTargetLang
    );
  qStableSort(functions);
  return functions;
}

AbstractMetaFunctionList ShellGenerator::getProtectedFunctionsThatNeedPromotion(const AbstractMetaClass* meta_class)
{
  AbstractMetaFunctionList functions;
  AbstractMetaFunctionList functions1 = getFunctionsToWrap(meta_class);
  foreach(AbstractMetaFunction* func, functions1) {
    if (!func->isPublic() || func->isVirtual()) {
      functions << func;
    }
  }
  qStableSort(functions);
  return functions;
}

/*!
Writes the include defined by \a inc to \a stream.
*/
void ShellGenerator::writeInclude(QTextStream &stream, const Include &inc)
{
  if (inc.name.isEmpty())
    return;
  if (inc.type == Include::TargetLangImport)
    return;
  stream << "#include ";
  if (inc.type == Include::IncludePath)
    stream << "<";
  else
    stream << "\"";
  stream << inc.name;
  if (inc.type == Include::IncludePath)
    stream << ">";
  else
    stream << "\"";
  stream << endl;
}

/*!
Returns true if the given function \a fun is operator>>() or
operator<<() that streams from/to a Q{Data,Text}Stream, false
otherwise.
*/
bool ShellGenerator::isSpecialStreamingOperator(const AbstractMetaFunction *fun)
{
  return ((fun->functionType() == AbstractMetaFunction::GlobalScopeFunction)
    && (fun->arguments().size() == 1)
    && (((fun->originalName() == "operator>>") && (fun->modifiedName() == "readFrom"))
    || ((fun->originalName() == "operator<<") && (fun->modifiedName() == "writeTo"))));
}

bool ShellGenerator::isBuiltIn(const QString& name) {

  static QSet<QString> builtIn;
  if (builtIn.isEmpty()) {
    builtIn.insert("Qt");
    builtIn.insert("QFont");
    builtIn.insert("QPixmap");
    builtIn.insert("QBrush");
    builtIn.insert("QBitArray");
    builtIn.insert("QPalette");
    builtIn.insert("QPen");
    builtIn.insert("QIcon");
    builtIn.insert("QImage");
    builtIn.insert("QPolygon");
    builtIn.insert("QRegion");
    builtIn.insert("QBitmap");
    builtIn.insert("QCursor");
    builtIn.insert("QColor");
    builtIn.insert("QSizePolicy");
    builtIn.insert("QKeySequence");
    builtIn.insert("QTextLength");
    builtIn.insert("QTextFormat");
    builtIn.insert("QMatrix");
    builtIn.insert("QDate");
    builtIn.insert("QTime");
    builtIn.insert("QDateTime");
    builtIn.insert("QUrl");
    builtIn.insert("QLocale");
    builtIn.insert("QRect");
    builtIn.insert("QRectF");
    builtIn.insert("QSize");
    builtIn.insert("QSizeF");
    builtIn.insert("QLine");
    builtIn.insert("QLineF");
    builtIn.insert("QPoint");
    builtIn.insert("QPointF");
    builtIn.insert("QRegExp");
  }
  return builtIn.contains(name);
}

<|endoftext|>


<commit_before>/* Copyright (C) 2015 Cotton Seed

   This file is part of arachne-pnr.  Arachne-pnr is free software;
   you can redistribute it and/or modify it under the terms of the GNU
   General Public License version 2 as published by the Free Software
   Foundation.

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

   You should have received a copy of the GNU General Public License
   along with this program. If not, see <http://www.gnu.org/licenses/>. */

#include "netlist.hh"
#include "global.hh"
#include "chipdb.hh"
#include "casting.hh"
#include "util.hh"
#include "designstate.hh"

#include <queue>
#include <cassert>
#include <set>

class Promoter
{
  std::vector<uint8_t> global_classes;
  static const char *global_class_name(uint8_t gc);

  DesignState &ds;
  const ChipDB *chipdb;
  Design *d;
  Model *top;
  const Models ⊧
  std::map<Instance *, uint8_t, IdLess> &gb_inst_gc;

  Net *const0;

  uint8_t port_gc(Port *conn, bool indirect);
  void pll_pass_through(Instance *inst, int cell, const char *p_name);
  bool routable(int g, Port *p);
  void make_routable(Net *n, int g);

public:
  Promoter(DesignState &ds_);

  void promote(bool do_promote);
};

const char *
Promoter::global_class_name(uint8_t gc)
{
  switch(gc)
    {
    case gc_clk: return "clk";
    case gc_cen: return "cen/wclke";
    case gc_sr: return "sr/we";
    case gc_rclke: return "rclke";
    case gc_re: return "re";
    default:
      abort();
      return nullptr;
    }
}

Promoter::Promoter(DesignState &ds_)
  : global_classes{
      gc_clk, gc_cen, gc_sr, gc_rclke, gc_re,
    },
    ds(ds_),
    chipdb(ds.chipdb),
    d(ds.d),
    top(ds.top),
    models(ds.models),
    gb_inst_gc(ds.gb_inst_gc),
    const0(nullptr)
{
  for (const auto &p : top->nets())
    {
      if (p.second->is_constant()
          && p.second->constant() == Value::ZERO)
        {
          const0 = p.second;
          break;
        }
    }

  // will prune
  if (!const0)
    {
      const0 = top->add_net("$false");
      const0->set_is_constant(true);
      const0->set_constant(Value::ZERO);
    }
}

uint8_t
Promoter::port_gc(Port *conn, bool indirect)
{
  Instance *inst = dyn_cast<Instance>(conn->node());
  assert(inst);

  if (models.is_lc(inst))
    {
      if (conn->name() == "CLK")
        return gc_clk;
      else if (conn->name() == "CEN")
        return gc_cen;
      else if (conn->name() == "SR")
        return gc_sr;
      else if (indirect
               && (conn->name() == "I0"
                   || conn->name() == "I1"
                   || conn->name() == "I2"
                   || conn->name() == "I3"))
        return gc_clk;
    }
  else if (models.is_ioX(inst))
    {
      if (conn->name() == "INPUT_CLOCK"
          || conn->name() == "OUTPUT_CLOCK")
        return gc_clk;
    }
  else if (models.is_gb(inst)
           || models.is_warmboot(inst)
           || models.is_pllX(inst))
    ;
  else
    {
      assert(models.is_ramX(inst));
      if (conn->name() == "WCLK"
          || conn->name() == "WCLKN"
          || conn->name() == "RCLK"
          || conn->name() == "RCLKN")
        return gc_clk;
      else if (conn->name() == "WCLKE")
        return gc_wclke;
      else if (conn->name() == "WE")
        return gc_we;
      else if (conn->name() == "RCLKE")
        return gc_rclke;
      else if (conn->name() == "RE")
        return gc_re;
    }

  return 0;
}

bool
Promoter::routable(int gc, Port *p)
{
  return (bool)((port_gc(p, true) & gc) == gc);
}

void
Promoter::pll_pass_through(Instance *inst, int cell, const char *p_name)
{
  Port *p = inst->find_port(p_name);
  Net *n = p->connection();
  if (!n)
    return;

  Net *t = top->add_net(n);
  p->connect(t);

  Instance *pass_inst = top->add_instance(models.lc);
  pass_inst->find_port("I0")->connect(t);
  pass_inst->find_port("I1")->connect(const0);
  pass_inst->find_port("I2")->connect(const0);
  pass_inst->find_port("I3")->connect(const0);
  pass_inst->set_param("LUT_INIT", BitVector(2, 2));
  pass_inst->find_port("O")->connect(n);

  const auto &p2 = chipdb->cell_mfvs.at(cell).at(p_name);
  int pass_cell = chipdb->loc_cell(Location(p2.first, 0));

  extend(ds.placement, pass_inst, pass_cell);
}

void
Promoter::make_routable(Net *n, int gc)
{
  Net *internal = nullptr;
  for (auto i = n->connections().begin();
       i != n->connections().end();)
    {
      Port *p = *i;
      ++i;

      if (!p->is_input())
        continue;
      if (routable(gc, p))
        continue;

      if (!internal)
        {
          internal = top->add_net(n);

          Instance *pass_inst = top->add_instance(models.lc);
          pass_inst->find_port("I0")->connect(n);
          pass_inst->find_port("I1")->connect(const0);
          pass_inst->find_port("I2")->connect(const0);
          pass_inst->find_port("I3")->connect(const0);
          pass_inst->set_param("LUT_INIT", BitVector(2, 2));
          pass_inst->find_port("O")->connect(internal);
        }
      p->connect(internal);
    }
}

void
Promoter::promote(bool do_promote)
{
  std::vector<Net *> nets;
  std::map<Net *, int, IdLess> net_idx;
  std::tie(nets, net_idx) = top->index_nets();
  int n_nets = nets.size();

  int n_global = 0;

  std::map<uint8_t, int> gc_global;
  std::map<uint8_t, int> gc_used;
  for (uint8_t gc : global_classes)
    {
      extend(gc_global, gc, 0);
      extend(gc_used, gc, 0);
    }

  std::vector<std::pair<Instance *, int>> plls;
  for (const auto &p : ds.placement)
    {
      Instance *inst = p.first;
      int c = p.second;

      if (models.is_gb_io(inst))
        {
          Port *out = inst->find_port("GLOBAL_BUFFER_OUTPUT");
          if (out->connected())
            {
              int g = chipdb->loc_pin_glb_num.at(chipdb->cell_location[c]);
              for (uint8_t gc : global_classes)
                {
                  if (gc & (1 << g))
                    ++gc_used[gc];
                }
              make_routable(out->connection(), 1 << g);
            }
        }
      else if (models.is_pllX(inst))
        {
          plls.push_back(std::make_pair(inst, c));

          Port *a = inst->find_port("PLLOUTGLOBAL");
          if (!a)
            a = inst->find_port("PLLOUTGLOBALA");
          assert(a);
          if (a->connected())
            {
              const auto &p2 = chipdb->cell_mfvs.at(c).at("PLLOUT_A");
              Location loc(p2.first, std::stoi(p2.second));
              int g = chipdb->loc_pin_glb_num.at(loc);
              for (uint8_t gc : global_classes)
                {
                  if (gc & (1 << g))
                    ++gc_used[gc];
                }
              make_routable(a->connection(), 1 << g);
            }

          Port *b = inst->find_port("PLLOUTGLOBALB");
          if (b && b->connected())
            {
              const auto &p2 = chipdb->cell_mfvs.at(c).at("PLLOUT_B");
              Location loc(p2.first, std::stoi(p2.second));
              int g = chipdb->loc_pin_glb_num.at(loc);
              for (uint8_t gc : global_classes)
                {
                  if (gc & (1 << g))
                    ++gc_used[gc];
                }
              make_routable(b->connection(), 1 << g);
            }
        }
    }

  for (const auto &p : plls)
    {
      Instance *inst = p.first;
      int c = p.second;
      pll_pass_through(inst, c, "LOCK");
      pll_pass_through(inst, c, "SDO");
    }

  std::set<Net *, IdLess> boundary_nets = top->boundary_nets(d);

  std::set<std::pair<int, int>, std::greater<std::pair<int, int>>> promote_q;
  std::map<int, uint8_t> net_gc;
  std::map<int, Port *> net_driver;
  for (int i = 1; i < n_nets; ++i) // skip 0, nullptr
    {
      Net *n = nets[i];
      if (contains(boundary_nets, n)
          || n->is_constant())
        continue;

      std::map<uint8_t, int> n_gc;
      for (uint8_t gc : global_classes)
        extend(n_gc, gc, 0);

      Port *driver = nullptr;
      for (Port *conn : n->connections())
        {
          assert(!conn->is_bidir());
          if (conn->is_output())
            {
              assert(!driver);
              driver = conn;
            }

          int gc = port_gc(conn, false);
          if (gc)
            ++n_gc[gc];
        }

      int max_gc = 0;
      int max_n = 0;
      for (const auto &p : n_gc)
        {
          if (p.second > max_n)
            {
              max_gc = p.first;
              max_n = p.second;
            }
        }

      if (driver
          && isa<Instance>(driver->node())
          && ((models.is_gbX(cast<Instance>(driver->node()))
               && driver->name() == "GLOBAL_BUFFER_OUTPUT")
              || (models.is_pllX(cast<Instance>(driver->node()))
                  && (driver->name() == "PLLOUTGLOBAL"
                      || driver->name() == "PLLOUTGLOBALA"
                      || driver->name() == "PLLOUTGLOBALB"))))
        {
          Instance *gb_inst = cast<Instance>(driver->node());

          uint8_t gc = max_gc ? max_gc : gc_clk;

          ++n_global;
          ++gc_global[gc];

          if (models.is_gbX(gb_inst))
            {
              if (driver->connected())
                make_routable(driver->connection(), gc);

              extend(gb_inst_gc, gb_inst, gc);
            }
          for (uint8_t gc2 : global_classes)
            {
              if ((gc2 & gc) == gc)
                ++gc_used[gc2];
            }
        }
      else if (do_promote
               && driver
               && max_gc
               && max_n > 4)
        {
          extend(net_driver, i, driver);
          extend(net_gc, i, max_gc);
          promote_q.insert(std::make_pair(max_n, i));
        }
    }

  int n_promoted = 0;
  std::map<uint8_t, int> gc_promoted;
  for (int gc : global_classes)
    extend(gc_promoted, gc, 0);

  while(!promote_q.empty())
    {
      std::pair<int, int> p = *promote_q.begin();
      promote_q.erase(promote_q.begin());
      assert(promote_q.empty()
             || promote_q.begin()->first <= p.first);

      Net *n = nets[p.second];
      uint8_t gc = net_gc.at(p.second);

      for (int gc2 : global_classes)
        {
          int k2 = 0;
          for (int i = 0; i < 8; ++i)
            {
              if (gc2 & (1 << i))
                ++k2;
            }

          if ((gc2 & gc) == gc)
            {
              if (gc_used.at(gc2) >= k2)
                goto L;
            }
        }

      {
        ++n_promoted;
        ++gc_promoted[gc];

        Instance *gb_inst = top->add_instance(models.gb);
        Net *t = top->add_net(n);

        int n_conn = 0;
        int n_conn_promoted = 0;
        for (auto i = n->connections().begin();
             i != n->connections().end();)
          {
            Port *conn = *i;
            ++i;
            if (conn->is_output()
                || conn->is_bidir())
              continue;

            ++n_conn;
            int conn_gc = port_gc(conn, true);
            if ((conn_gc & gc) == gc)
              {
                ++n_conn_promoted;
                conn->connect(t);
              }
          }

        gb_inst->find_port("USER_SIGNAL_TO_GLOBAL_BUFFER")->connect(n);
        gb_inst->find_port("GLOBAL_BUFFER_OUTPUT")->connect(t);

        ++n_global;
        ++gc_global[gc];
        extend(gb_inst_gc, gb_inst, gc);
        for (uint8_t gc2 : global_classes)
          {
            if ((gc2 & gc) == gc)
              ++gc_used[gc2];
          }

        *logs << "  promoted " << n->name()
              << ", " << n_conn_promoted << " / " << n_conn << "\n";
      }
    L:;
    }

  *logs << "  promoted " << n_promoted << " nets\n";
  for (const auto &p : gc_promoted)
    {
      if (p.second)
        *logs << "    " << p.second << " " << global_class_name(p.first) << "\n";
    }
  *logs << "  " << n_global << " globals\n";
  for (const auto &p : gc_global)
    {
      if (p.second)
        *logs << "    " << p.second << " " << global_class_name(p.first) << "\n";
    }

  d->prune();
}

void
promote_globals(DesignState &ds, bool do_promote)
{
  Promoter promoter(ds);
  promoter.promote(do_promote);
}
<commit_msg>Fix incorrect I/O block clock net names This resolves issue #61<commit_after>/* Copyright (C) 2015 Cotton Seed

   This file is part of arachne-pnr.  Arachne-pnr is free software;
   you can redistribute it and/or modify it under the terms of the GNU
   General Public License version 2 as published by the Free Software
   Foundation.

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

   You should have received a copy of the GNU General Public License
   along with this program. If not, see <http://www.gnu.org/licenses/>. */

#include "netlist.hh"
#include "global.hh"
#include "chipdb.hh"
#include "casting.hh"
#include "util.hh"
#include "designstate.hh"

#include <queue>
#include <cassert>
#include <set>

class Promoter
{
  std::vector<uint8_t> global_classes;
  static const char *global_class_name(uint8_t gc);

  DesignState &ds;
  const ChipDB *chipdb;
  Design *d;
  Model *top;
  const Models ⊧
  std::map<Instance *, uint8_t, IdLess> &gb_inst_gc;

  Net *const0;

  uint8_t port_gc(Port *conn, bool indirect);
  void pll_pass_through(Instance *inst, int cell, const char *p_name);
  bool routable(int g, Port *p);
  void make_routable(Net *n, int g);

public:
  Promoter(DesignState &ds_);

  void promote(bool do_promote);
};

const char *
Promoter::global_class_name(uint8_t gc)
{
  switch(gc)
    {
    case gc_clk: return "clk";
    case gc_cen: return "cen/wclke";
    case gc_sr: return "sr/we";
    case gc_rclke: return "rclke";
    case gc_re: return "re";
    default:
      abort();
      return nullptr;
    }
}

Promoter::Promoter(DesignState &ds_)
  : global_classes{
      gc_clk, gc_cen, gc_sr, gc_rclke, gc_re,
    },
    ds(ds_),
    chipdb(ds.chipdb),
    d(ds.d),
    top(ds.top),
    models(ds.models),
    gb_inst_gc(ds.gb_inst_gc),
    const0(nullptr)
{
  for (const auto &p : top->nets())
    {
      if (p.second->is_constant()
          && p.second->constant() == Value::ZERO)
        {
          const0 = p.second;
          break;
        }
    }

  // will prune
  if (!const0)
    {
      const0 = top->add_net("$false");
      const0->set_is_constant(true);
      const0->set_constant(Value::ZERO);
    }
}

uint8_t
Promoter::port_gc(Port *conn, bool indirect)
{
  Instance *inst = dyn_cast<Instance>(conn->node());
  assert(inst);

  if (models.is_lc(inst))
    {
      if (conn->name() == "CLK")
        return gc_clk;
      else if (conn->name() == "CEN")
        return gc_cen;
      else if (conn->name() == "SR")
        return gc_sr;
      else if (indirect
               && (conn->name() == "I0"
                   || conn->name() == "I1"
                   || conn->name() == "I2"
                   || conn->name() == "I3"))
        return gc_clk;
    }
  else if (models.is_ioX(inst))
    {
      if (conn->name() == "INPUT_CLK"
          || conn->name() == "OUTPUT_CLK")
        return gc_clk;
    }
  else if (models.is_gb(inst)
           || models.is_warmboot(inst)
           || models.is_pllX(inst))
    ;
  else
    {
      assert(models.is_ramX(inst));
      if (conn->name() == "WCLK"
          || conn->name() == "WCLKN"
          || conn->name() == "RCLK"
          || conn->name() == "RCLKN")
        return gc_clk;
      else if (conn->name() == "WCLKE")
        return gc_wclke;
      else if (conn->name() == "WE")
        return gc_we;
      else if (conn->name() == "RCLKE")
        return gc_rclke;
      else if (conn->name() == "RE")
        return gc_re;
    }

  return 0;
}

bool
Promoter::routable(int gc, Port *p)
{
  return (bool)((port_gc(p, true) & gc) == gc);
}

void
Promoter::pll_pass_through(Instance *inst, int cell, const char *p_name)
{
  Port *p = inst->find_port(p_name);
  Net *n = p->connection();
  if (!n)
    return;

  Net *t = top->add_net(n);
  p->connect(t);

  Instance *pass_inst = top->add_instance(models.lc);
  pass_inst->find_port("I0")->connect(t);
  pass_inst->find_port("I1")->connect(const0);
  pass_inst->find_port("I2")->connect(const0);
  pass_inst->find_port("I3")->connect(const0);
  pass_inst->set_param("LUT_INIT", BitVector(2, 2));
  pass_inst->find_port("O")->connect(n);

  const auto &p2 = chipdb->cell_mfvs.at(cell).at(p_name);
  int pass_cell = chipdb->loc_cell(Location(p2.first, 0));

  extend(ds.placement, pass_inst, pass_cell);
}

void
Promoter::make_routable(Net *n, int gc)
{
  Net *internal = nullptr;
  for (auto i = n->connections().begin();
       i != n->connections().end();)
    {
      Port *p = *i;
      ++i;

      if (!p->is_input())
        continue;
      if (routable(gc, p))
        continue;

      if (!internal)
        {
          internal = top->add_net(n);

          Instance *pass_inst = top->add_instance(models.lc);
          pass_inst->find_port("I0")->connect(n);
          pass_inst->find_port("I1")->connect(const0);
          pass_inst->find_port("I2")->connect(const0);
          pass_inst->find_port("I3")->connect(const0);
          pass_inst->set_param("LUT_INIT", BitVector(2, 2));
          pass_inst->find_port("O")->connect(internal);
        }
      p->connect(internal);
    }
}

void
Promoter::promote(bool do_promote)
{
  std::vector<Net *> nets;
  std::map<Net *, int, IdLess> net_idx;
  std::tie(nets, net_idx) = top->index_nets();
  int n_nets = nets.size();

  int n_global = 0;

  std::map<uint8_t, int> gc_global;
  std::map<uint8_t, int> gc_used;
  for (uint8_t gc : global_classes)
    {
      extend(gc_global, gc, 0);
      extend(gc_used, gc, 0);
    }

  std::vector<std::pair<Instance *, int>> plls;
  for (const auto &p : ds.placement)
    {
      Instance *inst = p.first;
      int c = p.second;

      if (models.is_gb_io(inst))
        {
          Port *out = inst->find_port("GLOBAL_BUFFER_OUTPUT");
          if (out->connected())
            {
              int g = chipdb->loc_pin_glb_num.at(chipdb->cell_location[c]);
              for (uint8_t gc : global_classes)
                {
                  if (gc & (1 << g))
                    ++gc_used[gc];
                }
              make_routable(out->connection(), 1 << g);
            }
        }
      else if (models.is_pllX(inst))
        {
          plls.push_back(std::make_pair(inst, c));

          Port *a = inst->find_port("PLLOUTGLOBAL");
          if (!a)
            a = inst->find_port("PLLOUTGLOBALA");
          assert(a);
          if (a->connected())
            {
              const auto &p2 = chipdb->cell_mfvs.at(c).at("PLLOUT_A");
              Location loc(p2.first, std::stoi(p2.second));
              int g = chipdb->loc_pin_glb_num.at(loc);
              for (uint8_t gc : global_classes)
                {
                  if (gc & (1 << g))
                    ++gc_used[gc];
                }
              make_routable(a->connection(), 1 << g);
            }

          Port *b = inst->find_port("PLLOUTGLOBALB");
          if (b && b->connected())
            {
              const auto &p2 = chipdb->cell_mfvs.at(c).at("PLLOUT_B");
              Location loc(p2.first, std::stoi(p2.second));
              int g = chipdb->loc_pin_glb_num.at(loc);
              for (uint8_t gc : global_classes)
                {
                  if (gc & (1 << g))
                    ++gc_used[gc];
                }
              make_routable(b->connection(), 1 << g);
            }
        }
    }

  for (const auto &p : plls)
    {
      Instance *inst = p.first;
      int c = p.second;
      pll_pass_through(inst, c, "LOCK");
      pll_pass_through(inst, c, "SDO");
    }

  std::set<Net *, IdLess> boundary_nets = top->boundary_nets(d);

  std::set<std::pair<int, int>, std::greater<std::pair<int, int>>> promote_q;
  std::map<int, uint8_t> net_gc;
  std::map<int, Port *> net_driver;
  for (int i = 1; i < n_nets; ++i) // skip 0, nullptr
    {
      Net *n = nets[i];
      if (contains(boundary_nets, n)
          || n->is_constant())
        continue;

      std::map<uint8_t, int> n_gc;
      for (uint8_t gc : global_classes)
        extend(n_gc, gc, 0);

      Port *driver = nullptr;
      for (Port *conn : n->connections())
        {
          assert(!conn->is_bidir());
          if (conn->is_output())
            {
              assert(!driver);
              driver = conn;
            }

          int gc = port_gc(conn, false);
          if (gc)
            ++n_gc[gc];
        }

      int max_gc = 0;
      int max_n = 0;
      for (const auto &p : n_gc)
        {
          if (p.second > max_n)
            {
              max_gc = p.first;
              max_n = p.second;
            }
        }

      if (driver
          && isa<Instance>(driver->node())
          && ((models.is_gbX(cast<Instance>(driver->node()))
               && driver->name() == "GLOBAL_BUFFER_OUTPUT")
              || (models.is_pllX(cast<Instance>(driver->node()))
                  && (driver->name() == "PLLOUTGLOBAL"
                      || driver->name() == "PLLOUTGLOBALA"
                      || driver->name() == "PLLOUTGLOBALB"))))
        {
          Instance *gb_inst = cast<Instance>(driver->node());

          uint8_t gc = max_gc ? max_gc : gc_clk;

          ++n_global;
          ++gc_global[gc];

          if (models.is_gbX(gb_inst))
            {
              if (driver->connected())
                make_routable(driver->connection(), gc);

              extend(gb_inst_gc, gb_inst, gc);
            }
          for (uint8_t gc2 : global_classes)
            {
              if ((gc2 & gc) == gc)
                ++gc_used[gc2];
            }
        }
      else if (do_promote
               && driver
               && max_gc
               && max_n > 4)
        {
          extend(net_driver, i, driver);
          extend(net_gc, i, max_gc);
          promote_q.insert(std::make_pair(max_n, i));
        }
    }

  int n_promoted = 0;
  std::map<uint8_t, int> gc_promoted;
  for (int gc : global_classes)
    extend(gc_promoted, gc, 0);

  while(!promote_q.empty())
    {
      std::pair<int, int> p = *promote_q.begin();
      promote_q.erase(promote_q.begin());
      assert(promote_q.empty()
             || promote_q.begin()->first <= p.first);

      Net *n = nets[p.second];
      uint8_t gc = net_gc.at(p.second);

      for (int gc2 : global_classes)
        {
          int k2 = 0;
          for (int i = 0; i < 8; ++i)
            {
              if (gc2 & (1 << i))
                ++k2;
            }

          if ((gc2 & gc) == gc)
            {
              if (gc_used.at(gc2) >= k2)
                goto L;
            }
        }

      {
        ++n_promoted;
        ++gc_promoted[gc];

        Instance *gb_inst = top->add_instance(models.gb);
        Net *t = top->add_net(n);

        int n_conn = 0;
        int n_conn_promoted = 0;
        for (auto i = n->connections().begin();
             i != n->connections().end();)
          {
            Port *conn = *i;
            ++i;
            if (conn->is_output()
                || conn->is_bidir())
              continue;

            ++n_conn;
            int conn_gc = port_gc(conn, true);
            if ((conn_gc & gc) == gc)
              {
                ++n_conn_promoted;
                conn->connect(t);
              }
          }

        gb_inst->find_port("USER_SIGNAL_TO_GLOBAL_BUFFER")->connect(n);
        gb_inst->find_port("GLOBAL_BUFFER_OUTPUT")->connect(t);

        ++n_global;
        ++gc_global[gc];
        extend(gb_inst_gc, gb_inst, gc);
        for (uint8_t gc2 : global_classes)
          {
            if ((gc2 & gc) == gc)
              ++gc_used[gc2];
          }

        *logs << "  promoted " << n->name()
              << ", " << n_conn_promoted << " / " << n_conn << "\n";
      }
    L:;
    }

  *logs << "  promoted " << n_promoted << " nets\n";
  for (const auto &p : gc_promoted)
    {
      if (p.second)
        *logs << "    " << p.second << " " << global_class_name(p.first) << "\n";
    }
  *logs << "  " << n_global << " globals\n";
  for (const auto &p : gc_global)
    {
      if (p.second)
        *logs << "    " << p.second << " " << global_class_name(p.first) << "\n";
    }

  d->prune();
}

void
promote_globals(DesignState &ds, bool do_promote)
{
  Promoter promoter(ds);
  promoter.promote(do_promote);
}
<|endoftext|>