Browse Source

Crawl: Move implementation from header to cpp

pull/4929/head
Gleb Mazovetskiy 4 years ago committed by Anders Jenbo
parent
commit
c8ddf7df65
  1. 3
      3rdParty/tl/CMakeLists.txt
  2. 216
      3rdParty/tl/function_ref.hpp
  3. 2
      CMake/Dependencies.cmake
  4. 1
      Source/CMakeLists.txt
  5. 4
      Source/debug.cpp
  6. 2
      Source/engine/path.cpp
  7. 60
      Source/lighting.cpp
  8. 85
      Source/lighting.h
  9. 6
      Source/missiles.cpp
  10. 2
      test/lighting_test.cpp

3
3rdParty/tl/CMakeLists.txt vendored

@ -0,0 +1,3 @@
add_library(tl INTERFACE)
target_include_directories(tl INTERFACE ${CMAKE_CURRENT_LIST_DIR})

216
3rdParty/tl/function_ref.hpp vendored

@ -0,0 +1,216 @@
///
// function_ref - A low-overhead non-owning function
// Written in 2017 by Simon Brand (@TartanLlama)
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to the
// public domain worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software. If not, see
// <http://creativecommons.org/publicdomain/zero/1.0/>.
///
#ifndef TL_FUNCTION_REF_HPP
#define TL_FUNCTION_REF_HPP
#define TL_FUNCTION_REF_VERSION_MAJOR 1
#define TL_FUNCTION_REF_VERSION_MINOR 0
#define TL_FUNCTION_REF_VERSION_PATCH 0
#if (defined(_MSC_VER) && _MSC_VER == 1900)
/// \exclude
#define TL_FUNCTION_REF_MSVC2015
#endif
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
!defined(__clang__))
/// \exclude
#define TL_FUNCTION_REF_GCC49
#endif
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
!defined(__clang__))
/// \exclude
#define TL_FUNCTION_REF_GCC54
#endif
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
!defined(__clang__))
// GCC < 5 doesn't support overloading on const&& for member functions
/// \exclude
#define TL_FUNCTION_REF_NO_CONSTRR
#endif
#if __cplusplus > 201103L
/// \exclude
#define TL_FUNCTION_REF_CXX14
#endif
// constexpr implies const in C++11, not C++14
#if (__cplusplus == 201103L || defined(TL_FUNCTION_REF_MSVC2015) || \
defined(TL_FUNCTION_REF_GCC49)) && \
!defined(TL_FUNCTION_REF_GCC54)
/// \exclude
#define TL_FUNCTION_REF_11_CONSTEXPR
#else
/// \exclude
#define TL_FUNCTION_REF_11_CONSTEXPR constexpr
#endif
#include <functional>
#include <utility>
namespace tl {
namespace detail {
namespace fnref {
// C++14-style aliases for brevity
template <class T> using remove_const_t = typename std::remove_const<T>::type;
template <class T>
using remove_reference_t = typename std::remove_reference<T>::type;
template <class T> using decay_t = typename std::decay<T>::type;
template <bool E, class T = void>
using enable_if_t = typename std::enable_if<E, T>::type;
template <bool B, class T, class F>
using conditional_t = typename std::conditional<B, T, F>::type;
// std::invoke from C++17
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
template <typename Fn, typename... Args,
typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>,
int = 0>
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
-> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
return std::mem_fn(f)(std::forward<Args>(args)...);
}
template <typename Fn, typename... Args,
typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>{}>>
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
return std::forward<Fn>(f)(std::forward<Args>(args)...);
}
// std::invoke_result from C++17
template <class F, class, class... Us> struct invoke_result_impl;
template <class F, class... Us>
struct invoke_result_impl<
F, decltype(tl::detail::fnref::invoke(std::declval<F>(), std::declval<Us>()...), void()),
Us...> {
using type = decltype(tl::detail::fnref::invoke(std::declval<F>(), std::declval<Us>()...));
};
template <class F, class... Us>
using invoke_result = invoke_result_impl<F, void, Us...>;
template <class F, class... Us>
using invoke_result_t = typename invoke_result<F, Us...>::type;
template <class, class R, class F, class... Args>
struct is_invocable_r_impl : std::false_type {};
template <class R, class F, class... Args>
struct is_invocable_r_impl<
typename std::is_convertible<invoke_result_t<F, Args...>, R>::type, R, F, Args...>
: std::true_type {};
template <class R, class F, class... Args>
using is_invocable_r = is_invocable_r_impl<std::true_type, R, F, Args...>;
} // namespace detail
} // namespace fnref
/// A lightweight non-owning reference to a callable.
///
/// Example usage:
///
/// ```cpp
/// void foo (function_ref<int(int)> func) {
/// std::cout << "Result is " << func(21); //42
/// }
///
/// foo([](int i) { return i*2; });
template <class F> class function_ref;
/// Specialization for function types.
template <class R, class... Args> class function_ref<R(Args...)> {
public:
constexpr function_ref() noexcept = delete;
/// Creates a `function_ref` which refers to the same callable as `rhs`.
constexpr function_ref(const function_ref<R(Args...)> &rhs) noexcept = default;
/// Constructs a `function_ref` referring to `f`.
///
/// \synopsis template <typename F> constexpr function_ref(F &&f) noexcept
template <typename F,
detail::fnref::enable_if_t<
!std::is_same<detail::fnref::decay_t<F>, function_ref>::value &&
detail::fnref::is_invocable_r<R, F &&, Args...>::value> * = nullptr>
TL_FUNCTION_REF_11_CONSTEXPR function_ref(F &&f) noexcept
: obj_(const_cast<void*>(reinterpret_cast<const void *>(std::addressof(f)))) {
callback_ = [](void *obj, Args... args) -> R {
return detail::fnref::invoke(
*reinterpret_cast<typename std::add_pointer<F>::type>(obj),
std::forward<Args>(args)...);
};
}
/// Makes `*this` refer to the same callable as `rhs`.
TL_FUNCTION_REF_11_CONSTEXPR function_ref<R(Args...)> &
operator=(const function_ref<R(Args...)> &rhs) noexcept = default;
/// Makes `*this` refer to `f`.
///
/// \synopsis template <typename F> constexpr function_ref &operator=(F &&f) noexcept;
template <typename F,
detail::fnref::enable_if_t<detail::fnref::is_invocable_r<R, F &&, Args...>::value>
* = nullptr>
TL_FUNCTION_REF_11_CONSTEXPR function_ref<R(Args...)> &operator=(F &&f) noexcept {
obj_ = reinterpret_cast<void *>(std::addressof(f));
callback_ = [](void *obj, Args... args) {
return detail::fnref::invoke(
*reinterpret_cast<typename std::add_pointer<F>::type>(obj),
std::forward<Args>(args)...);
};
return *this;
}
/// Swaps the referred callables of `*this` and `rhs`.
constexpr void swap(function_ref<R(Args...)> &rhs) noexcept {
std::swap(obj_, rhs.obj_);
std::swap(callback_, rhs.callback_);
}
/// Call the stored callable with the given arguments.
R operator()(Args... args) const {
return callback_(obj_, std::forward<Args>(args)...);
}
private:
void *obj_ = nullptr;
R (*callback_)(void *, Args...) = nullptr;
};
/// Swaps the referred callables of `lhs` and `rhs`.
template <typename R, typename... Args>
constexpr void swap(function_ref<R(Args...)> &lhs,
function_ref<R(Args...)> &rhs) noexcept {
lhs.swap(rhs);
}
#if __cplusplus >= 201703L
template <typename R, typename... Args>
function_ref(R (*)(Args...))->function_ref<R(Args...)>;
// TODO, will require some kind of callable traits
// template <typename F>
// function_ref(F) -> function_ref</* deduced if possible */>;
#endif
} // namespace tl
#endif

2
CMake/Dependencies.cmake

@ -185,6 +185,8 @@ endif()
add_subdirectory(3rdParty/libmpq)
add_subdirectory(3rdParty/tl)
add_subdirectory(3rdParty/hoehrmann_utf8)
add_subdirectory(3rdParty/PKWare)

1
Source/CMakeLists.txt

@ -248,6 +248,7 @@ target_link_libraries(libdevilutionx PUBLIC
libmpq
libsmackerdec
simpleini::simpleini
tl
hoehrmann_utf8
)

4
Source/debug.cpp

@ -723,7 +723,7 @@ std::string DebugCmdSpawnUniqueMonster(const string_view parameter)
int spawnedMonster = 0;
auto ret = Crawl(0, MaxCrawlRadius, [&](auto displacement) -> std::optional<std::string> {
auto ret = Crawl(0, MaxCrawlRadius, [&](Displacement displacement) -> std::optional<std::string> {
Point pos = myPlayer.position.tile + displacement;
if (dPlayer[pos.x][pos.y] != 0 || dMonster[pos.x][pos.y] != 0)
return {};
@ -809,7 +809,7 @@ std::string DebugCmdSpawnMonster(const string_view parameter)
int spawnedMonster = 0;
auto ret = Crawl(0, MaxCrawlRadius, [&](auto displacement) -> std::optional<std::string> {
auto ret = Crawl(0, MaxCrawlRadius, [&](Displacement displacement) -> std::optional<std::string> {
Point pos = myPlayer.position.tile + displacement;
if (dPlayer[pos.x][pos.y] != 0 || dMonster[pos.x][pos.y] != 0)
return {};

2
Source/engine/path.cpp

@ -436,7 +436,7 @@ bool path_solid_pieces(Point startPosition, Point destinationPosition)
std::optional<Point> FindClosestValidPosition(const std::function<bool(Point)> &posOk, Point startingPosition, unsigned int minimumRadius, unsigned int maximumRadius)
{
return Crawl(minimumRadius, maximumRadius, [&](auto displacement) -> std::optional<Point> {
return Crawl(minimumRadius, maximumRadius, [&](Displacement displacement) -> std::optional<Point> {
Point candidatePosition = startingPosition + displacement;
if (posOk(candidatePosition))
return candidatePosition;

60
Source/lighting.cpp

@ -128,8 +128,68 @@ void DoUnLight(int nXPos, int nYPos, int nRadius)
}
}
bool CrawlFlipsX(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored.flipX(), mirrored }) {
if (!function(displacement))
return false;
}
return true;
}
bool CrawlFlipsY(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored, mirrored.flipY() }) {
if (!function(displacement))
return false;
}
return true;
}
bool CrawlFlipsXY(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored.flipX(), mirrored, mirrored.flipXY(), mirrored.flipY() }) {
if (!function(displacement))
return false;
}
return true;
}
} // namespace
bool DoCrawl(unsigned radius, tl::function_ref<bool(Displacement)> function)
{
if (radius == 0)
return function(Displacement { 0, 0 });
if (!CrawlFlipsY({ 0, static_cast<int>(radius) }, function))
return false;
for (unsigned i = 1; i < radius; i++) {
if (!CrawlFlipsXY({ static_cast<int>(i), static_cast<int>(radius) }, function))
return false;
}
if (radius > 1) {
if (!CrawlFlipsXY({ static_cast<int>(radius) - 1, static_cast<int>(radius) - 1 }, function))
return false;
}
if (!CrawlFlipsX({ static_cast<int>(radius), 0 }, function))
return false;
for (unsigned i = 1; i < radius; i++) {
if (!CrawlFlipsXY({ static_cast<int>(radius), static_cast<int>(i) }, function))
return false;
}
return true;
}
bool DoCrawl(unsigned minRadius, unsigned maxRadius, tl::function_ref<bool(Displacement)> function)
{
for (unsigned i = minRadius; i <= maxRadius; i++) {
if (!DoCrawl(i, function))
return false;
}
return true;
}
void DoLighting(Point position, int nRadius, int lnum)
{
int xoff = 0;

85
Source/lighting.h

@ -8,12 +8,15 @@
#include <array>
#include <vector>
#include <function_ref.hpp>
#include "automap.h"
#include "engine.h"
#include "engine/point.hpp"
#include "miniwin/miniwin.h"
#include "utils/attributes.h"
#include "utils/stdcompat/invoke_result_t.hpp"
#include "utils/stdcompat/optional.hpp"
namespace devilution {
@ -75,42 +78,6 @@ void ChangeVisionXY(int id, Point position);
void ProcessVisionList();
void lighting_color_cycling();
template <typename F>
auto CrawlFlipsX(Displacement mirrored, F function) -> invoke_result_t<decltype(function), Displacement>
{
const Displacement Flips[] = { mirrored.flipX(), mirrored };
for (auto displacement : Flips) {
auto ret = function(displacement);
if (ret)
return ret;
}
return {};
}
template <typename F>
auto CrawlFlipsY(Displacement mirrored, F function) -> invoke_result_t<decltype(function), Displacement>
{
const Displacement Flips[] = { mirrored, mirrored.flipY() };
for (auto displacement : Flips) {
auto ret = function(displacement);
if (ret)
return ret;
}
return {};
}
template <typename F>
auto CrawlFlipsXY(Displacement mirrored, F function) -> invoke_result_t<decltype(function), Displacement>
{
const Displacement Flips[] = { mirrored.flipX(), mirrored, mirrored.flipXY(), mirrored.flipY() };
for (auto displacement : Flips) {
auto ret = function(displacement);
if (ret)
return ret;
}
return {};
}
constexpr int MaxCrawlRadius = 18;
/**
@ -137,45 +104,29 @@ constexpr int MaxCrawlRadius = 18;
* +-------> x
*/
bool DoCrawl(unsigned radius, tl::function_ref<bool(Displacement)> function);
bool DoCrawl(unsigned minRadius, unsigned maxRadius, tl::function_ref<bool(Displacement)> function);
template <typename F>
auto Crawl(unsigned radius, F function) -> invoke_result_t<decltype(function), Displacement>
{
if (radius == 0)
return function(Displacement { 0, 0 });
auto ret = CrawlFlipsY({ 0, static_cast<int>(radius) }, function);
if (ret)
return ret;
for (unsigned i = 1; i < radius; i++) {
ret = CrawlFlipsXY({ static_cast<int>(i), static_cast<int>(radius) }, function);
if (ret)
return ret;
}
if (radius > 1) {
ret = CrawlFlipsXY({ static_cast<int>(radius) - 1, static_cast<int>(radius) - 1 }, function);
if (ret)
return ret;
}
ret = CrawlFlipsX({ static_cast<int>(radius), 0 }, function);
if (ret)
return ret;
for (unsigned i = 1; i < radius; i++) {
ret = CrawlFlipsXY({ static_cast<int>(radius), static_cast<int>(i) }, function);
if (ret)
return ret;
}
return {};
invoke_result_t<decltype(function), Displacement> result;
DoCrawl(radius, [&result, &function](Displacement displacement) -> bool {
result = function(displacement);
return !result;
});
return result;
}
template <typename F>
auto Crawl(unsigned minRadius, unsigned maxRadius, F function) -> invoke_result_t<decltype(function), Displacement>
{
for (unsigned i = minRadius; i <= maxRadius; i++) {
auto displacement = Crawl(i, function);
if (displacement)
return displacement;
}
return {};
invoke_result_t<decltype(function), Displacement> result;
DoCrawl(minRadius, maxRadius, [&result, &function](Displacement displacement) -> bool {
result = function(displacement);
return !result;
});
return result;
}
/* rdata */

6
Source/missiles.cpp

@ -1218,7 +1218,7 @@ void AddJester(Missile &missile, const AddMissileParameter &parameter)
void AddStealPotions(Missile &missile, const AddMissileParameter & /*parameter*/)
{
Crawl(0, 2, [&](auto displacement) {
Crawl(0, 2, [&](Displacement displacement) {
Point target = missile.position.start + displacement;
if (!InDungeonBounds(target))
return false;
@ -3020,7 +3020,7 @@ void MI_FireRing(Missile &missile)
if (missile.limitReached)
return;
Crawl(3, [&](auto displacement) {
Crawl(3, [&](Displacement displacement) {
Point target = Point { missile.var1, missile.var2 } + displacement;
if (!InDungeonBounds(target))
return false;
@ -3376,7 +3376,7 @@ void MI_Chain(Missile &missile)
Direction dir = GetDirection(position, dst);
AddMissile(position, dst, dir, MIS_LIGHTCTRL, TARGET_MONSTERS, id, 1, missile._mispllvl);
int rad = std::min<int>(missile._mispllvl + 3, MaxCrawlRadius);
Crawl(1, rad, [&](auto displacement) {
Crawl(1, rad, [&](Displacement displacement) {
Point target = position + displacement;
if (InDungeonBounds(target) && dMonster[target.x][target.y] > 0) {
dir = GetDirection(position, target);

2
test/lighting_test.cpp

@ -13,7 +13,7 @@ TEST(Lighting, CrawlTables)
int x = 20;
int y = 20;
Crawl(0, MaxCrawlRadius, [&](auto displacement) {
Crawl(0, MaxCrawlRadius, [&](Displacement displacement) {
int dx = x + displacement.deltaX;
int dy = y + displacement.deltaY;
EXPECT_EQ(added[dx][dy], false) << "displacement " << displacement.deltaX << ":" << displacement.deltaY << " added twice";

Loading…
Cancel
Save