1/* Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 3Licensed under the Apache License, Version 2.0 (the "License"); 4you may not use this file except in compliance with the License. 5You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9Unless required by applicable law or agreed to in writing, software 10distributed under the License is distributed on an "AS IS" BASIS, 11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12See the License for the specific language governing permissions and 13limitations under the License. 14==============================================================================*/ 15 16// MakeCleanup(f) returns an RAII cleanup object that calls 'f' in its 17// destructor. The easiest way to use MakeCleanup is with a lambda argument, 18// capturing the return value in an 'auto' local variable. Most users will not 19// need more sophisticated syntax than that. 20// 21// Example: 22// void func() {} 23// FILE* fp = fopen("data.txt", "r"); 24// if (fp == nullptr) return; 25// auto fp_cleaner = gtl::MakeCleanup([fp] { fclose(fp); }); 26// // No matter what, fclose(fp) will happen. 27// DataObject d; 28// while (ReadDataObject(fp, &d)) { 29// if (d.IsBad()) { 30// LOG(ERROR) << "Bad Data"; 31// return; 32// } 33// PushGoodData(d); 34// } 35// } 36// 37// You can use Cleanup<F> directly, instead of using MakeCleanup and auto, 38// but there's rarely a reason to do that. 39// 40// You can call 'release()' on a Cleanup object to cancel the cleanup. 41 42#ifndef TENSORFLOW_LIB_GTL_CLEANUP_H_ 43#define TENSORFLOW_LIB_GTL_CLEANUP_H_ 44 45#include <type_traits> 46#include <utility> 47 48#include "tensorflow/core/platform/macros.h" 49 50namespace tensorflow { 51namespace gtl { 52 53// A move-only RAII object that calls a stored cleanup functor when 54// destroyed. Cleanup<F> is the return type of gtl::MakeCleanup(F). 55template <typename F> 56class Cleanup { 57 public: 58 Cleanup() : released_(true), f_() {} 59 60 template <typename G> 61 explicit Cleanup(G&& f) // NOLINT 62 : f_(std::forward<G>(f)) {} // NOLINT(build/c++11) 63 64 Cleanup(Cleanup&& src) // NOLINT 65 : released_(src.is_released()), f_(src.release()) {} 66 67 // Implicitly move-constructible from any compatible Cleanup<G>. 68 // The source will be released as if src.release() were called. 69 // A moved-from Cleanup can be safely destroyed or reassigned. 70 template <typename G> 71 Cleanup(Cleanup<G>&& src) // NOLINT 72 : released_(src.is_released()), f_(src.release()) {} 73 74 // Assignment to a Cleanup object behaves like destroying it 75 // and making a new one in its place, analogous to unique_ptr 76 // semantics. 77 Cleanup& operator=(Cleanup&& src) { // NOLINT 78 if (!released_) f_(); 79 released_ = src.released_; 80 f_ = src.release(); 81 return *this; 82 } 83 84 ~Cleanup() { 85 if (!released_) f_(); 86 } 87 88 // Releases the cleanup function instead of running it. 89 // Hint: use c.release()() to run early. 90 F release() { 91 released_ = true; 92 return std::move(f_); 93 } 94 95 bool is_released() const { return released_; } 96 97 private: 98 static_assert(!std::is_reference<F>::value, "F must not be a reference"); 99 100 bool released_ = false; 101 F f_; 102}; 103 104template <int&... ExplicitParameterBarrier, typename F, 105 typename DecayF = typename std::decay<F>::type> 106TF_MUST_USE_RESULT Cleanup<DecayF> MakeCleanup(F&& f) { 107 return Cleanup<DecayF>(std::forward<F>(f)); 108} 109 110} // namespace gtl 111} // namespace tensorflow 112 113#endif // TENSORFLOW_LIB_GTL_CLEANUP_H_ 114