Skip to content

Commit

Permalink
Use mainline Abseil instead of our fork
Browse files Browse the repository at this point in the history
  • Loading branch information
electroly committed Feb 19, 2024
1 parent df1b433 commit cbe2f1a
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 12 deletions.
2 changes: 1 addition & 1 deletion build/scripts/depsCheck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function checkTzdb {
echo
echo '# depsDownload.sh'

checkGitHubCommit "ABSEIL" "https://github.com/tmbasic-lang/abseil-cpp/commits.atom"
checkGitHubCommit "ABSEIL" "https://github.com/abseil/abseil-cpp/commits.atom"
checkGnu "binutils-" "BINUTILS" "https://ftp.gnu.org/gnu/binutils/"
checkJfrog "BOOST" "https://boostorg.jfrog.io/artifactory/main/release/"
checkGitHubRelease "CLI11" "https://github.com/CLIUtils/CLI11/releases.atom"
Expand Down
2 changes: 1 addition & 1 deletion build/scripts/depsDownload.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function downloadFile {
}

# don't update these versions by hand. instead, run scripts/depsCheck.sh
ABSEIL_VERSION=7626bacbbc05bfeb03a09e5993934c9d2b80b9ba
ABSEIL_VERSION=14b8a4eac3e5a7b97ba4cc7b7dadf2a85aae8215
BINUTILS_VERSION=2.42
BOOST_VERSION=1.84.0
CLI11_VERSION=2.4.1
Expand Down
15 changes: 15 additions & 0 deletions src/test/DateTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,18 @@ TEST(DateTest, DateTimeOffsetPartsRoundTrip) {
ASSERT_EQ(parts.millisecond, roundTripParts.millisecond);
ASSERT_EQ(parts.utcOffsetMilliseconds, roundTripParts.utcOffsetMilliseconds);
}

TEST(DateTest, TestZoneLookup) {
vm::initializeTzdb();

// We support this special time zone so we can recognize when we're using our own static data instead of the system
// zoneinfo data.
absl::TimeZone tz{};
ASSERT_TRUE(absl::LoadTimeZone("tmbasic-dummy-zone", &tz));

// Make sure LoadTimeZone actually returns false if the zone doesn't exist.
ASSERT_FALSE(absl::LoadTimeZone("invalid-time-zone", &tz));

// Make sure we have a valid zone.
ASSERT_TRUE(absl::LoadTimeZone("America/Chicago", &tz));
}
77 changes: 67 additions & 10 deletions src/vm/date.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,82 @@
#include "shared/tar.h"
#include "vm/RecordBuilder.h"

// This is tzdb.tar, the contents of /usr/share/zoneinfo.
extern const char kResourceTzdb[]; // NOLINT(modernize-avoid-c-arrays)
extern const uint kResourceTzdb_len;
// We depend on an internal implementation detail of Abseil in order to statically link our own zoneinfo data.
// However we have evidence that Google uses it in this way, so the risk of breakage should be low.
// See: https://github.com/abseil/abseil-cpp/pull/1626
#include <absl/time/internal/cctz/include/cctz/zone_info_source.h>

namespace vm {
using absl::time_internal::cctz::ZoneInfoSource;

// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static bool _isTzdbInitialized = false;

// Keep these alive because we have handed out string_views which must remain valid for the life of the program.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static std::vector<std::vector<char>> _zoneInfoFiles{};
// An implementation of ZoneInfoSource backed by static in-memory data.
static std::unordered_map<std::string, std::vector<char>> zoneInfoFiles{};

class StaticZoneInfoSource : public ZoneInfoSource {
public:
explicit StaticZoneInfoSource(const std::vector<char>& file) : _file(file), _len(file.size()) {}

std::size_t Read(void* ptr, std::size_t size) override {
size = std::min(size, _len);
memcpy(ptr, _file.data() + _offset, size);
_offset += size;
_len -= size;
return size;
}

int Skip(std::size_t offset) override {
offset = std::min(offset, _len);
_offset += offset;
_len -= offset;
return 0;
}

std::string Version() const override { return std::string(); }

private:
const std::vector<char>& _file;
std::size_t _offset = 0;
std::size_t _len;
};

std::unique_ptr<ZoneInfoSource> customZoneInfoSourceFactory(
const std::string& name,
const std::function<std::unique_ptr<ZoneInfoSource>(const std::string& name)>& fallback_factory) {
assert(_isTzdbInitialized);

// We accept a dummy name as a test that we're using our static data and not the system data.
if (name == "tmbasic-dummy-zone") {
return customZoneInfoSourceFactory("Etc/GMT-4", fallback_factory);
}

auto it = zoneInfoFiles.find(name);
if (it == zoneInfoFiles.end()) {
return nullptr;
}
return std::make_unique<StaticZoneInfoSource>(it->second);
}

// Abseil will look for this zone_info_source_factory symbol.
namespace absl {
namespace time_internal {
namespace cctz_extension {
ZoneInfoSourceFactory zone_info_source_factory = customZoneInfoSourceFactory;
} // namespace cctz_extension
} // namespace time_internal
} // namespace absl

// This is tzdb.tar, the contents of /usr/share/zoneinfo.
extern const char kResourceTzdb[]; // NOLINT(modernize-avoid-c-arrays)
extern const uint kResourceTzdb_len;

static void addStaticZoneInfoFile(const std::string& name, std::vector<char> data) {
const auto& storedData = _zoneInfoFiles.emplace_back(std::move(data));
std::string_view sv{ storedData.data(), storedData.size() };
absl::LoadStaticZoneInfoFile(name, sv);
zoneInfoFiles.emplace(name, std::move(data));
}

namespace vm {

void initializeTzdb() {
if (!_isTzdbInitialized) {
shared::untar(kResourceTzdb, static_cast<size_t>(kResourceTzdb_len), addStaticZoneInfoFile);
Expand Down

0 comments on commit cbe2f1a

Please sign in to comment.