On 08/05/2015 09:33 AM, Kinkie wrote:

> I crossed the topic of enumerating over iterations. 

You mean iterating enum[eration]s :-)


> We kind-of follow (C-ish)best
> practices on that, but that got me wondering if we can do better.
> I came up with a trinket which on its face looks quite elegant to me,
> and I'd like to understand with you guys if it makes sense to deploy it
> in our code. 

Maybe, after quite a few changes. It is risky for me to review this
because the problems in the posted code lie on several very different
layers, the code is outside Squid context, and I am not even sure what
[CODE] thread designation means. I hope this does not lead to a long
discussion, but here are a few things to consider:

* Iterating enums under Squid control ought to be a lot easier, safer,
and cheaper because we can add begin/end markers *with standard names*
to each enum. This is important because most iterations iterate
everything _and_ C++11 range loops always iterate everything. The
"everything" case is worth focusing on! See attached files for examples
of how standardized begin/end marks can be used.

* Your Iterator class is mixing two very different interfaces/APIs: One
provides begin/end() methods and is required for range loops (I do not
know how this API is called in the C++ standard). The other one is a
[partial] iterator API. Do not mix those two APIs! Each of the attached
files illustrates how to separate them (and there are two ways to
implement the second/iterator API).

* The stand-alone iterator API implementation in
t-enum-stand-alone-v3.cc allows for nice explicit for-loops and such,
but those global operators are rather invasive, and I am worried they
will cause problems in Squid context (as opposed a tiny test file!). I
recommend that you start with t-enum-v3.cc and then diff the two
attached files to see changes related to the stand-alone iterator API
implementation. If you really like stand-alone operator side-effects,
you may want to investigate whether they would work well in Squid context.

* Avoid static variables in templates, especially when you want to
instantiate different templates based on such trivial things as range
boundaries. This is (or used to be?) one of the dark C++ corners; they
might hurt inlining/performance as well.


The attached files are unpolished, but should illustrate the above
points and how to avoid some of the problems discussed here.


HTH,

Alex.

#include <cstdint>
#include <iostream>

// a sample enum
enum class Numbers {
  enumBegin_,

  zero = enumBegin_,
  one,
  two,
  three,

  enumEnd_ // maximum plus one
};

// another sample enum
enum class Colors: std::uint64_t  {
  enumBegin_ = 0xFFFF0000ULL,

  black = enumBegin_,
  red,
  white,

  enumEnd_ // maximum plus one
};

// To support range loops, we need to implement two APIs:
// EnumRange: A range container API (begin() and end() methods);
// EnumIterator: An iterator API (various operators: ++, *, !=).

/* Enum iterator operators. */
template <typename Enum>
Enum operator*(Enum value) { return value; }
template <typename Enum>
Enum operator++(Enum &value) { 
	typedef typename std::underlying_type<Enum>::type IntegralValue;
    return value = static_cast<Enum>(static_cast<IntegralValue>(value)+1);
}
template <typename Enum>
bool operator !=(Enum v1, Enum v2) { return v1 != v2; }
// TODO: Add suffix++, equality, and decrement operators for for/while loops.

// A range container API for an Enum.
// This EnumRange implementation focuses on the whole enum.
template <typename Enum>
class WholeEnum {
public:
  typedef Enum Iterator;
  Iterator begin() const { return Iterator(Enum::enumBegin_); }
  Iterator end() const { return Iterator(Enum::enumEnd_); }
};


// a hack to make dumping enum values simpler
template <typename Enum>
void dump(std::ostream &os, Enum value) {
    typedef typename std::underlying_type<Enum>::type IntegralValue;
	os << std::hex << static_cast<IntegralValue>(value) << ' ';
}


// sample code
int main() {

  /* Report all Numbers. */

  // beautiful range-for
  for (Numbers i: WholeEnum<Numbers>())
    dump(std::cout, i);
  std::cout << std::endl;

  // ugly explicit-for
  for (auto i = WholeEnum<Numbers>().begin(); i != WholeEnum<Numbers>().end(); ++i)
    dump(std::cout, *i);
  std::cout << std::endl;

  // beautiful explicit-for
  for (auto i = Numbers::enumBegin_; i != Numbers::enumEnd_; ++i)
    dump(std::cout, i);
  std::cout << std::endl;


  /* And now report all Colors. */

  // beautiful range-for
  for (Colors i: WholeEnum<Colors>())
    dump(std::cout, i);
  std::cout << std::endl;

  // ugly explicit-for
  for (auto i = WholeEnum<Colors>().begin(); i != WholeEnum<Colors>().end(); ++i)
    dump(std::cout, *i);
  std::cout << std::endl;

  // beautiful explicit-for
  for (auto i = Colors::enumBegin_; i != Colors::enumEnd_; ++i)
    dump(std::cout, i);
  std::cout << std::endl;

  return 0;
}
#include <cstdint>
#include <iostream>

// a sample enum
enum class Numbers {
  enumBegin_,

  zero = enumBegin_,
  one,
  two,
  three,

  enumEnd_ // maximum plus one
};

// another sample enum
enum class Colors: std::uint64_t  {
  enumBegin_ = 0xFFFF0000ULL,

  black = enumBegin_,
  red,
  white,

  enumEnd_ // maximum plus one
};

// To support range loops, we need to implement two APIs:
// EnumRange: A range container API (begin() and end() methods);
// EnumIterator: An iterator API (various operators: ++, *, !=).

// An Enum iterator.
template <typename Enum>
class EnumIterator {
public:
  explicit EnumIterator(Enum e): value(static_cast<value_t>(e)) {}

  Enum operator*() const {
    return static_cast<Enum>(value);
  }

  EnumIterator &operator++() {
    ++value;
    return *this;
  }

  bool operator !=(const EnumIterator &i) const { return value != i.value; }

  // TODO: Add suffix++, equality, and decrement operators for for/while loops.

private:
  typedef typename std::underlying_type<Enum>::type value_t;
  value_t value;
};


// A range container API for an Enum.
// This EnumRange implementation focuses on the whole enum.
template <typename Enum>
class WholeEnum {
public:
  typedef EnumIterator<Enum> Iterator;
  Iterator begin() const { return Iterator(Enum::enumBegin_); }
  Iterator end() const { return Iterator(Enum::enumEnd_); }
};


// a hack to make dumping enum values simpler
template <typename Enum>
void dump(std::ostream &os, Enum value) {
    typedef typename std::underlying_type<Enum>::type IntegralValue;
	os << std::hex << static_cast<IntegralValue>(value) << ' ';
}


// sample code
int main() {

  /* Report all Numbers. */

  // beautiful range-for
  for (Numbers i: WholeEnum<Numbers>())
    dump(std::cout, i);
  std::cout << std::endl;

  // ugly explicit-for
  for (auto i = WholeEnum<Numbers>().begin(); i != WholeEnum<Numbers>().end(); ++i)
    dump(std::cout, *i);
  std::cout << std::endl;

  // narrow range with explicit-for
  for (auto i = EnumIterator<Numbers>(Numbers::one); i != EnumIterator<Numbers>(Numbers::three); ++i)
    dump(std::cout, *i);
  std::cout << std::endl;


  /* And now report all Colors. */

  // beautiful range-for
  for (Colors i: WholeEnum<Colors>())
    dump(std::cout, i);
  std::cout << std::endl;

  // ugly explicit-for
  for (auto i = WholeEnum<Colors>().begin(); i != WholeEnum<Colors>().end(); ++i)
    dump(std::cout, *i);
  std::cout << std::endl;

  // narrow range with explicit-for
  for (auto i = EnumIterator<Colors>(Colors::black); i != EnumIterator<Colors>(Colors::white); ++i)
    dump(std::cout, *i);
  std::cout << std::endl;

  return 0;
}
_______________________________________________
squid-dev mailing list
squid-dev@lists.squid-cache.org
http://lists.squid-cache.org/listinfo/squid-dev

Reply via email to