Skip to content

Commit

Permalink
Do not bother with specializations for small argument counts in `Make…
Browse files Browse the repository at this point in the history
…rType` and

`InvokerType`.

They got less important since `ReferenceOrCheapValue` is gone, and it is less
confusing to have one implementation.

PiperOrigin-RevId: 686051961
  • Loading branch information
QrczakMK committed Oct 15, 2024
1 parent 83623ab commit 94ee17a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 237 deletions.
64 changes: 5 additions & 59 deletions riegeli/base/invoker.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ class InvokerBase : public ConditionallyAssignable<absl::conjunction<
template <
typename SrcFunction, typename... SrcArgs,
std::enable_if_t<
absl::conjunction<std::is_convertible<SrcFunction&&, Function>,
absl::conjunction<absl::negation<std::is_same<
std::tuple<std::decay_t<SrcFunction>,
std::decay_t<SrcArgs>...>,
std::tuple<InvokerType<Function, Args...>>>>,
std::is_convertible<SrcFunction&&, Function>,
std::is_convertible<SrcArgs&&, Args>...>::value,
int> = 0>
/*implicit*/ InvokerBase(SrcFunction&& function, SrcArgs&&... args)
Expand All @@ -94,42 +98,6 @@ class InvokerBase : public ConditionallyAssignable<absl::conjunction<
ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS std::tuple<Args...> args_;
};

// Specialization of `InvokerBase` for 0 arguments to exclude the constructor
// hijacking copy and move constructor for the 0 argument case, and to make the
// type trivially copy constructible more often.

template <typename Function>
class InvokerBase<Function> {
public:
using Result = decltype(std::declval<Function&&>()());

template <typename SrcFunction,
std::enable_if_t<
absl::conjunction<
absl::negation<std::is_same<std::decay_t<SrcFunction>,
InvokerType<Function>>>,
std::is_convertible<SrcFunction&&, Function>>::value,
int> = 0>
/*implicit*/ InvokerBase(SrcFunction&& function)
: function_(std::forward<SrcFunction>(function)) {}

InvokerBase(InvokerBase&& that) = default;
InvokerBase& operator=(InvokerBase&& that) = default;

InvokerBase(const InvokerBase& that) = default;
InvokerBase& operator=(const InvokerBase& that) = default;

/*implicit*/ operator Result() && {
return std::forward<Function>(function_)();
}

protected:
const Function& function() const { return function_; }

private:
ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS Function function_;
};

template <typename Enable, typename Function, typename... Args>
struct IsConstCallableImpl : std::false_type {};

Expand Down Expand Up @@ -182,28 +150,6 @@ class InvokerConstBase</*is_const_callable=*/true, Function, Args...>
}
};

// Specialization of `InvokerConstBase<true, ...>` for 0 arguments to make it
// compatible with the specialization of `InvokerBase`.

template <typename Function>
class InvokerConstBase</*is_const_callable=*/true, Function>
: public InvokerBase<Function> {
public:
using InvokerConstBase::InvokerBase::InvokerBase;

InvokerConstBase(InvokerConstBase&& that) = default;
InvokerConstBase& operator=(InvokerConstBase&& that) = default;

InvokerConstBase(const InvokerConstBase& that) = default;
InvokerConstBase& operator=(const InvokerConstBase& that) = default;

using ConstResult = decltype(std::declval<const Function&>()());

using InvokerConstBase::InvokerBase::operator typename InvokerConstBase::
Result;
/*implicit*/ operator ConstResult() const& { return this->function()(); }
};

} // namespace invoker_internal

// `InvokerType<Function, Args...>`, usually made with
Expand Down
231 changes: 53 additions & 178 deletions riegeli/base/maker.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ class MakerType : public ConditionallyAssignable<absl::conjunction<
template <
typename... SrcArgs,
std::enable_if_t<
absl::conjunction<std::is_convertible<SrcArgs&&, Args>...>::value,
absl::conjunction<
absl::negation<std::is_same<std::tuple<std::decay_t<SrcArgs>...>,
std::tuple<MakerType>>>,
std::is_convertible<SrcArgs&&, Args>...>::value,
int> = 0>
/*implicit*/ MakerType(SrcArgs&&... args)
: args_(std::forward<SrcArgs>(args)...) {}
Expand Down Expand Up @@ -104,7 +107,31 @@ class MakerType : public ConditionallyAssignable<absl::conjunction<
// `storage` must outlive usages of the returned reference.
template <
typename T,
std::enable_if_t<std::is_constructible<T, Args&&...>::value, int> = 0>
std::enable_if_t<absl::conjunction<std::is_constructible<T, Args&&...>,
initializer_internal::CanBindTo<
T&&, Args&&...>>::value,
int> = 0>
T&& Reference() && ABSL_ATTRIBUTE_LIFETIME_BOUND {
auto&& reference = std::get<0>(std::move(args_));
return std::forward<T>(
*absl::implicit_cast<std::remove_reference_t<T>*>(&reference));
}
template <
typename T,
std::enable_if_t<absl::conjunction<std::is_constructible<T, Args&&...>,
initializer_internal::CanBindTo<
T&&, Args&&...>>::value,
int> = 0>
T&& Reference(ABSL_ATTRIBUTE_UNUSED TemporaryStorage<T>&& storage) &&
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return std::move(*this).template Reference<T>();
}
template <typename T,
std::enable_if_t<absl::conjunction<
std::is_constructible<T, Args&&...>,
absl::negation<initializer_internal::CanBindTo<
T&&, Args&&...>>>::value,
int> = 0>
T&& Reference(TemporaryStorage<T>&& storage ABSL_ATTRIBUTE_LIFETIME_BOUND =
TemporaryStorage<T>()) && {
return absl::apply(
Expand All @@ -114,7 +141,30 @@ class MakerType : public ConditionallyAssignable<absl::conjunction<
std::move(args_));
}
template <typename T,
std::enable_if_t<std::is_constructible<T, const Args&...>::value,
std::enable_if_t<
absl::conjunction<std::is_constructible<T, const Args&...>,
initializer_internal::CanBindTo<
T&&, const Args&...>>::value,
int> = 0>
T&& Reference() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
return std::forward<T>(
*absl::implicit_cast<std::remove_reference_t<T>*>(&std::get<0>(args_)));
}
template <typename T,
std::enable_if_t<
absl::conjunction<std::is_constructible<T, const Args&...>,
initializer_internal::CanBindTo<
T&&, const Args&...>>::value,
int> = 0>
T&& Reference(ABSL_ATTRIBUTE_UNUSED TemporaryStorage<T>&& storage)
const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
return Reference<T>();
}
template <typename T,
std::enable_if_t<absl::conjunction<
std::is_constructible<T, const Args&...>,
absl::negation<initializer_internal::CanBindTo<
T&&, const Args&...>>>::value,
int> = 0>
T&& Reference(TemporaryStorage<T>&& storage ABSL_ATTRIBUTE_LIFETIME_BOUND =
TemporaryStorage<T>()) const& {
Expand Down Expand Up @@ -166,177 +216,6 @@ class MakerType : public ConditionallyAssignable<absl::conjunction<
ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS std::tuple<Args...> args_;
};

// Specializations of `MakerType` for 0 to 1 arguments to apply `CanBindTo`
// optimization for the 1 argument case, to exclude the constructor hijacking
// copy and move constructor for the 1 argument case, and to make the type
// trivially copy constructible more often.

template <>
class MakerType<> {
public:
MakerType() = default;

MakerType(MakerType&& that) = default;
MakerType& operator=(MakerType&& that) = default;

MakerType(const MakerType& that) = default;
MakerType& operator=(const MakerType& that) = default;

template <typename T,
std::enable_if_t<std::is_default_constructible<T>::value, int> = 0>
T Construct() const {
return T();
}

template <typename T,
std::enable_if_t<std::is_default_constructible<T>::value, int> = 0>
void ConstructAt(void* ptr) const {
new (ptr) T();
}

template <typename T,
std::enable_if_t<std::is_default_constructible<T>::value, int> = 0>
T&& Reference(TemporaryStorage<T>&& storage ABSL_ATTRIBUTE_LIFETIME_BOUND =
TemporaryStorage<T>()) const {
return std::move(storage).emplace();
}

template <typename T,
std::enable_if_t<
absl::conjunction<absl::negation<std::is_reference<T>>,
std::is_move_assignable<T>,
std::is_default_constructible<T>>::value,
int> = 0>
friend void RiegeliReset(T& dest, ABSL_ATTRIBUTE_UNUSED MakerType src) {
riegeli::Reset(dest);
}
};

template <typename Arg0>
class MakerType<Arg0> {
public:
template <
typename SrcArg0,
std::enable_if_t<
absl::conjunction<
absl::negation<std::is_same<std::decay_t<SrcArg0>, MakerType>>,
std::is_convertible<SrcArg0&&, Arg0>>::value,
int> = 0>
/*implicit*/ MakerType(SrcArg0&& arg0) : arg0_(std::forward<SrcArg0>(arg0)) {}

MakerType(MakerType&& that) = default;
MakerType& operator=(MakerType&& that) = default;

MakerType(const MakerType& that) = default;
MakerType& operator=(const MakerType& that) = default;

template <typename T,
std::enable_if_t<std::is_constructible<T, Arg0&&>::value, int> = 0>
T Construct() && {
return T(std::forward<Arg0>(arg0_));
}
template <
typename T,
std::enable_if_t<std::is_constructible<T, const Arg0&>::value, int> = 0>
T Construct() const& {
return T(arg0_);
}

template <typename T,
std::enable_if_t<std::is_constructible<T, Arg0&&>::value, int> = 0>
void ConstructAt(void* ptr) && {
new (ptr) T(std::forward<Arg0>(arg0_));
}
template <
typename T,
std::enable_if_t<std::is_constructible<T, const Arg0&>::value, int> = 0>
void ConstructAt(void* ptr) const& {
new (ptr) T(arg0_);
}

template <typename T,
std::enable_if_t<absl::conjunction<std::is_constructible<T, Arg0&&>,
initializer_internal::CanBindTo<
T&&, Arg0&&>>::value,
int> = 0>
T&& Reference() && ABSL_ATTRIBUTE_LIFETIME_BOUND {
auto&& reference = std::forward<Arg0>(arg0_);
return std::forward<T>(
*absl::implicit_cast<std::remove_reference_t<T>*>(&reference));
}
template <typename T,
std::enable_if_t<absl::conjunction<std::is_constructible<T, Arg0&&>,
initializer_internal::CanBindTo<
T&&, Arg0&&>>::value,
int> = 0>
T&& Reference(ABSL_ATTRIBUTE_UNUSED TemporaryStorage<T>&& storage) &&
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return std::move(*this).template Reference<T>();
}
template <typename T,
std::enable_if_t<absl::conjunction<
std::is_constructible<T, Arg0&&>,
absl::negation<initializer_internal::CanBindTo<
T&&, Arg0&&>>>::value,
int> = 0>
T&& Reference(TemporaryStorage<T>&& storage ABSL_ATTRIBUTE_LIFETIME_BOUND =
TemporaryStorage<T>()) && {
return std::move(storage).emplace(std::forward<Arg0>(arg0_));
}
template <
typename T,
std::enable_if_t<absl::conjunction<std::is_constructible<T, const Arg0&>,
initializer_internal::CanBindTo<
T&&, const Arg0&>>::value,
int> = 0>
T&& Reference() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
return std::forward<T>(
*absl::implicit_cast<std::remove_reference_t<T>*>(&arg0_));
}
template <
typename T,
std::enable_if_t<absl::conjunction<std::is_constructible<T, const Arg0&>,
initializer_internal::CanBindTo<
T&&, const Arg0&>>::value,
int> = 0>
T&& Reference(ABSL_ATTRIBUTE_UNUSED TemporaryStorage<T>&& storage)
const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
return Reference<T>();
}
template <typename T,
std::enable_if_t<absl::conjunction<
std::is_constructible<T, const Arg0&>,
absl::negation<initializer_internal::CanBindTo<
T&&, const Arg0&>>>::value,
int> = 0>
T&& Reference(TemporaryStorage<T>&& storage ABSL_ATTRIBUTE_LIFETIME_BOUND =
TemporaryStorage<T>()) const& {
return std::move(storage).emplace(arg0_);
}

template <typename T,
std::enable_if_t<
absl::conjunction<absl::negation<std::is_reference<T>>,
std::is_move_assignable<T>,
std::is_constructible<T, Arg0&&>>::value,
int> = 0>
friend void RiegeliReset(T& dest, MakerType&& src) {
riegeli::Reset(dest, std::forward<Arg0>(src.arg0_));
}
template <typename T,
std::enable_if_t<
absl::conjunction<absl::negation<std::is_reference<T>>,
std::is_move_assignable<T>,
std::is_constructible<T, const Arg0&>>::value,
int> = 0>
friend void RiegeliReset(T& dest, const MakerType& src) {
riegeli::Reset(dest, src.arg0_);
}

private:
ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS Arg0 arg0_;
};

// Support CTAD.
#if __cpp_deduction_guides
template <typename... Args>
Expand All @@ -353,10 +232,6 @@ class MakerTypeForBase
: public ConditionallyAssignable<absl::conjunction<
absl::negation<std::is_reference<Args>>...>::value> {
public:
// Make `MakerTypeFor<T>` trivially default constructible (for
// `TemporaryStorage` optimization).
MakerTypeForBase() = default;

// Constructs `MakerTypeFor` from `args...` convertible to `Args...`.
template <
typename... SrcArgs,
Expand Down

0 comments on commit 94ee17a

Please sign in to comment.