2019 day 3 + add br.h for some useful stuff (min, max... macros)
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
R75,D30,R83,U83,L12,D49,R71,U7,L72
|
R8,U5,L5,D3
|
||||||
U62,R66,U55,R34,D71,R55,D58,R83
|
U7,R6,D4,L4
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51
|
R75,D30,R83,U83,L12,D49,R71,U7,L72
|
||||||
U98,R91,D20,R16,D67,R40,U7,R15,U6,R7
|
U62,R66,U55,R34,D71,R55,D58,R83
|
||||||
|
2
2019/day03/EXAMPLE3.txt
Normal file
2
2019/day03/EXAMPLE3.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51
|
||||||
|
U98,R91,D20,R16,D67,R40,U7,R15,U6,R7
|
@@ -40,6 +40,10 @@ CFLAGS += -Wno-unused-result
|
|||||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||||
|
|
||||||
|
VALGRIND := valgrind
|
||||||
|
VALGRINDFLAGS := -q -s --leak-check=full --show-leak-kinds=all --track-origins=yes
|
||||||
|
|
||||||
|
|
||||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||||
export PATH := .:$(PATH)
|
export PATH := .:$(PATH)
|
||||||
|
|
||||||
@@ -49,11 +53,12 @@ all: ex1 ex2
|
|||||||
|
|
||||||
memcheck: memcheck1
|
memcheck: memcheck1
|
||||||
|
|
||||||
memcheck1:
|
memcheck1: aoc-c
|
||||||
@valgrind -q -s --track-origins=yes aoc-c -p 1 < $(INPUT)
|
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||||
|
|
||||||
memcheck2:
|
memcheck2: aoc-c
|
||||||
@valgrind -q -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||||
|
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||||
|
|
||||||
compile: aoc-c
|
compile: aoc-c
|
||||||
|
|
||||||
@@ -72,6 +77,11 @@ clean:
|
|||||||
@echo compiling $<
|
@echo compiling $<
|
||||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||||
|
|
||||||
.c.s:
|
# generate pre-processed file (.i) and assembler (.s)
|
||||||
|
%.i: %.c
|
||||||
|
@echo generating $@
|
||||||
|
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||||
|
|
||||||
|
%.s: %.c
|
||||||
@echo generating $@
|
@echo generating $@
|
||||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||||
|
@@ -55,12 +55,61 @@ is closer to the central port: its distance is =3 + 3 = 6=.
|
|||||||
|
|
||||||
Here are a few more examples:
|
Here are a few more examples:
|
||||||
|
|
||||||
- =R75,D30,R83,U83,L12,D49,R71,U7,L72=
|
- =R75,D30,R83,U83,L12,D49,R71,U7,L72U62,R66,U55,R34,D71,R55,D58,R83= =
|
||||||
=U62,R66,U55,R34,D71,R55,D58,R83= =distance =159=
|
distance =159=
|
||||||
- =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51=
|
- =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51U98,R91,D20,R16,D67,R40,U7,R15,U6,R7=
|
||||||
=U98,R91,D20,R16,D67,R40,U7,R15,U6,R7= =distance =135=
|
= distance =135=
|
||||||
|
|
||||||
/What is the Manhattan distance/ from the central port to the closest
|
/What is the Manhattan distance/ from the central port to the closest
|
||||||
intersection?
|
intersection?
|
||||||
|
|
||||||
To begin, [[file:3/input][get your puzzle input]].
|
Your puzzle answer was =860=.
|
||||||
|
|
||||||
|
** --- Part Two ---
|
||||||
|
It turns out that this circuit is very timing-sensitive; you actually
|
||||||
|
need to /minimize the signal delay/.
|
||||||
|
|
||||||
|
To do this, calculate the /number of steps/ each wire takes to reach
|
||||||
|
each intersection; choose the intersection where the /sum of both wires'
|
||||||
|
steps/ is lowest. If a wire visits a position on the grid multiple
|
||||||
|
times, use the steps value from the /first/ time it visits that position
|
||||||
|
when calculating the total value of a specific intersection.
|
||||||
|
|
||||||
|
The number of steps a wire takes is the total number of grid squares the
|
||||||
|
wire has entered to get to that location, including the intersection
|
||||||
|
being considered. Again consider the example from above:
|
||||||
|
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
...........
|
||||||
|
.+-----+...
|
||||||
|
.|.....|...
|
||||||
|
.|..+--X-+.
|
||||||
|
.|..|..|.|.
|
||||||
|
.|.-X--+.|.
|
||||||
|
.|..|....|.
|
||||||
|
.|.......|.
|
||||||
|
.o-------+.
|
||||||
|
...........
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
In the above example, the intersection closest to the central port is
|
||||||
|
reached after =8+5+5+2 = 20= steps by the first wire and =7+6+4+3 = 20=
|
||||||
|
steps by the second wire for a total of =20+20 = 40= steps.
|
||||||
|
|
||||||
|
However, the top-right intersection is better: the first wire takes only
|
||||||
|
=8+5+2 = 15= and the second wire takes only =7+6+2 = 15=, a total of
|
||||||
|
=15+15 = 30= steps.
|
||||||
|
|
||||||
|
Here are the best steps for the extra examples from above:
|
||||||
|
|
||||||
|
- =R75,D30,R83,U83,L12,D49,R71,U7,L72U62,R66,U55,R34,D71,R55,D58,R83= =
|
||||||
|
=610= steps
|
||||||
|
- =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51U98,R91,D20,R16,D67,R40,U7,R15,U6,R7=
|
||||||
|
= =410= steps
|
||||||
|
|
||||||
|
/What is the fewest combined steps the wires must take to reach an
|
||||||
|
intersection?/
|
||||||
|
|
||||||
|
Your puzzle answer was =9238=.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||||
|
224
2019/day03/aoc-c.c
Normal file
224
2019/day03/aoc-c.c
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
/* aoc-c.c: Advent of Code 2019, day 3 parts 1 & 2
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Bruno Raoult ("br")
|
||||||
|
* Licensed under the GNU General Public License v3.0 or later.
|
||||||
|
* Some rights reserved. See COPYING.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this
|
||||||
|
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "br.h"
|
||||||
|
#include "bits.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
typedef enum { DOWN = 'D', LEFT = 'L', RIGHT = 'R', UP = 'U' } dir_t;
|
||||||
|
|
||||||
|
struct point {
|
||||||
|
int x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wire {
|
||||||
|
int dist; /* total distance before this wire */
|
||||||
|
struct point delta; /* current delta */
|
||||||
|
struct point p0, p1;
|
||||||
|
struct list_head list; /* wire list */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct wires {
|
||||||
|
int nwires[2];
|
||||||
|
struct list_head head[2];
|
||||||
|
} wires[2];
|
||||||
|
|
||||||
|
static pool_t *wire_pool;
|
||||||
|
|
||||||
|
static struct wires *parse()
|
||||||
|
{
|
||||||
|
size_t alloc = 0;
|
||||||
|
ssize_t buflen;
|
||||||
|
char *buf = NULL, *token;
|
||||||
|
|
||||||
|
/* initialize wires lists */
|
||||||
|
INIT_LIST_HEAD(&wires->head[0]);
|
||||||
|
INIT_LIST_HEAD(&wires->head[1]);
|
||||||
|
|
||||||
|
for (int line = 0; line < 2; ++line) {
|
||||||
|
int x0 = 0, y0 = 0;
|
||||||
|
int x1 = 0, y1 = 0;
|
||||||
|
int totdist = 0;
|
||||||
|
|
||||||
|
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
|
||||||
|
fprintf(stderr, "error %d reading file.\n", errno);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (token = strtok(buf, ","); token; token = strtok(NULL, ",")) {
|
||||||
|
dir_t dir = *token;
|
||||||
|
int dist = atoi(token + 1);
|
||||||
|
struct wire *new = pool_get(wire_pool);
|
||||||
|
INIT_LIST_HEAD(&new->list);
|
||||||
|
new->dist = totdist;
|
||||||
|
new->delta.x = 0;
|
||||||
|
new->delta.y = 0;
|
||||||
|
totdist += abs(dist);
|
||||||
|
switch(dir) {
|
||||||
|
case DOWN:
|
||||||
|
y1 = y0 - dist;
|
||||||
|
new->delta.y = -dist;
|
||||||
|
break;
|
||||||
|
case UP:
|
||||||
|
y1 = y0 + dist;
|
||||||
|
new->delta.y = dist;
|
||||||
|
break;
|
||||||
|
case LEFT:
|
||||||
|
x1 = x0 - dist;
|
||||||
|
new->delta.x = -dist;
|
||||||
|
break;
|
||||||
|
case RIGHT:
|
||||||
|
x1 = x0 + dist;
|
||||||
|
new->delta.x = dist;
|
||||||
|
}
|
||||||
|
new->p0.x = min(x0, x1);
|
||||||
|
new->p0.y = min(y0, y1);
|
||||||
|
new->p1.x = max(x0, x1);
|
||||||
|
new->p1.y = max(y0, y1);
|
||||||
|
list_add_tail(&new->list, &wires->head[line]);
|
||||||
|
x0 = x1;
|
||||||
|
y0 = y1;
|
||||||
|
wires->nwires[line]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
free(buf);
|
||||||
|
return wires;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define manhattan(x, y) (abs(x) + abs(y))
|
||||||
|
|
||||||
|
static struct point *intersect(struct wire *w1, struct wire *w2, struct point *ret)
|
||||||
|
{
|
||||||
|
log_f(3, "(%d,%d)-(%d,%d) (%d,%d)-(%d,%d): ",
|
||||||
|
w1->p0.x, w1->p0.y, w1->p1.x, w1->p1.y,
|
||||||
|
w2->p0.x, w2->p0.y, w2->p1.x, w2->p1.y);
|
||||||
|
if (w1->p0.x == w1->p1.x) { /* w1 vertical */
|
||||||
|
/* TODO: overlapping wires (multiple intersections) */
|
||||||
|
if (w1->p0.x >= w2->p0.x && w1->p1.x <= w2->p1.x &&
|
||||||
|
w1->p0.y <= w2->p0.y && w1->p1.y >= w2->p1.y) {
|
||||||
|
log(3, "intersect 1 at (%d, %d)\n", w1->p0.x, w2->p0.y);
|
||||||
|
ret->x = w1->p0.x;
|
||||||
|
ret->y = w2->p0.y;
|
||||||
|
return ret;
|
||||||
|
//return manhatan(w1->p0.x, w2->p0.y);
|
||||||
|
}
|
||||||
|
log(3, "no intersection\n");
|
||||||
|
return NULL;
|
||||||
|
} else { /* w1 horizontal */
|
||||||
|
if (w1->p0.x <= w2->p0.x && w1->p1.x >= w2->p1.x &&
|
||||||
|
w1->p0.y <= w2->p1.y && w1->p1.y >= w2->p0.y) {
|
||||||
|
log(3, "intersect 2 at (%d, %d)\n", w2->p0.x, w1->p0.y);
|
||||||
|
ret->x = w2->p0.x;
|
||||||
|
ret->y = w1->p0.y;
|
||||||
|
return ret;
|
||||||
|
//return manhatan(w2->p0.x, w1->p0.y);
|
||||||
|
}
|
||||||
|
log(3, "no intersection\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32 part1(struct wires *w)
|
||||||
|
{
|
||||||
|
struct wire *w0, *w1;
|
||||||
|
struct point cross;
|
||||||
|
s32 res = INT32_MAX;
|
||||||
|
|
||||||
|
list_for_each_entry(w0, &w->head[0], list) {
|
||||||
|
list_for_each_entry(w1, &w->head[1], list) {
|
||||||
|
if (intersect(w0, w1, &cross)) {
|
||||||
|
int tmp = manhattan(cross.x, cross.y);
|
||||||
|
log(3, "new manhattan: %d\n", tmp);
|
||||||
|
res = min(tmp, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int part2(struct wires *w)
|
||||||
|
{
|
||||||
|
struct wire *w0, *w1;
|
||||||
|
struct point cross;
|
||||||
|
s32 res = INT32_MAX;
|
||||||
|
|
||||||
|
list_for_each_entry(w0, &w->head[0], list) {
|
||||||
|
list_for_each_entry(w1, &w->head[1], list) {
|
||||||
|
if (intersect(w0, w1, &cross)) {
|
||||||
|
if (cross.x || cross.y) {
|
||||||
|
int tmp = w0->dist + w1->dist;
|
||||||
|
|
||||||
|
/* as w->p0 contains the lowest value of (x, y), we lost the
|
||||||
|
* starting point information. We adjust remaining steps with
|
||||||
|
* the delta sign, which indicates if we swapped p0 and p1.
|
||||||
|
*/
|
||||||
|
tmp += w0->delta.x + w0->delta.y > 0 ?
|
||||||
|
abs(cross.x - w0->p0.x) + abs(cross.y - w0->p0.y) :
|
||||||
|
abs(cross.x - w0->p1.x) + abs(cross.y - w0->p1.y);
|
||||||
|
tmp += w1->delta.x + w1->delta.y > 0 ?
|
||||||
|
abs(cross.x - w1->p0.x) + abs(cross.y - w1->p0.y) :
|
||||||
|
abs(cross.x - w1->p1.x) + abs(cross.y - w1->p1.y);
|
||||||
|
/* new best */
|
||||||
|
res = min(tmp, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usage(char *prg)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int ac, char **av)
|
||||||
|
{
|
||||||
|
int opt, part = 1;
|
||||||
|
struct wires *wires;
|
||||||
|
|
||||||
|
while ((opt = getopt(ac, av, "d:p:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'd':
|
||||||
|
debug_level_set(atoi(optarg));
|
||||||
|
break;
|
||||||
|
case 'p': /* 1 or 2 */
|
||||||
|
part = atoi(optarg);
|
||||||
|
if (part < 1 || part > 2)
|
||||||
|
return usage(*av);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return usage(*av);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < ac)
|
||||||
|
return usage(*av);
|
||||||
|
wire_pool = pool_create("wire", 256, sizeof(struct wire));
|
||||||
|
|
||||||
|
wires = parse();
|
||||||
|
printf("%s : res=%d\n", *av, part == 1? part1(wires): part2(wires));
|
||||||
|
pool_destroy(wire_pool);
|
||||||
|
exit (0);
|
||||||
|
}
|
203
2019/include/br.h
Normal file
203
2019/include/br.h
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
/* bits.h - bits functions.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||||
|
* Licensed under the GNU General Public License v3.0 or later.
|
||||||
|
* Some rights reserved. See COPYING.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this
|
||||||
|
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
|
*
|
||||||
|
* Some parts are taken from Linux's kernel <linux/kernel.h> and others, and are :
|
||||||
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
|
*
|
||||||
|
* This header contains generic stuff.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BR_H
|
||||||
|
#define _BR_H
|
||||||
|
|
||||||
|
/* generate a (maybe) unique id.
|
||||||
|
*/
|
||||||
|
#define ___PASTE(x, y) x##y
|
||||||
|
#define __PASTE(x, y) ___PASTE(x, y)
|
||||||
|
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
|
||||||
|
//__##prefix##__COUNTER__
|
||||||
|
|
||||||
|
/* see https://lkml.org/lkml/2018/3/20/845 for explanation of this monster
|
||||||
|
*/
|
||||||
|
#define __is_constexpr(x) \
|
||||||
|
(sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* min()/max()/clamp() macros must accomplish three things:
|
||||||
|
*
|
||||||
|
* - avoid multiple evaluations of the arguments (so side-effects like
|
||||||
|
* "x++" happen only once) when non-constant.
|
||||||
|
* - perform strict type-checking (to generate warnings instead of
|
||||||
|
* nasty runtime surprises). See the "unnecessary" pointer comparison
|
||||||
|
* in __typecheck().
|
||||||
|
* - retain result as a constant expressions when called with only
|
||||||
|
* constant expressions (to avoid tripping VLA warnings in stack
|
||||||
|
* allocation usage).
|
||||||
|
*/
|
||||||
|
#define __typecheck(x, y) \
|
||||||
|
(!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
|
||||||
|
|
||||||
|
#define __no_side_effects(x, y) \
|
||||||
|
(__is_constexpr(x) && __is_constexpr(y))
|
||||||
|
|
||||||
|
#define __safe_cmp(x, y) \
|
||||||
|
(__typecheck(x, y) && __no_side_effects(x, y))
|
||||||
|
|
||||||
|
#define __cmp(x, y, op) ((x) op (y) ? (x) : (y))
|
||||||
|
|
||||||
|
#define __cmp_once(x, y, unique_x, unique_y, op) ({ \
|
||||||
|
typeof(x) unique_x = (x); \
|
||||||
|
typeof(y) unique_y = (y); \
|
||||||
|
__cmp(unique_x, unique_y, op); })
|
||||||
|
|
||||||
|
#define __careful_cmp(x, y, op) \
|
||||||
|
__builtin_choose_expr(__safe_cmp(x, y), \
|
||||||
|
__cmp(x, y, op), \
|
||||||
|
__cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* min - return minimum of two values of the same or compatible types
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
*/
|
||||||
|
#define min(x, y) __careful_cmp(x, y, <)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* max - return maximum of two values of the same or compatible types
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
*/
|
||||||
|
#define max(x, y) __careful_cmp(x, y, >)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* min3 - return minimum of three values
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
* @z: third value
|
||||||
|
*/
|
||||||
|
#define min3(x, y, z) min((typeof(x))min(x, y), z)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* max3 - return maximum of three values
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
* @z: third value
|
||||||
|
*/
|
||||||
|
#define max3(x, y, z) max((typeof(x))max(x, y), z)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* min_not_zero - return the minimum that is _not_ zero, unless both are zero
|
||||||
|
* @x: value1
|
||||||
|
* @y: value2
|
||||||
|
*/
|
||||||
|
#define min_not_zero(x, y) ({ \
|
||||||
|
typeof(x) __x = (x); \
|
||||||
|
typeof(y) __y = (y); \
|
||||||
|
__x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clamp - return a value clamped to a given range with strict typechecking
|
||||||
|
* @val: current value
|
||||||
|
* @lo: lowest allowable value
|
||||||
|
* @hi: highest allowable value
|
||||||
|
*
|
||||||
|
* This macro does strict typechecking of @lo/@hi to make sure they are of the
|
||||||
|
* same type as @val. See the unnecessary pointer comparisons.
|
||||||
|
*/
|
||||||
|
#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ..and if you can't take the strict
|
||||||
|
* types, you can specify one yourself.
|
||||||
|
*
|
||||||
|
* Or not use min/max/clamp at all, of course.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* min_t - return minimum of two values, using the specified type
|
||||||
|
* @type: data type to use
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
*/
|
||||||
|
#define min_t(type, x, y) __careful_cmp((type)(x), (type)(y), <)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* max_t - return maximum of two values, using the specified type
|
||||||
|
* @type: data type to use
|
||||||
|
* @x: first value
|
||||||
|
* @y: second value
|
||||||
|
*/
|
||||||
|
#define max_t(type, x, y) __careful_cmp((type)(x), (type)(y), >)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clamp_t - return a value clamped to a given range using a given type
|
||||||
|
* @type: the type of variable to use
|
||||||
|
* @val: current value
|
||||||
|
* @lo: minimum allowable value
|
||||||
|
* @hi: maximum allowable value
|
||||||
|
*
|
||||||
|
* This macro does no typechecking and uses temporary variables of type
|
||||||
|
* @type to make all the comparisons.
|
||||||
|
*/
|
||||||
|
#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clamp_val - return a value clamped to a given range using val's type
|
||||||
|
* @val: current value
|
||||||
|
* @lo: minimum allowable value
|
||||||
|
* @hi: maximum allowable value
|
||||||
|
*
|
||||||
|
* This macro does no typechecking and uses temporary variables of whatever
|
||||||
|
* type the input argument @val is. This is useful when @val is an unsigned
|
||||||
|
* type and @lo and @hi are literals that will otherwise be assigned a signed
|
||||||
|
* integer type.
|
||||||
|
*/
|
||||||
|
#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* swap - swap values of @a and @b
|
||||||
|
* @a: first value
|
||||||
|
* @b: second value
|
||||||
|
*/
|
||||||
|
#define swap(a, b) \
|
||||||
|
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ARRAY_SIZE - get the number of elements in array @arr
|
||||||
|
* @arr: array to be sized
|
||||||
|
*/
|
||||||
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* abs - return absolute value of an argument
|
||||||
|
* @x: the value. If it is unsigned type, it is converted to signed type first.
|
||||||
|
* char is treated as if it was signed (regardless of whether it really is)
|
||||||
|
* but the macro's return type is preserved as char.
|
||||||
|
*
|
||||||
|
* Return: an absolute value of x.
|
||||||
|
*/
|
||||||
|
#define abs(x) __abs_choose_expr(x, long long, \
|
||||||
|
__abs_choose_expr(x, long, \
|
||||||
|
__abs_choose_expr(x, int, \
|
||||||
|
__abs_choose_expr(x, short, \
|
||||||
|
__abs_choose_expr(x, char, \
|
||||||
|
__builtin_choose_expr( \
|
||||||
|
__builtin_types_compatible_p(typeof(x), char), \
|
||||||
|
(char)({ signed char __x = (x); __x<0?-__x:__x; }), \
|
||||||
|
((void)0)))))))
|
||||||
|
|
||||||
|
#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \
|
||||||
|
__builtin_types_compatible_p(typeof(x), signed type) || \
|
||||||
|
__builtin_types_compatible_p(typeof(x), unsigned type), \
|
||||||
|
({ signed type __x = (x); __x < 0 ? -__x : __x; }), other)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _BR_H */
|
Reference in New Issue
Block a user