Merge pull request #1124 from jagerman/deabseil-finale

De-abseil finale: no more abseil
pull/1051/head^2
Jeff 4 years ago committed by GitHub
commit 1e96347981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

6
.gitmodules vendored

@ -1,9 +1,6 @@
[submodule "external/nlohmann"]
path = external/nlohmann
url = https://github.com/nlohmann/json.git
[submodule "external/abseil-cpp"]
path = external/abseil-cpp
url = https://github.com/abseil/abseil-cpp.git
[submodule "external/googletest"]
path = external/googletest
url = https://github.com/google/googletest.git
@ -19,3 +16,6 @@
[submodule "external/optional-lite"]
path = external/optional-lite
url = https://github.com/martinmoene/optional-lite.git
[submodule "external/date"]
path = external/date
url = https://github.com/HowardHinnant/date.git

@ -96,12 +96,11 @@ matrix:
# - name: "undefined sanitizer"
# os: osx
# env: BUILD_TYPE=Debug XSAN=undefined PATH="/usr/local/opt/ccache/libexec:$PATH" CC=/usr/local/opt/llvm/bin/clang CXX=/usr/local/opt/llvm/bin/clang++
- name: "memory sanitizer"
os: linux
dist: xenial
compiler: clang
env: BUILD_TYPE=Debug XSAN=memory
addons: *core_apt_addons
# - name: "memory sanitizer"
# os: linux
# compiler: clang
# env: BUILD_TYPE=Debug XSAN=memory
# addons: *core_apt_addons
# - name: "router docker image"
# os: linux
# dist: xenial

@ -105,6 +105,7 @@ endif()
if(XSAN)
set(DEBUG_FLAGS ${DEBUG_FLAGS} "-fsanitize=${XSAN}" -fno-omit-frame-pointer)
set(OPTIMIZE_FLAGS "-O0")
message(STATUS "Doing a ${XSAN} sanitizer build")
endif(XSAN)
if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
@ -249,12 +250,12 @@ if(SUBMODULE_CHECK)
endfunction ()
message(STATUS "Checking submodules")
check_submodule(external/abseil-cpp)
check_submodule(external/nlohmann)
check_submodule(external/googletest)
check_submodule(external/cxxopts)
check_submodule(external/ghc-filesystem)
check_submodule(external/optional-lite)
check_submodule(external/date)
endif()
endif()
@ -262,12 +263,12 @@ if(WITH_TESTS)
add_subdirectory(external/googletest EXCLUDE_FROM_ALL)
endif()
add_subdirectory(external/abseil-cpp EXCLUDE_FROM_ALL)
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(external/nlohmann EXCLUDE_FROM_ALL)
add_subdirectory(external/cxxopts)
add_subdirectory(external/ghc-filesystem)
add_subdirectory(external/optional-lite)
add_subdirectory(external/date)
if(ANDROID)
list(APPEND LIBS log)

@ -121,7 +121,7 @@ SCAN_BUILD ?= scan-build
UNAME = $(shell which uname)
COMMON_CMAKE_OPTIONS = -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DWITH_SHARED=$(SHARED_LIB) -DDOWNLOAD_SODIUM=$(DOWNLOAD_SODIUM) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
COMMON_CMAKE_OPTIONS = -DSTATIC_LINK_RUNTIME=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DWITH_SHARED=$(SHARED_LIB) -DDOWNLOAD_SODIUM=$(DOWNLOAD_SODIUM) -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DXSAN=$(XSAN)
ifeq ($(shell $(UNAME)),SunOS)
CONFIG_CMD = $(shell gecho -n "cd '$(BUILD_ROOT)' && " ; gecho -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) $(COMMON_CMAKE_OPTIONS) '$(REPO)'")
@ -134,9 +134,9 @@ else
CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DUSE_SHELLHOOKS=$(SHELL_HOOKS) -DTRACY_ROOT=$(TRACY_ROOT) $(COMMON_CMAKE_OPTIONS) '$(REPO)'")
CONFIG_CMD_WINDOWS = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=ON -DUSE_SHELLHOOKS=$(SHELL_HOOKS) $(COMMON_CMAKE_OPTIONS) '$(REPO)'")
ANALYZE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "$(SCAN_BUILD) cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DXSAN=$(XSAN) $(COMMON_CMAKE_OPTIONS) '$(REPO)'")
ANALYZE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "$(SCAN_BUILD) cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) $(COMMON_CMAKE_OPTIONS) '$(REPO)'")
COVERAGE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DWITH_COVERAGE=yes -DXSAN=$(XSAN) $(COMMON_CMAKE_OPTIONS) '$(REPO)'")
COVERAGE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DCMAKE_CROSSCOMPILING=$(CROSS) -DWITH_COVERAGE=yes $(COMMON_CMAKE_OPTIONS) '$(REPO)'")
endif
TARGETS = $(REPO)/lokinet
@ -179,7 +179,6 @@ release-compile: release-configure
$(TARGETS): release-compile
release: $(TARGETS)
make -C '$(BUILD_ROOT)' test
make -C '$(BUILD_ROOT)' check
shadow-configure: clean
@ -219,13 +218,16 @@ testnet: $(TESTNET_VENV)
$(PYTHON3) $(REPO)/contrib/testnet/genconf.py --bin=$(TESTNET_EXE) --svc=$(TESTNET_SERVERS) --clients=$(TESTNET_CLIENTS) --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF) --ifname=$(TESTNET_IFNAME) --baseport=$(TESTNET_BASEPORT) --ip=$(TESTNET_IP) --netid=$(TESTNET_NETID) --lokid='$(TESTNET_VENV)/bin/python $(REPO)/contrib/testnet/lokid.py'
LLARP_DEBUG=$(TESTNET_DEBUG) supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF)
$(TEST_EXE): debug
gtest: debug
test x$(CROSS) = xOFF && $(MAKE) -C $(BUILD_ROOT) rungtest || test x$(CROSS) = xON
gtest: $(TEST_EXE)
test x$(CROSS) = xOFF && $(TEST_EXE) || test x$(CROSS) = xON
catch: debug
test x$(CROSS) = xOFF && $(MAKE) -C $(BUILD_ROOT) catch || test x$(CROSS) = xON
test: gtest
$(MAKE) -C $(BUILD_ROOT) check
check: debug
test x$(CROSS) = xOFF && $(MAKE) -C $(BUILD_ROOT) check || test x$(CROSS) = xON
test: check
static-configure: $(LIBUV_PREFIX) $(LIBCURL_PREFIX)
(test x$(TOOLCHAIN) = x && $(CONFIG_CMD) -DCMAKE_BUILD_TYPE=Release -DSTATIC_LINK=ON -DRELEASE_MOTTO="$(shell cat motto.txt)" -DCMAKE_C_FLAGS='$(CFLAGS)' -DCMAKE_CXX_FLAGS='$(CXXFLAGS)' -DLIBUV_ROOT='$(LIBUV_PREFIX)' -DLIBCURL_ROOT='$(LIBCURL_PREFIX)' ) || (test x$(TOOLCHAIN) != x && $(CONFIG_CMD) -DCMAKE_BUILD_TYPE=Release -DSTATIC_LINK=ON -DRELEASE_MOTTO="$(shell cat motto.txt)" -DCMAKE_C_FLAGS='$(CFLAGS)' -DCMAKE_CXX_FLAGS='$(CXXFLAGS)' -DLIBUV_ROOT='$(LIBUV_PREFIX)' -DLIBCURL_ROOT='$(LIBCURL_PREFIX)' -DCMAKE_TOOLCHAIN_FILE=$(TOOLCHAIN) -DNATIVE_BUILD=OFF )
@ -309,7 +311,7 @@ coverage-config: clean
coverage: coverage-config
$(MAKE) -C $(BUILD_ROOT)
test x$(CROSS) = xOFF && $(TEST_EXE) || true # continue even if tests fail
test x$(CROSS) = xOFF && $(MAKE) -C $(BUILD_ROOT) check || true # continue even if tests fail
mkdir -p "$(COVERAGE_OUTDIR)"
ifeq ($(CLANG),OFF)
gcovr -r . --branches --html --html-details -o "$(COVERAGE_OUTDIR)/lokinet.html"
@ -346,7 +348,7 @@ debian: debian-configure
cp $(EXE) lokinet
debian-test:
test x$(CROSS) = xOFF && $(TEST_EXE) || test x$(CROSS) = xON
test x$(CROSS) = xOFF && $(MAKE) -C $(BUILD_ROOT) check || test x$(CROSS) = xON
install:
DESTDIR=$(DESTDIR) $(MAKE) -C '$(BUILD_ROOT)' install

@ -1 +0,0 @@
Subproject commit aa844899c937bde5d2b24f276b59997e5b668bde

1
external/date vendored

@ -0,0 +1 @@
Subproject commit 9a0ee2542848ab8625984fc8cdbfb9b5414c0082

@ -77,7 +77,7 @@ namespace abyss
}
static void
OnTick(ABSL_ATTRIBUTE_UNUSED llarp_tcp_conn* conn)
OnTick(llarp_tcp_conn* /*conn*/)
{
}

@ -22,14 +22,13 @@ namespace abyss
auto itr = header.begin();
while(itr != header.end())
{
lowerHeader += ::tolower(*itr);
lowerHeader += std::tolower(*itr);
++itr;
}
if(ShouldProcessHeader(string_view(lowerHeader)))
if(ShouldProcessHeader(lowerHeader))
{
val = val.substr(val.find_first_not_of(' '));
Header.Headers.emplace(lowerHeader.c_str(),
llarp::string_view_string(val));
Header.Headers.emplace(lowerHeader.c_str(), val);
}
return true;
}

@ -15,6 +15,7 @@ set(LIB_UTIL_SRC
util/logging/file_logger.cpp
util/logging/json_logger.cpp
util/logging/logger.cpp
util/logging/logger_internal.cpp
util/logging/loglevel.cpp
util/logging/ostream_logger.cpp
util/logging/syslog_logger.cpp
@ -42,17 +43,12 @@ endif()
target_link_libraries(${UTIL_LIB} PUBLIC ${CRYPTOGRAPHY_LIB} ${LOG_LIB} ${CURL_LIBRARIES})
target_link_libraries(${UTIL_LIB} PUBLIC
absl::time absl::hash
nlohmann_json::nlohmann_json
ghc_filesystem
optional-lite
date::date
)
# cut back on fluff
if (NOT WIN32)
target_link_libraries(${UTIL_LIB} PUBLIC absl::strings)
endif(NOT WIN32)
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(ISOLATE_PROC_SRC linux/netns.cpp)
endif()

@ -12,8 +12,6 @@
#include <util/str.hpp>
#include <util/lokinet_init.h>
#include <absl/strings/strip.h>
#include <cstdlib>
#include <fstream>
#include <ios>
@ -21,17 +19,63 @@
namespace llarp
{
const char *
lokinetEnv(string_view suffix)
{
std::string env;
env.reserve(8 + suffix.size());
env.append("LOKINET_"s);
env.append(suffix.begin(), suffix.end());
return std::getenv(env.c_str());
}
std::string
tostr(string_view val)
fromEnv(string_view val, string_view envNameSuffix)
{
if(const char *ptr = lokinetEnv(envNameSuffix))
return ptr;
return {val.begin(), val.end()};
}
int
fromEnv(const int &val, string_view envNameSuffix)
{
if(const char *ptr = lokinetEnv(envNameSuffix))
return std::atoi(ptr);
return val;
}
uint16_t
fromEnv(const uint16_t &val, string_view envNameSuffix)
{
if(const char *ptr = lokinetEnv(envNameSuffix))
return std::atoi(ptr);
return val;
}
size_t
fromEnv(const size_t &val, string_view envNameSuffix)
{
if(const char *ptr = lokinetEnv(envNameSuffix))
return std::atoll(ptr);
return val;
}
nonstd::optional< bool >
fromEnv(const nonstd::optional< bool > &val, string_view envNameSuffix)
{
if(const char *ptr = lokinetEnv(envNameSuffix))
return IsTrueValue(ptr);
return val;
}
int
svtoi(string_view val)
{
auto str = tostr(val);
return std::atoi(str.c_str());
return std::atoi(val.data());
}
nonstd::optional< bool >
@ -62,14 +106,14 @@ namespace llarp
}
if(key == "default-protocol")
{
m_DefaultLinkProto = tostr(val);
m_DefaultLinkProto = val;
LogInfo("overriding default link protocol to '", val, "'");
}
if(key == "netid")
{
if(val.size() <= NetID::size())
{
m_netId = tostr(val);
m_netId = val;
LogInfo("setting netid to '", val, "'");
}
else
@ -97,29 +141,29 @@ namespace llarp
}
if(key == "nickname")
{
m_nickname = tostr(val);
m_nickname = val;
// set logger name here
LogContext::Instance().nodeName = nickname();
LogInfo("nickname set");
}
if(key == "encryption-privkey")
{
m_encryptionKeyfile = tostr(val);
m_encryptionKeyfile = val;
LogDebug("encryption key set to ", m_encryptionKeyfile);
}
if(key == "contact-file")
{
m_ourRcFile = tostr(val);
m_ourRcFile = val;
LogDebug("rc file set to ", m_ourRcFile);
}
if(key == "transport-privkey")
{
m_transportKeyfile = tostr(val);
m_transportKeyfile = val;
LogDebug("transport key set to ", m_transportKeyfile);
}
if((key == "identity-privkey" || key == "ident-privkey"))
{
m_identKeyfile = tostr(val);
m_identKeyfile = val;
LogDebug("identity key set to ", m_identKeyfile);
}
if(key == "public-address" || key == "public-ip")
@ -185,16 +229,16 @@ namespace llarp
}
else if(key == "profiles")
{
m_routerProfilesFile = tostr(val);
m_routerProfilesFile = val;
llarp::LogInfo("setting profiles to ", routerProfilesFile());
}
else if(key == "strict-connect")
{
m_strictConnect = tostr(val);
m_strictConnect = val;
}
else
{
m_netConfig.emplace(tostr(key), tostr(val));
m_netConfig.emplace(key, val);
}
}
@ -203,7 +247,7 @@ namespace llarp
{
if(key == "dir")
{
m_nodedbDir = tostr(val);
m_nodedbDir = val;
}
}
@ -213,12 +257,12 @@ namespace llarp
if(key == "upstream")
{
llarp::LogInfo("add upstream resolver ", val);
netConfig.emplace("upstream-dns", tostr(val));
netConfig.emplace("upstream-dns", val);
}
if(key == "bind")
{
llarp::LogInfo("set local dns to ", val);
netConfig.emplace("local-dns", tostr(val));
netConfig.emplace("local-dns", val);
}
}
@ -228,25 +272,21 @@ namespace llarp
uint16_t proto = 0;
std::unordered_set< std::string > parsed_opts;
std::string v = tostr(val);
std::string::size_type idx;
static constexpr char delimiter = ',';
do
{
idx = v.find_first_of(delimiter);
if(idx != std::string::npos)
idx = val.find_first_of(delimiter);
if(idx != string_view::npos)
{
std::string data = v.substr(0, idx);
absl::StripAsciiWhitespace(&data);
parsed_opts.emplace(std::move(data));
v = v.substr(idx + 1);
parsed_opts.insert(TrimWhitespace(val.substr(0, idx)));
val.remove_prefix(idx + 1);
}
else
{
absl::StripAsciiWhitespace(&v);
parsed_opts.insert(std::move(v));
parsed_opts.insert(TrimWhitespace(val));
}
} while(idx != std::string::npos);
} while(idx != string_view::npos);
std::unordered_set< std::string > opts;
/// for each option
for(const auto &item : parsed_opts)
@ -274,13 +314,12 @@ namespace llarp
}
else
{
m_InboundLinks.emplace_back(tostr(key), AF_INET, proto, std::move(opts));
m_InboundLinks.emplace_back(key, AF_INET, proto, std::move(opts));
}
}
void
ConnectConfig::fromSection(ABSL_ATTRIBUTE_UNUSED string_view key,
string_view val)
ConnectConfig::fromSection(string_view /*key*/, string_view val)
{
routers.emplace_back(val.begin(), val.end());
}
@ -288,7 +327,7 @@ namespace llarp
void
ServicesConfig::fromSection(string_view key, string_view val)
{
services.emplace_back(tostr(key), tostr(val));
services.emplace_back(key, val);
}
void
@ -296,37 +335,7 @@ namespace llarp
{
if(key == "pidfile")
{
pidfile = tostr(val);
}
}
void
MetricsConfig::fromSection(string_view key, string_view val)
{
if(key == "enable-metrics")
{
disableMetrics = IsFalseValue(val);
}
else if(key == "disable-metrics")
{
disableMetrics = IsTrueValue(val);
}
else if(key == "disable-metrics-log")
{
disableMetricLogs = IsTrueValue(val);
}
else if(key == "json-metrics-path")
{
jsonMetricsPath = tostr(val);
}
else if(key == "metric-tank-host")
{
metricTankHost = tostr(val);
}
else
{
// consume everything else as a metric tag
metricTags[tostr(key)] = tostr(val);
pidfile = val;
}
}
@ -339,7 +348,7 @@ namespace llarp
}
if(key == "bind")
{
m_rpcBindAddr = tostr(val);
m_rpcBindAddr = val;
}
if(key == "authkey")
{
@ -353,7 +362,7 @@ namespace llarp
if(key == "service-node-seed")
{
usingSNSeed = true;
ident_keyfile = tostr(val);
ident_keyfile = std::string{val};
}
if(key == "enabled")
{
@ -361,15 +370,15 @@ namespace llarp
}
if(key == "jsonrpc" || key == "addr")
{
lokidRPCAddr = tostr(val);
lokidRPCAddr = val;
}
if(key == "username")
{
lokidRPCUser = tostr(val);
lokidRPCUser = val;
}
if(key == "password")
{
lokidRPCPassword = tostr(val);
lokidRPCPassword = val;
}
}
@ -397,7 +406,7 @@ namespace llarp
}
if(key == "level")
{
const auto maybe = LogLevelFromString(tostr(val));
const auto maybe = LogLevelFromString(val);
if(not maybe.has_value())
{
LogError("bad log level: ", val);
@ -414,7 +423,7 @@ namespace llarp
if(key == "file")
{
LogInfo("open log file: ", val);
std::string fname = tostr(val);
std::string fname = val;
FILE *const logfile = ::fopen(fname.c_str(), "a");
if(logfile)
{
@ -494,7 +503,6 @@ namespace llarp
links = find_section< LinksConfig >(parser, "bind");
services = find_section< ServicesConfig >(parser, "services");
system = find_section< SystemConfig >(parser, "system");
metrics = find_section< MetricsConfig >(parser, "metrics");
api = find_section< ApiConfig >(parser, "api");
lokid = find_section< LokidConfig >(parser, "lokid");
bootstrap = find_section< BootstrapConfig >(parser, "bootstrap");
@ -630,10 +638,6 @@ llarp_generic_ensure_config(std::ofstream &f, std::string basepath,
f << "# uncomment for syslog logging\n";
f << "#type=syslog\n";
// metrics
f << "[metrics]\n";
f << "json-metrics-path=" << basepath << "metrics.json\n";
f << "\n\n";
f << "# admin api\n";

@ -6,7 +6,6 @@
#include <util/fs.hpp>
#include <util/str.hpp>
#include <absl/strings/str_cat.h>
#include <cstdlib>
#include <functional>
#include <string>
@ -18,76 +17,19 @@ namespace llarp
{
struct ConfigParser;
template < typename Type >
Type
fromEnv(const Type& val, string_view envNameSuffix)
{
std::string envName = absl::StrCat("LOKINET_", envNameSuffix);
char* ptr = std::getenv(envName.c_str());
if(ptr)
{
return ptr;
}
return val;
}
template <>
inline int
fromEnv< int >(const int& val, string_view envNameSuffix)
{
std::string envName = absl::StrCat("LOKINET_", envNameSuffix);
const char* ptr = std::getenv(envName.c_str());
if(ptr)
{
return std::atoi(ptr);
}
return val;
}
template <>
inline uint16_t
fromEnv< uint16_t >(const uint16_t& val, string_view envNameSuffix)
{
std::string envName = absl::StrCat("LOKINET_", envNameSuffix);
const char* ptr = std::getenv(envName.c_str());
if(ptr)
{
return std::atoi(ptr);
}
return val;
}
template <>
inline size_t
fromEnv< size_t >(const size_t& val, string_view envNameSuffix)
{
std::string envName = absl::StrCat("LOKINET_", envNameSuffix);
const char* ptr = std::getenv(envName.c_str());
if(ptr)
{
return std::atoll(ptr);
}
return val;
}
template <>
inline nonstd::optional< bool >
fromEnv< nonstd::optional< bool > >(const nonstd::optional< bool >& val,
string_view envNameSuffix)
{
std::string envName = absl::StrCat("LOKINET_", envNameSuffix);
const char* ptr = std::getenv(envName.c_str());
if(ptr)
{
return IsTrueValue(ptr);
}
inline const char*
lokinetEnv(string_view suffix);
return val;
}
std::string
fromEnv(string_view val, string_view envNameSuffix);
int
fromEnv(const int& val, string_view envNameSuffix);
uint16_t
fromEnv(const uint16_t& val, string_view envNameSuffix);
size_t
fromEnv(const size_t& val, string_view envNameSuffix);
nonstd::optional< bool >
fromEnv(const nonstd::optional< bool >& val, string_view envNameSuffix);
class RouterConfig
{
@ -244,18 +186,6 @@ namespace llarp
fromSection(string_view key, string_view val);
};
struct MetricsConfig
{
bool disableMetrics = true;
bool disableMetricLogs = true;
fs::path jsonMetricsPath;
std::string metricTankHost;
std::map< std::string, std::string > metricTags;
void
fromSection(string_view key, string_view val);
};
class ApiConfig
{
private:
@ -316,7 +246,6 @@ namespace llarp
LinksConfig links;
ServicesConfig services;
SystemConfig system;
MetricsConfig metrics;
ApiConfig api;
LokidConfig lokid;
BootstrapConfig bootstrap;

@ -53,7 +53,7 @@ namespace llarp
bool
ConfigParser::Parse()
{
std::list< String_t > lines;
std::list< string_view > lines;
{
auto itr = m_Data.begin();
// split into lines
@ -69,16 +69,16 @@ namespace llarp
}
}
String_t sectName;
string_view sectName;
size_t lineno = 0;
for(const auto& line : lines)
{
lineno++;
String_t realLine;
string_view realLine;
auto comment = line.find_first_of(';');
if(comment == String_t::npos)
if(comment == string_view::npos)
comment = line.find_first_of('#');
if(comment == String_t::npos)
if(comment == string_view::npos)
realLine = line;
else
realLine = line.substr(0, comment);
@ -89,8 +89,8 @@ namespace llarp
auto sectOpenPos = realLine.find_first_of('[');
auto sectClosPos = realLine.find_first_of(']');
auto kvDelim = realLine.find_first_of('=');
if(sectOpenPos != String_t::npos && sectClosPos != String_t::npos
&& kvDelim == String_t::npos)
if(sectOpenPos != string_view::npos && sectClosPos != string_view::npos
&& kvDelim == string_view::npos)
{
// section header
@ -104,13 +104,13 @@ namespace llarp
// set section name
sectName = realLine.substr(sectOpenPos, sectClosPos);
}
else if(kvDelim != String_t::npos)
else if(kvDelim != string_view::npos)
{
// key value pair
String_t::size_type k_start = 0;
String_t::size_type k_end = kvDelim;
String_t::size_type v_start = kvDelim + 1;
String_t::size_type v_end = realLine.size() - 1;
string_view::size_type k_start = 0;
string_view::size_type k_end = kvDelim;
string_view::size_type v_start = kvDelim + 1;
string_view::size_type v_end = realLine.size() - 1;
// clamp whitespaces
while(whitespace(realLine[k_start]) && k_start != kvDelim)
++k_start;
@ -122,8 +122,8 @@ namespace llarp
--v_end;
// sect.k = v
String_t k = realLine.substr(k_start, k_end - k_start);
String_t v = realLine.substr(v_start, 1 + (v_end - v_start));
string_view k = realLine.substr(k_start, k_end - k_start);
string_view v = realLine.substr(v_start, 1 + (v_end - v_start));
if(k.size() == 0 || v.size() == 0)
{
LogError(m_FileName, " invalid line (", lineno, "): '", line, "'");
@ -144,7 +144,7 @@ namespace llarp
void
ConfigParser::IterAll(
std::function< void(const String_t&, const Section_t&) > visit)
std::function< void(string_view, const Section_t&) > visit)
{
for(const auto& item : m_Config)
visit(item.first, item.second);

@ -12,11 +12,8 @@ namespace llarp
{
struct ConfigParser
{
using String_t = llarp::string_view;
using Section_t =
std::unordered_multimap< String_t, String_t, string_view_hash >;
using Config_impl_t =
std::unordered_map< String_t, Section_t, string_view_hash >;
using Section_t = std::unordered_multimap< std::string, std::string >;
using Config_impl_t = std::unordered_map< std::string, Section_t >;
/// clear parser
void
Clear();
@ -35,7 +32,7 @@ namespace llarp
/// iterate all sections and thier values
void
IterAll(std::function< void(const String_t&, const Section_t&) > visit);
IterAll(std::function< void(string_view, const Section_t&) > visit);
/// visit a section in config read only by name
/// return false if no section or value propagated from visitor

@ -12,7 +12,6 @@
#include <service/context.hpp>
#include <util/logging/logger.h>
#include <absl/strings/str_split.h>
#include <cxxopts.hpp>
#include <csignal>

@ -6,7 +6,6 @@
#include <util/buffer.hpp>
#include <absl/base/optimization.h>
#include <functional>
#include <cstdint>
@ -140,15 +139,17 @@ namespace llarp
}
static Crypto *
instance() ABSL_ATTRIBUTE_RETURNS_NONNULL
instance()
{
if(ABSL_PREDICT_TRUE(m_crypto))
{
#ifdef NDEBUG
return m_crypto;
#else
if(m_crypto)
return m_crypto;
}
assert(false && "Cryptomanager::instance() was undefined");
abort();
#endif
}
};

@ -20,8 +20,7 @@ namespace llarp
bool
GotIntroMessage::HandleMessage(
llarp_dht_context *ctx,
ABSL_ATTRIBUTE_UNUSED std::vector< std::unique_ptr< IMessage > >
&replies) const
std::vector< std::unique_ptr< IMessage > > & /*replies*/) const
{
auto &dht = *ctx->impl;

@ -161,7 +161,7 @@ namespace llarp
/// snode sessions we are talking to directly
SNodeSessions_t m_SNodeSessions;
std::unordered_map< huint128_t, PubKey, huint128_t::Hash > m_IPToKey;
std::unordered_map< huint128_t, PubKey > m_IPToKey;
huint128_t m_IfAddr;
huint128_t m_HigestAddr;
@ -169,8 +169,7 @@ namespace llarp
huint128_t m_NextAddr;
IPRange m_OurRange;
std::unordered_map< huint128_t, llarp_time_t, huint128_t::Hash >
m_IPActivity;
std::unordered_map< huint128_t, llarp_time_t > m_IPActivity;
llarp_tun_io m_Tun;

@ -18,8 +18,6 @@
#include <util/str.hpp>
#include <absl/strings/ascii.h>
namespace llarp
{
namespace handlers
@ -193,7 +191,7 @@ namespace llarp
{
routerStr = v;
}
absl::StripAsciiWhitespace(&routerStr);
routerStr = TrimWhitespace(routerStr);
if(!(exitRouter.FromString(routerStr)
|| HexDecode(routerStr.c_str(), exitRouter.begin(),
exitRouter.size())))

@ -215,8 +215,7 @@ namespace llarp
FlushSend();
/// maps ip to key (host byte order)
std::unordered_map< huint128_t, AlignedBuffer< 32 >, huint128_t::Hash >
m_IPToAddr;
std::unordered_map< huint128_t, AlignedBuffer< 32 > > m_IPToAddr;
/// maps key to ip (host byte order)
std::unordered_map< AlignedBuffer< 32 >, huint128_t,
AlignedBuffer< 32 >::Hash >
@ -289,8 +288,7 @@ namespace llarp
std::shared_ptr< dns::Proxy > m_Resolver;
/// maps ip address to timestamp last active
std::unordered_map< huint128_t, llarp_time_t, huint128_t::Hash >
m_IPActivity;
std::unordered_map< huint128_t, llarp_time_t > m_IPActivity;
/// our ip address (host byte order)
huint128_t m_OurIP;
/// next ip address to allocate (host byte order)

@ -54,7 +54,7 @@ namespace llarp
}
bool
HandleMessage(ABSL_ATTRIBUTE_UNUSED AbstractRouter* router) const override
HandleMessage(AbstractRouter* /*router*/) const override
{
return true;
}

@ -99,8 +99,7 @@ namespace llarp
}
bool
LinkIntroMessage::HandleMessage(
ABSL_ATTRIBUTE_UNUSED AbstractRouter* router) const
LinkIntroMessage::HandleMessage(AbstractRouter* /*router*/) const
{
if(!Verify())
return false;

@ -30,10 +30,14 @@ namespace llarp
huint128_t
IPPacket::In6ToHUInt(in6_addr addr)
{
uint32_t *ptr = in6_uint32_ptr(addr);
return huint128_t{ntohl(ptr[3])} | (huint128_t{ntohl(ptr[2])} << 32)
| (huint128_t{ntohl(ptr[1])} << 64)
| (huint128_t{ntohl(ptr[0])} << 96);
uint8_t *ptr = reinterpret_cast< uint8_t * >(addr.s6_addr);
uint128_t x{0};
for(int i = 0; i < 16; i++)
{
x <<= 8;
x |= ptr[i];
}
return huint128_t{x};
}
in6_addr

@ -1078,9 +1078,9 @@ namespace llarp
{
char buf[INET6_ADDRSTRLEN + 1] = {0};
std::string str;
in6_addr inaddr = {};
size_t numset = 0;
absl::uint128 bits = netmask_bits.h;
in6_addr inaddr = {};
size_t numset = 0;
uint128_t bits = netmask_bits.h;
while(bits)
{
if(bits & 1)

@ -1,7 +1,7 @@
#ifndef LLARP_NET_HPP
#define LLARP_NET_HPP
#include <absl/numeric/int128.h>
#include <net/uint128.hpp>
#include <net/address_info.hpp>
#include <net/net_int.hpp>
#include <net/net.h>

@ -64,16 +64,14 @@ namespace llarp
this->from_char_array(str);
}
Addr::Addr(string_view str, const uint16_t p_port) : Addr()
Addr::Addr(string_view str, const uint16_t p_port) : Addr(str)
{
this->from_char_array(str);
this->port(p_port);
}
Addr::Addr(string_view addr_str, string_view port_str) : Addr()
Addr::Addr(string_view addr_str, string_view port_str)
: Addr(addr_str, std::strtoul(port_str.data(), nullptr, 10))
{
this->from_char_array(string_view_string(addr_str).c_str());
this->port(std::strtoul(string_view_string(port_str).c_str(), nullptr, 10));
}
bool

@ -39,7 +39,7 @@ namespace llarp
std::string
huint128_t::ToString() const
{
absl::uint128 addr = ntoh128(h);
auto addr = ntoh128(h);
char tmp[INET6_ADDRSTRLEN] = {0};
if(!inet_ntop(AF_INET6, (void*)&addr, tmp, sizeof(tmp)))
return "";
@ -61,7 +61,7 @@ namespace llarp
bool
huint128_t::FromString(const std::string& str)
{
absl::uint128 i;
llarp::uint128_t i;
if(!inet_pton(AF_INET6, str.c_str(), &i))
return false;
h = ntoh128(i);
@ -90,4 +90,4 @@ namespace llarp
{
return std::to_string(ntohs(n));
}
} // namespace llarp
} // namespace llarp

@ -19,8 +19,7 @@
#include <util/endian.hpp>
#include <vector>
#include <absl/numeric/int128.h>
#include <absl/hash/hash.h>
#include "uint128.hpp"
namespace llarp
{
@ -104,15 +103,6 @@ namespace llarp
return h == x.h;
}
using Hash = absl::Hash< huint_t< UInt_t > >;
template < typename H >
friend H
AbslHashValue(H hash, const huint_t< UInt_t >& i)
{
return H::combine(std::move(hash), i.h);
}
using V6Container = std::vector< uint8_t >;
void
ToV6(V6Container& c);
@ -132,7 +122,7 @@ namespace llarp
using huint32_t = huint_t< uint32_t >;
using huint16_t = huint_t< uint16_t >;
using huint128_t = huint_t< absl::uint128 >;
using huint128_t = huint_t< llarp::uint128_t >;
template < typename UInt_t >
struct nuint_t
@ -187,15 +177,6 @@ namespace llarp
return n == x.n;
}
struct Hash
{
inline size_t
operator()(nuint_t x) const
{
return std::hash< UInt_t >{}(x.n);
}
};
using V6Container = std::vector< uint8_t >;
void
ToV6(V6Container& c);
@ -212,7 +193,7 @@ namespace llarp
using nuint32_t = nuint_t< uint32_t >;
using nuint16_t = nuint_t< uint16_t >;
using nuint128_t = nuint_t< absl::uint128 >;
using nuint128_t = nuint_t< llarp::uint128_t >;
static inline nuint32_t
xhtonl(huint32_t x)
@ -239,4 +220,27 @@ namespace llarp
}
} // namespace llarp
namespace std
{
template < typename UInt_t >
struct hash< llarp::nuint_t< UInt_t > >
{
size_t
operator()(const llarp::nuint_t< UInt_t >& x) const
{
return std::hash< UInt_t >{}(x.n);
}
};
template < typename UInt_t >
struct hash< llarp::huint_t< UInt_t > >
{
size_t
operator()(const llarp::huint_t< UInt_t >& x) const
{
return std::hash< UInt_t >{}(x.h);
}
};
} // namespace std
#endif

@ -0,0 +1,321 @@
#pragma once
#include <array>
#include <cstdint>
#include <algorithm>
#include <functional>
#include "../util/meta/traits.hpp"
#include "../util/endian.hpp"
namespace llarp
{
/// 128-bit unsigned integer. Does *not* support
/// multiplication/division/modulus.
struct uint128_t
{
// Swap order on little/big endian so that the first byte of the struct is
// always most significant on big endian and least significant on little
// endian.
#ifdef __BIG_ENDIAN__
uint64_t upper, lower;
#else
uint64_t lower, upper;
#endif
// Initializes with 0s
constexpr uint128_t() : uint128_t{0, 0}
{
}
// Initializes with least-significant value
constexpr uint128_t(uint64_t lower) : uint128_t{0, lower}
{
}
// Initializes with upper and lower values
constexpr uint128_t(uint64_t upper, uint64_t lower)
// clang-format off
#ifdef __BIG_ENDIAN__
: upper{upper}, lower{lower}
#else
: lower{lower}, upper{upper}
#endif
// clang-format on
{
}
constexpr uint128_t(const uint128_t&) = default;
constexpr uint128_t(uint128_t&&) = default;
constexpr uint128_t&
operator=(const uint128_t&) = default;
constexpr uint128_t&
operator=(uint128_t&&) = default;
// bitwise and
constexpr uint128_t&
operator&=(const uint128_t& o)
{
upper &= o.upper;
lower &= o.lower;
return *this;
}
constexpr uint128_t operator&(const uint128_t& o) const
{
uint128_t result = *this;
result &= o;
return result;
}
// bitwise or
constexpr uint128_t&
operator|=(const uint128_t& o)
{
upper |= o.upper;
lower |= o.lower;
return *this;
}
constexpr uint128_t
operator|(const uint128_t& o) const
{
uint128_t result = *this;
result |= o;
return result;
}
// bitwise xor
constexpr uint128_t&
operator^=(const uint128_t& o)
{
upper ^= o.upper;
lower ^= o.lower;
return *this;
}
constexpr uint128_t
operator^(const uint128_t& o) const
{
uint128_t result = *this;
result ^= o;
return result;
}
// bitwise not
constexpr uint128_t
operator~() const
{
return {~upper, ~lower};
}
// bool: true if any bit set
explicit constexpr operator bool() const
{
return static_cast< bool >(lower) || static_cast< bool >(upper);
}
// Casting to basic unsigned int types: casts away upper bits
explicit constexpr operator uint8_t() const
{
return static_cast< uint8_t >(lower);
}
explicit constexpr operator uint16_t() const
{
return static_cast< uint16_t >(lower);
}
explicit constexpr operator uint32_t() const
{
return static_cast< uint32_t >(lower);
}
explicit constexpr operator uint64_t() const
{
return lower;
}
constexpr bool
operator==(const uint128_t& b) const
{
return lower == b.lower && upper == b.upper;
}
constexpr bool
operator!=(const uint128_t& b) const
{
return lower != b.lower || upper != b.upper;
}
constexpr bool
operator<(const uint128_t& b) const
{
return upper < b.upper || (upper == b.upper && lower < b.lower);
}
constexpr bool
operator<=(const uint128_t& b) const
{
return upper < b.upper || (upper == b.upper && lower <= b.lower);
}
constexpr bool
operator>(const uint128_t& b) const
{
return upper > b.upper || (upper == b.upper && lower > b.lower);
}
constexpr bool
operator>=(const uint128_t& b) const
{
return upper > b.upper || (upper == b.upper && lower >= b.lower);
}
constexpr uint128_t&
operator++()
{
if(++lower == 0)
++upper;
return *this;
}
constexpr uint128_t
operator++(int)
{
auto copy = *this;
++*this;
return copy;
}
constexpr uint128_t&
operator+=(const uint128_t& b)
{
lower += b.lower;
if(lower < b.lower)
++upper;
upper += b.upper;
return *this;
}
constexpr uint128_t
operator+(const uint128_t& b) const
{
uint128_t result = *this;
result += b;
return result;
}
constexpr uint128_t&
operator-=(const uint128_t& b)
{
if(b.lower > lower)
--upper;
lower -= b.lower;
upper -= b.upper;
return *this;
}
constexpr uint128_t
operator-(const uint128_t& b) const
{
uint128_t result = *this;
result -= b;
return result;
}
constexpr uint128_t&
operator<<=(uint64_t shift)
{
if(shift == 0)
{
}
else if(shift < 64)
{
upper = upper << shift | (lower >> (64 - shift));
lower <<= shift;
}
else if(shift == 64)
{
upper = lower;
lower = 0;
}
else if(shift < 128)
{
upper = lower << (shift - 64);
lower = 0;
}
else
{
upper = lower = 0;
}
return *this;
}
constexpr uint128_t
operator<<(uint64_t shift) const
{
uint128_t result = *this;
result <<= shift;
return result;
}
constexpr uint128_t&
operator>>=(uint64_t shift)
{
if(shift == 0)
{
}
else if(shift < 64)
{
lower = lower >> shift | upper << (64 - shift);
upper >>= shift;
}
else if(shift == 64)
{
lower = upper;
upper = 0;
}
else if(shift < 128)
{
lower = upper >> (shift - 64);
upper = 0;
}
else
{
upper = lower = 0;
}
return *this;
}
constexpr uint128_t
operator>>(uint64_t shift) const
{
uint128_t result = *this;
result >>= shift;
return result;
}
};
static_assert(sizeof(uint128_t) == 16,
"uint128_t has unexpected size (padding?)");
} // namespace llarp
namespace std
{
// Hash function for uint128_t
template <>
struct hash< llarp::uint128_t >
{
size_t
operator()(const llarp::uint128_t& i) const
{
size_t h = std::hash< uint64_t >()(i.lower);
h ^= std::hash< uint64_t >()(i.upper) + 0x9e3779b9 + (h << 6) + (h >> 2);
return h;
}
};
} // namespace std
inline llarp::uint128_t
ntoh128(llarp::uint128_t i)
{
#ifdef __BIG_ENDIAN__
return i;
#else
const auto loSwapped = htobe64(i.lower);
const auto hiSwapped = htobe64(i.upper);
return {loSwapped, hiSwapped};
#endif
}

@ -625,9 +625,8 @@ namespace llarp
}
bool
Path::HandlePathTransferMessage(
ABSL_ATTRIBUTE_UNUSED const routing::PathTransferMessage& msg,
ABSL_ATTRIBUTE_UNUSED AbstractRouter* r)
Path::HandlePathTransferMessage(const routing::PathTransferMessage& /*msg*/,
AbstractRouter* /*r*/)
{
LogWarn("unwarranted path transfer message on tx=", TXID(),
" rx=", RXID());
@ -675,9 +674,8 @@ namespace llarp
}
bool
Path::HandlePathConfirmMessage(
ABSL_ATTRIBUTE_UNUSED const routing::PathConfirmMessage& msg,
AbstractRouter* r)
Path::HandlePathConfirmMessage(const routing::PathConfirmMessage& /*msg*/,
AbstractRouter* r)
{
return HandlePathConfirmMessage(r);
}
@ -725,7 +723,7 @@ namespace llarp
bool
Path::HandleCloseExitMessage(const routing::CloseExitMessage& msg,
ABSL_ATTRIBUTE_UNUSED AbstractRouter* r)
AbstractRouter* /*r*/)
{
/// allows exits to close from their end
if(SupportsAnyRoles(ePathRoleExit | ePathRoleSVC))

@ -191,8 +191,7 @@ namespace llarp
AbstractRouter* r) override;
bool
HandleHiddenServiceFrame(
ABSL_ATTRIBUTE_UNUSED const service::ProtocolFrame& frame) override
HandleHiddenServiceFrame(const service::ProtocolFrame& /*frame*/) override
{
/// TODO: implement me
LogWarn("Got hidden service data on transit hop");

@ -10,8 +10,7 @@ namespace llarp
PoW::~PoW() = default;
bool
PoW::DecodeKey(ABSL_ATTRIBUTE_UNUSED const llarp_buffer_t& k,
ABSL_ATTRIBUTE_UNUSED llarp_buffer_t* val)
PoW::DecodeKey(const llarp_buffer_t& /*k*/, llarp_buffer_t* /*val*/)
{
// TODO: implement me
return false;

@ -6,7 +6,7 @@
#include <util/bencode.hpp>
#include <util/thread/threading.hpp>
#include <absl/base/thread_annotations.h>
#include <util/thread/annotations.hpp>
#include <map>
namespace llarp
@ -57,7 +57,7 @@ namespace llarp
/// check if this router should have paths built over it
bool
IsBadForPath(const RouterID& r, uint64_t chances = 8)
LOCK_RETURNED(m_ProfilesMutex);
EXCLUDES(m_ProfilesMutex);
/// check if this router should be connected directly to
bool

@ -16,8 +16,6 @@
#include <functional>
#include <random>
using namespace std::chrono_literals;
namespace llarp
{
void

@ -805,7 +805,7 @@ namespace llarp
}
void
Router::HandleDHTLookupForExplore(ABSL_ATTRIBUTE_UNUSED RouterID remote,
Router::HandleDHTLookupForExplore(RouterID /*remote*/,
const std::vector< RouterContact > &results)
{
for(const auto &rc : results)
@ -1180,7 +1180,7 @@ namespace llarp
}
bool
Router::ValidateConfig(ABSL_ATTRIBUTE_UNUSED Config *conf) const
Router::ValidateConfig(Config * /*conf*/) const
{
return true;
}

@ -286,9 +286,7 @@ namespace llarp
struct Handler : public ::abyss::httpd::IRPCHandler
{
AbstractRouter* router;
std::unordered_map< absl::string_view, std::function< Response() >,
absl::Hash< absl::string_view > >
m_dispatch;
std::unordered_map< std::string, std::function< Response() > > m_dispatch;
Handler(::abyss::httpd::ConnImpl* conn, AbstractRouter* r)
: ::abyss::httpd::IRPCHandler(conn)
, router(r)
@ -401,8 +399,7 @@ namespace llarp
}
Response
HandleJSONRPC(Method_t method,
ABSL_ATTRIBUTE_UNUSED const Params& params) override
HandleJSONRPC(Method_t method, const Params& /*params*/) override
{
auto it = m_dispatch.find(method);
if(it != m_dispatch.end())

@ -12,15 +12,14 @@ namespace llarp
ConfigParser parser;
if(!parser.LoadFile(fname))
return false;
parser.IterAll([&](const ConfigParser::String_t& name,
const ConfigParser::Section_t& section) {
Config::section_t values;
values.first.assign(name.begin(), name.end());
for(const auto& item : section)
values.second.emplace_back(string_view_string(item.first),
string_view_string(item.second));
services.emplace_back(values);
});
parser.IterAll(
[&](string_view name, const ConfigParser::Section_t& section) {
Config::section_t values;
values.first.assign(name.begin(), name.end());
for(const auto& item : section)
values.second.emplace_back(item.first, item.second);
services.emplace_back(values);
});
return services.size() > 0;
}

@ -196,10 +196,7 @@ namespace llarp
if(!EndpointUtil::HasPathToService(addr, m_state->m_RemoteSessions))
{
if(!EnsurePathToService(
addr,
[](ABSL_ATTRIBUTE_UNUSED Address _addr,
ABSL_ATTRIBUTE_UNUSED OutboundContext* _ctx) {},
10000))
addr, [](Address, OutboundContext*) {}, 10000))
{
LogWarn("failed to ensure path to ", addr);
}
@ -966,7 +963,7 @@ namespace llarp
bool
Endpoint::EnsurePathToService(const Address remote, PathEnsureHook hook,
ABSL_ATTRIBUTE_UNUSED llarp_time_t timeoutMS)
llarp_time_t /*timeoutMS*/)
{
static constexpr size_t NumParalellLookups = 2;
LogInfo(Name(), " Ensure Path to ", remote.ToString());
@ -1120,9 +1117,8 @@ namespace llarp
}
bool
Endpoint::EnsureConvo(ABSL_ATTRIBUTE_UNUSED const AlignedBuffer< 32 > addr,
bool snode,
ABSL_ATTRIBUTE_UNUSED ConvoEventListener_ptr ev)
Endpoint::EnsureConvo(const AlignedBuffer< 32 > /*addr*/, bool snode,
ConvoEventListener_ptr /*ev*/)
{
if(snode)
{

@ -460,7 +460,7 @@ namespace llarp
bool
ProtocolFrame::HandleMessage(routing::IMessageHandler* h,
ABSL_ATTRIBUTE_UNUSED AbstractRouter* r) const
AbstractRouter* /*r*/) const
{
return h->HandleHiddenServiceFrame(*this);
}

@ -6,7 +6,7 @@
#include <numeric>
#include <type_traits>
#include <limits>
#include <absl/numeric/int128.h>
#include <net/uint128.hpp>
namespace llarp
{
@ -24,15 +24,14 @@ namespace llarp
}
constexpr std::size_t
count_bits_128(const absl::uint128& i)
count_bits_128(const uint128_t& i)
{
return count_bits(absl::Uint128High64(i))
+ count_bits(absl::Uint128Low64(i));
return count_bits(i.upper) + count_bits(i.lower);
}
template < typename InputIt >
constexpr std::size_t
__count_array_bits(InputIt begin, InputIt end)
count_array_bits_impl(InputIt begin, InputIt end)
{
return std::accumulate(begin, end, 0, [](auto acc, auto val) {
return acc + count_bits(val);
@ -43,7 +42,7 @@ namespace llarp
constexpr std::size_t
count_array_bits(const T& array)
{
return __count_array_bits(std::begin(array), std::end(array));
return count_array_bits_impl(std::begin(array), std::end(array));
}
} // namespace bits
} // namespace llarp

@ -5,7 +5,6 @@
#include <cinttypes>
#include <cstring>
#include <absl/numeric/int128.h>
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/endian.h>
@ -200,16 +199,4 @@ htole64buf(void *buf, uint64_t big64)
htobuf64(buf, htole64(big64));
}
inline absl::uint128
ntoh128(absl::uint128 i)
{
#ifdef __BIG_ENDIAN__
return i;
#else
const auto loSwapped = htobe64(absl::Uint128Low64(i));
const auto hiSwapped = htobe64(absl::Uint128High64(i));
return absl::MakeUint128(loSwapped, hiSwapped);
#endif
}
#endif

@ -0,0 +1,39 @@
#include <util/logging/logger_internal.hpp>
#include <date/date.h>
namespace llarp
{
std::ostream&
operator<<(std::ostream& out, const log_timestamp& ts)
{
std::chrono::milliseconds delta{ts.delta};
auto h = std::chrono::duration_cast< std::chrono::hours >(delta);
delta -= h;
auto m = std::chrono::duration_cast< std::chrono::minutes >(delta);
delta -= m;
auto s = std::chrono::duration_cast< std::chrono::seconds >(delta);
delta -= s;
auto ms = delta;
std::chrono::time_point< std::chrono::system_clock,
std::chrono::milliseconds >
now{std::chrono::milliseconds{ts.now}};
date::operator<<(out, now) << " UTC [+";
auto old_fill = out.fill('0');
if(h > 0h)
{
out << h.count() << 'h';
out.width(2); // 0-fill minutes if we have hours
}
if(h > 0h || m > 0min)
{
out << m.count() << 'm';
out.width(2); // 0-fill seconds if we have minutes
}
out << s.count() << '.';
out.width(3);
out << ms.count();
out.fill(old_fill);
return out << "s]";
}
} // namespace llarp

@ -3,28 +3,23 @@
#include <util/time.hpp>
#include <absl/time/clock.h>
#include <absl/time/time.h>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <util/thread/threading.hpp>
namespace llarp
{
/** internal */
template < typename TArg >
void
LogAppend(std::stringstream& ss, TArg&& arg) noexcept
/** internal, recursion terminator */
constexpr void
LogAppend(std::stringstream&) noexcept
{
ss << std::forward< TArg >(arg);
}
/** internal */
template < typename TArg, typename... TArgs >
void
LogAppend(std::stringstream& ss, TArg&& arg, TArgs&&... args) noexcept
{
LogAppend(ss, std::forward< TArg >(arg));
ss << std::forward< TArg >(arg);
LogAppend(ss, std::forward< TArgs >(args)...);
}
@ -54,18 +49,8 @@ namespace llarp
explicit log_timestamp(const char* fmt);
};
inline std::ostream&
operator<<(std::ostream& out, const log_timestamp& ts)
{
#if defined(ANDROID) || defined(RPI)
(void)ts;
return out << ts.now << " [+" << ts.delta << " ms]";
#else
absl::TimeZone tz = absl::LocalTimeZone();
return out << absl::FormatTime(ts.format, absl::FromUnixMillis(ts.now), tz)
<< " [+" << ts.delta << " ms]";
#endif
}
std::ostream&
operator<<(std::ostream& out, const log_timestamp& ts);
} // namespace llarp

@ -2,8 +2,6 @@
#include <util/mem.h>
#include <cstdlib>
#include <absl/base/attributes.h>
namespace llarp
{
void
@ -19,9 +17,7 @@ namespace llarp
} // namespace llarp
void
llarp_mem_slab(ABSL_ATTRIBUTE_UNUSED struct llarp_alloc *mem,
ABSL_ATTRIBUTE_UNUSED uint32_t *buf,
ABSL_ATTRIBUTE_UNUSED size_t sz)
llarp_mem_slab(struct llarp_alloc * /*mem*/, uint32_t * /*buf*/, size_t /*sz*/)
{
// not implemented
abort();

@ -7,6 +7,7 @@
#include <functional>
#include <iostream>
#include <cassert>
#include <algorithm>
namespace llarp
{

@ -9,18 +9,10 @@
namespace llarp
{
bool
CaselessCmp::operator()(string_view lhs, string_view rhs) const
CaselessLessThan::operator()(string_view lhs, string_view rhs) const
{
if(lhs.size() < rhs.size())
{
return true;
}
if(lhs.size() > rhs.size())
{
return false;
}
for(size_t i = 0; i < lhs.size(); ++i)
const size_t s = std::min(lhs.size(), rhs.size());
for(size_t i = 0; i < s; ++i)
{
auto l = std::tolower(lhs[i]);
auto r = std::tolower(rhs[i]);
@ -34,14 +26,15 @@ namespace llarp
return false;
}
}
return false;
return lhs.size() < rhs.size();
}
bool
IsFalseValue(string_view str)
{
static const std::set< string_view, CaselessCmp > vals{"no", "false", "0",
"off"};
static const std::set< string_view, CaselessLessThan > vals{"no", "false",
"0", "off"};
return vals.count(str) > 0;
}
@ -49,8 +42,8 @@ namespace llarp
bool
IsTrueValue(string_view str)
{
static const std::set< string_view, CaselessCmp > vals{"yes", "true", "1",
"on"};
static const std::set< string_view, CaselessLessThan > vals{"yes", "true",
"1", "on"};
return vals.count(str) > 0;
}
@ -67,4 +60,24 @@ namespace llarp
return false;
}
constexpr static char whitespace[] = " \t\n\r\f\v";
string_view
TrimWhitespace(string_view str)
{
size_t begin = str.find_first_not_of(whitespace);
if(begin == string_view::npos)
{
str.remove_prefix(str.size());
return str;
}
str.remove_prefix(begin);
size_t end = str.find_last_not_of(whitespace);
if(end != string_view::npos)
str.remove_suffix(str.size() - end - 1);
return str;
}
} // namespace llarp

@ -11,7 +11,7 @@ namespace llarp
bool
IsFalseValue(string_view str);
struct CaselessCmp
struct CaselessLessThan
{
bool
operator()(string_view lhs, string_view rhs) const;
@ -20,6 +20,14 @@ namespace llarp
bool
IsTrueValue(string_view str);
/// Trim leading and trailing (ascii) whitespace from the given string;
/// returns a string_view of the trimmed part of the string.
#ifdef __GNUG__
[[gnu::warn_unused_result]]
#endif
string_view
TrimWhitespace(string_view str);
} // namespace llarp
#endif

@ -1,17 +1,221 @@
#ifndef LLARP_STRING_VIEW_HPP
#define LLARP_STRING_VIEW_HPP
#include <absl/hash/hash.h>
#include <absl/strings/string_view.h>
namespace llarp
{
using string_view = absl::string_view;
using string_view_hash = absl::Hash< string_view >;
static std::string
string_view_string(const string_view& v)
{
return std::string(v);
}
} // namespace llarp
// Copied from loki-mq (with namespaces modified); when we fully import loki-mq
// we can just use it directly.
// To keep this identical to loki-mq's copy (e.g. to be able to diff it):
//
// clang-format off
#include <string>
#ifdef __cpp_lib_string_view
#include <string_view>
namespace llarp { using string_view = std::string_view; }
#else
#include <ostream>
#include <limits>
namespace llarp {
/// Basic implementation of std::string_view (except for std::hash support).
class simple_string_view {
const char *data_;
size_t size_;
public:
using traits_type = std::char_traits<char>;
using value_type = char;
using pointer = char*;
using const_pointer = const char*;
using reference = char&;
using const_reference = const char&;
using const_iterator = const_pointer;
using iterator = const_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = const_reverse_iterator;
using size_type = std::size_t;
using different_type = std::ptrdiff_t;
static constexpr auto& npos = std::string::npos;
constexpr simple_string_view() noexcept : data_{nullptr}, size_{0} {}
constexpr simple_string_view(const simple_string_view&) noexcept = default;
simple_string_view(const std::string& str) : data_{str.data()}, size_{str.size()} {}
constexpr simple_string_view(const char* data, size_t size) noexcept : data_{data}, size_{size} {}
simple_string_view(const char* data) : data_{data}, size_{traits_type::length(data)} {}
simple_string_view& operator=(const simple_string_view&) = default;
constexpr const char* data() const noexcept { return data_; }
constexpr size_t size() const noexcept { return size_; }
constexpr size_t length() const noexcept { return size_; }
constexpr size_t max_size() const noexcept { return std::numeric_limits<size_t>::max(); }
constexpr bool empty() const noexcept { return size_ == 0; }
operator std::string() const { return {data_, size_}; }
constexpr const char* begin() const noexcept { return data_; }
constexpr const char* cbegin() const noexcept { return data_; }
constexpr const char* end() const noexcept { return data_ + size_; }
constexpr const char* cend() const noexcept { return data_ + size_; }
reverse_iterator rbegin() const { return reverse_iterator{end()}; }
reverse_iterator crbegin() const { return reverse_iterator{end()}; }
reverse_iterator rend() const { return reverse_iterator{begin()}; }
reverse_iterator crend() const { return reverse_iterator{begin()}; }
constexpr const char& operator[](size_t pos) const { return data_[pos]; }
constexpr const char& front() const { return *data_; }
constexpr const char& back() const { return data_[size_ - 1]; }
int compare(simple_string_view s) const;
constexpr void remove_prefix(size_t n) { data_ += n; size_ -= n; }
constexpr void remove_suffix(size_t n) { size_ -= n; }
void swap(simple_string_view &s) noexcept { std::swap(data_, s.data_); std::swap(size_, s.size_); }
#if defined(__clang__) || !defined(__GNUG__) || __GNUC__ >= 6
constexpr // GCC 5.x is buggy wrt constexpr throwing
#endif
const char& at(size_t pos) const {
if (pos >= size())
throw std::out_of_range{"invalid string_view index"};
return data_[pos];
};
size_t copy(char* dest, size_t count, size_t pos = 0) const {
if (pos > size()) throw std::out_of_range{"invalid copy pos"};
size_t rcount = std::min(count, size_ - pos);
traits_type::copy(dest, data_ + pos, rcount);
return rcount;
}
#if defined(__clang__) || !defined(__GNUG__) || __GNUC__ >= 6
constexpr // GCC 5.x is buggy wrt constexpr throwing
#endif
simple_string_view substr(size_t pos = 0, size_t count = npos) const {
if (pos > size()) throw std::out_of_range{"invalid substr range"};
simple_string_view result = *this;
if (pos > 0) result.remove_prefix(pos);
if (count < result.size()) result.remove_suffix(result.size() - count);
return result;
}
size_t find(simple_string_view v, size_t pos = 0) const {
if (pos > size_ || v.size_ > size_) return npos;
for (const size_t max_pos = size_ - v.size_; pos <= max_pos; ++pos) {
if (0 == traits_type::compare(v.data_, data_ + pos, v.size_))
return pos;
}
return npos;
}
size_t find(char c, size_t pos = 0) const { return find({&c, 1}, pos); }
size_t find(const char* c, size_t pos, size_t count) const { return find({c, count}, pos); }
size_t find(const char* c, size_t pos = 0) const { return find(simple_string_view(c), pos); }
size_t rfind(simple_string_view v, size_t pos = npos) const {
if (v.size_ > size_) return npos;
const size_t max_pos = size_ - v.size_;
for (pos = std::min(pos, max_pos); pos <= max_pos; --pos) {
if (0 == traits_type::compare(v.data_, data_ + pos, v.size_))
return pos;
}
return npos;
}
size_t rfind(char c, size_t pos = npos) const { return rfind({&c, 1}, pos); }
size_t rfind(const char* c, size_t pos, size_t count) const { return rfind({c, count}, pos); }
size_t rfind(const char* c, size_t pos = npos) const { return rfind(simple_string_view(c), pos); }
constexpr size_t find_first_of(simple_string_view v, size_t pos = 0) const noexcept {
for (; pos < size_; ++pos)
for (char c : v)
if (data_[pos] == c)
return pos;
return npos;
}
constexpr size_t find_first_of(char c, size_t pos = 0) const noexcept { return find_first_of({&c, 1}, pos); }
constexpr size_t find_first_of(const char* c, size_t pos, size_t count) const { return find_first_of({c, count}, pos); }
size_t find_first_of(const char* c, size_t pos = 0) const { return find_first_of(simple_string_view(c), pos); }
constexpr size_t find_last_of(simple_string_view v, const size_t pos = npos) const noexcept {
if (size_ == 0) return npos;
const size_t last_pos = std::min(pos, size_-1);
for (size_t i = last_pos; i <= last_pos; --i)
for (char c : v)
if (data_[i] == c)
return i;
return npos;
}
constexpr size_t find_last_of(char c, size_t pos = npos) const noexcept { return find_last_of({&c, 1}, pos); }
constexpr size_t find_last_of(const char* c, size_t pos, size_t count) const { return find_last_of({c, count}, pos); }
size_t find_last_of(const char* c, size_t pos = npos) const { return find_last_of(simple_string_view(c), pos); }
constexpr size_t find_first_not_of(simple_string_view v, size_t pos = 0) const noexcept {
for (; pos < size_; ++pos) {
bool none = true;
for (char c : v) {
if (data_[pos] == c) {
none = false;
break;
}
}
if (none) return pos;
}
return npos;
}
constexpr size_t find_first_not_of(char c, size_t pos = 0) const noexcept { return find_first_not_of({&c, 1}, pos); }
constexpr size_t find_first_not_of(const char* c, size_t pos, size_t count) const { return find_first_not_of({c, count}, pos); }
size_t find_first_not_of(const char* c, size_t pos = 0) const { return find_first_not_of(simple_string_view(c), pos); }
constexpr size_t find_last_not_of(simple_string_view v, const size_t pos = npos) const noexcept {
if (size_ == 0) return npos;
const size_t last_pos = std::min(pos, size_-1);
for (size_t i = last_pos; i <= last_pos; --i) {
bool none = true;
for (char c : v) {
if (data_[i] == c) {
none = false;
break;
}
}
if (none) return i;
}
return npos;
}
constexpr size_t find_last_not_of(char c, size_t pos = npos) const noexcept { return find_last_not_of({&c, 1}, pos); }
constexpr size_t find_last_not_of(const char* c, size_t pos, size_t count) const { return find_last_not_of({c, count}, pos); }
size_t find_last_not_of(const char* c, size_t pos = npos) const { return find_last_not_of(simple_string_view(c), pos); }
};
inline bool operator==(simple_string_view lhs, simple_string_view rhs) {
return lhs.size() == rhs.size() && 0 == std::char_traits<char>::compare(lhs.data(), rhs.data(), lhs.size());
};
inline bool operator!=(simple_string_view lhs, simple_string_view rhs) {
return !(lhs == rhs);
}
inline int simple_string_view::compare(simple_string_view s) const {
int cmp = std::char_traits<char>::compare(data_, s.data(), std::min(size_, s.size()));
if (cmp) return cmp;
if (size_ < s.size()) return -1;
else if (size_ > s.size()) return 1;
return 0;
}
inline bool operator<(simple_string_view lhs, simple_string_view rhs) {
return lhs.compare(rhs) < 0;
};
inline bool operator<=(simple_string_view lhs, simple_string_view rhs) {
return lhs.compare(rhs) <= 0;
};
inline bool operator>(simple_string_view lhs, simple_string_view rhs) {
return lhs.compare(rhs) > 0;
};
inline bool operator>=(simple_string_view lhs, simple_string_view rhs) {
return lhs.compare(rhs) >= 0;
};
inline std::ostream& operator<<(std::ostream& os, const simple_string_view& s) {
os.write(s.data(), s.size());
return os;
}
using string_view = simple_string_view;
}
#endif
#endif

@ -1,10 +1,13 @@
#pragma once
#include <ciso646>
// Clang thread safety analysis macros. Does nothing under non-clang compilers.
// Enable thread safety attributes only with clang.
// The attributes can be safely erased when compiling with other compilers.
#if defined(__clang__) && (!defined(SWIG))
// Enable thread safety attributes only with clang and libc++ (the latter
// because we are using stl mutexes, which don't have the required annotations
// under stdlibc++). The attributes can be safely erased when compiling with
// other compilers.
#if defined(__clang__) && defined(_LIBCPP_VERSION) && !defined(SWIG)
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op

@ -5,7 +5,6 @@
#include <chrono>
#include <chrono>
using namespace std::chrono_literals;
namespace llarp
{

@ -1,10 +1,16 @@
#ifndef LLARP_TYPES_H
#define LLARP_TYPES_H
#include <cstdint>
#include <string>
using byte_t = uint8_t;
using llarp_proto_version_t = std::uint8_t;
using llarp_time_t = std::uint64_t;
using llarp_seconds_t = std::uint64_t;
namespace llarp
{
using namespace std::literals;
}
#endif

@ -1,8 +1,8 @@
set(TEST_EXE testAll)
set(CHECK_EXE checkAll)
set(GTEST_EXE testAll)
set(CATCH_EXE catchAll)
list(APPEND TEST_SRC
# Old gtest-based tests; new tests should use Catch2, instead.
list(APPEND GTEST_SRC
config/test_llarp_config_config.cpp
config/test_llarp_config_ini.cpp
crypto/test_llarp_crypto_types.cpp
@ -35,49 +35,52 @@ list(APPEND TEST_SRC
util/meta/test_llarp_util_traits.cpp
util/test_llarp_util_aligned.cpp
util/test_llarp_util_bencode.cpp
util/test_llarp_util_bits.cpp
util/test_llarp_util_decaying_hashset.cpp
util/test_llarp_util_encode.cpp
util/test_llarp_util_printer.cpp
util/test_llarp_utils_str.cpp
util/test_llarp_util_log_level.cpp
util/thread/test_llarp_util_queue_manager.cpp
util/thread/test_llarp_util_queue.cpp
util/thread/test_llarp_util_thread_pool.cpp
)
add_executable(${TEST_EXE}
add_executable(${GTEST_EXE}
# helpers
main.cpp
crypto/mock_crypto.cpp
dht/mock_context.cpp
test_util.cpp
# actual test cases
${TEST_SRC}
${GTEST_SRC}
)
target_link_libraries(${TEST_EXE} PUBLIC gmock gtest ${STATIC_LIB})
target_include_directories(${TEST_EXE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${GTEST_EXE} PUBLIC gmock gtest ${STATIC_LIB})
target_include_directories(${GTEST_EXE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
if(NOT WIN32)
target_link_libraries(${TEST_EXE} PUBLIC absl::variant)
else()
target_sources(${TEST_EXE} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/win32/test.rc")
target_link_libraries(${TEST_EXE} PUBLIC ws2_32 iphlpapi shlwapi)
endif(NOT WIN32)
if(WIN32)
target_sources(${GTEST_EXE} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/win32/test.rc")
target_link_libraries(${GTEST_EXE} PUBLIC ws2_32 iphlpapi shlwapi)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
target_link_directories(${TEST_EXE} PRIVATE /usr/local/lib)
target_link_directories(${GTEST_EXE} PRIVATE /usr/local/lib)
endif()
add_subdirectory(Catch2)
add_executable(${CHECK_EXE}
add_executable(${CATCH_EXE}
nodedb/test_nodedb.cpp
path/test_path.cpp
util/test_llarp_util_bits.cpp
util/test_llarp_util_printer.cpp
util/test_llarp_util_str.cpp
check_main.cpp)
target_link_libraries(${CHECK_EXE} PUBLIC ${STATIC_LIB} Catch2::Catch2)
target_include_directories(${CHECK_EXE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${CATCH_EXE} PUBLIC ${STATIC_LIB} Catch2::Catch2)
target_include_directories(${CATCH_EXE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
# Custom targets to invoke the different test suites:
add_custom_target(catch COMMAND ${CATCH_EXE})
add_custom_target(rungtest COMMAND ${GTEST_EXE})
add_custom_target(check COMMAND ${CHECK_EXE})
# Add a custom "check" target that runs all the test suites:
add_custom_target(check DEPENDS rungtest catch)

@ -38,8 +38,6 @@ level=info
#file=/path/to/logfile
# uncomment for syslog logging
#type=syslog
[metrics]
json-metrics-path=/home/lokinet/1/metrics.json
# admin api (disabled by default)
[api]
@ -84,8 +82,6 @@ eth0=5501
ifname=cluster-1
ifaddr=10.101.0.1/16
[metrics]
metric-tank-host=52.80.56.123:2003
)";
Config config;
@ -98,8 +94,6 @@ metric-tank-host=52.80.56.123:2003
UnorderedElementsAre(kv("ifname", "cluster-1"),
kv("ifaddr", "10.101.0.1/16")));
}
ASSERT_TRUE(config.metrics.disableMetricLogs);
ASSERT_TRUE(config.metrics.disableMetrics);
{
using kv = LinksConfig::Links::value_type;

@ -87,12 +87,12 @@ struct ClientHandler : public abyss::http::IRPCClientHandler
}
void
PopulateReqHeaders(ABSL_ATTRIBUTE_UNUSED abyss::http::Headers_t& hdr)
PopulateReqHeaders(abyss::http::Headers_t& /*hdr*/)
{
}
bool
HandleResponse(ABSL_ATTRIBUTE_UNUSED abyss::http::RPC_Response response)
HandleResponse(abyss::http::RPC_Response /*response*/)
{
test->AsyncStop();
return true;
@ -108,7 +108,7 @@ struct ServerHandler : public abyss::httpd::IRPCHandler
}
Response
HandleJSONRPC(Method_t method, ABSL_ATTRIBUTE_UNUSED const Params& params)
HandleJSONRPC(Method_t method, const Params& /*params*/)
{
test->AssertMethod(method);
test->called = true;

@ -1,66 +1,71 @@
#include <gtest/gtest.h>
#include <array>
#include <absl/types/variant.h>
#include <catch2/catch.hpp>
#include <util/bits.hpp>
using ArrayUC1 = std::array< unsigned char, 1 >;
using ArrayUC20 = std::array< unsigned char, 20 >;
using ArrayU1 = std::array< unsigned int, 1 >;
using ArrayULL1 = std::array< unsigned long long, 1 >;
using namespace llarp::bits;
using TestType = absl::variant< ArrayUC1, ArrayUC20, ArrayU1, ArrayULL1 >;
TEST_CASE("test bit counting, 8-bit", "[bits]") {
// Workaround for gcc 5's stdlib; we can drop this crap (and drop all the `T`'s below) once we
// stop supporting it.
using T = std::tuple<unsigned char, size_t>;
auto x = GENERATE(table<unsigned char, size_t>({
T{0b00000000, 0},
T{0b00000001, 1},
T{0b00000010, 1},
T{0b00000100, 1},
T{0b00001000, 1},
T{0b00010000, 1},
T{0b00100000, 1},
T{0b01000000, 1},
T{0b10000000, 1},
T{0b11111111, 8},
}));
std::array<unsigned char, 1> arr{{std::get<0>(x)}};
auto expected = std::get<1>(x);
REQUIRE( count_array_bits(arr) == expected );
}
struct InputData
{
TestType data;
size_t result;
};
TEST_CASE("test bit counting, 20 x 8-bit", "[bits]") {
std::array<unsigned char, 20> x{{
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000}};
REQUIRE( count_array_bits(x) == 0 );
struct TestBits : public ::testing::TestWithParam< InputData >
{
};
x = {{
0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100,
0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100,
0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100,
0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100}};
REQUIRE( count_array_bits(x) == 48 );
}
TEST_P(TestBits, bitcount)
{
auto d = GetParam();
ASSERT_EQ(d.result,
absl::visit(
[](const auto& v) { return llarp::bits::count_array_bits(v); },
d.data));
TEST_CASE("test bit counting, unsigned int", "[bits]") {
using T = std::tuple<unsigned int, size_t>; // gcc 5 workaround
auto x = GENERATE(table<unsigned int, size_t>({
T{0b00000000000000000000000000000000, 0},
T{0b00101010101010101010101010101010, 15},
T{0b10101010101010101010101010101010, 16},
T{0b01010101010101010101010101010101, 16},
T{0b11111111111111111111111111111111, 32},
}));
std::array<unsigned int, 1> arr{{std::get<0>(x)}};
auto expected = std::get<1>(x);
REQUIRE( llarp::bits::count_array_bits(arr) == expected );
}
// clang-format off
static const InputData inputData[] = {
{ArrayUC1{{0b00000000}}, 0},
{ArrayUC1{{0b00000001}}, 1},
{ArrayUC1{{0b00000010}}, 1},
{ArrayUC1{{0b00000100}}, 1},
{ArrayUC1{{0b00001000}}, 1},
{ArrayUC1{{0b00010000}}, 1},
{ArrayUC1{{0b00100000}}, 1},
{ArrayUC1{{0b01000000}}, 1},
{ArrayUC1{{0b10000000}}, 1},
{ArrayUC1{{0b11111111}}, 8},
{ArrayUC20{{0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000}}, 0},
{ArrayUC20{{0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100,
0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100,
0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100,
0b11111111, 0b00000100, 0b00000100, 0b00000100, 0b00000100}}, 48},
{ArrayU1{{0b00000000000000000000000000000000}}, 0},
{ArrayU1{{0b00101010101010101010101010101010}}, 15},
{ArrayU1{{0b10101010101010101010101010101010}}, 16},
{ArrayU1{{0b01010101010101010101010101010101}}, 16},
{ArrayU1{{0b11111111111111111111111111111111}}, 32},
{ArrayULL1{{0b0000000000000000000000000000000000000000000000000000000000000000}}, 0},
{ArrayULL1{{0b0010101010101010101010101010101000101010101010101010101010101010}}, 30},
{ArrayULL1{{0b1010101010101010101010101010101010101010101010101010101010101010}}, 32},
{ArrayULL1{{0b0101010101010101010101010101010101010101010101010101010101010101}}, 32},
{ArrayULL1{{0b1111111111111111111111111111111111111111111111111111111111111111}}, 64},
};
// clang-format on
TEST_CASE("test bit counting, unsigned long long", "[bits]") {
using T = std::tuple<unsigned long long, size_t>; // gcc 5 workaround
auto x = GENERATE(table<unsigned long long, size_t>({
T{0b0000000000000000000000000000000000000000000000000000000000000000, 0},
T{0b0010101010101010101010101010101000101010101010101010101010101010, 30},
T{0b1010101010101010101010101010101010101010101010101010101010101010, 32},
T{0b0101010101010101010101010101010101010101010101010101010101010101, 32},
T{0b1111111111111111111111111111111111111111111111111111111111111111, 64},
}));
INSTANTIATE_TEST_SUITE_P(TestBits, TestBits, ::testing::ValuesIn(inputData));
std::array<unsigned long long, 1> arr{{std::get<0>(x)}};
auto expected = std::get<1>(x);
REQUIRE( llarp::bits::count_array_bits(arr) == expected );
}

@ -1,13 +1,9 @@
#include <util/printer.hpp>
#include <absl/types/variant.h>
#include <unordered_map>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <catch2/catch.hpp>
#include <sstream>
#include <map>
using namespace llarp;
using namespace ::testing;
struct PrintableType
{
@ -19,127 +15,80 @@ struct PrintableType
}
};
using SingleVariant =
absl::variant< char, bool, short, int, unsigned int, const void *,
const char *, std::string, const int *,
std::pair< int, std::string >,
std::tuple< int, std::string, int >,
std::map< std::string, char >, PrintableType >;
using SingleType = std::pair< SingleVariant, Matcher< std::string > >;
class SingleValueTest : public ::testing::TestWithParam< SingleType >
{
};
TEST_P(SingleValueTest, value)
{
SingleType d = GetParam();
std::ostringstream stream;
template <typename T>
std::string print(const T &x) {
std::ostringstream os;
{
Printer printer(stream, -1, -1);
absl::visit([&](const auto &x) { printer.printValue(x); }, d.first);
Printer printer(os, -1, -1);
printer.printValue(x);
}
ASSERT_THAT(stream.str(), d.second);
return os.str();
}
static const char PTR_TYPE[] = "abacus";
static const int INT_VAL = 100;
// clang-format off
static const SingleType singleType[] = {
{char('a'), StrEq("[ 'a' ]")},
{bool(true), StrEq("[ true ]")},
{bool(false), StrEq("[ false ]")},
{short(123), StrEq("[ 123 ]")},
{int(INT_MAX - 1), StrEq("[ 2147483646 ]")},
{static_cast< unsigned int >(std::numeric_limits< int >::max()) + 1, StrEq("[ 2147483648 ]")},
{static_cast< const void * >(PTR_TYPE), AllOf(StartsWith("[ 0x"), EndsWith(" ]"))},
{static_cast< const char * >(PTR_TYPE), StrEq("[ \"abacus\" ]")},
{std::string("abacus"), StrEq("[ \"abacus\" ]")},
{static_cast< const int * >(&INT_VAL), AllOf(StartsWith("[ 0x"), EndsWith(" ]"))},
{std::pair< int, std::string >(100, "abacus"), StrEq("[ [ 100 \"abacus\" ] ]")},
{std::tuple< int, std::string, int >(100, "abacus", 123), StrEq("[ [ 100 \"abacus\" 123 ] ]")},
{std::map< std::string, char >{{"one", 'a'}, {"two", 'b'}, {"three", 'c'}}, StrEq("[ [ [ \"one\" \'a\' ] [ \"three\" \'c\' ] [ \"two\" 'b' ] ] ]")},
{PrintableType(), StrEq("[ PrintableType -2 -1 ]")},
TEST_CASE("printable types", "[printer]") {
REQUIRE( print(char('a')) == "[ 'a' ]" );
REQUIRE( print(bool(true)) == "[ true ]" );
REQUIRE( print(bool(false)) == "[ false ]" );
REQUIRE( print(short(123)) == "[ 123 ]" );
REQUIRE( print(int(std::numeric_limits<int>::max() - 1)) == "[ 2147483646 ]" );
REQUIRE( print(static_cast< unsigned int >(std::numeric_limits< int >::max()) + 1) == "[ 2147483648 ]" );
using Catch::Matchers::StartsWith;
using Catch::Matchers::EndsWith;
static const char PTR_TYPE[] = "abacus";
REQUIRE_THAT( print(static_cast< const void * >(PTR_TYPE)), StartsWith("[ 0x") && EndsWith(" ]") );
REQUIRE( print(static_cast< const char * >(PTR_TYPE)) == R"([ "abacus" ])" );
REQUIRE( print(std::string("abacus")) == R"([ "abacus" ])" );
static const int INT_VAL = 100;
REQUIRE_THAT( print(static_cast< const int * >(&INT_VAL)), StartsWith("[ 0x") && EndsWith(" ]") );
REQUIRE( print(std::pair< int, std::string >(100, "abacus")) == R"([ [ 100 "abacus" ] ])" );
REQUIRE( print(std::tuple< int, std::string, int >(100, "abacus", 123)) == R"([ [ 100 "abacus" 123 ] ])" );
REQUIRE( print(std::map< std::string, char >{{"one", 'a'}, {"two", 'b'}, {"three", 'c'}})
== R"([ [ [ "one" 'a' ] [ "three" 'c' ] [ "two" 'b' ] ] ])" );
REQUIRE( print(PrintableType()) == "[ PrintableType -2 -1 ]" );
};
// clang-format on
INSTANTIATE_TEST_SUITE_P(Printer, SingleValueTest,
::testing::ValuesIn(singleType));
using SingleAttributeType =
std::tuple< std::string, SingleVariant, Matcher< std::string > >;
class SingleAttributeTest
: public ::testing::TestWithParam< SingleAttributeType >
{
};
TEST_P(SingleAttributeTest, value)
{
SingleAttributeType d = GetParam();
std::ostringstream stream;
template <typename T>
std::string printAttribute(const std::string& attr, const T &x) {
std::ostringstream os;
{
Printer printer(stream, -1, -1);
absl::visit(
[&](const auto &x) { printer.printAttribute(std::get< 0 >(d), x); },
std::get< 1 >(d));
Printer printer(os, -1, -1);
printer.printAttribute(attr, x);
}
ASSERT_THAT(stream.str(), std::get< 2 >(d));
return os.str();
}
// clang-format off
static const SingleAttributeType singleAttributeType[] = {
SingleAttributeType("our_value", char('a'), StrEq("[ our_value = 'a' ]")),
SingleAttributeType("our_value", bool(true), StrEq("[ our_value = true ]")),
SingleAttributeType("our_value", bool(false), StrEq("[ our_value = false ]")),
SingleAttributeType("our_value", short(123), StrEq("[ our_value = 123 ]")),
SingleAttributeType("our_value", int(INT_MAX - 1), StrEq("[ our_value = 2147483646 ]")),
SingleAttributeType("our_value", static_cast< unsigned int >(std::numeric_limits< int >::max()) + 1, StrEq("[ our_value = 2147483648 ]")),
SingleAttributeType("our_value", static_cast< const void * >(PTR_TYPE), AllOf(StartsWith("[ our_value = 0x"), EndsWith(" ]"))),
SingleAttributeType("our_value", static_cast< const char * >(PTR_TYPE), StrEq("[ our_value = \"abacus\" ]")),
SingleAttributeType("our_value", std::string("abacus"), StrEq("[ our_value = \"abacus\" ]")),
SingleAttributeType("our_value", static_cast< const int * >(&INT_VAL), AllOf(StartsWith("[ our_value = 0x"), EndsWith(" ]"))),
SingleAttributeType("our_value", std::pair< int, std::string >(100, "abacus"), StrEq("[ our_value = [ 100 \"abacus\" ] ]")),
SingleAttributeType("our_value", std::tuple< int, std::string, int >(100, "abacus", 123), StrEq("[ our_value = [ 100 \"abacus\" 123 ] ]")),
SingleAttributeType("our_value", std::map< std::string, char >{{"one", 'a'}, {"two", 'b'}, {"three", 'c'}}, StrEq("[ our_value = [ [ \"one\" \'a\' ] [ \"three\" \'c\' ] [ \"two\" 'b' ] ] ]")),
SingleAttributeType("our_value", PrintableType(), StrEq("[ our_value = PrintableType -2 -1 ]")),
};
// clang-format on
INSTANTIATE_TEST_SUITE_P(Printer, SingleAttributeTest,
::testing::ValuesIn(singleAttributeType));
TEST_CASE("printable types, with attribute", "[printer]") {
REQUIRE( printAttribute("fee", char('a')) == "[ fee = 'a' ]" );
REQUIRE( printAttribute("fi", int(32)) == "[ fi = 32 ]" );
REQUIRE( printAttribute("fo", std::map< std::string, char >{{"one", 'a'}, {"two", 'b'}, {"three", 'c'}})
== R"([ fo = [ [ "one" 'a' ] [ "three" 'c' ] [ "two" 'b' ] ] ])" );
REQUIRE( printAttribute("fum", PrintableType()) == "[ fum = PrintableType -2 -1 ]");
}
using ManyAttributes =
std::pair< std::vector< std::pair< std::string, SingleVariant > >,
Matcher< std::string > >;
void printAnother(Printer &) {}
class ManyAttributesTest : public ::testing::TestWithParam< ManyAttributes >
{
};
template <typename T, typename... Tmore>
void printAnother(Printer &p, const std::string &attr, const T& x, const Tmore&... more) {
p.printAttribute(attr, x);
printAnother(p, more...);
}
TEST_P(ManyAttributesTest, value)
{
ManyAttributes d = GetParam();
std::ostringstream stream;
template <typename... T>
std::string printMany(const T&... x) {
std::ostringstream os;
{
Printer printer(stream, -1, -1);
std::for_each(d.first.begin(), d.first.end(), [&](const auto &y) {
std::string n = y.first;
const auto &v = y.second;
absl::visit([&](const auto &x) { printer.printAttribute(n, x); }, v);
});
Printer p(os, -1, -1);
printAnother(p, x...);
}
ASSERT_THAT(stream.str(), d.second);
return os.str();
}
// clang-format off
static const ManyAttributes manyAttributes[] = {
{{{"val", 1}, {"v2", 2}, {"v3", 3}, {"str", std::string("xxx")}}, StrEq("[ val = 1 v2 = 2 v3 = 3 str = \"xxx\" ]")},
{{{"str", std::string("xxx")}}, StrEq("[ str = \"xxx\" ]")}
};
// clang-format on
TEST_CASE("printable types, with multiple attributes", "[printer]") {
REQUIRE( printMany("val", 1, "v2", 2, "v3", 3, "str", std::string{"xxx"})
== "[ val = 1 v2 = 2 v3 = 3 str = \"xxx\" ]" );
REQUIRE( printMany("str", std::string{"xxx"}) == "[ str = \"xxx\" ]" );
}
INSTANTIATE_TEST_SUITE_P(Printer, ManyAttributesTest,
::testing::ValuesIn(manyAttributes));

@ -0,0 +1,93 @@
#include <util/str.hpp>
#include <catch2/catch.hpp>
using namespace std::literals;
TEST_CASE("TrimWhitespace -- positive tests", "[str][trim]")
{
// Test that things that should be trimmed actually get trimmed
auto fee = " J a c k"s;
auto fi = "\ra\nd"s;
auto fo = "\fthe "s;
auto fum = " \t\r\n\v\f Beanstalk\n\n\n\t\r\f\v \n\n\r\f\f\f\f\v"s;
for (auto* s: {&fee, &fi, &fo, &fum})
*s = llarp::TrimWhitespace(*s);
REQUIRE( fee == "J a c k" );
REQUIRE( fi == "a\nd" );
REQUIRE( fo == "the" );
REQUIRE( fum == "Beanstalk" );
}
TEST_CASE("TrimWhitespace -- negative tests", "[str][trim]")
{
// Test that things that shouldn't be trimmed don't get trimmed
auto c = GENERATE(range(std::numeric_limits<char>::min(), std::numeric_limits<char>::max()));
std::string plant = c + "bean"s + c;
plant = llarp::TrimWhitespace(plant);
if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v')
REQUIRE( plant == "bean" );
else
{
REQUIRE( plant.size() == 6 );
REQUIRE( plant.substr(1, 4) == "bean" );
}
}
TEST_CASE("caseless comparison tests - less than", "[str][lt]") {
using namespace llarp;
CaselessLessThan lt;
// Workaround for gcc 5's stdlib; we can drop this crap (and drop all the `T`'s below) once we
// stop supporting it.
using T = std::tuple<const char*, const char*>;
auto expect_less_than = GENERATE(table<const char*, const char*>({
T{"", "1"},
T{"1", "11"},
T{"abc", "abcd"},
T{"ABC", "abcd"},
T{"abc", "ABCD"},
T{"abc", "Abcd"},
T{"abc", "abcD"},
T{"abc", "abCd"},
T{"abc", "zz"},
T{"abc", "zzzz"},
T{"abc", "abd"},
T{"abc", "aBd"},
T{"abc", "abD"},
T{"ABC", "abd"},
T{"abC", "abd"},
}));
REQUIRE( lt(std::get<0>(expect_less_than), std::get<1>(expect_less_than)) );
REQUIRE( !lt(std::get<1>(expect_less_than), std::get<0>(expect_less_than)) );
}
TEST_CASE("caseless comparison tests - equality", "[str][eq]") {
using namespace llarp;
CaselessLessThan lt;
using T = std::tuple<const char*, const char*>; // gcc 5 workaround
auto expect_equal = GENERATE(table<const char*, const char*>({
T{"1", "1"},
T{"a", "A"},
T{"abc", "ABC"},
T{"abc", "aBc"},
T{"ABC", "abc"},
}));
REQUIRE( !lt(std::get<0>(expect_equal), std::get<1>(expect_equal)) );
REQUIRE( !lt(std::get<1>(expect_equal), std::get<0>(expect_equal)) );
}
TEST_CASE("truthy string values", "[str][truthy]") {
auto val = GENERATE("true", "TruE", "yes", "yeS", "yES", "yes", "YES", "1", "on", "oN", "ON");
REQUIRE( llarp::IsTrueValue(val) );
}
TEST_CASE("falsey string values", "[str][falsey]") {
auto val = GENERATE("false", "FalSe", "no", "NO", "No", "nO", "0", "off", "OFF");
REQUIRE( llarp::IsFalseValue(val) );
}
TEST_CASE("neither true nor false string values", "[str][nottruefalse]") {
auto val = GENERATE("false y", "maybe", "not on", "2", "yesno", "YESNO", "-1", "default", "OMG");
REQUIRE( !llarp::IsTrueValue(val) );
REQUIRE( !llarp::IsFalseValue(val) );
}

@ -1,68 +0,0 @@
#include <util/str.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace llarp;
using namespace ::testing;
struct CmpTestData
{
bool lt;
std::string lhs;
std::string rhs;
};
class CaselessCmpTest : public ::testing::TestWithParam< CmpTestData >
{
};
TEST_P(CaselessCmpTest, test)
{
CaselessCmp cmp;
auto d = GetParam();
ASSERT_EQ(d.lt, cmp(d.lhs, d.rhs));
}
std::vector< CmpTestData > CMPTESTDATA{
{true, "", "1"}, {false, "1", ""}, {true, "abc", "abcd"},
{true, "abc", "abd"}, {false, "11", "1"}, {false, "a", "A"},
{false, "abc", "aBc"}, {false, "ABC", "abc"}};
INSTANTIATE_TEST_SUITE_P(TestStr, CaselessCmpTest, ValuesIn(CMPTESTDATA));
using TestData = std::pair< bool, std::string >;
class TestIsFalseValue : public ::testing::TestWithParam< TestData >
{
};
TEST_P(TestIsFalseValue, test)
{
ASSERT_EQ(GetParam().first, IsFalseValue(GetParam().second));
}
std::vector< TestData > FALSE_DATA{
{true, "false"}, {true, "FaLsE"}, {true, "no"}, {true, "nO"},
{true, "No"}, {true, "NO"}, {true, "NO"}, {true, "0"},
{true, "off"}, {true, "oFF"}, {false, "false y"}, {false, "true"},
{false, "tRue"}, {false, "on"}};
INSTANTIATE_TEST_SUITE_P(TestStr, TestIsFalseValue, ValuesIn(FALSE_DATA));
class TestIsTrueValue : public ::testing::TestWithParam< TestData >
{
};
TEST_P(TestIsTrueValue, test)
{
ASSERT_EQ(GetParam().first, IsTrueValue(GetParam().second));
}
std::vector< TestData > TRUE_DATA{
{true, "true"}, {true, "TruE"}, {true, "yes"}, {true, "yeS"},
{true, "yES"}, {true, "YES"}, {true, "1"}, {false, "0"},
{true, "on"}, {true, "oN"}, {false, "false y"}, {false, "truth"},
{false, "false"}, {false, "off"}};
INSTANTIATE_TEST_SUITE_P(TestStr, TestIsTrueValue, ValuesIn(TRUE_DATA));

@ -1,85 +0,0 @@
environment:
matrix:
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
generator: "Visual Studio 14 2015"
compiler: msvc
configuration: Release
- platform: x64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
generator: "Visual Studio 14 2015 Win64"
compiler: msvc
configuration: Release
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
generator: "Visual Studio 15 2017"
compiler: msvc
configuration: Release
- platform: x64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
generator: "Visual Studio 15 2017 Win64"
compiler: msvc
configuration: Release
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
generator: "Visual Studio 16 2019"
compiler: msvc19
configuration: Release
arch: Win32
- platform: x64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
generator: "Visual Studio 16 2019"
compiler: msvc19
configuration: Release
arch: x64
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
generator: "MinGW Makefiles"
compiler: mingw
TOOLCHAIN_PATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32\bin
CC: C:/mingw-w64/i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32/bin/gcc.exe
CXX: C:/mingw-w64/i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32/bin/g++.exe
configuration: Release
- platform: x64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
generator: "MinGW Makefiles"
compiler: mingw
TOOLCHAIN_PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin
CC: C:/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/gcc.exe
CXX: C:/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/g++.exe
configuration: Release
matrix:
fast_finish: false
init:
- cmd: cmake --version
- cmd: msbuild /version
install:
- cmd: reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
- cmd: ren "C:\Program Files\Git\usr\bin\sh.exe" _sh.exe
build_script:
- mkdir build
- cd build
- if [%compiler%]==[msvc] cmake -G"%generator%" ..
- if [%compiler%]==[msvc19] cmake -G"%generator%" -A "%arch%" ..
- if [%compiler%]==[mingw] set PATH=%TOOLCHAIN_PATH%;%PATH%
- if [%compiler%]==[mingw] cmake -G"%generator%" -DCMAKE_C_COMPILER=%CC% -DCMAKE_CXX_COMPILER=%CXX% -DCMAKE_SH=CMAKE_SH-NOTFOUND -DCMAKE_BUILD_TYPE=%configuration% ..
- cmake --build . --config %configuration%
test_script:
- cd %APPVEYOR_BUILD_FOLDER%\build
- set CTEST_OUTPUT_ON_FAILURE=1
- ctest -C %configuration%
- if exist "test\Release\std_filesystem_test.exe" test\Release\std_filesystem_test.exe & exit 0
- cd ..

@ -1,25 +0,0 @@
---
Language: Cpp
BasedOnStyle: Chromium
AccessModifierOffset: '-4'
IndentWidth: '4'
ColumnLimit: 256
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakConstructorInitializers: BeforeComma
ConstructorInitializerAllOnOneLineOrOnePerLine: false
IndentPPDirectives: None
...

@ -1,17 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Detailed steps to reproduce the behavior.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Additional context**
Add any other context about the problem here.

@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

@ -1,2 +0,0 @@
/build*/
.vscode/

@ -1,104 +0,0 @@
language: cpp
dist: xenial # default distribution
os: linux # default os
sudo: false
matrix:
fast_finish: true
include:
- env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-5"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-6 && CXX=g++-6 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-6"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-7"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && GENERATOR='Unix Makefiles' && CONFIG=Debug && GHC_COVERAGE=1"
addons: { apt: { packages: ["g++-7", "lcov"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-8 && CXX=g++-8 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-8"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=gcc-9 && CXX=g++-9 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["g++-9"], sources: ["ubuntu-toolchain-r-test"] } }
- env: MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-5.0"] } }
- env: MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-6.0"] } }
- env: MATRIX_EVAL="CC=clang-7 && CXX=clang++-7 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-7", "libc++-7-dev", "libc++abi-7-dev"], sources: ["llvm-toolchain-xenial-7"] } }
- env: MATRIX_EVAL="CC=clang-8 && CXX=clang++-8 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-8", "libc++-8-dev", "libc++abi-8-dev"], sources: ["llvm-toolchain-xenial-8"] } }
- env: MATRIX_EVAL="CC=clang-9 && CXX=clang++-9 && GENERATOR='Unix Makefiles' && CONFIG=Release"
addons: { apt: { packages: ["clang-9", "libc++-9-dev", "libc++abi-9-dev"], sources: [{sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main', key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'}] } }
- os: osx
env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode && CONFIG=Release"
osx_image: xcode9.2
- os: osx
env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode && CONFIG=Release"
osx_image: xcode10.1
- os: osx
env: MATRIX_EVAL="CC=clang && CXX=clang++ && GENERATOR=Xcode && CONFIG=Release"
osx_image: xcode11.2
install:
- eval "${MATRIX_EVAL}"
- |
if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
brew update
fi
- |
if [ "${GHC_COVERAGE}" = "1" ]; then
gem install coveralls-lcov
fi
- $CC --version
- $CXX --version
- cmake --version
before_script:
- eval "${MATRIX_EVAL}"
- mkdir build
- cd build
- export VERBOSE=1
- |
if [ "${CONFIG}" = "Debug" ]; then
cmake -G"${GENERATOR}" -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_C_COMPILER=${CC} -DCMAKE_BUILD_TYPE=${CONFIG} -DGHC_COVERAGE=ON ..
else
cmake -G"${GENERATOR}" -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_C_COMPILER=${CC} -DCMAKE_BUILD_TYPE=${CONFIG} ..
fi
script:
- export VERBOSE=1
- cmake --build . --config ${CONFIG} --target filesystem_test
- |
if [ "${GHC_COVERAGE}" = "1" ]; then
cmake --build . --config ${CONFIG} --target filesystem_test
test/filesystem_test
else
cmake --build . --config ${CONFIG}
ctest -C ${CONFIG} -E Windows
if [ -f "test/std_filesystem_test" ]; then
test/std_filesystem_test || true
fi
fi
after_success:
- |
if [ "${GHC_COVERAGE}" = "1" ]; then
lcov --compat-libtool --directory . --capture --output-file coverage_output.info
lcov --remove coverage_output.info '/usr/*' '*/c++/*' '*.h' '*/catch.hpp' -o coverage.info
sed -i 's|SF:/.*/filesystem/|SF:../|g' coverage.info
coveralls-lcov coverage.info
fi

@ -1,56 +0,0 @@
cmake_minimum_required(VERSION 3.7.2)
project(ghcfilesystem)
include(CMakeDependentOption)
cmake_dependent_option(GHC_FILESYSTEM_BUILD_TESTING
"Enable tests" ON
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
cmake_dependent_option(GHC_FILESYSTEM_BUILD_EXAMPLES
"Build examples" ON
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
cmake_dependent_option(GHC_FILESYSTEM_WITH_INSTALL
"With install target" ON
"CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF)
if(NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()
if(CMAKE_CXX_STANDARD LESS 11)
message(FATAL_ERROR "CMAKE_CXX_STANDARD is less than 11, ghc::filesystem only works with C++11 and above.")
endif()
add_library(ghc_filesystem INTERFACE)
target_include_directories(ghc_filesystem INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_compile_options(ghc_filesystem INTERFACE "$<$<C_COMPILER_ID:MSVC>:/utf-8>")
target_compile_options(ghc_filesystem INTERFACE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
get_directory_property(hasParent PARENT_DIRECTORY)
if(NOT hasParent)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
include(GhcHelper)
if(GHC_FILESYSTEM_BUILD_TESTING)
enable_testing()
add_subdirectory(test)
endif()
if(GHC_FILESYSTEM_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
endif()
if(GHC_FILESYSTEM_WITH_INSTALL)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS ghc_filesystem EXPORT ghcFilesystemConfig)
install(EXPORT ghcFilesystemConfig NAMESPACE ghcFilesystem:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ghcFilesystem)
endif()

@ -1,27 +0,0 @@
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. 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.
3. Neither the name of the copyright holder 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 HOLDER 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.

@ -1,710 +0,0 @@
![Supported Platforms](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-blue.svg)
[![Build Status](https://travis-ci.org/gulrak/filesystem.svg?branch=master)](https://travis-ci.org/gulrak/filesystem)
[![Build status](https://ci.appveyor.com/api/projects/status/t07wp3k2cddo0hpo/branch/master?svg=true)](https://ci.appveyor.com/project/gulrak/filesystem)
[![Coverage Status](https://coveralls.io/repos/github/gulrak/filesystem/badge.svg?branch=master)](https://coveralls.io/github/gulrak/filesystem?branch=master)
[![Latest Release Tag](https://img.shields.io/github/tag/gulrak/filesystem.svg)](https://github.com/gulrak/filesystem/tree/v1.2.10)
# Filesystem
This is a header-only single-file std::filesystem compatible helper library,
based on the C++17 specs, but implemented for C++11, C++14 or C++17 (tightly following
the C++17 with very few documented exceptions). It is currently tested on
macOS 10.12/10.14, Windows 10, and Ubuntu 18.04 but should work on other versions too, as long as you have a
C++11 compatible compiler. It is of course in its own namespace `ghc::filesystem`
to not interfere with a regular `std::filesystem` should you use it in a mixed C++17
environment.
*It could still use some polishing, test coverage is above 90%, I didn't benchmark
much yet, but I'll try to optimize some parts and refactor others, so I'm striving
to improve it as long as it doesn't introduce additional C++17 compatibility
issues. Feedback is always welcome. Simply open an issue if you see something missing
or wrong or not behaving as expected and I'll comment.*
## Motivation
I'm often in need of filesystem functionality, mostly `fs::path`, but directory
access too, and when beginning to use C++11, I used that language update
to try to reduce my third-party dependencies. I could drop most of what
I used, but still missed some stuff that I started implementing for the
fun of it. Originally I based these helpers on my own coding- and naming
conventions. When C++17 was finalized, I wanted to use that interface,
but it took a while, to push myself to convert my classes.
The implementation is closely based on chapter 30.10 from the C++17 standard
and a draft close to that version is
[Working Draft N4687](https://github.com/cplusplus/draft/raw/master/papers/n4687.pdf).
It is from after the standardization of C++17 but it contains the latest filesystem
interface changes compared to the
[Working Draft N4659](https://github.com/cplusplus/draft/raw/master/papers/n4659.pdf).
I want to thank the people working on improving C++, I really liked how the language
evolved with C++11 and the following standards. Keep on the good work!
Oh, and if you ask yourself, what `ghc` is standing for, it is simply
`gulraks helper classes`, yeah, I know, not very imaginative, but I wanted a
short namespace and I use it in some of my private classes (so it has nothing
to do with Haskell).
## Platforms
`ghc::filesystem` is developed on macOS but tested on Windows and Linux.
It should work on any of these with a C++11-capable compiler. I currently
don't have a BSD derivate besides macOS, so the preprocessor checks will
cry out if you try to use it there, but if there is demand, I can try to
help. Also there are some checks to hopefully better work on Android, but
as I currently don't test with the Android NDK, I wouldn't call it a
supported platform yet. All in all, I don't see it replacing `std::filesystem`
where full C++17 is available, it doesn't try to be a "better"
`std::filesystem`, just a drop-in if you can't use it (with the exception
of the UTF-8 preference on Windows).
Unit tests are currently run with:
* macOS 10.12: Xcode 9.2 (clang-900.0.39.2), GCC 9.2, Clang 9.0, macOS 10.13: Xcode 10.1, macOS 10.14: Xcode 11.2
* Windows: Visual Studio 2017, Visual Studio 2015, Visual Studio 2019, MinGW GCC 6.3 (Win32), GCC 7.2 (Win64)
* Linux (Ubuntu): GCC (5.5, 6.5, 7.4, 8.3, 9.2), Clang (5.0, 6.0, 7.1, 8.0, 9.0)
## Tests
The header comes with a set of unit-tests and uses [CMake](https://cmake.org/)
as a build tool and [Catch2](https://github.com/catchorg/Catch2) as test framework.
All tests agains this implementation should succeed, depending on your environment
it might be that there are some warnings, e.g. if you have no rights to create
Symlinks on Windows or at least the test thinks so, but these are just informative.
To build the tests from inside the project directory under macOS or Linux just:
```cpp
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
```
This generates `filesystem_test`, the binary that runs all tests.
If the default compiler is a GCC 8 or newer, or Clang 7 or newer, it
additionally tries to build a version of the test binary compiled against GCCs/Clangs
`std::filesystem` implementation, named `std_filesystem_test`
as an additional test of conformance. Ideally all tests should compile and
succeed with all filesystem implementations, but in reality, there are
some differences in behavior, sometimes due to room for interpretation in
in the standard, and there might be issues in these implementations too.
## Usage
### Downloads
The latest release version is [v1.2.10](https://github.com/gulrak/filesystem/tree/v1.2.10) and
source archives can be found [here](https://github.com/gulrak/filesystem/releases/tag/v1.2.10).
### Using it as Single-File-Header
As `ghc::filesystem` is at first a header-only library, it should be enough to copy the header
or the `include/ghc` directory into your project folder oder point your include path to this place and
simply include the `filesystem.hpp` header (or `ghc/filesystem.hpp` if you use the subdirectory).
Everything is in the namespace `ghc::filesystem`, so one way to use it only as
a fallback could be:
```cpp
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
```
**Note that this code uses a two-stage preprocessor condition because Visual Studio 2015
doesn't like the `(<...>)` syntax, even if it could cut evaluation early before.**
**Note also, that on MSVC this detection only works starting from version 15.7 on and when setting
the `/Zc:__cplusplus` compile switch, as the compiler allways reports `199711L`
without that switch ([see](https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/)).**
If you want to also use the `fstream` wrapper with `path` support as fallback,
you might use:
```cpp
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
```
Now you have e.g. `fs::ofstream out(somePath);` and it is either the wrapper or
the C++17 `std::ofstream`.
**Be aware, as a header-only library, it is not hiding the fact, that it
uses system includes, so they "pollute" your global namespace.**
:information_source: **Hint:** There is an additional header named `ghc/fs_std.hpp` that implements this
dynamic selection of a filesystem implementation, that you can include
instead of `ghc/filesystem.hpp` when you want std::filesystem where
available and ghc::filesystem where not. It also enables the `wchar_t`
support on `ghc::filesystem` on Windows, so the resulting implementation
in the `fs` namespace will be compatible.
### Using it as Forwarding-/Implementation-Header
Alternatively, starting from v1.1.0 `ghc::filesystem` can also be used by
including one of two additional wrapper headers. These allow to include
a forwarded version in most places (`ghc/fs_fwd.hpp`) while hiding the
implementation details in a single cpp that includes `ghc/fs_impl.hpp` to
implement the needed code. That way system includes are only visible from
inside the cpp, all other places are clean.
Be aware, that it is currently not supported to hide the implementation
into a Windows-DLL, as a DLL interface with C++ standard templates in interfaces
is a different beast. If someone is willing to give it a try, I might integrate
a PR but currently working on that myself is not a priority.
If you use the forwarding/implementation approach, you can still use the dynamic
switching like this:
```cpp
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/fs-fwd.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
```
and in the implementation hiding cpp, you might use (before any include that includes `ghc/fs_fwd.hpp`
to take precedence:
```cpp
#if !(defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>))
#include <ghc/fs_impl.hpp>
#endif
#endif
```
:information_source: **Hint:** There are additional helper headers, named `ghc/fs_std_fwd.hpp` and
`ghc/fs_std_impl.hpp` that use this technique, so you can simply include them
if you want to dynamically select the filesystem implementation. they also
enable the `wchar_t` support on `ghc::filesystem` on Windows, so the resulting
implementation in the `fs` namespace will be compatible.
### Git Submodule and CMake
Starting from v1.1.0, it is possible to add `ghc::filesystem`
as a git submodule, add the directory to your `CMakeLists.txt` with
`add_subdirectory()` and then simply use `target_link_libraries(your-target ghc_filesystem)`
to ensure correct include path that allow `#include <ghc/filesystem.hpp>`
to work.
The `CMakeLists.txt` offers a few options to customize its behaviour:
* `GHC_FILESYSTEM_BUILD_TESTING` - Compile tests, default is `OFF` when used as
a submodule, else `ON`.
* `GHC_FILESYSTEM_BUILD_EXAMPLES` - Compile the examples, default is `OFF` when used as
a submodule, else `ON`.
* `GHC_FILESYSTEM_WITH_INSTALL` - Add install target to build, default is `OFF` when used as
a submodule, else `ON`.
### Versioning
There is a version macro `GHC_FILESYSTEM_VERSION` defined in case future changes
might make it needed to react on the version, but I don't plan to break anything.
It's the version as decimal number `(major * 10000 + minor * 100 + patch)`.
**Note:** Starting from v1.0.2 only even patch versions will be used for releases
and odd patch version will only be used for in between commits while working on
the next version.
## Documentation
There is almost no documentation in this release, as any `std::filesystem`
documentation would work, besides the few differences explained in the next
section. So you might head over to https://en.cppreference.com/w/cpp/filesystem
for a description of the components of this library.
The only additions to the standard are documented here:
### `ghc::filesystem::ifstream`, `ghc::filesystem::ofstream`, `ghc::filesystem::fstream`
These are simple wrappers around `std::ifstream`, `std::ofstream` and `std::fstream`.
They simply add an `open()` method and a constuctor with an `ghc::filesystem::path`
argument as the `fstream` variants in C++17 have them.
### `ghc::filesystem::u8arguments`
This is a helper class that currently checks for UTF-8 encoding on non-Windows platforms but on Windows it
fetches the command line arguments als Unicode strings from the OS with
```cpp
::CommandLineToArgvW(::GetCommandLineW(), &argc)
```
and then converts them to UTF-8, and replaces `argc` and `argv`. It is a guard-like
class that reverts its changes when going out of scope.
So basic usage is:
```cpp
namespace fs = ghc::filesystem;
int main(int argc, char* argv[])
{
fs::u8arguments u8guard(argc, argv);
if(!u8guard.valid()) {
std::cerr << "Bad encoding, needs UTF-8." << std::endl;
exit(EXIT_FAILURE);
}
// now use argc/argv as usual, they have utf-8 enconding on windows
// ...
return 0;
}
```
That way `argv` is UTF-8 encoded as long as the scope from `main` is valid.
**Note:** On macOS, while debugging under Xcode the code currently will return
`false` as Xcode starts the application with `US-ASCII` as encoding, no matter what
encoding is actually used and even setting `LC_ALL` in the product scheme doesn't
change anything. I still need to investigate this.
## Differences
As this implementation is based on existing code from my private helper
classes, it derived some constraints of it, leading to some differences
between this and the standard C++17 API.
### LWG Defects
This implementation has switchable behavior for the LWG defects
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
[#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935) and
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937).
The currently selected behavior is following
[#2682](https://wg21.cmeerw.net/lwg/issue2682),
[#2937](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2937) but
not following [#2935](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2935),
as I feel it is a bug to report no error on a `create_directory()` or `create_directories()`
where a regular file of the same name prohibits the creation of a directory and forces
the user of those functions to double-check via `fs::is_directory` if it really worked.
The more intuitive approach to directory creation of treating a file with that name as an
error is also advocated by the newer paper
[WG21 P1164R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1164r0.pdf), the revison
P1161R1 was agreed upon on Kona 2019 meeting [see merge](https://github.com/cplusplus/draft/issues/2703)
and GCC by now switched to following its proposal
([GCC #86910](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86910)).
### Not Implemented on C++ before C++17
```cpp
// methods in ghc::filesystem::path:
path& operator+=(basic_string_view<value_type> x);
int compare(basic_string_view<value_type> s) const;
```
These are not implemented under C++11 and C++14, as there is no
`std::basic_string_view` available and I did want to keep this
implementation self-contained and not write a full C++17-upgrade for
C++11/14. Starting with v1.1.0 these are supported when compiling
ghc::filesystem under C++17.
### Differences in API
```cpp
filesystem::path::string_type
filesystem::path::value_type
```
In Windows, an implementation should use `std::wstring` and `wchar_t` as types used
for the native representation, but as I'm a big fan of the
["UTF-8 Everywhere" philosophy](https://utf8everywhere.org/), I decided
agains it for now. If you need to call some Windows API, use the W-variant
with the `path::wstring()` member
(e.g. `GetFileAttributesW(p.wstring().c_str())`). This gives you the
Unicode variant independant of the `UNICODE` macro and makes sharing code
between Windows, Linux and macOS easier.
Starting with v1.2.0 `ghc::filesystem` has the option to select the more
standard conforming APi with `wchar_t` and `std::wstring` on Windows by
defining `GHC_WIN_WSTRING_STRING_TYPE`. This define has no effect on other
platforms and will be set by the helping headers `ghc/fs_std.hpp` and
the pair `ghc/fs_std_fwd.hpp`/`ghc/fs_std_impl.hpp` to enhance compatibility.
```cpp
const path::string_type& path::native() const /*noexcept*/;
const path::value_type *path::c_str() const /*noexcept*/;
```
These two can not be `noexcept` with the current implementation. This due
to the fact, that internally path is working on the generic path version
only, and the getters need to do a conversion to native path format.
```cpp
const path::string_type& path::generic_string() const;
```
This returns a const reference, instead of a value, because it can. This
implementation uses the generic representation for internal workings, so
it's "free" to return that.
### Differences in Behavior
#### fs.path ([ref](https://en.cppreference.com/w/cpp/filesystem/path))
As the complete inner mechanics of this implementation `fs::path` are working
on the generic format, it is the internal representation. So creating any mixed
slash `fs::path` object under Windows (e.g. with `"C:\foo/bar"`) will lead to a
unified path with `"C:\foo\bar"` via `native()` and `"C:/foo/bar"` via
`generic_string()` API.
Additionally this implementation follows the standards suggestion to handle
posix paths of the form `"//host/path"` and USC path on windows also as having
a root-name (e.g. `"//host"`). The GCC implementation didn't choose to do that
while testing on Ubuntu 18.04 and macOS with GCC 8.1.0 or Clang 7.0.0. This difference
will show as warnings under std::filesystem. This leads to a change in the
algorithm described in the standard for `operator/=(path& p)` where any path
`p` with `p.is_absolute()` will degrade to an assignment, while this implementation
has the exception where `*this == *this.root_name()` and `p == preferred_seperator`
a normal append will be done, to allow:
```cpp
fs::path p1 = "//host/foo/bar/file.txt";
fs::path p2;
for (auto p : p1) p2 /= p;
ASSERT(p1 == p2);
```
For all non-host-leading paths the behaviour will match the one described by
the standard.
#### fs.op.copy ([ref](https://en.cppreference.com/w/cpp/filesystem/copy))
Then there is `fs::copy`. The tests in the suite fail partially with C++17 `std::filesystem`
on GCC/Clang. They complain about a copy call with `fs::copy_options::recursive` combined
with `fs::copy_options::create_symlinks` or `fs::copy_options::create_hard_links` if the
source is a directory. There is nothing in the standard that forbids this combination
and it is the only way to deep-copy a tree while only create links for the files.
There is [LWG #2682](https://wg21.cmeerw.net/lwg/issue2682) that supports this
interpretation, but the issue ignores the usefulness of the combination with recursive
and part of the justification for the proposed solution is "we did it so for almost two years".
But this makes `fs::copy` with `fs::copy_options::create_symlinks` or `fs::copy_options::create_hard_links`
just a more complicated syntax for the `fs::create_symlink` or `fs::create_hardlink` operation
and I don't want to believe, that this was the intention of the original writing.
As there is another issue related to copy, with a different take on the description.
**Note:** With v1.1.2 I decided to integrate a behavior switch for this and make the LWG #2682
the default.
## Open Issues
### General Known Issues
There are still some methods that break the `noexcept` clause, some
are related to LWG defects, some are due to my implementation. I
work on fixing the later ones, and might in cases where there is no
way of implementing the feature without risk of an exception, break
conformance and remove the `noexcept`.
### Windows
#### Symbolic Links on Windows
As symbolic links on Windows, while being supported more or less since
Windows Vista (with some strict security constraints) and fully since some earlier
build of Windows 10, when "Developer Mode" is activated, are at time of writing
(2018) rarely used, still they are supported with this implementation.
#### Permissions
The Windows ACL permission feature translates badly to the POSIX permission
bit mask used in the interface of C++17 filesystem. The permissions returned
in the `file_status` are therefore currently synthesized for the `user`-level
and copied to the `group`- and `other`-level. There is still some potential
for more interaction with the Windows permission system, but currently setting
or reading permissions with this implementation will most certainly not lead
to the expected behavior.
## Release Notes
### [v1.2.10](https://github.com/gulrak/filesystem/releases/tag/v1.2.10)
* The Visual Studio 2019 compiler, GCC 9.2 and Clang 9.0 where added to the
CI configuration.
* Bugfix for [#39](https://github.com/gulrak/filesystem/issues/39), `fs::rename`
on Windows didn't replace an axisting regular file as required by the standard,
but gave an error. New tests and a fix as provided in the issue was implemented.
* Bugfix for [#39](https://github.com/gulrak/filesystem/issues/39), for the
forwarding use via `fs_fwd.hpp` or `fs_std_fwd.hpp` der was a use of
`DWORD` in the forwarding part leading to an error if `Windows.h` was not
included before the header. The tests were changed to give an error in that
case too and the useage of `DWORD` was removed.
* Bugfix for [#38](https://github.com/gulrak/filesystem/issues/38), casting the
return value of `GetProcAddress` gave a warning with `-Wcast-function-type`
on MSYS2 and MinGW GCC 9 builds.
### [v1.2.8](https://github.com/gulrak/filesystem/releases/tag/v1.2.8)
* Pull request [#30](https://github.com/gulrak/filesystem/pull/30), the
`CMakeLists.txt` will automatically exclude building examples and tests when
used as submodule, the configuration options now use a prefixed name to
reduce risk of conflicts.
* Pull request [#24](https://github.com/gulrak/filesystem/pull/24), install
target now creates a `ghcFilesystemConfig.cmake` in
`${CMAKE_INSTALL_LIBDIR}/cmake/ghcFilesystem` for `find_package` that
exports a target as `ghcFilesystem::ghc_filesystem`.
* Pull request [#31](https://github.com/gulrak/filesystem/pull/31), fixes
`error: redundant redeclaration of 'constexpr' static data member` deprecation
warning in C++17 mode.
* Pull request [#32](https://github.com/gulrak/filesystem/pull/32), fixes
old-style-cast warnings.
* Pull request [#34](https://github.com/gulrak/filesystem/pull/34), fixes
[TOCTOU](https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use) situation
on `fs::create_directories`, thanks for the PR!
* Feature [#35](https://github.com/gulrak/filesystem/issues/35), new CMake
option to add an install target `GHC_FILESYSTEM_WITH_INSTALL` that is
defaulted to OFF if `ghc::filesystem` is used via `add_subdirectory`.
* Bugfix for [#33](https://github.com/gulrak/filesystem/issues/33), fixes
an issue with `fs::path::lexically_normal()` that leaves a trailing separator
in case of a resulting path ending with `..` as last element.
* Bugfix for [#36](https://github.com/gulrak/filesystem/issues/36), warings
on Xcode 11.2 due to unhelpfull references in path element iteration.
### [v1.2.6](https://github.com/gulrak/filesystem/releases/tag/v1.2.6)
* Pull request [#23](https://github.com/gulrak/filesystem/pull/23), tests and
examples can now be disabled in CMake via seting `BUILD_TESTING` and
`BUILD_EXAMPLES` to `NO`, `OFF` or `FALSE`.
* Pull request [#25](https://github.com/gulrak/filesystem/pull/25),
missing specialization for construction from `std::string_view` when
available was added.
* Additional test case when `std::string_view` is available.
* Bugfix for [#27](https://github.com/gulrak/filesystem/issues/27), the
`fs::path::preferred_seperator` declaration was not compiling on pre
C++17 compilers and no test accessed it, to show the problem. Fixed
it to an construction C++11 compiler should accept and added a test that
is successful on all combinations tested.
* Bugfix for [#29](https://github.com/gulrak/filesystem/issues/29), stricter
warning settings where chosen and resulting warnings where fixed.
### [v1.2.4](https://github.com/gulrak/filesystem/releases/tag/v1.2.4)
* Enabled stronger warning switches and resulting fixed issues on GCC and MinGW
* Bugfix for #22, the `fs::copy_options` where not forwarded from `fs::copy` to
`fs::copy_file` in one of the cases.
### [v1.2.2](https://github.com/gulrak/filesystem/releases/tag/v1.2.2)
* Fix for ([#21](https://github.com/gulrak/filesystem/pull/21)), when compiling
on Alpine Linux with musl instead of glibc, the wrong `strerror_r` signature
was expected. The complex preprocessor define mix was dropped in favor of
the usual dispatch by overloading a unifying wrapper.
### [v1.2.0](https://github.com/gulrak/filesystem/releases/tag/v1.2.0)
* Added MinGW 32/64 and Visual Studio 2015 builds to the CI configuration.
* Fixed additional compilation issues on MinGW.
* Pull request ([#13](https://github.com/gulrak/filesystem/pull/13)), set
minimum required CMake version to 3.7.2 (as in Debian 8).
* Pull request ([#14](https://github.com/gulrak/filesystem/pull/14)), added
support for a make install target.
* Bugfix for ([#15](https://github.com/gulrak/filesystem/issues/15)), the
forward/impl way of using `ghc::filesystem` missed a `<vector>` include
in the windows case.
* Bugfix for ([#16](https://github.com/gulrak/filesystem/issues/16)),
VS2019 didn't like the old size dispatching in the utf8 decoder, so it
was changed to a sfinae based approach.
* New feature ([#17](https://github.com/gulrak/filesystem/issues/17)), optional
support for standard conforming `wchar_t/std::wstring` interface when
compiling on Windows with defined `GHC_WIN_WSTRING_STRING_TYPE`, this is
default when using the `ghc/fs_std*.hpp` header, to enhance compatibility.
* New feature ([#18](https://github.com/gulrak/filesystem/issues/18)), optional
filesystem exceptions/errors on unicode errors with defined
`GHC_RAISE_UNICODE_ERRORS` (instead of replacing invalid code points or
UTF-8 encoding errors with the replacement character `U+FFFD`).
* Pull request ([#20](https://github.com/gulrak/filesystem/pull/20)), fix for
file handle leak in `fs::copy_file`.
* Coverage now checked in CI (~95% line coverage).
### [v1.1.4](https://github.com/gulrak/filesystem/releases/tag/v1.1.4)
* Additional Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
error in old unified `readdir/readdir_r` code of `fs::directory_iterator`;
as `readdir_r` is now depricated, I decided to drop it and the resulting
code is much easier, shorter and due to more refactoring faster
* Fix for crashing unit tests against MSVC C++17 std::filesystem
* Travis-CI now additionally test with Xcode 10.2 on macOS
* Some minor refactorings
### [v1.1.2](https://github.com/gulrak/filesystem/releases/tag/v1.1.2)
* Bugfix for ([#11](https://github.com/gulrak/filesystem/issues/11)),
`fs::path::lexically_normal()` had some issues with `".."`-sequences.
* Bugfix for ([#12](https://github.com/gulrak/filesystem/issues/12)),
`fs::recursive_directory_iterator` could run into endless loops,
the methods depth() and pop() had issues and the copy behaviour and
`input_iterator_tag` conformance was broken, added tests
* Restructured some CMake code into a macro to ease the support for
C++17 std::filesystem builds of tests and examples for interoperability
checks.
* Some fixes on Windows tests to ease interoperability test runs.
* Reduced noise on `fs::weakly_canonical()` tests against `std::fs`
* Added simple `du` example showing the `recursive_directory_iterator`
used to add the sizes of files in a directory tree.
* Added error checking in `fs::file_time_type` test helpers
* `fs::copy()` now conforms LWG #2682, disallowing the use of
`copy_option::create_symlinks' to be used on directories
### [v1.1.0](https://github.com/gulrak/filesystem/releases/tag/v1.1.0)
* Restructuring of the project directory. The header files are now using
`hpp` as extension to be marked as c++ and they where moved to
`include/ghc/` to be able to include by `<ghc/filesystem.hpp>` as the
former include name might have been to generic and conflict with other
files.
* Better CMake support: `ghc::filesystem` now can be used as a submodul
and added with `add_subdirectory` and will export itself as `ghc_filesystem`
target. To use it, only `target_link_libraries(your-target ghc_filesystem)`
is needed and the include directories will be set so `#include <ghc/filesystem.hpp>`
will be a valid directive.
Still you can simply only add the header file to you project and include it
from there.
* Enhancement ([#10](https://github.com/gulrak/filesystem/issues/10)),
support for separation of implementation and forwarded api: Two
additional simple includes are added, that can be used to forward
`ghc::filesystem` declarations (`fs_fwd.hpp`) and to wrap the
implementation into a single cpp (`fs_impl.hpp`)
* The `std::basic_string_view` variants of the `fs::path` api are
now supported when compiling with C++17.
* Added CI integration for Travis-CI and Appveyor.
* Fixed MinGW compilation issues.
* Added long filename support for Windows.
### [v1.0.10](https://github.com/gulrak/filesystem/releases/tag/v1.0.10)
* Bugfix for ([#9](https://github.com/gulrak/filesystem/issues/9)), added
missing return statement to `ghc::filesystem::path::generic_string()`
* Added checks to hopefully better compile against Android NDK. There where
no tests run yet, so feedback is needed to actually call this supported.
* `filesystem.h` was renamed `filesystem.hpp` to better reflect that it is
a c++ language header.
### [v1.0.8](https://github.com/gulrak/filesystem/releases/tag/v1.0.8)
* Bugfix for ([#6](https://github.com/gulrak/filesystem/issues/6)), where
`ghc::filesystem::remove()` and `ghc::filesystem::remove_all()` both are
now able to remove a single file and both will not raise an error if the
path doesn't exist.
* Merged pull request ([#7](https://github.com/gulrak/filesystem/pull/7)),
a typo leading to setting error code instead of comparing it in
`ghc::filesystem::remove()` under Windows.
* Bugfix for (([#8](https://github.com/gulrak/filesystem/issues/8)), the
Windows version of `ghc::filesystem::directory_iterator` now releases
resources when reaching `end()` like the POSIX one does.
### [v1.0.6](https://github.com/gulrak/filesystem/releases/tag/v1.0.6)
* Bugfix for ([#4](https://github.com/gulrak/filesystem/issues/4)), missing error_code
propagation in `ghc::filesystem::copy()` and `ghc::filesystem::remove_all` fixed.
* Bugfix for ([#5](https://github.com/gulrak/filesystem/issues/5)), added missing std
namespace in `ghc::filesystem::recursive_directory_iterator::difference_type`.
### [v1.0.4](https://github.com/gulrak/filesystem/releases/tag/v1.0.4)
* Bugfix for ([#3](https://github.com/gulrak/filesystem/issues/3)), fixed missing inlines
and added test to ensure including into multiple implementation files works as expected.
* Building tests with `-Wall -Wextra -Werror` and fixed resulting issues.
### [v1.0.2](https://github.com/gulrak/filesystem/releases/tag/v1.0.2)
* Updated catch2 to v2.4.0.
* Refactored `fs.op.permissions` test to work with all tested `std::filesystem`
implementations (gcc, clang, msvc++).
* Added helper class `ghc::filesystem::u8arguments` as `argv` converter, to
help follow the UTF-8 path on windows. Simply instantiate it with `argc` and
`argv` and it will fetch the Unicode version of the command line and convert
it to UTF-8. The destructor reverts the change.
* Added `examples` folder with hopefully some usefull example usage. Examples are
tested (and build) with `ghc::filesystem` and C++17 `std::filesystem` when
available.
* Starting with this version, only even patch level versions will be tagged and
odd patch levels mark in-between non-stable wip states.
* Tests can now also be run against MS version of std::filesystem for comparison.
* Added missing `fstream` include.
* Removed non-conforming C99 `timespec`/`timeval` usage.
* Fixed some integer type mismatches that could lead to warnings.
* Fixed `chrono` conversion issues in test and example on clang 7.0.0.
### [v1.0.1](https://github.com/gulrak/filesystem/releases/tag/v1.0.1)
* Bugfix: `ghc::filesystem::canonical` now sees empty path as non-existant and reports
an error. Due to this `ghc::filesystem::weakly_canonical` now returns relative
paths for non-existant argument paths. ([#1](https://github.com/gulrak/filesystem/issues/1))
* Bugfix: `ghc::filesystem::remove_all` now also counts directories removed ([#2](https://github.com/gulrak/filesystem/issues/2))
* Bugfix: `recursive_directory_iterator` tests didn't respect equality domain issues
and dereferencable constraints, leading to fails on `std::filesystem` tests.
* Bugfix: Some `noexcept` tagged methods and functions could indirectly throw exceptions
due to UFT-8 decoding issues.
* `std_filesystem_test` is now also generated if LLVM/clang 7.0.0 is found.
### [v1.0.0](https://github.com/gulrak/filesystem/releases/tag/v1.0.0)
This was the first public release version. It implements the full range of
C++17 std::filesystem, as far as possible without other C++17 dependencies.

@ -1,38 +0,0 @@
macro(AddExecutableWithStdFS targetName)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0))
if(APPLE)
include_directories(/usr/local/opt/llvm/include)
link_directories(/usr/local/opt/llvm/lib)
endif()
add_executable(${targetName} ${ARGN})
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17)
if(APPLE)
target_link_libraries(${targetName} -lc++fs)
else()
target_compile_options(${targetName} PRIVATE "-stdlib=libc++")
target_link_libraries(${targetName} -stdlib=libc++ -lc++fs)
endif()
target_link_libraries(${targetName} -lc++fs)
target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
endif()
if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0))
add_executable(${targetName} ${ARGN})
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
target_link_libraries(${targetName} -lstdc++fs)
endif()
target_compile_definitions(${targetName} PRIVATE USE_STD_FS)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15))
add_executable(${targetName} ${ARGN})
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${targetName} PROPERTY CXX_STANDARD_REQUIRED ON)
target_compile_options(${targetName} PRIVATE "/Zc:__cplusplus")
target_compile_definitions(${targetName} PRIVATE USE_STD_FS _CRT_SECURE_NO_WARNINGS)
endif()
endmacro()

@ -1,5 +0,0 @@
@PACKAGE_INIT@
set_and_check(ghcfilesystem_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@")
check_required_components(ghcfilesystem)

@ -1,12 +0,0 @@
add_executable(fs_dir dir.cpp)
target_link_libraries(fs_dir ghc_filesystem)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(fs_dir PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
AddExecutableWithStdFS(std_fs_dir dir.cpp)
add_executable(fs_du du.cpp)
target_link_libraries(fs_du ghc_filesystem)
AddExecutableWithStdFS(std_fs_du du.cpp)

@ -1,60 +0,0 @@
#include <chrono>
#include <iomanip>
#include <iostream>
#include <string>
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
template <typename TP>
std::time_t to_time_t(TP tp)
{
// Based on trick from: Nico Josuttis, C++17 - The Complete Guide
std::chrono::system_clock::duration dt = std::chrono::duration_cast<std::chrono::system_clock::duration>(tp - TP::clock::now());
return std::chrono::system_clock::to_time_t(std::chrono::system_clock::now() + dt);
}
static std::string perm_to_str(fs::perms prms)
{
std::string result;
result.reserve(9);
for (int i = 0; i < 9; ++i) {
result = ((static_cast<int>(prms) & (1 << i)) ? "xwrxwrxwr"[i] : '-') + result;
}
return result;
}
int main(int argc, char* argv[])
{
#ifdef GHC_FILESYSTEM_VERSION
fs::u8arguments u8guard(argc, argv);
if (!u8guard.valid()) {
std::cerr << "Invalid character encoding, UTF-8 based encoding needed." << std::endl;
std::exit(EXIT_FAILURE);
}
#endif
if (argc > 2) {
std::cerr << "USAGE: dir <path>" << std::endl;
exit(1);
}
fs::path dir{"."};
if (argc == 2) {
dir = fs::u8path(argv[1]);
}
for (auto de : fs::directory_iterator(dir)) {
auto ft = to_time_t(de.last_write_time());
auto ftm = *std::localtime(&ft);
std::cout << (de.is_directory() ? "d" : "-") << perm_to_str(de.symlink_status().permissions()) << " " << std::setw(8) << (de.is_directory() ? "-" : std::to_string(de.file_size())) << " " << std::put_time(&ftm, "%Y-%m-%d %H:%M:%S") << " "
<< de.path().filename().string() << std::endl;
}
return 0;
}

@ -1,61 +0,0 @@
#include <iostream>
#include <iomanip>
#include <chrono>
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#endif
#endif
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
int main(int argc, char* argv[])
{
#ifdef GHC_FILESYSTEM_VERSION
fs::u8arguments u8guard(argc, argv);
if(!u8guard.valid()) {
std::cerr << "Invalid character encoding, UTF-8 based encoding needed." << std::endl;
std::exit(EXIT_FAILURE);
}
#endif
if(argc > 2) {
std::cerr << "USAGE: du <path>" << std::endl;
exit(1);
}
fs::path dir{"."};
if(argc == 2) {
dir = fs::u8path(argv[1]);
}
uint64_t totalSize = 0;
int totalDirs = 0;
int totalFiles = 0;
int maxDepth = 0;
try {
auto rdi = fs::recursive_directory_iterator(dir);
for(auto de : rdi) {
if(rdi.depth() > maxDepth) {
maxDepth = rdi.depth();
}
if(de.is_regular_file()) {
totalSize += de.file_size();
++totalFiles;
}
else if(de.is_directory()) {
++totalDirs;
}
}
}
catch(fs::filesystem_error fe) {
std::cerr << "Error: " << fe.what() << std::endl;
exit(1);
}
std::cout << totalSize << " bytes in " << totalFiles << " files and " << totalDirs << " directories, maximum depth: " << maxDepth << std::endl;
return 0;
}

File diff suppressed because it is too large Load Diff

@ -1,46 +0,0 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
//---------------------------------------------------------------------------------------
// fs_fwd.hpp - The forwarding header for the header/implementation seperated usage of
// ghc::filesystem.
// This file can be include at any place, where ghc::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace,
// as long as one cpp includes fs_impl.hpp to deliver the matching implementations.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD
#include <ghc/filesystem.hpp>
#endif // GHC_FILESYSTEM_FWD_H

@ -1,43 +0,0 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
//---------------------------------------------------------------------------------------
// fs_impl.hpp - The implementation header for the header/implementation seperated usage of
// ghc::filesystem.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_fwd.hpp directly or via a different
// header to work.
//---------------------------------------------------------------------------------------
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>

@ -1,64 +0,0 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
//---------------------------------------------------------------------------------------
// fs_std.hpp - The dynamic switching header that includes std::filesystem if detected
// or ghc::filesystem if not, and makes the resulting API available in the
// namespace fs.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_H
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#define GHC_WIN_WSTRING_STRING_TYPE
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_H

@ -1,68 +0,0 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
//---------------------------------------------------------------------------------------
// fs_std_fwd.hpp - The forwarding header for the header/implementation seperated usage of
// ghc::filesystem that uses std::filesystem if it detects it.
// This file can be include at any place, where fs::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace,
// as long as one cpp includes fs_std_impl.hpp to deliver the matching implementations.
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_FWD_H
#define GHC_FILESYSTEM_STD_FWD_H
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
#define GHC_WIN_WSTRING_STRING_TYPE
#define GHC_FILESYSTEM_FWD
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_FWD_H

@ -1,51 +0,0 @@
//---------------------------------------------------------------------------------------
//
// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14
//
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
//---------------------------------------------------------------------------------------
// fs_std_impl.hpp - The implementation header for the header/implementation seperated usage of
// ghc::filesystem that does nothing if std::filesystem is detected.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_std_fwd.hpp directly or via a different
// header to work.
//---------------------------------------------------------------------------------------
#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
#if __has_include(<filesystem>)
#define GHC_USE_STD_FS
#endif
#endif
#ifndef GHC_USE_STD_FS
#define GHC_WIN_WSTRING_STRING_TYPE
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>
#endif

@ -1,54 +0,0 @@
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON)
include(ParseAndAddCatchTests)
if(GHC_COVERAGE)
message("Generating test runner for coverage run...")
set(CMAKE_EXE_LINKER_FLAGS "${CMCMAKE_EXE_LINKER_FLAGS} --coverage")
add_executable(filesystem_test filesystem_test.cpp catch.hpp)
if(MINGW)
target_compile_options(filesystem_test PUBLIC --coverage "-Wa,-mbig-obj")
else()
target_compile_options(filesystem_test PUBLIC --coverage)
endif()
target_link_libraries(filesystem_test PUBLIC ghc_filesystem --coverage)
else()
message("Generating test runner for normal test...")
add_executable(filesystem_test filesystem_test.cpp catch.hpp)
target_link_libraries(filesystem_test ghc_filesystem)
target_compile_options(filesystem_test PRIVATE
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wshadow -Wconversion -Wsign-conversion -Wpedantic -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/WX>)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
ParseAndAddCatchTests(filesystem_test)
AddExecutableWithStdFS(std_filesystem_test filesystem_test.cpp catch.hpp)
if(WIN32)
add_executable(filesystem_test_wchar filesystem_test.cpp catch.hpp)
target_link_libraries(filesystem_test_wchar ghc_filesystem)
target_compile_options(filesystem_test_wchar PRIVATE
$<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Werror>
$<$<CXX_COMPILER_ID:GNU>:-Wall -Werror>
$<$<CXX_COMPILER_ID:MSVC>:/WX>)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(filesystem_test_wchar PRIVATE _CRT_SECURE_NO_WARNINGS GHC_WIN_WSTRING_STRING_TYPE)
else()
target_compile_definitions(filesystem_test_wchar PRIVATE GHC_WIN_WSTRING_STRING_TYPE)
endif()
ParseAndAddCatchTests(filesystem_test_wchar)
endif()
endif()
add_executable(multifile_test multi1.cpp multi2.cpp catch.hpp)
target_link_libraries(multifile_test ghc_filesystem)
add_test(multifile_test multifile_test)
add_executable(fwd_impl_test fwd_test.cpp impl_test.cpp)
target_link_libraries(fwd_impl_test ghc_filesystem)
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
target_compile_definitions(fwd_impl_test PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
add_test(fwd_impl_test fwd_impl_test)

File diff suppressed because it is too large Load Diff

@ -1,225 +0,0 @@
#==================================================================================================#
# supported macros #
# - TEST_CASE, #
# - SCENARIO, #
# - TEST_CASE_METHOD, #
# - CATCH_TEST_CASE, #
# - CATCH_SCENARIO, #
# - CATCH_TEST_CASE_METHOD. #
# #
# Usage #
# 1. make sure this module is in the path or add this otherwise: #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# 2. make sure that you've enabled testing option for the project by the call: #
# enable_testing() #
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
# project(testing_target) #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# enable_testing() #
# #
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
# #
# file(GLOB SOURCE_FILES "*.cpp") #
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
# #
# include(ParseAndAddCatchTests) #
# ParseAndAddCatchTests(${PROJECT_NAME}) #
# #
# The following variables affect the behavior of the script: #
# #
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
# -- enables debug messages #
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
# -- adds fixture class name to the test name #
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
# -- adds cmake target name to the test name #
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
# #
# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way #
# a test should be run. For instance to use test MPI, one can write #
# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
# just before calling this ParseAndAddCatchTests function #
# #
# The AdditionalCatchParameters optional variable can be used to pass extra argument to the test #
# command. For example, to include successful tests in the output, one can write #
# set(AdditionalCatchParameters --success) #
# #
# After the script, the ParseAndAddCatchTests_TESTS property for the target, and for each source #
# file in the target is set, and contains the list of the tests extracted from that target, or #
# from that file. This is useful, for example to add further labels or properties to the tests. #
# #
#==================================================================================================#
if (CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer")
endif()
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
function(ParseAndAddCatchTests_PrintDebugMessage)
if(PARSE_CATCH_TESTS_VERBOSE)
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
endif()
endfunction()
# This removes the contents between
# - block comments (i.e. /* ... */)
# - full line comments (i.e. // ... )
# contents have been read into '${CppCode}'.
# !keep partial line comments
function(ParseAndAddCatchTests_RemoveComments CppCode)
string(ASCII 2 CMakeBeginBlockComment)
string(ASCII 3 CMakeEndBlockComment)
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
endfunction()
# Worker function
function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
# If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
return()
endif()
# According to CMake docs EXISTS behavior is well-defined only for full paths.
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
if(NOT EXISTS ${SourceFile})
message(WARNING "Cannot find source file: ${SourceFile}")
return()
endif()
ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
# Remove block and fullline comments
ParseAndAddCatchTests_RemoveComments(Contents)
# Find definition of test names
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
)
endif()
foreach(TestName ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
# Get test type and fixture if applicable
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
# Get string parts of test definition
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
# Strip wrapping quotation marks
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
# Validate that a test name and tags have been provided
list(LENGTH TestStrings TestStringsLength)
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
endif()
# Assign name and tags
list(GET TestStrings 0 Name)
if("${TestType}" STREQUAL "SCENARIO")
set(Name "Scenario: ${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
set(CTestName "${TestFixture}:${Name}")
else()
set(CTestName "${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
set(CTestName "${TestTarget}:${CTestName}")
endif()
# add target to labels to enable running all tests added from this target
set(Labels ${TestTarget})
if(TestStringsLength EQUAL 2)
list(GET TestStrings 1 Tags)
string(TOLOWER "${Tags}" Tags)
# remove target from labels if the test is hidden
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
list(REMOVE_ITEM Labels ${TestTarget})
endif()
string(REPLACE "]" ";" Tags "${Tags}")
string(REPLACE "[" "" Tags "${Tags}")
else()
# unset tags variable from previous loop
unset(Tags)
endif()
list(APPEND Labels ${Tags})
set(HiddenTagFound OFF)
foreach(label ${Labels})
string(REGEX MATCH "^!hide|^\\." result ${label})
if(result)
set(HiddenTagFound ON)
break()
endif(result)
endforeach(label)
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
else()
ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
if(Labels)
ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
endif()
# Escape commas in the test spec
string(REPLACE "," "\\," Name ${Name})
# Add the test and set its properties
add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
else()
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Labels}")
endif()
set_property(
TARGET ${TestTarget}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
set_property(
SOURCE ${SourceFile}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "\"${CTestName}\"")
endif()
endforeach()
endfunction()
# entry point
function(ParseAndAddCatchTests TestTarget)
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
get_target_property(SourceFiles ${TestTarget} SOURCES)
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
foreach(SourceFile ${SourceFiles})
ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
endforeach()
ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
endfunction()

File diff suppressed because it is too large Load Diff

@ -1,7 +0,0 @@
// This test file is part of the fwd_test.cpp/impl_test.cpp pair
// and used to test the new optional two-part usage of ghc::filesystem
// where exactly one cpp includes fs_impl.hpp and all others use
// fs_fwd.hpp (to test this with maximum functionality, the unit tests
// are included here, signaling they should only include the fs_fwd.hpp)
#define GHC_FILESYSTEM_FWD_TEST
#include "filesystem_test.cpp"

@ -1,9 +0,0 @@
// This test file is part of the fwd_test.cpp/impl_test.cpp pair
// and used to test the new optional two-part usage of ghc::filesystem
// where exactly one cpp includes fs_impl.hpp and all others use
// fs_fwd.hpp (to test this with maximum functionality, the unit tests
// are included here, signaling they should only include the fs_fwd.hpp)
#define NOMINMAX
#include <ghc/fs_impl.hpp>
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

@ -1,50 +0,0 @@
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
//
//---------------------------------------------------------------------------------------
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
// This test and the one in multi2.cpp doesn't actualy test relevant functionality,
// it is just used to check that it is possible to include filesystem.h in multiple
// source files.
TEST_CASE("Multifile-test 1", "[multi]")
{
CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string());
std::string str = "/usr/local/bin";
std::u16string u16str = u"/usr/local/bin";
std::u32string u32str = U"/usr/local/bin";
CHECK(str == fs::path(str.begin(), str.end()));
CHECK(str == fs::path(u16str.begin(), u16str.end()));
CHECK(str == fs::path(u32str.begin(), u32str.end()));
}

@ -1,48 +0,0 @@
//---------------------------------------------------------------------------------------
//
// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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 "catch.hpp"
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
// This test and the one in multi1.cpp doesn't actualy test relevant functionality,
// it is just used to check that it is possible to include filesystem.h in multiple
// source files.
TEST_CASE("Multifile-test 2", "[multi]")
{
CHECK("/usr/local/bin" == fs::path("/usr/local/bin").generic_string());
std::string str = "/usr/local/bin";
std::u16string u16str = u"/usr/local/bin";
std::u32string u32str = U"/usr/local/bin";
CHECK(str == fs::path(str.begin(), str.end()));
CHECK(str == fs::path(u16str.begin(), u16str.end()));
CHECK(str == fs::path(u32str.begin(), u32str.end()));
}
Loading…
Cancel
Save