Merge branch 'master' into acs

This commit is contained in:
Sally Coolatta 2023-01-01 17:13:31 -05:00
commit 0d67b12c74
11 changed files with 239 additions and 51 deletions

View file

@ -134,8 +134,6 @@ if("${SRB2_CONFIG_SYSTEM_LIBRARIES}")
find_package(CURL REQUIRED)
find_package(OPENMPT REQUIRED)
find_package(GME REQUIRED)
find_package(DiscordRPC REQUIRED)
find_package(acsvm REQUIRED)
endif()
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View file

@ -1,33 +0,0 @@
include(LibFindMacros)
libfind_pkg_check_modules(DISCORDRPC_PKGCONF DISCORDRPC)
find_path(DISCORDRPC_INCLUDE_DIR
NAMES discord_rpc.h
PATHS
${DISCORDRPC_PKGCONF_INCLUDE_DIRS}
"/usr/include"
"/usr/local/include"
)
find_library(DISCORDRPC_LIBRARY
NAMES discord-rpc
PATHS
${DISCORDRPC_PKGCONF_LIBRARY_DIRS}
"/usr/lib"
"/usr/local/lib"
)
set(DISCORDRPC_PROCESS_INCLUDES DISCORDRPC_INCLUDE_DIR)
set(DISCORDRPC_PROCESS_LIBS DISCORDRPC_LIBRARY)
libfind_process(DISCORDRPC)
if(DISCORDRPC_FOUND AND NOT TARGET DiscordRPC::DiscordRPC)
add_library(DiscordRPC::DiscordRPC UNKNOWN IMPORTED)
set_target_properties(
DiscordRPC::DiscordRPC
PROPERTIES
IMPORTED_LOCATION "${DISCORDRPC_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${DISCORDRPC_INCLUDE_DIR}"
)
endif()

View file

@ -1,9 +1,12 @@
#ifndef __SRB2_CXXUTIL_HPP__
#define __SRB2_CXXUTIL_HPP__
#include <cstdlib>
#include <type_traits>
#include <utility>
#include "doomdef.h"
namespace srb2 {
template <class F>
@ -19,7 +22,8 @@ public:
void operator=(Finally&& from) = delete;
~Finally() noexcept {
f_();
if (call_)
f_();
}
private:
@ -32,6 +36,117 @@ Finally<std::decay_t<F>> finally(F&& f) noexcept {
return Finally {std::forward<F>(f)};
}
struct SourceLocation {
const char* file_name;
unsigned int line_number;
};
#define SRB2_SOURCE_LOCATION \
srb2::SourceLocation { __FILE__, __LINE__ }
#ifndef SRB2_ASSERT_HANDLER
#define SRB2_ASSERT_HANDLER srb2::IErrorAssertHandler
#endif
#if !defined(NDEBUG) || defined(PARANOIA)
// An assertion level of 2 will activate all invocations of the SRB2_ASSERT macro
#define SRB2_ASSERTION_LEVEL 2
#else
// The minimum assertion level is 1
#define SRB2_ASSERTION_LEVEL 1
#endif
/// Assert a precondition expression in debug builds.
#define SRB2_ASSERT(expr) srb2::do_assert<2, SRB2_ASSERT_HANDLER>([&] { return (expr); }, SRB2_SOURCE_LOCATION, #expr)
class IErrorAssertHandler {
public:
static void handle(const SourceLocation& source_location, const char* expression) {
I_Error("Assertion failed at %s:%u: %s != true",
source_location.file_name,
source_location.line_number,
expression);
}
};
class NoOpAssertHandler {
public:
static void handle(const SourceLocation& source_location, const char* expression) {}
};
/// @brief Assert a precondition expression, aborting the application if it fails.
/// @tparam Expr
/// @tparam Level the level of this assertion; if it is less than or equal to SRB2_ASSERTION_LEVEL, this overload will
/// activate.
/// @param expr a callable which returns a bool
/// @param source_location a struct containing the source location of the assertion, e.g. SRB2_SOURCE_LOCATION
/// @param expression the expression evaluated in the expression callable
/// @param message an optional message to display for the assertion
template <unsigned int Level, class Handler, class Expr>
std::enable_if_t<(Level <= SRB2_ASSERTION_LEVEL), void>
do_assert(const Expr& expr, const SourceLocation& source_location, const char* expression = "") noexcept {
static_assert(Level > 0, "level of an assertion must not be 0");
if (!expr()) {
Handler::handle(source_location, expression);
std::abort();
}
}
template <unsigned int Level, class, class Expr>
std::enable_if_t<(Level > SRB2_ASSERTION_LEVEL), void>
do_assert(const Expr&, const SourceLocation&, const char* = "") noexcept {
}
template <typename T>
class NotNull final {
T ptr_;
public:
static_assert(std::is_convertible_v<decltype(std::declval<T>() != nullptr), bool>,
"T is not comparable with nullptr_t");
/// @brief Move-construct from the pointer value U, asserting that it is not null. Allows construction of a
/// NotNull<T> from any compatible pointer U, for example with polymorphic classes.
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, T>>>
constexpr NotNull(U&& rhs) : ptr_(std::forward<U>(rhs)) {
SRB2_ASSERT(ptr_ != nullptr);
}
/// @brief Wrap the pointer type T, asserting that the pointer is not null.
template <typename = std::enable_if_t<!std::is_same_v<std::nullptr_t, T>>>
constexpr NotNull(T rhs) : ptr_(std::move(rhs)) {
SRB2_ASSERT(ptr_ != nullptr);
}
/// @brief Copy construction from NotNull of convertible type U. Only if the incoming pointer is NotNull already.
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, T>>>
constexpr NotNull(const NotNull<U>& rhs) : NotNull(rhs.get()) {
// Value is guaranteed to be not null by construction; no assertion necessary
}
NotNull(const NotNull& rhs) = default;
NotNull& operator=(const NotNull& rhs) = default;
/// @brief Get the stored pointer.
constexpr T get() const { return ptr_; }
/// @brief Convert to T (the pointer type).
constexpr operator T() const { return get(); }
/// @brief Arrow-dereference to *T (the actual value pointed to).
constexpr decltype(auto) operator->() const { return get(); }
/// @brief Dereference to *T (the actual value pointed to).
constexpr decltype(auto) operator*() const { return *get(); }
// It is not allowed to construct NotNull<T> with nullptr regardless of T.
NotNull(std::nullptr_t) = delete;
NotNull& operator=(std::nullptr_t) = delete;
};
template <class T>
NotNull(T) -> NotNull<T>;
} // namespace srb2
#endif // __SRB2_CXXUTIL_HPP__

View file

@ -645,6 +645,7 @@ UINT32 quickncasehash (const char *p, size_t n)
#endif
// An assert-type mechanism.
// NOTE: USE SRB2_ASSERT FOR C++ CODE INSTEAD
#ifdef PARANOIA
#define I_Assert(e) ((e) ? (void)0 : I_Error("assert failed: %s, file %s, line %d", #e, __FILE__, __LINE__))
#else

View file

@ -110,7 +110,10 @@ typedef long ssize_t;
#define strnicmp(x,y,n) strncasecmp(x,y,n)
#endif
char *strcasestr(const char *in, const char *what);
char *nongnu_strcasestr(const char *in, const char *what);
#ifndef _GNU_SOURCE
#define strcasestr nongnu_strcasestr
#endif
#define stristr strcasestr
#if defined (PC_DOS) || defined (_WIN32) || defined (__HAIKU__)

View file

@ -51,7 +51,7 @@ swapp (char ***ppap, char ***ppbp, char **cpap, char **cpbp)
}
char *
strcasestr (const char *s, const char *q)
nongnu_strcasestr (const char *s, const char *q)
{
size_t qn;

View file

@ -1,3 +1,5 @@
target_sources(srb2tests PRIVATE
boolcompat.cpp
notnull.cpp
testbase.hpp
)

View file

@ -1,3 +1,4 @@
#include "testbase.hpp"
#include <catch2/catch_test_macros.hpp>
#include "../doomtype.h"

31
src/tests/notnull.cpp Normal file
View file

@ -0,0 +1,31 @@
#include "testbase.hpp"
#include <catch2/catch_test_macros.hpp>
#include "../cxxutil.hpp"
namespace {
class A {
public:
virtual bool foo() = 0;
};
class B : public A {
public:
virtual bool foo() override final { return true; };
};
} // namespace
TEST_CASE("NotNull<int*> is constructible from int*") {
int a = 0;
REQUIRE(srb2::NotNull(static_cast<int*>(&a)));
}
TEST_CASE("NotNull<A*> is constructible from B* where B inherits from A") {
B b;
REQUIRE(srb2::NotNull(static_cast<B*>(&b)));
}
TEST_CASE("NotNull<A*> dereferences to B& to call foo") {
B b;
srb2::NotNull<A*> a {static_cast<B*>(&b)};
REQUIRE(a->foo());
}

6
src/tests/testbase.hpp Normal file
View file

@ -0,0 +1,6 @@
#ifndef __SRB2_TESTS_TESTBASE_HPP__
#define __SRB2_TESTS_TESTBASE_HPP__
#define SRB2_ASSERT_HANDLER srb2::NoOpAssertHandler
#endif // __SRB2_TESTS_TESTBASE_HPP__

View file

@ -88,7 +88,7 @@ if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
zutil.c
)
list(TRANSFORM ZLIB_SRCS PREPEND "${ZLIB_SOURCE_DIR}/")
configure_file("${ZLIB_SOURCE_DIR}/zlib.pc.cmakein" "${ZLIB_BINARY_DIR}/zlib.pc" @ONLY)
configure_file("${ZLIB_SOURCE_DIR}/zconf.h.cmakein" "${ZLIB_BINARY_DIR}/include/zconf.h" @ONLY)
configure_file("${ZLIB_SOURCE_DIR}/zlib.h" "${ZLIB_BINARY_DIR}/include/zlib.h" @ONLY)
@ -123,7 +123,7 @@ if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
png.h
pngconf.h
pngpriv.h
pngdebug.h
pnginfo.h
@ -472,7 +472,7 @@ if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
soundlib/OggStream.h
soundlib/Loaders.h
soundlib/BitReader.h
soundlib/opal.h
soundlib/opal.h
sounddsp/AGC.cpp
sounddsp/EQ.cpp
@ -501,7 +501,7 @@ if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
endif()
target_compile_features(openmpt PRIVATE cxx_std_11)
target_compile_definitions(openmpt PRIVATE -DLIBOPENMPT_BUILD)
target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/common")
target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/src")
target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/include")
@ -528,17 +528,81 @@ if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
target_link_libraries(gme PRIVATE ZLIB::ZLIB)
endif()
if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")
CPMAddPackage(
NAME DiscordRPC
VERSION 3.4.0
URL "https://github.com/discord/discord-rpc/archive/refs/tags/v3.4.0.zip"
EXCLUDE_FROM_ALL ON
OPTIONS
"BUILD_EXAMPLES OFF"
CPMAddPackage(
NAME RapidJSON
VERSION 1.1.0
URL "https://github.com/Tencent/rapidjson/archive/v1.1.0.tar.gz"
EXCLUDE_FROM_ALL ON
DOWNLOAD_ONLY ON
)
if(RapidJSON_ADDED)
add_library(RapidJSON INTERFACE)
add_library(RapidJSON::RapidJSON ALIAS RapidJSON)
target_include_directories(RapidJSON INTERFACE "${RapidJSON_SOURCE_DIR}/include")
endif()
CPMAddPackage(
NAME DiscordRPC
VERSION 3.4.0
URL "https://github.com/discord/discord-rpc/archive/refs/tags/v3.4.0.zip"
EXCLUDE_FROM_ALL ON
DOWNLOAD_ONLY ON
)
if(DiscordRPC_ADDED)
set(DiscordRPC_SOURCES
include/discord_rpc.h
include/discord_register.h
src/discord_rpc.cpp
src/rpc_connection.h
src/rpc_connection.cpp
src/serialization.h
src/serialization.cpp
src/connection.h
src/backoff.h
src/msg_queue.h
)
target_include_directories(discord-rpc INTERFACE "${DiscordRPC_SOURCE_DIR}/include")
list(TRANSFORM DiscordRPC_SOURCES PREPEND "${DiscordRPC_SOURCE_DIR}/")
# Discord RPC is always statically linked because it's tiny.
add_library(discord-rpc STATIC ${DiscordRPC_SOURCES})
add_library(DiscordRPC::DiscordRPC ALIAS discord-rpc)
target_include_directories(discord-rpc PUBLIC "${DiscordRPC_SOURCE_DIR}/include")
target_compile_features(discord-rpc PUBLIC cxx_std_11)
target_link_libraries(discord-rpc PRIVATE RapidJSON::RapidJSON)
# Platform-specific connection and register impls
if(WIN32)
target_compile_definitions(discord-rpc PUBLIC -DDISCORD_WINDOWS)
target_sources(discord-rpc PRIVATE
"${DiscordRPC_SOURCE_DIR}/src/connection_win.cpp"
"${DiscordRPC_SOURCE_DIR}/src/discord_register_win.cpp"
)
target_link_libraries(discord-rpc PRIVATE psapi advapi32)
endif()
if(UNIX)
target_sources(discord-rpc PRIVATE
"${DiscordRPC_SOURCE_DIR}/src/connection_unix.cpp"
)
if(APPLE)
target_compile_definitions(discord-rpc PUBLIC -DDISCORD_OSX)
target_sources(discord-rpc PRIVATE
"${DiscordRPC_SOURCE_DIR}/src/discord_register_osx.m"
)
target_link_libraries(discord-rpc PUBLIC "-framework AppKit")
endif()
if(UNIX AND NOT APPLE)
target_compile_definitions(discord-rpc PUBLIC -DDISCORD_LINUX)
target_sources(discord-rpc PRIVATE
"${DiscordRPC_SOURCE_DIR}/src/discord_register_linux.cpp"
)
endif()
endif()
endif()
if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}")