+#define FLOWMAP_SET(FM, FIELD) \
+ flowmap_set(FM, FLOW_U64_OFFSET(FIELD), FLOW_U64_SIZE(FIELD))
+
+#define FLOWMAP_SET__(FM, FIELD, SIZE) \
+ flowmap_set(FM, FLOW_U64_OFFSET(FIELD), \
+ DIV_ROUND_UP(SIZE, sizeof(uint64_t)))
+
+/* XXX: Only works for full 64-bit units. */
+#define FLOWMAP_CLEAR(FM, FIELD) \
+ BUILD_ASSERT_DECL(FLOW_U64_OFFREM(FIELD) == 0); \
+ BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->FIELD) % sizeof(uint64_t) == 0); \
+ flowmap_clear(FM, FLOW_U64_OFFSET(FIELD), FLOW_U64_SIZE(FIELD))
+
+/* Iterate through all units in 'FMAP'. */
+#define FLOWMAP_FOR_EACH_UNIT(UNIT) \
+ for ((UNIT) = 0; (UNIT) < FLOWMAP_UNITS; (UNIT)++)
+
+/* Iterate through all map units in 'FMAP'. */
+#define FLOWMAP_FOR_EACH_MAP(MAP, FLOWMAP) \
+ for (size_t unit__ = 0; \
+ unit__ < FLOWMAP_UNITS && ((MAP) = (FLOWMAP).bits[unit__], true); \
+ unit__++)
+
+struct flowmap_aux;
+static inline bool flowmap_next_index(struct flowmap_aux *, size_t *idx);
+
+#define FLOWMAP_AUX_INITIALIZER(FLOWMAP) { .unit = 0, .map = (FLOWMAP) }
+
+/* Iterate through all struct flow u64 indices specified by 'MAP'. This is a
+ * slower but easier version of the FLOWMAP_FOR_EACH_MAP() &
+ * MAP_FOR_EACH_INDEX() combination. */
+#define FLOWMAP_FOR_EACH_INDEX(IDX, MAP) \
+ for (struct flowmap_aux aux__ = FLOWMAP_AUX_INITIALIZER(MAP); \
+ flowmap_next_index(&aux__, &(IDX));)
+
+/* Flowmap inline implementations. */
+static inline void
+flowmap_init(struct flowmap *fm)
+{
+ memset(fm, 0, sizeof *fm);
+}
+
+static inline bool
+flowmap_equal(struct flowmap a, struct flowmap b)
+{
+ return !memcmp(&a, &b, sizeof a);
+}
+
+static inline bool
+flowmap_is_set(const struct flowmap *fm, size_t idx)
+{
+ return (fm->bits[idx / MAP_T_BITS] & (MAP_1 << (idx % MAP_T_BITS))) != 0;
+}
+
+/* Returns 'true' if any of the 'n_bits' bits starting at 'idx' are set in
+ * 'fm'. 'n_bits' can be at most MAP_T_BITS. */
+static inline bool
+flowmap_are_set(const struct flowmap *fm, size_t idx, unsigned int n_bits)
+{
+ map_t n_bits_mask = (MAP_1 << n_bits) - 1;
+ size_t unit = idx / MAP_T_BITS;
+
+ idx %= MAP_T_BITS;
+
+ if (fm->bits[unit] & (n_bits_mask << idx)) {
+ return true;
+ }
+ /* The seemingly unnecessary bounds check on 'unit' is a workaround for a
+ * false-positive array out of bounds error by GCC 4.9. */
+ if (unit + 1 < FLOWMAP_UNITS && idx + n_bits > MAP_T_BITS) {
+ /* Check the remaining bits from the next unit. */
+ return fm->bits[unit + 1] & (n_bits_mask >> (MAP_T_BITS - idx));
+ }
+ return false;
+}
+
+/* Set the 'n_bits' consecutive bits in 'fm', starting at bit 'idx'.
+ * 'n_bits' can be at most MAP_T_BITS. */
+static inline void
+flowmap_set(struct flowmap *fm, size_t idx, unsigned int n_bits)
+{
+ map_t n_bits_mask = (MAP_1 << n_bits) - 1;
+ size_t unit = idx / MAP_T_BITS;
+
+ idx %= MAP_T_BITS;
+
+ fm->bits[unit] |= n_bits_mask << idx;
+ /* The seemingly unnecessary bounds check on 'unit' is a workaround for a
+ * false-positive array out of bounds error by GCC 4.9. */
+ if (unit + 1 < FLOWMAP_UNITS && idx + n_bits > MAP_T_BITS) {
+ /* 'MAP_T_BITS - idx' bits were set on 'unit', set the remaining
+ * bits from the next unit. */
+ fm->bits[unit + 1] |= n_bits_mask >> (MAP_T_BITS - idx);
+ }
+}
+
+/* Clears the 'n_bits' consecutive bits in 'fm', starting at bit 'idx'.
+ * 'n_bits' can be at most MAP_T_BITS. */
+static inline void
+flowmap_clear(struct flowmap *fm, size_t idx, unsigned int n_bits)
+{
+ map_t n_bits_mask = (MAP_1 << n_bits) - 1;
+ size_t unit = idx / MAP_T_BITS;
+
+ idx %= MAP_T_BITS;
+
+ fm->bits[unit] &= ~(n_bits_mask << idx);
+ /* The seemingly unnecessary bounds check on 'unit' is a workaround for a
+ * false-positive array out of bounds error by GCC 4.9. */
+ if (unit + 1 < FLOWMAP_UNITS && idx + n_bits > MAP_T_BITS) {
+ /* 'MAP_T_BITS - idx' bits were cleared on 'unit', clear the
+ * remaining bits from the next unit. */
+ fm->bits[unit + 1] &= ~(n_bits_mask >> (MAP_T_BITS - idx));
+ }
+}
+
+/* OR the bits in the flowmaps. */
+static inline struct flowmap
+flowmap_or(struct flowmap a, const struct flowmap b)
+{
+ struct flowmap map;
+ size_t unit;
+
+ FLOWMAP_FOR_EACH_UNIT (unit) {
+ map.bits[unit] = a.bits[unit] | b.bits[unit];
+ }
+ return map;
+}
+
+/* AND the bits in the flowmaps. */
+static inline struct flowmap
+flowmap_and(struct flowmap a, const struct flowmap b)
+{
+ struct flowmap map;
+ size_t unit;
+
+ FLOWMAP_FOR_EACH_UNIT (unit) {
+ map.bits[unit] = a.bits[unit] & b.bits[unit];
+ }
+ return map;
+}
+
+static inline bool
+flowmap_is_empty(const struct flowmap fm)
+{
+ map_t map;
+
+ FLOWMAP_FOR_EACH_MAP (map, fm) {
+ if (map) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static inline unsigned int
+flowmap_n_1bits(struct flowmap fm)
+{
+ unsigned int n_1bits = 0;
+ size_t unit;
+
+ FLOWMAP_FOR_EACH_UNIT (unit) {
+ n_1bits += count_1bits(fm.bits[unit]);
+ }
+ return n_1bits;
+}
+
+struct flowmap_aux {
+ size_t unit;
+ struct flowmap map;
+};
+
+static inline bool
+flowmap_next_index(struct flowmap_aux *aux, size_t *idx)
+{
+ for (;;) {
+ map_t *map = &aux->map.bits[aux->unit];
+ if (*map) {
+ *idx = aux->unit * MAP_T_BITS + raw_ctz(*map);
+ *map = zero_rightmost_1bit(*map);
+ return true;
+ }
+ if (++aux->unit >= FLOWMAP_UNITS) {
+ return false;
+ }
+ }
+}
+
+\f
+/* Compressed flow. */