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