Browse Source

Working ANSIColor constexpr ctor.

Steve Thielemann 3 years ago
parent
commit
352b428394
2 changed files with 354 additions and 53 deletions
  1. 34 41
      ansicolor.cpp
  2. 320 12
      ansicolor.h

+ 34 - 41
ansicolor.cpp

@@ -12,13 +12,7 @@
  * with sensible defaults (White on Black).
  *
  */
-ANSIColor::ANSIColor()
-    : fg(COLOR::WHITE),
-      bg(COLOR::BLACK),
-      reset(0),
-      bold(0),
-      blink(0),
-      inverse(0) {}
+ANSIColor::ANSIColor() : fg(COLOR::WHITE), bg(COLOR::BLACK), attr(0) {}
 
 /**
  * Construct a new ANSIColor::ANSIColor object
@@ -72,10 +66,10 @@ ANSIColor::ANSIColor(std::initializer_list<int> il) : ANSIColor() {
   for (auto const &i : il) {
     switch (i) {
       case 1:
-        bold = 1;
+        attr |= A_BOLD;
         break;
       case 5:
-        blink = 1;
+        attr |= A_BLINK;
         break;
       case 30:
       case 31:
@@ -154,21 +148,23 @@ ANSIColor::ANSIColor(COLOR f, COLOR b, ATTR a1, ATTR a2) : ANSIColor() {
 ANSIColor &ANSIColor::Attr(ATTR a) {
   switch (a) {
     case ATTR::RESET:
-      reset = 1;
+      attr |= A_RESET;
       break;
     case ATTR::BOLD:
-      bold = 1;
+      attr |= A_BOLD;
       break;
     case ATTR::BLINK:
-      blink = 1;
+      attr |= A_BLINK;
       break;
     case ATTR::INVERSE:
-      inverse = 1;
+      attr |= A_INVERSE;
       break;
   }
   return *this;
 }
 
+#define MASK (A_BOLD | A_BLINK | A_INVERSE)
+
 /**
  * Equal operator.
  *
@@ -178,8 +174,7 @@ ANSIColor &ANSIColor::Attr(ATTR a) {
  * @return bool
  */
 bool ANSIColor::operator==(const ANSIColor &c) const {
-  return ((fg == c.fg) and (bg == c.bg) and (bold == c.bold) and
-          (blink == c.blink) and (inverse == c.inverse));
+  return ((fg == c.fg) and (bg == c.bg) and ((attr & MASK) == (c.attr & MASK)));
 }
 
 /**
@@ -191,8 +186,8 @@ bool ANSIColor::operator==(const ANSIColor &c) const {
  * @return bool
  */
 bool ANSIColor::operator!=(const ANSIColor &c) const {
-  return !((fg == c.fg) and (bg == c.bg) and (bold == c.bold) and
-           (blink == c.blink) and (inverse == c.inverse));
+  return !((fg == c.fg) and (bg == c.bg) and
+           ((attr & MASK) == (c.attr & MASK)));
 }
 
 /**
@@ -202,10 +197,7 @@ bool ANSIColor::operator!=(const ANSIColor &c) const {
  */
 void ANSIColor::setFg(COLOR f) {
   fg = f;
-  reset = 0;
-  bold = 0;
-  blink = 0;
-  inverse = 0;
+  attr = 0;
 }
 
 /**
@@ -216,7 +208,7 @@ void ANSIColor::setFg(COLOR f) {
  */
 void ANSIColor::setFg(COLOR f, ATTR a) {
   fg = f;
-  attr(a);
+  setAttr(a);
 }
 
 /**
@@ -233,12 +225,9 @@ void ANSIColor::setBg(COLOR b) { bg = b; }
  *
  * @param[in] a ATTR
  */
-void ANSIColor::attr(ATTR a) {
+void ANSIColor::setAttr(ATTR a) {
   // first, clear all attributes
-  reset = 0;
-  bold = 0;
-  blink = 0;
-  inverse = 0;
+  attr = 0;
   Attr(a);
 }
 
@@ -250,28 +239,30 @@ std::string ANSIColor::output(void) const {
   std::string clr(CSI);
 
   // check for special cases
-  if (reset and (fg == COLOR::BLACK) and (bg == COLOR::BLACK)) {
+  if (((attr & A_RESET) == A_RESET) and (fg == COLOR::BLACK) and
+      (bg == COLOR::BLACK)) {
     clr += "0m";
     return clr;
   }
 
-  if (reset and (fg == COLOR::WHITE) and (bg == COLOR::BLACK)) {
+  if (((attr & A_RESET) == A_RESET) and (fg == COLOR::WHITE) and
+      (bg == COLOR::BLACK)) {
     clr += "0m";
     return clr;
   }
 
-  if (reset) {
+  if ((attr & A_RESET) == A_RESET) {
     clr += "0;";
   }
 
-  if (bold) {
-    if (blink) {
+  if ((attr & A_BOLD) == A_BOLD) {
+    if ((attr & A_BLINK) == A_BLINK) {
       clr += "5;";
     }
     clr += "1;";
   } else {
-    if (!reset) clr += "0;";
-    if (blink) {
+    if (!((attr & A_RESET) == A_RESET)) clr += "0;";
+    if ((attr & A_BLINK) == A_BLINK) {
       clr += "5;";
     }
   }
@@ -286,28 +277,30 @@ std::string ANSIColor::operator()(void) const {
   std::string clr(CSI);
 
   // check for special cases
-  if (reset and (fg == COLOR::BLACK) and (bg == COLOR::BLACK)) {
+  if (((attr & A_RESET) == A_RESET) and (fg == COLOR::BLACK) and
+      (bg == COLOR::BLACK)) {
     clr += "0m";
     return clr;
   }
 
-  if (reset and (fg == COLOR::WHITE) and (bg == COLOR::BLACK)) {
+  if (((attr & A_RESET) == A_RESET) and (fg == COLOR::WHITE) and
+      (bg == COLOR::BLACK)) {
     clr += "0m";
     return clr;
   }
 
-  if (reset) {
+  if ((attr & A_RESET) == A_RESET) {
     clr += "0;";
   }
 
-  if (bold) {
-    if (blink) {
+  if ((attr & A_BOLD) == A_BOLD) {
+    if ((attr & A_BLINK) == A_BLINK) {
       clr += "5;";
     }
     clr += "1;";
   } else {
-    if (!reset) clr += "0;";
-    if (blink) {
+    if (!((attr & A_RESET) == A_RESET)) clr += "0;";
+    if ((attr & A_BLINK) == A_BLINK) {
       clr += "5;";
     }
   }

+ 320 - 12
ansicolor.h

@@ -50,6 +50,24 @@ enum class ATTR : std::int8_t {
   INVERSE = 7
 };
 
+// std::int32_t 
+
+constexpr long strhash(const char *txt) {
+  long result = 0;
+  
+  for (int x = 0; x < 3; ++x) {
+    // char c = txt[x] - 'A';
+    result = (result << 8) | txt[x];
+  }
+
+  return result;
+};
+
+#define A_BOLD    0x01
+#define A_BLINK   0x02
+#define A_INVERSE 0x04
+#define A_RESET   0x10
+
 /**
  * @class ANSIColor
  * This holds foreground, background and ANSI-BBS attribute
@@ -65,17 +83,10 @@ class ANSIColor {
   COLOR fg;
   /** Background color */
   COLOR bg;
-  // Track attributes (ATTR)
-  /** reset flag / always send color and attributes */
-  unsigned int reset : 1;
-  /** bold / bright flag */
-  unsigned int bold : 1;
-  /** blink slow blinking text */
-  unsigned int blink : 1;
-  /** inverse */
-  unsigned int inverse : 1;
-
-public:
+
+  int attr;
+
+ public:
   ANSIColor();
   ANSIColor(ATTR a);
   ANSIColor(COLOR f);
@@ -85,6 +96,104 @@ public:
   ANSIColor(COLOR f, COLOR b, ATTR a);
   ANSIColor(COLOR f, COLOR b, ATTR a1, ATTR a2);
   ANSIColor(std::initializer_list<int> il);
+
+  constexpr ANSIColor(const char *text)
+      : fg(COLOR::WHITE),
+        bg(COLOR::BLACK),
+        attr(0) {
+    const char *cp = text;
+    bool use_on = false;
+
+    while (*cp != 0) {
+      long key = strhash(cp);
+
+      switch (key) {
+        case strhash("BRI"):
+          attr |= A_BOLD;
+          break;
+        case strhash("BOL"):
+          attr |= A_BOLD;
+          break;
+        case strhash("BLI"):
+          attr |= A_BLINK;
+          break;
+        case strhash("INV"):
+          attr |= A_INVERSE;
+          break;
+        case strhash("RES"):
+          attr |= A_RESET;
+          break;
+        case strhash("ON "):
+          use_on = true;
+          break;
+
+        case strhash("BLU"):
+          if (use_on)
+            bg = COLOR::BLUE;
+          else
+            bg = COLOR::BLUE;
+
+          break;
+        case strhash("RED"):
+          if (use_on)
+            bg = COLOR::RED;
+          else
+            fg = COLOR::RED;
+          break;
+        case strhash("GRE"):
+          if (use_on)
+            bg = COLOR::GREEN;
+          else
+            fg =  COLOR::GREEN;
+          break;
+        case strhash("YEL"):
+          if (use_on)
+            bg = COLOR::YELLOW;
+          else {
+            fg = COLOR::YELLOW;
+            attr |= A_BOLD;
+          }
+          // if (use_on) throw error!
+          break;
+        case strhash("BRO"):
+          if (use_on)
+            bg = COLOR::BROWN;
+          else
+            fg = COLOR::BROWN;
+          break;
+        case strhash("CYA"):
+          if (use_on)
+            bg = COLOR::CYAN;
+          else
+            fg = COLOR::CYAN;
+          break;
+        case strhash("MAG"):
+          if (use_on)
+            bg = COLOR::MAGENTA;
+          else
+            fg = COLOR::MAGENTA;
+          break;
+        case strhash("BLA"):
+          if (use_on)
+            bg = COLOR::BLACK;
+          else
+            fg = COLOR::BLACK;
+          break;
+        case strhash("WHI"):
+          if (use_on)
+            bg = COLOR::WHITE;
+          else
+            fg = COLOR::WHITE;
+          break;
+      }
+
+      // skip to the space character
+      while ((*cp != ' ') && (*cp != 0)) ++cp;
+      // skip past the space character
+      while (*cp == ' ') ++cp;
+    }
+  };
+
   /*
   ANSIColor(int c1);
   ANSIColor(int c1, int c2);
@@ -107,12 +216,211 @@ public:
    * @return COLOR
    */
   COLOR getBg() { return bg; };
-  void attr(ATTR a);
+  void setAttr(ATTR a);
 
   std::string output(void) const;
   std::string operator()(void) const;
 };
 
+#ifdef NON_WORKING
+#include <vector>
+
+constexpr std::vector<int> from_text(const char *text) {
+  std::vector<int> vi;
+
+  const char *cp = text;
+  bool use_on = false;
+
+  while (*cp != 0) {
+    int key = strhash(cp);
+
+    switch (key) {
+      case strhash("BRI"):
+        vi.push_back(1);
+        break;
+      case strhash("BOL"):
+        vi.push_back(1);
+        break;
+      case strhash("BLI"):
+        vi.push_back(5);
+        break;
+      case strhash("INV"):
+        vi.push_back(7);
+        break;
+
+      case strhash("ON "):
+        use_on = true;
+        break;
+
+      case strhash("BLU"):
+        if (use_on)
+          ac.setBg(COLOR::BLUE);
+        else
+          ac.setFg(COLOR::BLUE);
+
+        break;
+      case strhash("RED"):
+        if (use_on)
+          ac.setBg(COLOR::RED);
+        else
+          ac.setFg(COLOR::RED);
+        break;
+      case strhash("GRE"):
+        if (use_on)
+          ac.setBg(COLOR::GREEN);
+        else
+          ac.setFg(COLOR::GREEN);
+        break;
+      case strhash("YEL"):
+        // if (use_on) throw error!
+        ac.setFg(COLOR::YELLOW);
+        ac.Attr(ATTR::BOLD);
+        break;
+      case strhash("BRO"):
+        if (use_on)
+          ac.setBg(COLOR::BROWN);
+        else
+          ac.setFg(COLOR::BROWN);
+        break;
+      case strhash("CYA"):
+        if (use_on)
+          ac.setBg(COLOR::CYAN);
+        else
+          ac.setFg(COLOR::CYAN);
+        break;
+      case strhash("MAG"):
+        if (use_on)
+          ac.setBg(COLOR::MAGENTA);
+        else
+          ac.setFg(COLOR::MAGENTA);
+        break;
+      case strhash("BLA"):
+        if (use_on)
+          ac.setBg(COLOR::BLACK);
+        else
+          ac.setFg(COLOR::BLACK);
+        break;
+      case strhash("WHI"):
+        if (use_on)
+          ac.setBg(COLOR::WHITE);
+        else
+          ac.setFg(COLOR::WHITE);
+        break;
+    }
+
+    // skip to the space character
+    while ((*cp != ' ') && (*cp != 0)) ++cp;
+    // skip past the space character
+    while (*cp == ' ') ++cp;
+  }
+  return vi;
+}
+#endif
+
+/*
+Maybe make char, char, char (fg, bg, attr) and store those from
+the constexpr.  
+
+This "works", in that it does construct an ANSIColor from text.
+
+However, it isn't stored as an ANSIColor, but calls the function
+at run-time.  (I was hoping for an efficient way to construct
+ANSIColor from a string.)
+
+Maybe a template that constructs it from a initializer_list?
+ */
+
+constexpr ANSIColor ac_from_text(const char *text) {
+  ANSIColor ac(nullptr);
+
+  const char *cp = text;
+  bool use_on = false;
+
+  while (*cp != 0) {
+    int key = strhash(cp);
+
+    switch (key) {
+      case strhash("BRI"):
+        ac.Attr(ATTR::BRIGHT);
+        break;
+      case strhash("BOL"):
+        ac.Attr(ATTR::BOLD);
+        break;
+      case strhash("BLI"):
+        ac.Attr(ATTR::BLINK);
+        break;
+      case strhash("INV"):
+        ac.Attr(ATTR::INVERSE);
+        break;
+
+      case strhash("ON "):
+        use_on = true;
+        break;
+
+      case strhash("BLU"):
+        if (use_on)
+          ac.setBg(COLOR::BLUE);
+        else
+          ac.setFg(COLOR::BLUE);
+
+        break;
+      case strhash("RED"):
+        if (use_on)
+          ac.setBg(COLOR::RED);
+        else
+          ac.setFg(COLOR::RED);
+        break;
+      case strhash("GRE"):
+        if (use_on)
+          ac.setBg(COLOR::GREEN);
+        else
+          ac.setFg(COLOR::GREEN);
+        break;
+      case strhash("YEL"):
+        // if (use_on) throw error!
+        ac.setFg(COLOR::YELLOW);
+        ac.Attr(ATTR::BOLD);
+        break;
+      case strhash("BRO"):
+        if (use_on)
+          ac.setBg(COLOR::BROWN);
+        else
+          ac.setFg(COLOR::BROWN);
+        break;
+      case strhash("CYA"):
+        if (use_on)
+          ac.setBg(COLOR::CYAN);
+        else
+          ac.setFg(COLOR::CYAN);
+        break;
+      case strhash("MAG"):
+        if (use_on)
+          ac.setBg(COLOR::MAGENTA);
+        else
+          ac.setFg(COLOR::MAGENTA);
+        break;
+      case strhash("BLA"):
+        if (use_on)
+          ac.setBg(COLOR::BLACK);
+        else
+          ac.setFg(COLOR::BLACK);
+        break;
+      case strhash("WHI"):
+        if (use_on)
+          ac.setBg(COLOR::WHITE);
+        else
+          ac.setFg(COLOR::WHITE);
+        break;
+    }
+
+    // skip to the space character
+    while ((*cp != ' ') && (*cp != 0)) ++cp;
+    // skip past the space character
+    while (*cp == ' ') ++cp;
+  }
+  return ac;
+};
+
 extern ANSIColor reset;
 
 #endif