InodeCache::get(const std::string& path,
ContentType type,
Digest& file_digest,
- int* return_value)
+ HashSourceCodeResult* return_value)
{
if (!initialize()) {
return false;
file_digest = bucket->entries[0].file_digest;
if (return_value) {
- *return_value = bucket->entries[0].return_value;
+ *return_value =
+ HashSourceCodeResult::from_bitmask(bucket->entries[0].return_value);
}
found = true;
break;
InodeCache::put(const std::string& path,
ContentType type,
const Digest& file_digest,
- int return_value)
+ HashSourceCodeResult return_value)
{
if (!initialize()) {
return false;
bucket->entries[0].key_digest = key_digest;
bucket->entries[0].file_digest = file_digest;
- bucket->entries[0].return_value = return_value;
+ bucket->entries[0].return_value = return_value.to_bitmask();
});
if (!success) {
#pragma once
#include <Fd.hpp>
+#include <hashutil.hpp>
#include <util/Duration.hpp>
#include <util/TimePoint.hpp>
bool get(const std::string& path,
ContentType type,
Digest& file_digest,
- int* return_value = nullptr);
+ HashSourceCodeResult* return_value = nullptr);
// Put hash digest and return value from a successful call to do_hash_file()
// in hashutil.cpp.
bool put(const std::string& path,
ContentType type,
const Digest& file_digest,
- int return_value = 0);
+ HashSourceCodeResult return_value);
// Unmaps the current cache and removes the mapped file from disk.
//
if (ctx.config.direct_mode()) {
if (!is_pch) { // else: the file has already been hashed.
- int result = hash_source_code_file(ctx, file_digest, path);
- if (result & HASH_SOURCE_CODE_ERROR
- || result & HASH_SOURCE_CODE_FOUND_TIME) {
+ auto ret = hash_source_code_file(ctx, file_digest, path);
+ if (ret.contains(HashSourceCode::error)
+ || ret.contains(HashSourceCode::found_time)) {
return false;
}
}
hash.hash_delimiter("sourcecode hash");
Digest input_file_digest;
- int result =
+ auto ret =
hash_source_code_file(ctx, input_file_digest, ctx.args_info.input_file);
- if (result & HASH_SOURCE_CODE_ERROR) {
+ if (ret.contains(HashSourceCode::error)) {
return nonstd::make_unexpected(Statistic::internal_error);
}
- if (result & HASH_SOURCE_CODE_FOUND_TIME) {
+ if (ret.contains(HashSourceCode::found_time)) {
LOG_RAW("Disabling direct mode");
ctx.config.set_direct_mode(false);
return {};
auto hashed_files_iter = hashed_files.find(path);
if (hashed_files_iter == hashed_files.end()) {
Digest actual_digest;
- int ret = hash_source_code_file(ctx, actual_digest, path, fs.size);
- if (ret & HASH_SOURCE_CODE_ERROR) {
+ auto ret = hash_source_code_file(ctx, actual_digest, path, fs.size);
+ if (ret.contains(HashSourceCode::error)) {
LOG("Failed hashing {}", path);
return false;
}
- if (ret & HASH_SOURCE_CODE_FOUND_TIME) {
+ if (ret.contains(HashSourceCode::found_time)) {
return false;
}
namespace {
-// Returns one of HASH_SOURCE_CODE_FOUND_DATE, HASH_SOURCE_CODE_FOUND_TIME or
-// HASH_SOURCE_CODE_FOUND_TIMESTAMP if "_DATE__", "_TIME__" or "_TIMESTAMP__"
-// starts at str[pos].
-//
// Pre-condition: str[pos - 1] == '_'
-int
+HashSourceCode
check_for_temporal_macros_helper(std::string_view str, size_t pos)
{
if (pos + 7 > str.length()) {
- return 0;
+ return HashSourceCode::ok;
}
- int found = 0;
+ HashSourceCode found = HashSourceCode::ok;
int macro_len = 7;
if (memcmp(&str[pos], "_DATE__", 7) == 0) {
- found = HASH_SOURCE_CODE_FOUND_DATE;
+ found = HashSourceCode::found_date;
} else if (memcmp(&str[pos], "_TIME__", 7) == 0) {
- found = HASH_SOURCE_CODE_FOUND_TIME;
+ found = HashSourceCode::found_time;
} else if (pos + 12 <= str.length()
&& memcmp(&str[pos], "_TIMESTAMP__", 12) == 0) {
- found = HASH_SOURCE_CODE_FOUND_TIMESTAMP;
+ found = HashSourceCode::found_timestamp;
macro_len = 12;
} else {
- return 0;
+ return HashSourceCode::ok;
}
// Check char before and after macro to verify that the found macro isn't part
return found;
}
- return 0;
+ return HashSourceCode::ok;
}
-int
+HashSourceCodeResult
check_for_temporal_macros_bmh(std::string_view str, size_t start = 0)
{
- int result = 0;
+ HashSourceCodeResult result;
// We're using the Boyer-Moore-Horspool algorithm, which searches starting
// from the *end* of the needle. Our needles are 8 characters long, so i
// the assumption that 'E' is less common in source than '_', we check
// str[i-2] first.
if (str[i - 2] == 'E' && str[i - 7] == '_') {
- result |= check_for_temporal_macros_helper(str, i - 6);
+ result.insert(check_for_temporal_macros_helper(str, i - 6));
}
// macro_skip tells us how far we can skip forward upon seeing str[i] at
#ifdef HAVE_AVX2
# ifndef _MSC_VER // MSVC does not need explicit enabling of AVX2.
-int check_for_temporal_macros_avx2(std::string_view str)
+HashSourceCodeResult check_for_temporal_macros_avx2(std::string_view str)
__attribute__((target("avx2")));
# endif
// The following algorithm, which uses AVX2 instructions to find __DATE__,
// __TIME__ and __TIMESTAMP__, is heavily inspired by
// <http://0x80.pl/articles/simd-strfind.html>.
-int
+HashSourceCodeResult
check_for_temporal_macros_avx2(std::string_view str)
{
- int result = 0;
+ HashSourceCodeResult result;
// Set all 32 bytes in first and last to '_' and 'E' respectively.
const __m256i first = _mm256_set1_epi8('_');
// Clear the least significant bit set.
mask = mask & (mask - 1);
- result |= check_for_temporal_macros_helper(str, start);
+ result.insert(check_for_temporal_macros_helper(str, start));
}
}
- result |= check_for_temporal_macros_bmh(str, pos);
+ result.insert(check_for_temporal_macros_bmh(str, pos));
return result;
}
#endif
-int
+HashSourceCodeResult
do_hash_file(const Context& ctx,
Digest& digest,
const std::string& path,
check_temporal_macros ? InodeCache::ContentType::checked_for_temporal_macros
: InodeCache::ContentType::raw;
if (ctx.config.inode_cache()) {
- int result;
+ HashSourceCodeResult result;
if (ctx.inode_cache.get(path, content_type, digest, &result)) {
return result;
}
const auto data = util::read_file<std::string>(path, size_hint);
if (!data) {
LOG("Failed to read {}: {}", path, data.error());
- return HASH_SOURCE_CODE_ERROR;
+ return HashSourceCodeResult(HashSourceCode::error);
}
- int result = HASH_SOURCE_CODE_OK;
+ HashSourceCodeResult result;
if (check_temporal_macros) {
- result |= check_for_temporal_macros(*data);
+ result.insert(check_for_temporal_macros(*data));
}
Hash hash;
} // namespace
-int
+HashSourceCodeResult
check_for_temporal_macros(std::string_view str)
{
#ifdef HAVE_AVX2
return check_for_temporal_macros_bmh(str);
}
-int
+HashSourceCodeResult
hash_source_code_file(const Context& ctx,
Digest& digest,
const std::string& path,
auto result =
do_hash_file(ctx, digest, path, size_hint, check_temporal_macros);
- if (!check_temporal_macros || result == HASH_SOURCE_CODE_OK
- || (result & HASH_SOURCE_CODE_ERROR)) {
+ if (!check_temporal_macros || result.empty()
+ || result.contains(HashSourceCode::error)) {
return result;
}
- if (result & HASH_SOURCE_CODE_FOUND_TIME) {
+ if (result.contains(HashSourceCode::found_time)) {
// We don't know for sure that the program actually uses the __TIME__ macro,
// but we have to assume it anyway and hash the time stamp. However, that's
// not very useful since the chance that we get a cache hit later the same
Hash hash;
hash.hash(digest.to_string());
- if (result & HASH_SOURCE_CODE_FOUND_DATE) {
+ if (result.contains(HashSourceCode::found_date)) {
LOG("Found __DATE__ in {}", path);
hash.hash_delimiter("date");
auto now = Util::localtime();
if (!now) {
- return HASH_SOURCE_CODE_ERROR;
+ result.insert(HashSourceCode::error);
+ return result;
}
hash.hash(now->tm_year);
hash.hash(now->tm_mon);
}
}
- if (result & HASH_SOURCE_CODE_FOUND_TIMESTAMP) {
+ if (result.contains(HashSourceCode::found_timestamp)) {
LOG("Found __TIMESTAMP__ in {}", path);
const auto stat = Stat::stat(path);
if (!stat) {
- return HASH_SOURCE_CODE_ERROR;
+ result.insert(HashSourceCode::error);
+ return result;
}
auto modified_time = Util::localtime(stat.mtime());
if (!modified_time) {
- return HASH_SOURCE_CODE_ERROR;
+ result.insert(HashSourceCode::error);
+ return result;
}
hash.hash_delimiter("timestamp");
#ifdef HAVE_ASCTIME_R
auto timestamp = asctime(&*modified_time);
#endif
if (!timestamp) {
- return HASH_SOURCE_CODE_ERROR;
+ result.insert(HashSourceCode::error);
+ return result;
}
hash.hash(timestamp);
}
const std::string& path,
size_t size_hint)
{
- return do_hash_file(ctx, digest, path, size_hint, false)
- == HASH_SOURCE_CODE_OK;
+ return do_hash_file(ctx, digest, path, size_hint, false).empty();
}
bool
-// Copyright (C) 2009-2022 Joel Rosdahl and other contributors
+// Copyright (C) 2009-2023 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
#pragma once
+#include <util/BitSet.hpp>
+
#include <cstddef>
#include <string>
#include <string_view>
class Digest;
class Hash;
-const int HASH_SOURCE_CODE_OK = 0;
-const int HASH_SOURCE_CODE_ERROR = (1 << 0);
-const int HASH_SOURCE_CODE_FOUND_DATE = (1 << 1);
-const int HASH_SOURCE_CODE_FOUND_TIME = (1 << 2);
-const int HASH_SOURCE_CODE_FOUND_TIMESTAMP = (1 << 3);
+enum class HashSourceCode {
+ ok = 0,
+ error = 1U << 0,
+ found_date = 1U << 1,
+ found_time = 1U << 2,
+ found_timestamp = 1U << 3,
+};
-// Search for the strings "DATE", "TIME" and "TIMESTAMP" with two surrounding
-// underscores in `str`.
-//
-// Returns a bitmask with HASH_SOURCE_CODE_FOUND_DATE,
-// HASH_SOURCE_CODE_FOUND_TIME and HASH_SOURCE_CODE_FOUND_TIMESTAMP set
-// appropriately.
-int check_for_temporal_macros(std::string_view str);
+using HashSourceCodeResult = util::BitSet<HashSourceCode>;
+
+// Search for tokens (described in HashSourceCode) in `str`.
+HashSourceCodeResult check_for_temporal_macros(std::string_view str);
-// Hash a source code file using the inode cache if enabled. Returns a bitmask
-// of HASH_SOURCE_CODE_* results.
-int hash_source_code_file(const Context& ctx,
- Digest& digest,
- const std::string& path,
- size_t size_hint = 0);
+// Hash a source code file using the inode cache if enabled.
+HashSourceCodeResult hash_source_code_file(const Context& ctx,
+ Digest& digest,
+ const std::string& path,
+ size_t size_hint = 0);
// Hash a binary file (using the inode cache if enabled) and put its digest in
// `digest`
-// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2023 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
put(InodeCache& inode_cache,
const std::string& filename,
const std::string& str,
- int return_value)
+ HashSourceCodeResult return_value)
{
return inode_cache.put(filename,
InodeCache::ContentType::checked_for_temporal_macros,
InodeCache inode_cache(config, util::Duration(0));
Digest digest;
- int return_value;
+ HashSourceCodeResult return_value;
CHECK(!inode_cache.get("a",
InodeCache::ContentType::checked_for_temporal_macros,
util::write_file("a", "");
Digest digest;
- int return_value;
+ HashSourceCodeResult return_value;
CHECK(!inode_cache.get("a",
InodeCache::ContentType::checked_for_temporal_macros,
InodeCache inode_cache(config, util::Duration(0));
util::write_file("a", "a text");
- CHECK(put(inode_cache, "a", "a text", 1));
+ HashSourceCodeResult result;
+ result.insert(HashSourceCode::found_date);
+ CHECK(put(inode_cache, "a", "a text", result));
Digest digest;
- int return_value;
+ HashSourceCodeResult return_value;
CHECK(inode_cache.get("a",
InodeCache::ContentType::checked_for_temporal_macros,
digest,
&return_value));
CHECK(digest == Hash().hash("a text").digest());
- CHECK(return_value == 1);
+ CHECK(return_value.to_bitmask()
+ == static_cast<int>(HashSourceCode::found_date));
CHECK(inode_cache.get_hits() == 1);
CHECK(inode_cache.get_misses() == 0);
CHECK(inode_cache.get_errors() == 0);
CHECK(inode_cache.get_misses() == 1);
CHECK(inode_cache.get_errors() == 0);
- CHECK(put(inode_cache, "a", "something else", 2));
+ CHECK(put(inode_cache,
+ "a",
+ "something else",
+ HashSourceCodeResult(HashSourceCode::found_time)));
CHECK(inode_cache.get("a",
InodeCache::ContentType::checked_for_temporal_macros,
digest,
&return_value));
CHECK(digest == Hash().hash("something else").digest());
- CHECK(return_value == 2);
+ CHECK(return_value.to_bitmask()
+ == static_cast<int>(HashSourceCode::found_time));
CHECK(inode_cache.get_hits() == 2);
CHECK(inode_cache.get_misses() == 1);
CHECK(inode_cache.get_errors() == 0);
Digest binary_digest = Hash().hash("binary").digest();
Digest code_digest = Hash().hash("code").digest();
- CHECK(inode_cache.put("a", InodeCache::ContentType::raw, binary_digest, 1));
- CHECK(inode_cache.put(
- "a", InodeCache::ContentType::checked_for_temporal_macros, code_digest, 2));
+ CHECK(inode_cache.put("a",
+ InodeCache::ContentType::raw,
+ binary_digest,
+ HashSourceCodeResult(HashSourceCode::found_date)));
+ CHECK(inode_cache.put("a",
+ InodeCache::ContentType::checked_for_temporal_macros,
+ code_digest,
+ HashSourceCodeResult(HashSourceCode::found_time)));
Digest digest;
- int return_value;
+ HashSourceCodeResult return_value;
CHECK(
inode_cache.get("a", InodeCache::ContentType::raw, digest, &return_value));
CHECK(digest == binary_digest);
- CHECK(return_value == 1);
+ CHECK(return_value.to_bitmask()
+ == static_cast<int>(HashSourceCode::found_date));
CHECK(inode_cache.get("a",
InodeCache::ContentType::checked_for_temporal_macros,
digest,
&return_value));
CHECK(digest == code_digest);
- CHECK(return_value == 2);
+ CHECK(return_value.to_bitmask()
+ == static_cast<int>(HashSourceCode::found_time));
}
TEST_SUITE_END();
-// Copyright (C) 2010-2022 Joel Rosdahl and other contributors
+// Copyright (C) 2010-2023 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
"#define alphabet abcdefghijklmnopqrstuvwxyz\n"
"a__DATE__";
- CHECK(check_for_temporal_macros(time_start));
- CHECK(!check_for_temporal_macros(time_start.substr(1)));
-
- CHECK(check_for_temporal_macros(time_middle.substr(0)));
- CHECK(check_for_temporal_macros(time_middle.substr(1)));
- CHECK(check_for_temporal_macros(time_middle.substr(2)));
- CHECK(check_for_temporal_macros(time_middle.substr(3)));
- CHECK(check_for_temporal_macros(time_middle.substr(4)));
- CHECK(check_for_temporal_macros(time_middle.substr(5)));
- CHECK(check_for_temporal_macros(time_middle.substr(6)));
- CHECK(check_for_temporal_macros(time_middle.substr(7)));
-
- CHECK(check_for_temporal_macros(time_end));
- CHECK(check_for_temporal_macros(time_end.substr(time_end.length() - 8)));
- CHECK(!check_for_temporal_macros(time_end.substr(time_end.length() - 7)));
-
- CHECK(check_for_temporal_macros(date_start));
- CHECK(!check_for_temporal_macros(date_start.substr(1)));
-
- CHECK(check_for_temporal_macros(date_middle.substr(0)));
- CHECK(check_for_temporal_macros(date_middle.substr(1)));
- CHECK(check_for_temporal_macros(date_middle.substr(2)));
- CHECK(check_for_temporal_macros(date_middle.substr(3)));
- CHECK(check_for_temporal_macros(date_middle.substr(4)));
- CHECK(check_for_temporal_macros(date_middle.substr(5)));
- CHECK(check_for_temporal_macros(date_middle.substr(6)));
- CHECK(check_for_temporal_macros(date_middle.substr(7)));
-
- CHECK(check_for_temporal_macros(date_end));
- CHECK(check_for_temporal_macros(date_end.substr(date_end.length() - 8)));
- CHECK(!check_for_temporal_macros(date_end.substr(date_end.length() - 7)));
-
- CHECK(check_for_temporal_macros(timestamp_start));
- CHECK(!check_for_temporal_macros(timestamp_start.substr(1)));
-
- CHECK(check_for_temporal_macros(timestamp_middle));
- CHECK(check_for_temporal_macros(timestamp_middle.substr(1)));
- CHECK(check_for_temporal_macros(timestamp_middle.substr(2)));
- CHECK(check_for_temporal_macros(timestamp_middle.substr(3)));
- CHECK(check_for_temporal_macros(timestamp_middle.substr(4)));
- CHECK(check_for_temporal_macros(timestamp_middle.substr(5)));
- CHECK(check_for_temporal_macros(timestamp_middle.substr(6)));
- CHECK(check_for_temporal_macros(timestamp_middle.substr(7)));
-
- CHECK(check_for_temporal_macros(timestamp_end));
- CHECK(check_for_temporal_macros(
- timestamp_end.substr(timestamp_end.length() - 13)));
- CHECK(!check_for_temporal_macros(
- timestamp_end.substr(timestamp_end.length() - 12)));
-
- CHECK(!check_for_temporal_macros(no_temporal.substr(0)));
- CHECK(!check_for_temporal_macros(no_temporal.substr(1)));
- CHECK(!check_for_temporal_macros(no_temporal.substr(2)));
- CHECK(!check_for_temporal_macros(no_temporal.substr(3)));
- CHECK(!check_for_temporal_macros(no_temporal.substr(4)));
- CHECK(!check_for_temporal_macros(no_temporal.substr(5)));
- CHECK(!check_for_temporal_macros(no_temporal.substr(6)));
- CHECK(!check_for_temporal_macros(no_temporal.substr(7)));
+ auto check = check_for_temporal_macros;
+
+ CHECK(check(time_start).contains(HashSourceCode::found_time));
+ CHECK(check(time_start.substr(1)).empty());
+
+ CHECK(check(time_middle.substr(0)).contains(HashSourceCode::found_time));
+ CHECK(check(time_middle.substr(1)).contains(HashSourceCode::found_time));
+ CHECK(check(time_middle.substr(2)).contains(HashSourceCode::found_time));
+ CHECK(check(time_middle.substr(3)).contains(HashSourceCode::found_time));
+ CHECK(check(time_middle.substr(4)).contains(HashSourceCode::found_time));
+ CHECK(check(time_middle.substr(5)).contains(HashSourceCode::found_time));
+ CHECK(check(time_middle.substr(6)).contains(HashSourceCode::found_time));
+ CHECK(check(time_middle.substr(7)).contains(HashSourceCode::found_time));
+
+ CHECK(check(time_end).contains(HashSourceCode::found_time));
+ CHECK(check(time_end.substr(time_end.length() - 8))
+ .contains(HashSourceCode::found_time));
+ CHECK(check(time_end.substr(time_end.length() - 7)).empty());
+
+ CHECK(check(date_start).contains(HashSourceCode::found_date));
+ CHECK(check(date_start.substr(1)).empty());
+
+ CHECK(check(date_middle.substr(0)).contains(HashSourceCode::found_date));
+ CHECK(check(date_middle.substr(1)).contains(HashSourceCode::found_date));
+ CHECK(check(date_middle.substr(2)).contains(HashSourceCode::found_date));
+ CHECK(check(date_middle.substr(3)).contains(HashSourceCode::found_date));
+ CHECK(check(date_middle.substr(4)).contains(HashSourceCode::found_date));
+ CHECK(check(date_middle.substr(5)).contains(HashSourceCode::found_date));
+ CHECK(check(date_middle.substr(6)).contains(HashSourceCode::found_date));
+ CHECK(check(date_middle.substr(7)).contains(HashSourceCode::found_date));
+
+ CHECK(check(date_end).contains(HashSourceCode::found_date));
+ CHECK(check(date_end.substr(date_end.length() - 8))
+ .contains(HashSourceCode::found_date));
+ CHECK(check(date_end.substr(date_end.length() - 7)).empty());
+
+ CHECK(check(timestamp_start).contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_start.substr(1)).empty());
+
+ CHECK(check(timestamp_middle).contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_middle.substr(1))
+ .contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_middle.substr(2))
+ .contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_middle.substr(3))
+ .contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_middle.substr(4))
+ .contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_middle.substr(5))
+ .contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_middle.substr(6))
+ .contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_middle.substr(7))
+ .contains(HashSourceCode::found_timestamp));
+
+ CHECK(check(timestamp_end).contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_end.substr(timestamp_end.length() - 13))
+ .contains(HashSourceCode::found_timestamp));
+ CHECK(check(timestamp_end.substr(timestamp_end.length() - 12)).empty());
+
+ CHECK(check(no_temporal.substr(0)).empty());
+ CHECK(check(no_temporal.substr(1)).empty());
+ CHECK(check(no_temporal.substr(2)).empty());
+ CHECK(check(no_temporal.substr(3)).empty());
+ CHECK(check(no_temporal.substr(4)).empty());
+ CHECK(check(no_temporal.substr(5)).empty());
+ CHECK(check(no_temporal.substr(6)).empty());
+ CHECK(check(no_temporal.substr(7)).empty());
for (size_t i = 0; i < temporal_at_avx_boundary.size() - 8; ++i) {
- CHECK(check_for_temporal_macros(temporal_at_avx_boundary.substr(i)));
+ CHECK(!check(temporal_at_avx_boundary.substr(i)).empty());
}
for (size_t i = 0; i < no_temporal_at_avx_boundary.size() - 8; ++i) {
- CHECK(!check_for_temporal_macros(no_temporal_at_avx_boundary.substr(i)));
+ CHECK(check(no_temporal_at_avx_boundary.substr(i)).empty());
}
}