No-op; fix GPL address and use the explicit-program-name version.
[dcpomatic.git] / src / lib / safe_stringstream.h
1 /*
2     Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #ifndef DCPOMATIC_SAFE_STRINGSTREAM_H
22 #define DCPOMATIC_SAFE_STRINGSTREAM_H
23
24 #include <boost/thread/mutex.hpp>
25
26 /* I've not been able to reproduce it, but there have been reports that DCP-o-matic crashes
27  * on OS X with two simultaneous backtraces that look like this:
28  *
29  * 0 libSystem.B.dylib  0x00007fff84ebe264 __numeric_load_locale + 125
30  * 1 libSystem.B.dylib  0x00007fff84e2aac4 loadlocale + 323
31  * 2 libstdc++.6.dylib  0x00007fff8976ba69 std::__convert_from_v(int* const&, char*, int, char const*, ...) + 199
32  * 3 libstdc++.6.dylib  0x00007fff8974e99b std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char,
33 std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const + 199
34  * 4 libstdc++.6.dylib  0x00007fff8974ebc0 std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> >
35 >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const + 28
36  * 5 libstdc++.6.dylib  0x00007fff897566a2 std::ostream& std::ostream::_M_insert<double>(double) + 178
37  * 6 libdcpomatic.dylib 0x0000000100331e21 StringPrivate::Composition& StringPrivate::Composition::arg<float>(float const&) + 33
38  *
39  * in two different threads.  I'm assuming that for some bizarre reason it is unsafe to use two separate stringstream
40  * objects in different threads on OS X.  This is a hack to work around it.
41  */
42
43 class SafeStringStream
44 {
45 public:
46         SafeStringStream ()
47         {}
48
49         SafeStringStream (std::string s)
50                 : _stream (s)
51         {}
52
53         template <class T>
54         std::ostream& operator<< (T val)
55         {
56                 boost::mutex::scoped_lock lm (_mutex);
57                 _stream << val;
58                 return _stream;
59         }
60
61         template <class T>
62         std::istream& operator>> (T& val)
63         {
64                 boost::mutex::scoped_lock lm (_mutex);
65                 _stream >> val;
66                 return _stream;
67         }
68
69         std::string str () const {
70                 return _stream.str ();
71         }
72
73         void str (std::string const & s) {
74                 _stream.str (s);
75         }
76
77         void imbue (std::locale const & loc)
78         {
79                 boost::mutex::scoped_lock lm (_mutex);
80                 _stream.imbue (loc);
81         }
82
83         void width (int w)
84         {
85                 _stream.width (w);
86         }
87
88         void fill (int f)
89         {
90                 _stream.fill (f);
91         }
92
93         void precision (int p)
94         {
95                 _stream.precision (p);
96         }
97
98         bool good () const
99         {
100                 return _stream.good ();
101         }
102
103         std::string getline ()
104         {
105                 boost::mutex::scoped_lock lm (_mutex);
106                 std::string s;
107                 std::getline (_stream, s);
108                 return s;
109         }
110
111         void setf (std::ios_base::fmtflags flags, std::ios_base::fmtflags mask)
112         {
113                 _stream.setf (flags, mask);
114         }
115
116 private:
117         static boost::mutex _mutex;
118         std::stringstream _stream;
119 };
120
121 #endif