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