<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Network/Win32/SocketPollerImpl.hpp>
#include <Nazara/Network/Debug.hpp>

namespace Nz
{
	SocketPollerImpl::SocketPollerImpl()
	{
		#if !NAZARA_NETWORK_POLL_SUPPORT
		FD_ZERO(&m_readSockets);
		FD_ZERO(&m_readyToReadSockets);
		FD_ZERO(&m_readyToWriteSockets);
		FD_ZERO(&m_writeSockets);
		#endif
	}

	void SocketPollerImpl::Clear()
	{
		#if NAZARA_NETWORK_POLL_SUPPORT
		m_allSockets.clear();
		m_readyToReadSockets.clear();
		m_readyToWriteSockets.clear();
		m_sockets.clear();
		#else
		FD_ZERO(&m_readSockets);
		FD_ZERO(&m_readyToReadSockets);
		FD_ZERO(&m_readyToWriteSockets);
		FD_ZERO(&m_writeSockets);
		#endif
	}

	bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
	{
		#if NAZARA_NETWORK_POLL_SUPPORT
		return m_readyToReadSockets.count(socket) != 0;
		#else
		return FD_ISSET(socket, &m_readyToReadSockets) != 0;
		#endif
	}

	bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const
	{
		#if NAZARA_NETWORK_POLL_SUPPORT
		return m_readyToWriteSockets.count(socket) != 0;
		#else
		return FD_ISSET(socket, &m_readyToWriteSockets) != 0;
		#endif
	}

	bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
	{
		#if NAZARA_NETWORK_POLL_SUPPORT
		return m_allSockets.count(socket) != 0;
		#else
		return FD_ISSET(socket, &m_readSockets) != 0 ||
		       FD_ISSET(socket, &m_writeSockets) != 0;
		#endif
	}

	bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
	{
		NazaraAssert(!IsRegistered(socket), "Socket is already registered");

		#if NAZARA_NETWORK_POLL_SUPPORT
		PollSocket entry = {
			socket,
			0,
			0
		};

		if (eventFlags & SocketPollEvent_Read)
			entry.events |= POLLRDNORM;

		if (eventFlags & SocketPollEvent_Write)
			entry.events |= POLLWRNORM;

		m_allSockets[socket] = m_sockets.size();
		m_sockets.emplace_back(entry);
		#else
		for (std::size_t i = 0; i < 2; ++i)
		{
			if ((eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write)) == 0)
				continue;

			fd_set& targetSet = (i == 0) ? m_readSockets : m_writeSockets;
			if (targetSet.fd_count > FD_SETSIZE)
			{
				NazaraError("Socket count exceeding hard-coded FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")");
				return false;
			}

			FD_SET(socket, &targetSet);
		}
		#endif

		return true;
	}

	void SocketPollerImpl::UnregisterSocket(SocketHandle socket)
	{
		NazaraAssert(IsRegistered(socket), "Socket is not registered");

		#if NAZARA_NETWORK_POLL_SUPPORT
		if (m_sockets.size() > 1U)
		{
			// Instead of using vector::erase, let's move the last element to the now unoccupied position
			std::size_t entry = m_allSockets[socket];

			// Get the last element and update it's position
			const PollSocket& lastElement = m_sockets.back();
			m_allSockets[lastElement.fd] = entry;

			// Now move it properly (lastElement is invalid after the following line) and pop it
			m_sockets[entry] = std::move(m_sockets.back());
		}
		m_sockets.pop_back();

		m_allSockets.erase(socket);
		m_readyToReadSockets.erase(socket);
		m_readyToWriteSockets.erase(socket);
		#else
		FD_CLR(socket, &m_readSockets);
		FD_CLR(socket, &m_readyToReadSockets);
		FD_CLR(socket, &m_readyToWriteSockets);
		FD_CLR(socket, &m_writeSockets);
		#endif
	}

	int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error)
	{
		int activeSockets;

		#if NAZARA_NETWORK_POLL_SUPPORT
		activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast<int>(msTimeout), error);
		#else
		m_readyToReadSockets = m_readSockets;
		m_readyToWriteSockets = m_writeSockets;

		timeval tv;
		tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
		tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);

		activeSockets = ::select(0xDEADBEEF, &m_readyToReadSockets, &m_readyToWriteSockets, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows
		if (activeSockets == SOCKET_ERROR)
		{
			if (error)
				*error = SocketImpl::TranslateWSAErrorToSocketError(WSAGetLastError());

			return 0;
		}

		if (error)
			*error = SocketError_NoError;
		#endif

		return activeSockets;
	}
}
<commit_msg>Network/SocketPollerImpl: Fix possible weird behavior with SocketPoller<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Network/Win32/SocketPollerImpl.hpp>
#include <Nazara/Network/Debug.hpp>

namespace Nz
{
	SocketPollerImpl::SocketPollerImpl()
	{
		#if !NAZARA_NETWORK_POLL_SUPPORT
		FD_ZERO(&m_readSockets);
		FD_ZERO(&m_readyToReadSockets);
		FD_ZERO(&m_readyToWriteSockets);
		FD_ZERO(&m_writeSockets);
		#endif
	}

	void SocketPollerImpl::Clear()
	{
		#if NAZARA_NETWORK_POLL_SUPPORT
		m_allSockets.clear();
		m_readyToReadSockets.clear();
		m_readyToWriteSockets.clear();
		m_sockets.clear();
		#else
		FD_ZERO(&m_readSockets);
		FD_ZERO(&m_readyToReadSockets);
		FD_ZERO(&m_readyToWriteSockets);
		FD_ZERO(&m_writeSockets);
		#endif
	}

	bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
	{
		#if NAZARA_NETWORK_POLL_SUPPORT
		return m_readyToReadSockets.count(socket) != 0;
		#else
		return FD_ISSET(socket, &m_readyToReadSockets) != 0;
		#endif
	}

	bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const
	{
		#if NAZARA_NETWORK_POLL_SUPPORT
		return m_readyToWriteSockets.count(socket) != 0;
		#else
		return FD_ISSET(socket, &m_readyToWriteSockets) != 0;
		#endif
	}

	bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
	{
		#if NAZARA_NETWORK_POLL_SUPPORT
		return m_allSockets.count(socket) != 0;
		#else
		return FD_ISSET(socket, &m_readSockets) != 0 ||
		       FD_ISSET(socket, &m_writeSockets) != 0;
		#endif
	}

	bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
	{
		NazaraAssert(!IsRegistered(socket), "Socket is already registered");

		#if NAZARA_NETWORK_POLL_SUPPORT
		PollSocket entry = {
			socket,
			0,
			0
		};

		if (eventFlags & SocketPollEvent_Read)
			entry.events |= POLLRDNORM;

		if (eventFlags & SocketPollEvent_Write)
			entry.events |= POLLWRNORM;

		m_allSockets[socket] = m_sockets.size();
		m_sockets.emplace_back(entry);
		#else
		for (std::size_t i = 0; i < 2; ++i)
		{
			if ((eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write)) == 0)
				continue;

			fd_set& targetSet = (i == 0) ? m_readSockets : m_writeSockets;
			if (targetSet.fd_count > FD_SETSIZE)
			{
				NazaraError("Socket count exceeding hard-coded FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")");
				return false;
			}

			FD_SET(socket, &targetSet);
		}
		#endif

		return true;
	}

	void SocketPollerImpl::UnregisterSocket(SocketHandle socket)
	{
		NazaraAssert(IsRegistered(socket), "Socket is not registered");

		#if NAZARA_NETWORK_POLL_SUPPORT
		if (m_sockets.size() > 1U)
		{
			// Instead of using vector::erase, let's move the last element to the now unoccupied position
			std::size_t entry = m_allSockets[socket];

			// Get the last element and update it's position
			const PollSocket& lastElement = m_sockets.back();
			m_allSockets[lastElement.fd] = entry;

			// Now move it properly (lastElement is invalid after the following line) and pop it
			m_sockets[entry] = std::move(m_sockets.back());
		}
		m_sockets.pop_back();

		m_allSockets.erase(socket);
		m_readyToReadSockets.erase(socket);
		m_readyToWriteSockets.erase(socket);
		#else
		FD_CLR(socket, &m_readSockets);
		FD_CLR(socket, &m_readyToReadSockets);
		FD_CLR(socket, &m_readyToWriteSockets);
		FD_CLR(socket, &m_writeSockets);
		#endif
	}

	int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error)
	{
		int activeSockets;

		#if NAZARA_NETWORK_POLL_SUPPORT
		activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast<int>(msTimeout), error);
		#else
		fd_set* readSet = nullptr;
		fd_set* writeSet = nullptr;

		if (m_readSockets.fd_count > 0)
		{
			m_readyToReadSockets = m_readSockets;
			readSet = &m_readyToReadSockets;
		}

		if (m_writeSockets.fd_count > 0)
		{
			m_readyToWriteSockets = m_writeSockets;
			readSet = &m_readyToWriteSockets;
		}

		timeval tv;
		tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
		tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);

		activeSockets = ::select(0xDEADBEEF, readSet, writeSet, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows
		if (activeSockets == SOCKET_ERROR)
		{
			if (error)
				*error = SocketImpl::TranslateWSAErrorToSocketError(WSAGetLastError());

			return 0;
		}

		if (error)
			*error = SocketError_NoError;
		#endif

		return activeSockets;
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "path.h"

namespace shk {

namespace detail {

std::pair<StringPiece, StringPiece> basenameSplitPiece(const std::string &path) {
  const auto last_nonslash = path.find_last_not_of('/');
  const auto slash_pos = path.find_last_of('/', last_nonslash);

  if (slash_pos == std::string::npos) {
    return std::make_pair(StringPiece(".", 1), StringPiece(path));
  } else if (last_nonslash == std::string::npos) {
    return std::make_pair(StringPiece("/", 1), StringPiece("/", 1));
  } else {
    return std::make_pair(
        slash_pos == 0 ?
            StringPiece("/", 1) :
            StringPiece(path.data(), slash_pos),
        StringPiece(
            path.data() + slash_pos + 1,
            last_nonslash - slash_pos));
  }
}

void canonicalizePath(std::string *path) throw(PathError) {
  size_t len = path->size();
  char *str = 0;
  if (len > 0) {
    str = &(*path)[0];
    canonicalizePath(str, &len);
    path->resize(len);
  }
  if (len == 0) {
    *path = ".";
  }
}

void canonicalizePath(
    char *path,
    size_t *len) throw(PathError) {
  // WARNING: this function is performance-critical; please benchmark
  // any changes you make to it.
  if (*len == 0) {
    return;
  }

  const int kMaxPathComponents = 62;
  char *components[kMaxPathComponents];
  int component_count = 0;

  char *start = path;
  char *dst = start;
  const char *src = start;
  const char *end = start + *len;

  if (*src == '/') {
#ifdef _WIN32
    // network path starts with //
    if (*len > 1 && *(src + 1) == '/') {
      src += 2;
      dst += 2;
    } else {
      ++src;
      ++dst;
    }
#else
    ++src;
    ++dst;
#endif
  }

  while (src < end) {
    if (*src == '.') {
      if (src + 1 == end || src[1] == '/') {
        // '.' component; eliminate.
        src += 2;
        continue;
      } else if (src[1] == '.' && (src + 2 == end || src[2] == '/')) {
        // '..' component.  Back up if possible.
        if (component_count > 0) {
          dst = components[component_count - 1];
          src += 3;
          --component_count;
        } else {
          *dst++ = *src++;
          *dst++ = *src++;
          *dst++ = *src++;
        }
        continue;
      }
    }

    if (*src == '/') {
      src++;
      continue;
    }

    if (component_count == kMaxPathComponents) {
      throw PathError("path has too many components", path);
    }
    components[component_count] = dst;
    ++component_count;

    while (*src != '/' && src != end) {
      *dst++ = *src++;
    }
    *dst++ = *src++;  // Copy '/' or final \0 character as well.
  }

  if (dst == start) {
    *len = 0;
  } else {
    *len = dst - start - (component_count ? 1 : 0);
  }
}

namespace {

#ifdef _WIN32
template<typename Iter>
void replaceBackslashes(const Iter begin, const Iter end) {
  for (auto c = begin; c < end; ++c) {
    if (*c == '\\') {
      *c = '/';
    }
  }
}
#endif

CanonicalizedPath makeCanonicalizedPath(
    FileSystem &file_system, std::string &&path) {
  if (path.empty()) {
    throw PathError("Empty path", path);
  }

#ifdef _WIN32
  replaceBackslashes(path.begin(), path.end());
#endif

  // We have a path (say /a/b/c) and want to find a prefix of this path that
  // exists on the file system (for example /a).
  //
  // pos points to the last character in the path that is about to be tested for
  // existence.
  auto pos = path.size() - 1;  // The string is verified to not be empty above
  Stat stat;
  bool at_root = false;
  bool at_relative_root = false;
  for (;;) {
    // Discard any trailing slashes. They have no semantic meaning.
    while (path[pos] == '/') {
      if (pos == 0) {
        // As a special case, don't discard a trailing slash if the path is only
        // "/", since that would transform an absolute path into a relative one.
        at_root = true;
        break;
      }
      pos--;
    }

    StringPiece path_to_try(
        at_relative_root ? "." : path.c_str(),
        pos + 1);
    // Use stat, not lstat: the idea is to follow symlinks to the actual file to
    // directory where this will live. Comparing links for identity does no
    // good.
    stat = file_system.stat(path_to_try.asString());
    if (stat.result == 0) {
      // Found an existing file
      break;
    } else if (at_root || at_relative_root) {
      throw PathError(
          "None of the path components can be accessed and exist", path);
    } else {
      while (path[pos] != '/') {
        if (pos == 0) {
          // The loop hit the beginning of the string. That means this is a
          // relative path and this none of the path components other than the
          // current working directory exist.
          at_relative_root = true;
          break;
        }
        pos--;
      }
    }
  }

  // At this point, the longest prefix of path that actually exists has been
  // found. Now extract the nonexisting part of the path and canonicalize it.
  do {
    pos++;
  } while (pos != path.size() && path[pos] == '/');
  auto len = path.size() - pos;
  std::string nonexisting_part(&path[pos], len);
  if (len > 0) {
    canonicalizePath(&nonexisting_part[0], &len);
    nonexisting_part.resize(len);
  }

  canonicalizePath(&path);
  return CanonicalizedPath(
      stat.metadata.ino,
      stat.metadata.dev,
      std::move(nonexisting_part));
}

}  // anonymous namespace
}  // namespace detail

Paths::Paths(FileSystem &file_system)
    : _file_system(file_system) {}

Path Paths::get(const std::string &path) throw(PathError) {
  return get(std::string(path));
}

Path Paths::get(std::string &&path) throw(PathError) {
  const auto original_result = _original_paths.emplace(path);
  const auto canonicalized_result = _canonicalized_paths.insert(
      detail::makeCanonicalizedPath(_file_system, std::move(path)));
  return Path(
      &*canonicalized_result.first,
      &*original_result.first);
}

}  // namespace shk
<commit_msg>fixup<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "path.h"

namespace shk {

namespace detail {

std::pair<StringPiece, StringPiece> basenameSplitPiece(const std::string &path) {
  const auto last_nonslash = path.find_last_not_of('/');
  const auto slash_pos = path.find_last_of('/', last_nonslash);

  if (slash_pos == std::string::npos) {
    return std::make_pair(StringPiece(".", 1), StringPiece(path));
  } else if (last_nonslash == std::string::npos) {
    return std::make_pair(StringPiece("/", 1), StringPiece("/", 1));
  } else {
    return std::make_pair(
        slash_pos == 0 ?
            StringPiece("/", 1) :
            StringPiece(path.data(), slash_pos),
        StringPiece(
            path.data() + slash_pos + 1,
            last_nonslash - slash_pos));
  }
}

void canonicalizePath(std::string *path) throw(PathError) {
  size_t len = path->size();
  char *str = 0;
  if (len > 0) {
    str = &(*path)[0];
    canonicalizePath(str, &len);
    path->resize(len);
  }
  if (len == 0) {
    *path = ".";
  }
}

void canonicalizePath(
    char *path,
    size_t *len) throw(PathError) {
  // WARNING: this function is performance-critical; please benchmark
  // any changes you make to it.
  if (*len == 0) {
    return;
  }

  const int kMaxPathComponents = 62;
  char *components[kMaxPathComponents];
  int component_count = 0;

  char *start = path;
  char *dst = start;
  const char *src = start;
  const char *end = start + *len;

  if (*src == '/') {
#ifdef _WIN32
    // network path starts with //
    if (*len > 1 && *(src + 1) == '/') {
      src += 2;
      dst += 2;
    } else {
      ++src;
      ++dst;
    }
#else
    ++src;
    ++dst;
#endif
  }

  while (src < end) {
    if (*src == '.') {
      if (src + 1 == end || src[1] == '/') {
        // '.' component; eliminate.
        src += 2;
        continue;
      } else if (src[1] == '.' && (src + 2 == end || src[2] == '/')) {
        // '..' component.  Back up if possible.
        if (component_count > 0) {
          dst = components[component_count - 1];
          src += 3;
          --component_count;
        } else {
          *dst++ = *src++;
          *dst++ = *src++;
          *dst++ = *src++;
        }
        continue;
      }
    }

    if (*src == '/') {
      src++;
      continue;
    }

    if (component_count == kMaxPathComponents) {
      throw PathError("path has too many components", path);
    }
    components[component_count] = dst;
    ++component_count;

    while (*src != '/' && src != end) {
      *dst++ = *src++;
    }
    *dst++ = *src++;  // Copy '/' or final \0 character as well.
  }

  if (dst == start) {
    *len = 0;
  } else {
    *len = dst - start - (component_count ? 1 : 0);
  }
}

namespace {

#ifdef _WIN32
template<typename Iter>
void replaceBackslashes(const Iter begin, const Iter end) {
  for (auto c = begin; c < end; ++c) {
    if (*c == '\\') {
      *c = '/';
    }
  }
}
#endif

CanonicalizedPath makeCanonicalizedPath(
    FileSystem &file_system, std::string &&path) {
  if (path.empty()) {
    throw PathError("Empty path", path);
  }

#ifdef _WIN32
  replaceBackslashes(path.begin(), path.end());
#endif

  // We have a path (say /a/b/c) and want to find a prefix of this path that
  // exists on the file system (for example /a).
  //
  // pos points to the last character in the path that is about to be tested for
  // existence.
  auto pos = path.size() - 1;  // The string is verified to not be empty above
  Stat stat;
  bool at_root = false;
  bool at_relative_root = false;
  for (;;) {
    // Discard any trailing slashes. They have no semantic meaning.
    while (path[pos] == '/') {
      if (pos == 0) {
        // As a special case, don't discard a trailing slash if the path is only
        // "/", since that would transform an absolute path into a relative one.
        at_root = true;
        break;
      }
      pos--;
    }

    StringPiece path_to_try(
        at_relative_root ? "." : path.c_str(),
        pos + 1);
    // Use stat, not lstat: the idea is to follow symlinks to the actual file to
    // directory where this will live. Comparing links for identity does no
    // good.
    stat = file_system.stat(path_to_try.asString());
    if (stat.result == 0) {
      // Found an existing file
      break;
    } else if (at_root || at_relative_root) {
      throw PathError(
          "None of the path components can be accessed and exist", path);
    } else {
      while (path[pos] != '/') {
        if (pos == 0) {
          // The loop hit the beginning of the string. That means this is a
          // relative path and this none of the path components other than the
          // current working directory exist.
          at_relative_root = true;
          break;
        }
        pos--;
      }
    }
  }

  // At this point, the longest prefix of path that actually exists has been
  // found. Now extract the nonexisting part of the path and canonicalize it.
  do {
    pos++;
  } while (pos != path.size() && path[pos] == '/');
  auto len = path.size() - pos;
  std::string nonexisting_part(&path[pos], len);
  if (len > 0) {
    canonicalizePath(&nonexisting_part[0], &len);
    nonexisting_part.resize(len);
  }

  return CanonicalizedPath(
      stat.metadata.ino,
      stat.metadata.dev,
      std::move(nonexisting_part));
}

}  // anonymous namespace
}  // namespace detail

Paths::Paths(FileSystem &file_system)
    : _file_system(file_system) {}

Path Paths::get(const std::string &path) throw(PathError) {
  return get(std::string(path));
}

Path Paths::get(std::string &&path) throw(PathError) {
  const auto original_result = _original_paths.emplace(path);
  const auto canonicalized_result = _canonicalized_paths.insert(
      detail::makeCanonicalizedPath(_file_system, std::move(path)));
  return Path(
      &*canonicalized_result.first,
      &*original_result.first);
}

}  // namespace shk
<|endoftext|>


<commit_before>/*  Sirikata
 *  QueryHandlerFactory.cpp
 *
 *  Copyright (c) 2010, Ewen Cheslack-Postava
 *  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 Sirikata 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 <sirikata/core/util/Platform.hpp>
#include <sirikata/core/options/Options.hpp>

#include <prox/BruteForceQueryHandler.hpp>
#include <prox/RTreeQueryHandler.hpp>
#include <prox/RTreeCutQueryHandler.hpp>

namespace Sirikata {

/** Creates a Prox::QueryHandler of the specified type. Parses the arguments
 *  specified and passes them to the query handler constructor.
 */
template<typename SimulationTraits>
Prox::QueryHandler<SimulationTraits>* QueryHandlerFactory(const String& type, const String& args) {
    static OptionValue* branching = NULL;
    if (branching == NULL) {
        branching = new OptionValue("branching", "10", Sirikata::OptionValueType<uint32>(), "Number of children each node should have.");
        Sirikata::InitializeClassOptions ico("query_handler", NULL,
            branching,
            NULL);
    }

    assert(branching != NULL);

    // Since these options end up being shared if you instantiate multiple
    // QueryHandlers, reset them each time.
    branching->unsafeAs<uint32>() = 10;

    OptionSet* optionsSet = OptionSet::getOptions("query_handler", NULL);
    optionsSet->parse(args);

    if (type == "brute") {
        return new Prox::BruteForceQueryHandler<SimulationTraits>();
    }
    else if (type == "dist") { // We just use brute force and special case the
                               // queries in Proximity
        return new Prox::BruteForceQueryHandler<SimulationTraits>();
    }
    else if (type == "rtree") {
        return new Prox::RTreeQueryHandler<SimulationTraits>(branching->unsafeAs<uint32>());
    }
    else if (type == "rtreecut") {
        return new Prox::RTreeCutQueryHandler<SimulationTraits>(branching->unsafeAs<uint32>(), false);
    }
    else if (type == "rtreecutagg") {
        return new Prox::RTreeCutQueryHandler<SimulationTraits>(branching->unsafeAs<uint32>(), true);
    }
    else {
        return NULL;
    }
}

} // namespace Sirikata
<commit_msg>Make QueryHandlerFactory generate RebuildingQueryHandlers, add a parameter to control the batch size when transitioning queries to the new handler.<commit_after>/*  Sirikata
 *  QueryHandlerFactory.cpp
 *
 *  Copyright (c) 2010, Ewen Cheslack-Postava
 *  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 Sirikata 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 <sirikata/core/util/Platform.hpp>
#include <sirikata/core/options/Options.hpp>

#include <prox/BruteForceQueryHandler.hpp>
#include <prox/RTreeQueryHandler.hpp>
#include <prox/RTreeCutQueryHandler.hpp>
#include <prox/RebuildingQueryHandler.hpp>

namespace Sirikata {

/** Creates a Prox::QueryHandler of the specified type. Parses the arguments
 *  specified and passes them to the query handler constructor.
 */
template<typename SimulationTraits>
Prox::QueryHandler<SimulationTraits>* QueryHandlerFactory(const String& type, const String& args) {
    static OptionValue* branching = NULL;
    static OptionValue* rebuild_batch_size = NULL;
    if (branching == NULL) {
        branching = new OptionValue("branching", "10", Sirikata::OptionValueType<uint32>(), "Number of children each node should have.");
        rebuild_batch_size = new OptionValue("rebuild-batch-size", "10", Sirikata::OptionValueType<uint32>(), "Number of queries to transition on each iteration when rebuilding. Keep this small to avoid long latencies between updates.");
        Sirikata::InitializeClassOptions ico("query_handler", NULL,
            branching,
            rebuild_batch_size,
            NULL);
    }

    assert(branching != NULL);

    // Since these options end up being shared if you instantiate multiple
    // QueryHandlers, reset them each time.
    branching->unsafeAs<uint32>() = 10;

    OptionSet* optionsSet = OptionSet::getOptions("query_handler", NULL);
    optionsSet->parse(args);

    if (type == "brute") {
        return new Prox::RebuildingQueryHandler<SimulationTraits>(
            Prox::BruteForceQueryHandler<SimulationTraits>::Constructor(), rebuild_batch_size->unsafeAs<uint32>()
        );
    }
    else if (type == "dist") { // We just use brute force and special case the
                               // queries in Proximity
        return new Prox::RebuildingQueryHandler<SimulationTraits>(
            Prox::BruteForceQueryHandler<SimulationTraits>::Constructor(), rebuild_batch_size->unsafeAs<uint32>()
        );
    }
    else if (type == "rtree") {
        return new Prox::RebuildingQueryHandler<SimulationTraits>(
            Prox::RTreeQueryHandler<SimulationTraits>::Constructor(branching->unsafeAs<uint32>()), rebuild_batch_size->unsafeAs<uint32>()
        );
    }
    else if (type == "rtreecut") {
        return new Prox::RebuildingQueryHandler<SimulationTraits>(
            Prox::RTreeCutQueryHandler<SimulationTraits>::Constructor(branching->unsafeAs<uint32>(), false), rebuild_batch_size->unsafeAs<uint32>()
        );
    }
    else if (type == "rtreecutagg") {
        return new Prox::RebuildingQueryHandler<SimulationTraits>(
            Prox::RTreeCutQueryHandler<SimulationTraits>::Constructor(branching->unsafeAs<uint32>(), true), rebuild_batch_size->unsafeAs<uint32>()
        );
    }
    else {
        return NULL;
    }
}

} // namespace Sirikata
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <limits>

using uchar = unsigned char;
const double cx = -.6, cy = 0;
const uchar max_iter = std::numeric_limits<uchar>::max();

struct rgb_t { unsigned char r, g, b; };

rgb_t **row_ptrs;
rgb_t  *img_data;

void screen_dump(const int width, const int height)
{
    FILE *fp = fopen("out_mandelbrot.ppm", "w");
    fprintf(fp, "P6\n%d %d\n255\n", width, height);
    for (int i = height - 1; i >= 0; i--)
        fwrite(row_ptrs[i], 1, width * sizeof(rgb_t), fp);
    fclose(fp);
}

void alloc_2d(const int width, const int height)
{
    img_data = new rgb_t[width * height];
    row_ptrs = new rgb_t*[height];

    row_ptrs[0] = img_data;
    for (int i = 1; i < height; i++)
        row_ptrs[i] = row_ptrs[i - 1] + width;
}

void map_colour(rgb_t * const px)
{
    const uchar num_shades = 16;
    const rgb_t mapping[num_shades] =
    { { 66,30,15 },{ 25,7,26 },{ 9,1,47 },{ 4,4,73 },{ 0,7,100 },
    { 12,44,138 },{ 24,82,177 },{ 57,125,209 },{ 134,181,229 },{ 211,236,248 },
    { 241,233,191 },{ 248,201,95 },{ 255,170,0 },{ 204,128,0 },{ 153,87,0 },
    { 106,52,3 } };

    if (px->r == max_iter || px->r == 0) {
        px->r = 0; px->g = 0; px->b = 0;
    }
    else {
        const uchar uc = px->r % num_shades;
        *px = mapping[uc];
    }
}

void calc_mandel(const int width, const int height, const double scale)
{
    for (int i = 0; i < height; i++) {

        const double y = (i - height / 2) * scale + cy;

        rgb_t *px = row_ptrs[i];
        for (int j = 0; j < width; j++, px++) {

            const double x = (j - width / 2) * scale + cx;
            double zx, zy, zx2, zy2;
            uchar iter = 0;

            zx = hypot(x - .25, y);
            if (x < zx - 2 * zx * zx + .25)     iter = max_iter;
            if ((x + 1)*(x + 1) + y * y < 1 / 16) iter = max_iter;

            zx = zy = zx2 = zy2 = 0;
            do {
                zy = 2 * zx * zy + y;
                zx = zx2 - zy2 + x;
                zx2 = zx * zx;
                zy2 = zy * zy;
            } while (iter++ < max_iter && zx2 + zy2 < 4);

            px->r = iter;
            px->g = iter;
            px->b = iter;
        }
    }

    for (int i = 0; i < height; i++) {
        rgb_t *px = row_ptrs[i];
        for (int j = 0; j < width; j++, px++) {
            map_colour(px);
        }
    }
}

int main(int argc, char *argv[])
{
    const int width = (argc > 1) ? std::atoi(argv[1]) : 4096;
    const int height = (argc > 2) ? std::atoi(argv[2]) : 4096;
    const double scale = 1. / (width / 4);

    alloc_2d(width, height);
    calc_mandel(width, height, scale);
    screen_dump(width, height);

    delete[] img_data;
    delete[] row_ptrs;
    return 0;
}
<commit_msg>updating output filename<commit_after>#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <limits>

using uchar = unsigned char;
const double cx = -.6, cy = 0;
const uchar max_iter = std::numeric_limits<uchar>::max();

struct rgb_t { unsigned char r, g, b; };

rgb_t **row_ptrs;
rgb_t  *img_data;

void screen_dump(const int width, const int height)
{
    FILE *fp = fopen("cpu-mandelbrot.ppm", "w");
    fprintf(fp, "P6\n%d %d\n255\n", width, height);
    for (int i = height - 1; i >= 0; i--)
        fwrite(row_ptrs[i], 1, width * sizeof(rgb_t), fp);
    fclose(fp);
}

void alloc_2d(const int width, const int height)
{
    img_data = new rgb_t[width * height];
    row_ptrs = new rgb_t*[height];

    row_ptrs[0] = img_data;
    for (int i = 1; i < height; i++)
        row_ptrs[i] = row_ptrs[i - 1] + width;
}

void map_colour(rgb_t * const px)
{
    const uchar num_shades = 16;
    const rgb_t mapping[num_shades] =
    { { 66,30,15 },{ 25,7,26 },{ 9,1,47 },{ 4,4,73 },{ 0,7,100 },
    { 12,44,138 },{ 24,82,177 },{ 57,125,209 },{ 134,181,229 },{ 211,236,248 },
    { 241,233,191 },{ 248,201,95 },{ 255,170,0 },{ 204,128,0 },{ 153,87,0 },
    { 106,52,3 } };

    if (px->r == max_iter || px->r == 0) {
        px->r = 0; px->g = 0; px->b = 0;
    }
    else {
        const uchar uc = px->r % num_shades;
        *px = mapping[uc];
    }
}

void calc_mandel(const int width, const int height, const double scale)
{
    for (int i = 0; i < height; i++) {

        const double y = (i - height / 2) * scale + cy;

        rgb_t *px = row_ptrs[i];
        for (int j = 0; j < width; j++, px++) {

            const double x = (j - width / 2) * scale + cx;
            double zx, zy, zx2, zy2;
            uchar iter = 0;

            zx = hypot(x - .25, y);
            if (x < zx - 2 * zx * zx + .25)     iter = max_iter;
            if ((x + 1)*(x + 1) + y * y < 1 / 16) iter = max_iter;

            zx = zy = zx2 = zy2 = 0;
            do {
                zy = 2 * zx * zy + y;
                zx = zx2 - zy2 + x;
                zx2 = zx * zx;
                zy2 = zy * zy;
            } while (iter++ < max_iter && zx2 + zy2 < 4);

            px->r = iter;
            px->g = iter;
            px->b = iter;
        }
    }

    for (int i = 0; i < height; i++) {
        rgb_t *px = row_ptrs[i];
        for (int j = 0; j < width; j++, px++) {
            map_colour(px);
        }
    }
}

int main(int argc, char *argv[])
{
    const int width = (argc > 1) ? std::atoi(argv[1]) : 4096;
    const int height = (argc > 2) ? std::atoi(argv[2]) : 4096;
    const double scale = 1. / (width / 4);

    alloc_2d(width, height);
    calc_mandel(width, height, scale);
    screen_dump(width, height);

    delete[] img_data;
    delete[] row_ptrs;
    return 0;
}
<|endoftext|>


<commit_before>#include <string>
#include <iostream>
#include <SDL.h>
#include <SDL_ttf.h>
#include "res_path.h"
#include "cleanup.h"

/*
 * Lesson 6: True Type Fonts with SDL_ttf
 */
//Screen attributes
const int SCREEN_WIDTH  = 2560;
const int SCREEN_HEIGHT = 1440;

/*
 * Log an SDL error with some error message to the output stream of our choice
 * @param os The output stream to write the message too
 * @param msg The error message to write, format will be msg error: SDL_GetError()
 */
void logSDLError(std::ostream &os, const std::string &msg){
   os << msg << " error: " << SDL_GetError() << std::endl;
}
/*
 * Draw an SDL_Texture to an SDL_Renderer at some destination rect
 * taking a clip of the texture if desired
 * @param tex The source texture we want to draw
 * @param rend The renderer we want to draw too
 * @param dst The destination rectangle to render the texture too
 * @param clip The sub-section of the texture to draw (clipping rect)
 *		default of nullptr draws the entire texture
 */
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, SDL_Rect dst, SDL_Rect *clip = nullptr){
   SDL_RenderCopy(ren, tex, clip, &dst);
}

/*
 * Draw an SDL_Texture to an SDL_Renderer at position x, y, preserving
 * the texture's width and height and taking a clip of the texture if desired
 * If a clip is passed, the clip's width and height will be used instead of the texture's
 * @param tex The source texture we want to draw
 * @param rend The renderer we want to draw too
 * @param x The x coordinate to draw too
 * @param y The y coordinate to draw too
 * @param clip The sub-section of the texture to draw (clipping rect)
 *		default of nullptr draws the entire texture
 */
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y, SDL_Rect *clip = nullptr){
   SDL_Rect dst;
   dst.x = x;
   dst.y = y;
   if (clip != nullptr){
      dst.w = clip->w;
      dst.h = clip->h;
   }
   else {
      SDL_QueryTexture(tex, NULL, NULL, &dst.w, &dst.h);
   }
   renderTexture(tex, ren, dst, clip);
}
/*
 * Render the message we want to display to a texture for drawing
 * @param message The message we want to display
 * @param fontFile The font we want to use to render the text
 * @param color The color we want the text to be
 * @param fontSize The size we want the font to be
 * @param renderer The renderer to load the texture in
 * @return An SDL_Texture containing the rendered message, or nullptr if something went wrong
 */
SDL_Texture* renderText(const std::string &message, const std::string &fontFile, SDL_Color color,
                        int fontSize, SDL_Renderer *renderer)
{
   //Open the font
   TTF_Font *font = TTF_OpenFont(fontFile.c_str(), fontSize);
   if (font == nullptr){
      logSDLError(std::cout, "TTF_OpenFont");
      return nullptr;
   }
   //We need to first render to a surface as that's what TTF_RenderText returns, then
   //load that surface into a texture
   SDL_Surface *surf = TTF_RenderText_Blended(font, message.c_str(), color);
   if (surf == nullptr){
      TTF_CloseFont(font);
      logSDLError(std::cout, "TTF_RenderText");
      return nullptr;
   }
   SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surf);
   if (texture == nullptr){
      logSDLError(std::cout, "CreateTexture");
   }
   //Clean up the surface and font
   SDL_FreeSurface(surf);
   TTF_CloseFont(font);
   return texture;
}
SDL_Texture* drawText(const std::string &message, const std::string &fontFile, SDL_Color color,
                      int fontSize, SDL_Renderer *renderer, int x, int y) {
   SDL_Texture* t = renderText(message,getResourcePath("pinetree")+fontFile, color, 64, renderer);
   renderTexture(t, renderer, x, y);
   return t;
}

auto timePrev = std::chrono::high_resolution_clock::now();

// Returns time since last time this function was called in seconds with nanosecond precision
double GetDelta()
{
   // Gett current time as a std::chrono::time_point
   // which basically contains info about the current point in time
   auto timeCurrent = std::chrono::high_resolution_clock::now();

   // Compare the two to create time_point containing delta time in nanosecnds
   auto timeDiff = std::chrono::duration_cast< std::chrono::nanoseconds >( timeCurrent - timePrev );

   // Get the tics as a variable
   double delta = timeDiff.count();

   // Turn nanoseconds into seconds
   delta /= 1000000000;

   timePrev = timeCurrent;
   return delta;
}

int main(int, char**){
   //Start up SDL and make sure it went ok
   if (SDL_Init(SDL_INIT_VIDEO) != 0){
      logSDLError(std::cout, "SDL_Init");
      return 1;
   }
   //Also need to init SDL_ttf
   if (TTF_Init() != 0){
      logSDLError(std::cout, "TTF_Init");
      SDL_Quit();
      return 1;
   }

   //Setup our window and renderer
   SDL_Window *window = SDL_CreateWindow("Pinetree", SDL_WINDOWPOS_CENTERED,
                                         SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
   SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
   if (window == nullptr){
      logSDLError(std::cout, "CreateWindow");
      TTF_Quit();
      SDL_Quit();
      return 1;
   }
   SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
   if (renderer == nullptr){
      logSDLError(std::cout, "CreateRenderer");
      cleanup(window);
      TTF_Quit();
      SDL_Quit();
      return 1;
   }

   const std::string resPath = getResourcePath("pinetree");
   std::cout << resPath << std::endl;
   //We'll render the string "TTF fonts are cool!" in white
   //Color is in RGB format
   //   if (image == nullptr){
   //      cleanup(image, renderer, window);
   //      TTF_Quit();
   //      SDL_Quit();
   //      return 1;
   //   }

   //Get the texture w/h so we can center it in the screen

   SDL_Event e;
   bool quit = false;

   SDL_Color color = {255,255,255,255};
   SDL_Texture* t = renderText("Pinetree",getResourcePath("pinetree")+"Tuffy.ttf", color, 64, renderer);
   int iW, iH;
   SDL_QueryTexture(t, NULL, NULL, &iW, &iH);
   int x = SCREEN_WIDTH / 2 - iW / 2;
   int y = SCREEN_HEIGHT / 2 - iH / 2;

   double last = 0;
   float deltaTime = 0.0;

   unsigned int bIndex = 0;

   SDL_Surface *image = SDL_LoadBMP("bg.bmp");
   if (image == NULL)
      SDL_ShowSimpleMessageBox(0, "Image init error", SDL_GetError(),
                               window);
   SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
                                                        image);
   if (texture == NULL)
      SDL_ShowSimpleMessageBox(0, "Texture init error",
                               SDL_GetError(), window);

   while (!quit){
      //Event Polling
      while (SDL_PollEvent(&e)){

         if (e.type == SDL_QUIT){
            quit = true;
         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE){
            quit = true;
         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RIGHT) {

         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_DOWN) {
            if (bIndex!=1) {
               ++bIndex;
            }
            else {
               bIndex=0;
            }

         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_UP) {
            if (bIndex!=0) {
               --bIndex;
            }
            else {
               bIndex=0;
            }
         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_LEFT) {

         }
         if(e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RETURN) {
            switch(bIndex) {
               case 0:
                  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION,
                                           "You clicked list",
                                           "NOT IMPLEMENTED YET",
                                           NULL);
                  break;

               case 1:
                  quit=true;
                  break;
            }

         }
      }
      double now = SDL_GetTicks();
      //deltatime is in seconds
      if (now > last) {
         deltaTime = ((float)(now - last)) / 1000;
         last = now;
      }

      SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
      SDL_RenderClear(renderer);

      renderTexture(texture, renderer, 0,0);

      //We can draw our message as we do any other texture, since it's been
      //rendered to a texture

      renderTexture(t, renderer, x, y);

      SDL_Texture* t2=renderText("(C)ForestCorp"+std::to_string(bIndex), getResourcePath("pinetree")+"Tuffy.ttf", {255,255,255,255}, 40, renderer);
      renderTexture(t2, renderer, x-10, y+65);

      //List button
      SDL_Rect listButtonRect = {100,100,400,100}; /* Define button rectangle */
      SDL_Texture* listButtonText = renderText("List", getResourcePath("pinetree")+"Tuffy.ttf", {0,0,0,255}, 100, renderer); /* Define button text */
      int listButtonOn=bIndex-0; /* Calculate if the button should be on */
      SDL_SetRenderDrawColor(renderer, 255*(bIndex-0)*listButtonOn/* Calculate again */, 255, 255, 255); /* Set rectangle color */
      SDL_RenderFillRect(renderer, &listButtonRect); /* Draw the rect */
      renderTexture(listButtonText, renderer, 100,100); /* Render the text's texture */

      //Shutdown button
      SDL_Rect shutdownButtonRect = {100,200,400,100}; /* Define button rectangle */
      SDL_Texture* shutdownButtonText = renderText("Shutdown", getResourcePath("pinetree")+"Tuffy.ttf", {0,0,0,255}, 100, renderer); /* Define button text */
      int shutdownButtonOn=bIndex-1; /* Calculate if the button should be on */
      SDL_SetRenderDrawColor(renderer, 255*(bIndex-1)*shutdownButtonOn/* Calculate again */, 255, 255, 255); /* Set rectangle color */
      SDL_RenderFillRect(renderer, &shutdownButtonRect); /* Draw the rect */
      renderTexture(shutdownButtonText, renderer, 100,200); /* Render the text's texture */

      SDL_RenderPresent(renderer);

   }
   //Clean up
   //   cleanup(image, renderer, window);
   //   TTF_Quit();
   //   SDL_Quit();

   return 0;
}
<commit_msg>Added settings Button<commit_after>#include <string>
#include <iostream>
#include <SDL.h>
#include <SDL_ttf.h>
#include "res_path.h"
#include "cleanup.h"

/*
 * Lesson 6: True Type Fonts with SDL_ttf
 */
//Screen attributes
const int SCREEN_WIDTH  = 2560;
const int SCREEN_HEIGHT = 1440;

/*
 * Log an SDL error with some error message to the output stream of our choice
 * @param os The output stream to write the message too
 * @param msg The error message to write, format will be msg error: SDL_GetError()
 */
void logSDLError(std::ostream &os, const std::string &msg){
   os << msg << " error: " << SDL_GetError() << std::endl;
}
/*
 * Draw an SDL_Texture to an SDL_Renderer at some destination rect
 * taking a clip of the texture if desired
 * @param tex The source texture we want to draw
 * @param rend The renderer we want to draw too
 * @param dst The destination rectangle to render the texture too
 * @param clip The sub-section of the texture to draw (clipping rect)
 *		default of nullptr draws the entire texture
 */
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, SDL_Rect dst, SDL_Rect *clip = nullptr){
   SDL_RenderCopy(ren, tex, clip, &dst);
}

/*
 * Draw an SDL_Texture to an SDL_Renderer at position x, y, preserving
 * the texture's width and height and taking a clip of the texture if desired
 * If a clip is passed, the clip's width and height will be used instead of the texture's
 * @param tex The source texture we want to draw
 * @param rend The renderer we want to draw too
 * @param x The x coordinate to draw too
 * @param y The y coordinate to draw too
 * @param clip The sub-section of the texture to draw (clipping rect)
 *		default of nullptr draws the entire texture
 */
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y, SDL_Rect *clip = nullptr){
   SDL_Rect dst;
   dst.x = x;
   dst.y = y;
   if (clip != nullptr){
      dst.w = clip->w;
      dst.h = clip->h;
   }
   else {
      SDL_QueryTexture(tex, NULL, NULL, &dst.w, &dst.h);
   }
   renderTexture(tex, ren, dst, clip);
}
/*
 * Render the message we want to display to a texture for drawing
 * @param message The message we want to display
 * @param fontFile The font we want to use to render the text
 * @param color The color we want the text to be
 * @param fontSize The size we want the font to be
 * @param renderer The renderer to load the texture in
 * @return An SDL_Texture containing the rendered message, or nullptr if something went wrong
 */
SDL_Texture* renderText(const std::string &message, const std::string &fontFile, SDL_Color color,
                        int fontSize, SDL_Renderer *renderer)
{
   //Open the font
   TTF_Font *font = TTF_OpenFont(fontFile.c_str(), fontSize);
   if (font == nullptr){
      logSDLError(std::cout, "TTF_OpenFont");
      return nullptr;
   }
   //We need to first render to a surface as that's what TTF_RenderText returns, then
   //load that surface into a texture
   SDL_Surface *surf = TTF_RenderText_Blended(font, message.c_str(), color);
   if (surf == nullptr){
      TTF_CloseFont(font);
      logSDLError(std::cout, "TTF_RenderText");
      return nullptr;
   }
   SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surf);
   if (texture == nullptr){
      logSDLError(std::cout, "CreateTexture");
   }
   //Clean up the surface and font
   SDL_FreeSurface(surf);
   TTF_CloseFont(font);
   return texture;
}
SDL_Texture* drawText(const std::string &message, const std::string &fontFile, SDL_Color color,
                      int fontSize, SDL_Renderer *renderer, int x, int y) {
   SDL_Texture* t = renderText(message,getResourcePath("pinetree")+fontFile, color, 64, renderer);
   renderTexture(t, renderer, x, y);
   return t;
}

auto timePrev = std::chrono::high_resolution_clock::now();

// Returns time since last time this function was called in seconds with nanosecond precision
double GetDelta()
{
   // Gett current time as a std::chrono::time_point
   // which basically contains info about the current point in time
   auto timeCurrent = std::chrono::high_resolution_clock::now();

   // Compare the two to create time_point containing delta time in nanosecnds
   auto timeDiff = std::chrono::duration_cast< std::chrono::nanoseconds >( timeCurrent - timePrev );

   // Get the tics as a variable
   double delta = timeDiff.count();

   // Turn nanoseconds into seconds
   delta /= 1000000000;

   timePrev = timeCurrent;
   return delta;
}

int main(int, char**){
   //Start up SDL and make sure it went ok
   if (SDL_Init(SDL_INIT_VIDEO) != 0){
      logSDLError(std::cout, "SDL_Init");
      return 1;
   }
   //Also need to init SDL_ttf
   if (TTF_Init() != 0){
      logSDLError(std::cout, "TTF_Init");
      SDL_Quit();
      return 1;
   }

   //Setup our window and renderer
   SDL_Window *window = SDL_CreateWindow("Pinetree", SDL_WINDOWPOS_CENTERED,
                                         SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
   SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
   if (window == nullptr){
      logSDLError(std::cout, "CreateWindow");
      TTF_Quit();
      SDL_Quit();
      return 1;
   }
   SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
   if (renderer == nullptr){
      logSDLError(std::cout, "CreateRenderer");
      cleanup(window);
      TTF_Quit();
      SDL_Quit();
      return 1;
   }

   const std::string resPath = getResourcePath("pinetree");
   std::cout << resPath << std::endl;
   //We'll render the string "TTF fonts are cool!" in white
   //Color is in RGB format
   //   if (image == nullptr){
   //      cleanup(image, renderer, window);
   //      TTF_Quit();
   //      SDL_Quit();
   //      return 1;
   //   }

   //Get the texture w/h so we can center it in the screen

   SDL_Event e;
   bool quit = false;

   SDL_Color color = {255,255,255,255};
   SDL_Texture* t = renderText("Pinetree",getResourcePath("pinetree")+"Tuffy.ttf", color, 64, renderer);
   int iW, iH;
   SDL_QueryTexture(t, NULL, NULL, &iW, &iH);
   int x = SCREEN_WIDTH / 2 - iW / 2;
   int y = SCREEN_HEIGHT / 2 - iH / 2;

   double last = 0;
   float deltaTime = 0.0;

   unsigned int bIndex = 0;

   SDL_Surface *image = SDL_LoadBMP("bg.bmp");
   if (image == NULL)
      SDL_ShowSimpleMessageBox(0, "Image init error", SDL_GetError(),
                               window);
   SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
                                                        image);
   if (texture == NULL)
      SDL_ShowSimpleMessageBox(0, "Texture init error",
                               SDL_GetError(), window);

   while (!quit){
      //Event Polling
      while (SDL_PollEvent(&e)){

         if (e.type == SDL_QUIT){
            quit = true;
         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE){
            quit = true;
         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RIGHT) {

         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_DOWN) {
            if (bIndex!=2) {
               ++bIndex;
            }
            else {
               bIndex=0;
            }

         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_UP) {
            if (bIndex!=0) {
               --bIndex;
            }
            else {
               bIndex=0;
            }
         }
         if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_LEFT) {

         }
         if(e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RETURN) {
            switch(bIndex) {
               case 0:
                  SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION,
                                           "You clicked list",
                                           "NOT IMPLEMENTED YET",
                                           NULL);
                  break;

               case 1:
                  quit=true;
                  break;
                case 2:
                    SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION,
                                             "You clicked settings",
                                             "NOT IMPLEMENTED YET",
                                             NULL);

                break;
            }

         }
      }
      double now = SDL_GetTicks();
      //deltatime is in seconds
      if (now > last) {
         deltaTime = ((float)(now - last)) / 1000;
         last = now;
      }

      SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
      SDL_RenderClear(renderer);

      renderTexture(texture, renderer, 0,0);

      //We can draw our message as we do any other texture, since it's been
      //rendered to a texture

      renderTexture(t, renderer, x, y);

      SDL_Texture* t2=renderText("(C)ForestCorp"+std::to_string(bIndex), getResourcePath("pinetree")+"Tuffy.ttf", {255,255,255,255}, 40, renderer);
      renderTexture(t2, renderer, x-10, y+65);

      //List button
      SDL_Rect listButtonRect = {100,100,400,100}; /* Define button rectangle */
      SDL_Texture* listButtonText = renderText("List", getResourcePath("pinetree")+"Tuffy.ttf", {0,0,0,255}, 100, renderer); /* Define button text */
      int listButtonOn=bIndex-0; /* Calculate if the button should be on */
      SDL_SetRenderDrawColor(renderer, 255*(bIndex-0)*listButtonOn/* Calculate again */, 255, 255, 255); /* Set rectangle color */
      SDL_RenderFillRect(renderer, &listButtonRect); /* Draw the rect */
      renderTexture(listButtonText, renderer, 100,100); /* Render the text's texture */

      //Shutdown button
      SDL_Rect shutdownButtonRect = {100,200,400,100}; /* Define button rectangle */
      SDL_Texture* shutdownButtonText = renderText("Shutdown", getResourcePath("pinetree")+"Tuffy.ttf", {0,0,0,255}, 100, renderer); /* Define button text */
      int shutdownButtonOn=bIndex-1; /* Calculate if the button should be on */
      SDL_SetRenderDrawColor(renderer, 255*(bIndex-1)*shutdownButtonOn/* Calculate again */, 255, 255, 255); /* Set rectangle color */
      SDL_RenderFillRect(renderer, &shutdownButtonRect); /* Draw the rect */
      renderTexture(shutdownButtonText, renderer, 100,200); /* Render the text's texture */

       //Settings Button
       SDL_Rect settingsButtonRect = {100,300,400,100}; /* Define button rectangle */
      SDL_Texture* settingsButtonText = renderText("Settings", getResourcePath("pinetree")+"Tuffy.ttf", {0,0,0,255}, 100, renderer); /* Define button text */
       int settingsButtonOn=bIndex-2; /* Calculate if the button should be on */
       SDL_SetRenderDrawColor(renderer, 255*(bIndex-2)*settingsButtonOn/* Calculate again */, 255, 255, 255); /* Set rectangle color */
       SDL_RenderFillRect(renderer, &settingsButtonRect); /* Draw the rect */
       renderTexture(settingsButtonText, renderer, 100,300); /* Render the text's texture */

      SDL_RenderPresent(renderer);

   }
   //Clean up
   //   cleanup(image, renderer, window);
   //   TTF_Quit();
   //   SDL_Quit();

   return 0;
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <string.h>
#include <iostream>

int main() {
#ifdef __APPLE__
  const char* name = "DYLD_LIBRARY_PATH";
#else
  const char* name = "LD_LIBRARY_PATH";
#endif

  const char* cetLDPathValue = getenv("CETD_LIBRARY_PATH");
  int res = setenv("DYLD_LIBRARY_PATH", cetLDPathValue, 1);

  const char* localLDPathValue = getenv(name);

  if(strcmp(localLDPathValue,cetLDPathValue) != 0) {
    return 1;
  }
  std::cout << localLDPathValue << std::endl;

  return 0;
}
<commit_msg>Fix errors reported by Travis on Linux<commit_after>#include <cstdlib>
#include <string.h>
#include <iostream>

int main() {
#ifdef __APPLE__
  const char* name = "DYLD_LIBRARY_PATH";
#else
  const char* name = "LD_LIBRARY_PATH";
#endif

  const char* cetLDPathValue = getenv("CETD_LIBRARY_PATH");
  int res = setenv(name, cetLDPathValue, 1);

  if (res != 0) {
    std::cerr << "could not set " << name << std::endl;
    return 1;
  }

  const char* localLDPathValue = getenv(name);

  if(strcmp(localLDPathValue,cetLDPathValue) != 0) {
    return 1;
  }
  std::cout << localLDPathValue << std::endl;

  return 0;
}
<|endoftext|>


<commit_before>/* dro project
 */

#include "wtf.h" //breakpoint for unhandled conditions

#include "gpio.h"
#include "nvic.h"
#include "clocks.h"

#include "systick.h"
using namespace SystemTimer;
#include "polledtimer.h"
#include "tableofpointers.h"

#include "core_cmInstr.h"  //wfe OR wfi
#include "cruntime.h"

#include "p1343_board.h"

using namespace LPC;

//the next line actually sets up the clocks before main and pretty much anything else gets called:
ClockStarter startup InitStep(InitHardware/2) (true,0,1000);//external wasn't working properly, need a test to check before switching to it.
P1343devkit board InitStep(InitApplication);//construction of this turns on internal peripherals and configures pins.
Irq pushButton(board.button.pini);

using namespace LPC;

HandleInterrupt(P1343ButtonIrqNum){
  board.toggleLed(4);
  board.button.irqAcknowledge();
}

HandleInterrupt(54){
  board.toggleLed(5);
  board.button.irqAcknowledge();
}

//p0-4,p05 for qei.
InputPin<0,4> primePhase;
InputPin<0,5> otherPhase;
Irq prime(primePhase.pini);
#define myIrq 4

//should go up and down depending upon the input signals;
static int axis(0);

HandleInterrupt( myIrq ) {
  //prime phase interrupt
  bool dirbit = otherPhase;
  if (dirbit) {
    --axis; //ignoring quarter phase for now
  } else {
    ++axis; //will be +/-4 here
  }
  //??lpc input clear
}

#include "fifo.h"
static FifoBuffer<33> outgoing;
static FifoBuffer<63> incoming;

#include "uart.h"
/** called by isr on an input event.
 * negative values of @param are notifications of line errors, -1 for interrupts disabled */
bool uartReceiver(int indata){
  if((incoming=u8(indata))){
    return true;
  } else {
    wtf(24);
    return false;
  }
}

/** called by isr when transmission becomes possible.
 *  @returns either an 8 bit unsigned character, or -1 to disable transmission events*/
int uartSender(){
  return outgoing;//negative for fifo empty
}

void prepUart(){
  theUart.setFraming("N81");
  theUart.setBaud(115200);
  theUart.setTransmitter(&uartSender);
  theUart.setReceiver(&uartReceiver);

  theUart.reception(true);
  theUart.irq(true);
}

#include "minimath.h"

static CyclicTimer slowToggle; //since action is polled might as well wait until main to declare the object.
RegisterTimer(slowToggle);

MakeRef(SystemTicker,PolledTimerServer);

int main(void) {
  prepUart();
  slowToggle.restart(ticksForSeconds(1.333));
  //soft stuff
  int events=0;

  prime.enable();
  pushButton.enable();//@nvic
  board.button.setIrqStyle(GPIO::LowEdge,true);
  Irq gp2irq(gpioBankInterrupt(2));
  gp2irq.prepare();
  //no longer doing this prophylactically in the loop as we now use atomics rather than interrupt gating to deal with concurrency.
  EnableInterrupts;//master enable
//  events=sumObjs();
  while (1) {
    MNE(WFE);//wait for event, expecting interrupts to also be events.
    ++events;
    board.led1 = board.button;
    if(slowToggle.hasFired()){
      board.toggleLed(0);
      if((outgoing='A'+(events&15))){
        theUart.beTransmitting();
      }
    }
  }
  return 0;
}

<commit_msg>input irq's working, mostly with templated i/o<commit_after>/* dro project
 */

#include "wtf.h" //breakpoint for unhandled conditions

#include "gpio.h"
#include "nvic.h"
#include "clocks.h"

#include "systick.h"
using namespace SystemTimer;
#include "polledtimer.h"
#include "tableofpointers.h"

#include "core_cmInstr.h"  //wfe OR wfi
#include "cruntime.h"

#include "p1343_board.h"

using namespace LPC;

//the next line actually sets up the clocks before main and pretty much anything else gets called:
ClockStarter startup InitStep(InitHardware/2) (true,0,1000);//external wasn't working properly, need a test to check before switching to it.
P1343devkit board InitStep(InitApplication);//construction of this turns on internal peripherals and configures pins.
Irq pushButton(board.button.pini);

using namespace LPC;

HandleInterrupt(P1343ButtonIrqNum){
  board.toggleLed(4);
  board.button.irqAcknowledge();
}

HandleInterrupt(54){//this gets the button irq
  board.toggleLed(5);
  board.button.irqAcknowledge();
}

//p0-4,p05 for qei.
InputPin<0,4> primePhase;
InputPin<0,5> otherPhase;
Irq prime(primePhase.pini);
#define myIrq 4

//should go up and down depending upon the input signals;
static int axis(0);

HandleInterrupt( myIrq ) {
  //prime phase interrupt
  bool dirbit = otherPhase;
  if (dirbit) {
    --axis; //ignoring quarter phase for now
  } else {
    ++axis; //will be +/-4 here
  }
  //??lpc input clear
}

#include "fifo.h"
static FifoBuffer<33> outgoing;
static FifoBuffer<63> incoming;

#include "uart.h"
/** called by isr on an input event.
 * negative values of @param are notifications of line errors, -1 for interrupts disabled */
bool uartReceiver(int indata){
  if((incoming=u8(indata))){
    return true;
  } else {
    wtf(24);
    return false;
  }
}

/** called by isr when transmission becomes possible.
 *  @returns either an 8 bit unsigned character, or -1 to disable transmission events*/
int uartSender(){
  return outgoing;//negative for fifo empty
}

void prepUart(){
  theUart.setFraming("N81");
  theUart.setBaud(115200);
  theUart.setTransmitter(&uartSender);
  theUart.setReceiver(&uartReceiver);

  theUart.reception(true);
  theUart.irq(true);
}

#include "minimath.h"

static CyclicTimer slowToggle; //since action is polled might as well wait until main to declare the object.
RegisterTimer(slowToggle);

MakeRef(SystemTicker,PolledTimerServer);

int main(void) {
  prepUart();
  slowToggle.restart(ticksForSeconds(0.333));
  //soft stuff
  int events=0;

  prime.enable();
  pushButton.enable();//@nvic
  board.button.setIrqStyle(GPIO::AnyEdge,true);
  Irq gp2irq(gpioBankInterrupt(2));
  gp2irq.prepare();
  //no longer doing this prophylactically in the loop as we now use atomics rather than interrupt gating to deal with concurrency.
  EnableInterrupts;//master enable
//  events=sumObjs();
  while (1) {
    MNE(WFE);//wait for event, expecting interrupts to also be events.
    ++events;
//works, now will do using isr    board.led1 = board.button;
    if(slowToggle.hasFired()){
      board.toggleLed(0);
      if((outgoing='A'+(events&15))){
        theUart.beTransmitting();
      }
    }
  }
  return 0;
}

<|endoftext|>


<commit_before>/*
 * Memory pool.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_POOL_HXX
#define BENG_PROXY_POOL_HXX

#include "trace.h"

#include <inline/compiler.h>

#include <utility>
#include <new>

#ifndef NDEBUG
#include <assert.h>
#endif

#include <stddef.h>
#include <stdbool.h>

struct pool;
struct SlicePool;

struct pool_mark_state {
    /**
     * The area that was current when the mark was set.
     */
    struct linear_pool_area *area;

    /**
     * The area before #area.  This is used to dispose areas that were
     * inserted before the current area due to a large allocation.
     */
    struct linear_pool_area *prev;

    /**
     * The position within the current area when the mark was set.
     */
    size_t position;

#ifndef NDEBUG
    /**
     * Used in an assertion: if the pool was empty before pool_mark(),
     * it must be empty again after pool_rewind().
     */
    bool was_empty;
#endif
};

struct StringView;

void
pool_recycler_clear();

gcc_malloc
struct pool *
pool_new_libc(struct pool *parent, const char *name);

gcc_malloc
struct pool *
pool_new_linear(struct pool *parent, const char *name, size_t initial_size);

gcc_malloc
struct pool *
pool_new_slice(struct pool *parent, const char *name,
               struct SlicePool *slice_pool);

#ifdef NDEBUG

#define pool_set_major(pool)
#define pool_set_persistent(pool)

#else

void
pool_set_major(struct pool *pool);

void
pool_set_persistent(struct pool *pool);

#endif

void
pool_ref_impl(struct pool *pool TRACE_ARGS_DECL);

#define pool_ref(pool) pool_ref_impl(pool TRACE_ARGS)
#define pool_ref_fwd(pool) pool_ref_impl(pool TRACE_ARGS_FWD)

unsigned
pool_unref_impl(struct pool *pool TRACE_ARGS_DECL);

#define pool_unref(pool) pool_unref_impl(pool TRACE_ARGS)
#define pool_unref_fwd(pool) pool_unref_impl(pool TRACE_ARGS_FWD)

class LinearPool {
    struct pool &p;

public:
    LinearPool(struct pool &parent, const char *name, size_t initial_size)
        :p(*pool_new_linear(&parent, name, initial_size)) {}

    ~LinearPool() {
        gcc_unused auto ref = pool_unref(&p);
#ifndef NDEBUG
        assert(ref == 0);
#endif
    }

    struct pool &get() {
        return p;
    }

    operator struct pool &() {
        return p;
    }

    operator struct pool *() {
        return &p;
    }
};

/**
 * Returns the total size of all allocations in this pool.
 */
gcc_pure
size_t
pool_netto_size(const struct pool *pool);

/**
 * Returns the total amount of memory allocated by this pool.
 */
gcc_pure
size_t
pool_brutto_size(const struct pool *pool);

/**
 * Returns the total size of this pool and all of its descendants
 * (recursively).
 */
gcc_pure
size_t
pool_recursive_netto_size(const struct pool *pool);

gcc_pure
size_t
pool_recursive_brutto_size(const struct pool *pool);

/**
 * Returns the total size of all descendants of this pool (recursively).
 */
gcc_pure
size_t
pool_children_netto_size(const struct pool *pool);

gcc_pure
size_t
pool_children_brutto_size(const struct pool *pool);

void
pool_dump_tree(const struct pool *pool);

#ifndef NDEBUG
#include <inline/list.h>

struct pool_notify_state {
    struct list_head siblings;

    struct pool *pool;

    const char *name;

    bool destroyed, registered;

#ifdef TRACE
    const char *file;
    int line;

    const char *destroyed_file;
    int destroyed_line;
#endif
};

void
pool_notify(struct pool *pool, struct pool_notify_state *notify);

bool
pool_denotify(struct pool_notify_state *notify);

/**
 * Hands over control from an existing #pool_notify to a new one.  The
 * old one is unregistered.
 */
void
pool_notify_move(struct pool *pool, struct pool_notify_state *src,
                 struct pool_notify_state *dest);

class PoolNotify {
    struct pool_notify_state state;

public:
    explicit PoolNotify(struct pool &pool) {
        pool_notify(&pool, &state);
    }

    PoolNotify(const PoolNotify &) = delete;

#ifndef NDEBUG
    ~PoolNotify() {
        assert(!state.registered);
    }
#endif

    bool Denotify() {
        return pool_denotify(&state);
    }
};

#endif

class ScopePoolRef {
    struct pool &pool;
#ifndef NDEBUG
    PoolNotify notify;
#endif

#ifdef TRACE
    const char *const file;
    unsigned line;
#endif

public:
    explicit ScopePoolRef(struct pool &_pool TRACE_ARGS_DECL_)
        :pool(_pool)
#ifndef NDEBUG
        , notify(_pool)
#endif
         TRACE_ARGS_INIT
    {
        pool_ref_fwd(&_pool);
    }

    ScopePoolRef(const ScopePoolRef &) = delete;

    ~ScopePoolRef() {
#ifndef NDEBUG
        notify.Denotify();
#endif
        pool_unref_fwd(&pool);
    }
};

#ifndef NDEBUG

void
pool_ref_notify_impl(struct pool *pool, struct pool_notify_state *notify TRACE_ARGS_DECL);

void
pool_unref_denotify_impl(struct pool *pool, struct pool_notify_state *notify
                         TRACE_ARGS_DECL);

/**
 * Do a "checked" pool reference.
 */
#define pool_ref_notify(pool, notify) \
    pool_ref_notify_impl(pool, notify TRACE_ARGS)

/**
 * Do a "checked" pool unreference.  If the pool has been destroyed,
 * an assertion will fail.  Double frees are also caught.
 */
#define pool_unref_denotify(pool, notify) \
    pool_unref_denotify_impl(pool, notify TRACE_ARGS)

#else
#define pool_ref_notify(pool, notify) pool_ref(pool)
#define pool_unref_denotify(pool, notify) pool_unref(pool)
#endif

#ifdef NDEBUG

static inline void
pool_trash(gcc_unused struct pool *pool)
{
}

static inline void
pool_commit()
{
}

static inline void
pool_attach(gcc_unused struct pool *pool, gcc_unused const void *p,
            gcc_unused const char *name)
{
}

static inline void
pool_attach_checked(gcc_unused struct pool *pool, gcc_unused const void *p,
                    gcc_unused const char *name)
{
}

static inline void
pool_detach(gcc_unused struct pool *pool, gcc_unused const void *p)
{
}

static inline void
pool_detach_checked(gcc_unused struct pool *pool, gcc_unused const void *p)
{
}

static inline const char *
pool_attachment_name(gcc_unused struct pool *pool, gcc_unused const void *p)
{
    return NULL;
}

#else

void
pool_trash(struct pool *pool);

void
pool_commit();

bool
pool_contains(struct pool *pool, const void *ptr, size_t size);

/**
 * Attach an opaque object to the pool.  It must be detached before
 * the pool is destroyed.  This is used in debugging mode to track
 * whether all external objects have been destroyed.
 */
void
pool_attach(struct pool *pool, const void *p, const char *name);

/**
 * Same as pool_attach(), but checks if the object is already
 * registered.
 */
void
pool_attach_checked(struct pool *pool, const void *p, const char *name);

void
pool_detach(struct pool *pool, const void *p);

void
pool_detach_checked(struct pool *pool, const void *p);

const char *
pool_attachment_name(struct pool *pool, const void *p);

#endif

void
pool_mark(struct pool *pool, struct pool_mark_state *mark);

void
pool_rewind(struct pool *pool, const struct pool_mark_state *mark);

class AutoRewindPool {
    struct pool &pool;
    pool_mark_state mark;

public:
    AutoRewindPool(struct pool &_pool):pool(_pool) {
        pool_mark(&pool, &mark);
    }

    AutoRewindPool(const AutoRewindPool &) = delete;

    ~AutoRewindPool() {
        pool_rewind(&pool, &mark);
    }
};

gcc_malloc
void *
p_malloc_impl(struct pool *pool, size_t size TRACE_ARGS_DECL);

#define p_malloc(pool, size) p_malloc_impl(pool, size TRACE_ARGS)
#define p_malloc_fwd(pool, size) p_malloc_impl(pool, size TRACE_ARGS_FWD)

void
p_free(struct pool *pool, const void *ptr);

gcc_malloc
void *
p_calloc_impl(struct pool *pool, size_t size TRACE_ARGS_DECL);

#define p_calloc(pool, size) p_calloc_impl(pool, size TRACE_ARGS)

gcc_malloc
void *
p_memdup_impl(struct pool *pool, const void *src, size_t length TRACE_ARGS_DECL);

#define p_memdup(pool, src, length) p_memdup_impl(pool, src, length TRACE_ARGS)
#define p_memdup_fwd(pool, src, length) p_memdup_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc
char *
p_strdup_impl(struct pool *pool, const char *src TRACE_ARGS_DECL);

#define p_strdup(pool, src) p_strdup_impl(pool, src TRACE_ARGS)
#define p_strdup_fwd(pool, src) p_strdup_impl(pool, src TRACE_ARGS_FWD)

static inline const char *
p_strdup_checked(struct pool *pool, const char *s)
{
    return s == NULL ? NULL : p_strdup(pool, s);
}

gcc_malloc
char *
p_strdup_lower_impl(struct pool *pool, const char *src TRACE_ARGS_DECL);

#define p_strdup_lower(pool, src) p_strdup_lower_impl(pool, src TRACE_ARGS)
#define p_strdup_lower_fwd(pool, src) p_strdup_lower_impl(pool, src TRACE_ARGS_FWD)

gcc_malloc
char *
p_strndup_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL);

#define p_strndup(pool, src, length) p_strndup_impl(pool, src, length TRACE_ARGS)
#define p_strndup_fwd(pool, src, length) p_strndup_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc
char *
p_strndup_lower_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL);

#define p_strndup_lower(pool, src, length) p_strndup_lower_impl(pool, src, length TRACE_ARGS)
#define p_strndup_lower_fwd(pool, src, length) p_strndup_lower_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc gcc_printf(2, 3)
char *
p_sprintf(struct pool *pool, const char *fmt, ...);

gcc_malloc
char *
p_strcat(struct pool *pool, const char *s, ...);

gcc_malloc
char *
p_strncat(struct pool *pool, const char *s, size_t length, ...);

template<typename T>
T *
PoolAlloc(pool &p)
{
    return (T *)p_malloc(&p, sizeof(T));
}

template<typename T>
T *
PoolAlloc(pool &p, size_t n)
{
    return (T *)p_malloc(&p, sizeof(T) * n);
}

template<>
inline void *
PoolAlloc<void>(pool &p, size_t n)
{
    return p_malloc(&p, n);
}

template<typename T, typename... Args>
T *
NewFromPool(pool &p, Args&&... args)
{
    void *t = PoolAlloc<T>(p);
    return ::new(t) T(std::forward<Args>(args)...);
}

template<typename T>
void
DeleteFromPool(struct pool &pool, T *t)
{
    t->~T();
    p_free(&pool, t);
}

/**
 * A disposer for boost::intrusive that invokes the DeleteFromPool()
 * on the given pointer.
 */
class PoolDisposer {
    struct pool &p;

public:
    explicit PoolDisposer(struct pool &_p):p(_p) {}

    template<typename T>
    void operator()(T *t) {
        DeleteFromPool(p, t);
    }
};

template<typename T>
void
DeleteUnrefPool(struct pool &pool, T *t)
{
    DeleteFromPool(pool, t);
    pool_unref(&pool);
}

template<typename T>
void
DeleteUnrefTrashPool(struct pool &pool, T *t)
{
    pool_trash(&pool);
    DeleteUnrefPool(pool, t);
}

class PoolAllocator {
    struct pool &pool;

public:
    explicit constexpr PoolAllocator(struct pool &_pool):pool(_pool) {}

    void *Allocate(size_t size) {
        return p_malloc(&pool, size);
    }

    char *DupString(const char *p) {
        return p_strdup(&pool, p);
    }

    void Free(void *p) {
        p_free(&pool, p);
    }

    template<typename T, typename... Args>
    T *New(Args&&... args) {
        return NewFromPool<T>(pool, std::forward<Args>(args)...);
    }

    template<typename T>
    void Delete(T *t) {
        DeleteFromPool(pool, t);
    }
};

gcc_malloc
char *
p_strdup_impl(struct pool &pool, StringView src TRACE_ARGS_DECL);

gcc_malloc
char *
p_strdup_lower_impl(struct pool &pool, StringView src TRACE_ARGS_DECL);

#endif
<commit_msg>pool: add cast operators to class ScopePoolRef<commit_after>/*
 * Memory pool.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_POOL_HXX
#define BENG_PROXY_POOL_HXX

#include "trace.h"

#include <inline/compiler.h>

#include <utility>
#include <new>

#ifndef NDEBUG
#include <assert.h>
#endif

#include <stddef.h>
#include <stdbool.h>

struct pool;
struct SlicePool;

struct pool_mark_state {
    /**
     * The area that was current when the mark was set.
     */
    struct linear_pool_area *area;

    /**
     * The area before #area.  This is used to dispose areas that were
     * inserted before the current area due to a large allocation.
     */
    struct linear_pool_area *prev;

    /**
     * The position within the current area when the mark was set.
     */
    size_t position;

#ifndef NDEBUG
    /**
     * Used in an assertion: if the pool was empty before pool_mark(),
     * it must be empty again after pool_rewind().
     */
    bool was_empty;
#endif
};

struct StringView;

void
pool_recycler_clear();

gcc_malloc
struct pool *
pool_new_libc(struct pool *parent, const char *name);

gcc_malloc
struct pool *
pool_new_linear(struct pool *parent, const char *name, size_t initial_size);

gcc_malloc
struct pool *
pool_new_slice(struct pool *parent, const char *name,
               struct SlicePool *slice_pool);

#ifdef NDEBUG

#define pool_set_major(pool)
#define pool_set_persistent(pool)

#else

void
pool_set_major(struct pool *pool);

void
pool_set_persistent(struct pool *pool);

#endif

void
pool_ref_impl(struct pool *pool TRACE_ARGS_DECL);

#define pool_ref(pool) pool_ref_impl(pool TRACE_ARGS)
#define pool_ref_fwd(pool) pool_ref_impl(pool TRACE_ARGS_FWD)

unsigned
pool_unref_impl(struct pool *pool TRACE_ARGS_DECL);

#define pool_unref(pool) pool_unref_impl(pool TRACE_ARGS)
#define pool_unref_fwd(pool) pool_unref_impl(pool TRACE_ARGS_FWD)

class LinearPool {
    struct pool &p;

public:
    LinearPool(struct pool &parent, const char *name, size_t initial_size)
        :p(*pool_new_linear(&parent, name, initial_size)) {}

    ~LinearPool() {
        gcc_unused auto ref = pool_unref(&p);
#ifndef NDEBUG
        assert(ref == 0);
#endif
    }

    struct pool &get() {
        return p;
    }

    operator struct pool &() {
        return p;
    }

    operator struct pool *() {
        return &p;
    }
};

/**
 * Returns the total size of all allocations in this pool.
 */
gcc_pure
size_t
pool_netto_size(const struct pool *pool);

/**
 * Returns the total amount of memory allocated by this pool.
 */
gcc_pure
size_t
pool_brutto_size(const struct pool *pool);

/**
 * Returns the total size of this pool and all of its descendants
 * (recursively).
 */
gcc_pure
size_t
pool_recursive_netto_size(const struct pool *pool);

gcc_pure
size_t
pool_recursive_brutto_size(const struct pool *pool);

/**
 * Returns the total size of all descendants of this pool (recursively).
 */
gcc_pure
size_t
pool_children_netto_size(const struct pool *pool);

gcc_pure
size_t
pool_children_brutto_size(const struct pool *pool);

void
pool_dump_tree(const struct pool *pool);

#ifndef NDEBUG
#include <inline/list.h>

struct pool_notify_state {
    struct list_head siblings;

    struct pool *pool;

    const char *name;

    bool destroyed, registered;

#ifdef TRACE
    const char *file;
    int line;

    const char *destroyed_file;
    int destroyed_line;
#endif
};

void
pool_notify(struct pool *pool, struct pool_notify_state *notify);

bool
pool_denotify(struct pool_notify_state *notify);

/**
 * Hands over control from an existing #pool_notify to a new one.  The
 * old one is unregistered.
 */
void
pool_notify_move(struct pool *pool, struct pool_notify_state *src,
                 struct pool_notify_state *dest);

class PoolNotify {
    struct pool_notify_state state;

public:
    explicit PoolNotify(struct pool &pool) {
        pool_notify(&pool, &state);
    }

    PoolNotify(const PoolNotify &) = delete;

#ifndef NDEBUG
    ~PoolNotify() {
        assert(!state.registered);
    }
#endif

    bool Denotify() {
        return pool_denotify(&state);
    }
};

#endif

class ScopePoolRef {
    struct pool &pool;
#ifndef NDEBUG
    PoolNotify notify;
#endif

#ifdef TRACE
    const char *const file;
    unsigned line;
#endif

public:
    explicit ScopePoolRef(struct pool &_pool TRACE_ARGS_DECL_)
        :pool(_pool)
#ifndef NDEBUG
        , notify(_pool)
#endif
         TRACE_ARGS_INIT
    {
        pool_ref_fwd(&_pool);
    }

    ScopePoolRef(const ScopePoolRef &) = delete;

    ~ScopePoolRef() {
#ifndef NDEBUG
        notify.Denotify();
#endif
        pool_unref_fwd(&pool);
    }

    operator struct pool &() {
        return pool;
    }

    operator struct pool *() {
        return &pool;
    }
};

#ifndef NDEBUG

void
pool_ref_notify_impl(struct pool *pool, struct pool_notify_state *notify TRACE_ARGS_DECL);

void
pool_unref_denotify_impl(struct pool *pool, struct pool_notify_state *notify
                         TRACE_ARGS_DECL);

/**
 * Do a "checked" pool reference.
 */
#define pool_ref_notify(pool, notify) \
    pool_ref_notify_impl(pool, notify TRACE_ARGS)

/**
 * Do a "checked" pool unreference.  If the pool has been destroyed,
 * an assertion will fail.  Double frees are also caught.
 */
#define pool_unref_denotify(pool, notify) \
    pool_unref_denotify_impl(pool, notify TRACE_ARGS)

#else
#define pool_ref_notify(pool, notify) pool_ref(pool)
#define pool_unref_denotify(pool, notify) pool_unref(pool)
#endif

#ifdef NDEBUG

static inline void
pool_trash(gcc_unused struct pool *pool)
{
}

static inline void
pool_commit()
{
}

static inline void
pool_attach(gcc_unused struct pool *pool, gcc_unused const void *p,
            gcc_unused const char *name)
{
}

static inline void
pool_attach_checked(gcc_unused struct pool *pool, gcc_unused const void *p,
                    gcc_unused const char *name)
{
}

static inline void
pool_detach(gcc_unused struct pool *pool, gcc_unused const void *p)
{
}

static inline void
pool_detach_checked(gcc_unused struct pool *pool, gcc_unused const void *p)
{
}

static inline const char *
pool_attachment_name(gcc_unused struct pool *pool, gcc_unused const void *p)
{
    return NULL;
}

#else

void
pool_trash(struct pool *pool);

void
pool_commit();

bool
pool_contains(struct pool *pool, const void *ptr, size_t size);

/**
 * Attach an opaque object to the pool.  It must be detached before
 * the pool is destroyed.  This is used in debugging mode to track
 * whether all external objects have been destroyed.
 */
void
pool_attach(struct pool *pool, const void *p, const char *name);

/**
 * Same as pool_attach(), but checks if the object is already
 * registered.
 */
void
pool_attach_checked(struct pool *pool, const void *p, const char *name);

void
pool_detach(struct pool *pool, const void *p);

void
pool_detach_checked(struct pool *pool, const void *p);

const char *
pool_attachment_name(struct pool *pool, const void *p);

#endif

void
pool_mark(struct pool *pool, struct pool_mark_state *mark);

void
pool_rewind(struct pool *pool, const struct pool_mark_state *mark);

class AutoRewindPool {
    struct pool &pool;
    pool_mark_state mark;

public:
    AutoRewindPool(struct pool &_pool):pool(_pool) {
        pool_mark(&pool, &mark);
    }

    AutoRewindPool(const AutoRewindPool &) = delete;

    ~AutoRewindPool() {
        pool_rewind(&pool, &mark);
    }
};

gcc_malloc
void *
p_malloc_impl(struct pool *pool, size_t size TRACE_ARGS_DECL);

#define p_malloc(pool, size) p_malloc_impl(pool, size TRACE_ARGS)
#define p_malloc_fwd(pool, size) p_malloc_impl(pool, size TRACE_ARGS_FWD)

void
p_free(struct pool *pool, const void *ptr);

gcc_malloc
void *
p_calloc_impl(struct pool *pool, size_t size TRACE_ARGS_DECL);

#define p_calloc(pool, size) p_calloc_impl(pool, size TRACE_ARGS)

gcc_malloc
void *
p_memdup_impl(struct pool *pool, const void *src, size_t length TRACE_ARGS_DECL);

#define p_memdup(pool, src, length) p_memdup_impl(pool, src, length TRACE_ARGS)
#define p_memdup_fwd(pool, src, length) p_memdup_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc
char *
p_strdup_impl(struct pool *pool, const char *src TRACE_ARGS_DECL);

#define p_strdup(pool, src) p_strdup_impl(pool, src TRACE_ARGS)
#define p_strdup_fwd(pool, src) p_strdup_impl(pool, src TRACE_ARGS_FWD)

static inline const char *
p_strdup_checked(struct pool *pool, const char *s)
{
    return s == NULL ? NULL : p_strdup(pool, s);
}

gcc_malloc
char *
p_strdup_lower_impl(struct pool *pool, const char *src TRACE_ARGS_DECL);

#define p_strdup_lower(pool, src) p_strdup_lower_impl(pool, src TRACE_ARGS)
#define p_strdup_lower_fwd(pool, src) p_strdup_lower_impl(pool, src TRACE_ARGS_FWD)

gcc_malloc
char *
p_strndup_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL);

#define p_strndup(pool, src, length) p_strndup_impl(pool, src, length TRACE_ARGS)
#define p_strndup_fwd(pool, src, length) p_strndup_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc
char *
p_strndup_lower_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL);

#define p_strndup_lower(pool, src, length) p_strndup_lower_impl(pool, src, length TRACE_ARGS)
#define p_strndup_lower_fwd(pool, src, length) p_strndup_lower_impl(pool, src, length TRACE_ARGS_FWD)

gcc_malloc gcc_printf(2, 3)
char *
p_sprintf(struct pool *pool, const char *fmt, ...);

gcc_malloc
char *
p_strcat(struct pool *pool, const char *s, ...);

gcc_malloc
char *
p_strncat(struct pool *pool, const char *s, size_t length, ...);

template<typename T>
T *
PoolAlloc(pool &p)
{
    return (T *)p_malloc(&p, sizeof(T));
}

template<typename T>
T *
PoolAlloc(pool &p, size_t n)
{
    return (T *)p_malloc(&p, sizeof(T) * n);
}

template<>
inline void *
PoolAlloc<void>(pool &p, size_t n)
{
    return p_malloc(&p, n);
}

template<typename T, typename... Args>
T *
NewFromPool(pool &p, Args&&... args)
{
    void *t = PoolAlloc<T>(p);
    return ::new(t) T(std::forward<Args>(args)...);
}

template<typename T>
void
DeleteFromPool(struct pool &pool, T *t)
{
    t->~T();
    p_free(&pool, t);
}

/**
 * A disposer for boost::intrusive that invokes the DeleteFromPool()
 * on the given pointer.
 */
class PoolDisposer {
    struct pool &p;

public:
    explicit PoolDisposer(struct pool &_p):p(_p) {}

    template<typename T>
    void operator()(T *t) {
        DeleteFromPool(p, t);
    }
};

template<typename T>
void
DeleteUnrefPool(struct pool &pool, T *t)
{
    DeleteFromPool(pool, t);
    pool_unref(&pool);
}

template<typename T>
void
DeleteUnrefTrashPool(struct pool &pool, T *t)
{
    pool_trash(&pool);
    DeleteUnrefPool(pool, t);
}

class PoolAllocator {
    struct pool &pool;

public:
    explicit constexpr PoolAllocator(struct pool &_pool):pool(_pool) {}

    void *Allocate(size_t size) {
        return p_malloc(&pool, size);
    }

    char *DupString(const char *p) {
        return p_strdup(&pool, p);
    }

    void Free(void *p) {
        p_free(&pool, p);
    }

    template<typename T, typename... Args>
    T *New(Args&&... args) {
        return NewFromPool<T>(pool, std::forward<Args>(args)...);
    }

    template<typename T>
    void Delete(T *t) {
        DeleteFromPool(pool, t);
    }
};

gcc_malloc
char *
p_strdup_impl(struct pool &pool, StringView src TRACE_ARGS_DECL);

gcc_malloc
char *
p_strdup_lower_impl(struct pool &pool, StringView src TRACE_ARGS_DECL);

#endif
<|endoftext|>