// Copyright 2004-present Facebook. All Rights Reserved. #pragma once #include namespace facebook::gorilla { #pragma region out // Adaptation of c#'s out keyword in c++ // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier // // Instead of passing a parameter by reference for output, we pass it by // this "out" struct instead. Both the method declaration and the caller // needs to explicitly write "out" in the code, so there is less chance // of confussion. // // Example: // // void getString(out output) { // output = "This is the Output"; // } // // std::string stringOutput; // getString(out(stringOutput)); // template class InOutBase { public: explicit InOutBase(T& item) : item_(&item) {} InOutBase(T&& item) = delete; InOutBase() = delete; InOutBase(const InOutBase& other) = default; InOutBase(InOutBase&& other) noexcept = default; T& Item() { return *item_; } operator T&() { return Item(); } #pragma region OperatorForwarding public: // todo(widagdos): forward all operators template [[nodiscard]] bool operator==(const TOther& rhs) const { return *item_ == rhs; } template [[nodiscard]] bool operator!=(const TOther& rhs) const { return *item_ != rhs; } Tcrtp operator+() const { *item_ = +item_; return *this; } Tcrtp operator-() const { *item_ = -item_; return *this; } template auto operator+(const TOther& t2) const { return *item_ + t2; } template auto operator-(const TOther& t2) const { return *item_ - t2; } template auto operator*(const TOther& t2) const { return *item_ * t2; } template auto operator/(const TOther& t2) const { return *item_ / t2; } template auto operator%(const TOther& t2) const { return *item_ % t2; } template auto operator|(const TOther& t2) const { return *item_ | t2; } template auto operator&(const TOther& t2) const { return *item_ & t2; } template auto operator^(const TOther& t2) const { return *item_ ^ t2; } template Tcrtp operator+=(const TOther& t2) { *item_ += t2; return static_cast(*this); } template Tcrtp operator-=(const TOther& t2) { *item_ -= t2; return static_cast(*this); } template Tcrtp operator*=(const TOther& t2) { *item_ *= t2; return static_cast(*this); } template Tcrtp operator/=(const TOther& t2) { *item_ /= t2; return static_cast(*this); } template Tcrtp operator%=(const TOther& t2) { *item_ %= t2; return static_cast(*this); } template Tcrtp operator&=(const TOther& t2) { *item_ &= t2; return static_cast(*this); } template Tcrtp operator|=(const TOther& t2) { *item_ |= t2; return static_cast(*this); } template Tcrtp operator^=(const TOther& t2) { *item_ ^= t2; } template auto& operator[](TOther&& other) { return (*item_)[std::forward(other)]; } #pragma endregion OperatorForwarding #pragma region StringForwarding public: auto begin() { return item_->begin(); } auto end() { return item_->end(); } auto begin() const { return item_->begin(); } auto end() const { return item_->end(); } auto& at(size_t pos) { return item_->at(pos); } auto& operator[](size_t pos) { return (*item_)[pos]; } auto empty() const { return item_->empty(); } auto size() const { return item_->size(); } auto max_size() const { return item_->max_size(); } auto reserve(size_t capacity) { return item_->reserve(capacity); } auto capacity() const { return item_->capacity(); } auto resize(size_t capacity) { return item_->resize(capacity); } template Tcrtp append(const TOther& other) { item_->append(other); return static_cast(*this); } template void push_back(const TOther& other) { item_->push_back(other); } #pragma endregion StringForwarding protected: // This cannot be reference since we enable this error: // binding reference member 'item_' to stack allocated parameter 'item' // [-Werror,-Wdangling-field] T* item_; }; // Adaptation of c# out keyword template class out : public InOutBase, T> { public: explicit out(T& item) : InOutBase, T>(item) {} out(T&& item) = delete; out() = delete; out(const out& other) = default; out(out&& other) noexcept = default; out& operator=(const T& a) { *InOutBase, T>::item_ = a; return *this; } out& operator=(T&& a) { *InOutBase, T>::item_ = std::move(a); return *this; } void PrintTo(const out& item, std::ostream* os); }; // // Adaptation of c# ref keyword template class inout : public InOutBase, T> { public: explicit inout(T& item) : InOutBase, T>(item) {} inout(T&& item) = delete; inout() = delete; inout(const inout& other) = default; inout(inout&& other) noexcept = default; inout& operator=(const T& a) { *InOutBase, T>::item_ = a; return *this; } inout& operator=(T&& a) { *InOutBase, T>::item_ = std::move(a); return *this; } }; template inline std::ostream& operator<<(std::ostream& os, const out& item) { os << (T&)item; return os; } template inline std::ostream& operator<<(std::ostream& os, const inout& item) { os << (T&)item; return os; } template inline void PrintTo(const out& item, std::ostream* os) { *os << (T&)item; } #pragma endregion out } // namespace facebook::gorilla int main() { return 0; }