// Copyright 2019 Google LLC // // 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. // MakeCleanup(f) returns an RAII cleanup object that calls 'f' in its // destructor. The easiest way to use MakeCleanup is with a lambda argument, // capturing the return value in an 'auto' local variable. Most users will not // need more sophisticated syntax than that. // // Example: // void func() {} // FILE* fp = fopen("data.txt", "r"); // if (fp == nullptr) return; // auto fp_cleaner = absl::MakeCleanup([fp] { fclose(fp); }); // // No matter what, fclose(fp) will happen. // DataObject d; // while (ReadDataObject(fp, &d)) { // if (d.IsBad()) { // LOG(ERROR) << "Bad Data"; // return; // } // PushGoodData(d); // } // } // // You can use Cleanup directly, instead of using MakeCleanup and auto, // but there's rarely a reason to do that. // // You can call 'release()' on a Cleanup object to cancel the cleanup. // // Style exception for rvalue references: CL/62979921. // No NOLINT qualifiers, since cpplint's handling of && is imperfect. #ifndef DARWINN_PORT_DEFAULT_CLEANUP_H_ #define DARWINN_PORT_DEFAULT_CLEANUP_H_ #include #include #include "port/default/macros.h" namespace platforms { namespace darwinn { // A move-only RAII object that calls a stored cleanup functor when destroyed. // Cleanup is the return type of absl::MakeCleanup(F). template class Cleanup { public: Cleanup() : released_(true), f_() {} template explicit Cleanup(G&& f) // NOLINT : f_(std::forward(f)) {} // NOLINT(build/c++11) Cleanup(Cleanup&& src) // NOLINT : released_(src.is_released()), f_(src.release()) { } // Implicitly move-constructible from any compatible Cleanup. // The source will be released as if src.release() were called. // A moved-from Cleanup can be safely destroyed or reassigned. template Cleanup(Cleanup&& src) // NOLINT : released_(src.is_released()), f_(src.release()) { } // Assignment to a Cleanup object behaves like destroying it and making a new // one in its place, analogous to unique_ptr semantics. Cleanup& operator=(Cleanup&& src) { // NOLINT if (!released_) f_(); released_ = src.released_; f_ = src.release(); return *this; } ~Cleanup() { if (!released_) f_(); } // Releases the cleanup function instead of running it. // Hint: use c.release()() to run early. F release() { released_ = true; return std::move(f_); } bool is_released() const { return released_; } private: static_assert(!std::is_reference(), "F must not be a reference"); bool released_ = false; F f_; }; template ::type> ABSL_MUST_USE_RESULT Cleanup MakeCleanup(F&& f) { static_assert(sizeof...(ExplicitParameterBarrier) == 0, "No explicit template arguments."); return Cleanup(std::forward(f)); } } // namespace darwinn } // namespace platforms #endif // DARWINN_PORT_DEFAULT_CLEANUP_H_