<commit_before>/*

Copyright (c) 2007, 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/storage.hpp"
#include <deque>
#include "libtorrent/disk_io_thread.hpp"

namespace libtorrent
{

	disk_io_thread::disk_io_thread(int block_size)
		: m_abort(false)
		, m_queue_buffer_size(0)
		, m_pool(block_size)
		, m_disk_io_thread(boost::ref(*this))
	{}

	disk_io_thread::~disk_io_thread()
	{
		boost::mutex::scoped_lock l(m_mutex);
		m_abort = true;
		m_signal.notify_all();
		l.unlock();

		m_disk_io_thread.join();
	}

	// aborts read operations
	void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s)
	{
		boost::mutex::scoped_lock l(m_mutex);
		// read jobs are aborted, write and move jobs are syncronized
		for (std::deque<disk_io_job>::iterator i = m_jobs.begin();
			i != m_jobs.end();)
		{
			if (i->storage != s)
			{
				++i;
				continue;
			}
			if (i->action == disk_io_job::read)
			{
				i->callback(-1, *i);
				m_jobs.erase(i++);
				continue;
			}
			++i;
		}
		m_signal.notify_all();
	}

	bool range_overlap(int start1, int length1, int start2, int length2)
	{
		return (start1 <= start2 && start1 + length1 > start2)
			|| (start2 <= start1 && start2 + length2 > start1);
	}

	namespace
	{
		bool operator<(disk_io_job const& lhs, disk_io_job const& rhs)
		{
			if (lhs.storage.get() < rhs.storage.get()) return true;
			if (lhs.storage.get() > rhs.storage.get()) return false;
			if (lhs.piece < rhs.piece) return true;
			if (lhs.piece > rhs.piece) return false;
			if (lhs.offset < rhs.offset) return true;
//			if (lhs.offset > rhs.offset) return false;
			return false;
		}
	}

	void disk_io_thread::add_job(disk_io_job const& j
		, boost::function<void(int, disk_io_job const&)> const& f)
	{
		assert(!j.callback);
		boost::mutex::scoped_lock l(m_mutex);

		std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
		if (j.action == disk_io_job::read)
		{
			// when we're reading, we may not skip
			// ahead of any write operation that overlaps
			// the region we're reading
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::read && *i < j)
					break;
				if (i->action == disk_io_job::write
					&& i->storage == j.storage
					&& i->piece == j.piece
					&& range_overlap(i->offset, i->buffer_size
						, j.offset, j.buffer_size))
				{
					// we have to stop, and we haven't
					// found a suitable place for this job
					// so just queue it up at the end
					i = m_jobs.rbegin();
					break;
				}
			}
		}
		else if (j.action == disk_io_job::write)
		{
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::write && *i < j)
				{
					if (i != m_jobs.rbegin()
						&& i.base()->storage.get() != j.storage.get())
						i = m_jobs.rbegin();
					break;
				}
			}
		}

		if (i == m_jobs.rend()) i = m_jobs.rbegin();

		std::deque<disk_io_job>::iterator k = m_jobs.insert(i.base(), j);
		k->callback.swap(const_cast<boost::function<void(int, disk_io_job const&)>&>(f));
		if (j.action == disk_io_job::write)
			m_queue_buffer_size += j.buffer_size;
		assert(j.storage.get());
		m_signal.notify_all();
	}

	char* disk_io_thread::allocate_buffer()
	{
		boost::mutex::scoped_lock l(m_mutex);
		return (char*)m_pool.ordered_malloc();
	}

	void disk_io_thread::operator()()
	{
		for (;;)
		{
			boost::mutex::scoped_lock l(m_mutex);
			while (m_jobs.empty() && !m_abort)
				m_signal.wait(l);
			if (m_abort && m_jobs.empty()) return;

			boost::function<void(int, disk_io_job const&)> handler;
			handler.swap(m_jobs.front().callback);
			disk_io_job j = m_jobs.front();
			m_jobs.pop_front();
			m_queue_buffer_size -= j.buffer_size;
			l.unlock();

			int ret = 0;

			try
			{
//				std::cerr << "DISK THREAD: executing job: " << j.action << std::endl;
				switch (j.action)
				{
					case disk_io_job::read:
						l.lock();
						j.buffer = (char*)m_pool.ordered_malloc();
						l.unlock();
						if (j.buffer == 0)
						{
							ret = -1;
							j.str = "out of memory";
						}
						else
						{
							ret = j.storage->read_impl(j.buffer, j.piece, j.offset
								, j.buffer_size);

							// simulates slow drives
							// usleep(300);
						}
						break;
					case disk_io_job::write:
						assert(j.buffer);
						j.storage->write_impl(j.buffer, j.piece, j.offset
							, j.buffer_size);

						// simulates a slow drive
						// usleep(300);
						break;
					case disk_io_job::hash:
						{
							sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
							j.str.resize(20);
							std::memcpy(&j.str[0], &h[0], 20);
						}
						break;
					case disk_io_job::move_storage:
						ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
						break;
					case disk_io_job::release_files:
						j.storage->release_files_impl();
						break;
				}
			}
			catch (std::exception& e)
			{
//				std::cerr << "DISK THREAD: exception: " << e.what() << std::endl;
				j.str = e.what();
				ret = -1;
			}

//			if (!handler) std::cerr << "DISK THREAD: no callback specified" << std::endl;
//			else std::cerr << "DISK THREAD: invoking callback" << std::endl;
			try { if (handler) handler(ret, j); }
			catch (std::exception&) {}

			if (j.buffer) m_pool.ordered_free(j.buffer);
		}
	}
}

<commit_msg>fixed mutex issue in disk io thread<commit_after>/*

Copyright (c) 2007, 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/storage.hpp"
#include <deque>
#include "libtorrent/disk_io_thread.hpp"

namespace libtorrent
{

	disk_io_thread::disk_io_thread(int block_size)
		: m_abort(false)
		, m_queue_buffer_size(0)
		, m_pool(block_size)
		, m_disk_io_thread(boost::ref(*this))
	{}

	disk_io_thread::~disk_io_thread()
	{
		boost::mutex::scoped_lock l(m_mutex);
		m_abort = true;
		m_signal.notify_all();
		l.unlock();

		m_disk_io_thread.join();
	}

	// aborts read operations
	void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s)
	{
		boost::mutex::scoped_lock l(m_mutex);
		// read jobs are aborted, write and move jobs are syncronized
		for (std::deque<disk_io_job>::iterator i = m_jobs.begin();
			i != m_jobs.end();)
		{
			if (i->storage != s)
			{
				++i;
				continue;
			}
			if (i->action == disk_io_job::read)
			{
				i->callback(-1, *i);
				m_jobs.erase(i++);
				continue;
			}
			++i;
		}
		m_signal.notify_all();
	}

	bool range_overlap(int start1, int length1, int start2, int length2)
	{
		return (start1 <= start2 && start1 + length1 > start2)
			|| (start2 <= start1 && start2 + length2 > start1);
	}

	namespace
	{
		bool operator<(disk_io_job const& lhs, disk_io_job const& rhs)
		{
			if (lhs.storage.get() < rhs.storage.get()) return true;
			if (lhs.storage.get() > rhs.storage.get()) return false;
			if (lhs.piece < rhs.piece) return true;
			if (lhs.piece > rhs.piece) return false;
			if (lhs.offset < rhs.offset) return true;
//			if (lhs.offset > rhs.offset) return false;
			return false;
		}
	}

	void disk_io_thread::add_job(disk_io_job const& j
		, boost::function<void(int, disk_io_job const&)> const& f)
	{
		assert(!j.callback);
		boost::mutex::scoped_lock l(m_mutex);

		std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
		if (j.action == disk_io_job::read)
		{
			// when we're reading, we may not skip
			// ahead of any write operation that overlaps
			// the region we're reading
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::read && *i < j)
					break;
				if (i->action == disk_io_job::write
					&& i->storage == j.storage
					&& i->piece == j.piece
					&& range_overlap(i->offset, i->buffer_size
						, j.offset, j.buffer_size))
				{
					// we have to stop, and we haven't
					// found a suitable place for this job
					// so just queue it up at the end
					i = m_jobs.rbegin();
					break;
				}
			}
		}
		else if (j.action == disk_io_job::write)
		{
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::write && *i < j)
				{
					if (i != m_jobs.rbegin()
						&& i.base()->storage.get() != j.storage.get())
						i = m_jobs.rbegin();
					break;
				}
			}
		}

		if (i == m_jobs.rend()) i = m_jobs.rbegin();

		std::deque<disk_io_job>::iterator k = m_jobs.insert(i.base(), j);
		k->callback.swap(const_cast<boost::function<void(int, disk_io_job const&)>&>(f));
		if (j.action == disk_io_job::write)
			m_queue_buffer_size += j.buffer_size;
		assert(j.storage.get());
		m_signal.notify_all();
	}

	char* disk_io_thread::allocate_buffer()
	{
		boost::mutex::scoped_lock l(m_mutex);
		return (char*)m_pool.ordered_malloc();
	}

	void disk_io_thread::operator()()
	{
		for (;;)
		{
			boost::mutex::scoped_lock l(m_mutex);
			while (m_jobs.empty() && !m_abort)
				m_signal.wait(l);
			if (m_abort && m_jobs.empty()) return;

			boost::function<void(int, disk_io_job const&)> handler;
			handler.swap(m_jobs.front().callback);
			disk_io_job j = m_jobs.front();
			m_jobs.pop_front();
			m_queue_buffer_size -= j.buffer_size;
			l.unlock();

			int ret = 0;

			try
			{
//				std::cerr << "DISK THREAD: executing job: " << j.action << std::endl;
				switch (j.action)
				{
					case disk_io_job::read:
						l.lock();
						j.buffer = (char*)m_pool.ordered_malloc();
						l.unlock();
						if (j.buffer == 0)
						{
							ret = -1;
							j.str = "out of memory";
						}
						else
						{
							ret = j.storage->read_impl(j.buffer, j.piece, j.offset
								, j.buffer_size);

							// simulates slow drives
							// usleep(300);
						}
						break;
					case disk_io_job::write:
						assert(j.buffer);
						j.storage->write_impl(j.buffer, j.piece, j.offset
							, j.buffer_size);

						// simulates a slow drive
						// usleep(300);
						break;
					case disk_io_job::hash:
						{
							sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
							j.str.resize(20);
							std::memcpy(&j.str[0], &h[0], 20);
						}
						break;
					case disk_io_job::move_storage:
						ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
						break;
					case disk_io_job::release_files:
						j.storage->release_files_impl();
						break;
				}
			}
			catch (std::exception& e)
			{
//				std::cerr << "DISK THREAD: exception: " << e.what() << std::endl;
				j.str = e.what();
				ret = -1;
			}

//			if (!handler) std::cerr << "DISK THREAD: no callback specified" << std::endl;
//			else std::cerr << "DISK THREAD: invoking callback" << std::endl;
			try { if (handler) handler(ret, j); }
			catch (std::exception&) {}

			if (j.buffer)
			{
				l.lock();
				m_pool.ordered_free(j.buffer);
			}
		}
	}
}

<|endoftext|>


<commit_before>/* dlvhex -- Answer-Set Programming with external interfaces.
 * Copyright (C) 2005, 2006, 2007 Roman Schindlauer
 *
 * This file is part of dlvhex.
 *
 * dlvhex is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * dlvhex 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with dlvhex; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */

/**
 * @file AtomSet.cpp
 * @author Roman Schindlauer
 * @date Tue Feb  7 17:19:18 CET 2006
 *
 * @brief AtomSet class.
 *
 *
 */

#include <vector>
#include <algorithm>

#include "dlvhex/AtomSet.h"

DLVHEX_NAMESPACE_BEGIN

void
multiplySets(std::vector<AtomSet>& s1,
			 std::vector<AtomSet>& s2,
			 std::vector<AtomSet>& result)
{
	//
	// write result into temporary vector. in case the result parameter
	// is one of the two input vectors
	//
	std::vector<AtomSet> tmpset;

	AtomSet un;

//	unsigned outer = 1;
	for (std::vector<AtomSet>::iterator i1 = s1.begin();
			i1 != s1.end();
			++i1)
	{
//		unsigned inner = 1;
//		std::cerr << "outer loop: " << outer++ << std::endl;
//		std::cerr << "outer set has: " << (*i1).size() << std::endl;
		for (std::vector<AtomSet>::iterator i2 = s2.begin();
				i2 != s2.end();
				++i2)
		{
//			std::cerr << "inner loop: " << inner++ << std::endl;
			//
			// make union of two atomsets:
			//
			un = *i1;
			un.insert(*i2);

			//
			// now ensure minimality:
			//
			bool add = true;

			std::vector<AtomSet>::iterator curras = tmpset.begin();

//			unsigned i = 1;

			if (((*i1).size() > 0) && ((*i2).size() > 0))
			while (curras != tmpset.end())
			{
//				std::cerr << "looking at existing set " << i++
//					<< "   new union: " << un.size() << " current: " << (*curras).size() << std::endl;
				//
				// is the new one a superset (or equal) than an existing one
				//
				if (std::includes(un.begin(), un.end(), (*curras).begin(), (*curras).end()))
				{
//					std::cerr << "	 new union is superset!" << std::endl;
//					std::cerr << "	 new union: " << un.size() << " current: " << (*curras).size() << std::endl;
					add = false;
					break;
				}

				//
				// is the new one a subset of an existing one? Must be a *real* subset,
				// if we passed the previous "if"!
				//
				if (std::includes((*curras).begin(), (*curras).end(), un.begin(), un.end()))
				{
//					std::cerr << "	 new union is subset!" << std::endl;
					//
					// remove existing one
					//
					tmpset.erase(curras);
					break;
				}

				curras++;
			}

			if (add)
				tmpset.push_back(un);
		}
	}

	//
	// now we can write the result
	//
	swap(result, tmpset);
}

AtomSet::const_iterator
AtomSet::begin() const
{
	return const_iterator(atoms.begin());
}

AtomSet::const_iterator
AtomSet::end() const
{
	return const_iterator(atoms.end());
}

void
AtomSet::clear()
{
	atoms.clear();
}

bool
AtomSet::empty() const
{
	return atoms.empty();
}

size_t
AtomSet::size() const
{
	return atoms.size();
}

void
AtomSet::insert(const AtomPtr& ap)
{
	/// @todo test if *ap really exists

	atoms.insert(ap);
}

void
AtomSet::insert(const AtomSet& add)
{
	atoms.insert(add.atoms.begin(), add.atoms.end());
}

AtomSet
AtomSet::difference(const AtomSet& as) const
{
  AtomSet res;

  std::set_difference(this->atoms.begin(), this->atoms.end(),
		      as.atoms.begin(), as.atoms.end(),
		      std::inserter(res.atoms, res.atoms.begin())
		      );

  return res;
}

void
AtomSet::matchPredicate(const std::string& pred,
			AtomSet& matched) const
{
	/// @todo: stdlib algorithm!
	for (atomset_t::const_iterator a = atoms.begin();
		 a != atoms.end();
		 a++)
	{
		if ((*a)->getPredicate() == pred)
			matched.atoms.insert(*a);
	}
}

void
AtomSet::matchAtom(const AtomPtr& atom,
		   AtomSet& matched) const
{
	/// @todo: stdlib algorithm!
	for (atomset_t::const_iterator a = atoms.begin();
		 a != atoms.end();
		 a++)
	{
		if ((*a)->unifiesWith(atom))
			matched.atoms.insert(*a);
	}
}

void
AtomSet::accept(BaseVisitor& v)
{
  v.visit(this);
}

/**
 * @brief General purpose predicate functor, which returns true iff
 * predicate of g matches pred.
 */
struct PredicateMatches : public std::binary_function<AtomPtr, std::string, bool>
{
  bool
  operator() (const AtomPtr& g, const std::string& pred) const
  {
    return (g->getPredicate() == Term(pred));
  }
};

void
AtomSet::remove(const std::string& pred)
{
	atomset_t::iterator cur = atoms.begin();

	atomset_t::const_iterator last = atoms.end();

	while ((cur = std::find_if(cur, last, std::bind2nd(PredicateMatches(), pred))) != last)
	{
		atomset_t::iterator tmp = cur++;

		atoms.erase(tmp);
	}
}

void
AtomSet::remove(const std::vector<std::string>& preds)
{
	for (std::vector<std::string>::const_iterator predit = preds.begin();
		 predit != preds.end();
		 ++predit)
	{
		remove(*predit);
	}
}

void
AtomSet::keep(const std::vector<std::string>& preds)
{
	atomset_t::iterator cur = atoms.begin();

	atomset_t::const_iterator last = atoms.end();

	//
	// go through all atoms of this set
	//
	while (cur != last)
	{
		//
		// look if the current atom is in the filter set
		//
		if ((std::find_if(preds.begin(),
						  preds.end(),
				  std::bind1st(PredicateMatches(), *cur))) == preds.end())
		{
			//
			// if not, delete this atom
			//
			atomset_t::iterator tmp = cur++;

			atoms.erase(tmp);
		}
		else
		{
			cur++;
		}
	}
}

void
AtomSet::keepPos()
{
	atomset_t::iterator cur = atoms.begin();

	atomset_t::const_iterator last = atoms.end();

	//
	// go through all atoms of this set
	//
	while (cur != last)
	{
		if ((*cur)->isStronglyNegated())
		{
			atomset_t::iterator tmp = cur++;

			atoms.erase(tmp);
		}
		else
		{
			cur++;
		}
	}
}

/**
 * @brief General purpose predicate functor, which returns true iff
 * (*g == a).
 */
struct AtomMatches : public std::binary_function<AtomPtr, Atom, bool>
{
  bool
  operator() (const AtomPtr& g, const Atom& a) const
  {
    return (*g == a);
  }
};

bool
AtomSet::isConsistent() const
{
	atomset_t::iterator cur = atoms.begin();

	atomset_t::const_iterator last = atoms.end();

	//
	// go through all atoms of this set
	//
	while (cur != last)
	{
		Atom a(**cur);
		a.negate();

		//
		// see if 'cur' occurs negated (i.e., 'a') in the range of 'cur+1' to
		// 'last'
		//
		if (std::find_if(++cur, last, std::bind2nd(AtomMatches(), a)) != last)
			return false;
	}

	return true;
}

bool
AtomSet::operator== (const AtomSet& atomset2) const
{
	return ((this->size() == atomset2.size())
	  && std::equal(this->begin(), this->end(), atomset2.begin()));
}

bool
AtomSet::operator!= (const AtomSet& atomset2) const
{
	return !(*this == atomset2);
}

int
AtomSet::operator< (const AtomSet& atomset2) const
{
	if (this->size() < atomset2.size())
		return true;

	if (this->size() > atomset2.size())
		return false;

	//return !(std::includes(this->begin(), this->end(), atomset2.begin(), atomset2.end()));

	// find first mismatch
	std::pair<AtomSet::const_iterator, AtomSet::const_iterator> result;
	result = std::mismatch(this->begin(), this->end(), atomset2.begin());

	//
	// no mismatch? then they are equal!
	//
	if (result.first == this->end())
		return false;

	return *(result.first) < *(result.second);
}

DLVHEX_NAMESPACE_END

/* vim: set noet sw=4 ts=4 tw=80: */

// Local Variables:
// mode: C++
// End:
<commit_msg>(AtomSet::difference): Fix set difference.<commit_after>/* dlvhex -- Answer-Set Programming with external interfaces.
 * Copyright (C) 2005, 2006, 2007 Roman Schindlauer
 *
 * This file is part of dlvhex.
 *
 * dlvhex is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * dlvhex 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with dlvhex; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */

/**
 * @file AtomSet.cpp
 * @author Roman Schindlauer
 * @date Tue Feb  7 17:19:18 CET 2006
 *
 * @brief AtomSet class.
 *
 *
 */

#include <vector>
#include <algorithm>

#include "dlvhex/AtomSet.h"

DLVHEX_NAMESPACE_BEGIN

void
multiplySets(std::vector<AtomSet>& s1,
			 std::vector<AtomSet>& s2,
			 std::vector<AtomSet>& result)
{
	//
	// write result into temporary vector. in case the result parameter
	// is one of the two input vectors
	//
	std::vector<AtomSet> tmpset;

	AtomSet un;

//	unsigned outer = 1;
	for (std::vector<AtomSet>::iterator i1 = s1.begin();
			i1 != s1.end();
			++i1)
	{
//		unsigned inner = 1;
//		std::cerr << "outer loop: " << outer++ << std::endl;
//		std::cerr << "outer set has: " << (*i1).size() << std::endl;
		for (std::vector<AtomSet>::iterator i2 = s2.begin();
				i2 != s2.end();
				++i2)
		{
//			std::cerr << "inner loop: " << inner++ << std::endl;
			//
			// make union of two atomsets:
			//
			un = *i1;
			un.insert(*i2);

			//
			// now ensure minimality:
			//
			bool add = true;

			std::vector<AtomSet>::iterator curras = tmpset.begin();

//			unsigned i = 1;

			if (((*i1).size() > 0) && ((*i2).size() > 0))
			while (curras != tmpset.end())
			{
//				std::cerr << "looking at existing set " << i++
//					<< "   new union: " << un.size() << " current: " << (*curras).size() << std::endl;
				//
				// is the new one a superset (or equal) than an existing one
				//
				if (std::includes(un.begin(), un.end(), (*curras).begin(), (*curras).end()))
				{
//					std::cerr << "	 new union is superset!" << std::endl;
//					std::cerr << "	 new union: " << un.size() << " current: " << (*curras).size() << std::endl;
					add = false;
					break;
				}

				//
				// is the new one a subset of an existing one? Must be a *real* subset,
				// if we passed the previous "if"!
				//
				if (std::includes((*curras).begin(), (*curras).end(), un.begin(), un.end()))
				{
//					std::cerr << "	 new union is subset!" << std::endl;
					//
					// remove existing one
					//
					tmpset.erase(curras);
					break;
				}

				curras++;
			}

			if (add)
				tmpset.push_back(un);
		}
	}

	//
	// now we can write the result
	//
	swap(result, tmpset);
}

AtomSet::const_iterator
AtomSet::begin() const
{
	return const_iterator(atoms.begin());
}

AtomSet::const_iterator
AtomSet::end() const
{
	return const_iterator(atoms.end());
}

void
AtomSet::clear()
{
	atoms.clear();
}

bool
AtomSet::empty() const
{
	return atoms.empty();
}

size_t
AtomSet::size() const
{
	return atoms.size();
}

void
AtomSet::insert(const AtomPtr& ap)
{
	/// @todo test if *ap really exists

	atoms.insert(ap);
}

void
AtomSet::insert(const AtomSet& add)
{
	atoms.insert(add.atoms.begin(), add.atoms.end());
}

AtomSet
AtomSet::difference(const AtomSet& as) const
{
  AtomSet res;

//   std::set_difference(this->atoms.begin(), this->atoms.end(),
// 		      as.atoms.begin(), as.atoms.end(),
// 		      std::inserter(res.atoms, res.atoms.begin())
// 		      );

  for (atomset_t::const_iterator a = atoms.begin();
       a != atoms.end();
       ++a)
    {
      if (as.atoms.find(*a) == as.atoms.end())
	res.atoms.insert(*a);
    }

  return res;
}

void
AtomSet::matchPredicate(const std::string& pred,
			AtomSet& matched) const
{
	/// @todo: stdlib algorithm!
	for (atomset_t::const_iterator a = atoms.begin();
		 a != atoms.end();
		 a++)
	{
		if ((*a)->getPredicate() == pred)
			matched.atoms.insert(*a);
	}
}

void
AtomSet::matchAtom(const AtomPtr& atom,
		   AtomSet& matched) const
{
	/// @todo: stdlib algorithm!
	for (atomset_t::const_iterator a = atoms.begin();
		 a != atoms.end();
		 a++)
	{
		if ((*a)->unifiesWith(atom))
			matched.atoms.insert(*a);
	}
}

void
AtomSet::accept(BaseVisitor& v)
{
  v.visit(this);
}

/**
 * @brief General purpose predicate functor, which returns true iff
 * predicate of g matches pred.
 */
struct PredicateMatches : public std::binary_function<AtomPtr, std::string, bool>
{
  bool
  operator() (const AtomPtr& g, const std::string& pred) const
  {
    return (g->getPredicate() == Term(pred));
  }
};

void
AtomSet::remove(const std::string& pred)
{
	atomset_t::iterator cur = atoms.begin();

	atomset_t::const_iterator last = atoms.end();

	while ((cur = std::find_if(cur, last, std::bind2nd(PredicateMatches(), pred))) != last)
	{
		atomset_t::iterator tmp = cur++;

		atoms.erase(tmp);
	}
}

void
AtomSet::remove(const std::vector<std::string>& preds)
{
	for (std::vector<std::string>::const_iterator predit = preds.begin();
		 predit != preds.end();
		 ++predit)
	{
		remove(*predit);
	}
}

void
AtomSet::keep(const std::vector<std::string>& preds)
{
	atomset_t::iterator cur = atoms.begin();

	atomset_t::const_iterator last = atoms.end();

	//
	// go through all atoms of this set
	//
	while (cur != last)
	{
		//
		// look if the current atom is in the filter set
		//
		if ((std::find_if(preds.begin(),
						  preds.end(),
				  std::bind1st(PredicateMatches(), *cur))) == preds.end())
		{
			//
			// if not, delete this atom
			//
			atomset_t::iterator tmp = cur++;

			atoms.erase(tmp);
		}
		else
		{
			cur++;
		}
	}
}

void
AtomSet::keepPos()
{
	atomset_t::iterator cur = atoms.begin();

	atomset_t::const_iterator last = atoms.end();

	//
	// go through all atoms of this set
	//
	while (cur != last)
	{
		if ((*cur)->isStronglyNegated())
		{
			atomset_t::iterator tmp = cur++;

			atoms.erase(tmp);
		}
		else
		{
			cur++;
		}
	}
}

/**
 * @brief General purpose predicate functor, which returns true iff
 * (*g == a).
 */
struct AtomMatches : public std::binary_function<AtomPtr, Atom, bool>
{
  bool
  operator() (const AtomPtr& g, const Atom& a) const
  {
    return (*g == a);
  }
};

bool
AtomSet::isConsistent() const
{
	atomset_t::iterator cur = atoms.begin();

	atomset_t::const_iterator last = atoms.end();

	//
	// go through all atoms of this set
	//
	while (cur != last)
	{
		Atom a(**cur);
		a.negate();

		//
		// see if 'cur' occurs negated (i.e., 'a') in the range of 'cur+1' to
		// 'last'
		//
		if (std::find_if(++cur, last, std::bind2nd(AtomMatches(), a)) != last)
			return false;
	}

	return true;
}

bool
AtomSet::operator== (const AtomSet& atomset2) const
{
	return ((this->size() == atomset2.size())
	  && std::equal(this->begin(), this->end(), atomset2.begin()));
}

bool
AtomSet::operator!= (const AtomSet& atomset2) const
{
	return !(*this == atomset2);
}

int
AtomSet::operator< (const AtomSet& atomset2) const
{
	if (this->size() < atomset2.size())
		return true;

	if (this->size() > atomset2.size())
		return false;

	//return !(std::includes(this->begin(), this->end(), atomset2.begin(), atomset2.end()));

	// find first mismatch
	std::pair<AtomSet::const_iterator, AtomSet::const_iterator> result;
	result = std::mismatch(this->begin(), this->end(), atomset2.begin());

	//
	// no mismatch? then they are equal!
	//
	if (result.first == this->end())
		return false;

	return *(result.first) < *(result.second);
}

DLVHEX_NAMESPACE_END

/* vim: set noet sw=4 ts=4 tw=80: */

// Local Variables:
// mode: C++
// End:
<|endoftext|>


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

#include "ClangdLSPServer.h"
#include "Path.h"
#include "Trace.h"
#include "Transport.h"
#include "index/Serialization.h"
#include "clang/Basic/Version.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <thread>

using namespace llvm;
using namespace clang;
using namespace clang::clangd;

// FIXME: remove this option when Dex is cheap enough.
static cl::opt<bool> UseDex("use-dex-index",
                            cl::desc("Use experimental Dex dynamic index."),
                            cl::init(false), cl::Hidden);

static cl::opt<Path> CompileCommandsDir(
    "compile-commands-dir",
    cl::desc("Specify a path to look for compile_commands.json. If path "
             "is invalid, clangd will look in the current directory and "
             "parent paths of each source file."));

static cl::opt<unsigned>
    WorkerThreadsCount("j", cl::desc("Number of async workers used by clangd"),
                       cl::init(getDefaultAsyncThreadsCount()));

// FIXME: also support "plain" style where signatures are always omitted.
enum CompletionStyleFlag { Detailed, Bundled };
static cl::opt<CompletionStyleFlag> CompletionStyle(
    "completion-style", cl::desc("Granularity of code completion suggestions"),
    cl::values(
        clEnumValN(Detailed, "detailed",
                   "One completion item for each semantically distinct "
                   "completion, with full type information."),
        clEnumValN(Bundled, "bundled",
                   "Similar completion items (e.g. function overloads) are "
                   "combined. Type information shown where possible.")),
    cl::init(Detailed));

// FIXME: Flags are the wrong mechanism for user preferences.
// We should probably read a dotfile or similar.
static cl::opt<bool> IncludeIneligibleResults(
    "include-ineligible-results",
    cl::desc("Include ineligible completion results (e.g. private members)"),
    cl::init(clangd::CodeCompleteOptions().IncludeIneligibleResults),
    cl::Hidden);

static cl::opt<JSONStreamStyle> InputStyle(
    "input-style", cl::desc("Input JSON stream encoding"),
    cl::values(
        clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"),
        clEnumValN(JSONStreamStyle::Delimited, "delimited",
                   "messages delimited by --- lines, with # comment support")),
    cl::init(JSONStreamStyle::Standard));

static cl::opt<bool> PrettyPrint("pretty", cl::desc("Pretty-print JSON output"),
                                 cl::init(false));

static cl::opt<Logger::Level> LogLevel(
    "log", cl::desc("Verbosity of log messages written to stderr"),
    cl::values(clEnumValN(Logger::Error, "error", "Error messages only"),
               clEnumValN(Logger::Info, "info", "High level execution tracing"),
               clEnumValN(Logger::Debug, "verbose", "Low level details")),
    cl::init(Logger::Info));

static cl::opt<bool>
    Test("lit-test",
         cl::desc("Abbreviation for -input-style=delimited -pretty "
                  "-run-synchronously -enable-test-scheme. "
                  "Intended to simplify lit tests."),
         cl::init(false), cl::Hidden);

static cl::opt<bool> EnableTestScheme(
    "enable-test-uri-scheme",
    cl::desc("Enable 'test:' URI scheme. Only use in lit tests."),
    cl::init(false), cl::Hidden);

enum PCHStorageFlag { Disk, Memory };
static cl::opt<PCHStorageFlag> PCHStorage(
    "pch-storage",
    cl::desc("Storing PCHs in memory increases memory usages, but may "
             "improve performance"),
    cl::values(clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"),
               clEnumValN(PCHStorageFlag::Memory, "memory",
                          "store PCHs in memory")),
    cl::init(PCHStorageFlag::Disk));

static cl::opt<int>
    LimitResults("limit-results",
                 cl::desc("Limit the number of results returned by clangd. "
                          "0 means no limit."),
                 cl::init(100));

static cl::opt<bool>
    RunSynchronously("run-synchronously",
                     cl::desc("Parse on main thread. If set, -j is ignored"),
                     cl::init(false), cl::Hidden);

static cl::opt<Path> ResourceDir("resource-dir",
                                 cl::desc("Directory for system clang headers"),
                                 cl::init(""), cl::Hidden);

static cl::opt<Path> InputMirrorFile(
    "input-mirror-file",
    cl::desc(
        "Mirror all LSP input to the specified file. Useful for debugging."),
    cl::init(""), cl::Hidden);

static cl::opt<bool> EnableIndex(
    "index",
    cl::desc(
        "Enable index-based features. By default, clangd maintains an index "
        "built from symbols in opened files. Global index support needs to "
        "enabled separatedly."),
    cl::init(true), cl::Hidden);

static cl::opt<bool> AllScopesCompletion(
    "all-scopes-completion",
    cl::desc(
        "If set to true, code completion will include index symbols that are "
        "not defined in the scopes (e.g. "
        "namespaces) visible from the code completion point. Such completions "
        "can insert scope qualifiers."),
    cl::init(false), cl::Hidden);

static cl::opt<bool>
    ShowOrigins("debug-origin", cl::desc("Show origins of completion items"),
                cl::init(clangd::CodeCompleteOptions().ShowOrigins),
                cl::Hidden);

static cl::opt<bool> HeaderInsertionDecorators(
    "header-insertion-decorators",
    cl::desc("Prepend a circular dot or space before the completion "
             "label, depending on whether "
             "an include line will be inserted or not."),
    cl::init(true));

static cl::opt<Path> IndexFile(
    "index-file",
    cl::desc(
        "Index file to build the static index. The file must have been created "
        "by a compatible clangd-index.\n"
        "WARNING: This option is experimental only, and will be removed "
        "eventually. Don't rely on it."),
    cl::init(""), cl::Hidden);

static cl::opt<bool> EnableBackgroundIndex(
    "background-index",
    cl::desc("Index project code in the background and persist index on disk. "
             "Experimental"),
    cl::init(false), cl::Hidden);

enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs };
static cl::opt<CompileArgsFrom> CompileArgsFrom(
    "compile_args_from", cl::desc("The source of compile commands"),
    cl::values(clEnumValN(LSPCompileArgs, "lsp",
                          "All compile commands come from LSP and "
                          "'compile_commands.json' files are ignored"),
               clEnumValN(FilesystemCompileArgs, "filesystem",
                          "All compile commands come from the "
                          "'compile_commands.json' files")),
    cl::init(FilesystemCompileArgs), cl::Hidden);

static cl::opt<bool> EnableFunctionArgSnippets(
    "function-arg-placeholders",
    cl::desc("When disabled, completions contain only parentheses for "
             "function calls. When enabled, completions also contain "
             "placeholders for method parameters."),
    cl::init(clangd::CodeCompleteOptions().EnableFunctionArgSnippets));

namespace {

/// \brief Supports a test URI scheme with relaxed constraints for lit tests.
/// The path in a test URI will be combined with a platform-specific fake
/// directory to form an absolute path. For example, test:///a.cpp is resolved
/// C:\clangd-test\a.cpp on Windows and /clangd-test/a.cpp on Unix.
class TestScheme : public URIScheme {
public:
  Expected<std::string> getAbsolutePath(StringRef /*Authority*/, StringRef Body,
                                        StringRef /*HintPath*/) const override {
    using namespace llvm::sys;
    // Still require "/" in body to mimic file scheme, as we want lengths of an
    // equivalent URI in both schemes to be the same.
    if (!Body.startswith("/"))
      return make_error<StringError>(
          "Expect URI body to be an absolute path starting with '/': " + Body,
          inconvertibleErrorCode());
    Body = Body.ltrim('/');
    SmallVector<char, 16> Path(Body.begin(), Body.end());
    path::native(Path);
    auto Err = fs::make_absolute(TestScheme::TestDir, Path);
    if (Err)
      llvm_unreachable("Failed to make absolute path in test scheme.");
    return std::string(Path.begin(), Path.end());
  }

  Expected<URI> uriFromAbsolutePath(StringRef AbsolutePath) const override {
    StringRef Body = AbsolutePath;
    if (!Body.consume_front(TestScheme::TestDir)) {
      return make_error<StringError>("Path " + AbsolutePath +
                                         " doesn't start with root " + TestDir,
                                     inconvertibleErrorCode());
    }

    return URI("test", /*Authority=*/"", sys::path::convert_to_slash(Body));
  }

private:
  const static char TestDir[];
};

#ifdef _WIN32
const char TestScheme::TestDir[] = "C:\\clangd-test";
#else
const char TestScheme::TestDir[] = "/clangd-test";
#endif

}

int main(int argc, char *argv[]) {
  sys::PrintStackTraceOnErrorSignal(argv[0]);
  cl::SetVersionPrinter([](raw_ostream &OS) {
    OS << clang::getClangToolFullVersion("clangd") << "\n";
  });
  cl::ParseCommandLineOptions(
      argc, argv,
      "clangd is a language server that provides IDE-like features to editors. "
      "\n\nIt should be used via an editor plugin rather than invoked "
      "directly. "
      "For more information, see:"
      "\n\thttps://clang.llvm.org/extra/clangd.html"
      "\n\thttps://microsoft.github.io/language-server-protocol/");
  if (Test) {
    RunSynchronously = true;
    InputStyle = JSONStreamStyle::Delimited;
    PrettyPrint = true;
    preventThreadStarvationInTests(); // Ensure background index makes progress.
  }
  if (Test || EnableTestScheme) {
    static URISchemeRegistry::Add<TestScheme> X(
        "test", "Test scheme for clangd lit tests.");
  }

  if (!RunSynchronously && WorkerThreadsCount == 0) {
    errs() << "A number of worker threads cannot be 0. Did you mean to "
              "specify -run-synchronously?";
    return 1;
  }

  if (RunSynchronously) {
    if (WorkerThreadsCount.getNumOccurrences())
      errs() << "Ignoring -j because -run-synchronously is set.\n";
    WorkerThreadsCount = 0;
  }

  // Validate command line arguments.
  Optional<raw_fd_ostream> InputMirrorStream;
  if (!InputMirrorFile.empty()) {
    std::error_code EC;
    InputMirrorStream.emplace(InputMirrorFile, /*ref*/ EC,
                              sys::fs::FA_Read | sys::fs::FA_Write);
    if (EC) {
      InputMirrorStream.reset();
      errs() << "Error while opening an input mirror file: " << EC.message();
    } else {
      InputMirrorStream->SetUnbuffered();
    }
  }

  // Setup tracing facilities if CLANGD_TRACE is set. In practice enabling a
  // trace flag in your editor's config is annoying, launching with
  // `CLANGD_TRACE=trace.json vim` is easier.
  Optional<raw_fd_ostream> TraceStream;
  std::unique_ptr<trace::EventTracer> Tracer;
  if (auto *TraceFile = getenv("CLANGD_TRACE")) {
    std::error_code EC;
    TraceStream.emplace(TraceFile, /*ref*/ EC,
                        sys::fs::FA_Read | sys::fs::FA_Write);
    if (EC) {
      TraceStream.reset();
      errs() << "Error while opening trace file " << TraceFile << ": "
             << EC.message();
    } else {
      Tracer = trace::createJSONTracer(*TraceStream, PrettyPrint);
    }
  }

  Optional<trace::Session> TracingSession;
  if (Tracer)
    TracingSession.emplace(*Tracer);

  // Use buffered stream to stderr (we still flush each log message). Unbuffered
  // stream can cause significant (non-deterministic) latency for the logger.
  errs().SetBuffered();
  StreamLogger Logger(errs(), LogLevel);
  clangd::LoggingSession LoggingSession(Logger);

  // If --compile-commands-dir arg was invoked, check value and override default
  // path.
  Optional<Path> CompileCommandsDirPath;
  if (!CompileCommandsDir.empty()) {
    if (sys::fs::exists(CompileCommandsDir)) {
      // We support passing both relative and absolute paths to the
      // --compile-commands-dir argument, but we assume the path is absolute in
      // the rest of clangd so we make sure the path is absolute before
      // continuing.
      SmallString<128> Path(CompileCommandsDir);
      if (std::error_code EC = sys::fs::make_absolute(Path)) {
        errs() << "Error while converting the relative path specified by "
                  "--compile-commands-dir to an absolute path: "
               << EC.message() << ". The argument will be ignored.\n";
      } else {
        CompileCommandsDirPath = Path.str();
      }
    } else {
      errs() << "Path specified by --compile-commands-dir does not exist. The "
                "argument will be ignored.\n";
    }
  }

  ClangdServer::Options Opts;
  switch (PCHStorage) {
  case PCHStorageFlag::Memory:
    Opts.StorePreamblesInMemory = true;
    break;
  case PCHStorageFlag::Disk:
    Opts.StorePreamblesInMemory = false;
    break;
  }
  if (!ResourceDir.empty())
    Opts.ResourceDir = ResourceDir;
  Opts.BuildDynamicSymbolIndex = EnableIndex;
  Opts.HeavyweightDynamicSymbolIndex = UseDex;
  Opts.BackgroundIndex = EnableBackgroundIndex;
  std::unique_ptr<SymbolIndex> StaticIdx;
  std::future<void> AsyncIndexLoad; // Block exit while loading the index.
  if (EnableIndex && !IndexFile.empty()) {
    // Load the index asynchronously. Meanwhile SwapIndex returns no results.
    SwapIndex *Placeholder;
    StaticIdx.reset(Placeholder = new SwapIndex(llvm::make_unique<MemIndex>()));
    AsyncIndexLoad = runAsync<void>([Placeholder] {
      if (auto Idx = loadIndex(IndexFile, /*UseDex=*/true))
        Placeholder->reset(std::move(Idx));
    });
    if (RunSynchronously)
      AsyncIndexLoad.wait();
  }
  Opts.StaticIndex = StaticIdx.get();
  Opts.AsyncThreadsCount = WorkerThreadsCount;

  clangd::CodeCompleteOptions CCOpts;
  CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
  CCOpts.Limit = LimitResults;
  CCOpts.BundleOverloads = CompletionStyle != Detailed;
  CCOpts.ShowOrigins = ShowOrigins;
  if (!HeaderInsertionDecorators) {
    CCOpts.IncludeIndicator.Insert.clear();
    CCOpts.IncludeIndicator.NoInsert.clear();
  }
  CCOpts.SpeculativeIndexRequest = Opts.StaticIndex;
  CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets;
  CCOpts.AllScopes = AllScopesCompletion;

  // Initialize and run ClangdLSPServer.
  // Change stdin to binary to not lose \r\n on windows.
  sys::ChangeStdinToBinary();
  auto Transport = newJSONTransport(
      stdin, outs(),
      InputMirrorStream ? InputMirrorStream.getPointer() : nullptr, PrettyPrint,
      InputStyle);
  ClangdLSPServer LSPServer(
      *Transport, CCOpts, CompileCommandsDirPath,
      /*UseDirBasedCDB=*/CompileArgsFrom == FilesystemCompileArgs, Opts);
  constexpr int NoShutdownRequestErrorCode = 1;
  set_thread_name("clangd.main");
  return LSPServer.run() ? 0 : NoShutdownRequestErrorCode;
}
<commit_msg>[clangd] Enable cross-namespace completions by default in clangd<commit_after>//===--- ClangdMain.cpp - clangd server loop ------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ClangdLSPServer.h"
#include "Path.h"
#include "Trace.h"
#include "Transport.h"
#include "index/Serialization.h"
#include "clang/Basic/Version.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <thread>

using namespace llvm;
using namespace clang;
using namespace clang::clangd;

// FIXME: remove this option when Dex is cheap enough.
static cl::opt<bool> UseDex("use-dex-index",
                            cl::desc("Use experimental Dex dynamic index."),
                            cl::init(false), cl::Hidden);

static cl::opt<Path> CompileCommandsDir(
    "compile-commands-dir",
    cl::desc("Specify a path to look for compile_commands.json. If path "
             "is invalid, clangd will look in the current directory and "
             "parent paths of each source file."));

static cl::opt<unsigned>
    WorkerThreadsCount("j", cl::desc("Number of async workers used by clangd"),
                       cl::init(getDefaultAsyncThreadsCount()));

// FIXME: also support "plain" style where signatures are always omitted.
enum CompletionStyleFlag { Detailed, Bundled };
static cl::opt<CompletionStyleFlag> CompletionStyle(
    "completion-style", cl::desc("Granularity of code completion suggestions"),
    cl::values(
        clEnumValN(Detailed, "detailed",
                   "One completion item for each semantically distinct "
                   "completion, with full type information."),
        clEnumValN(Bundled, "bundled",
                   "Similar completion items (e.g. function overloads) are "
                   "combined. Type information shown where possible.")),
    cl::init(Detailed));

// FIXME: Flags are the wrong mechanism for user preferences.
// We should probably read a dotfile or similar.
static cl::opt<bool> IncludeIneligibleResults(
    "include-ineligible-results",
    cl::desc("Include ineligible completion results (e.g. private members)"),
    cl::init(clangd::CodeCompleteOptions().IncludeIneligibleResults),
    cl::Hidden);

static cl::opt<JSONStreamStyle> InputStyle(
    "input-style", cl::desc("Input JSON stream encoding"),
    cl::values(
        clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"),
        clEnumValN(JSONStreamStyle::Delimited, "delimited",
                   "messages delimited by --- lines, with # comment support")),
    cl::init(JSONStreamStyle::Standard));

static cl::opt<bool> PrettyPrint("pretty", cl::desc("Pretty-print JSON output"),
                                 cl::init(false));

static cl::opt<Logger::Level> LogLevel(
    "log", cl::desc("Verbosity of log messages written to stderr"),
    cl::values(clEnumValN(Logger::Error, "error", "Error messages only"),
               clEnumValN(Logger::Info, "info", "High level execution tracing"),
               clEnumValN(Logger::Debug, "verbose", "Low level details")),
    cl::init(Logger::Info));

static cl::opt<bool>
    Test("lit-test",
         cl::desc("Abbreviation for -input-style=delimited -pretty "
                  "-run-synchronously -enable-test-scheme. "
                  "Intended to simplify lit tests."),
         cl::init(false), cl::Hidden);

static cl::opt<bool> EnableTestScheme(
    "enable-test-uri-scheme",
    cl::desc("Enable 'test:' URI scheme. Only use in lit tests."),
    cl::init(false), cl::Hidden);

enum PCHStorageFlag { Disk, Memory };
static cl::opt<PCHStorageFlag> PCHStorage(
    "pch-storage",
    cl::desc("Storing PCHs in memory increases memory usages, but may "
             "improve performance"),
    cl::values(clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"),
               clEnumValN(PCHStorageFlag::Memory, "memory",
                          "store PCHs in memory")),
    cl::init(PCHStorageFlag::Disk));

static cl::opt<int>
    LimitResults("limit-results",
                 cl::desc("Limit the number of results returned by clangd. "
                          "0 means no limit."),
                 cl::init(100));

static cl::opt<bool>
    RunSynchronously("run-synchronously",
                     cl::desc("Parse on main thread. If set, -j is ignored"),
                     cl::init(false), cl::Hidden);

static cl::opt<Path> ResourceDir("resource-dir",
                                 cl::desc("Directory for system clang headers"),
                                 cl::init(""), cl::Hidden);

static cl::opt<Path> InputMirrorFile(
    "input-mirror-file",
    cl::desc(
        "Mirror all LSP input to the specified file. Useful for debugging."),
    cl::init(""), cl::Hidden);

static cl::opt<bool> EnableIndex(
    "index",
    cl::desc(
        "Enable index-based features. By default, clangd maintains an index "
        "built from symbols in opened files. Global index support needs to "
        "enabled separatedly."),
    cl::init(true), cl::Hidden);

static cl::opt<bool> AllScopesCompletion(
    "all-scopes-completion",
    cl::desc(
        "If set to true, code completion will include index symbols that are "
        "not defined in the scopes (e.g. "
        "namespaces) visible from the code completion point. Such completions "
        "can insert scope qualifiers."),
    cl::init(true));

static cl::opt<bool>
    ShowOrigins("debug-origin", cl::desc("Show origins of completion items"),
                cl::init(clangd::CodeCompleteOptions().ShowOrigins),
                cl::Hidden);

static cl::opt<bool> HeaderInsertionDecorators(
    "header-insertion-decorators",
    cl::desc("Prepend a circular dot or space before the completion "
             "label, depending on whether "
             "an include line will be inserted or not."),
    cl::init(true));

static cl::opt<Path> IndexFile(
    "index-file",
    cl::desc(
        "Index file to build the static index. The file must have been created "
        "by a compatible clangd-index.\n"
        "WARNING: This option is experimental only, and will be removed "
        "eventually. Don't rely on it."),
    cl::init(""), cl::Hidden);

static cl::opt<bool> EnableBackgroundIndex(
    "background-index",
    cl::desc("Index project code in the background and persist index on disk. "
             "Experimental"),
    cl::init(false), cl::Hidden);

enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs };
static cl::opt<CompileArgsFrom> CompileArgsFrom(
    "compile_args_from", cl::desc("The source of compile commands"),
    cl::values(clEnumValN(LSPCompileArgs, "lsp",
                          "All compile commands come from LSP and "
                          "'compile_commands.json' files are ignored"),
               clEnumValN(FilesystemCompileArgs, "filesystem",
                          "All compile commands come from the "
                          "'compile_commands.json' files")),
    cl::init(FilesystemCompileArgs), cl::Hidden);

static cl::opt<bool> EnableFunctionArgSnippets(
    "function-arg-placeholders",
    cl::desc("When disabled, completions contain only parentheses for "
             "function calls. When enabled, completions also contain "
             "placeholders for method parameters."),
    cl::init(clangd::CodeCompleteOptions().EnableFunctionArgSnippets));

namespace {

/// \brief Supports a test URI scheme with relaxed constraints for lit tests.
/// The path in a test URI will be combined with a platform-specific fake
/// directory to form an absolute path. For example, test:///a.cpp is resolved
/// C:\clangd-test\a.cpp on Windows and /clangd-test/a.cpp on Unix.
class TestScheme : public URIScheme {
public:
  Expected<std::string> getAbsolutePath(StringRef /*Authority*/, StringRef Body,
                                        StringRef /*HintPath*/) const override {
    using namespace llvm::sys;
    // Still require "/" in body to mimic file scheme, as we want lengths of an
    // equivalent URI in both schemes to be the same.
    if (!Body.startswith("/"))
      return make_error<StringError>(
          "Expect URI body to be an absolute path starting with '/': " + Body,
          inconvertibleErrorCode());
    Body = Body.ltrim('/');
    SmallVector<char, 16> Path(Body.begin(), Body.end());
    path::native(Path);
    auto Err = fs::make_absolute(TestScheme::TestDir, Path);
    if (Err)
      llvm_unreachable("Failed to make absolute path in test scheme.");
    return std::string(Path.begin(), Path.end());
  }

  Expected<URI> uriFromAbsolutePath(StringRef AbsolutePath) const override {
    StringRef Body = AbsolutePath;
    if (!Body.consume_front(TestScheme::TestDir)) {
      return make_error<StringError>("Path " + AbsolutePath +
                                         " doesn't start with root " + TestDir,
                                     inconvertibleErrorCode());
    }

    return URI("test", /*Authority=*/"", sys::path::convert_to_slash(Body));
  }

private:
  const static char TestDir[];
};

#ifdef _WIN32
const char TestScheme::TestDir[] = "C:\\clangd-test";
#else
const char TestScheme::TestDir[] = "/clangd-test";
#endif

}

int main(int argc, char *argv[]) {
  sys::PrintStackTraceOnErrorSignal(argv[0]);
  cl::SetVersionPrinter([](raw_ostream &OS) {
    OS << clang::getClangToolFullVersion("clangd") << "\n";
  });
  cl::ParseCommandLineOptions(
      argc, argv,
      "clangd is a language server that provides IDE-like features to editors. "
      "\n\nIt should be used via an editor plugin rather than invoked "
      "directly. "
      "For more information, see:"
      "\n\thttps://clang.llvm.org/extra/clangd.html"
      "\n\thttps://microsoft.github.io/language-server-protocol/");
  if (Test) {
    RunSynchronously = true;
    InputStyle = JSONStreamStyle::Delimited;
    PrettyPrint = true;
    preventThreadStarvationInTests(); // Ensure background index makes progress.
  }
  if (Test || EnableTestScheme) {
    static URISchemeRegistry::Add<TestScheme> X(
        "test", "Test scheme for clangd lit tests.");
  }

  if (!RunSynchronously && WorkerThreadsCount == 0) {
    errs() << "A number of worker threads cannot be 0. Did you mean to "
              "specify -run-synchronously?";
    return 1;
  }

  if (RunSynchronously) {
    if (WorkerThreadsCount.getNumOccurrences())
      errs() << "Ignoring -j because -run-synchronously is set.\n";
    WorkerThreadsCount = 0;
  }

  // Validate command line arguments.
  Optional<raw_fd_ostream> InputMirrorStream;
  if (!InputMirrorFile.empty()) {
    std::error_code EC;
    InputMirrorStream.emplace(InputMirrorFile, /*ref*/ EC,
                              sys::fs::FA_Read | sys::fs::FA_Write);
    if (EC) {
      InputMirrorStream.reset();
      errs() << "Error while opening an input mirror file: " << EC.message();
    } else {
      InputMirrorStream->SetUnbuffered();
    }
  }

  // Setup tracing facilities if CLANGD_TRACE is set. In practice enabling a
  // trace flag in your editor's config is annoying, launching with
  // `CLANGD_TRACE=trace.json vim` is easier.
  Optional<raw_fd_ostream> TraceStream;
  std::unique_ptr<trace::EventTracer> Tracer;
  if (auto *TraceFile = getenv("CLANGD_TRACE")) {
    std::error_code EC;
    TraceStream.emplace(TraceFile, /*ref*/ EC,
                        sys::fs::FA_Read | sys::fs::FA_Write);
    if (EC) {
      TraceStream.reset();
      errs() << "Error while opening trace file " << TraceFile << ": "
             << EC.message();
    } else {
      Tracer = trace::createJSONTracer(*TraceStream, PrettyPrint);
    }
  }

  Optional<trace::Session> TracingSession;
  if (Tracer)
    TracingSession.emplace(*Tracer);

  // Use buffered stream to stderr (we still flush each log message). Unbuffered
  // stream can cause significant (non-deterministic) latency for the logger.
  errs().SetBuffered();
  StreamLogger Logger(errs(), LogLevel);
  clangd::LoggingSession LoggingSession(Logger);

  // If --compile-commands-dir arg was invoked, check value and override default
  // path.
  Optional<Path> CompileCommandsDirPath;
  if (!CompileCommandsDir.empty()) {
    if (sys::fs::exists(CompileCommandsDir)) {
      // We support passing both relative and absolute paths to the
      // --compile-commands-dir argument, but we assume the path is absolute in
      // the rest of clangd so we make sure the path is absolute before
      // continuing.
      SmallString<128> Path(CompileCommandsDir);
      if (std::error_code EC = sys::fs::make_absolute(Path)) {
        errs() << "Error while converting the relative path specified by "
                  "--compile-commands-dir to an absolute path: "
               << EC.message() << ". The argument will be ignored.\n";
      } else {
        CompileCommandsDirPath = Path.str();
      }
    } else {
      errs() << "Path specified by --compile-commands-dir does not exist. The "
                "argument will be ignored.\n";
    }
  }

  ClangdServer::Options Opts;
  switch (PCHStorage) {
  case PCHStorageFlag::Memory:
    Opts.StorePreamblesInMemory = true;
    break;
  case PCHStorageFlag::Disk:
    Opts.StorePreamblesInMemory = false;
    break;
  }
  if (!ResourceDir.empty())
    Opts.ResourceDir = ResourceDir;
  Opts.BuildDynamicSymbolIndex = EnableIndex;
  Opts.HeavyweightDynamicSymbolIndex = UseDex;
  Opts.BackgroundIndex = EnableBackgroundIndex;
  std::unique_ptr<SymbolIndex> StaticIdx;
  std::future<void> AsyncIndexLoad; // Block exit while loading the index.
  if (EnableIndex && !IndexFile.empty()) {
    // Load the index asynchronously. Meanwhile SwapIndex returns no results.
    SwapIndex *Placeholder;
    StaticIdx.reset(Placeholder = new SwapIndex(llvm::make_unique<MemIndex>()));
    AsyncIndexLoad = runAsync<void>([Placeholder] {
      if (auto Idx = loadIndex(IndexFile, /*UseDex=*/true))
        Placeholder->reset(std::move(Idx));
    });
    if (RunSynchronously)
      AsyncIndexLoad.wait();
  }
  Opts.StaticIndex = StaticIdx.get();
  Opts.AsyncThreadsCount = WorkerThreadsCount;

  clangd::CodeCompleteOptions CCOpts;
  CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
  CCOpts.Limit = LimitResults;
  CCOpts.BundleOverloads = CompletionStyle != Detailed;
  CCOpts.ShowOrigins = ShowOrigins;
  if (!HeaderInsertionDecorators) {
    CCOpts.IncludeIndicator.Insert.clear();
    CCOpts.IncludeIndicator.NoInsert.clear();
  }
  CCOpts.SpeculativeIndexRequest = Opts.StaticIndex;
  CCOpts.EnableFunctionArgSnippets = EnableFunctionArgSnippets;
  CCOpts.AllScopes = AllScopesCompletion;

  // Initialize and run ClangdLSPServer.
  // Change stdin to binary to not lose \r\n on windows.
  sys::ChangeStdinToBinary();
  auto Transport = newJSONTransport(
      stdin, outs(),
      InputMirrorStream ? InputMirrorStream.getPointer() : nullptr, PrettyPrint,
      InputStyle);
  ClangdLSPServer LSPServer(
      *Transport, CCOpts, CompileCommandsDirPath,
      /*UseDirBasedCDB=*/CompileArgsFrom == FilesystemCompileArgs, Opts);
  constexpr int NoShutdownRequestErrorCode = 1;
  set_thread_name("clangd.main");
  return LSPServer.run() ? 0 : NoShutdownRequestErrorCode;
}
<|endoftext|>


<commit_before>#include "ScoutObjectives.h"
#include <iostream>
using namespace BWAPI;

ScoutObjectives::ScoutObjectives():bEnnemy_found(false)
{

}

ScoutObjectives::~ScoutObjectives(){

}

bool ScoutObjectives::ennemy_found() const{
 return bEnnemy_found;
}

void ScoutObjectives::set_ennemy_found(bool b){
	bEnnemy_found=b;
}

std::list<Position> ScoutObjectives::get_Objectives(){
std::list<Position> temp;
	for each (Position pos in objectives){
		temp.push_back(pos);
		assigned_objectives.push_back(pos);
	}
	objectives.clear();
return temp;
}

void ScoutObjectives::find_ennemy(){

	//Scout the different possible bases
	myStartLocation = BWTA::getStartLocation(BWAPI::Broodwar->self());
	std::list<BWTA::BaseLocation*> path = getBestPath( BWTA::getStartLocations(), myStartLocation);
	Broodwar->printf("Number of bases : %d",path.size());

	for(std::list<BWTA::BaseLocation*>::iterator p=path.begin();p!=path.end();p++){
		objectives.push_back((*p)->getPosition());
	}
}

std::list<BWTA::BaseLocation*> ScoutObjectives::getBestPath( std::set<BWTA::BaseLocation* > baseLocations, BWTA::BaseLocation* myStartLocation) const
{
	std::list<BWTA::BaseLocation*> res;
	baseLocations.erase( myStartLocation);
	BWTA::BaseLocation* baseFrom = myStartLocation;
	while( !baseLocations.empty())
	{
		BWTA::BaseLocation* nearestBase = NULL;
		double dist = 0xFFFF;
		for( std::set<BWTA::BaseLocation* >::iterator b = baseLocations.begin(); b != baseLocations.end(); b++)
		{
			double dist2 = baseFrom->getGroundDistance( *b);
			if( dist2 <= 0) // Unreachable by walk.
				baseLocations.erase( nearestBase);
			if( dist2 < dist)
			{
				nearestBase = *b;
				dist = dist2;
			}
		}
		baseLocations.erase( nearestBase);
		res.push_back( nearestBase);
		baseFrom = nearestBase;
	}
	return res;
}

void ScoutObjectives::onUnitShow(BWAPI::Unit* unit){

	if(unit->getType().isResourceDepot() && ! this->ennemy_found()){
		this->set_ennemy_found(true);
		//Find the right base location
		std::set<BWTA::BaseLocation*> res = BWTA::getStartLocations();
		for(std::set<BWTA::BaseLocation* >::iterator b = res.begin(); b!= res.end(); ++b){
			if( (*b)->getTilePosition() == unit->getTilePosition() ){
				eStartLocation = (*b);
				break;
			}
		}

		if(eStartLocation == NULL)
			Broodwar -> printf("eStartLocation is NULL, problem...");
		Broodwar->printf("Ennemy main base found, waiting for objectives");
		BWTA::Region* region = eStartLocation->getRegion();

		explore_region(region);

	}
		//We assume that if the ennemy was not spotted and we find a ResourceDepot, then it is the main base : requires fast scout
}

bool ScoutObjectives::got_objectives(){

	return objectives.size() > 0;
}

void ScoutObjectives::explore_region(BWTA::Region* region){
	std::list<Position>::iterator pos;
	BWTA::Polygon polygon = (*region).getPolygon();
	std::list<Position> to_see;
	for(std::vector<Position>::iterator it = polygon.begin(); it != polygon.end(); ++it)
		to_see.push_back((*it));

	//Select a first position added to the objectives
	//TODO select a not yet seen position
	Position current_pos= polygon.getNearestPoint(eStartLocation->getPosition());
	objectives.push_back(current_pos);
	to_see.remove(current_pos);

	double max_dist=0;
	double test_dist=0;
	Position current_target;
	int size=to_see.size();
	while(size >0){
		max_dist=0;
		current_target=current_pos;
		//Find the farthest point of current_pos
		for(pos = to_see.begin(); pos != to_see.end(); ++pos){
			test_dist=(*pos).getApproxDistance(current_pos);
			if(test_dist > max_dist){
				max_dist=test_dist;
				current_target = (*pos);
			}
		}
		Broodwar->printf("ou ? x %d  y %d", current_target.x(), current_target.y());
		Broodwar->drawCircle(CoordinateType::Screen,current_target.x(), current_target.y(),200,Colors::Yellow, true);
	//	void drawCircleMap(int x, int y, int radius, Color color = Color(BWAPI::Colors::Green), bool isSolid = false);
		objectives.push_back(current_target);
		current_pos=current_target;
		to_see.remove(current_pos);
		size--;
	}
	Broodwar->printf("Nombre d'objectifs : %d", objectives.size());
}

void ScoutObjectives::accomplished(BWAPI::Position p){
this->assigned_objectives.remove(p);
}<commit_msg>branching ScoutManager<commit_after>#include "ScoutObjectives.h"
#include <iostream>
using namespace BWAPI;

ScoutObjectives::ScoutObjectives():bEnnemy_found(false)
{

}

ScoutObjectives::~ScoutObjectives(){

}

bool ScoutObjectives::ennemy_found() const{
 return bEnnemy_found;
}

void ScoutObjectives::set_ennemy_found(bool b){
	bEnnemy_found=b;
}

std::list<Position> ScoutObjectives::get_Objectives(){
std::list<Position> temp;
	for each (Position pos in objectives){
		temp.push_back(pos);
		assigned_objectives.push_back(pos);
	}
	objectives.clear();
return temp;
}

void ScoutObjectives::find_ennemy(){

	//Scout the different possible bases
	myStartLocation = BWTA::getStartLocation(BWAPI::Broodwar->self());
	std::list<BWTA::BaseLocation*> path = getBestPath( BWTA::getStartLocations(), myStartLocation);
	Broodwar->printf("Number of bases : %d",path.size());

	for(std::list<BWTA::BaseLocation*>::iterator p=path.begin();p!=path.end();p++){
		objectives.push_back((*p)->getPosition());
	}
}

std::list<BWTA::BaseLocation*> ScoutObjectives::getBestPath( std::set<BWTA::BaseLocation* > baseLocations, BWTA::BaseLocation* myStartLocation) const
{
	std::list<BWTA::BaseLocation*> res;
	baseLocations.erase( myStartLocation);
	BWTA::BaseLocation* baseFrom = myStartLocation;
	while( !baseLocations.empty())
	{
		BWTA::BaseLocation* nearestBase = NULL;
		double dist = 0xFFFF;
		for( std::set<BWTA::BaseLocation* >::iterator b = baseLocations.begin(); b != baseLocations.end(); b++)
		{
			double dist2 = baseFrom->getGroundDistance( *b);
			if( dist2 <= 0) // Unreachable by walk.
				baseLocations.erase( nearestBase);
			if( dist2 < dist)
			{
				nearestBase = *b;
				dist = dist2;
			}
		}
		baseLocations.erase( nearestBase);
		res.push_back( nearestBase);
		baseFrom = nearestBase;
	}
	return res;
}

void ScoutObjectives::onUnitShow(BWAPI::Unit* unit){

	if(unit->getType().isResourceDepot() && ! this->ennemy_found()){
		this->set_ennemy_found(true);
		//Find the right base location
		std::set<BWTA::BaseLocation*> res = BWTA::getStartLocations();
		for(std::set<BWTA::BaseLocation* >::iterator b = res.begin(); b!= res.end(); ++b){
			if( (*b)->getTilePosition() == unit->getTilePosition() ){
				eStartLocation = (*b);
				break;
			}
		}

		if(eStartLocation == NULL)
			Broodwar -> printf("eStartLocation is NULL, problem...");
		Broodwar->printf("Ennemy main base found, waiting for objectives");
		BWTA::Region* region = eStartLocation->getRegion();

		explore_region(region);

	}
		//We assume that if the ennemy was not spotted and we find a ResourceDepot, then it is the main base : requires fast scout
}

bool ScoutObjectives::got_objectives(){

	return objectives.size() > 0;
}

void ScoutObjectives::explore_region(BWTA::Region* region){
	std::list<Position>::iterator pos;
	BWTA::Polygon polygon = (*region).getPolygon();
	std::list<Position> to_see;
	for(std::vector<Position>::iterator it = polygon.begin(); it != polygon.end(); ++it)
		to_see.push_back((*it));

	//Select a first position added to the objectives
	//TODO select a not yet seen position
	Position current_pos= polygon.getNearestPoint(eStartLocation->getPosition());
	objectives.push_back(current_pos);
	to_see.remove(current_pos);

	double max_dist=0;
	double test_dist=0;
	Position current_target;
	int size=to_see.size();
	while(size >0){
		max_dist=0;
		current_target=current_pos;
		//Find the farthest point of current_pos
		for(pos = to_see.begin(); pos != to_see.end(); ++pos){
			test_dist=(*pos).getApproxDistance(current_pos);
			if(test_dist > max_dist){
				max_dist=test_dist;
				current_target = (*pos);
			}
		}
		Broodwar->printf("ou ? x %d  y %d", current_target.x(), current_target.y());
		Broodwar->drawCircle(CoordinateType::Screen,current_target.x(), current_target.y(),200,Colors::Yellow, true);
	//	void drawCircleMap(int x, int y, int radius, Color color = Color(BWAPI::Colors::Green), bool isSolid = false);
		objectives.push_back(current_target);
		current_pos=current_target;
		to_see.remove(current_pos);
		size--;
	}
	Broodwar->printf("Nombre d'objectifs : %d", objectives.size());
}

void ScoutObjectives::accomplished(BWAPI::Position p){

this->assigned_objectives.remove(p);
}<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2005 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/io.h>

//#define DEBUG_WKB_READER 1

namespace geos {

string WKBReader::BAD_GEOM_TYPE_MSG = "bad geometry type encountered in ";

ostream &
WKBReader::printHEX(istream &is, ostream &os)
{
	ios_base::fmtflags fl = os.flags(); // take note of output stream flags

	// Set hex,uppercase,fill and width output stream flags
	os.setf(ios::uppercase);
	os.setf(ios::hex, ios::basefield);
	os.fill('0');

	long pos = is.tellg(); // take note of input stream get pointer
	is.seekg(0, ios::beg); // rewind input stream

	char each=0;
	while(!is.eof())
	{
		is.read(&each, 1);
		os << setw(2) <<
			static_cast<int>(static_cast<unsigned char>(each));
	}

	is.clear(); // clear input stream eof flag
	is.seekg(pos); // reset input stream position
	os.setf(fl);  // reset output stream status
	return os;
}

Geometry *
WKBReader::read(istream &is)
{
	dis.setInStream(&is); // will default to machine endian
	return readGeometry();
}

Geometry *
WKBReader::readGeometry()
{
	// determine byte order
	byte byteOrder = dis.readByte();

#if DEBUG_WKB_READER
	cout<<"WKB byteOrder: "<<(int)byteOrder<<endl;
#endif

	// default is machine endian
	if (byteOrder == WKBConstants::wkbNDR)
		dis.setOrder(ByteOrderValues::ENDIAN_LITTLE);

	int typeInt = dis.readInt();
	int geometryType = typeInt & 0xff;

#if DEBUG_WKB_READER
	cout<<"WKB geometryType: "<<geometryType<<endl;
#endif

	bool hasZ = ((typeInt & 0x80000000) != 0);
	if (hasZ) inputDimension = 3;
	else inputDimension = 2; // doesn't handle M currently

#if DEBUG_WKB_READER
	cout<<"WKB hasZ: "<<hasZ<<endl;
#endif

#if DEBUG_WKB_READER
	cout<<"WKB dimensions: "<<inputDimension<<endl;
#endif

	// allocate space for ordValues
	if ( ordValues.size() < inputDimension )
		ordValues.resize(inputDimension);

	switch (geometryType) {
		case WKBConstants::wkbPoint :
			return readPoint();
		case WKBConstants::wkbLineString :
			return readLineString();
		case WKBConstants::wkbPolygon :
			return readPolygon();
		case WKBConstants::wkbMultiPoint :
			return readMultiPoint();
		case WKBConstants::wkbMultiLineString :
			return readMultiLineString();
		case WKBConstants::wkbMultiPolygon :
			return readMultiPolygon();
		case WKBConstants::wkbGeometryCollection :
			return readGeometryCollection();
	}
	throw new ParseException("Unknown WKB type " + geometryType);
}

Point *
WKBReader::readPoint()
{
	readCoordinate();
#if DEBUG_WKB_READER
	cout<<"Coordinates: "<<ordValues[0]<<","<<ordValues[1]<<endl;
#endif
	return factory.createPoint(Coordinate(ordValues[0], ordValues[1]));
}

LineString *
WKBReader::readLineString()
{
	int size = dis.readInt();
	CoordinateSequence *pts = readCoordinateSequence(size);
	return factory.createLineString(pts);
}

LinearRing *
WKBReader::readLinearRing()
{
	int size = dis.readInt();
	CoordinateSequence *pts = readCoordinateSequence(size);
	return factory.createLinearRing(pts);
}

Polygon *
WKBReader::readPolygon()
{
	int numRings = dis.readInt();
	LinearRing *shell = readLinearRing();

	vector<Geometry *>*holes=NULL;
	if ( numRings > 1 )
	{
		try {
			holes = new vector<Geometry *>(numRings-1);
			for (int i=0; i<numRings-1; i++)
				(*holes)[i] = (Geometry *)readLinearRing();
		} catch (...) {
			for (unsigned int i=0; i<holes->size(); i++)
				delete (*holes)[i];
			delete holes;
			delete shell;
			throw;
		}
	}
	return factory.createPolygon(shell, holes);
}

MultiPoint *
WKBReader::readMultiPoint()
{
	int numGeoms = dis.readInt();
	vector<Geometry *> *geoms = new vector<Geometry *>(numGeoms);

	try {
		for (int i=0; i<numGeoms; i++)
		{
			Geometry *g = readGeometry();
			if (!dynamic_cast<Point *>(g))
				throw new ParseException(BAD_GEOM_TYPE_MSG+
					" MultiPoint");
			(*geoms)[i] = g;
		}
	} catch (...) {
		for (unsigned int i=0; i<geoms->size(); i++)
			delete (*geoms)[i];
		delete geoms;
		throw;
	}
	return factory.createMultiPoint(geoms);
}

MultiLineString *
WKBReader::readMultiLineString()
{
	int numGeoms = dis.readInt();
	vector<Geometry *> *geoms = new vector<Geometry *>(numGeoms);

	try {
		for (int i=0; i<numGeoms; i++)
		{
			Geometry *g = readGeometry();
			if (!dynamic_cast<LineString *>(g))
				throw new ParseException(BAD_GEOM_TYPE_MSG+
					" LineString");
			(*geoms)[i] = g;
		}
	} catch (...) {
		for (unsigned int i=0; i<geoms->size(); i++)
			delete (*geoms)[i];
		delete geoms;
		throw;
	}
	return factory.createMultiLineString(geoms);
}

MultiPolygon *
WKBReader::readMultiPolygon()
{
	int numGeoms = dis.readInt();
	vector<Geometry *> *geoms = new vector<Geometry *>(numGeoms);

	try {
		for (int i=0; i<numGeoms; i++)
		{
			Geometry *g = readGeometry();
			if (!dynamic_cast<Polygon *>(g))
				throw new ParseException(BAD_GEOM_TYPE_MSG+
					" Polygon");
			(*geoms)[i] = g;
		}
	} catch (...) {
		for (unsigned int i=0; i<geoms->size(); i++)
			delete (*geoms)[i];
		delete geoms;
		throw;
	}
	return factory.createMultiPolygon(geoms);
}

GeometryCollection *
WKBReader::readGeometryCollection()
{
	int numGeoms = dis.readInt();
	vector<Geometry *> *geoms = new vector<Geometry *>(numGeoms);

	try {
		for (int i=0; i<numGeoms; i++)
			(*geoms)[i] = (readGeometry());
	} catch (...) {
		for (unsigned int i=0; i<geoms->size(); i++)
			delete (*geoms)[i];
		delete geoms;
		throw;
	}
	return factory.createGeometryCollection(geoms);
}

CoordinateSequence *
WKBReader::readCoordinateSequence(int size)
{
	CoordinateSequence *seq = factory.getCoordinateSequenceFactory()->create(size, inputDimension);
	unsigned int targetDim = seq->getDimension();
	if ( targetDim > inputDimension )
		targetDim = inputDimension;
	for (int i=0; i<size; i++) {
		readCoordinate();
		for (unsigned int j=0; j<targetDim; j++) {
			seq->setOrdinate(i, j, ordValues[j]);
		}
	}
	return seq;
}

void
WKBReader::readCoordinate()
{
	static const PrecisionModel &pm = *factory.getPrecisionModel();
	for (unsigned int i=0; i<inputDimension; ++i)
	{
		if ( i <= 1 ) ordValues[i] = pm.makePrecise(dis.readDouble());
		else ordValues[i] = dis.readDouble();
	}
}

} // namespace geos
<commit_msg>Added support for SRID flag in WKB (full EWKB is accepted now)<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2005 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/io.h>

//#define DEBUG_WKB_READER 1

namespace geos {

string WKBReader::BAD_GEOM_TYPE_MSG = "bad geometry type encountered in ";

ostream &
WKBReader::printHEX(istream &is, ostream &os)
{
	ios_base::fmtflags fl = os.flags(); // take note of output stream flags

	// Set hex,uppercase,fill and width output stream flags
	os.setf(ios::uppercase);
	os.setf(ios::hex, ios::basefield);
	os.fill('0');

	long pos = is.tellg(); // take note of input stream get pointer
	is.seekg(0, ios::beg); // rewind input stream

	char each=0;
	while(!is.eof())
	{
		is.read(&each, 1);
		os << setw(2) <<
			static_cast<int>(static_cast<unsigned char>(each));
	}

	is.clear(); // clear input stream eof flag
	is.seekg(pos); // reset input stream position
	os.setf(fl);  // reset output stream status
	return os;
}

Geometry *
WKBReader::read(istream &is)
{
	dis.setInStream(&is); // will default to machine endian
	return readGeometry();
}

Geometry *
WKBReader::readGeometry()
{
	// determine byte order
	byte byteOrder = dis.readByte();

#if DEBUG_WKB_READER
	cout<<"WKB byteOrder: "<<(int)byteOrder<<endl;
#endif

	// default is machine endian
	if (byteOrder == WKBConstants::wkbNDR)
		dis.setOrder(ByteOrderValues::ENDIAN_LITTLE);

	int typeInt = dis.readInt();
	int geometryType = typeInt & 0xff;

#if DEBUG_WKB_READER
	cout<<"WKB geometryType: "<<geometryType<<endl;
#endif

	bool hasZ = ((typeInt & 0x80000000) != 0);
	if (hasZ) inputDimension = 3;
	else inputDimension = 2; // doesn't handle M currently

#if DEBUG_WKB_READER
	cout<<"WKB hasZ: "<<hasZ<<endl;
#endif

#if DEBUG_WKB_READER
	cout<<"WKB dimensions: "<<inputDimension<<endl;
#endif

	bool hasSRID = ((typeInt & 0x20000000) != 0);

#if DEBUG_WKB_READER
	cout<<"WKB hasSRID: "<<hasZ<<endl;
#endif

	if (hasSRID) dis.readInt(); // skip SRID

	// allocate space for ordValues
	if ( ordValues.size() < inputDimension )
		ordValues.resize(inputDimension);

	switch (geometryType) {
		case WKBConstants::wkbPoint :
			return readPoint();
		case WKBConstants::wkbLineString :
			return readLineString();
		case WKBConstants::wkbPolygon :
			return readPolygon();
		case WKBConstants::wkbMultiPoint :
			return readMultiPoint();
		case WKBConstants::wkbMultiLineString :
			return readMultiLineString();
		case WKBConstants::wkbMultiPolygon :
			return readMultiPolygon();
		case WKBConstants::wkbGeometryCollection :
			return readGeometryCollection();
	}
	throw new ParseException("Unknown WKB type " + geometryType);
}

Point *
WKBReader::readPoint()
{
	readCoordinate();
#if DEBUG_WKB_READER
	cout<<"Coordinates: "<<ordValues[0]<<","<<ordValues[1]<<endl;
#endif
	return factory.createPoint(Coordinate(ordValues[0], ordValues[1]));
}

LineString *
WKBReader::readLineString()
{
	int size = dis.readInt();
	CoordinateSequence *pts = readCoordinateSequence(size);
	return factory.createLineString(pts);
}

LinearRing *
WKBReader::readLinearRing()
{
	int size = dis.readInt();
	CoordinateSequence *pts = readCoordinateSequence(size);
	return factory.createLinearRing(pts);
}

Polygon *
WKBReader::readPolygon()
{
	int numRings = dis.readInt();
	LinearRing *shell = readLinearRing();

	vector<Geometry *>*holes=NULL;
	if ( numRings > 1 )
	{
		try {
			holes = new vector<Geometry *>(numRings-1);
			for (int i=0; i<numRings-1; i++)
				(*holes)[i] = (Geometry *)readLinearRing();
		} catch (...) {
			for (unsigned int i=0; i<holes->size(); i++)
				delete (*holes)[i];
			delete holes;
			delete shell;
			throw;
		}
	}
	return factory.createPolygon(shell, holes);
}

MultiPoint *
WKBReader::readMultiPoint()
{
	int numGeoms = dis.readInt();
	vector<Geometry *> *geoms = new vector<Geometry *>(numGeoms);

	try {
		for (int i=0; i<numGeoms; i++)
		{
			Geometry *g = readGeometry();
			if (!dynamic_cast<Point *>(g))
				throw new ParseException(BAD_GEOM_TYPE_MSG+
					" MultiPoint");
			(*geoms)[i] = g;
		}
	} catch (...) {
		for (unsigned int i=0; i<geoms->size(); i++)
			delete (*geoms)[i];
		delete geoms;
		throw;
	}
	return factory.createMultiPoint(geoms);
}

MultiLineString *
WKBReader::readMultiLineString()
{
	int numGeoms = dis.readInt();
	vector<Geometry *> *geoms = new vector<Geometry *>(numGeoms);

	try {
		for (int i=0; i<numGeoms; i++)
		{
			Geometry *g = readGeometry();
			if (!dynamic_cast<LineString *>(g))
				throw new ParseException(BAD_GEOM_TYPE_MSG+
					" LineString");
			(*geoms)[i] = g;
		}
	} catch (...) {
		for (unsigned int i=0; i<geoms->size(); i++)
			delete (*geoms)[i];
		delete geoms;
		throw;
	}
	return factory.createMultiLineString(geoms);
}

MultiPolygon *
WKBReader::readMultiPolygon()
{
	int numGeoms = dis.readInt();
	vector<Geometry *> *geoms = new vector<Geometry *>(numGeoms);

	try {
		for (int i=0; i<numGeoms; i++)
		{
			Geometry *g = readGeometry();
			if (!dynamic_cast<Polygon *>(g))
				throw new ParseException(BAD_GEOM_TYPE_MSG+
					" Polygon");
			(*geoms)[i] = g;
		}
	} catch (...) {
		for (unsigned int i=0; i<geoms->size(); i++)
			delete (*geoms)[i];
		delete geoms;
		throw;
	}
	return factory.createMultiPolygon(geoms);
}

GeometryCollection *
WKBReader::readGeometryCollection()
{
	int numGeoms = dis.readInt();
	vector<Geometry *> *geoms = new vector<Geometry *>(numGeoms);

	try {
		for (int i=0; i<numGeoms; i++)
			(*geoms)[i] = (readGeometry());
	} catch (...) {
		for (unsigned int i=0; i<geoms->size(); i++)
			delete (*geoms)[i];
		delete geoms;
		throw;
	}
	return factory.createGeometryCollection(geoms);
}

CoordinateSequence *
WKBReader::readCoordinateSequence(int size)
{
	CoordinateSequence *seq = factory.getCoordinateSequenceFactory()->create(size, inputDimension);
	unsigned int targetDim = seq->getDimension();
	if ( targetDim > inputDimension )
		targetDim = inputDimension;
	for (int i=0; i<size; i++) {
		readCoordinate();
		for (unsigned int j=0; j<targetDim; j++) {
			seq->setOrdinate(i, j, ordValues[j]);
		}
	}
	return seq;
}

void
WKBReader::readCoordinate()
{
	static const PrecisionModel &pm = *factory.getPrecisionModel();
	for (unsigned int i=0; i<inputDimension; ++i)
	{
		if ( i <= 1 ) ordValues[i] = pm.makePrecise(dis.readDouble());
		else ordValues[i] = dis.readDouble();
	}
}

} // namespace geos
<|endoftext|>