Multi-Dimensional Analog Literals

Version 2006-05-24, by Eelis

This software has been released into the Public Domain


Table of contents

  1. Tutorial
  2. Changelog
  3. Header analogliterals.hpp

1. Tutorial

(download as .cpp)

// Note: The following is all standard-conforming C++, this is not a hypothetical language extension.

#include "analogliterals.hpp"
#include <cassert>

int main ()
{
  using namespace analog_literals::symbols;

// Consider:

  unsigned int a = 4;

// Have you ever felt that integer literals like "4" don't convey the true size of the value they denote? If so, use an analog integer literal instead:

  unsigned int b = I---------I;

  assert( a == b );

// Due to the way C++ operators work, we must use N*2+1 dashes between the I's to get a value of N:

  assert( I-I == 0 );
  assert( I---I == 1 );
  assert( I-----I == 2 );
  assert( I-------I == 3 );

// These one-dimensional analog literals are of type analog_literals::line<N>, which is convertible to unsigned int.

// In some cases, two-dimensional analog literals are appropriate:

  unsigned int c = ( o-----o
                     |     !
                     !     !
                     !     !
                     o-----o ).area;

  assert( c == (I-----I) * (I-------I) );

  assert( ( o-----o
            |     !
            !     !
            !     !
            !     !
            o-----o ).area == ( o---------o
                                |         !
                                !         !
                                o---------o ).area );

// Two-dimensional analog literals are of type analog_literals::rectangle<X, Y> which exposes static member constants width, height, and area.

/* As an example use-case, imagine specifying window dimensions in a GUI toolkit API using:

   window.dimensions = o-----------o
                       |           !
                       !           !
                       !           !
                       !           !
                       o-----------o ;

Who said C++ was unintuitive!? */

// But wait, there's more. We can use three-dimensional analog literals, too:

  assert( ( o-------------o
            |L             \
            | L             \
            |  L             \
            |   o-------------o
            |   !             !
            !   !             !
            o   |             !
             L  |             !
              L |             !
               L|             !
                o-------------o ).volume == ( o-------------o
                                              |             !
                                              !             !
                                              !             !
                                              o-------------o ).area * int(I-------------I) );

// Three-dimensional analog literals are of type analog_literals::cuboid<X, Y, Z> which exposes static member constants width, height, depth, and volume. In addition, three free-standing functions top, side, and front are provided which yield rectangles:

  assert( top( o-------o
               |L       \
               | L       \
               |  o-------o
               |  !       !
               !  !       !
               o  |       !
                L |       !
                 L|       !
                  o-------o ) == ( o-------o
                                   |       !
                                   !       !
                                   o-------o ) );

// The current implementation has one restriction on cuboid dimensions: the height of a cuboid literal must be at least its depth + 2.

// Note that storing these literals directly in a variable requires you to specify the dimension sizes:

  analog_literals::rectangle<4, 2> r = o---------o
                                       |         !
                                       !         !
                                       o---------o;

// This of course defeats the purpose of using the analog literal. C++0x's proposed `auto' feature would come in quite handy here. We can actually fix this problem partially (using the stack-ref-to-temporary's-base trick used by Alexandrescu's ScopeGuard), but we would no longer be able to use the values in ICE's, and frankly I think this madness has gone far enough already.

}

2. Changelog


(download)

 operator T () const { return T(); } };

  template  struct excls { excls operator! () const { return gen(); } };

  template  struct dashes: excls, 0>
  { dashes operator-- (int) const { return gen(); } };

  template  struct L_symbols {}; // represents a L|L|L|.. series
  template  L_symbols operator| (L_symbols, Lsymbol) { return gen(); }

  template  struct eL_symbols {}; // represents a !L|!L|!L|.. series
  template  eL_symbols operator| (eL_symbols, eLsymbol) { return gen(); }

  dashes operator-- (line_end, int) { return gen(); }
  excls operator! (line_end) { return gen(); }

// Result types

  template  struct line: L_symbols, 0>
  { static uint const length; operator uint () const { return len; } };
  template  struct rectangle { static uint const width, height, area; };
  template  struct cuboid { static uint const width, height, depth, volume; };

// Static members

  template  uint const line::length = len;

  template  uint const rectangle::width = x;
  template  uint const rectangle::height = y;
  template  uint const rectangle::area = x * y;

  template  uint const cuboid::width = x;
  template  uint const cuboid::height = y;
  template  uint const cuboid::depth = z;
  template  uint const cuboid::volume = x * y * z;

  template  rectangle front (cuboid) { return gen(); }
  template  rectangle side (cuboid) { return gen(); }
  template  rectangle top (cuboid) { return gen(); }

// Equality

  template  bool operator== (line, line) { return ax == bx; }

  template  bool operator== (rectangle, rectangle)
  { return ax == bx && ay == by; }

  template 
  bool operator== (cuboid, cuboid) { return ax == bx && ay == by && az == bz; }

// Construction

  // line

  line<0> operator- (line_end, line_end) { return gen(); }
  template  line operator- (dashes, line_end) { return gen(); }

  // rectangle

  template  struct lower_rectangle {}; // with lower right corner

  template 
  lower_rectangle operator- (excls, excl_marks>, line_end)
  { return gen(); }

  template  rectangle operator| (line, lower_rectangle) { return gen(); }

  // cuboid

  template  struct cuboid_top {};
  template  struct half_cuboid {};
    // dimensions of complete cuboid known, rest is for show

  template 
  cuboid_top operator| (L_symbols, n>, line) { return gen(); }

  template 
  eL_symbols, 0> // todo: assert: n%3=2
    operator| (cuboid_top, excls) { return gen(); }

  template 
  cuboid operator| (eL_symbols, z>, lower_rectangle) { return gen(); }

// Convenience namespaces that can be "using namespace"'d:

  namespace symbols
  {
    using analog_literals::o;
    using analog_literals::I;
    using analog_literals::L;
  }

  namespace shapes
  {
    using analog_literals::line;
    using analog_literals::rectangle;
    using analog_literals::cuboid;
  }

} // analog_literals

#endif // header guard

#ifdef ANALOGLITERALS_TEST

int main ()
{
  using namespace analog_literals::symbols;
  using namespace analog_literals::shapes;

  line<3>(I-------I);

  rectangle<2, 3>(o-----o
                  |     !
                  !     !
                  !     !
                  o-----o);

  cuboid<6, 6, 3>(o-------------o
                  |L             \
                  | L             \
                  |  L             \
                  |   o-------------o
                  |   !             !
                  !   !             !
                  o   |             !
                   L  |             !
                    L |             !
                     L|             !
                      o-------------o );

  cuboid<3, 4, 2>(o-------o
                  |L       \
                  | L       \
                  |  o-------o
                  |  !       !
                  o  |       !
                   L |       !
                    L|       !
                     o-------o);
}

#endif // testing
]]>

Valid XHTML 1.1