mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-02-18 09:30:39 +01:00
util: add a tristate helper
Yet another crazy macro that allows to define a logical tristate. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
42546acf3f
commit
ebd41833cb
1 changed files with 131 additions and 0 deletions
131
src/util-tristate.h
Normal file
131
src/util-tristate.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A type-safe tristate implementation. A tristate value has three options,
|
||||
* usually a logical 'on' and 'off' plus the 'unset' value.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* DEFINE_TRISTATE(yes, no, unset);
|
||||
* DEFINE_TRISTATE(on, off, neither);
|
||||
*
|
||||
* tristate t = tristate_unset;
|
||||
* if (something)
|
||||
* t = tristate_yes;
|
||||
* else if (something_else)
|
||||
* t = tristate_no;
|
||||
*
|
||||
* if (tristate_is_yes(t))
|
||||
* printf("yep");
|
||||
*
|
||||
* switch (tristate_value(t)) {
|
||||
* case tristate_val_yes:
|
||||
* case tristate_val_no:
|
||||
* case tristate_val_unset:
|
||||
* }
|
||||
*
|
||||
* Basic type safety is provided - mixing tristates types causes an
|
||||
* abort(). For example:
|
||||
*
|
||||
* DEFINE_TRISTATE(yes, no, unset);
|
||||
* DEFINE_TRISTATE(on, off, neither);
|
||||
*
|
||||
* tristate t1 = tristate_unset;
|
||||
* tristate t2 = tristate_off;
|
||||
* tristate t3 = tristate_neither;
|
||||
*
|
||||
* t2 and t3 have the same "type". t1 is a different "type".
|
||||
*
|
||||
* tristate_is_neither(t1) // this will abort
|
||||
* tristate_is_yes(t2) // this will abort
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
unsigned val;
|
||||
} tristate;
|
||||
|
||||
/* Implementation detail:
|
||||
* Tristate value is type_mask | val
|
||||
* where val are the 2 LSB with
|
||||
* 11 ... logical true state
|
||||
* 10 ... logical false state
|
||||
* 00 ... unset state
|
||||
* All other bits are the type mask. This type mask is used to check that
|
||||
* two different tristate definitions cannot be intermixed.
|
||||
*/
|
||||
static const unsigned _TRISTATE_TYPE_MASK = ~0x3;
|
||||
|
||||
/* implementation detail, ignore */
|
||||
static inline void _tristate_check_type(const tristate *t1, unsigned type) {
|
||||
assert((t1->val & _TRISTATE_TYPE_MASK) == type || !"Invalid tristate type comparison");
|
||||
}
|
||||
|
||||
/**
|
||||
* For the three given arguments on, off and none, define:
|
||||
* - tristate_on, tristate_off and tristate_none as constant values to
|
||||
* assign. For example: tristate t = tristate_on;
|
||||
* - tristate_is_on(), tristate_is_off(), tristate_is_none() as functions to check
|
||||
* a tristate. This function will abort if different tristate types are
|
||||
* mixed. For example:
|
||||
* tristate t = tristate_on;
|
||||
* if (tristate_is_none(t)) { .... }
|
||||
* - tristate_onoff_value() to retrieve the value from a tristate to be used
|
||||
* in e.g. a switch statement. The values are tristate_val_on,
|
||||
* tristate_val_off, trisate_val_none. For example:
|
||||
* switch(tristate_onoff_value(t)) {
|
||||
* case tristate_val_on: break;
|
||||
* case tristate_val_off: break;
|
||||
* case tristate_val_none: break;
|
||||
* }
|
||||
*/
|
||||
#define DEFINE_TRISTATE(_on, _off, _none) \
|
||||
static const unsigned _TRISTATE_TYPE_##_on##_off = (__LINE__ << 2); \
|
||||
static const unsigned tristate_val_##_on = _TRISTATE_TYPE_##_on##_off | 3; \
|
||||
static const unsigned tristate_val_##_off = _TRISTATE_TYPE_##_on##_off | 2; \
|
||||
static const unsigned tristate_val_##_none = _TRISTATE_TYPE_##_on##_off | 0; \
|
||||
static const tristate tristate_##_on = { .val = tristate_val_##_on }; \
|
||||
static const tristate tristate_##_off = { .val = tristate_val_##_off }; \
|
||||
static const tristate tristate_##_none = { .val = tristate_val_##_none }; \
|
||||
static inline bool tristate_is_##_on(tristate t) { \
|
||||
_tristate_check_type(&t, _TRISTATE_TYPE_##_on##_off); \
|
||||
return t.val == tristate_##_on.val; \
|
||||
} \
|
||||
static inline bool tristate_is_##_off(tristate t) { \
|
||||
_tristate_check_type(&t, _TRISTATE_TYPE_##_on##_off); \
|
||||
return t.val == tristate_##_off.val; \
|
||||
} \
|
||||
static inline bool tristate_is_##_none(tristate t) { \
|
||||
_tristate_check_type(&t, _TRISTATE_TYPE_##_on##_off); \
|
||||
return t.val == tristate_##_none.val; \
|
||||
} \
|
||||
static inline signed char tristate_##_on##_off_value(tristate t) { \
|
||||
_tristate_check_type(&t, _TRISTATE_TYPE_##_on##_off); \
|
||||
return t.val; \
|
||||
} \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
|
||||
|
||||
Loading…
Add table
Reference in a new issue