Skip to content

Commit

Permalink
Move chrono interop utils to new library (#201)
Browse files Browse the repository at this point in the history
This structure makes more sense and makes the library easier to
understand.
  • Loading branch information
chiphogg authored Nov 28, 2023
1 parent 8fa4e38 commit 4019870
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 53 deletions.
25 changes: 24 additions & 1 deletion au/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ cc_library(
name = "au",
hdrs = ["au.hh"],
visibility = ["//visibility:public"],
deps = [":math"],
deps = [
":chrono_interop",
":math",
],
)

cc_test(
Expand Down Expand Up @@ -124,6 +127,26 @@ cc_test(
],
)

cc_library(
name = "chrono_interop",
hdrs = ["chrono_interop.hh"],
deps = [
":units",
],
)

cc_test(
name = "chrono_interop_test",
size = "small",
srcs = ["chrono_interop_test.cc"],
deps = [
":chrono_interop",
":prefix",
":testing",
"@com_google_googletest//:gtest_main",
],
)

cc_library(
name = "chrono_policy_validation",
testonly = True,
Expand Down
30 changes: 1 addition & 29 deletions au/au.hh
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,6 @@

#pragma once

#include <chrono>

#include "au/chrono_interop.hh"
#include "au/math.hh"
#include "au/prefix.hh"
#include "au/units/seconds.hh"

namespace au {

// Define 1:1 mapping between duration types of chrono library and our library.
template <typename RepT, typename Period>
struct CorrespondingQuantity<std::chrono::duration<RepT, Period>> {
using Unit = decltype(Seconds{} * (mag<Period::num>() / mag<Period::den>()));
using Rep = RepT;

using ChronoDuration = std::chrono::duration<Rep, Period>;

static constexpr Rep extract_value(ChronoDuration d) { return d.count(); }
static constexpr ChronoDuration construct_from_value(Rep x) { return ChronoDuration{x}; }
};

// Convert any Au duration quantity to an equivalent `std::chrono::duration`.
template <typename U, typename R>
constexpr auto as_chrono_duration(Quantity<U, R> dt) {
constexpr auto ratio = unit_ratio(U{}, seconds);
static_assert(is_rational(ratio), "Cannot convert to chrono::duration with non-rational ratio");
return std::chrono::duration<R,
std::ratio<get_value<std::intmax_t>(numerator(ratio)),
get_value<std::intmax_t>(denominator(ratio))>>{dt};
}

} // namespace au
23 changes: 0 additions & 23 deletions au/au_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,31 +31,8 @@

using ::testing::StaticAssertTypeEq;

using namespace std::chrono_literals;

namespace au {

TEST(DurationQuantity, InterconvertsWithExactlyEquivalentChronoDuration) {
constexpr QuantityD<Seconds> from_chrono = std::chrono::duration<double>{1.23};
EXPECT_THAT(from_chrono, SameTypeAndValue(seconds(1.23)));

constexpr auto val = std::chrono::nanoseconds::rep{456};
constexpr std::chrono::nanoseconds from_au = nano(seconds)(val);
EXPECT_THAT(from_au.count(), SameTypeAndValue(val));
}

TEST(DurationQuantity, InterconvertsWithIndirectlyEquivalentChronoDuration) {
constexpr QuantityD<Seconds> from_chrono = as_quantity(1234ms);
EXPECT_THAT(from_chrono, SameTypeAndValue(seconds(1.234)));
}

TEST(AsChronoDuration, ProducesExpectedResults) {
constexpr auto original = milli(seconds)(12.3f);
constexpr auto result = as_chrono_duration(original);
EXPECT_THAT(result.count(), SameTypeAndValue(12.3f));
EXPECT_THAT(as_quantity(result), QuantityEquivalent(original));
}

TEST(Conversions, SupportIntMHzToU32Hz) {
constexpr QuantityU32<Hertz> freq = mega(hertz)(40);
EXPECT_THAT(freq, SameTypeAndValue(hertz(40'000'000u)));
Expand Down
47 changes: 47 additions & 0 deletions au/chrono_interop.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2023 Aurora Operations, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <chrono>
#include <cstdint>

#include "au/quantity.hh"
#include "au/units/seconds.hh"

namespace au {

// Define 1:1 mapping between duration types of chrono library and our library.
template <typename RepT, typename Period>
struct CorrespondingQuantity<std::chrono::duration<RepT, Period>> {
using Unit = decltype(Seconds{} * (mag<Period::num>() / mag<Period::den>()));
using Rep = RepT;

using ChronoDuration = std::chrono::duration<Rep, Period>;

static constexpr Rep extract_value(ChronoDuration d) { return d.count(); }
static constexpr ChronoDuration construct_from_value(Rep x) { return ChronoDuration{x}; }
};

// Convert any Au duration quantity to an equivalent `std::chrono::duration`.
template <typename U, typename R>
constexpr auto as_chrono_duration(Quantity<U, R> dt) {
constexpr auto ratio = unit_ratio(U{}, seconds);
static_assert(is_rational(ratio), "Cannot convert to chrono::duration with non-rational ratio");
return std::chrono::duration<R,
std::ratio<get_value<std::intmax_t>(numerator(ratio)),
get_value<std::intmax_t>(denominator(ratio))>>{dt};
}

} // namespace au
46 changes: 46 additions & 0 deletions au/chrono_interop_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2023 Aurora Operations, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "au/chrono_interop.hh"

#include "au/prefix.hh"
#include "au/testing.hh"
#include "gtest/gtest.h"

using namespace std::chrono_literals;

namespace au {

TEST(DurationQuantity, InterconvertsWithExactlyEquivalentChronoDuration) {
constexpr QuantityD<Seconds> from_chrono = std::chrono::duration<double>{1.23};
EXPECT_THAT(from_chrono, SameTypeAndValue(seconds(1.23)));

constexpr auto val = std::chrono::nanoseconds::rep{456};
constexpr std::chrono::nanoseconds from_au = nano(seconds)(val);
EXPECT_THAT(from_au.count(), SameTypeAndValue(val));
}

TEST(DurationQuantity, InterconvertsWithIndirectlyEquivalentChronoDuration) {
constexpr QuantityD<Seconds> from_chrono = as_quantity(1234ms);
EXPECT_THAT(from_chrono, SameTypeAndValue(seconds(1.234)));
}

TEST(AsChronoDuration, ProducesExpectedResults) {
constexpr auto original = milli(seconds)(12.3f);
constexpr auto result = as_chrono_duration(original);
EXPECT_THAT(result.count(), SameTypeAndValue(12.3f));
EXPECT_THAT(as_quantity(result), QuantityEquivalent(original));
}

} // namespace au

0 comments on commit 4019870

Please sign in to comment.