libzypp  17.38.7
DrunkenBishop.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
11 #include <cstdint>
12 #include <iostream>
13 
14 #include "DrunkenBishop.h"
15 
16 //#include <zypp-core/base/LogTools.h>
17 #include <zypp-core/base/Flags.h>
18 #include <zypp-core/base/String.h>
20 
21 
22 using std::endl;
23 
25 namespace zypp
26 {
28  namespace base
29  {
31  namespace
32  {
34  enum class Direction : std::uint8_t // actually 2 bits
35  {
36  NW = 0x0,
37  NE = 0x1,
38  SW = 0x2,
39  SE = 0x3,
40  };
41 
45  inline std::uint8_t hexDigit( char ch_r )
46  {
47  switch ( ch_r )
48  {
49  case 'F': case 'f': return 15;
50  case 'E': case 'e': return 14;
51  case 'D': case 'd': return 13;
52  case 'C': case 'c': return 12;
53  case 'B': case 'b': return 11;
54  case 'A': case 'a': return 10;
55  case '9': return 9;
56  case '8': return 8;
57  case '7': return 7;
58  case '6': return 6;
59  case '5': return 5;
60  case '4': return 4;
61  case '3': return 3;
62  case '2': return 2;
63  case '1': return 1;
64  case '0': return 0;
65  }
66  throw std::invalid_argument( str::Str() << "Not a hex digit '" << ch_r << "'" );
67  }
68  } // namespace
70 
76  {
77  public:
79  Impl()
80  : _h( 0U )
81  , _w( 0u )
82  , _s( 0U )
83  , _e( 0U )
84  , _renderSSH( true )
85  {}
86 
90  void compute( const std::string & data_r, const std::string & title_r, unsigned height_r = Auto, unsigned width_r = Auto )
91  {
92  // store rendering details
93  _renderSSH = ( data_r.size() <= 32 ); // up to the ssh fingerprint size
94  _fp = str::toUpper( data_r.size() <= 8 ? data_r : data_r.substr( data_r.size()-8 ) );
95  _tt = title_r;
96 
97  // init the board
98  _h = odd(height_r);
99  _w = odd(width_r);
100 
101  if ( _h == Auto )
102  {
103  if ( _renderSSH )
104  { _w = 17; _h = 9; }
105  else
106  { _w = 19; _h = 11; }
107  }
108  else if ( _w == Auto )
109  {
110  _w = (2*_h)-1;
111  }
112 
113  _board = std::vector<std::uint8_t>( _w*_h, 0 );
114  _s = _w*_h/2; // start
115  _e = _s; // current/end
116  ++_board[_e];
117 
118  // go
119  for ( const char * ch = data_r.c_str(); *ch; /*NOOP*/ )
120  {
121  std::uint8_t next4 = bite( ch );
122  // next4: 0x94
123  // bits: 10 01 01 00
124  // step: 4 3 2 1
125  static const std::uint8_t stepMask(0x3);
126  move( Direction( next4 & stepMask ) );
127  move( Direction( (next4>>2) & stepMask ) );
128  move( Direction( (next4>>4) & stepMask ) );
129  move( Direction( (next4>>6) ) );
130  }
131  }
132 
134  std::ostream & dumpOn( std::ostream & str, const std::string & prefix_r, Options options_r ) const
135  {
136  if ( _board.empty() )
137  {
138  // "++\n"
139  // "++"
140  return str << prefix_r << "++" << endl << prefix_r << "++";
141  }
142 
143  static const char * colorReset = "\033[0m";
144  static const char * colorBg = "\033[48;5;242m";
145  bool useColor = options_r.testFlag( USE_COLOR );
146 
147  renderTitleOn( str << prefix_r , _tt );
148 
149  for ( unsigned p = 0; p < _board.size(); ++p )
150  {
151  if ( ( p % _w ) == 0 )
152  {
153  if ( p )
154  str << ( useColor ? colorReset: "" ) << '|';
155  str << endl << prefix_r << '|' << ( useColor ? colorBg : "" );
156  }
157  renderOn( str, useColor, p );
158  }
159  str << ( useColor ? colorReset: "" ) << '|';
160 
161  renderTitleOn( str << endl << prefix_r, _fp );
162  return str;
163  }
164 
165  private:
167  static unsigned odd( unsigned val_r )
168  { return( val_r == Auto ? val_r : val_r|1U ); }
169 
173  static std::uint8_t bite( const char *& ch_r )
174  {
175  std::uint8_t ret = hexDigit( *ch_r ) << 4;
176  if ( *(++ch_r) )
177  ret |= hexDigit( *(ch_r++) );
178  return ret;
179  }
180 
181  private:
183  void move( Direction direction_r )
184  {
185  switch ( direction_r )
186  {
187  case Direction::NW:
188  if ( atTL() )
189  /*no move*/;
190  else if ( atT() )
191  _e -= 1;
192  else if ( atL() )
193  _e -= _w;
194  else
195  _e -= _w+1;
196  break;
197 
198  case Direction::NE:
199  if ( atTR() )
200  /*no move*/;
201  else if ( atT() )
202  _e += 1;
203  else if ( atR() )
204  _e -= _w;
205  else
206  _e -= _w-1;
207  break;
208 
209  case Direction::SW:
210  if ( atBL() )
211  /*no move*/;
212  else if ( atB() )
213  _e -= 1;
214  else if ( atL() )
215  _e += _w;
216  else
217  _e += _w-1;
218  break;
219 
220  case Direction::SE:
221  if ( atBR() )
222  /*no move*/;
223  else if ( atB() )
224  _e += 1;
225  else if ( atR() )
226  _e += _w;
227  else
228  _e += _w+1;
229  break;
230 
231  default:
232  throw std::invalid_argument( str::Str() << "Bad Direction " << unsigned(direction_r) );
233  }
234  // update the board
235  ++_board[_e];
236  }
237 
239  bool atTL() const
240  { return( _e == 0 ); }
241 
243  bool atTR() const
244  { return( _e == _w-1 ); }
245 
247  bool atBL() const
248  { return( _e == _board.size()-_w ); }
249 
251  bool atBR() const
252  { return( _e == _board.size()-1 ); }
253 
255  bool atT() const
256  { return( _e < _w ); }
257 
259  bool atB() const
260  { return( _e >= _board.size()-_w ); }
261 
263  bool atL() const
264  { return( ( _e % _w ) == 0 ); }
265 
267  bool atR() const
268  { return( ( _e % _w ) == (_w-1) ); }
269 
270  private:
272  const char * color( std::uint8_t idx_r ) const
273  {
274  static const std::vector<const char *> colors = {
275  "", // no coin
276  "\033[38;5;21m", // blue (cold)
277  "\033[38;5;39m",
278  "\033[38;5;50m",
279  "\033[38;5;48m",
280  "\033[38;5;46m", // green
281  "\033[38;5;118m",
282  "\033[38;5;190m",
283  "\033[38;5;226m", // yellow
284  "\033[38;5;220m",
285  "\033[38;5;214m", // orange
286  "\033[38;5;208m",
287  "\033[38;5;202m",
288  "\033[38;5;196m", // red
289  "\033[38;5;203m",
290  "\033[38;5;210m",
291  "\033[38;5;217m", // pink
292  "\033[38;5;224m",
293  "\033[38;5;231m", // white (hot)
294  };
295 #if 0
296  // cycle through heat map to test all colors
297  if ( ! idx_r )
298  return "";
299  static unsigned i = 0;
300  if ( ++i == colors.size() )
301  i = 1;
302  return colors[i];
303 #endif
304  return ( idx_r < colors.size() ? colors[idx_r] : *colors.rbegin() );
305  }
306 
308  std::ostream & renderTitleOn( std::ostream & str, const std::string & title_r ) const
309  {
310  std::string buffer( _w+2, '-' );
311  *buffer.begin() = *buffer.rbegin() = '+';
312 
313  if ( !title_r.empty() && _w >= 2 ) // extra 2 for "[]"
314  {
315  std::string::size_type tlen = std::min( title_r.size(), std::string::size_type(_w-2) );
316  std::string::size_type tpos = (_w-tlen)/2; // not (_w-2-tlen) because buffer is size _w+2
317  buffer[tpos++] = '[';
318  for ( std::string::size_type p = 0; p < tlen; ++p, ++tpos )
319  buffer[tpos] = title_r[p];
320  buffer[tpos] = ']';
321  }
322  return str << buffer;
323  }
324 
326  std::ostream & renderOn( std::ostream & str, bool useColor_r, unsigned pos_r ) const
327  {
328  static const std::string sshSet( " .o+=*BOX@%&#/^" );
329  static const std::string gpgSet( " .^:li?(fxXZ#MW&8%@" );
330  const std::string & charSet( _renderSSH ? sshSet : gpgSet );
331 
332  if ( useColor_r )
333  str << color( _board[pos_r] );
334 
335  if ( pos_r == _e )
336  return str << 'E';
337 
338  if ( pos_r == _s )
339  return str << 'S';
340 
341  return str << ( _board[pos_r] < charSet.size() ? charSet[_board[pos_r]] : *charSet.rbegin() );
342  }
343 
344  private:
346  static constexpr const unsigned Auto = unsigned(-1);
347 
348  private:
349  std::vector<std::uint8_t> _board;
350  unsigned _h;
351  unsigned _w;
352  unsigned _s;
353  unsigned _e;
354 
355  private:
356  bool _renderSSH;
357  std::string _fp;
358  std::string _tt;
359 
360  public:
362  static shared_ptr<Impl> nullimpl()
363  {
364  static shared_ptr<Impl> _nullimpl( new Impl );
365  return _nullimpl;
366  }
367  };
368 
370  // CLASS NAME : DrunkenBishop
372 
374  : _pimpl( Impl::nullimpl() )
375  { /*nothing to compute*/ }
376 
377  DrunkenBishop::DrunkenBishop( const std::string & data_r, const std::string & title_r )
378  : _pimpl( new Impl )
379  { _pimpl->compute( data_r, title_r ); }
380 
381  DrunkenBishop::DrunkenBishop( const std::string & data_r, const std::string & title_r, unsigned height_r )
382  : _pimpl( new Impl )
383  { _pimpl->compute( data_r, title_r, height_r ); }
384 
385  DrunkenBishop::DrunkenBishop( const std::string & data_r, const std::string & title_r, unsigned height_r, unsigned width_r )
386  : _pimpl( new Impl )
387  { _pimpl->compute( data_r, title_r, height_r, width_r ); }
388 
390  {}
391 
392  std::ostream & DrunkenBishop::dumpOn( std::ostream & str, const std::string & prefix_r, Options options_r ) const
393  { return _pimpl->dumpOn( str, prefix_r, options_r ); }
394 
395  std::string DrunkenBishop::asString( const std::string & prefix_r, Options options_r ) const
396  {
397  std::ostringstream str;
398  dumpOn( str, prefix_r, options_r );
399  return str.str();
400  }
401 
402  std::vector<std::string> DrunkenBishop::asLines( const std::string & prefix_r, Options options_r ) const
403  {
404  std::vector<std::string> ret;
405  str::split( asString( prefix_r, options_r ), std::back_inserter(ret), "\n" );
406  return ret;
407  }
408 
409  } // namespace base
411 } // namespace zypp
bool atB() const
Whether _e is in the bottom row.
DrunkenBishop()
Default ctor: empty board (1x1)
DrunkenBishop implementation.
std::ostream & renderOn(std::ostream &str, bool useColor_r, unsigned pos_r) const
Render board numbers to printable chars.
bool atTL() const
Whether _e is in the top left corner.
std::ostream & dumpOn(std::ostream &str, const std::string &prefix_r, Options options_r) const
Render board to a stream.
bool atT() const
Whether _e is in the top row.
void move(Direction direction_r)
Move Bishop from _e into direction_r and update the _board.
bool atBR() const
Whether _e is in the bottom right corner.
String related utilities and Regular expression matching.
std::ostream & renderTitleOn(std::ostream &str, const std::string &title_r) const
Render non empty title strings.
Impl()
Default is an empty board.
std::vector< std::uint8_t > _board
the board
unsigned split(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=" \, const Trim trim_r=NO_TRIM)
Split line_r into words.
Definition: String.h:602
bool atTR() const
Whether _e is in the top right corner.
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:212
std::string _fp
fingerprint to render as bottom title
bool atL() const
Whether _e is in the left column.
std::ostream & dumpOn(std::ostream &str, Options options_r=Options()) const
Render board to steam.
Definition: DrunkenBishop.h:97
Direction
Direction the drunken Bishop wants to move.
std::string toUpper(const std::string &s)
Return uppercase version of s.
Definition: String.cc:203
const char * color(std::uint8_t idx_r) const
ANSI color heatmap.
SolvableIdType size_type
Definition: poolconstants.h:59
std::vector< std::string > asLines(Options options_r=Options()) const
Render to an array of lines.
std::string asString(Options options_r=Options()) const
Render board as string.
static constexpr const unsigned Auto
Request default width/height values.
bool _renderSSH
whether to render the ssh (or gpg) char set
bool atR() const
Whether _e is in the right column.
void compute(const std::string &data_r, const std::string &title_r, unsigned height_r=Auto, unsigned width_r=Auto)
Build up a new board.
static unsigned odd(unsigned val_r)
Increment even width/height values.
std::string _tt
text to render as top title
RW_pointer< Impl > _pimpl
Implementation class.
bool atBL() const
Whether _e is in the bottom left corner.
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
unsigned _s
start position
static shared_ptr< Impl > nullimpl()
Offer default Impl.
static std::uint8_t bite(const char *&ch_r)
Get next 4 moves (8 bit) from next 2 hex digits (1st digit != &#39;\0&#39; asserted, 0-pad if necessary)...
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26