ALPSCore reference
format.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1998-2018 ALPS Collaboration. See COPYRIGHT.TXT
3  * All rights reserved. Use is subject to license terms. See LICENSE.TXT
4  * For use in publications, see ACKNOWLEDGE.TXT
5  */
6 #pragma once
7 
8 #include <cassert>
9 #include <ostream>
10 #include <memory>
11 
12 namespace alps { namespace alea { namespace internal {
13  class format_sentry;
14  template <typename T> class format_registry;
15 }}}
16 
17 namespace alps { namespace alea { namespace internal {
18 
33 {
34 public:
35  explicit format_sentry(std::ostream &str)
36  : stream_(str)
37  , saved_(nullptr)
38  {
39  // save all flags to auxiliary ios_base instance
40  saved_.copyfmt(stream_);
41  }
42 
44  {
45  // restore flags
46  stream_.copyfmt(saved_);
47  }
48 
49  std::ios::fmtflags saved_flags() const { return saved_.flags(); }
50 
51  std::ostream &stream() { return stream_; }
52 
53  const std::ostream &stream() const { return stream_; }
54 
55 private:
56  // make it non-copyable and -movable
57  format_sentry(const format_sentry &) = delete;
58  format_sentry &operator=(const format_sentry &) = delete;
59 
60  std::ostream &stream_;
61  std::ios saved_;
62 };
63 
89 template <typename T>
90 T &get_format(std::ios_base &stream, T initial_value = T())
91 {
92  return format_registry<T>::get(stream, initial_value);
93 }
94 
105 template <typename T>
106 class format_registry
107 {
108 public:
110  static T &get(std::ios_base &stream, T init = T())
111  {
112  T *&format = get_format(stream);
113 
114  // if format is not there, we should add it
115  if (format == nullptr) {
116  format = new T(init); // must be copy constructible
117  stream.register_callback(callback, get_xindex());
118  }
119  return *format;
120  }
121 
123  static void remove(std::ios_base &stream)
124  {
125  callback(std::ios::erase_event, stream, get_xindex());
126  }
127 
128 protected:
130  static void callback(std::ios::event event, std::ios_base &stream,
131  int xindex)
132  {
133  if (xindex != get_xindex()) { assert(false); }
134  T *&self = get_format(stream);
135 
136  switch (event) {
137  case std::ios::erase_event:
138  // this will be called in destructor, so we MUST NOT throw
139  // exceptions
140  delete self;
141  self = nullptr;
142  break;
143 
144  case std::ios::copyfmt_event:
145  // copyfmt first triggers an erase_event, which we use to clean up
146  // the memory, then does a shallow copy, and then triggers this
147  // event. This means that self here will point to the original
148  // instance.
149  self = new T(*self);
150  break;
151 
152  case std::ios::imbue_event:
153  // FIXME
154  break;
155  }
156  }
157 
158  static T *& get_format(std::ios_base &stream)
159  {
160  return reinterpret_cast<T *&>(stream.pword(get_xindex()));
161  }
162 
163  static int get_xindex()
164  {
165  // guaranteed to be distinct since for different iomanip's since their
166  // T will be different. xalloc is threadsafe from C++14 onwards, however
167  // C++11 guarantees that static initialization is threadsafe, so we're
168  // fine.
169  static int xindex = std::ios_base::xalloc();
170  return xindex;
171  }
172 
173 private:
174  format_registry() = delete;
175 };
176 
177 
178 // explicitly disallow some built-in types
179 
180 template <> class format_registry<char> { };
181 template <> class format_registry<bool> { };
182 template <> class format_registry<short> { };
183 template <> class format_registry<unsigned short> { };
184 template <> class format_registry<int> { };
185 template <> class format_registry<unsigned int> { };
186 template <> class format_registry<long> { };
187 template <> class format_registry<unsigned long> { };
188 template <> class format_registry<float> { };
189 template <> class format_registry<double> { };
190 
191 }}}
std::ios::fmtflags saved_flags() const
Definition: format.hpp:49
static void callback(std::ios::event event, std::ios_base &stream, int xindex)
Definition: format.hpp:130
T & get_format(std::ios_base &stream, T initial_value=T())
Definition: format.hpp:90
const std::ostream & stream() const
Definition: format.hpp:53
format_sentry(std::ostream &str)
Definition: format.hpp:35
static T *& get_format(std::ios_base &stream)
Definition: format.hpp:158
static T & get(std::ios_base &stream, T init=T())
Definition: format.hpp:110