1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #ifndef Toolbox_h
27 #define Toolbox_h
28 
29 
30 #include <algorithm>
31 #include "tstrings.h"
32 
33 
34 /**
35  * Placeholder for API not falling into any particular category.
36  */
37 
38 
39 
40 struct deletePtr {
41     template <class PtrT>
operatordeletePtr42     void operator () (PtrT ptr) const {
43         delete ptr;
44     }
45 };
46 
47 
48 /**
49  * Deletes all pointers in the given range of items.
50  */
51 template <class It>
deleteAll(It b,It e)52 void deleteAll(It b, It e) {
53     std::for_each(b, e, deletePtr());
54 }
55 
56 /**
57  * Deletes all pointers from the container.
58  */
59 template <class Ctnr>
deleteAll(Ctnr & ctnr)60 void deleteAll(Ctnr& ctnr) {
61     deleteAll(std::begin(ctnr), std::end(ctnr));
62 }
63 
64 
65 /**
66  * Applies std::for_each() to the given object that has begin() and end()
67  * methods.
68  */
69 template <class Ctnr, class Fn>
forEach(Ctnr & ctnr,Fn fn)70 void forEach(Ctnr& ctnr, Fn fn) {
71     std::for_each(std::begin(ctnr), std::end(ctnr), fn);
72 }
73 
74 template <class Ctnr, class Fn>
forEach(const Ctnr & ctnr,Fn fn)75 void forEach(const Ctnr& ctnr, Fn fn) {
76     std::for_each(std::begin(ctnr), std::end(ctnr), fn);
77 }
78 
79 
80 /**
81  * Runs the given functor from destructor. Don't use directly.
82  * This is just a helper for runAtEndOfScope().
83  */
84 template <class Fn>
85 class AtEndOfScope {
86     Fn func;
87     bool theAbort;
88 public:
AtEndOfScope(Fn f)89     explicit AtEndOfScope(Fn f): func(f), theAbort(false) {
90     }
~AtEndOfScope()91     ~AtEndOfScope() {
92         if (!theAbort) {
93             JP_NO_THROW(func());
94         }
95     }
96     void abort(bool v=true) {
97         theAbort = v;
98     }
99 };
100 
101 /**
102  * Helper to create AtEndOfScope instance without need to
103  * specify template type explicitly. Like std::make_pair to construct
104  * std::pair instance.
105  *
106  * Use case:
107  * Say you need to call a function (foo()) at exit from another
108  * function (bar()).
109  * You will normally do:
110  *  void bar() {
111  *    workload();
112  *    foo();
113  *  }
114  *
115  * If workload() can throw exceptions things become little bit more
116  * complicated:
117  *  void bar() {
118  *    JP_NO_THROW(workload());
119  *    foo();
120  *  }
121  *
122  * If there is branching in bar() it is little bit more complicated again:
123  *  int bar() {
124  *    if (...) {
125  *      JP_NO_THROW(workload());
126  *      foo();
127  *      return 0;
128  *    }
129  *    if (...) {
130  *      JP_NO_THROW(workload2());
131  *      foo();
132  *      return 1;
133  *    }
134  *    foo();
135  *    return 2;
136  *  }
137  *
138  * So for relatively complex bar() this approach will end up with
139  * missing foo() call. The standard solution to avoid errors like this,
140  * is to call foo() from some object's destructor, i.e. delegate
141  * responsibility to ensure it is always called to compiler:
142  *
143  * struct FooCaller {
144  *     ~FooCaller() { JP_NO_THROW(foo()); }
145  * };
146  *
147  *  int bar() {
148  *    FooCaller fooCaller;
149  *    if (...) {
150  *      JP_NO_THROW(workload());
151  *      return 0;
152  *    }
153  *    if (...) {
154  *      JP_NO_THROW(workload2());
155  *      foo();
156  *    }
157  *    return 2;
158  *  }
159  *
160  * However it is annoying to explicitly create FooCaller-like types
161  * for tasks like this. Use of runAtEndOfScope() saves you from this:
162  *
163  *  int bar() {
164  *    const auto fooCaller = runAtEndOfScope(foo);
165  *    if (...) {
166  *      JP_NO_THROW(workload());
167  *      return 0;
168  *    }
169  *    if (...) {
170  *      JP_NO_THROW(workload2());
171  *      foo();
172  *    }
173  *    return 2;
174  *  }
175  *
176  */
177 template <class Fn>
runAtEndOfScope(Fn func)178 AtEndOfScope<Fn> runAtEndOfScope(Fn func) {
179     return AtEndOfScope<Fn>(func);
180 }
181 
182 #endif // #ifndef Toolbox_h
183