ChampSim
inf_stream.h
Go to the documentation of this file.
1 /*
2  * Copyright 2023 The ChampSim Contributors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INF_STREAM_H
18 #define INF_STREAM_H
19 
20 #include <bzlib.h>
21 #include <cassert>
22 #include <iostream>
23 #include <lzma.h>
24 #include <memory>
25 #include <zlib.h>
26 
27 namespace champsim
28 {
29 namespace decomp_tags
30 {
31 enum class status_t { CAN_CONTINUE, END, ERROR };
32 
33 namespace detail
34 {
35 template <typename State, typename R, R (*Del)(State*)>
36 struct end_deleter {
37  void operator()(State* s)
38  {
39  Del(s);
40  delete s;
41  }
42 };
43 } // namespace detail
44 
45 struct bzip2_tag_t {
46  using state_type = bz_stream;
47  using in_char_type = std::remove_pointer_t<decltype(state_type::next_in)>;
48  using out_char_type = std::remove_pointer_t<decltype(state_type::next_out)>;
49  using deflate_state_type = std::unique_ptr<state_type, detail::end_deleter<state_type, int, ::BZ2_bzCompressEnd>>;
50  using inflate_state_type = std::unique_ptr<state_type, detail::end_deleter<state_type, int, ::BZ2_bzDecompressEnd>>;
52 
53  static status_type deflate(deflate_state_type& x, bool flush)
54  {
55  auto ret = ::BZ2_bzCompress(x.get(), flush ? BZ_FLUSH : BZ_RUN);
56  if (ret == BZ_RUN_OK)
57  return status_type::CAN_CONTINUE;
58  if (ret == BZ_FLUSH_OK)
59  return status_type::END;
60  return status_type::ERROR;
61  }
62 
64  {
65  ::BZ2_bzDecompress(x.get());
66  return status_type::CAN_CONTINUE;
67  }
68 
70  {
71  deflate_state_type state{new state_type};
72  *state = state_type{NULL, 0u, 0u, 0u, NULL, 0u, 0u, 0u, NULL, NULL, NULL, NULL};
73  ::BZ2_bzCompressInit(state.get(), 9, 0, 0);
74  return state;
75  }
76 
78  {
79  inflate_state_type state{new state_type};
80  *state = state_type{NULL, 0u, 0u, 0u, NULL, 0u, 0u, 0u, NULL, NULL, NULL, NULL};
81  ::BZ2_bzDecompressInit(state.get(), 0, 0);
82  return state;
83  }
84 };
85 
86 template <int window = 15 + 16, int compression = Z_DEFAULT_COMPRESSION>
87 struct gzip_tag_t {
88  using state_type = z_stream;
89  using in_char_type = std::remove_pointer_t<decltype(state_type::next_in)>;
90  using out_char_type = std::remove_pointer_t<decltype(state_type::next_out)>;
91  using deflate_state_type = std::unique_ptr<state_type, detail::end_deleter<state_type, int, ::deflateEnd>>;
92  using inflate_state_type = std::unique_ptr<state_type, detail::end_deleter<state_type, int, ::inflateEnd>>;
94 
95  static status_type deflate(deflate_state_type& x, bool flush)
96  {
97  auto ret = ::deflate(x.get(), flush ? Z_FINISH : Z_NO_FLUSH);
98  if (ret == Z_OK)
99  return status_type::CAN_CONTINUE;
100  if (ret == Z_STREAM_END)
101  return status_type::END;
102  return status_type::ERROR;
103  }
104 
106  {
107  ::inflate(x.get(), Z_BLOCK);
108  return status_type::CAN_CONTINUE;
109  }
110 
112  {
113  deflate_state_type state{new state_type};
114  *state = state_type{Z_NULL, 0, 0, Z_NULL, 0, 0, NULL, NULL, Z_NULL, Z_NULL, Z_NULL, 0, 0ul, 0ul};
115  ::deflateInit(state.get(), compression);
116  return state;
117  }
118 
120  {
121  inflate_state_type state{new state_type};
122  *state = state_type{Z_NULL, 0, 0, Z_NULL, 0, 0, NULL, NULL, Z_NULL, Z_NULL, Z_NULL, 0, 0ul, 0ul};
123  ::inflateInit2(state.get(), window);
124  return state;
125  }
126 };
127 
128 template <uint32_t flags = 0>
129 struct lzma_tag_t {
130  using state_type = lzma_stream;
131  using in_char_type = std::remove_const_t<std::remove_pointer_t<decltype(state_type::next_in)>>;
132  using out_char_type = std::remove_pointer_t<decltype(state_type::next_out)>;
133  using deflate_state_type = std::unique_ptr<state_type, detail::end_deleter<state_type, void, ::lzma_end>>;
134  using inflate_state_type = std::unique_ptr<state_type, detail::end_deleter<state_type, void, ::lzma_end>>;
136 
137  static status_type deflate(deflate_state_type& x, bool flush)
138  {
139  auto ret = ::lzma_code(x.get(), flush ? LZMA_FULL_FLUSH : LZMA_RUN);
140  if (ret == LZMA_OK)
141  return status_type::CAN_CONTINUE;
142  else if (ret == LZMA_STREAM_END)
143  return status_type::END;
144  else
145  return status_type::ERROR;
146  }
147 
149  {
150  auto ret = ::lzma_code(x.get(), LZMA_RUN);
151  if (ret == LZMA_OK)
152  return status_type::CAN_CONTINUE;
153  else if (ret == LZMA_STREAM_END)
154  return status_type::END;
155  else
156  return status_type::ERROR;
157  }
158 
160  {
161  deflate_state_type state{new state_type};
162  *state = LZMA_STREAM_INIT;
163  auto ret = ::lzma_easy_encoder(state.get(), LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
164  assert(ret == LZMA_OK);
165  return state;
166  }
167 
169  {
170  inflate_state_type state{new state_type};
171  *state = LZMA_STREAM_INIT;
172  auto ret = ::lzma_stream_decoder(state.get(), std::numeric_limits<uint64_t>::max(), flags);
173  assert(ret == LZMA_OK);
174  return state;
175  }
176 };
177 } // namespace decomp_tags
178 
179 template <typename Tag, typename StreamType = std::ifstream>
180 struct inf_istream {
181  template <typename IStrm>
182  class inf_streambuf : public std::basic_streambuf<typename IStrm::char_type, std::char_traits<typename IStrm::char_type>>
183  {
184  private:
185  using base_type = std::basic_streambuf<typename IStrm::char_type, std::char_traits<typename IStrm::char_type>>;
186  using int_type = typename base_type::int_type;
187  using char_type = typename base_type::char_type;
188  using strm_in_buf_type = typename Tag::in_char_type;
189  using strm_out_buf_type = typename Tag::out_char_type;
190 
191  constexpr static std::size_t CHUNK = (1 << 16);
192 
193  std::array<strm_in_buf_type, CHUNK> in_buf;
194  std::array<char_type, CHUNK> out_buf;
195  typename Tag::inflate_state_type strm = Tag::new_inflate_state();
196  typename std::add_pointer<IStrm>::type src;
197 
198  public:
199  explicit inf_streambuf(IStrm* in) : src(in) {}
200  explicit inf_streambuf(Tag, IStrm* in) : inf_streambuf(in) {}
201 
202  std::size_t bytes_read() const { return strm->total_out - (this->egptr() - this->gptr()); }
203 
204  protected:
205  int_type underflow() override;
206  };
207 
208  std::unique_ptr<StreamType> underlying;
209  std::unique_ptr<inf_streambuf<StreamType>> buffer = std::make_unique<inf_streambuf<StreamType>>(underlying.get());
210  std::streamsize gcount_ = 0;
211  bool eof_ = false;
212 
213  inf_istream& read(char* s, std::streamsize count)
214  {
215  std::istream inflated{buffer.get()};
216  inflated.read(s, count);
217  gcount_ = inflated.gcount();
218  eof_ = inflated.eof();
219  return *this;
220  }
221 
222  bool eof() const { return eof_; }
223  std::streamsize gcount() const { return gcount_; }
224 
225  explicit inf_istream(std::string s) : underlying(std::make_unique<StreamType>(s)) {}
226  explicit inf_istream(StreamType&& str) : underlying(std::make_unique<StreamType>(std::move(str))) {}
227 };
228 
229 template <typename T, typename S>
230 template <typename I>
232 {
233  std::array<strm_out_buf_type, std::tuple_size<decltype(out_buf)>::value> uns_out_buf;
234 
235  strm->avail_out = uns_out_buf.size();
236  strm->next_out = uns_out_buf.data();
237  do {
238  // Check to see if we have consumed all available input
239  if (strm->avail_in == 0) {
240  // Check to see if the input stream is sane
241  if (src->fail()) {
242  this->setg(this->out_buf.data(), this->out_buf.data(), this->out_buf.data());
243  return base_type::underflow();
244  }
245 
246  // Read data from the stream and convert to zlib-appropriate format
247  std::array<char_type, std::tuple_size<decltype(in_buf)>::value> sig_in_buf;
248  src->read(sig_in_buf.data(), sig_in_buf.size());
249  auto bytes_read = src->gcount();
250  assert(bytes_read >= 0);
251  std::memcpy(in_buf.data(), sig_in_buf.data(), static_cast<std::size_t>(src->gcount()));
252 
253  // Record that bytes are available in in_buf
254  strm->avail_in = static_cast<unsigned>(src->gcount());
255  strm->next_in = in_buf.data();
256 
257  // If we failed to get any data
258  if (strm->avail_in == 0) {
259  this->setg(this->out_buf.data(), this->out_buf.data(), this->out_buf.data());
260  return base_type::underflow();
261  }
262  }
263 
264  // Perform inflation
265  auto result = T::inflate(strm);
266  assert(result == T::status_type::CAN_CONTINUE || result == T::status_type::END);
267  }
268  // Repeat until we actually get new output
269  while (strm->avail_out == uns_out_buf.size());
270 
271  // Copy into a format appropriate for the stream
272  std::memcpy(this->out_buf.data(), uns_out_buf.data(), uns_out_buf.size() - strm->avail_out);
273 
274  auto bytes_remaining = std::size(uns_out_buf) - strm->avail_out;
275  assert(bytes_remaining <= std::numeric_limits<std::make_signed_t<decltype(bytes_remaining)>>::max());
276  this->setg(this->out_buf.data(), this->out_buf.data(),
277  std::next(this->out_buf.data(), static_cast<std::make_signed_t<decltype(bytes_remaining)>>(bytes_remaining)));
278  return base_type::traits_type::to_int_type(this->out_buf.front());
279 }
280 } // namespace champsim
281 
282 #endif
Definition: inf_stream.h:183
std::size_t bytes_read() const
Definition: inf_stream.h:202
int_type underflow() override
Definition: inf_stream.h:231
inf_streambuf(IStrm *in)
Definition: inf_stream.h:199
typename base_type::char_type char_type
Definition: inf_stream.h:187
inf_streambuf(Tag, IStrm *in)
Definition: inf_stream.h:200
typename Tag::out_char_type strm_out_buf_type
Definition: inf_stream.h:189
typename Tag::in_char_type strm_in_buf_type
Definition: inf_stream.h:188
Tag::inflate_state_type strm
Definition: inf_stream.h:195
std::array< char_type, CHUNK > out_buf
Definition: inf_stream.h:194
constexpr static std::size_t CHUNK
Definition: inf_stream.h:191
typename base_type::int_type int_type
Definition: inf_stream.h:186
std::basic_streambuf< typename IStrm::char_type, std::char_traits< typename IStrm::char_type > > base_type
Definition: inf_stream.h:185
std::add_pointer< IStrm >::type src
Definition: inf_stream.h:196
std::array< strm_in_buf_type, CHUNK > in_buf
Definition: inf_stream.h:193
status_t
Definition: inf_stream.h:31
Definition: champsim.h:24
Definition: inf_stream.h:45
std::unique_ptr< state_type, detail::end_deleter< state_type, int, ::BZ2_bzCompressEnd > > deflate_state_type
Definition: inf_stream.h:49
static status_type deflate(deflate_state_type &x, bool flush)
Definition: inf_stream.h:53
std::remove_pointer_t< decltype(state_type::next_in)> in_char_type
Definition: inf_stream.h:47
static status_type inflate(inflate_state_type &x)
Definition: inf_stream.h:63
static deflate_state_type new_deflate_state()
Definition: inf_stream.h:69
std::unique_ptr< state_type, detail::end_deleter< state_type, int, ::BZ2_bzDecompressEnd > > inflate_state_type
Definition: inf_stream.h:50
std::remove_pointer_t< decltype(state_type::next_out)> out_char_type
Definition: inf_stream.h:48
static inflate_state_type new_inflate_state()
Definition: inf_stream.h:77
bz_stream state_type
Definition: inf_stream.h:46
void operator()(State *s)
Definition: inf_stream.h:37
Definition: inf_stream.h:87
static status_type inflate(inflate_state_type &x)
Definition: inf_stream.h:105
std::remove_pointer_t< decltype(state_type::next_out)> out_char_type
Definition: inf_stream.h:90
static inflate_state_type new_inflate_state()
Definition: inf_stream.h:119
std::unique_ptr< state_type, detail::end_deleter< state_type, int, ::inflateEnd > > inflate_state_type
Definition: inf_stream.h:92
std::unique_ptr< state_type, detail::end_deleter< state_type, int, ::deflateEnd > > deflate_state_type
Definition: inf_stream.h:91
static deflate_state_type new_deflate_state()
Definition: inf_stream.h:111
z_stream state_type
Definition: inf_stream.h:88
static status_type deflate(deflate_state_type &x, bool flush)
Definition: inf_stream.h:95
std::remove_pointer_t< decltype(state_type::next_in)> in_char_type
Definition: inf_stream.h:89
Definition: inf_stream.h:129
std::remove_pointer_t< decltype(state_type::next_out)> out_char_type
Definition: inf_stream.h:132
std::remove_const_t< std::remove_pointer_t< decltype(state_type::next_in)> > in_char_type
Definition: inf_stream.h:131
std::unique_ptr< state_type, detail::end_deleter< state_type, void, ::lzma_end > > inflate_state_type
Definition: inf_stream.h:134
static status_type deflate(deflate_state_type &x, bool flush)
Definition: inf_stream.h:137
static deflate_state_type new_deflate_state()
Definition: inf_stream.h:159
lzma_stream state_type
Definition: inf_stream.h:130
static status_type inflate(inflate_state_type &x)
Definition: inf_stream.h:148
static inflate_state_type new_inflate_state()
Definition: inf_stream.h:168
std::unique_ptr< state_type, detail::end_deleter< state_type, void, ::lzma_end > > deflate_state_type
Definition: inf_stream.h:133
Definition: inf_stream.h:180
inf_istream(StreamType &&str)
Definition: inf_stream.h:226
inf_istream(std::string s)
Definition: inf_stream.h:225
bool eof() const
Definition: inf_stream.h:222
std::unique_ptr< StreamType > underlying
Definition: inf_stream.h:208
std::streamsize gcount() const
Definition: inf_stream.h:223
std::streamsize gcount_
Definition: inf_stream.h:210
bool eof_
Definition: inf_stream.h:211
std::unique_ptr< inf_streambuf< StreamType > > buffer
Definition: inf_stream.h:209
inf_istream & read(char *s, std::streamsize count)
Definition: inf_stream.h:213