summaryrefslogtreecommitdiff
path: root/tiger-compiler/lib/misc/xalloc.hh
blob: 1d819ef6c232d94a6e80caf796c565d52644b1c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/**
 ** \file misc/xalloc.hh
 ** \brief Declaration of misc::xalloc.
 **/

#pragma once

#include <functional>
#include <iostream>

namespace misc
{
  /// Defines the operator() for the classes get_type, set_type and swap_type.
  struct iomanipulator
  {
    virtual ~iomanipulator() = default;
    virtual void operator()(std::ostream& o) const = 0;
  };

  /** \brief Launch the iomanipulator action on o.
   **
   ** Call the operator() of g (so set, get or swap the
   ** xalloced data with data_).
   */
  std::ostream& operator<<(std::ostream& o, const iomanipulator& g);

  /** \brief Allocate slots in std::ostreams.
   **
   ** Used to store flags in streams so that calling print
   ** with additional parameters is no longer required (for
   ** example in ast/libast.hh).
   **
   ** Set, get or swap data.
   ** The idea is to build the right inner class with set, get or
   ** swap methods, then use this class as a parameter of operator<<.
   **
   ** `StoredType` must be `CopyConstructible`. If it's not
   ** `DefaultConstructible`, then arguments for its constructor are
   ** to be passed to the `xalloc` constructor.
   */
  template <class StoredType> class xalloc
  {
  private:
    /** \brief Handle the data to put in the xalloced place.
     **
     ** This inner class is used only with the set method.
     */
    class set_type : public iomanipulator
    {
    public:
      /// Set data_ to data.
      set_type(const xalloc& slot, StoredType& data);
      /// Set the data in the xalloced place.
      void operator()(std::ostream& ostr) const override;

    private:
      /// The xalloced data.
      const xalloc& slot_;
      /// Data to put in the stream.
      StoredType& data_;
    };

    /** \brief Handle the data to get from the xalloced place.
     **
     ** This inner class is used only with the get method.
     */
    class get_type : public iomanipulator
    {
    public:
      /// Set data_ to data.
      get_type(const xalloc& slot, StoredType& data);

      /// Get the data from the xalloced place.
      void operator()(std::ostream& ostr) const override;

    private:
      /// The xalloced data.
      const xalloc& slot_;
      /// Variable in which we return the xalloc data.
      StoredType& data_;
    };

    /** \brief Swap the data stored in the stream for a given one.
     **
     ** This inner class is used only with the swap method.
     */
    class swap_type : public iomanipulator
    {
    public:
      /// Set data_ to data.
      swap_type(const xalloc& slot, StoredType& data);

      /// Swap the data from the xalloced place for a given one.
      void operator()(std::ostream& ostr) const override;

    private:
      /// The xalloced data.
      const xalloc& slot_;
      /// Variable in which we store the data to be swapped.
      StoredType& data_;
    };

    /// The index of the slot.
    const long int index_;
    // The model that is used to create new instances.
    const StoredType model_;

  public:
    /// Allocates the slot.
    template <typename... Args> xalloc(Args&&... args);

    static void
    deallocate(std::ios_base::event type, std::ios_base& ios, int index);

    /// The xalloc index.
    long int index() const;
    /// The stored data as an lvalue.
    StoredType& operator()(std::ostream& ostr) const;

    /// A setter.
    /// \param data where to find the value when the setter is executed.
    set_type set(StoredType& data) const;

    /// A getter.
    /// \param data where to store the value when the getter is executed.
    get_type get(StoredType& data) const;

    /// A swapper.
    /// \param data value to exchange when the swapper is executed.
    swap_type swap(StoredType& data) const;
  };

} // namespace misc

#include <misc/xalloc.hxx>