Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20736f94 authored by Dominik Laskowski's avatar Dominik Laskowski Committed by Android (Google) Code Review
Browse files

Merge changes I0fcfa426,I2f1510ec,I07d70dc8 into main

* changes:
  SF: Fix error handling for getDisplayVsyncPeriod
  SF: Handle BAD_CONFIG for getActiveConfig
  FTL: Add Expected<T, E>
parents 6db95914 a109bb2e
Loading
Loading
Loading
Loading

include/ftl/expected.h

0 → 100644
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright 2024 The Android Open Source Project
 *
 * 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 <android-base/expected.h>
#include <ftl/optional.h>

#include <utility>

namespace android::ftl {

// Superset of base::expected<T, E> with monadic operations.
//
// TODO: Extend std::expected<T, E> in C++23.
//
template <typename T, typename E>
struct Expected final : base::expected<T, E> {
  using Base = base::expected<T, E>;
  using Base::expected;

  using Base::error;
  using Base::has_value;
  using Base::value;

  template <typename P>
  constexpr bool has_error(P predicate) const {
    return !has_value() && predicate(error());
  }

  constexpr Optional<T> value_opt() const& {
    return has_value() ? Optional(value()) : std::nullopt;
  }

  constexpr Optional<T> value_opt() && {
    return has_value() ? Optional(std::move(value())) : std::nullopt;
  }

  // Delete new for this class. Its base doesn't have a virtual destructor, and
  // if it got deleted via base class pointer, it would cause undefined
  // behavior. There's not a good reason to allocate this object on the heap
  // anyway.
  static void* operator new(size_t) = delete;
  static void* operator new[](size_t) = delete;
};

template <typename E>
constexpr auto Unexpected(E&& error) {
  return base::unexpected(std::forward<E>(error));
}

}  // namespace android::ftl
+4 −0
Original line number Diff line number Diff line
@@ -10,11 +10,15 @@ package {
cc_test {
    name: "ftl_test",
    test_suites: ["device-tests"],
    header_libs: [
        "libbase_headers",
    ],
    srcs: [
        "algorithm_test.cpp",
        "cast_test.cpp",
        "concat_test.cpp",
        "enum_test.cpp",
        "expected_test.cpp",
        "fake_guard_test.cpp",
        "flags_test.cpp",
        "function_test.cpp",
+77 −0
Original line number Diff line number Diff line
/*
 * Copyright 2024 The Android Open Source Project
 *
 * 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 <ftl/expected.h>
#include <gtest/gtest.h>

#include <string>
#include <system_error>

namespace android::test {

using IntExp = ftl::Expected<int, std::errc>;
using StringExp = ftl::Expected<std::string, std::errc>;

using namespace std::string_literals;

TEST(Expected, Construct) {
  // Default value.
  EXPECT_TRUE(IntExp().has_value());
  EXPECT_EQ(IntExp(), IntExp(0));

  EXPECT_TRUE(StringExp().has_value());
  EXPECT_EQ(StringExp(), StringExp(""));

  // Value.
  ASSERT_TRUE(IntExp(42).has_value());
  EXPECT_EQ(42, IntExp(42).value());

  ASSERT_TRUE(StringExp("test").has_value());
  EXPECT_EQ("test"s, StringExp("test").value());

  // Error.
  const auto exp = StringExp(ftl::Unexpected(std::errc::invalid_argument));
  ASSERT_FALSE(exp.has_value());
  EXPECT_EQ(std::errc::invalid_argument, exp.error());
}

TEST(Expected, HasError) {
  EXPECT_FALSE(IntExp(123).has_error([](auto) { return true; }));
  EXPECT_FALSE(IntExp(ftl::Unexpected(std::errc::io_error)).has_error([](auto) { return false; }));

  EXPECT_TRUE(StringExp(ftl::Unexpected(std::errc::permission_denied)).has_error([](auto e) {
    return e == std::errc::permission_denied;
  }));
}

TEST(Expected, ValueOpt) {
  EXPECT_EQ(ftl::Optional(-1), IntExp(-1).value_opt());
  EXPECT_EQ(std::nullopt, IntExp(ftl::Unexpected(std::errc::broken_pipe)).value_opt());

  {
    const StringExp exp("foo"s);
    EXPECT_EQ(ftl::Optional('f'),
              exp.value_opt().transform([](const auto& s) { return s.front(); }));
    EXPECT_EQ("foo"s, exp.value());
  }
  {
    StringExp exp("foobar"s);
    EXPECT_EQ(ftl::Optional(6), std::move(exp).value_opt().transform(&std::string::length));
    EXPECT_TRUE(exp.value().empty());
  }
}

}  // namespace android::test
+2 −2
Original line number Diff line number Diff line
@@ -97,13 +97,13 @@ public:
    MOCK_CONST_METHOD1(isConnected, bool(PhysicalDisplayId));
    MOCK_CONST_METHOD2(getModes,
                       std::vector<HWComposer::HWCDisplayMode>(PhysicalDisplayId, int32_t));
    MOCK_CONST_METHOD1(getActiveMode, std::optional<hal::HWConfigId>(PhysicalDisplayId));
    MOCK_CONST_METHOD1(getActiveMode, ftl::Expected<hal::HWConfigId, status_t>(PhysicalDisplayId));
    MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(PhysicalDisplayId));
    MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent));
    MOCK_CONST_METHOD0(isUsingVrComposer, bool());
    MOCK_CONST_METHOD1(getDisplayConnectionType, ui::DisplayConnectionType(PhysicalDisplayId));
    MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId));
    MOCK_CONST_METHOD2(getDisplayVsyncPeriod, status_t(PhysicalDisplayId, nsecs_t*));
    MOCK_CONST_METHOD1(getDisplayVsyncPeriod, ftl::Expected<nsecs_t, status_t>(PhysicalDisplayId));
    MOCK_METHOD4(setActiveModeWithConstraints,
                 status_t(PhysicalDisplayId, hal::HWConfigId,
                          const hal::VsyncPeriodChangeConstraints&,
+2 −4
Original line number Diff line number Diff line
@@ -239,10 +239,8 @@ nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const {
        return 0;
    }

    nsecs_t vsyncPeriod;
    const auto status = mHwComposer.getDisplayVsyncPeriod(physicalId, &vsyncPeriod);
    if (status == NO_ERROR) {
        return vsyncPeriod;
    if (const auto vsyncPeriodOpt = mHwComposer.getDisplayVsyncPeriod(physicalId).value_opt()) {
        return *vsyncPeriodOpt;
    }

    return refreshRateSelector().getActiveMode().modePtr->getVsyncRate().getPeriodNsecs();
Loading