<commit_before>// @(#)root/base:$Name:  $:$Id: TAttAxis.cxx,v 1.14 2007/01/12 09:31:33 brun Exp $
// Author: Rene Brun   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Riostream.h"
#include "TFile.h"
#include "TAttAxis.h"
#include "TStyle.h"
#include "TVirtualPad.h"
#include "TColor.h"
#include "TClass.h"
#include "TMathBase.h"

ClassImp(TAttAxis)

//______________________________________________________________________________
//
//  Manages histogram axis attributes
//

TAttAxis::TAttAxis()
{
   // Constructor.
   ResetAttAxis();
}

//______________________________________________________________________________
TAttAxis::~TAttAxis()
{
   // Destructor.
}

//______________________________________________________________________________
void TAttAxis::Copy(TAttAxis &attaxis) const
{
   // Copy of the object.

   attaxis.fNdivisions  = fNdivisions;
   attaxis.fAxisColor   = fAxisColor;
   attaxis.fLabelColor  = fLabelColor;
   attaxis.fLabelFont   = fLabelFont;
   attaxis.fLabelOffset = fLabelOffset;
   attaxis.fLabelSize   = fLabelSize;
   attaxis.fTickLength  = fTickLength;
   attaxis.fTitleOffset = fTitleOffset;
   attaxis.fTitleSize   = fTitleSize;
   attaxis.fTitleColor  = fTitleColor;
   attaxis.fTitleFont   = fTitleFont;
}

//______________________________________________________________________________
void TAttAxis::ResetAttAxis(Option_t *option)
{
   // Reset axis attributes

   if (gStyle) {
      fNdivisions  = gStyle->GetNdivisions(option);
      fAxisColor   = gStyle->GetAxisColor(option);
      fLabelColor  = gStyle->GetLabelColor(option);
      fLabelFont   = gStyle->GetLabelFont(option);
      fLabelOffset = gStyle->GetLabelOffset(option);
      fLabelSize   = gStyle->GetLabelSize(option);
      fTickLength  = gStyle->GetTickLength(option);
      fTitleOffset = gStyle->GetTitleOffset(option);
      fTitleSize   = gStyle->GetTitleSize(option);
      fTitleColor  = gStyle->GetTitleColor(option);
      fTitleFont   = gStyle->GetTitleFont(option);
   } else {
      fNdivisions  = 510;
      fAxisColor   = 1;
      fLabelColor  = 1;
      fLabelFont   = 62;
      fLabelOffset = 0.005;
      fLabelSize   = 0.04;
      fTickLength  = 0.03;
      fTitleOffset = 1;
      fTitleSize   = fLabelSize;
      fTitleColor  = 1;
      fTitleFont   = 62;
   }
}

//______________________________________________________________________________
void TAttAxis::SaveAttributes(ostream &out, const char *name, const char *subname)
{
    // Save axis attributes as C++ statement(s) on output stream out

   if (fNdivisions != 510) {
      out<<"   "<<name<<subname<<"->SetNdivisions("<<fNdivisions<<");"<<endl;
   }
   if (fAxisColor != 1) {
      if (fAxisColor > 228) {
         TColor::SaveColor(out, fAxisColor);
         out<<"   "<<name<<subname<<"->SetAxisColor(ci);" << endl;
      } else
         out<<"   "<<name<<subname<<"->SetAxisColor("<<fAxisColor<<");"<<endl;
   }
   if (fLabelColor != 1) {
      if (fLabelColor > 228) {
         TColor::SaveColor(out, fLabelColor);
         out<<"   "<<name<<subname<<"->SetLabelColor(ci);" << endl;
      } else
         out<<"   "<<name<<subname<<"->SetLabelColor("<<fLabelColor<<");"<<endl;
   }
   if (fLabelFont != 62) {
      out<<"   "<<name<<subname<<"->SetLabelFont("<<fLabelFont<<");"<<endl;
   }
   if (TMath::Abs(fLabelOffset-0.005) > 0.0001) {
      out<<"   "<<name<<subname<<"->SetLabelOffset("<<fLabelOffset<<");"<<endl;
   }
   if (TMath::Abs(fLabelSize-0.04) > 0.001) {
      out<<"   "<<name<<subname<<"->SetLabelSize("<<fLabelSize<<");"<<endl;
   }
   if (TMath::Abs(fTitleSize-0.04) > 0.001) {
      out<<"   "<<name<<subname<<"->SetTitleSize("<<fTitleSize<<");"<<endl;
   }
   if (TMath::Abs(fTickLength-0.03) > 0.001) {
      out<<"   "<<name<<subname<<"->SetTickLength("<<fTickLength<<");"<<endl;
   }
   if (TMath::Abs(fTitleOffset-1) > 0.001) {
      out<<"   "<<name<<subname<<"->SetTitleOffset("<<fTitleOffset<<");"<<endl;
   }
   if (fTitleColor != 1) {
      if (fTitleColor > 228) {
         TColor::SaveColor(out, fTitleColor);
         out<<"   "<<name<<subname<<"->SetTitleColor(ci);" << endl;
      } else
         out<<"   "<<name<<subname<<"->SetTitleColor("<<fTitleColor<<");"<<endl;
   }
   if (fTitleFont != 62) {
      out<<"   "<<name<<subname<<"->SetTitleFont("<<fTitleFont<<");"<<endl;
   }
}

//______________________________________________________________________________
void TAttAxis::SetAxisColor(Color_t color)
{
   // Set color of the line axis and tick marks

   fAxisColor = color;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetLabelColor(Color_t color)
{
   // Set color of labels

   fLabelColor = color;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetLabelFont(Style_t font)
{
   // Set labels' font.

   fLabelFont = font;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetLabelOffset(Float_t offset)
{
   // Set distance between the axis and the labels
   // The distance is expressed in per cent of the pad width

   fLabelOffset = offset;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetLabelSize(Float_t size)
{
   // Set size of axis labels
   // The size is expressed in per cent of the pad width

   fLabelSize = size;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetNdivisions(Int_t n, Bool_t optim)
{
   // Set the number of divisions for this axis.
   //
   // if optim = kTRUE (default), the number of divisions will be
   //                   optimized around the specified value.
   // if optim = kFALSE, or n < 0, the axis will be forced to use
   //                   exactly n divisions.
   //
   // n = n1 + 100*n2 + 10000*n3
   //
   // Where n1 is the number of primary divisions,
   // n2 is the number of second order divisions and
   // n3 is the number of third order divisions.
   //
   // e.g. 512 means 12 primary and 5 secondary divisions.
   //
   // If the number of divisions is "optimized" (see above) n1, n2, n3 are
   // maximum values.

   fNdivisions = n;
   if (!optim) fNdivisions = -abs(n);
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTickLength(Float_t length)
{
   // Set tick mark length
   // The length is expressed in per cent of the pad width

   fTickLength = length;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTitleOffset(Float_t offset)
{
   // Set distance between the axis and the axis title
   // Offset is a correction factor with respect to the "standard" value.
   // offset = 1  uses the default position that is computed in function
   // of the label offset and size.
   // offset = 1.2 will add 20 per cent more to the default offset.

   fTitleOffset = offset;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTitleSize(Float_t size)
{
   // Set size of axis title
   // The size is expressed in per cent of the pad width

   fTitleSize = size;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTitleColor(Color_t color)
{
   // Set color of axis title

   fTitleColor = color;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTitleFont(Style_t font)
{
   // Set the title font.

   fTitleFont = font;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::Streamer(TBuffer &R__b)
{
   // Stream an object of class TAttAxis.

   if (R__b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      if (R__v > 3) {
         TAttAxis::Class()->ReadBuffer(R__b, this, R__v, R__s, R__c);
         return;
      }
      //====process old versions before automatic schema evolution
      R__b >> fNdivisions;
      R__b >> fAxisColor;
      R__b >> fLabelColor;
      R__b >> fLabelFont;
      R__b >> fLabelOffset;
      R__b >> fLabelSize;
      R__b >> fTickLength;
      R__b >> fTitleOffset;
      // !file is the case of only TMapFile
      TFile *file = (TFile*)R__b.GetParent();
      if (R__v > 1 && (!file || (file && file->GetVersion() > 900)))
         R__b >> fTitleSize;
      else
         fTitleSize = fLabelSize;
      if (R__v > 2) {
         R__b >> fTitleColor;
         R__b >> fTitleFont;
      }
      //====end of old versions

   } else {
      TAttAxis::Class()->WriteBuffer(R__b,this);
   }
}
<commit_msg>Remove dependency from TFile (thanks to new function TBuffer::GetVersionOwner)<commit_after>// @(#)root/base:$Name:  $:$Id: TAttAxis.cxx,v 1.15 2007/01/15 11:52:01 rdm Exp $
// Author: Rene Brun   12/12/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Riostream.h"
#include "TAttAxis.h"
#include "TStyle.h"
#include "TVirtualPad.h"
#include "TColor.h"
#include "TClass.h"
#include "TMathBase.h"

ClassImp(TAttAxis)

//______________________________________________________________________________
//
//  Manages histogram axis attributes
//

TAttAxis::TAttAxis()
{
   // Constructor.
   ResetAttAxis();
}

//______________________________________________________________________________
TAttAxis::~TAttAxis()
{
   // Destructor.
}

//______________________________________________________________________________
void TAttAxis::Copy(TAttAxis &attaxis) const
{
   // Copy of the object.

   attaxis.fNdivisions  = fNdivisions;
   attaxis.fAxisColor   = fAxisColor;
   attaxis.fLabelColor  = fLabelColor;
   attaxis.fLabelFont   = fLabelFont;
   attaxis.fLabelOffset = fLabelOffset;
   attaxis.fLabelSize   = fLabelSize;
   attaxis.fTickLength  = fTickLength;
   attaxis.fTitleOffset = fTitleOffset;
   attaxis.fTitleSize   = fTitleSize;
   attaxis.fTitleColor  = fTitleColor;
   attaxis.fTitleFont   = fTitleFont;
}

//______________________________________________________________________________
void TAttAxis::ResetAttAxis(Option_t *option)
{
   // Reset axis attributes

   if (gStyle) {
      fNdivisions  = gStyle->GetNdivisions(option);
      fAxisColor   = gStyle->GetAxisColor(option);
      fLabelColor  = gStyle->GetLabelColor(option);
      fLabelFont   = gStyle->GetLabelFont(option);
      fLabelOffset = gStyle->GetLabelOffset(option);
      fLabelSize   = gStyle->GetLabelSize(option);
      fTickLength  = gStyle->GetTickLength(option);
      fTitleOffset = gStyle->GetTitleOffset(option);
      fTitleSize   = gStyle->GetTitleSize(option);
      fTitleColor  = gStyle->GetTitleColor(option);
      fTitleFont   = gStyle->GetTitleFont(option);
   } else {
      fNdivisions  = 510;
      fAxisColor   = 1;
      fLabelColor  = 1;
      fLabelFont   = 62;
      fLabelOffset = 0.005;
      fLabelSize   = 0.04;
      fTickLength  = 0.03;
      fTitleOffset = 1;
      fTitleSize   = fLabelSize;
      fTitleColor  = 1;
      fTitleFont   = 62;
   }
}

//______________________________________________________________________________
void TAttAxis::SaveAttributes(ostream &out, const char *name, const char *subname)
{
    // Save axis attributes as C++ statement(s) on output stream out

   if (fNdivisions != 510) {
      out<<"   "<<name<<subname<<"->SetNdivisions("<<fNdivisions<<");"<<endl;
   }
   if (fAxisColor != 1) {
      if (fAxisColor > 228) {
         TColor::SaveColor(out, fAxisColor);
         out<<"   "<<name<<subname<<"->SetAxisColor(ci);" << endl;
      } else
         out<<"   "<<name<<subname<<"->SetAxisColor("<<fAxisColor<<");"<<endl;
   }
   if (fLabelColor != 1) {
      if (fLabelColor > 228) {
         TColor::SaveColor(out, fLabelColor);
         out<<"   "<<name<<subname<<"->SetLabelColor(ci);" << endl;
      } else
         out<<"   "<<name<<subname<<"->SetLabelColor("<<fLabelColor<<");"<<endl;
   }
   if (fLabelFont != 62) {
      out<<"   "<<name<<subname<<"->SetLabelFont("<<fLabelFont<<");"<<endl;
   }
   if (TMath::Abs(fLabelOffset-0.005) > 0.0001) {
      out<<"   "<<name<<subname<<"->SetLabelOffset("<<fLabelOffset<<");"<<endl;
   }
   if (TMath::Abs(fLabelSize-0.04) > 0.001) {
      out<<"   "<<name<<subname<<"->SetLabelSize("<<fLabelSize<<");"<<endl;
   }
   if (TMath::Abs(fTitleSize-0.04) > 0.001) {
      out<<"   "<<name<<subname<<"->SetTitleSize("<<fTitleSize<<");"<<endl;
   }
   if (TMath::Abs(fTickLength-0.03) > 0.001) {
      out<<"   "<<name<<subname<<"->SetTickLength("<<fTickLength<<");"<<endl;
   }
   if (TMath::Abs(fTitleOffset-1) > 0.001) {
      out<<"   "<<name<<subname<<"->SetTitleOffset("<<fTitleOffset<<");"<<endl;
   }
   if (fTitleColor != 1) {
      if (fTitleColor > 228) {
         TColor::SaveColor(out, fTitleColor);
         out<<"   "<<name<<subname<<"->SetTitleColor(ci);" << endl;
      } else
         out<<"   "<<name<<subname<<"->SetTitleColor("<<fTitleColor<<");"<<endl;
   }
   if (fTitleFont != 62) {
      out<<"   "<<name<<subname<<"->SetTitleFont("<<fTitleFont<<");"<<endl;
   }
}

//______________________________________________________________________________
void TAttAxis::SetAxisColor(Color_t color)
{
   // Set color of the line axis and tick marks

   fAxisColor = color;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetLabelColor(Color_t color)
{
   // Set color of labels

   fLabelColor = color;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetLabelFont(Style_t font)
{
   // Set labels' font.

   fLabelFont = font;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetLabelOffset(Float_t offset)
{
   // Set distance between the axis and the labels
   // The distance is expressed in per cent of the pad width

   fLabelOffset = offset;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetLabelSize(Float_t size)
{
   // Set size of axis labels
   // The size is expressed in per cent of the pad width

   fLabelSize = size;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetNdivisions(Int_t n, Bool_t optim)
{
   // Set the number of divisions for this axis.
   //
   // if optim = kTRUE (default), the number of divisions will be
   //                   optimized around the specified value.
   // if optim = kFALSE, or n < 0, the axis will be forced to use
   //                   exactly n divisions.
   //
   // n = n1 + 100*n2 + 10000*n3
   //
   // Where n1 is the number of primary divisions,
   // n2 is the number of second order divisions and
   // n3 is the number of third order divisions.
   //
   // e.g. 512 means 12 primary and 5 secondary divisions.
   //
   // If the number of divisions is "optimized" (see above) n1, n2, n3 are
   // maximum values.

   fNdivisions = n;
   if (!optim) fNdivisions = -abs(n);
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTickLength(Float_t length)
{
   // Set tick mark length
   // The length is expressed in per cent of the pad width

   fTickLength = length;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTitleOffset(Float_t offset)
{
   // Set distance between the axis and the axis title
   // Offset is a correction factor with respect to the "standard" value.
   // offset = 1  uses the default position that is computed in function
   // of the label offset and size.
   // offset = 1.2 will add 20 per cent more to the default offset.

   fTitleOffset = offset;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTitleSize(Float_t size)
{
   // Set size of axis title
   // The size is expressed in per cent of the pad width

   fTitleSize = size;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTitleColor(Color_t color)
{
   // Set color of axis title

   fTitleColor = color;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::SetTitleFont(Style_t font)
{
   // Set the title font.

   fTitleFont = font;
   if (gPad) gPad->Modified();
}

//______________________________________________________________________________
void TAttAxis::Streamer(TBuffer &R__b)
{
   // Stream an object of class TAttAxis.

   if (R__b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      if (R__v > 3) {
         TAttAxis::Class()->ReadBuffer(R__b, this, R__v, R__s, R__c);
         return;
      }
      //====process old versions before automatic schema evolution
      R__b >> fNdivisions;
      R__b >> fAxisColor;
      R__b >> fLabelColor;
      R__b >> fLabelFont;
      R__b >> fLabelOffset;
      R__b >> fLabelSize;
      R__b >> fTickLength;
      R__b >> fTitleOffset;

      if (R__v > 1 && R__b.GetVersionOwner() > 900)
         R__b >> fTitleSize;
      else
         fTitleSize = fLabelSize;
      if (R__v > 2) {
         R__b >> fTitleColor;
         R__b >> fTitleFont;
      }
      //====end of old versions

   } else {
      TAttAxis::Class()->WriteBuffer(R__b,this);
   }
}
<|endoftext|>


<commit_before>// @(#)root/base:$Name:  $:$Id: TAttLine.cxx,v 1.17 2007/02/21 09:33:21 couet Exp $
// Author: Rene Brun   28/11/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Riostream.h"
#include "TAttLine.h"
#include "TVirtualPad.h"
#include "TStyle.h"
#include "TVirtualX.h"
#include "TVirtualPadEditor.h"
#include "TColor.h"
#include <cmath>

ClassImp(TAttLine)

//______________________________________________________________________________
/* Begin_Html

Line Attributes class

This class is used (in general by secondary inheritance)
by many other classes (graphics, histograms). It holds all the line attributes.

Line attributes

Line attributes are:

Line Color.

Line Width.

Line Style.

Line Color

The line color is a color index (integer) pointing in the ROOT
color table. The following table shows the first 50 default colors.
End_Html
Begin_Macro(source)
{
   TCanvas *c = new TCanvas("c","Line colors",0,0,500,200);
   c.DrawColorTable();
   return c;
}
End_Macro

Begin_Html

Line Width

The line width is expressed in pixel units.
The following picture shows the line widths from 1 to 10 pixels.
End_Html
Begin_Macro(source)
{
   TCanvas *Lw = new TCanvas("Lw","test",500,200);
   TText  t;
   t.SetTextAlign(32);
   t.SetTextSize(0.08);
   Int_t i=1;
   gStyle->SetLineStyleString(9,"400 20");
   for (float s=0.1; s<1.0 ; s+=0.092) {
      TLine *lh = new TLine(0.15,s,.85,s);
      lh->SetLineWidth(i);
      t.DrawText(0.1,s,Form("%d",i++));
      lh->Draw();
   }
   return Lw;
}
End_Macro

Begin_Html

Line Style

Line styles are identified via integer numbers. The four basic line styles
are:

   1 = solid
   2 = dash
   3 = dot-dot
   4 = dash-dot

Additional line styles can be defined using <tt>TStyle::SetLineStyleString</tt>.

Example:

   gStyle->SetLineStyleString(5,"20 12 4 12");
   gStyle->SetLineStyleString(6,"20 12 4 12 4 12 4 12");
   gStyle->SetLineStyleString(7,"20 20");
   gStyle->SetLineStyleString(8,"20 12 4 12 4 12");
   gStyle->SetLineStyleString(9,"80 20");

The following picture shows the first 10 line styles.
End_Html
Begin_Macro(source)
{
   TCanvas *Ls = new TCanvas("Ls","test",500,200);
   TText  t;
   t.SetTextAlign(32);
   t.SetTextSize(0.08);
   Int_t i=1;
   gStyle->SetLineStyleString(9,"400 20");
   for (float s=0.1; s<1.0 ; s+=0.092) {
      TLine *lh = new TLine(0.15,s,.85,s);
      lh->SetLineStyle(i);
      t.DrawText(0.1,s,Form("%d",i++));
      lh->Draw();
   }
   return Ls;
}
End_Macro */

//______________________________________________________________________________
TAttLine::TAttLine()
{
   // AttLine default constructor.

   if (!gStyle) return;
   fLineColor = gStyle->GetLineColor();
   fLineWidth = gStyle->GetLineWidth();
   fLineStyle = gStyle->GetLineStyle();
}

//______________________________________________________________________________
TAttLine::TAttLine(Color_t color, Style_t style, Width_t width)
{
   // AttLine normal constructor.
   // Line attributes are taking from the argument list
   //   color : must be one of the valid color index
   //   style : 1=solid, 2=dash, 3=dash-dot, 4=dot-dot. New styles can be
   //           defined using TStyle::SetLineStyleString.
   //   width : expressed in pixel units

   fLineColor = color;
   fLineWidth = width;
   fLineStyle = style;
}

//______________________________________________________________________________
TAttLine::~TAttLine()
{
   // AttLine destructor.
}

//______________________________________________________________________________
void TAttLine::Copy(TAttLine &attline) const
{
   // Copy this line attributes to a new TAttLine.

   attline.fLineColor  = fLineColor;
   attline.fLineStyle  = fLineStyle;
   attline.fLineWidth  = fLineWidth;
}

//______________________________________________________________________________
Int_t TAttLine::DistancetoLine(Int_t px, Int_t py, Double_t xp1, Double_t yp1, Double_t xp2, Double_t yp2 )
{
   // Compute distance from point px,py to a line.
   // Compute the closest distance of approach from point px,py to this line.
   // The distance is computed in pixels units.
   //
   // Algorithm:
   //
   //   A(x1,y1)         P                             B(x2,y2)
   //   -----------------+------------------------------
   //                    |
   //                    |
   //                    |
   //                    |
   //                   M(x,y)
   //
   // Let us call  a = distance AM     A=a**2
   //              b = distance BM     B=b**2
   //              c = distance AB     C=c**2
   //              d = distance PM     D=d**2
   //              u = distance AP     U=u**2
   //              v = distance BP     V=v**2     c = u + v
   //
   // D = A - U
   // D = B - V  = B -(c-u)**2
   //    ==> u = (A -B +C)/2c

   Double_t xl, xt, yl, yt;
   Double_t x     = px;
   Double_t y     = py;
   Double_t x1    = gPad->XtoAbsPixel(xp1);
   Double_t y1    = gPad->YtoAbsPixel(yp1);
   Double_t x2    = gPad->XtoAbsPixel(xp2);
   Double_t y2    = gPad->YtoAbsPixel(yp2);
   if (x1 < x2) {xl = x1; xt = x2;}
   else         {xl = x2; xt = x1;}
   if (y1 < y2) {yl = y1; yt = y2;}
   else         {yl = y2; yt = y1;}
   if (x < xl-2 || x> xt+2) return 9999;  //following algorithm only valid in the box
   if (y < yl-2 || y> yt+2) return 9999;  //surrounding the line
   Double_t xx1   = x  - x1;
   Double_t xx2   = x  - x2;
   Double_t x1x2  = x1 - x2;
   Double_t yy1   = y  - y1;
   Double_t yy2   = y  - y2;
   Double_t y1y2  = y1 - y2;
   Double_t a     = xx1*xx1   + yy1*yy1;
   Double_t b     = xx2*xx2   + yy2*yy2;
   Double_t c     = x1x2*x1x2 + y1y2*y1y2;
   if (c <= 0)  return 9999;
   Double_t v     = sqrt(c);
   Double_t u     = (a - b + c)/(2*v);
   Double_t d     = TMath::Abs(a - u*u);
   if (d < 0)   return 9999;

   return Int_t(sqrt(d) - 0.5*Double_t(fLineWidth));
}

//______________________________________________________________________________
void TAttLine::Modify()
{
   // Change current line attributes if necessary.

   if (!gPad) return;
   Int_t lineWidth = TMath::Abs(fLineWidth%100);
   if (!gPad->IsBatch()) {
      gVirtualX->SetLineColor(fLineColor);
      if (fLineStyle > 0 && fLineStyle < 30) gVirtualX->SetLineStyle(fLineStyle);
      else                                   gVirtualX->SetLineStyle(1);
      gVirtualX->SetLineWidth(lineWidth);
   }

   if (fLineStyle > 0 && fLineStyle < 30) gPad->SetAttLinePS(fLineColor,fLineStyle,lineWidth);
   else                                   gPad->SetAttLinePS(fLineColor,1,lineWidth);
}

//______________________________________________________________________________
void TAttLine::ResetAttLine(Option_t *)
{
   // Reset this line attributes to default values.

   fLineColor  = 1;
   fLineStyle  = 1;
   fLineWidth  = 1;
}

//______________________________________________________________________________
void TAttLine::SaveLineAttributes(ostream &out, const char *name, Int_t coldef, Int_t stydef, Int_t widdef)
{
   // Save line attributes as C++ statement(s) on output stream out.

   if (fLineColor != coldef) {
      if (fLineColor > 228) {
         TColor::SaveColor(out, fLineColor);
         out<<"   "<<name<<"->SetLineColor(ci);" << endl;
      } else
         out<<"   "<<name<<"->SetLineColor("<<fLineColor<<");"<<endl;
   }
   if (fLineStyle != stydef) {
      out<<"   "<<name<<"->SetLineStyle("<<fLineStyle<<");"<<endl;
   }
   if (fLineWidth != widdef) {
      out<<"   "<<name<<"->SetLineWidth("<<fLineWidth<<");"<<endl;
   }
}

//______________________________________________________________________________
void TAttLine::SetLineAttributes()
{
   // Invoke the DialogCanvas Line attributes.

   TVirtualPadEditor::UpdateLineAttributes(fLineColor,fLineStyle,fLineWidth);
}
<commit_msg>- Help improvments.<commit_after>// @(#)root/base:$Name:  $:$Id: TAttLine.cxx,v 1.18 2007/02/21 12:39:00 couet Exp $
// Author: Rene Brun   28/11/94

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "Riostream.h"
#include "TAttLine.h"
#include "TVirtualPad.h"
#include "TStyle.h"
#include "TVirtualX.h"
#include "TVirtualPadEditor.h"
#include "TColor.h"
#include <cmath>

ClassImp(TAttLine)

//______________________________________________________________________________
/* Begin_Html

Line Attributes class

This class is used (in general by secondary inheritance)
by many other classes (graphics, histograms). It holds all the line attributes.

Line attributes

Line attributes are:

Line Color.

Line Width.

Line Style.

Line Color

The line color is a color index (integer) pointing in the ROOT
color table.
The line color of any class inheriting from <tt>TAttLine</tt> can
be changed using the method <tt>SetLineColor</tt> and retrieved using the
method <tt>GetLineColor</tt>.
The following table shows the first 50 default colors.
End_Html
Begin_Macro(source)
{
   TCanvas *c = new TCanvas("c","Line colors",0,0,500,200);
   c.DrawColorTable();
   return c;
}
End_Macro

Begin_Html

Line Width

The line width is expressed in pixel units.
The line width of any class inheriting from <tt>TAttLine</tt> can
be changed using the method <tt>SetLineWidth</tt> and retrieved using the
method <tt>GetLineWidth</tt>.
The following picture shows the line widths from 1 to 10 pixels.
End_Html
Begin_Macro(source)
{
   TCanvas *Lw = new TCanvas("Lw","test",500,200);
   TText  t;
   t.SetTextAlign(32);
   t.SetTextSize(0.08);
   Int_t i=1;
   gStyle->SetLineStyleString(9,"400 20");
   for (float s=0.1; s<1.0 ; s+=0.092) {
      TLine *lh = new TLine(0.15,s,.85,s);
      lh->SetLineWidth(i);
      t.DrawText(0.1,s,Form("%d",i++));
      lh->Draw();
   }
   return Lw;
}
End_Macro

Begin_Html

Line Style

Line styles are identified via integer numbers.
The line style of any class inheriting from <tt>TAttLine</tt> can
be changed using the method <tt>SetLineStyle</tt> and retrieved using the
method <tt>GetLineStyle</tt>.
The four basic line styles are:

   1 = solid
   2 = dash
   3 = dot-dot
   4 = dash-dot

Additional line styles can be defined using <tt>TStyle::SetLineStyleString</tt>.

Example:

   gStyle->SetLineStyleString(5,"20 12 4 12");
   gStyle->SetLineStyleString(6,"20 12 4 12 4 12 4 12");
   gStyle->SetLineStyleString(7,"20 20");
   gStyle->SetLineStyleString(8,"20 12 4 12 4 12");
   gStyle->SetLineStyleString(9,"80 20");

The following picture shows the first 10 line styles.
End_Html
Begin_Macro(source)
{
   TCanvas *Ls = new TCanvas("Ls","test",500,200);
   TText  t;
   t.SetTextAlign(32);
   t.SetTextSize(0.08);
   Int_t i=1;
   gStyle->SetLineStyleString(9,"400 20");
   for (float s=0.1; s<1.0 ; s+=0.092) {
      TLine *lh = new TLine(0.15,s,.85,s);
      lh->SetLineStyle(i);
      t.DrawText(0.1,s,Form("%d",i++));
      lh->Draw();
   }
   return Ls;
}
End_Macro */

//______________________________________________________________________________
TAttLine::TAttLine()
{
   // AttLine default constructor.

   if (!gStyle) return;
   fLineColor = gStyle->GetLineColor();
   fLineWidth = gStyle->GetLineWidth();
   fLineStyle = gStyle->GetLineStyle();
}

//______________________________________________________________________________
TAttLine::TAttLine(Color_t color, Style_t style, Width_t width)
{
   // AttLine normal constructor.
   // Line attributes are taking from the argument list
   //   color : must be one of the valid color index
   //   style : 1=solid, 2=dash, 3=dash-dot, 4=dot-dot. New styles can be
   //           defined using TStyle::SetLineStyleString.
   //   width : expressed in pixel units

   fLineColor = color;
   fLineWidth = width;
   fLineStyle = style;
}

//______________________________________________________________________________
TAttLine::~TAttLine()
{
   // AttLine destructor.
}

//______________________________________________________________________________
void TAttLine::Copy(TAttLine &attline) const
{
   // Copy this line attributes to a new TAttLine.

   attline.fLineColor  = fLineColor;
   attline.fLineStyle  = fLineStyle;
   attline.fLineWidth  = fLineWidth;
}

//______________________________________________________________________________
Int_t TAttLine::DistancetoLine(Int_t px, Int_t py, Double_t xp1, Double_t yp1, Double_t xp2, Double_t yp2 )
{
   // Compute distance from point px,py to a line.
   // Compute the closest distance of approach from point px,py to this line.
   // The distance is computed in pixels units.
   //
   // Algorithm:
   //
   //   A(x1,y1)         P                             B(x2,y2)
   //   -----------------+------------------------------
   //                    |
   //                    |
   //                    |
   //                    |
   //                   M(x,y)
   //
   // Let us call  a = distance AM     A=a**2
   //              b = distance BM     B=b**2
   //              c = distance AB     C=c**2
   //              d = distance PM     D=d**2
   //              u = distance AP     U=u**2
   //              v = distance BP     V=v**2     c = u + v
   //
   // D = A - U
   // D = B - V  = B -(c-u)**2
   //    ==> u = (A -B +C)/2c

   Double_t xl, xt, yl, yt;
   Double_t x     = px;
   Double_t y     = py;
   Double_t x1    = gPad->XtoAbsPixel(xp1);
   Double_t y1    = gPad->YtoAbsPixel(yp1);
   Double_t x2    = gPad->XtoAbsPixel(xp2);
   Double_t y2    = gPad->YtoAbsPixel(yp2);
   if (x1 < x2) {xl = x1; xt = x2;}
   else         {xl = x2; xt = x1;}
   if (y1 < y2) {yl = y1; yt = y2;}
   else         {yl = y2; yt = y1;}
   if (x < xl-2 || x> xt+2) return 9999;  //following algorithm only valid in the box
   if (y < yl-2 || y> yt+2) return 9999;  //surrounding the line
   Double_t xx1   = x  - x1;
   Double_t xx2   = x  - x2;
   Double_t x1x2  = x1 - x2;
   Double_t yy1   = y  - y1;
   Double_t yy2   = y  - y2;
   Double_t y1y2  = y1 - y2;
   Double_t a     = xx1*xx1   + yy1*yy1;
   Double_t b     = xx2*xx2   + yy2*yy2;
   Double_t c     = x1x2*x1x2 + y1y2*y1y2;
   if (c <= 0)  return 9999;
   Double_t v     = sqrt(c);
   Double_t u     = (a - b + c)/(2*v);
   Double_t d     = TMath::Abs(a - u*u);
   if (d < 0)   return 9999;

   return Int_t(sqrt(d) - 0.5*Double_t(fLineWidth));
}

//______________________________________________________________________________
void TAttLine::Modify()
{
   // Change current line attributes if necessary.

   if (!gPad) return;
   Int_t lineWidth = TMath::Abs(fLineWidth%100);
   if (!gPad->IsBatch()) {
      gVirtualX->SetLineColor(fLineColor);
      if (fLineStyle > 0 && fLineStyle < 30) gVirtualX->SetLineStyle(fLineStyle);
      else                                   gVirtualX->SetLineStyle(1);
      gVirtualX->SetLineWidth(lineWidth);
   }

   if (fLineStyle > 0 && fLineStyle < 30) gPad->SetAttLinePS(fLineColor,fLineStyle,lineWidth);
   else                                   gPad->SetAttLinePS(fLineColor,1,lineWidth);
}

//______________________________________________________________________________
void TAttLine::ResetAttLine(Option_t *)
{
   // Reset this line attributes to default values.

   fLineColor  = 1;
   fLineStyle  = 1;
   fLineWidth  = 1;
}

//______________________________________________________________________________
void TAttLine::SaveLineAttributes(ostream &out, const char *name, Int_t coldef, Int_t stydef, Int_t widdef)
{
   // Save line attributes as C++ statement(s) on output stream out.

   if (fLineColor != coldef) {
      if (fLineColor > 228) {
         TColor::SaveColor(out, fLineColor);
         out<<"   "<<name<<"->SetLineColor(ci);" << endl;
      } else
         out<<"   "<<name<<"->SetLineColor("<<fLineColor<<");"<<endl;
   }
   if (fLineStyle != stydef) {
      out<<"   "<<name<<"->SetLineStyle("<<fLineStyle<<");"<<endl;
   }
   if (fLineWidth != widdef) {
      out<<"   "<<name<<"->SetLineWidth("<<fLineWidth<<");"<<endl;
   }
}

//______________________________________________________________________________
void TAttLine::SetLineAttributes()
{
   // Invoke the DialogCanvas Line attributes.

   TVirtualPadEditor::UpdateLineAttributes(fLineColor,fLineStyle,fLineWidth);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/vlog.h"

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace logging {

namespace {

class VlogTest : public testing::Test {
};

TEST_F(VlogTest, NoVmodule) {
  EXPECT_EQ(0, VlogInfo("", "").GetVlogLevel("test1"));
  EXPECT_EQ(0, VlogInfo("0", "").GetVlogLevel("test2"));
  EXPECT_EQ(0, VlogInfo("blah", "").GetVlogLevel("test3"));
  EXPECT_EQ(0, VlogInfo("0blah1", "").GetVlogLevel("test4"));
  EXPECT_EQ(1, VlogInfo("1", "").GetVlogLevel("test5"));
  EXPECT_EQ(5, VlogInfo("5", "").GetVlogLevel("test6"));
}

TEST_F(VlogTest, Vmodule) {
  const char kVSwitch[] = "-1";
  const char kVModuleSwitch[] =
      "foo=,bar=0,baz=blah,,qux=0blah1,quux=1,corge=5";
  VlogInfo vlog_info(kVSwitch, kVModuleSwitch);
  EXPECT_EQ(-1, vlog_info.GetVlogLevel("/path/to/grault.cc"));
  EXPECT_EQ(0, vlog_info.GetVlogLevel("/path/to/foo.cc"));
  EXPECT_EQ(0, vlog_info.GetVlogLevel("D:\\Path\\To\\bar-inl.mm"));
  EXPECT_EQ(-1, vlog_info.GetVlogLevel("D:\\path\\to what/bar_unittest.m"));
  EXPECT_EQ(0, vlog_info.GetVlogLevel("baz.h"));
  EXPECT_EQ(0, vlog_info.GetVlogLevel("/another/path/to/qux.h"));
  EXPECT_EQ(1, vlog_info.GetVlogLevel("/path/to/quux"));
  EXPECT_EQ(5, vlog_info.GetVlogLevel("c:\\path/to/corge.h"));
}

#define BENCHMARK(iters, elapsed, code)                         \
  do {                                                          \
    base::TimeTicks start = base::TimeTicks::Now();             \
    for (int i = 0; i < iters; ++i) code;                       \
    base::TimeTicks end = base::TimeTicks::Now();               \
    elapsed = end - start;                                      \
    double cps = iters / elapsed.InSecondsF();                  \
    LOG(INFO) << cps << " cps (" << elapsed.InSecondsF()        \
              << "s elapsed)";                                  \
  } while (0)

double GetSlowdown(const base::TimeDelta& base,
                   const base::TimeDelta& elapsed) {
  return elapsed.InSecondsF() / base.InSecondsF();
}

TEST_F(VlogTest, Perf) {
  const char* kVlogs[] = {
    "/path/to/foo.cc",
    "C:\\path\\to\\bar.h",
    "/path/to/not-matched.mm",
    "C:\\path\\to\\baz-inl.mm",
    "C:\\path\\to\\qux.mm",
    "/path/to/quux.mm",
    "/path/to/another-not-matched.mm",
  };
  const int kVlogCount = arraysize(kVlogs);

  base::TimeDelta null_elapsed;
  {
    VlogInfo null_vlog_info("", "");
    BENCHMARK(10000000, null_elapsed, {
      EXPECT_NE(-1, null_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
    });
  }

  {
    VlogInfo small_vlog_info("0", "foo=1,bar=2,baz=3,qux=4,quux=5");
    base::TimeDelta elapsed;
    BENCHMARK(10000000, elapsed, {
      EXPECT_NE(-1, small_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
    });
    LOG(INFO) << "slowdown = " << GetSlowdown(null_elapsed, elapsed)
              << "x";
  }

  {
    VlogInfo pattern_vlog_info("0", "fo*=1,ba?=2,b*?z=3,*ux=4,?uux=5");
    base::TimeDelta elapsed;
    BENCHMARK(10000000, elapsed, {
      EXPECT_NE(-1, pattern_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
    });
    LOG(INFO) << "slowdown = " << GetSlowdown(null_elapsed, elapsed)
              << "x";
  }
}

#undef BENCHMARK

}  // namespace

}  // namespace logging
<commit_msg>If VlogTest.Perf is ran under Valgrind, decrease the number of benchmark iterations. Otherwise the test may time out due to slowdown.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/vlog.h"

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace logging {

namespace {

class VlogTest : public testing::Test {
};

TEST_F(VlogTest, NoVmodule) {
  EXPECT_EQ(0, VlogInfo("", "").GetVlogLevel("test1"));
  EXPECT_EQ(0, VlogInfo("0", "").GetVlogLevel("test2"));
  EXPECT_EQ(0, VlogInfo("blah", "").GetVlogLevel("test3"));
  EXPECT_EQ(0, VlogInfo("0blah1", "").GetVlogLevel("test4"));
  EXPECT_EQ(1, VlogInfo("1", "").GetVlogLevel("test5"));
  EXPECT_EQ(5, VlogInfo("5", "").GetVlogLevel("test6"));
}

TEST_F(VlogTest, Vmodule) {
  const char kVSwitch[] = "-1";
  const char kVModuleSwitch[] =
      "foo=,bar=0,baz=blah,,qux=0blah1,quux=1,corge=5";
  VlogInfo vlog_info(kVSwitch, kVModuleSwitch);
  EXPECT_EQ(-1, vlog_info.GetVlogLevel("/path/to/grault.cc"));
  EXPECT_EQ(0, vlog_info.GetVlogLevel("/path/to/foo.cc"));
  EXPECT_EQ(0, vlog_info.GetVlogLevel("D:\\Path\\To\\bar-inl.mm"));
  EXPECT_EQ(-1, vlog_info.GetVlogLevel("D:\\path\\to what/bar_unittest.m"));
  EXPECT_EQ(0, vlog_info.GetVlogLevel("baz.h"));
  EXPECT_EQ(0, vlog_info.GetVlogLevel("/another/path/to/qux.h"));
  EXPECT_EQ(1, vlog_info.GetVlogLevel("/path/to/quux"));
  EXPECT_EQ(5, vlog_info.GetVlogLevel("c:\\path/to/corge.h"));
}

#define BENCHMARK(iters, elapsed, code)                         \
  do {                                                          \
    base::TimeTicks start = base::TimeTicks::Now();             \
    for (int i = 0; i < iters; ++i) code;                       \
    base::TimeTicks end = base::TimeTicks::Now();               \
    elapsed = end - start;                                      \
    double cps = iters / elapsed.InSecondsF();                  \
    LOG(INFO) << cps << " cps (" << elapsed.InSecondsF()        \
              << "s elapsed)";                                  \
  } while (0)

double GetSlowdown(const base::TimeDelta& base,
                   const base::TimeDelta& elapsed) {
  return elapsed.InSecondsF() / base.InSecondsF();
}

TEST_F(VlogTest, Perf) {
  const char* kVlogs[] = {
    "/path/to/foo.cc",
    "C:\\path\\to\\bar.h",
    "/path/to/not-matched.mm",
    "C:\\path\\to\\baz-inl.mm",
    "C:\\path\\to\\qux.mm",
    "/path/to/quux.mm",
    "/path/to/another-not-matched.mm",
  };
  const int kVlogCount = arraysize(kVlogs);
  const int kBenchmarkIterations = RunningOnValgrind() ? 30000 : 10000000;

  base::TimeDelta null_elapsed;
  {
    VlogInfo null_vlog_info("", "");
    BENCHMARK(kBenchmarkIterations, null_elapsed, {
      EXPECT_NE(-1, null_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
    });
  }

  {
    VlogInfo small_vlog_info("0", "foo=1,bar=2,baz=3,qux=4,quux=5");
    base::TimeDelta elapsed;
    BENCHMARK(kBenchmarkIterations, elapsed, {
      EXPECT_NE(-1, small_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
    });
    LOG(INFO) << "slowdown = " << GetSlowdown(null_elapsed, elapsed)
              << "x";
  }

  {
    VlogInfo pattern_vlog_info("0", "fo*=1,ba?=2,b*?z=3,*ux=4,?uux=5");
    base::TimeDelta elapsed;
    BENCHMARK(kBenchmarkIterations, elapsed, {
      EXPECT_NE(-1, pattern_vlog_info.GetVlogLevel(kVlogs[i % kVlogCount]));
    });
    LOG(INFO) << "slowdown = " << GetSlowdown(null_elapsed, elapsed)
              << "x";
  }
}

#undef BENCHMARK

}  // namespace

}  // namespace logging
<|endoftext|>


<commit_before>// Title       : Implementation of Coroutine in Cpp
// Author      : hanzh.xu@gmail.com
// Date        : 11-22-2020
// License     : MIT License

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <vector>

using namespace std;

template<typename T>
class Gen : public std::enable_shared_from_this<Gen<T>> {
public:
    int state;
    Gen() : state(0) {}
    virtual bool next(T& output) = 0;
    bool operator()(T& output) {
        return next(output);
    }
};

template<typename S, typename T>
class Coroutine : public std::enable_shared_from_this<Coroutine<S,T>> {
public:
    int state;
    Coroutine() : state(0) {}
    virtual ~Coroutine() {}
    virtual bool next(S& input, T &output) = 0;
    bool operator()(S& input, T &output) {
        return next(input, output);
    }
    shared_ptr<Coroutine<S,T>> getPtr() { return this->shared_from_this(); }
};

#define PRG_BEG \
switch(state) { \
case 0:;

#define PRG_END \
case -1:; \
default: { return false; } }

#define YIELD() \
do { state=__LINE__; return true; case __LINE__:; } while (0)

#define RETURN() { state = -1; return false; }

/* Examples */

/*
L: def prod_iter(s):
0:   if len(s) == 0:
1:     yield []
2:   else:
3:     x = 0
4:     while true:
5:       xs = []
6:       iter = generator.create(prod_iter(s[1:]))
7:       while true:
8:         xs, isAlive = iter.resume()
9:         if !isAlive:
10           break
11         yield [x] + xs
12       x += 1
13       if x >= s[0]:
14         break
-1   return
*/
class BetterProdGen : public Gen<vector<int>> {
public:
    vector<unsigned int> s;
    int x;
    shared_ptr<BetterProdGen> iter;
    vector<int> xs;
    BetterProdGen(const vector<unsigned int>& _s) : s(_s) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(s.size()==0) {
            output.clear();
            YIELD();
            RETURN();
        }
        for(x = 0; x < s[0]; ++x) {
            iter = make_shared<BetterProdGen>(
                vector<unsigned int>(s.begin() + 1, s.end()));
            while(iter->next(xs)) {
                output.clear();
                output.push_back(x);
                output.insert(output.end(), xs.begin(), xs.end());
                YIELD();
            }
        }
        PRG_END
    }
};

/*
def hanoi(n, a, b, c):
    if n == 1:
        s = str(a) +  ' --> ' + str(c)
        yield s
    else:
        for s in hanoi(n - 1, a, c, b):
            yield s
        for s in hanoi(1    , a, b, c):
            yield s
        for s in hanoi(n - 1, b, a, c):
            yield s
*/
class BetterHanoiGen : public Gen<string> {
public:
    int n;
    string a, b, c;
    shared_ptr<Gen<string> > iter;
    BetterHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}
    bool next(string& output) {
        PRG_BEG
        if(n == 1) {
            output = a + " --> " + c;
            YIELD();
            RETURN();
        }
        iter = make_shared<BetterHanoiGen>(n - 1, a, c, b);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(1, a, b, c);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(n - 1, b, a, c);
        while(iter->next(output)) YIELD();
        PRG_END
    }
};

class PrimeGen : public Gen<int> {
public:
    vector<int> primes;
    int i, j;
    PrimeGen() {}
    bool next(int& output) {
        PRG_BEG
        for(i = 2; true; ++i) {
            j = 0;
            for(j = 0; j < primes.size(); ++j) {
                if(i % primes[j] == 0) {
                    goto loop1_end;
                }
            }
            primes.push_back(i);
            output = i;
            YIELD();
            loop1_end:;
        }
        PRG_END
    }
};

class SubsetGen: public Gen<vector<int> > {
public:
    int n, i, j;
    SubsetGen(int _n) : n(_n) {}
    bool next(vector<int>& output) {
        PRG_BEG
        for(i = 0; i < (1 << n); ++i) {
            output.clear();
            for(int j = 0; j < n; ++j) {
                if((i >> j) & 1) {
                    output.push_back(j);
                }
            }
            YIELD();
        }
        PRG_END
    }
};

class PermutationGen: public Gen<vector<int> > {
public:
    int beg, n, i;
    vector<int>& arr;
    shared_ptr<PermutationGen> iter;
    PermutationGen(int _beg, vector<int>& _arr) : beg(_beg), n(_arr.size()), arr(_arr) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(beg >= n - 1) {
            for(i = 0; i < n; ++i) {
                output[i] = arr[i];
            }
            YIELD();
            RETURN();
        }
        for(i = beg; i < n; ++i) {
            swap(arr[beg], arr[i]);
            iter = make_shared<PermutationGen>(beg + 1, arr);
            while((*iter)(output)) YIELD();
            swap(arr[beg], arr[i]);
        }
        PRG_END
    }
    void swap(int& a, int &b) {
        int c = a;
        a = b;
        b = c;
    }
};

class GuessNumber : public Coroutine<int, int> {
public:
    int t, num;
    GuessNumber() {}
    bool next(int& input, int& output) {
        PRG_BEG
        t = 0;
        srand(time(0));
        cout << "Guess a number between 0 and 100!" << endl;
        while(true) {
            cout << "Match " << t << endl;
            num = rand() % 100;
            cout << "input a number:";
            YIELD();
            while(input != num) {
                if(input == -1) RETURN();
                if(input < num) {
                    cout << "Too low!" << endl;
                    output = -1;
                } else {
                    cout << "Too high!" << endl;
                    output = 1;
                }
                cout << "input a number agian:";
                YIELD();
            }
            cout << "Bingo! It's " << num << "!" << endl;
            cout << "Let's play it again!" << endl;
            t++;
            output = 0;
        }
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

class GuessYourNumber : public Coroutine<string, int> {
public:
    int beg, end, mid;
    GuessYourNumber() {}
    bool next(string& input, int& output) {
        PRG_BEG
        cout << "Keep a number between 0 and 100 in your mind!" << endl;
        cout << "Are you ready?(y/n)" << endl;
        YIELD();
        if(input[0] != 'y') {
            goto bye;
        }
        beg = 0, end = 101;
        while(beg < end) {
            mid = (beg + end) / 2;
            cout << "Is it " << mid << "?" << endl;
            cout << "Input 's' if it is smaller than your number." << endl;
            cout << "Input 'b' if it is bigger than your number." << endl;
            cout << "Input 'y' if it is your number!" << endl;
            YIELD();
            if(input[0] == 's') {
                beg = mid+1;
            } else if(input[0] == 'b') {
                end = mid;
            } else {
                cout << "YES! It's " << mid << "!" << endl;
                RETURN();
            }
        }
        cout << "No possible! The number must be " << mid << "!" << endl;
        bye:;
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

template<typename T>
void print(vector<T>& vec) {
    cout << "{ ";
    for(int i = 0; i < vec.size(); ++i) {
        cout << vec[i] << ", ";
    }
    cout << "}" << endl;
}

void testBetterHanoiGen() {
    cout << "testBetterHanoiGen" << endl;
    string s;
    BetterHanoiGen gen(3, "A", "B", "C");
    int k = 0;
    while(gen(s)) {
        cout << s << endl;
        k++;
    }
    cout << "HanoiGen is solved in " << k << " steps." << endl;
}

void testPrimeGen() {
    cout << "Prime numbers" << endl;
    PrimeGen primeGen;
    int p;
    for(int i = 0; i < 30; ++i) {
        primeGen(p);
        cout << p << " ";
    }
    cout << endl;
}

void testSubsetGen() {
    cout << "testSubsetGen" << endl;
    int n = 5;
    vector<int> output(n);
    SubsetGen gen(n);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Subsets." << endl;
}

void testPermutationGen() {
    cout << "testPermutationGen" << endl;
    vector<int> arr({1,2,3,4});
    PermutationGen gen(0, arr);
    vector<int> output(arr.size());
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Permutations." << endl;
}

void testBetterProdGen() {
    cout << "testBetterProdGen" << endl;
    vector<unsigned int> dimSize({3,2,4});
    vector<int> output(dimSize.size());
    BetterProdGen gen(dimSize);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " rows." << endl;
}

void testGuessNumber() {
    GuessNumber guess;
    int num, output;
    guess(num, output);
    do {
        cin >> num;
    } while(guess(num, output));
}

void testGuessYourNumber() {
    cout << "testGuessYourNumber" << endl;
    GuessYourNumber guess;
    string input;
    int output;
    guess(input, output);
    do {
        cin >> input;
    } while(guess(input, output));
}

int main() {

    testBetterHanoiGen();

    testPrimeGen();

    testSubsetGen();

    testPermutationGen();

    testBetterProdGen();

    // testGuessNumber();

    // testGuessYourNumber();

    return 0;
}
<commit_msg>Update macro_v2.cpp<commit_after>// Title       : Implementation of Coroutine in Cpp, Version 2.0
// Author      : hanzh.xu@gmail.com
// Date        : 11-22-2020
// License     : MIT License

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <vector>

using namespace std;

template<typename T>
class Gen : public std::enable_shared_from_this<Gen<T>> {
public:
    int state;
    Gen() : state(0) {}
    virtual bool next(T& output) = 0;
    bool operator()(T& output) {
        return next(output);
    }
};

template<typename S, typename T>
class Coroutine : public std::enable_shared_from_this<Coroutine<S,T>> {
public:
    int state;
    Coroutine() : state(0) {}
    virtual ~Coroutine() {}
    virtual bool next(S& input, T &output) = 0;
    bool operator()(S& input, T &output) {
        return next(input, output);
    }
    shared_ptr<Coroutine<S,T>> getPtr() { return this->shared_from_this(); }
};

#define PRG_BEG \
switch(state) { \
case 0:;

#define PRG_END \
case -1:; \
default: { return false; } }

#define YIELD() \
do { state=__LINE__; return true; case __LINE__:; } while (0)

#define RETURN() { state = -1; return false; }

/* Examples */

/*
L: def prod_iter(s):
0:   if len(s) == 0:
1:     yield []
2:   else:
3:     x = 0
4:     while true:
5:       xs = []
6:       iter = generator.create(prod_iter(s[1:]))
7:       while true:
8:         xs, isAlive = iter.resume()
9:         if !isAlive:
10           break
11         yield [x] + xs
12       x += 1
13       if x >= s[0]:
14         break
-1   return
*/
class BetterProdGen : public Gen<vector<int>> {
public:
    vector<unsigned int> s;
    int x;
    shared_ptr<BetterProdGen> iter;
    vector<int> xs;
    BetterProdGen(const vector<unsigned int>& _s) : s(_s) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(s.size()==0) {
            output.clear();
            YIELD();
            RETURN();
        }
        for(x = 0; x < s[0]; ++x) {
            iter = make_shared<BetterProdGen>(
                vector<unsigned int>(s.begin() + 1, s.end()));
            while(iter->next(xs)) {
                output.clear();
                output.push_back(x);
                output.insert(output.end(), xs.begin(), xs.end());
                YIELD();
            }
        }
        PRG_END
    }
};

/*
def hanoi(n, a, b, c):
    if n == 1:
        s = str(a) +  ' --> ' + str(c)
        yield s
    else:
        for s in hanoi(n - 1, a, c, b):
            yield s
        for s in hanoi(1    , a, b, c):
            yield s
        for s in hanoi(n - 1, b, a, c):
            yield s
*/
class BetterHanoiGen : public Gen<string> {
public:
    int n;
    string a, b, c;
    shared_ptr<Gen<string> > iter;
    BetterHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}
    bool next(string& output) {
        PRG_BEG
        if(n == 1) {
            output = a + " --> " + c;
            YIELD();
            RETURN();
        }
        iter = make_shared<BetterHanoiGen>(n - 1, a, c, b);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(1, a, b, c);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(n - 1, b, a, c);
        while(iter->next(output)) YIELD();
        PRG_END
    }
};

class PrimeGen : public Gen<int> {
public:
    vector<int> primes;
    int i, j;
    PrimeGen() {}
    bool next(int& output) {
        PRG_BEG
        for(i = 2; true; ++i) {
            j = 0;
            for(j = 0; j < primes.size(); ++j) {
                if(i % primes[j] == 0) {
                    goto loop1_end;
                }
            }
            primes.push_back(i);
            output = i;
            YIELD();
            loop1_end:;
        }
        PRG_END
    }
};

class SubsetGen: public Gen<vector<int> > {
public:
    int n, i, j;
    SubsetGen(int _n) : n(_n) {}
    bool next(vector<int>& output) {
        PRG_BEG
        for(i = 0; i < (1 << n); ++i) {
            output.clear();
            for(int j = 0; j < n; ++j) {
                if((i >> j) & 1) {
                    output.push_back(j);
                }
            }
            YIELD();
        }
        PRG_END
    }
};

class PermutationGen: public Gen<vector<int> > {
public:
    int beg, n, i;
    vector<int>& arr;
    shared_ptr<PermutationGen> iter;
    PermutationGen(int _beg, vector<int>& _arr) : beg(_beg), n(_arr.size()), arr(_arr) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(beg >= n - 1) {
            for(i = 0; i < n; ++i) {
                output[i] = arr[i];
            }
            YIELD();
            RETURN();
        }
        for(i = beg; i < n; ++i) {
            swap(arr[beg], arr[i]);
            iter = make_shared<PermutationGen>(beg + 1, arr);
            while((*iter)(output)) YIELD();
            swap(arr[beg], arr[i]);
        }
        PRG_END
    }
    void swap(int& a, int &b) {
        int c = a;
        a = b;
        b = c;
    }
};

class GuessNumber : public Coroutine<int, int> {
public:
    int t, num;
    GuessNumber() {}
    bool next(int& input, int& output) {
        PRG_BEG
        t = 0;
        srand(time(0));
        cout << "Guess a number between 0 and 100!" << endl;
        while(true) {
            cout << "Match " << t << endl;
            num = rand() % 100;
            cout << "input a number:";
            YIELD();
            while(input != num) {
                if(input == -1) RETURN();
                if(input < num) {
                    cout << "Too low!" << endl;
                    output = -1;
                } else {
                    cout << "Too high!" << endl;
                    output = 1;
                }
                cout << "input a number agian:";
                YIELD();
            }
            cout << "Bingo! It's " << num << "!" << endl;
            cout << "Let's play it again!" << endl;
            t++;
            output = 0;
        }
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

class GuessYourNumber : public Coroutine<string, int> {
public:
    int beg, end, mid;
    GuessYourNumber() {}
    bool next(string& input, int& output) {
        PRG_BEG
        cout << "Keep a number between 0 and 100 in your mind!" << endl;
        cout << "Are you ready?(y/n)" << endl;
        YIELD();
        if(input[0] != 'y') {
            goto bye;
        }
        beg = 0, end = 101;
        while(beg < end) {
            mid = (beg + end) / 2;
            cout << "Is it " << mid << "?" << endl;
            cout << "Input 's' if it is smaller than your number." << endl;
            cout << "Input 'b' if it is bigger than your number." << endl;
            cout << "Input 'y' if it is your number!" << endl;
            YIELD();
            if(input[0] == 's') {
                beg = mid+1;
            } else if(input[0] == 'b') {
                end = mid;
            } else {
                cout << "YES! It's " << mid << "!" << endl;
                RETURN();
            }
        }
        cout << "No possible! The number must be " << mid << "!" << endl;
        bye:;
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

template<typename T>
void print(vector<T>& vec) {
    cout << "{ ";
    for(int i = 0; i < vec.size(); ++i) {
        cout << vec[i] << ", ";
    }
    cout << "}" << endl;
}

void testBetterHanoiGen() {
    cout << "testBetterHanoiGen" << endl;
    string s;
    BetterHanoiGen gen(3, "A", "B", "C");
    int k = 0;
    while(gen(s)) {
        cout << s << endl;
        k++;
    }
    cout << "HanoiGen is solved in " << k << " steps." << endl;
}

void testPrimeGen() {
    cout << "Prime numbers" << endl;
    PrimeGen primeGen;
    int p;
    for(int i = 0; i < 30; ++i) {
        primeGen(p);
        cout << p << " ";
    }
    cout << endl;
}

void testSubsetGen() {
    cout << "testSubsetGen" << endl;
    int n = 5;
    vector<int> output(n);
    SubsetGen gen(n);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Subsets." << endl;
}

void testPermutationGen() {
    cout << "testPermutationGen" << endl;
    vector<int> arr({1,2,3,4});
    PermutationGen gen(0, arr);
    vector<int> output(arr.size());
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Permutations." << endl;
}

void testBetterProdGen() {
    cout << "testBetterProdGen" << endl;
    vector<unsigned int> dimSize({3,2,4});
    vector<int> output(dimSize.size());
    BetterProdGen gen(dimSize);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " rows." << endl;
}

void testGuessNumber() {
    GuessNumber guess;
    int num, output;
    guess(num, output);
    do {
        cin >> num;
    } while(guess(num, output));
}

void testGuessYourNumber() {
    cout << "testGuessYourNumber" << endl;
    GuessYourNumber guess;
    string input;
    int output;
    guess(input, output);
    do {
        cin >> input;
    } while(guess(input, output));
}

int main() {

    testBetterHanoiGen();

    testPrimeGen();

    testSubsetGen();

    testPermutationGen();

    testBetterProdGen();

    // testGuessNumber();

    // testGuessYourNumber();

    return 0;
}
<|endoftext|>


<commit_before>// Title       : Implementation of Coroutine in Cpp, Version 2.0
// Author      : hanzh.xu@gmail.com
// Date        : 11-22-2020
// License     : MIT License

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <vector>

using namespace std;

template<typename T>
class Generator : public std::enable_shared_from_this<Generator<T>> {
public:
    int state;
    Generator() : state(0) {}
    virtual bool next(T& output) = 0;
    bool operator()(T& output) {
        return next(output);
    }
    shared_ptr<Generator<T>> getPtr() { return this->shared_from_this(); }
};

template<typename T>
class IteratorHelper : public std::enable_shared_from_this<IteratorHelper<T>> {
public:
    shared_ptr<Generator<T>> gen;
    T output;
    bool pending;
    IteratorHelper(Generator<T> &_gen) : gen(_gen.getPtr()),  pending(false) {}
    IteratorHelper(shared_ptr<Generator<T>> _gen) : gen(_gen),  pending(false) {}
    T next() {
        if(!pending) hasNext();
        if(pending) {
            pending = false;
        } else {
            // Error, Iterator is done.
        }
        return output;
    }
    bool hasNext() {
        if(pending) return pending;
        return pending = gen->next(output);
    }
    shared_ptr<IteratorHelper<T>> getPtr() { return this->shared_from_this(); }
};

template<typename S, typename T>
class Coroutine : public std::enable_shared_from_this<Coroutine<S,T>> {
public:
    int state;
    Coroutine() : state(0) {}
    virtual ~Coroutine() {}
    virtual bool next(S& input, T &output) = 0;
    bool operator()(S& input, T &output) {
        return next(input, output);
    }
    shared_ptr<Coroutine<S,T>> getPtr() { return this->shared_from_this(); }
};

#define PRG_BEG \
switch(state) { \
case 0:;

#define PRG_END \
case -1:; \
default: { return false; } }

#define YIELD() \
do { state = __LINE__; return true; case __LINE__:; } while(0)

#define RETURN() \
do { state = -1; return false; } while(0)

/* Examples */

class FibGen : public Generator<int> {
public:
    int a, b;
    FibGen() : a(1), b(1) {}
    bool next(int &output) {
        PRG_BEG
        while(true) {
            output = a;
            a = b;
            b = output + a;
            YIELD();
        }
        PRG_END
    }
};

void testFibGen() {
    cout << "testFibGen" << endl;
    FibGen gen;
    int x;
    for(int i = 0; i < 30; ++i) {
        gen(x);
        cout << x << " ";
    }
    cout << endl;
}

/*
L: def prod_iter(s):
0:   if len(s) == 0:
1:     yield []
2:   else:
3:     x = 0
4:     while true:
5:       xs = []
6:       iter = generator.create(prod_iter(s[1:]))
7:       while true:
8:         xs, isAlive = iter.resume()
9:         if !isAlive:
10           break
11         yield [x] + xs
12       x += 1
13       if x >= s[0]:
14         break
-1   return
*/
class BetterProdGen : public Generator<vector<int>> {
public:
    vector<unsigned int> s;
    int x;
    shared_ptr<BetterProdGen> iter;
    vector<int> xs;
    BetterProdGen(const vector<unsigned int>& _s) : s(_s) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(s.size()==0) {
            output.clear();
            YIELD();
            RETURN();
        }
        for(x = 0; x < s[0]; ++x) {
            iter = make_shared<BetterProdGen>(
                vector<unsigned int>(s.begin() + 1, s.end()));
            while(iter->next(xs)) {
                output.clear();
                output.push_back(x);
                output.insert(output.end(), xs.begin(), xs.end());
                YIELD();
            }
        }
        PRG_END
    }
};

/*
def hanoi(n, a, b, c):
    if n == 1:
        s = str(a) +  ' --> ' + str(c)
        yield s
    else:
        for s in hanoi(n - 1, a, c, b):
            yield s
        for s in hanoi(1    , a, b, c):
            yield s
        for s in hanoi(n - 1, b, a, c):
            yield s
*/
class BetterHanoiGen : public Generator<string> {
public:
    int n;
    string a, b, c;
    shared_ptr<Generator<string> > iter;
    BetterHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}
    bool next(string& output) {
        PRG_BEG
        if(n == 1) {
            output = a + " --> " + c;
            YIELD();
            RETURN();
        }
        iter = make_shared<BetterHanoiGen>(n - 1, a, c, b);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(1, a, b, c);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(n - 1, b, a, c);
        while(iter->next(output)) YIELD();
        PRG_END
    }
};

class PrimeGen : public Generator<int> {
public:
    vector<int> primes;
    int i, j;
    PrimeGen() {}
    bool next(int& output) {
        PRG_BEG
        for(i = 2; true; ++i) {
            j = 0;
            for(j = 0; j < primes.size(); ++j) {
                if(i % primes[j] == 0) {
                    goto loop1_end;
                }
            }
            primes.push_back(i);
            output = i;
            YIELD();
            loop1_end:;
        }
        PRG_END
    }
};

class SubsetGen: public Generator<vector<int> > {
public:
    int n, i, j;
    SubsetGen(int _n) : n(_n) {}
    bool next(vector<int>& output) {
        PRG_BEG
        for(i = 0; i < (1 << n); ++i) {
            output.clear();
            for(int j = 0; j < n; ++j) {
                if((i >> j) & 1) {
                    output.push_back(j);
                }
            }
            YIELD();
        }
        PRG_END
    }
};

class PermutationGen: public Generator<vector<int> > {
public:
    int beg, n, i;
    vector<int>& arr;
    shared_ptr<PermutationGen> iter;
    PermutationGen(int _beg, vector<int>& _arr) : beg(_beg), n(_arr.size()), arr(_arr) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(beg >= n - 1) {
            for(i = 0; i < n; ++i) {
                output[i] = arr[i];
            }
            YIELD();
            RETURN();
        }
        for(i = beg; i < n; ++i) {
            swap(arr[beg], arr[i]);
            iter = make_shared<PermutationGen>(beg + 1, arr);
            while((*iter)(output)) YIELD();
            swap(arr[beg], arr[i]);
        }
        PRG_END
    }
    void swap(int& a, int &b) {
        int c = a;
        a = b;
        b = c;
    }
};

class GuessNumber : public Coroutine<int, int> {
public:
    int t, num;
    GuessNumber() {}
    bool next(int& input, int& output) {
        PRG_BEG
        t = 0;
        srand(time(0));
        cout << "Guess a number between 0 and 100!" << endl;
        while(true) {
            cout << "Match " << t << endl;
            num = rand() % 100;
            cout << "input a number:";
            YIELD();
            while(input != num) {
                if(input == -1) RETURN();
                if(input < num) {
                    cout << "Too low!" << endl;
                    output = -1;
                } else {
                    cout << "Too high!" << endl;
                    output = 1;
                }
                cout << "input a number agian:";
                YIELD();
            }
            cout << "Bingo! It's " << num << "!" << endl;
            cout << "Let's play it again!" << endl;
            t++;
            output = 0;
        }
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

class GuessYourNumber : public Coroutine<string, int> {
public:
    int beg, end, mid;
    GuessYourNumber() {}
    bool next(string& input, int& output) {
        PRG_BEG
        cout << "Keep a number between 0 and 100 in your mind!" << endl;
        cout << "Are you ready?(y/n)" << endl;
        YIELD();
        if(input[0] != 'y') {
            goto bye;
        }
        beg = 0, end = 101;
        while(beg < end) {
            mid = (beg + end) / 2;
            cout << "Is it " << mid << "?" << endl;
            cout << "Input 's' if it is smaller than your number." << endl;
            cout << "Input 'b' if it is bigger than your number." << endl;
            cout << "Input 'y' if it is your number!" << endl;
            YIELD();
            if(input[0] == 's') {
                beg = mid+1;
            } else if(input[0] == 'b') {
                end = mid;
            } else {
                cout << "YES! It's " << mid << "!" << endl;
                RETURN();
            }
        }
        cout << "No possible! The number must be " << mid << "!" << endl;
        bye:;
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

template<typename T>
void print(vector<T>& vec) {
    cout << "{ ";
    for(int i = 0; i < vec.size(); ++i) {
        cout << vec[i] << ", ";
    }
    cout << "}" << endl;
}

void testBetterHanoiGen() {
    cout << "testBetterHanoiGen" << endl;
    string s;
    BetterHanoiGen gen(3, "A", "B", "C");
    int k = 0;
    while(gen(s)) {
        cout << s << endl;
        k++;
    }
    cout << "HanoiGen is solved in " << k << " steps." << endl;
}

void testPrimeGen() {
    cout << "Prime numbers" << endl;
    PrimeGen primeGen;
    int p;
    for(int i = 0; i < 30; ++i) {
        primeGen(p);
        cout << p << " ";
    }
    cout << endl;
}

void testSubsetGen() {
    cout << "testSubsetGen" << endl;
    int n = 5;
    vector<int> output(n);
    SubsetGen gen(n);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Subsets." << endl;
}

void testPermutationGen() {
    cout << "testPermutationGen" << endl;
    vector<int> arr({1,2,3,4});
    PermutationGen gen(0, arr);
    vector<int> output(arr.size());
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Permutations." << endl;
}

void testBetterProdGen() {
    cout << "testBetterProdGen" << endl;
    vector<unsigned int> dimSize({3,2,4});
    vector<int> output(dimSize.size());
    BetterProdGen gen(dimSize);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " rows." << endl;
}

void testGuessNumber() {
    GuessNumber guess;
    int num, output;
    guess(num, output);
    do {
        cin >> num;
    } while(guess(num, output));
}

void testGuessYourNumber() {
    cout << "testGuessYourNumber" << endl;
    GuessYourNumber guess;
    string input;
    int output;
    guess(input, output);
    do {
        cin >> input;
    } while(guess(input, output));
}

int main() {

    testFibGen();

    testBetterHanoiGen();

    testPrimeGen();

    testSubsetGen();

    testPermutationGen();

    testBetterProdGen();

    // testGuessNumber();

    // testGuessYourNumber();

    return 0;
}
<commit_msg>Update macro_v2.cpp<commit_after>// Title       : Implementation of Coroutine in Cpp, Version 2.0
// Author      : hanzh.xu@gmail.com
// Date        : 11-22-2020
// License     : MIT License

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <vector>

#define PRG_BEG \
switch(state) { \
case 0:;

#define PRG_END \
case -1:; \
default: { return false; } }

#define YIELD() \
do { state = __LINE__; return true; case __LINE__:; } while(0)

#define YIELD_ALL(iter,output) \
do { while((iter)->next((output))) { YIELD(); } } while(0)

#define RETURN() \
do { state = -1; return false; } while(0)

using namespace std;

template<typename T>
class Generator : public std::enable_shared_from_this<Generator<T>> {
public:
    int state;
    Generator() : state(0) {}
    virtual bool next(T& output) = 0;
    bool operator()(T& output) {
        return next(output);
    }
    shared_ptr<Generator<T>> getPtr() { return this->shared_from_this(); }
};

template<typename T>
class GenIter : public std::enable_shared_from_this<GenIter<T>> {
public:
    shared_ptr<Generator<T>> gen;
    T output;
    bool pending;
    GenIter(Generator<T> &_gen) : gen(_gen.getPtr()),  pending(false) {}
    GenIter(shared_ptr<Generator<T>> _gen) : gen(_gen),  pending(false) {}
    T next() {
        if(!pending) hasNext();
        if(pending) {
            pending = false;
        } else {
            // Error, Iterator is done.
        }
        return output;
    }
    bool hasNext() {
        if(pending) return pending;
        return pending = gen->next(output);
    }
    shared_ptr<GenIter<T>> getPtr() { return this->shared_from_this(); }
};

template<typename S, typename T>
class Coroutine : public std::enable_shared_from_this<Coroutine<S,T>> {
public:
    int state;
    Coroutine() : state(0) {}
    virtual ~Coroutine() {}
    virtual bool next(S& input, T &output) = 0;
    bool operator()(S& input, T &output) {
        return next(input, output);
    }
    shared_ptr<Coroutine<S,T>> getPtr() { return this->shared_from_this(); }
};

/* Examples */

class FibGen : public Generator<int> {
public:
    int a, b;
    FibGen() : a(1), b(1) {}
    bool next(int &output) {
        PRG_BEG
        while(true) {
            output = a;
            a = b;
            b = output + a;
            YIELD();
        }
        PRG_END
    }
};

void testFibGen() {
    cout << "testFibGen" << endl;
    FibGen gen;
    int x;
    for(int i = 0; i < 30; ++i) {
        gen(x);
        cout << x << " ";
    }
    cout << endl;
}

/*
L: def prod_iter(s):
0:   if len(s) == 0:
1:     yield []
2:   else:
3:     x = 0
4:     while true:
5:       xs = []
6:       iter = generator.create(prod_iter(s[1:]))
7:       while true:
8:         xs, isAlive = iter.resume()
9:         if !isAlive:
10           break
11         yield [x] + xs
12       x += 1
13       if x >= s[0]:
14         break
-1   return
*/
class BetterProdGen : public Generator<vector<int>> {
public:
    vector<unsigned int> s;
    int x;
    shared_ptr<BetterProdGen> iter;
    vector<int> xs;
    BetterProdGen(const vector<unsigned int>& _s) : s(_s) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(s.size()==0) {
            output.clear();
            YIELD();
            RETURN();
        }
        for(x = 0; x < s[0]; ++x) {
            iter = make_shared<BetterProdGen>(
                vector<unsigned int>(s.begin() + 1, s.end()));
            while(iter->next(xs)) {
                output.clear();
                output.push_back(x);
                output.insert(output.end(), xs.begin(), xs.end());
                YIELD();
            }
        }
        PRG_END
    }
};

/*
def hanoi(n, a, b, c):
    if n == 1:
        s = str(a) +  ' --> ' + str(c)
        yield s
    else:
        for s in hanoi(n - 1, a, c, b):
            yield s
        for s in hanoi(1    , a, b, c):
            yield s
        for s in hanoi(n - 1, b, a, c):
            yield s
*/
class BetterHanoiGen : public Generator<string> {
public:
    int n;
    string a, b, c;
    shared_ptr<Generator<string> > iter;
    BetterHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}
    bool next(string& output) {
        PRG_BEG
        if(n == 1) {
            output = a + " --> " + c;
            YIELD();
            RETURN();
        }
        iter = make_shared<BetterHanoiGen>(n - 1, a, c, b);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(1, a, b, c);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(n - 1, b, a, c);
        while(iter->next(output)) YIELD();
        PRG_END
    }
};

class PrimeGen : public Generator<int> {
public:
    vector<int> primes;
    int i, j;
    PrimeGen() {}
    bool next(int& output) {
        PRG_BEG
        for(i = 2; true; ++i) {
            j = 0;
            for(j = 0; j < primes.size(); ++j) {
                if(i % primes[j] == 0) {
                    goto loop1_end;
                }
            }
            primes.push_back(i);
            output = i;
            YIELD();
            loop1_end:;
        }
        PRG_END
    }
};

class SubsetGen: public Generator<vector<int> > {
public:
    int n, i, j;
    SubsetGen(int _n) : n(_n) {}
    bool next(vector<int>& output) {
        PRG_BEG
        for(i = 0; i < (1 << n); ++i) {
            output.clear();
            for(int j = 0; j < n; ++j) {
                if((i >> j) & 1) {
                    output.push_back(j);
                }
            }
            YIELD();
        }
        PRG_END
    }
};

class PermutationGen: public Generator<vector<int> > {
public:
    int beg, n, i;
    vector<int>& arr;
    shared_ptr<PermutationGen> iter;
    PermutationGen(int _beg, vector<int>& _arr) : beg(_beg), n(_arr.size()), arr(_arr) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(beg >= n - 1) {
            for(i = 0; i < n; ++i) {
                output[i] = arr[i];
            }
            YIELD();
            RETURN();
        }
        for(i = beg; i < n; ++i) {
            swap(arr[beg], arr[i]);
            iter = make_shared<PermutationGen>(beg + 1, arr);
            while((*iter)(output)) YIELD();
            swap(arr[beg], arr[i]);
        }
        PRG_END
    }
    void swap(int& a, int &b) {
        int c = a;
        a = b;
        b = c;
    }
};

class GuessNumber : public Coroutine<int, int> {
public:
    int t, num;
    GuessNumber() {}
    bool next(int& input, int& output) {
        PRG_BEG
        t = 0;
        srand(time(0));
        cout << "Guess a number between 0 and 100!" << endl;
        while(true) {
            cout << "Match " << t << endl;
            num = rand() % 100;
            cout << "input a number:";
            YIELD();
            while(input != num) {
                if(input == -1) RETURN();
                if(input < num) {
                    cout << "Too low!" << endl;
                    output = -1;
                } else {
                    cout << "Too high!" << endl;
                    output = 1;
                }
                cout << "input a number agian:";
                YIELD();
            }
            cout << "Bingo! It's " << num << "!" << endl;
            cout << "Let's play it again!" << endl;
            t++;
            output = 0;
        }
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

class GuessYourNumber : public Coroutine<string, int> {
public:
    int beg, end, mid;
    GuessYourNumber() {}
    bool next(string& input, int& output) {
        PRG_BEG
        cout << "Keep a number between 0 and 100 in your mind!" << endl;
        cout << "Are you ready?(y/n)" << endl;
        YIELD();
        if(input[0] != 'y') {
            goto bye;
        }
        beg = 0, end = 101;
        while(beg < end) {
            mid = (beg + end) / 2;
            cout << "Is it " << mid << "?" << endl;
            cout << "Input 's' if it is smaller than your number." << endl;
            cout << "Input 'b' if it is bigger than your number." << endl;
            cout << "Input 'y' if it is your number!" << endl;
            YIELD();
            if(input[0] == 's') {
                beg = mid+1;
            } else if(input[0] == 'b') {
                end = mid;
            } else {
                cout << "YES! It's " << mid << "!" << endl;
                RETURN();
            }
        }
        cout << "No possible! The number must be " << mid << "!" << endl;
        bye:;
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

template<typename T>
void print(vector<T>& vec) {
    cout << "{ ";
    for(int i = 0; i < vec.size(); ++i) {
        cout << vec[i] << ", ";
    }
    cout << "}" << endl;
}

void testBetterHanoiGen() {
    cout << "testBetterHanoiGen" << endl;
    string s;
    BetterHanoiGen gen(3, "A", "B", "C");
    int k = 0;
    while(gen(s)) {
        cout << s << endl;
        k++;
    }
    cout << "HanoiGen is solved in " << k << " steps." << endl;
}

void testPrimeGen() {
    cout << "Prime numbers" << endl;
    PrimeGen primeGen;
    int p;
    for(int i = 0; i < 30; ++i) {
        primeGen(p);
        cout << p << " ";
    }
    cout << endl;
}

void testSubsetGen() {
    cout << "testSubsetGen" << endl;
    int n = 5;
    vector<int> output(n);
    SubsetGen gen(n);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Subsets." << endl;
}

void testPermutationGen() {
    cout << "testPermutationGen" << endl;
    vector<int> arr({1,2,3,4});
    PermutationGen gen(0, arr);
    vector<int> output(arr.size());
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Permutations." << endl;
}

void testBetterProdGen() {
    cout << "testBetterProdGen" << endl;
    vector<unsigned int> dimSize({3,2,4});
    vector<int> output(dimSize.size());
    BetterProdGen gen(dimSize);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " rows." << endl;
}

void testGuessNumber() {
    GuessNumber guess;
    int num, output;
    guess(num, output);
    do {
        cin >> num;
    } while(guess(num, output));
}

void testGuessYourNumber() {
    cout << "testGuessYourNumber" << endl;
    GuessYourNumber guess;
    string input;
    int output;
    guess(input, output);
    do {
        cin >> input;
    } while(guess(input, output));
}

int main() {

    testFibGen();

    testBetterHanoiGen();

    testPrimeGen();

    testSubsetGen();

    testPermutationGen();

    testBetterProdGen();

    // testGuessNumber();

    // testGuessYourNumber();

    return 0;
}
<|endoftext|>


<commit_before><commit_msg>Planning: fix typo<commit_after><|endoftext|>