Compare commits
379 Commits
0223d4bd2c
...
main
Author | SHA1 | Date | |
---|---|---|---|
ad6a39e82a | |||
3a857e4d53 | |||
f80a051177 | |||
129fa07787 | |||
1472082c86 | |||
e8bed49e13 | |||
83d70dcc7a | |||
56d2e63fac | |||
5c91de5d40 | |||
40a9c7b12e | |||
34b6cd7b57 | |||
5ad5c87fd8 | |||
11e7b45676 | |||
3f2a5648df | |||
0a3b404c4c | |||
a214d2b70d | |||
f490c2353e | |||
2ed6284bcd | |||
5fc204744a | |||
d1cf8d96b8 | |||
b285f74997 | |||
c949c64da2 | |||
357e8ce087 | |||
5cde9051ec | |||
111fde4fbd | |||
f54479189b | |||
8e00fec33c | |||
d0376f21c3 | |||
04a856dc47 | |||
0658ffdd7d | |||
efe0dec8f0 | |||
6d4a8dd85b | |||
11cb3c5c64 | |||
7e0a21704e | |||
008599e79c | |||
fe381ae7f0 | |||
4a0749999e | |||
18720b9e09 | |||
17e140f235 | |||
a1e436babc | |||
02a1dda786 | |||
ef29ca28a1 | |||
c1b3e83c68 | |||
bd2548fca9 | |||
3f5b282883 | |||
38ef781f0a | |||
13d183de79 | |||
dfe2207e8e | |||
31a255a9ac | |||
25d25b399e | |||
f5ebb5c5cc | |||
c608f6dcde | |||
9e3a875e37 | |||
4c0f6e3025 | |||
68f200ff65 | |||
8aff410ff4 | |||
16da47600c | |||
8b68bf4449 | |||
c86517897e | |||
9c999e9717 | |||
05643127c2 | |||
6a5a0da435 | |||
3dd072c53e | |||
8f09fcf13f | |||
8f444d7341 | |||
d7fa1c4fb5 | |||
0c787d9a51 | |||
64ad068ec8 | |||
ab73311d6b | |||
d116b98ae9 | |||
325c8254b8 | |||
76ab3d0c5b | |||
bc2b2ac726 | |||
b7c0b1fa01 | |||
487766c0a2 | |||
a0fddb5f44 | |||
f68d5b319e | |||
9455b99342 | |||
ea4967bfcd | |||
d1026e8f59 | |||
01cdce6608 | |||
b8f6763a3b | |||
81a58c6266 | |||
ca06a4a355 | |||
9d375aecfc | |||
d412824317 | |||
d8e05b0fca | |||
a49a2ed073 | |||
2c14abff21 | |||
50919df627 | |||
73c9fa8150 | |||
b949e11314 | |||
f003511e10 | |||
36f763830f | |||
c7553e7849 | |||
|
6012d4d375 | ||
ce446be296 | |||
a8cab0c7c3 | |||
dbff06e5da | |||
0fb4219c92 | |||
58ba8b4ab8 | |||
cca3d6fbe5 | |||
cfba08b197 | |||
ca8de49d5e | |||
ea9c144127 | |||
d4d5af0cb6 | |||
5ee230df69 | |||
9fe7b64263 | |||
8df13f9713 | |||
74ab0ba990 | |||
46dee29af6 | |||
ad7c6f3042 | |||
d485983efc | |||
23c33894a5 | |||
9bd03e0650 | |||
6de646f0d1 | |||
a525ab6338 | |||
2de0c3c9c8 | |||
6e4c64db39 | |||
b73db03da9 | |||
f6d1fe7b9d | |||
30cdb5e1a4 | |||
b4a2603c7b | |||
abcc4af572 | |||
94f0d95544 | |||
452a912fe5 | |||
46d6b77596 | |||
65c03075f1 | |||
4a565af1c2 | |||
0a03bc557b | |||
282d55c3cd | |||
920f830fac | |||
e3d6b622dc | |||
5795d24ab4 | |||
86a62f0b2d | |||
f3ae028751 | |||
d2b5a9dc34 | |||
563798871a | |||
cced357154 | |||
4653101623 | |||
0fb3d8832f | |||
c30ca858e4 | |||
cd41685cb5 | |||
d2d66dc763 | |||
284eeb3dea | |||
f74a1ffb8a | |||
b001690c95 | |||
0fe04e43dc | |||
bd851b6524 | |||
|
1cfd1c81f0 | ||
|
130f2a4d54 | ||
625966f5b8 | |||
521e6e1bca | |||
bacbc6eded | |||
5694883ef5 | |||
6a43725e30 | |||
4d938b6cd7 | |||
0c9b93b42a | |||
04fcca5829 | |||
ddfa8cf05b | |||
5008963937 | |||
155e066ed2 | |||
626bd1df41 | |||
8ed39e52b7 | |||
e83b690822 | |||
0004b2091e | |||
a201283599 | |||
d5c37f5d48 | |||
1c10926cf9 | |||
94c6b2eec5 | |||
b50f3a7098 | |||
8783eca22c | |||
3d18e36ff4 | |||
b6af1f3edb | |||
|
68d81fd1da | ||
|
b206ee5b87 | ||
|
13c977957f | ||
|
d0adb2378a | ||
d1221ab086 | |||
f2b32f236d | |||
696273367a | |||
f7336d6814 | |||
a461bf2842 | |||
0ce9f9aafa | |||
ea530e7d8d | |||
2694f8d4d0 | |||
f9a80239b4 | |||
ffb27a8338 | |||
dbfc914efb | |||
c4772bb416 | |||
bc8dac927a | |||
42d1f7bf48 | |||
828d13f967 | |||
b67600957e | |||
0d7424d9c6 | |||
d9b0f7b7c4 | |||
378df8cf5b | |||
c56f9ca769 | |||
37a38bdc4a | |||
e0720bdd0a | |||
2fda973085 | |||
79428d6192 | |||
ebb8a0d738 | |||
721f9da54e | |||
5da5adb8bf | |||
adb8fc6b95 | |||
4dbcc30dc3 | |||
49bbc2372c | |||
aa0f475b17 | |||
9a0d7a2ca7 | |||
ea429a99a7 | |||
4fa4a5d366 | |||
e25d79e95b | |||
4be7c56b88 | |||
c78a3e7285 | |||
f807acc983 | |||
b64bc6c1d5 | |||
6aa605a0de | |||
1f835c10c5 | |||
d4ec54ed5b | |||
4ac39e5a69 | |||
b8e61bcacb | |||
efb25f363f | |||
1e8556b5d5 | |||
5c392199fe | |||
6b753e9d6c | |||
35053f3c8c | |||
97411fbb08 | |||
ecbeffc3d9 | |||
7082ce3565 | |||
58027905b8 | |||
76bd022049 | |||
cf2bed124e | |||
dacefcd5ad | |||
db7013309b | |||
63e737b863 | |||
f1af70e55a | |||
ec4684a756 | |||
897453fb39 | |||
81cfe12d67 | |||
640feea875 | |||
2692f3f621 | |||
5346b0e7fa | |||
c84a37874c | |||
b11c35be26 | |||
858258770b | |||
1caa102c23 | |||
9fd980c71b | |||
6c3672f8d1 | |||
96c9f7d6e3 | |||
fe4520da7f | |||
a03cc1c1c4 | |||
f1dc062250 | |||
645188216e | |||
e3382ef3dd | |||
8a67ac0321 | |||
b255dc5d43 | |||
33bee9500c | |||
46fd8a30bc | |||
77ef1fa003 | |||
457b3eb9b9 | |||
a88aa2312b | |||
cd4a21380d | |||
a0b094aa61 | |||
0e333e5cb9 | |||
0344a9162f | |||
8d3a064c73 | |||
2f47bb23ea | |||
0f932bca95 | |||
95ef1bc864 | |||
8748eb0f1f | |||
7b7095b8d7 | |||
f3717c906b | |||
f8720a2129 | |||
bdfad93f4a | |||
50963c233b | |||
90303eb8b5 | |||
118d7f8452 | |||
93ef9438b8 | |||
43378e9366 | |||
9d9b111e2c | |||
a84c52fa94 | |||
aace9d72de | |||
befb71ed22 | |||
fde80b124b | |||
85b4204894 | |||
ca6b612d0d | |||
d0c6c6e4f7 | |||
33ae1b1751 | |||
295f032d6a | |||
cbbfb507c3 | |||
394cfcd2ca | |||
81867c5a18 | |||
9933153c9d | |||
94aeedb78b | |||
2dec566985 | |||
d973d86ec7 | |||
60a042951b | |||
b06d784563 | |||
cede0eb93f | |||
af7543b623 | |||
e07241fd25 | |||
1458315653 | |||
9c5e734ece | |||
dbf9b52cb3 | |||
7fd472c17c | |||
80c19f9331 | |||
37fa19f6be | |||
42addcefad | |||
d20651dd50 | |||
0cea717fcb | |||
b998ada9d2 | |||
171eadf318 | |||
fb5be18e18 | |||
34acd4012b | |||
395060c266 | |||
23c0e33c82 | |||
b67985003c | |||
192545c9a3 | |||
3235bd3b15 | |||
e871ccf091 | |||
6f6a6b286a | |||
833732ae58 | |||
7c981d6633 | |||
6a0a81aa38 | |||
b62404686a | |||
3cfe781a08 | |||
0ea7a9278a | |||
736cae886a | |||
867eb7fda0 | |||
cb1e5ed442 | |||
68f40df298 | |||
3e886caf63 | |||
a6ccc58636 | |||
a46c23235d | |||
a0cb3e5fd8 | |||
8f2c0f8c2d | |||
401b567e20 | |||
cbe3616422 | |||
edcafd2a00 | |||
9a65775f7a | |||
f769e9b361 | |||
a9c713a5ea | |||
e93108d033 | |||
adcc449bea | |||
172dac6bfe | |||
568bc1c0ac | |||
89c85cc40a | |||
2fc8a49cea | |||
bd0ccdd942 | |||
9bd7a0cd85 | |||
58980edfb0 | |||
ba89d9cf0c | |||
bd0c02fb5f | |||
ad032df481 | |||
7a1a200a73 | |||
2d431892da | |||
6e9e4be8e3 | |||
12d4bdda61 | |||
9a9742bf26 | |||
92f7ea1b2c | |||
1a09c380a2 | |||
5b0a1d7b53 | |||
92cc3e90c4 | |||
9c60bd6d12 | |||
2646b3fa75 | |||
16f4f9f926 | |||
984c6cc942 | |||
3011ffcb5c | |||
16deb0f76b | |||
1db46ed0b0 | |||
937c1b434b | |||
419376949f | |||
fbb553645e | |||
44c9d00b85 | |||
ce4bcbe7c5 | |||
ba0a6217fd | |||
f4348d3faf | |||
150e4ba2a7 |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,3 +1,15 @@
|
||||
ex*-c
|
||||
core
|
||||
aoc-c
|
||||
core*
|
||||
.ccls*
|
||||
.projectile
|
||||
.dir-locals.el
|
||||
gmon.out
|
||||
*.o
|
||||
ex*-cob
|
||||
lib/
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
README.html
|
||||
compile_commands.json
|
||||
|
87
2019/Makefile
Normal file
87
2019/Makefile
Normal file
@@ -0,0 +1,87 @@
|
||||
# AOC Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
|
||||
SUBDIRS := $(shell echo day??)
|
||||
|
||||
CC = gcc
|
||||
|
||||
#LIBS = -lreadline -lncurses
|
||||
CFLAGS += -std=gnu11
|
||||
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
INCDIR := ./include
|
||||
LIBSRCDIR := ./libsrc
|
||||
LIBDIR := ./lib
|
||||
LIB := libaoc_$(shell uname -m)
|
||||
SLIB := $(LIBDIR)/$(LIB).a
|
||||
DLIB := $(LIBDIR)/$(LIB).so
|
||||
LIBSRC := $(wildcard $(LIBSRCDIR)/*.c)
|
||||
LIBOBJ := $(patsubst %.c,%.o,$(LIBSRC))
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
.PHONY: clean cleanlib cleanall all redo output lib $(SUBDIRS)
|
||||
|
||||
all: lib $(SUBDIRS)
|
||||
|
||||
clean:
|
||||
@for dir in $(SUBDIRS) ; do \
|
||||
$(MAKE) --no-print-directory -C $$dir clean ; \
|
||||
done
|
||||
|
||||
cleanlib: clean
|
||||
@$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ)
|
||||
|
||||
cleanall: clean cleanlib
|
||||
|
||||
redo: cleanall all
|
||||
|
||||
$(SUBDIRS):
|
||||
@echo "========================================="
|
||||
@echo "================= $@ ================="
|
||||
@echo "========================================="
|
||||
@echo
|
||||
@echo "+++++++++++++++++ part 1"
|
||||
+@$(MAKE) --no-print-directory -C $@ ex1 2>&1
|
||||
@echo "+++++++++++++++++ part 2"
|
||||
+@$(MAKE) --no-print-directory -C $@ ex2 2>&1
|
||||
|
||||
output:
|
||||
@$(MAKE) --no-print-directory all >OUTPUT 2>&1
|
||||
|
||||
lib: $(DLIB) $(SLIB)
|
||||
|
||||
$(SLIB): $(LIBOBJ)
|
||||
@echo building $@ static library.
|
||||
@mkdir -p $(LIBDIR)
|
||||
@$(AR) $(ARFLAGS) -o $@ $^
|
||||
|
||||
$(DLIB): CFLAGS += -fPIC
|
||||
$(DLIB): LDFLAGS += -shared
|
||||
$(DLIB): $(LIBOBJ)
|
||||
@echo building $@ shared library.
|
||||
@mkdir -p $(LIBDIR)
|
||||
@$(CC) $(LDFLAGS) $^ -o $@
|
||||
|
||||
.c.o:
|
||||
@echo compiling $<.
|
||||
@$(CC) -c $(CFLAGS) $(LDFLAGS) -I $(INCDIR) -o $@ $<
|
132
2019/RESULTS.txt
Normal file
132
2019/RESULTS.txt
Normal file
@@ -0,0 +1,132 @@
|
||||
=========================================
|
||||
================= day01 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=3318604
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+87
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=4975039
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+89
|
||||
|
||||
=========================================
|
||||
================= day02 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=3790689
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+88
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=6533
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+88
|
||||
|
||||
=========================================
|
||||
================= day03 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=860
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+99
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=9238
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+98
|
||||
|
||||
=========================================
|
||||
================= day04 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=2090
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+90
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=1419
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+89
|
||||
|
||||
=========================================
|
||||
================= day05 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=10987514
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+87
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=14195011
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+87
|
||||
|
||||
=========================================
|
||||
================= day06 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
compiling aoc-c.c
|
||||
aoc-c : res=453028
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+417
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=562
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+417
|
||||
|
||||
=========================================
|
||||
================= day07 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=65464
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+94
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=1518124
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+94
|
||||
|
||||
=========================================
|
||||
================= day08 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=2250
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+93
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
#### # # ## # # #
|
||||
# # # # # # #
|
||||
### #### # # # #
|
||||
# # # # # # #
|
||||
# # # # # # # #
|
||||
# # # ## ## ####
|
||||
aoc-c : res=0
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+90
|
||||
|
||||
=========================================
|
||||
================= day09 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ part 1
|
||||
aoc-c : res=2682107844
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+92
|
||||
|
||||
+++++++++++++++++ part 2
|
||||
aoc-c : res=34738
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 1+1, page-faults: 0+95
|
100
2019/day01/INPUT.txt
Normal file
100
2019/day01/INPUT.txt
Normal file
@@ -0,0 +1,100 @@
|
||||
123457
|
||||
98952
|
||||
65241
|
||||
62222
|
||||
144922
|
||||
111868
|
||||
71513
|
||||
74124
|
||||
140122
|
||||
133046
|
||||
65283
|
||||
107447
|
||||
144864
|
||||
136738
|
||||
118458
|
||||
91049
|
||||
71486
|
||||
100320
|
||||
143765
|
||||
88677
|
||||
62034
|
||||
139946
|
||||
81017
|
||||
128668
|
||||
126450
|
||||
56551
|
||||
136839
|
||||
64516
|
||||
91821
|
||||
139909
|
||||
52907
|
||||
78846
|
||||
102008
|
||||
58518
|
||||
128627
|
||||
71256
|
||||
133546
|
||||
90986
|
||||
50808
|
||||
139055
|
||||
88769
|
||||
94491
|
||||
128902
|
||||
55976
|
||||
103658
|
||||
123605
|
||||
113468
|
||||
128398
|
||||
61725
|
||||
100388
|
||||
96763
|
||||
101378
|
||||
139952
|
||||
138298
|
||||
87171
|
||||
51840
|
||||
64828
|
||||
58250
|
||||
88273
|
||||
136781
|
||||
120097
|
||||
127291
|
||||
143752
|
||||
117291
|
||||
100023
|
||||
147239
|
||||
71296
|
||||
100907
|
||||
127612
|
||||
122424
|
||||
62942
|
||||
95445
|
||||
74040
|
||||
118994
|
||||
81810
|
||||
146408
|
||||
98939
|
||||
71359
|
||||
112120
|
||||
100630
|
||||
139576
|
||||
98998
|
||||
92481
|
||||
53510
|
||||
76343
|
||||
125428
|
||||
73447
|
||||
62472
|
||||
91370
|
||||
73506
|
||||
126539
|
||||
50739
|
||||
73133
|
||||
81906
|
||||
100856
|
||||
52758
|
||||
142303
|
||||
107605
|
||||
77797
|
||||
124355
|
93
2019/day01/Makefile
Normal file
93
2019/day01/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
75
2019/day01/README.org
Normal file
75
2019/day01/README.org
Normal file
@@ -0,0 +1,75 @@
|
||||
** --- Day 1: The Tyranny of the Rocket Equation ---
|
||||
Santa has become stranded at the edge of the Solar System while
|
||||
delivering presents to other planets! To accurately calculate his
|
||||
position in space, safely align his warp drive, and return to Earth in
|
||||
time to save Christmas, he needs you to bring him measurements from
|
||||
/fifty stars/.
|
||||
|
||||
Collect stars by solving puzzles. Two puzzles will be made available on
|
||||
each day in the Advent calendar; the second puzzle is unlocked when you
|
||||
complete the first. Each puzzle grants /one star/. Good luck!
|
||||
|
||||
The Elves quickly load you into a spacecraft and prepare to launch.
|
||||
|
||||
At the first Go / No Go poll, every Elf is Go until the Fuel
|
||||
Counter-Upper. They haven't determined the amount of fuel required yet.
|
||||
|
||||
Fuel required to launch a given /module/ is based on its /mass/.
|
||||
Specifically, to find the fuel required for a module, take its mass,
|
||||
divide by three, round down, and subtract 2.
|
||||
|
||||
For example:
|
||||
|
||||
- For a mass of =12=, divide by 3 and round down to get =4=, then
|
||||
subtract 2 to get =2=.
|
||||
- For a mass of =14=, dividing by 3 and rounding down still yields =4=,
|
||||
so the fuel required is also =2=.
|
||||
- For a mass of =1969=, the fuel required is =654=.
|
||||
- For a mass of =100756=, the fuel required is =33583=.
|
||||
|
||||
The Fuel Counter-Upper needs to know the total fuel requirement. To find
|
||||
it, individually calculate the fuel needed for the mass of each module
|
||||
(your puzzle input), then add together all the fuel values.
|
||||
|
||||
/What is the sum of the fuel requirements/ for all of the modules on
|
||||
your spacecraft?
|
||||
|
||||
Your puzzle answer was =3318604=.
|
||||
|
||||
** --- Part Two ---
|
||||
During the second Go / No Go poll, the Elf in charge of the Rocket
|
||||
Equation Double-Checker stops the launch sequence. Apparently, you
|
||||
forgot to include additional fuel for the fuel you just added.
|
||||
|
||||
Fuel itself requires fuel just like a module - take its mass, divide by
|
||||
three, round down, and subtract 2. However, that fuel /also/ requires
|
||||
fuel, and /that/ fuel requires fuel, and so on. Any mass that would
|
||||
require /negative fuel/ should instead be treated as if it requires
|
||||
/zero fuel/; the remaining mass, if any, is instead handled by /wishing
|
||||
really hard/, which has no mass and is outside the scope of this
|
||||
calculation.
|
||||
|
||||
So, for each module mass, calculate its fuel and add it to the total.
|
||||
Then, treat the fuel amount you just calculated as the input mass and
|
||||
repeat the process, continuing until a fuel requirement is zero or
|
||||
negative. For example:
|
||||
|
||||
- A module of mass =14= requires =2= fuel. This fuel requires no further
|
||||
fuel (2 divided by 3 and rounded down is =0=, which would call for a
|
||||
negative fuel), so the total fuel required is still just =2=.
|
||||
- At first, a module of mass =1969= requires =654= fuel. Then, this fuel
|
||||
requires =216= more fuel (=654 / 3 - 2=). =216= then requires =70=
|
||||
more fuel, which requires =21= fuel, which requires =5= fuel, which
|
||||
requires no further fuel. So, the total fuel required for a module of
|
||||
mass =1969= is =654 + 216 + 70 + 21 + 5 = 966=.
|
||||
- The fuel required by a module of mass =100756= and its fuel is:
|
||||
=33583 + 11192 + 3728 + 1240 + 411 + 135 + 43 + 12 + 2 = 50346=.
|
||||
|
||||
/What is the sum of the fuel requirements/ for all of the modules on
|
||||
your spacecraft when also taking into account the mass of the added
|
||||
fuel? (Calculate the fuel requirements for each module separately, then
|
||||
add them all up at the end.)
|
||||
|
||||
Your puzzle answer was =4975039=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
74
2019/day01/aoc-c.c
Normal file
74
2019/day01/aoc-c.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 1 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 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>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "pool.h"
|
||||
#include "list.h"
|
||||
#include "bits.h"
|
||||
|
||||
static u64 part1()
|
||||
{
|
||||
u64 res = 0;
|
||||
int cur;
|
||||
|
||||
while (scanf("%d", &cur) != EOF)
|
||||
res += cur / 3 - 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
static u64 part2()
|
||||
{
|
||||
u64 res = 0;
|
||||
int cur;
|
||||
|
||||
while (scanf("%d", &cur) != EOF)
|
||||
while ((cur = cur / 3 - 2) > 0)
|
||||
res += cur;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
printf("%s : res=%lu\n", *av, part == 1? part1(): part2());
|
||||
|
||||
exit (0);
|
||||
}
|
1
2019/day02/EXAMPLE.txt
Normal file
1
2019/day02/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
1,9,10,3,2,3,11,0,99,30,40,50
|
1
2019/day02/EXAMPLE2.txt
Normal file
1
2019/day02/EXAMPLE2.txt
Normal file
@@ -0,0 +1 @@
|
||||
1,0,0,0,99
|
1
2019/day02/EXAMPLE3.txt
Normal file
1
2019/day02/EXAMPLE3.txt
Normal file
@@ -0,0 +1 @@
|
||||
2,3,0,3,99
|
1
2019/day02/EXAMPLE4.txt
Normal file
1
2019/day02/EXAMPLE4.txt
Normal file
@@ -0,0 +1 @@
|
||||
2,4,4,5,99,0
|
1
2019/day02/EXAMPLE5.txt
Normal file
1
2019/day02/EXAMPLE5.txt
Normal file
@@ -0,0 +1 @@
|
||||
1,1,1,4,99,5,6,0,99
|
1
2019/day02/INPUT.txt
Normal file
1
2019/day02/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
||||
1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,1,13,19,1,9,19,23,2,13,23,27,2,27,13,31,2,31,10,35,1,6,35,39,1,5,39,43,1,10,43,47,1,5,47,51,1,13,51,55,2,55,9,59,1,6,59,63,1,13,63,67,1,6,67,71,1,71,10,75,2,13,75,79,1,5,79,83,2,83,6,87,1,6,87,91,1,91,13,95,1,95,13,99,2,99,13,103,1,103,5,107,2,107,10,111,1,5,111,115,1,2,115,119,1,119,6,0,99,2,0,14,0
|
93
2019/day02/Makefile
Normal file
93
2019/day02/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
159
2019/day02/README.org
Normal file
159
2019/day02/README.org
Normal file
@@ -0,0 +1,159 @@
|
||||
** --- Day 2: 1202 Program Alarm ---
|
||||
On the way to your
|
||||
[[https://en.wikipedia.org/wiki/Gravity_assist][gravity assist]] around
|
||||
the Moon, your ship computer beeps angrily about a
|
||||
"[[https://www.hq.nasa.gov/alsj/a11/a11.landing.html#1023832][1202
|
||||
program alarm]]". On the radio, an Elf is already explaining how to
|
||||
handle the situation: "Don't worry, that's perfectly norma--" The ship
|
||||
computer [[https://en.wikipedia.org/wiki/Halt_and_Catch_Fire][bursts
|
||||
into flames]].
|
||||
|
||||
You notify the Elves that the computer's
|
||||
[[https://en.wikipedia.org/wiki/Magic_smoke][magic smoke]] seems to have
|
||||
escaped. "That computer ran /Intcode/ programs like the gravity assist
|
||||
program it was working on; surely there are enough spare parts up there
|
||||
to build a new Intcode computer!"
|
||||
|
||||
An Intcode program is a list of
|
||||
[[https://en.wikipedia.org/wiki/Integer][integers]] separated by commas
|
||||
(like =1,0,0,3,99=). To run one, start by looking at the first integer
|
||||
(called position =0=). Here, you will find an /opcode/ - either =1=,
|
||||
=2=, or =99=. The opcode indicates what to do; for example, =99= means
|
||||
that the program is finished and should immediately halt. Encountering
|
||||
an unknown opcode means something went wrong.
|
||||
|
||||
Opcode =1= /adds/ together numbers read from two positions and stores
|
||||
the result in a third position. The three integers /immediately after/
|
||||
the opcode tell you these three positions - the first two indicate the
|
||||
/positions/ from which you should read the input values, and the third
|
||||
indicates the /position/ at which the output should be stored.
|
||||
|
||||
For example, if your Intcode computer encounters =1,10,20,30=, it should
|
||||
read the values at positions =10= and =20=, add those values, and then
|
||||
overwrite the value at position =30= with their sum.
|
||||
|
||||
Opcode =2= works exactly like opcode =1=, except it /multiplies/ the two
|
||||
inputs instead of adding them. Again, the three integers after the
|
||||
opcode indicate /where/ the inputs and outputs are, not their values.
|
||||
|
||||
Once you're done processing an opcode, /move to the next one/ by
|
||||
stepping forward =4= positions.
|
||||
|
||||
For example, suppose you have the following program:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
1,9,10,3,2,3,11,0,99,30,40,50
|
||||
#+END_EXAMPLE
|
||||
|
||||
For the purposes of illustration, here is the same program split into
|
||||
multiple lines:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
1,9,10,3,
|
||||
2,3,11,0,
|
||||
99,
|
||||
30,40,50
|
||||
#+END_EXAMPLE
|
||||
|
||||
The first four integers, =1,9,10,3=, are at positions =0=, =1=, =2=, and
|
||||
=3=. Together, they represent the first opcode (=1=, addition), the
|
||||
positions of the two inputs (=9= and =10=), and the position of the
|
||||
output (=3=). To handle this opcode, you first need to get the values at
|
||||
the input positions: position =9= contains =30=, and position =10=
|
||||
contains =40=. /Add/ these numbers together to get =70=. Then, store
|
||||
this value at the output position; here, the output position (=3=) is
|
||||
/at/ position =3=, so it overwrites itself. Afterward, the program looks
|
||||
like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
1,9,10,70,
|
||||
2,3,11,0,
|
||||
99,
|
||||
30,40,50
|
||||
#+END_EXAMPLE
|
||||
|
||||
Step forward =4= positions to reach the next opcode, =2=. This opcode
|
||||
works just like the previous, but it multiplies instead of adding. The
|
||||
inputs are at positions =3= and =11=; these positions contain =70= and
|
||||
=50= respectively. Multiplying these produces =3500=; this is stored at
|
||||
position =0=:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3500,9,10,70,
|
||||
2,3,11,0,
|
||||
99,
|
||||
30,40,50
|
||||
#+END_EXAMPLE
|
||||
|
||||
Stepping forward =4= more positions arrives at opcode =99=, halting the
|
||||
program.
|
||||
|
||||
Here are the initial and final states of a few more small programs:
|
||||
|
||||
- =1,0,0,0,99= becomes =2,0,0,0,99= (=1 + 1 = 2=).
|
||||
- =2,3,0,3,99= becomes =2,3,0,6,99= (=3 * 2 = 6=).
|
||||
- =2,4,4,5,99,0= becomes =2,4,4,5,99,9801= (=99 * 99 = 9801=).
|
||||
- =1,1,1,4,99,5,6,0,99= becomes =30,1,1,4,2,5,6,0,99=.
|
||||
|
||||
Once you have a working computer, the first step is to restore the
|
||||
gravity assist program (your puzzle input) to the "1202 program alarm"
|
||||
state it had just before the last computer caught fire. To do this,
|
||||
/before running the program/, replace position =1= with the value =12=
|
||||
and replace position =2= with the value =2=. /What value is left at
|
||||
position =0=/ after the program halts?
|
||||
|
||||
Your puzzle answer was =3790689=.
|
||||
|
||||
** --- Part Two ---
|
||||
"Good, the new computer seems to be working correctly! /Keep it nearby/
|
||||
during this mission - you'll probably use it again. Real Intcode
|
||||
computers support many more features than your new one, but we'll let
|
||||
you know what they are as you need them."
|
||||
|
||||
"However, your current priority should be to complete your gravity
|
||||
assist around the Moon. For this mission to succeed, we should settle on
|
||||
some terminology for the parts you've already built."
|
||||
|
||||
Intcode programs are given as a list of integers; these values are used
|
||||
as the initial state for the computer's /memory/. When you run an
|
||||
Intcode program, make sure to start by initializing memory to the
|
||||
program's values. A position in memory is called an /address/ (for
|
||||
example, the first value in memory is at "address 0").
|
||||
|
||||
Opcodes (like =1=, =2=, or =99=) mark the beginning of an /instruction/.
|
||||
The values used immediately after an opcode, if any, are called the
|
||||
instruction's /parameters/. For example, in the instruction =1,2,3,4=,
|
||||
=1= is the opcode; =2=, =3=, and =4= are the parameters. The instruction
|
||||
=99= contains only an opcode and has no parameters.
|
||||
|
||||
The address of the current instruction is called the /instruction
|
||||
pointer/; it starts at =0=. After an instruction finishes, the
|
||||
instruction pointer increases by /the number of values in the
|
||||
instruction/; until you add more instructions to the computer, this is
|
||||
always =4= (=1= opcode + =3= parameters) for the add and multiply
|
||||
instructions. (The halt instruction would increase the instruction
|
||||
pointer by =1=, but it halts the program instead.)
|
||||
|
||||
"With terminology out of the way, we're ready to proceed. To complete
|
||||
the gravity assist, you need to /determine what pair of inputs produces
|
||||
the output =19690720=/."
|
||||
|
||||
The inputs should still be provided to the program by replacing the
|
||||
values at addresses =1= and =2=, just like before. In this program, the
|
||||
value placed in address =1= is called the /noun/, and the value placed
|
||||
in address =2= is called the /verb/. Each of the two input values will
|
||||
be between =0= and =99=, inclusive.
|
||||
|
||||
Once the program has halted, its output is available at address =0=,
|
||||
also just like before. Each time you try a pair of inputs, make sure you
|
||||
first /reset the computer's memory to the values in the program/ (your
|
||||
puzzle input) - in other words, don't reuse memory from a previous
|
||||
attempt.
|
||||
|
||||
Find the input /noun/ and /verb/ that cause the program to produce the
|
||||
output =19690720=. /What is =100 * noun + verb=?/ (For example, if
|
||||
=noun=12= and =verb=2=, the answer would be =1202=.)
|
||||
|
||||
Your puzzle answer was =6533=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
150
2019/day02/aoc-c.c
Normal file
150
2019/day02/aoc-c.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 2 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 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>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
typedef enum {
|
||||
ADD = 1,
|
||||
MUL = 2,
|
||||
RET = 99
|
||||
} opcode_t;
|
||||
|
||||
#define MAXOPS 1024
|
||||
struct program {
|
||||
int length; /* total program length */
|
||||
int cur; /* current position */
|
||||
int ops[MAXOPS]; /* should really be dynamic */
|
||||
};
|
||||
|
||||
#define OP(p) ((p)->ops + (p)->cur)
|
||||
|
||||
#define A1(p) ((p)->ops + *((p)->ops + (p)->cur + 1))
|
||||
#define A2(p) ((p)->ops + *((p)->ops + (p)->cur + 2))
|
||||
#define A3(p) ((p)->ops + *((p)->ops + (p)->cur + 3))
|
||||
|
||||
static int run(struct program *prog)
|
||||
{
|
||||
while (1) {
|
||||
opcode_t opcode = *OP(prog);
|
||||
switch (opcode) {
|
||||
case ADD:
|
||||
*A3(prog) = *A1(prog) + *A2(prog);
|
||||
break;
|
||||
case MUL:
|
||||
*A3(prog) = *A1(prog) * *A2(prog);
|
||||
break;
|
||||
case RET:
|
||||
return prog->ops[0];
|
||||
default:
|
||||
fprintf(stderr, "wrong opcode %d at %d.\n", opcode, prog->cur);
|
||||
exit (1);
|
||||
}
|
||||
prog->cur += 4;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct program *parse()
|
||||
{
|
||||
size_t alloc = 0;
|
||||
ssize_t buflen;
|
||||
char *buf = NULL, *token;
|
||||
int input;
|
||||
struct program *prog = NULL;
|
||||
|
||||
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
|
||||
fprintf(stderr, "error reading file.\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(prog = calloc(1, sizeof(struct program)))) {
|
||||
fprintf(stderr, "cannot allocate program.\n");
|
||||
goto freebuf;
|
||||
}
|
||||
for (token = strtok(buf, ","); token; token = strtok(NULL, ",")) {
|
||||
if (prog->length >= MAXOPS - 1) {
|
||||
fprintf(stderr, "overflow !\n");
|
||||
free(prog);
|
||||
prog = NULL;
|
||||
goto freebuf;
|
||||
}
|
||||
input=atoi(token);
|
||||
prog->ops[prog->length++] = input;
|
||||
}
|
||||
freebuf:
|
||||
free(buf);
|
||||
end:
|
||||
return prog;
|
||||
}
|
||||
|
||||
static int part1(struct program *p)
|
||||
{
|
||||
p->ops[1] = 12;
|
||||
p->ops[2] = 2;
|
||||
|
||||
return run(p);
|
||||
}
|
||||
|
||||
static int part2(struct program *p)
|
||||
{
|
||||
struct program work;
|
||||
|
||||
for (int noun = 0; noun < 100; ++noun) {
|
||||
for (int verb = 0; verb < 100; ++verb) {
|
||||
work = *p;
|
||||
work.ops[1] = noun;
|
||||
work.ops[2] = verb;
|
||||
if (run(&work) == 19690720)
|
||||
return noun * 100 + verb;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 program *p;
|
||||
|
||||
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);
|
||||
p = parse();
|
||||
printf("%s : res=%d\n", *av, part == 1? part1(p): part2(p));
|
||||
free(p);
|
||||
exit (0);
|
||||
}
|
2
2019/day03/EXAMPLE.txt
Normal file
2
2019/day03/EXAMPLE.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
R8,U5,L5,D3
|
||||
U7,R6,D4,L4
|
2
2019/day03/EXAMPLE2.txt
Normal file
2
2019/day03/EXAMPLE2.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
R75,D30,R83,U83,L12,D49,R71,U7,L72
|
||||
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
|
2
2019/day03/INPUT.txt
Normal file
2
2019/day03/INPUT.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
R1000,D722,L887,D371,R430,D952,R168,D541,L972,D594,R377,U890,R544,U505,L629,U839,L680,D863,L315,D10,L482,U874,L291,U100,R770,D717,L749,U776,L869,D155,R250,U672,L195,D991,L556,D925,R358,U296,R647,D652,L790,D780,L865,U405,L400,D160,L460,U50,R515,D666,R306,U746,R754,U854,L332,U254,R673,U795,R560,U69,L507,U332,L328,U547,L717,U291,R626,U868,L583,D256,R371,U462,R793,U559,L571,U270,R738,U425,L231,U549,L465,U21,L647,U43,R847,U104,L699,U378,L549,D975,R13,D306,R532,D730,L566,U846,L903,D224,R448,D424,L727,D199,L626,D872,L541,D786,L304,U462,R347,U379,R29,D556,L775,D768,L284,D480,R654,D659,R818,D57,L77,U140,R619,D148,R686,D461,L910,U244,R115,D769,R968,U802,L737,U868,R399,D150,L791,U579,L856,D11,R115,U522,L443,D575,L133,U750,R437,U718,L79,D119,L97,U471,R817,U438,R157,U105,L219,U777,L965,U687,L906,D744,L983,D350,R664,D917,R431,D721,L153,U757,L665,U526,L49,U166,L59,D293,R962,D764,R538,U519,L24,U91,R11,U574,L647,U891,R44,D897,L715,U498,L624,D573,R287,U762,L613,D79,R122,U148,L849,D385,R792,D20,L512,D431,R818,U428,L10,D800,R773,D936,L594,D38,R824,D216,L220,U358,L463,U550,R968,D346,L658,U113,R813,U411,L730,D84,R479,U877,L730,D961,L839,D792,R424,U321,L105,D862,L815,D243,L521,D913,L1,D513,L269,U495,L27,U16,R904,D926,R640,U948,R346,D240,L273,U131,L296,U556,R347,D640,L261,D43,R136,U824,R126,U583,R736,U530,L734,U717,L256,U362,L86,U48,R851,U519,L610,D134,L554,D766,L179,U637,R71,D895,L21,D908,R486,D863,R31,U85,R420,D718,R466,D861,R655,D304,L701,D403,L860,D208,L595,U64,R999
|
||||
L992,D463,R10,D791,R312,D146,R865,D244,L364,D189,R35,U328,R857,D683,L660,D707,L908,D277,R356,U369,R197,D35,R625,D862,L769,U705,L728,U999,R938,U233,L595,U266,L697,U966,L536,D543,L669,D829,R910,U693,R753,D389,L647,U603,L660,D787,L138,D119,L131,D266,R268,D917,R776,U290,R920,U904,L46,D139,L341,D19,R982,U790,L981,U791,L147,U30,L246,U677,R343,D492,R398,D234,R76,D423,L709,D392,R741,U408,R878,U29,R446,U36,R806,U78,L76,D813,R584,U682,L187,U666,L340,D301,L694,U15,R800,U276,L755,U558,R366,D309,R571,U976,L286,D833,R318,U365,L864,U408,L352,D61,R284,D272,R240,D845,L206,U721,R367,D541,R628,U581,L750,D680,R695,D30,R849,U743,L214,U605,R533,U493,R803,D783,R168,U877,L61,D726,L794,D116,R717,U44,R964,U674,L291,D372,L381,D523,L644,U438,R983,D390,R520,D471,R556,D693,L919,D863,R84,D629,L264,D429,R82,U64,R835,D801,R93,U770,R441,D152,L718,D788,L797,U699,L82,U206,L40,U952,R902,U570,L759,D655,L131,D901,L470,D804,L407,U458,L922,D21,L171,U841,L237,D301,R192,D293,R984,U243,R846,U139,L413,U162,R925,D235,L115,U443,L884,D910,R335,U274,L338,U160,R125,D775,R824,D821,R531,D761,L189,U822,L602,D732,R473,U149,L128,U30,R77,D957,R811,D154,L988,D237,R425,D855,R482,D571,R134,D731,L905,U869,R916,D689,L17,U24,R353,D996,R832,U855,L76,U659,R581,D483,R821,D145,R199,D344,R487,D436,L92,U491,R365,D909,L17,D148,R307,U57,R666,U660,R195,D767,R612,D902,L594,D299,R670,D881,L583,D793,R58,U89,L99,D355,R394,D350,R920,U544,R887,U564,L238,U979,L565,D914,L95,U150,R292,U495,R506,U475,R813,D308,L797,D484,R9
|
93
2019/day03/Makefile
Normal file
93
2019/day03/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
119
2019/day03/README.org
Normal file
119
2019/day03/README.org
Normal file
@@ -0,0 +1,119 @@
|
||||
** --- Day 3: Crossed Wires ---
|
||||
The gravity assist was successful, and you're well on your way to the
|
||||
Venus refuelling station. During the rush back on Earth, the fuel
|
||||
management system wasn't completely installed, so that's next on the
|
||||
priority list.
|
||||
|
||||
Opening the front panel reveals a jumble of wires. Specifically, /two
|
||||
wires/ are connected to a central port and extend outward on a grid. You
|
||||
trace the path each wire takes as it leaves the central port, one wire
|
||||
per line of text (your puzzle input).
|
||||
|
||||
The wires twist and turn, but the two wires occasionally cross paths. To
|
||||
fix the circuit, you need to /find the intersection point closest to the
|
||||
central port/. Because the wires are on a grid, use the
|
||||
[[https://en.wikipedia.org/wiki/Taxicab_geometry][Manhattan distance]]
|
||||
for this measurement. While the wires do technically cross right at the
|
||||
central port where they both start, this point does not count, nor does
|
||||
a wire count as crossing with itself.
|
||||
|
||||
For example, if the first wire's path is =R8,U5,L5,D3=, then starting
|
||||
from the central port (=o=), it goes right =8=, up =5=, left =5=, and
|
||||
finally down =3=:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
...........
|
||||
...........
|
||||
...........
|
||||
....+----+.
|
||||
....|....|.
|
||||
....|....|.
|
||||
....|....|.
|
||||
.........|.
|
||||
.o-------+.
|
||||
...........
|
||||
#+END_EXAMPLE
|
||||
|
||||
Then, if the second wire's path is =U7,R6,D4,L4=, it goes up =7=, right
|
||||
=6=, down =4=, and left =4=:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
...........
|
||||
.+-----+...
|
||||
.|.....|...
|
||||
.|..+--X-+.
|
||||
.|..|..|.|.
|
||||
.|.-X--+.|.
|
||||
.|..|....|.
|
||||
.|.......|.
|
||||
.o-------+.
|
||||
...........
|
||||
#+END_EXAMPLE
|
||||
|
||||
These wires cross at two locations (marked =X=), but the lower-left one
|
||||
is closer to the central port: its distance is =3 + 3 = 6=.
|
||||
|
||||
Here are a few more examples:
|
||||
|
||||
- =R75,D30,R83,U83,L12,D49,R71,U7,L72= \\
|
||||
=U62,R66,U55,R34,D71,R55,D58,R83=
|
||||
= distance =159=
|
||||
- =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51= \\
|
||||
=U98,R91,D20,R16,D67,R40,U7,R15,U6,R7=
|
||||
= distance =135=
|
||||
|
||||
/What is the Manhattan distance/ from the central port to the closest
|
||||
intersection?
|
||||
|
||||
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,L72= \\
|
||||
=U62,R66,U55,R34,D71,R55,D58,R83=
|
||||
= =610= steps
|
||||
- =R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51= \\
|
||||
=U98,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: **
|
168
2019/day03/aoc-c.c
Normal file
168
2019/day03/aoc-c.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 3 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 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>
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
typedef enum { DOWN = 'D', LEFT = 'L', RIGHT = 'R', UP = 'U' } dir_t;
|
||||
|
||||
struct point {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct wire - one segment on wire.
|
||||
* @dist: total distance from start before the current segment
|
||||
* @dir: indicates which of ends[0] and ends[1] was the original line end point
|
||||
* @ends: segment ends, ordered (ends[0].x <= ends[1].x and ends[0].y <= ends[1].y)
|
||||
* @list: segments list
|
||||
*/
|
||||
struct wire {
|
||||
int dist;
|
||||
int dir;
|
||||
struct point ends[2];
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static pool_t *wire_pool;
|
||||
|
||||
static struct list_head *parse(struct list_head *wires)
|
||||
{
|
||||
size_t alloc = 0;
|
||||
ssize_t buflen;
|
||||
char *buf = NULL, *token;
|
||||
|
||||
for (int line = 0; line < 2; ++line) {
|
||||
struct point p0 = {0, 0}, p1 = {0, 0};
|
||||
int totdist = 0;
|
||||
|
||||
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
|
||||
fprintf(stderr, "error %d reading input.\n", errno);
|
||||
wires = NULL;
|
||||
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;
|
||||
totdist += abs(dist);
|
||||
new->dir = !!(dir == DOWN || dir == LEFT);
|
||||
if (dir == DOWN || dir == UP) /* vertical segment */
|
||||
p1.y = p0.y + (1 - (new->dir * 2)) * dist;
|
||||
else /* horizontal segment */
|
||||
p1.x = p0.x + (1 - (new->dir * 2)) * dist;
|
||||
new->ends[0].x = min(p0.x, p1.x); /* order ends (p0.? <= p1.?) */
|
||||
new->ends[0].y = min(p0.y, p1.y);
|
||||
new->ends[1].x = max(p0.x, p1.x);
|
||||
new->ends[1].y = max(p0.y, p1.y);
|
||||
list_add_tail(&new->list, &wires[line]);
|
||||
p0 = p1;
|
||||
}
|
||||
}
|
||||
end:
|
||||
free(buf);
|
||||
return wires;
|
||||
}
|
||||
|
||||
static struct point *intersect(struct wire *w0, struct wire *w1, struct point *ret)
|
||||
{
|
||||
if (w0->ends[0].x == w0->ends[1].x) { /* w0 vertical */
|
||||
/* BUG: overlapping wires is not handled */
|
||||
if (w0->ends[0].x >= w1->ends[0].x && w0->ends[1].x <= w1->ends[1].x &&
|
||||
w0->ends[0].y <= w1->ends[0].y && w0->ends[1].y >= w1->ends[1].y) {
|
||||
ret->x = w0->ends[0].x;
|
||||
ret->y = w1->ends[0].y;
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
} else { /* w0 horizontal */
|
||||
if (w0->ends[0].x <= w1->ends[0].x && w0->ends[1].x >= w1->ends[1].x &&
|
||||
w0->ends[0].y <= w1->ends[1].y && w0->ends[1].y >= w1->ends[0].y) {
|
||||
ret->x = w1->ends[0].x;
|
||||
ret->y = w0->ends[0].y;
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* part 1 */
|
||||
#define manhattan(point) (abs(point.x) + abs(point.y))
|
||||
/* part 2 */
|
||||
#define signal(point, w0, w1) \
|
||||
(w0->dist + w1->dist + \
|
||||
abs(cross.x - w0->ends[w0->dir].x) + abs(cross.y - w0->ends[w0->dir].y) + \
|
||||
abs(cross.x - w1->ends[w1->dir].x) + abs(cross.y - w1->ends[w1->dir].y))
|
||||
|
||||
static int doit(struct list_head *w, int part)
|
||||
{
|
||||
struct wire *w0, *w1;
|
||||
struct point cross;
|
||||
s32 res = INT32_MAX;
|
||||
|
||||
list_for_each_entry(w0, &w[0], list)
|
||||
list_for_each_entry(w1, &w[1], list)
|
||||
if (intersect(w0, w1, &cross))
|
||||
res = min_not_zero(res, part == 1 ?
|
||||
manhattan(cross) :
|
||||
signal(cross, w0, w1));
|
||||
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 list_head wires[2] = { LIST_HEAD_INIT(wires[0]), LIST_HEAD_INIT(wires[1]) };
|
||||
|
||||
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)
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < ac)
|
||||
return usage(*av);
|
||||
wire_pool = pool_create("wire", 256, sizeof(struct wire));
|
||||
|
||||
if (parse(wires)) {
|
||||
printf("%s : res=%d\n", *av, doit(wires, part));
|
||||
pool_destroy(wire_pool);
|
||||
}
|
||||
exit (0);
|
||||
}
|
1
2019/day04/INPUT.txt
Normal file
1
2019/day04/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
||||
130254-678275
|
93
2019/day04/Makefile
Normal file
93
2019/day04/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
43
2019/day04/README.org
Normal file
43
2019/day04/README.org
Normal file
@@ -0,0 +1,43 @@
|
||||
** --- Day 4: Secure Container ---
|
||||
You arrive at the Venus fuel depot only to discover it's protected by a
|
||||
password. The Elves had written the password on a sticky note, but
|
||||
someone threw it out.
|
||||
|
||||
However, they do remember a few key facts about the password:
|
||||
|
||||
- It is a six-digit number.
|
||||
- The value is within the range given in your puzzle input.
|
||||
- Two adjacent digits are the same (like =22= in =122345=).
|
||||
- Going from left to right, the digits /never decrease/; they only ever
|
||||
increase or stay the same (like =111123= or =135679=).
|
||||
|
||||
Other than the range rule, the following are true:
|
||||
|
||||
- =111111= meets these criteria (double =11=, never decreases).
|
||||
- =223450= does not meet these criteria (decreasing pair of digits
|
||||
=50=).
|
||||
- =123789= does not meet these criteria (no double).
|
||||
|
||||
/How many different passwords/ within the range given in your puzzle
|
||||
input meet these criteria?
|
||||
|
||||
Your puzzle answer was =2090=.
|
||||
|
||||
** --- Part Two ---
|
||||
An Elf just remembered one more important detail: the two adjacent
|
||||
matching digits /are not part of a larger group of matching digits/.
|
||||
|
||||
Given this additional criterion, but still ignoring the range rule, the
|
||||
following are now true:
|
||||
|
||||
- =112233= meets these criteria because the digits never decrease and
|
||||
all repeated digits are exactly two digits long.
|
||||
- =123444= no longer meets the criteria (the repeated =44= is part of a
|
||||
larger group of =444=).
|
||||
- =111122= meets the criteria (even though =1= is repeated more than
|
||||
twice, it still contains a double =22=).
|
||||
|
||||
/How many different passwords/ within the range given in your puzzle
|
||||
input meet all of the criteria?
|
||||
|
||||
Your puzzle answer was =1419=.
|
126
2019/day04/aoc-c.c
Normal file
126
2019/day04/aoc-c.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 4 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 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>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "likely.h"
|
||||
|
||||
/**
|
||||
* next_number() - finds next suitable number after a faulty right digit
|
||||
* @number: the number
|
||||
* @faulty: the faulty digit position (1, 10, 100, etc...)
|
||||
* @left: the left digit of faulty one
|
||||
*
|
||||
* This function is called when rule 4 is violated:
|
||||
* "Going from left to right, the digits never decrease."
|
||||
* Example: 453456
|
||||
* ^
|
||||
* Here we will replace the faulty digit and next ones with its left digit
|
||||
* value (5 here). Returned number will be 455555.
|
||||
* This function allowed to save 546,495/548,022 calls to is_valid(), which
|
||||
* is 99.7%.
|
||||
*/
|
||||
static int next_number(int number, int faulty, int left)
|
||||
{
|
||||
int next = number - number % (faulty * 10);
|
||||
|
||||
for (; faulty; faulty /= 10)
|
||||
next += left * faulty;
|
||||
return next;
|
||||
}
|
||||
|
||||
static int is_valid(int number, int part, int *next)
|
||||
{
|
||||
int valid = 0, dups[10] = { 0 }, work = number;
|
||||
int digit, dec = number + 1, faulty = 1;
|
||||
*next = number + 1;
|
||||
|
||||
for (digit = number % 10; number > 10; digit = dec, faulty *= 10) {
|
||||
number /= 10;
|
||||
dec = number % 10;
|
||||
if (dec > digit) {
|
||||
*next = next_number(work, faulty, dec);
|
||||
return 0;
|
||||
}
|
||||
if (dec == digit) {
|
||||
valid = 1;
|
||||
dups[digit] += 2;
|
||||
}
|
||||
}
|
||||
if (!valid || part == 1)
|
||||
return valid;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
if (dups[i] == 2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int doit(int *nums, int part)
|
||||
{
|
||||
int res = 0, next = 0;
|
||||
|
||||
for (int i = nums[0]; i < nums[1]; i = next) {
|
||||
if (unlikely(is_valid(i, part, &next)))
|
||||
res++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int *parse(int *res)
|
||||
{
|
||||
size_t alloc = 0;
|
||||
char *buf = NULL;
|
||||
|
||||
getline(&buf, &alloc, stdin);
|
||||
*res = atoi(strtok(buf, "-"));
|
||||
*(res+1) = atoi(strtok(NULL, "-"));
|
||||
free(buf);
|
||||
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;
|
||||
int nums[2];
|
||||
|
||||
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)
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
if (optind < ac)
|
||||
return usage(*av);
|
||||
|
||||
parse(nums);
|
||||
printf("%s : res=%d\n", *av, doit(nums, part));
|
||||
|
||||
exit (0);
|
||||
}
|
1
2019/day05/EXAMPLE.txt
Normal file
1
2019/day05/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,0,4,0,99
|
1
2019/day05/EXAMPLE1.txt
Normal file
1
2019/day05/EXAMPLE1.txt
Normal file
@@ -0,0 +1 @@
|
||||
1002,4,3,4,33
|
1
2019/day05/EXAMPLE2.txt
Normal file
1
2019/day05/EXAMPLE2.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,9,8,9,10,9,4,9,99,-1,8
|
1
2019/day05/EXAMPLE3.txt
Normal file
1
2019/day05/EXAMPLE3.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,9,7,9,10,9,4,9,99,-1,8
|
1
2019/day05/EXAMPLE4.txt
Normal file
1
2019/day05/EXAMPLE4.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,3,1108,-1,8,3,4,3,99
|
1
2019/day05/EXAMPLE5.txt
Normal file
1
2019/day05/EXAMPLE5.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,3,1107,-1,8,3,4,3,99
|
1
2019/day05/EXAMPLE6.txt
Normal file
1
2019/day05/EXAMPLE6.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9
|
1
2019/day05/EXAMPLE7.txt
Normal file
1
2019/day05/EXAMPLE7.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,3,1105,-1,9,1101,0,0,12,4,12,99,1
|
1
2019/day05/EXAMPLE8.txt
Normal file
1
2019/day05/EXAMPLE8.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99
|
1
2019/day05/INPUT.txt
Normal file
1
2019/day05/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,225,1,225,6,6,1100,1,238,225,104,0,1101,86,8,225,1101,82,69,225,101,36,65,224,1001,224,-106,224,4,224,1002,223,8,223,1001,224,5,224,1,223,224,223,102,52,148,224,101,-1144,224,224,4,224,1002,223,8,223,101,1,224,224,1,224,223,223,1102,70,45,225,1002,143,48,224,1001,224,-1344,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1101,69,75,225,1001,18,85,224,1001,224,-154,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,1101,15,59,225,1102,67,42,224,101,-2814,224,224,4,224,1002,223,8,223,101,3,224,224,1,223,224,223,1101,28,63,225,1101,45,22,225,1101,90,16,225,2,152,92,224,1001,224,-1200,224,4,224,102,8,223,223,101,7,224,224,1,223,224,223,1101,45,28,224,1001,224,-73,224,4,224,1002,223,8,223,101,7,224,224,1,224,223,223,1,14,118,224,101,-67,224,224,4,224,1002,223,8,223,1001,224,2,224,1,223,224,223,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,7,677,677,224,102,2,223,223,1005,224,329,1001,223,1,223,1008,226,226,224,1002,223,2,223,1005,224,344,1001,223,1,223,1107,677,226,224,1002,223,2,223,1006,224,359,1001,223,1,223,107,677,677,224,102,2,223,223,1005,224,374,101,1,223,223,1108,677,226,224,102,2,223,223,1005,224,389,1001,223,1,223,1007,677,677,224,1002,223,2,223,1005,224,404,101,1,223,223,1008,677,226,224,102,2,223,223,1005,224,419,101,1,223,223,1108,226,677,224,102,2,223,223,1006,224,434,1001,223,1,223,8,677,226,224,1002,223,2,223,1005,224,449,101,1,223,223,1008,677,677,224,1002,223,2,223,1006,224,464,1001,223,1,223,1108,226,226,224,1002,223,2,223,1005,224,479,1001,223,1,223,1007,226,677,224,102,2,223,223,1005,224,494,1001,223,1,223,1007,226,226,224,102,2,223,223,1005,224,509,101,1,223,223,107,677,226,224,1002,223,2,223,1006,224,524,1001,223,1,223,108,677,677,224,102,2,223,223,1006,224,539,101,1,223,223,7,677,226,224,102,2,223,223,1006,224,554,1001,223,1,223,1107,226,677,224,102,2,223,223,1005,224,569,101,1,223,223,108,677,226,224,1002,223,2,223,1006,224,584,101,1,223,223,108,226,226,224,102,2,223,223,1006,224,599,1001,223,1,223,1107,226,226,224,102,2,223,223,1006,224,614,1001,223,1,223,8,226,677,224,102,2,223,223,1006,224,629,1001,223,1,223,107,226,226,224,102,2,223,223,1005,224,644,101,1,223,223,8,226,226,224,102,2,223,223,1006,224,659,101,1,223,223,7,226,677,224,102,2,223,223,1005,224,674,101,1,223,223,4,223,99,226
|
93
2019/day05/Makefile
Normal file
93
2019/day05/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
184
2019/day05/README.org
Normal file
184
2019/day05/README.org
Normal file
@@ -0,0 +1,184 @@
|
||||
** --- Day 5: Sunny with a Chance of Asteroids ---
|
||||
You're starting to sweat as the ship makes its way toward Mercury. The
|
||||
Elves suggest that you get the air conditioner working by upgrading your
|
||||
ship computer to support the Thermal Environment Supervision Terminal.
|
||||
|
||||
The Thermal Environment Supervision Terminal (TEST) starts by running a
|
||||
/diagnostic program/ (your puzzle input). The TEST diagnostic program
|
||||
will run on [[file:~/dev/advent-of-code/2019/day02][your existing Intcode computer]] after a few
|
||||
modifications:
|
||||
|
||||
/First/, you'll need to add /two new instructions/:
|
||||
|
||||
- Opcode =3= takes a single integer as /input/ and saves it to the
|
||||
position given by its only parameter. For example, the instruction
|
||||
=3,50= would take an input value and store it at address =50=.
|
||||
- Opcode =4= /outputs/ the value of its only parameter. For example, the
|
||||
instruction =4,50= would output the value at address =50=.
|
||||
|
||||
Programs that use these instructions will come with documentation that
|
||||
explains what should be connected to the input and output. The program
|
||||
=3,0,4,0,99= outputs whatever it gets as input, then halts.
|
||||
|
||||
/Second/, you'll need to add support for /parameter modes/:
|
||||
|
||||
Each parameter of an instruction is handled based on its parameter mode.
|
||||
Right now, your ship computer already understands parameter mode =0=,
|
||||
/position mode/, which causes the parameter to be interpreted as a
|
||||
/position/ - if the parameter is =50=, its value is /the value stored at
|
||||
address =50= in memory/. Until now, all parameters have been in position
|
||||
mode.
|
||||
|
||||
Now, your ship computer will also need to handle parameters in mode =1=,
|
||||
/immediate mode/. In immediate mode, a parameter is interpreted as a
|
||||
/value/ - if the parameter is =50=, its value is simply /=50=/.
|
||||
|
||||
Parameter modes are stored in the same value as the instruction's
|
||||
opcode. The opcode is a two-digit number based only on the ones and tens
|
||||
digit of the value, that is, the opcode is the rightmost two digits of
|
||||
the first value in an instruction. Parameter modes are single digits,
|
||||
one per parameter, read right-to-left from the opcode: the first
|
||||
parameter's mode is in the hundreds digit, the second parameter's mode
|
||||
is in the thousands digit, the third parameter's mode is in the
|
||||
ten-thousands digit, and so on. Any missing modes are =0=.
|
||||
|
||||
For example, consider the program =1002,4,3,4,33=.
|
||||
|
||||
The first instruction, =1002,4,3,4=, is a /multiply/ instruction - the
|
||||
rightmost two digits of the first value, =02=, indicate opcode =2=,
|
||||
multiplication. Then, going right to left, the parameter modes are =0=
|
||||
(hundreds digit), =1= (thousands digit), and =0= (ten-thousands digit,
|
||||
not present and therefore zero):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
ABCDE
|
||||
1002
|
||||
|
||||
DE - two-digit opcode, 02 == opcode 2
|
||||
C - mode of 1st parameter, 0 == position mode
|
||||
B - mode of 2nd parameter, 1 == immediate mode
|
||||
A - mode of 3rd parameter, 0 == position mode,
|
||||
omitted due to being a leading zero
|
||||
#+END_EXAMPLE
|
||||
|
||||
This instruction multiplies its first two parameters. The first
|
||||
parameter, =4= in position mode, works like it did before - its value is
|
||||
the value stored at address =4= (=33=). The second parameter, =3= in
|
||||
immediate mode, simply has value =3=. The result of this operation,
|
||||
=33 * 3 = 99=, is written according to the third parameter, =4= in
|
||||
position mode, which also works like it did before - =99= is written to
|
||||
address =4=.
|
||||
|
||||
Parameters that an instruction writes to will /never be in immediate
|
||||
mode/.
|
||||
|
||||
/Finally/, some notes:
|
||||
|
||||
- It is important to remember that the instruction pointer should
|
||||
increase by /the number of values in the instruction/ after the
|
||||
instruction finishes. Because of the new instructions, this amount is
|
||||
no longer always =4=.
|
||||
- Integers can be negative: =1101,100,-1,4,0= is a valid program (find
|
||||
=100 + -1=, store the result in position =4=).
|
||||
|
||||
The TEST diagnostic program will start by requesting from the user the
|
||||
ID of the system to test by running an /input/ instruction - provide it
|
||||
=1=, the ID for the ship's air conditioner unit.
|
||||
|
||||
It will then perform a series of diagnostic tests confirming that
|
||||
various parts of the Intcode computer, like parameter modes, function
|
||||
correctly. For each test, it will run an /output/ instruction indicating
|
||||
how far the result of the test was from the expected value, where =0=
|
||||
means the test was successful. Non-zero outputs mean that a function is
|
||||
not working correctly; check the instructions that were run before the
|
||||
output instruction to see which one failed.
|
||||
|
||||
Finally, the program will output a /diagnostic code/ and immediately
|
||||
halt. This final output isn't an error; an output followed immediately
|
||||
by a halt means the program finished. If all outputs were zero except
|
||||
the diagnostic code, the diagnostic program ran successfully.
|
||||
|
||||
After providing =1= to the only input instruction and passing all the
|
||||
tests, /what diagnostic code does the program produce?/
|
||||
|
||||
Your puzzle answer was =10987514=.
|
||||
|
||||
** --- Part Two ---
|
||||
The air conditioner comes online! Its cold air feels good for a while,
|
||||
but then the TEST alarms start to go off. Since the air conditioner
|
||||
can't vent its heat anywhere but back into the spacecraft, it's actually
|
||||
making the air inside the ship /warmer/.
|
||||
|
||||
Instead, you'll need to use the TEST to extend the
|
||||
[[https://en.wikipedia.org/wiki/Spacecraft_thermal_control][thermal
|
||||
radiators]]. Fortunately, the diagnostic program (your puzzle input) is
|
||||
already equipped for this. Unfortunately, your Intcode computer is not.
|
||||
|
||||
Your computer is only missing a few opcodes:
|
||||
|
||||
- Opcode =5= is /jump-if-true/: if the first parameter is /non-zero/, it
|
||||
sets the instruction pointer to the value from the second parameter.
|
||||
Otherwise, it does nothing.
|
||||
- Opcode =6= is /jump-if-false/: if the first parameter /is zero/, it
|
||||
sets the instruction pointer to the value from the second parameter.
|
||||
Otherwise, it does nothing.
|
||||
- Opcode =7= is /less than/: if the first parameter is /less than/ the
|
||||
second parameter, it stores =1= in the position given by the third
|
||||
parameter. Otherwise, it stores =0=.
|
||||
- Opcode =8= is /equals/: if the first parameter is /equal to/ the
|
||||
second parameter, it stores =1= in the position given by the third
|
||||
parameter. Otherwise, it stores =0=.
|
||||
|
||||
Like all instructions, these instructions need to support /parameter
|
||||
modes/ as described above.
|
||||
|
||||
Normally, after an instruction is finished, the instruction pointer
|
||||
increases by the number of values in that instruction. /However/, if the
|
||||
instruction modifies the instruction pointer, that value is used and the
|
||||
instruction pointer is /not automatically increased/.
|
||||
|
||||
For example, here are several programs that take one input, compare it
|
||||
to the value =8=, and then produce one output:
|
||||
|
||||
- =3,9,8,9,10,9,4,9,99,-1,8= - Using /position mode/, consider whether
|
||||
the input is /equal to/ =8=; output =1= (if it is) or =0= (if it is
|
||||
not).
|
||||
- =3,9,7,9,10,9,4,9,99,-1,8= - Using /position mode/, consider whether
|
||||
the input is /less than/ =8=; output =1= (if it is) or =0= (if it is
|
||||
not).
|
||||
- =3,3,1108,-1,8,3,4,3,99= - Using /immediate mode/, consider whether
|
||||
the input is /equal to/ =8=; output =1= (if it is) or =0= (if it is
|
||||
not).
|
||||
- =3,3,1107,-1,8,3,4,3,99= - Using /immediate mode/, consider whether
|
||||
the input is /less than/ =8=; output =1= (if it is) or =0= (if it is
|
||||
not).
|
||||
|
||||
Here are some jump tests that take an input, then output =0= if the
|
||||
input was zero or =1= if the input was non-zero:
|
||||
|
||||
- =3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9= (using /position mode/)
|
||||
- =3,3,1105,-1,9,1101,0,0,12,4,12,99,1= (using /immediate mode/)
|
||||
|
||||
Here's a larger example:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,
|
||||
1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,
|
||||
999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99
|
||||
#+END_EXAMPLE
|
||||
|
||||
The above example program uses an input instruction to ask for a single
|
||||
number. The program will then output =999= if the input value is below
|
||||
=8=, output =1000= if the input value is equal to =8=, or output =1001=
|
||||
if the input value is greater than =8=.
|
||||
|
||||
This time, when the TEST diagnostic program runs its input instruction
|
||||
to get the ID of the system to test, /provide it =5=/, the ID for the
|
||||
ship's thermal radiator controller. This diagnostic test suite only
|
||||
outputs one number, the /diagnostic code/.
|
||||
|
||||
/What is the diagnostic code for system ID =5=?/
|
||||
|
||||
Your puzzle answer was =14195011=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
162
2019/day05/aoc-c.c
Normal file
162
2019/day05/aoc-c.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 5 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 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>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
|
||||
typedef enum {
|
||||
ADD = 1, MUL = 2,
|
||||
INP = 3, OUT = 4,
|
||||
JMP_T = 5, JMP_F = 6,
|
||||
SET_LT = 7, SET_EQ = 8,
|
||||
HLT = 99
|
||||
} opcode_t;
|
||||
|
||||
/**
|
||||
* ops - array of op-codes, mnemo, and number of parameters
|
||||
* @op: An integer, the opcode
|
||||
* @nargs: Opcode number of parameters (unused)
|
||||
* @jump: Next instruction (usually @nargs + 1)
|
||||
* @mnemo: Opcode mnemo (unused, for debug)
|
||||
*/
|
||||
typedef struct {
|
||||
int op;
|
||||
u8 nargs;
|
||||
u8 jump;
|
||||
char *mnemo;
|
||||
} ops_t;
|
||||
|
||||
#define MAXOPS 1024
|
||||
typedef struct {
|
||||
int length; /* total program length */
|
||||
int cur; /* current position */
|
||||
int mem [MAXOPS]; /* should really be dynamic */
|
||||
} program_t;
|
||||
|
||||
static ops_t ops[] = {
|
||||
[ADD] = { ADD, 3, 4, __stringify(ADD) },
|
||||
[MUL] = { MUL, 3, 4, __stringify(MUL) },
|
||||
[INP] = { INP, 1, 2, __stringify(INP) },
|
||||
[OUT] = { OUT, 1, 2, __stringify(OUT) },
|
||||
[JMP_T] = { JMP_T, 2, 3, __stringify(JMP_T) },
|
||||
[JMP_F] = { JMP_F, 2, 3, __stringify(JMP_F) },
|
||||
[SET_LT] = { SET_LT, 3, 4, __stringify({SET_LT) },
|
||||
[SET_EQ] = { SET_EQ, 3, 4, __stringify(SET_EQ) },
|
||||
[HLT] = { HLT, 0, 1, __stringify(HLT) }
|
||||
};
|
||||
|
||||
|
||||
static int _flag_pow10[] = {1, 100, 1000, 10000};
|
||||
#define OP(p, n) ((p->mem[n]) % 100)
|
||||
#define ISDIRECT(p, n, i) ((((p->mem[n]) / _flag_pow10[i]) % 10))
|
||||
#define DIRECT(p, i) ((p)->mem[i])
|
||||
#define INDIRECT(p, i) (DIRECT(p, DIRECT(p, i)))
|
||||
|
||||
#define peek(p, n, i) (ISDIRECT(p, n, i)? DIRECT(p, n + i): INDIRECT(p, n + i))
|
||||
#define poke(p, n, i, val) do { \
|
||||
INDIRECT(p, n + i) = val; } \
|
||||
while (0)
|
||||
|
||||
static int run(program_t *p, int in)
|
||||
{
|
||||
int out = -1;
|
||||
while (1) {
|
||||
int op = OP(p, p->cur), cur = p->cur;
|
||||
|
||||
if (!(ops[op].op)) {
|
||||
fprintf(stderr, "PANIC: illegal instruction %d at %d.\n", op, p->cur);
|
||||
return -1;
|
||||
}
|
||||
switch (op) {
|
||||
case ADD:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) + peek(p, p->cur, 2));
|
||||
break;
|
||||
case MUL:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) * peek(p, p->cur, 2));
|
||||
break;
|
||||
case INP:
|
||||
poke(p, p->cur, 1, in);
|
||||
break;
|
||||
case OUT:
|
||||
out = peek(p, p->cur, 1);
|
||||
break;
|
||||
case JMP_T:
|
||||
if (peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case JMP_F:
|
||||
if (!peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case SET_LT:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) < peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case SET_EQ:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) == peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case HLT:
|
||||
return out;
|
||||
}
|
||||
if (p->cur == cur)
|
||||
p->cur += ops[op].jump;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse(program_t *prog)
|
||||
{
|
||||
while (scanf("%d%*c", &prog->mem[prog->length++]) > 0)
|
||||
;
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int opt, part = 1, in = -1;
|
||||
program_t p = { 0 };
|
||||
|
||||
while ((opt = getopt(ac, av, "d:p:i:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_level_set(atoi(optarg));
|
||||
break;
|
||||
case 'i':
|
||||
in = 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);
|
||||
if (in == -1)
|
||||
in = part == 1? 1: 5;
|
||||
parse(&p);
|
||||
printf("%s : res=%d\n", *av, run(&p, in));
|
||||
exit (0);
|
||||
}
|
53
2019/day05/run-examples.sh
Executable file
53
2019/day05/run-examples.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
make compile
|
||||
|
||||
printf "***** EXAMPLE.txt: input value, then output it\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 1 < EXAMPLE.txt
|
||||
printf "Expected: 5\t"
|
||||
./aoc-c -i 5 < EXAMPLE.txt
|
||||
|
||||
printf "\n***** EXAMPLE2.txt: equal test, position mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 8 < EXAMPLE2.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 0 < EXAMPLE.txt
|
||||
|
||||
printf "\n***** EXAMPLE3.txt: less than test, position mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 7 < EXAMPLE3.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 8 < EXAMPLE3.txt
|
||||
|
||||
printf "\n***** EXAMPLE4.txt: equal test, immediate mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 8 < EXAMPLE4.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 0 < EXAMPLE4.txt
|
||||
|
||||
printf "\n***** EXAMPLE5.txt: less than test, immediate mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 7 < EXAMPLE5.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 8 < EXAMPLE5.txt
|
||||
|
||||
printf "\n***** EXAMPLE6.txt: equal/jump test, position mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 8 < EXAMPLE6.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 0 < EXAMPLE6.txt
|
||||
|
||||
printf "\n***** EXAMPLE7.txt: equal/jump test, immediate mode\n"
|
||||
printf "Expected: 1\t"
|
||||
./aoc-c -i 8 < EXAMPLE7.txt
|
||||
printf "Expected: 0\t"
|
||||
./aoc-c -i 0 < EXAMPLE7.txt
|
||||
|
||||
printf "\n***** EXAMPLE8.txt: equal/less/jump test, mixed mode\n"
|
||||
printf "Expected:999\t"
|
||||
./aoc-c -i 7 < EXAMPLE8.txt
|
||||
printf "Expected: 1000\t"
|
||||
./aoc-c -i 8 < EXAMPLE8.txt
|
||||
printf "Expected: 1001\t"
|
||||
./aoc-c -i 9 < EXAMPLE8.txt
|
11
2019/day06/EXAMPLE.txt
Normal file
11
2019/day06/EXAMPLE.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
13
2019/day06/EXAMPLE2.txt
Normal file
13
2019/day06/EXAMPLE2.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
K)YOU
|
||||
I)SAN
|
2306
2019/day06/INPUT.txt
Normal file
2306
2019/day06/INPUT.txt
Normal file
File diff suppressed because it is too large
Load Diff
93
2019/day06/Makefile
Normal file
93
2019/day06/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
147
2019/day06/README.org
Normal file
147
2019/day06/README.org
Normal file
@@ -0,0 +1,147 @@
|
||||
** --- Day 6: Universal Orbit Map ---
|
||||
You've landed at the Universal Orbit Map facility on Mercury. Because
|
||||
navigation in space often involves transferring between orbits, the
|
||||
orbit maps here are useful for finding efficient routes between, for
|
||||
example, you and Santa. You download a map of the local orbits (your
|
||||
puzzle input).
|
||||
|
||||
Except for the universal Center of Mass (=COM=), every object in space
|
||||
is in orbit around exactly one other object. An
|
||||
[[https://en.wikipedia.org/wiki/Orbit][orbit]] looks roughly like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
\
|
||||
\
|
||||
|
|
||||
|
|
||||
AAA--> o o <--BBB
|
||||
|
|
||||
|
|
||||
/
|
||||
/
|
||||
#+END_EXAMPLE
|
||||
|
||||
In this diagram, the object =BBB= is in orbit around =AAA=. The path
|
||||
that =BBB= takes around =AAA= (drawn with lines) is only partly shown.
|
||||
In the map data, this orbital relationship is written =AAA)BBB=, which
|
||||
means "=BBB= is in orbit around =AAA=".
|
||||
|
||||
Before you use your map data to plot a course, you need to make sure it
|
||||
wasn't corrupted during the download. To verify maps, the Universal
|
||||
Orbit Map facility uses /orbit count checksums/ - the total number of
|
||||
/direct orbits/ (like the one shown above) and /indirect orbits/.
|
||||
|
||||
Whenever =A= orbits =B= and =B= orbits =C=, then =A= /indirectly orbits/
|
||||
=C=. This chain can be any number of objects long: if =A= orbits =B=,
|
||||
=B= orbits =C=, and =C= orbits =D=, then =A= indirectly orbits =D=.
|
||||
|
||||
For example, suppose you have the following map:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
#+END_EXAMPLE
|
||||
|
||||
Visually, the above map of orbits looks like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
G - H J - K - L
|
||||
/ /
|
||||
COM - B - C - D - E - F
|
||||
\
|
||||
I
|
||||
#+END_EXAMPLE
|
||||
|
||||
In this visual representation, when two objects are connected by a line,
|
||||
the one on the right directly orbits the one on the left.
|
||||
|
||||
Here, we can count the total number of orbits as follows:
|
||||
|
||||
- =D= directly orbits =C= and indirectly orbits =B= and =COM=, a total
|
||||
of =3= orbits.
|
||||
- =L= directly orbits =K= and indirectly orbits =J=, =E=, =D=, =C=, =B=,
|
||||
and =COM=, a total of =7= orbits.
|
||||
- =COM= orbits nothing.
|
||||
|
||||
The total number of direct and indirect orbits in this example is =42=.
|
||||
|
||||
/What is the total number of direct and indirect orbits/ in your map
|
||||
data?
|
||||
|
||||
Your puzzle answer was =453028=.
|
||||
|
||||
** --- Part Two ---
|
||||
Now, you just need to figure out how many /orbital transfers/ you
|
||||
(=YOU=) need to take to get to Santa (=SAN=).
|
||||
|
||||
You start at the object =YOU= are orbiting; your destination is the
|
||||
object =SAN= is orbiting. An orbital transfer lets you move from any
|
||||
object to an object orbiting or orbited by that object.
|
||||
|
||||
For example, suppose you have the following map:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
COM)B
|
||||
B)C
|
||||
C)D
|
||||
D)E
|
||||
E)F
|
||||
B)G
|
||||
G)H
|
||||
D)I
|
||||
E)J
|
||||
J)K
|
||||
K)L
|
||||
K)YOU
|
||||
I)SAN
|
||||
#+END_EXAMPLE
|
||||
|
||||
Visually, the above map of orbits looks like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
YOU
|
||||
/
|
||||
G - H J - K - L
|
||||
/ /
|
||||
COM - B - C - D - E - F
|
||||
\
|
||||
I - SAN
|
||||
#+END_EXAMPLE
|
||||
|
||||
In this example, =YOU= are in orbit around =K=, and =SAN= is in orbit
|
||||
around =I=. To move from =K= to =I=, a minimum of =4= orbital transfers
|
||||
are required:
|
||||
|
||||
- =K= to =J=
|
||||
- =J= to =E=
|
||||
- =E= to =D=
|
||||
- =D= to =I=
|
||||
|
||||
Afterward, the map of orbits looks like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
G - H J - K - L
|
||||
/ /
|
||||
COM - B - C - D - E - F
|
||||
\
|
||||
I - SAN
|
||||
\
|
||||
YOU
|
||||
#+END_EXAMPLE
|
||||
|
||||
/What is the minimum number of orbital transfers required/ to move from
|
||||
the object =YOU= are orbiting to the object =SAN= is orbiting? (Between
|
||||
the objects they are orbiting - /not/ between =YOU= and =SAN=.)
|
||||
|
||||
Your puzzle answer was =562=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
270
2019/day06/aoc-c.c
Normal file
270
2019/day06/aoc-c.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 6 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 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>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "debug.h"
|
||||
#include "pool.h"
|
||||
|
||||
/**
|
||||
* As the character set is [1-9A-Z], the trie arrays size will be 26 + 9 = 35,
|
||||
* organized as:
|
||||
* char: 1 2 ... 8 9 A B ... Y Z
|
||||
* index: 0 1 ... 7 8 9 10 ... 33 34
|
||||
*/
|
||||
#define TRIESIZE ('Z' - 'A' + 1 + '9' - '1' + 1)
|
||||
#define c2index(c) ((c) >= 'A'? (c) - 'A' + 9: (c) - '1')
|
||||
#define index2c(c) ((c) >= 9? (c) + 'A' - 9: (c) + '1')
|
||||
|
||||
/**
|
||||
* object_t - object representation
|
||||
* @parent: a pointer to the object we orbit around
|
||||
* @sibling: a list of objects orbiting around @parent
|
||||
* @child: a list of object orbiting around this object
|
||||
* @name: the object name
|
||||
*
|
||||
* Example: if N1 and N2 orbit around O and S orbits around N1, we will
|
||||
* have :
|
||||
* +---------+
|
||||
* +---->| 0 |<---------+
|
||||
* | |---------| |
|
||||
* | | parent |--->NIL |
|
||||
* | |---------| |
|
||||
* +-------------------+---->| child |<---------+-----------------+
|
||||
* | | |---------| | |
|
||||
* | | +-->| sibling |<--+ | |
|
||||
* | | | +---------+ | | |
|
||||
* | | | | | |
|
||||
* | +---------+ | +-----------------+ | +---------+ |
|
||||
* | | N1 |<---+-----+ | | N2 | |
|
||||
* | |---------| | | | |---------| |
|
||||
* | | parent |----+ | +--| parent | |
|
||||
* | |---------| | |---------| |
|
||||
* | +->| child |<---------+----+ NIL<---| child | |
|
||||
* | | |---------| | | |---------| |
|
||||
* +-+->| sibling |<---------+----+----------------->| sibling |<---+
|
||||
* | +---------+ | | +---------+
|
||||
* | | |
|
||||
* | +---------+ | |
|
||||
* | | S | | |
|
||||
* | |---------| | |
|
||||
* | | parent |----------+ |
|
||||
* | |---------| |
|
||||
* | | child |--->NIL |
|
||||
* | |---------| |
|
||||
* +->| sibling |<--------------+
|
||||
* +---------+
|
||||
*
|
||||
*/
|
||||
typedef struct object {
|
||||
struct object *parent;
|
||||
struct list_head sibling, child;
|
||||
char name[8];
|
||||
} object_t;
|
||||
|
||||
/**
|
||||
* trie_t - trie node
|
||||
* @child: array of pointers to trie_t children of current node
|
||||
* @object: pointer to object data (NULL if node only)
|
||||
*
|
||||
* For example, if objects N1, N2, and S exist, the structure will be:
|
||||
*
|
||||
* Root trie
|
||||
* +--------+-------------------------------------+
|
||||
* | object | 0 | 1 | ... | N | ... | S | ... | Z |
|
||||
* +--------+---------------+---------------------+
|
||||
* | | | | |
|
||||
* v v | | v
|
||||
* NIL NIL | | NIL
|
||||
* +----------------------------+ +-----+
|
||||
* | "N" trie | "S" trie
|
||||
* | +--------+-------------+ | +--------------------------+
|
||||
* +-->| object | 0 | ... | Z | +->| object | 0 | 1 | 2 | ... |
|
||||
* +--------+-------------+ +--------------------------+
|
||||
* | | | | | | |
|
||||
* | v v v v | |
|
||||
* | NIL NIL NIL NIL | |
|
||||
* | +---------------------------------+ |
|
||||
* | | +-----------+
|
||||
* | | "S1" trie | "S2" trie
|
||||
* | | +------------------+ | +------------------+
|
||||
* | +-->| object | 0 | ... | +-->| object | 0 | ... |
|
||||
* | +------------------+ +------------------+
|
||||
* | | | | |
|
||||
* | | v | v
|
||||
* v v NIL v NIL
|
||||
* +-----------+ +-----------+ +-----------+
|
||||
* | Object N | | Object S1 | | Object S2 |
|
||||
* +-----------+ +-----------+ +-----------+
|
||||
*/
|
||||
typedef struct trie {
|
||||
struct trie *child[TRIESIZE];
|
||||
object_t *object;
|
||||
} trie_t;
|
||||
|
||||
static pool_t *pool_tries, *pool_objects;
|
||||
|
||||
static trie_t *trie_get(trie_t *parent, char *name, int pos)
|
||||
{
|
||||
trie_t *trie;
|
||||
|
||||
if ((trie = pool_get(pool_tries))) {
|
||||
for (int i = 0; i < TRIESIZE; ++i)
|
||||
trie->child[i] = NULL;
|
||||
trie->object = NULL;
|
||||
if (parent)
|
||||
parent->child[c2index(name[pos])] = trie;
|
||||
}
|
||||
return trie;
|
||||
}
|
||||
|
||||
static trie_t *trie_find(trie_t *root, char *name)
|
||||
{
|
||||
int len = strlen(name);
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
int ind = c2index(name[i]);
|
||||
root = root->child[ind] ? root->child[ind]: trie_get(root, name, i);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
static object_t *object_find(trie_t *root, char *name)
|
||||
{
|
||||
trie_t *trie = trie_find(root, name);
|
||||
|
||||
if (!trie->object) {
|
||||
trie->object = pool_get(pool_objects);
|
||||
trie->object->parent = NULL;
|
||||
strcpy(trie->object->name, name);
|
||||
INIT_LIST_HEAD(&trie->object->child);
|
||||
INIT_LIST_HEAD(&trie->object->sibling);
|
||||
}
|
||||
return trie->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_orbits - get all orbits (direct and indirect) around an object
|
||||
* @object: object address
|
||||
* @depth: depth of current object
|
||||
*/
|
||||
static int get_orbits(object_t *object, int depth)
|
||||
{
|
||||
int ret = depth;
|
||||
object_t *cur;
|
||||
|
||||
if (!list_empty(&object->child))
|
||||
list_for_each_entry(cur, &object->child, sibling)
|
||||
ret += get_orbits(cur, depth + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int part1(trie_t *root, char *name)
|
||||
{
|
||||
object_t *object = object_find(root, name);
|
||||
return get_orbits(object, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_depth - get depth of an object in a tree
|
||||
* @object: object address
|
||||
* Return: object depth
|
||||
*/
|
||||
static int get_depth(object_t *obj)
|
||||
{
|
||||
int res = 0;
|
||||
for (; obj; obj = obj->parent)
|
||||
res++;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int part2(trie_t *root, char *name1, char *name2)
|
||||
{
|
||||
object_t *obj1 = object_find(root, name1), *obj2 = object_find(root, name2);
|
||||
int count = 0, depth1, depth2;
|
||||
|
||||
depth1 = get_depth(obj1);
|
||||
depth2 = get_depth(obj2);
|
||||
/* ensure highest depth is obj1
|
||||
*/
|
||||
if (depth1 < depth2) {
|
||||
swap(obj1, obj2);
|
||||
swap(depth1, depth2);
|
||||
}
|
||||
/* make the 2 depths equal
|
||||
*/
|
||||
for (; depth1 > depth2; count++, depth1--)
|
||||
obj1 = obj1->parent;
|
||||
/* find common parent
|
||||
*/
|
||||
for (; obj1 != obj2; count += 2) {
|
||||
obj1 = obj1->parent;
|
||||
obj2 = obj2->parent;
|
||||
}
|
||||
return count - 2; /* coz' we want parents objects */
|
||||
}
|
||||
|
||||
static void parse(trie_t *root)
|
||||
{
|
||||
char str1[8], str2[8];
|
||||
|
||||
while (scanf(" %7[^)])%s", str1, str2) == 2) {
|
||||
object_t *star = object_find(root, str1);
|
||||
object_t *planet = object_find(root, str2);
|
||||
/* link planet to star, add planet to star's planets list
|
||||
*/
|
||||
planet->parent = star;
|
||||
list_add(&planet->sibling, &star->child);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
if (optind < ac)
|
||||
return usage(*av);
|
||||
|
||||
pool_tries = pool_create("tries", 1024, sizeof(trie_t));
|
||||
pool_objects = pool_create("objects", 1024, sizeof(object_t));
|
||||
trie_t *root = trie_get(NULL, NULL, 0);
|
||||
parse(root);
|
||||
printf("%s : res=%d\n", *av,
|
||||
part == 1 ? part1(root, "COM") : part2(root, "YOU", "SAN"));
|
||||
pool_destroy(pool_tries);
|
||||
pool_destroy(pool_objects);
|
||||
exit (0);
|
||||
}
|
1
2019/day07/EXAMPLE.txt
Normal file
1
2019/day07/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0
|
1
2019/day07/EXAMPLE1.txt
Normal file
1
2019/day07/EXAMPLE1.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0
|
1
2019/day07/EXAMPLE2.txt
Normal file
1
2019/day07/EXAMPLE2.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0
|
1
2019/day07/INPUT.txt
Normal file
1
2019/day07/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
||||
3,8,1001,8,10,8,105,1,0,0,21,30,39,64,81,102,183,264,345,426,99999,3,9,1001,9,2,9,4,9,99,3,9,1002,9,4,9,4,9,99,3,9,1002,9,5,9,101,2,9,9,102,3,9,9,1001,9,2,9,1002,9,2,9,4,9,99,3,9,1002,9,3,9,1001,9,5,9,1002,9,3,9,4,9,99,3,9,102,4,9,9,1001,9,3,9,102,4,9,9,1001,9,5,9,4,9,99,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,99,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,99
|
93
2019/day07/Makefile
Normal file
93
2019/day07/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
167
2019/day07/README.org
Normal file
167
2019/day07/README.org
Normal file
@@ -0,0 +1,167 @@
|
||||
** --- Day 7: Amplification Circuit ---
|
||||
Based on the navigational maps, you're going to need to send more power
|
||||
to your ship's thrusters to reach Santa in time. To do this, you'll need
|
||||
to configure a series of
|
||||
[[https://en.wikipedia.org/wiki/Amplifier][amplifiers]] already
|
||||
installed on the ship.
|
||||
|
||||
There are five amplifiers connected in series; each one receives an
|
||||
input signal and produces an output signal. They are connected such that
|
||||
the first amplifier's output leads to the second amplifier's input, the
|
||||
second amplifier's output leads to the third amplifier's input, and so
|
||||
on. The first amplifier's input value is =0=, and the last amplifier's
|
||||
output leads to your ship's thrusters.
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
O-------O O-------O O-------O O-------O O-------O
|
||||
0 ->| Amp A |->| Amp B |->| Amp C |->| Amp D |->| Amp E |-> (to thrusters)
|
||||
O-------O O-------O O-------O O-------O O-------O
|
||||
#+END_EXAMPLE
|
||||
|
||||
The Elves have sent you some /Amplifier Controller Software/ (your
|
||||
puzzle input), a program that should run on your [[file:5][existing
|
||||
Intcode computer]]. Each amplifier will need to run a copy of the
|
||||
program.
|
||||
|
||||
When a copy of the program starts running on an amplifier, it will first
|
||||
use an input instruction to ask the amplifier for its current /phase
|
||||
setting/ (an integer from =0= to =4=). Each phase setting is used
|
||||
/exactly once/, but the Elves can't remember which amplifier needs which
|
||||
phase setting.
|
||||
|
||||
The program will then call another input instruction to get the
|
||||
amplifier's input signal, compute the correct output signal, and supply
|
||||
it back to the amplifier with an output instruction. (If the amplifier
|
||||
has not yet received an input signal, it waits until one arrives.)
|
||||
|
||||
Your job is to /find the largest output signal that can be sent to the
|
||||
thrusters/ by trying every possible combination of phase settings on the
|
||||
amplifiers. Make sure that memory is not shared or reused between copies
|
||||
of the program.
|
||||
|
||||
For example, suppose you want to try the phase setting sequence
|
||||
=3,1,2,4,0=, which would mean setting amplifier =A= to phase setting
|
||||
=3=, amplifier =B= to setting =1=, =C= to =2=, =D= to =4=, and =E= to
|
||||
=0=. Then, you could determine the output signal that gets sent from
|
||||
amplifier =E= to the thrusters with the following steps:
|
||||
|
||||
- Start the copy of the amplifier controller software that will run on
|
||||
amplifier =A=. At its first input instruction, provide it the
|
||||
amplifier's phase setting, =3=. At its second input instruction,
|
||||
provide it the input signal, =0=. After some calculations, it will use
|
||||
an output instruction to indicate the amplifier's output signal.
|
||||
- Start the software for amplifier =B=. Provide it the phase setting
|
||||
(=1=) and then whatever output signal was produced from amplifier =A=.
|
||||
It will then produce a new output signal destined for amplifier =C=.
|
||||
- Start the software for amplifier =C=, provide the phase setting (=2=)
|
||||
and the value from amplifier =B=, then collect its output signal.
|
||||
- Run amplifier =D='s software, provide the phase setting (=4=) and
|
||||
input value, and collect its output signal.
|
||||
- Run amplifier =E='s software, provide the phase setting (=0=) and
|
||||
input value, and collect its output signal.
|
||||
|
||||
The final output signal from amplifier =E= would be sent to the
|
||||
thrusters. However, this phase setting sequence may not have been the
|
||||
best one; another sequence might have sent a higher signal to the
|
||||
thrusters.
|
||||
|
||||
Here are some example programs:
|
||||
|
||||
- Max thruster signal /=43210=/ (from phase setting sequence
|
||||
=4,3,2,1,0=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0
|
||||
#+END_EXAMPLE
|
||||
|
||||
- Max thruster signal /=54321=/ (from phase setting sequence
|
||||
=0,1,2,3,4=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,23,3,24,1002,24,10,24,1002,23,-1,23,
|
||||
101,5,23,23,1,24,23,23,4,23,99,0,0
|
||||
#+END_EXAMPLE
|
||||
|
||||
- Max thruster signal /=65210=/ (from phase setting sequence
|
||||
=1,0,4,3,2=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,
|
||||
1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0
|
||||
#+END_EXAMPLE
|
||||
|
||||
Try every combination of phase settings on the amplifiers. /What is the
|
||||
highest signal that can be sent to the thrusters?/
|
||||
|
||||
Your puzzle answer was =65464=.
|
||||
|
||||
** --- Part Two ---
|
||||
It's no good - in this configuration, the amplifiers can't generate a
|
||||
large enough output signal to produce the thrust you'll need. The Elves
|
||||
quickly talk you through rewiring the amplifiers into a /feedback loop/:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
O-------O O-------O O-------O O-------O O-------O
|
||||
0 -+->| Amp A |->| Amp B |->| Amp C |->| Amp D |->| Amp E |-.
|
||||
| O-------O O-------O O-------O O-------O O-------O |
|
||||
| |
|
||||
'--------------------------------------------------------+
|
||||
|
|
||||
v
|
||||
(to thrusters)
|
||||
#+END_EXAMPLE
|
||||
|
||||
Most of the amplifiers are connected as they were before; amplifier
|
||||
=A='s output is connected to amplifier =B='s input, and so on.
|
||||
/However,/ the output from amplifier =E= is now connected into amplifier
|
||||
=A='s input. This creates the feedback loop: the signal will be sent
|
||||
through the amplifiers /many times/.
|
||||
|
||||
In feedback loop mode, the amplifiers need /totally different phase
|
||||
settings/: integers from =5= to =9=, again each used exactly once. These
|
||||
settings will cause the Amplifier Controller Software to repeatedly take
|
||||
input and produce output many times before halting. Provide each
|
||||
amplifier its phase setting at its first input instruction; all further
|
||||
input/output instructions are for signals.
|
||||
|
||||
Don't restart the Amplifier Controller Software on any amplifier during
|
||||
this process. Each one should continue receiving and sending signals
|
||||
until it halts.
|
||||
|
||||
All signals sent or received in this process will be between pairs of
|
||||
amplifiers except the very first signal and the very last signal. To
|
||||
start the process, a =0= signal is sent to amplifier =A='s input
|
||||
/exactly once/.
|
||||
|
||||
Eventually, the software on the amplifiers will halt after they have
|
||||
processed the final loop. When this happens, the last output signal from
|
||||
amplifier =E= is sent to the thrusters. Your job is to /find the largest
|
||||
output signal that can be sent to the thrusters/ using the new phase
|
||||
settings and feedback loop arrangement.
|
||||
|
||||
Here are some example programs:
|
||||
|
||||
- Max thruster signal /=139629729=/ (from phase setting sequence
|
||||
=9,8,7,6,5=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,
|
||||
27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5
|
||||
#+END_EXAMPLE
|
||||
|
||||
- Max thruster signal /=18216=/ (from phase setting sequence
|
||||
=9,7,8,5,6=):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,
|
||||
-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,
|
||||
53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10
|
||||
#+END_EXAMPLE
|
||||
|
||||
Try every combination of the new phase settings on the amplifier
|
||||
feedback loop. /What is the highest signal that can be sent to the
|
||||
thrusters?/
|
||||
|
||||
Your puzzle answer was =1518124=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
257
2019/day07/aoc-c.c
Normal file
257
2019/day07/aoc-c.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 7 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 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>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
#include "list.h"
|
||||
#include "pool.h"
|
||||
|
||||
/* operators codes
|
||||
*/
|
||||
typedef enum {
|
||||
ADD = 1, MUL = 2, /* CALC: add and mult */
|
||||
INP = 3, OUT = 4, /* I/O: input and output value */
|
||||
JMP_T = 5, JMP_F = 6, /* JUMPS: jump if true / if false */
|
||||
SET_LT = 7, SET_EQ = 8, /* COND SETS: set if true/false */
|
||||
HLT = 99 /* HALT */
|
||||
} opcode_t;
|
||||
|
||||
/**
|
||||
* ops - array of op-codes, mnemo, and number of parameters
|
||||
* @op: An integer, the opcode
|
||||
* @length: Next instruction offset
|
||||
*/
|
||||
typedef struct {
|
||||
int op;
|
||||
u8 length;
|
||||
} ops_t;
|
||||
|
||||
typedef struct input {
|
||||
int val;
|
||||
struct list_head list;
|
||||
} input_t;
|
||||
|
||||
#define MAXOPS 1024
|
||||
typedef struct {
|
||||
int length; /* total program length */
|
||||
int cur; /* current position */
|
||||
struct list_head input; /* process input queue */
|
||||
int mem [MAXOPS]; /* should really be dynamic */
|
||||
} program_t;
|
||||
|
||||
static ops_t ops[] = {
|
||||
[ADD] = { ADD, 4 }, [MUL] = { MUL, 4 },
|
||||
[INP] = { INP, 2 }, [OUT] = { OUT, 2 },
|
||||
[JMP_T] = { JMP_T, 3 }, [JMP_F] = { JMP_F, 3 },
|
||||
[SET_LT] = { SET_LT, 4 }, [SET_EQ] = { SET_EQ, 4 },
|
||||
[HLT] = { HLT, 1 }
|
||||
};
|
||||
|
||||
|
||||
static int _flag_pow10[] = {1, 100, 1000, 10000};
|
||||
#define OP(p, n) ((p->mem[n]) % 100)
|
||||
#define ISDIRECT(p, n, i) ((((p->mem[n]) / _flag_pow10[i]) % 10))
|
||||
#define DIRECT(p, i) ((p)->mem[i])
|
||||
#define INDIRECT(p, i) (DIRECT(p, DIRECT(p, i)))
|
||||
|
||||
#define peek(p, n, i) (ISDIRECT(p, n, i)? DIRECT(p, n + i): INDIRECT(p, n + i))
|
||||
#define poke(p, n, i, val) do { \
|
||||
INDIRECT(p, n + i) = val; } \
|
||||
while (0)
|
||||
|
||||
|
||||
static pool_t *pool_input;
|
||||
static __always_inline int prg_add_input(program_t *prg, int in)
|
||||
{
|
||||
input_t *input = pool_get(pool_input);
|
||||
input->val = in;
|
||||
list_add_tail(&input->list, &prg->input);
|
||||
return in;
|
||||
}
|
||||
|
||||
static __always_inline int prg_get_input(program_t *prg, int *out)
|
||||
{
|
||||
input_t *input = list_first_entry_or_null(&prg->input, input_t, list);
|
||||
if (!input)
|
||||
return 0;
|
||||
*out = input->val;
|
||||
list_del(&input->list);
|
||||
pool_add(pool_input, input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* permute - get next permutation of an array of integers
|
||||
* @len: length of array
|
||||
* @array: address of array
|
||||
*
|
||||
* Algorithm: lexicographic permutations
|
||||
* https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
|
||||
* Before the initial call, the array must be sorted (e.g. 0 2 3 5)
|
||||
*
|
||||
* Return: 1 if next permutation was found, 0 if no more permutation.
|
||||
*
|
||||
*/
|
||||
static int permute_next(int len, int *array)
|
||||
{
|
||||
int k, l;
|
||||
|
||||
/* 1. Find the largest index k such that a[k] < a[k + 1] */
|
||||
for (k = len - 2; k >= 0 && array[k] >= array[k + 1]; k--)
|
||||
;
|
||||
/* No more permutations */
|
||||
if (k < 0)
|
||||
return 0;
|
||||
/* 2. Find the largest index l greater than k such that a[k] < a[l] */
|
||||
for (l = len - 1; array[l] <= array[k]; l--)
|
||||
;
|
||||
/* 3. Swap the value of a[k] with that of a[l] */
|
||||
swap(array[k], array[l]);
|
||||
/* 4. Reverse sequence from a[k + 1] up to the final element */
|
||||
for (l = len - 1, k++; k < l; k++, l--)
|
||||
swap(array[k], array[l]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int run(program_t *p, int *end)
|
||||
{
|
||||
int out = -1;
|
||||
while (1) {
|
||||
int op = OP(p, p->cur), cur = p->cur, input;
|
||||
|
||||
if (!(ops[op].op)) {
|
||||
fprintf(stderr, "PANIC: illegal instruction %d at %d.\n", op, p->cur);
|
||||
return -1;
|
||||
}
|
||||
switch (op) {
|
||||
case ADD:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) + peek(p, p->cur, 2));
|
||||
break;
|
||||
case MUL:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) * peek(p, p->cur, 2));
|
||||
break;
|
||||
case INP:
|
||||
if (prg_get_input(p, &input))
|
||||
poke(p, p->cur, 1, input);
|
||||
else
|
||||
/* we need an input which is not yet avalaible, so we need
|
||||
* to put the program in "waiting mode": We stop it (and
|
||||
* return output value) without setting end flag.
|
||||
*/
|
||||
goto sleep;
|
||||
break;
|
||||
case OUT:
|
||||
out = peek(p, p->cur, 1);
|
||||
break;
|
||||
case JMP_T:
|
||||
if (peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case JMP_F:
|
||||
if (!peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case SET_LT:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) < peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case SET_EQ:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) == peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case HLT:
|
||||
*end = 1;
|
||||
sleep:
|
||||
return out;
|
||||
}
|
||||
if (p->cur == cur)
|
||||
p->cur += ops[op].length;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse(program_t *prog)
|
||||
{
|
||||
while (scanf("%d%*c", &prog->mem[prog->length++]) > 0)
|
||||
;
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int phase1[] = {0, 1, 2, 3, 4}, phase2[] = {5, 6, 7, 8, 9}, *phase;
|
||||
int opt, max = 0, part = 1;
|
||||
program_t p = { 0 }, prg[5];
|
||||
|
||||
while ((opt = getopt(ac, av, "d:p:o:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_level_set(atoi(optarg));
|
||||
break;
|
||||
case 'o':
|
||||
for (ulong i = 0; i < strlen(optarg); ++i)
|
||||
phase1[i] = optarg[i] - '0';
|
||||
break;
|
||||
case 'p': /* 1 or 2 */
|
||||
part = atoi(optarg);
|
||||
if (part < 1 || part > 2)
|
||||
return usage(*av);
|
||||
break;
|
||||
default:
|
||||
return usage(*av);
|
||||
}
|
||||
}
|
||||
|
||||
pool_input = pool_create("input", 128, sizeof(input_t));
|
||||
|
||||
if (optind < ac)
|
||||
return usage(*av);
|
||||
|
||||
phase = part == 1? phase1: phase2;
|
||||
parse(&p);
|
||||
|
||||
do {
|
||||
int out = 0, end = 0;
|
||||
/* reset programs initial state, and add phase to their input
|
||||
*/
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(prg); ++i) {
|
||||
prg[i] = p;
|
||||
INIT_LIST_HEAD(&prg[i].input);
|
||||
prg_add_input(&prg[i], phase[i]);
|
||||
}
|
||||
|
||||
/* run the 5 processes in order (0, 1, 2, 3, 4, 0, 1, etc...),
|
||||
* until end flag is set by the process 4 (HLT instruction)
|
||||
*/
|
||||
while (!end) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
/* add last process output in current process input queue
|
||||
*/
|
||||
prg_add_input(&prg[i], out);
|
||||
out = run(&prg[i], &end);
|
||||
}
|
||||
}
|
||||
max = max(max, out);
|
||||
} while (permute_next(5, phase));
|
||||
|
||||
printf("%s : res=%d\n", *av, max);
|
||||
pool_destroy(pool_input);
|
||||
exit(0);
|
||||
}
|
1
2019/day08/EXAMPLE.txt
Normal file
1
2019/day08/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
0222112222120000
|
1
2019/day08/INPUT.txt
Normal file
1
2019/day08/INPUT.txt
Normal file
File diff suppressed because one or more lines are too long
93
2019/day08/Makefile
Normal file
93
2019/day08/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
99
2019/day08/README.org
Normal file
99
2019/day08/README.org
Normal file
@@ -0,0 +1,99 @@
|
||||
** --- Day 8: Space Image Format ---
|
||||
The Elves' spirits are lifted when they realize you have an opportunity
|
||||
to reboot one of their Mars rovers, and so they are curious if you would
|
||||
spend a brief sojourn on Mars. You land your ship near the rover.
|
||||
|
||||
When you reach the rover, you discover that it's already in the process
|
||||
of rebooting! It's just waiting for someone to enter a
|
||||
[[https://en.wikipedia.org/wiki/BIOS][BIOS]] password. The Elf
|
||||
responsible for the rover takes a picture of the password (your puzzle
|
||||
input) and sends it to you via the Digital Sending Network.
|
||||
|
||||
Unfortunately, images sent via the Digital Sending Network aren't
|
||||
encoded with any normal encoding; instead, they're encoded in a special
|
||||
Space Image Format. None of the Elves seem to remember why this is the
|
||||
case. They send you the instructions to decode it.
|
||||
|
||||
Images are sent as a series of digits that each represent the color of a
|
||||
single pixel. The digits fill each row of the image left-to-right, then
|
||||
move downward to the next row, filling rows top-to-bottom until every
|
||||
pixel of the image is filled.
|
||||
|
||||
Each image actually consists of a series of identically-sized /layers/
|
||||
that are filled in this way. So, the first digit corresponds to the
|
||||
top-left pixel of the first layer, the second digit corresponds to the
|
||||
pixel to the right of that on the same layer, and so on until the last
|
||||
digit, which corresponds to the bottom-right pixel of the last layer.
|
||||
|
||||
For example, given an image =3= pixels wide and =2= pixels tall, the
|
||||
image data =123456789012= corresponds to the following image layers:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
Layer 1: 123
|
||||
456
|
||||
|
||||
Layer 2: 789
|
||||
012
|
||||
#+END_EXAMPLE
|
||||
|
||||
The image you received is /=25= pixels wide and =6= pixels tall/.
|
||||
|
||||
To make sure the image wasn't corrupted during transmission, the Elves
|
||||
would like you to find the layer that contains the /fewest =0= digits/.
|
||||
On that layer, what is /the number of =1= digits multiplied by the
|
||||
number of =2= digits?/
|
||||
|
||||
Your puzzle answer was =2250=.
|
||||
|
||||
** --- Part Two ---
|
||||
Now you're ready to decode the image. The image is rendered by stacking
|
||||
the layers and aligning the pixels with the same positions in each
|
||||
layer. The digits indicate the color of the corresponding pixel: =0= is
|
||||
black, =1= is white, and =2= is transparent.
|
||||
|
||||
The layers are rendered with the first layer in front and the last layer
|
||||
in back. So, if a given position has a transparent pixel in the first
|
||||
and second layers, a black pixel in the third layer, and a white pixel
|
||||
in the fourth layer, the final image would have a /black/ pixel at that
|
||||
position.
|
||||
|
||||
For example, given an image =2= pixels wide and =2= pixels tall, the
|
||||
image data =0222112222120000= corresponds to the following image layers:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
Layer 1: 02
|
||||
22
|
||||
|
||||
Layer 2: 11
|
||||
22
|
||||
|
||||
Layer 3: 22
|
||||
12
|
||||
|
||||
Layer 4: 00
|
||||
00
|
||||
#+END_EXAMPLE
|
||||
|
||||
Then, the full image can be found by determining the top visible pixel
|
||||
in each position:
|
||||
|
||||
- The top-left pixel is /black/ because the top layer is =0=.
|
||||
- The top-right pixel is /white/ because the top layer is =2=
|
||||
(transparent), but the second layer is =1=.
|
||||
- The bottom-left pixel is /white/ because the top two layers are =2=,
|
||||
but the third layer is =1=.
|
||||
- The bottom-right pixel is /black/ because the only visible pixel in
|
||||
that position is =0= (from layer 4).
|
||||
|
||||
So, the final image looks like this:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
01
|
||||
10
|
||||
#+END_EXAMPLE
|
||||
|
||||
/What message is produced after decoding your image?/
|
||||
|
||||
Your puzzle answer was =FHJUL=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
120
2019/day08/aoc-c.c
Normal file
120
2019/day08/aoc-c.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 8 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 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>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
#include "list.h"
|
||||
#include "pool.h"
|
||||
|
||||
struct input {
|
||||
int len;
|
||||
char *buf;
|
||||
|
||||
};
|
||||
|
||||
static int part1(struct input *input, int width, int height)
|
||||
{
|
||||
int depth = input->len / width / height;
|
||||
int minzero = input->len, n1n2;
|
||||
|
||||
for (int i = 0; i < depth; ++i) {
|
||||
char *layer = input->buf + i * (width * height);
|
||||
int tmp[10] = {0};
|
||||
for (int j = 0; j < width*height; ++j) {
|
||||
tmp[layer[j] - '0'] ++;
|
||||
}
|
||||
if (tmp[0] < minzero) {
|
||||
minzero = tmp[0];
|
||||
n1n2 = tmp[1] * tmp[2];
|
||||
}
|
||||
}
|
||||
return n1n2;
|
||||
}
|
||||
|
||||
static int part2(struct input *input, int width, int height)
|
||||
{
|
||||
for (int line = 0; line < height; line++) {
|
||||
for (int pixel = 0; pixel < width; ++pixel) {
|
||||
char *pos = input->buf + line * width + pixel;
|
||||
while (pos < input->buf + input->len && *pos == '2')
|
||||
pos += width * height;
|
||||
putchar(*pos == '0'? ' ': '#');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse(struct input *input)
|
||||
{
|
||||
size_t alloc = 0;
|
||||
ssize_t buflen;
|
||||
char *buf = NULL;
|
||||
|
||||
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
|
||||
fprintf(stderr, "error reading file.\n");
|
||||
return 0;
|
||||
}
|
||||
buf[buflen--] = 0;
|
||||
input->buf = buf;
|
||||
input->len = buflen;
|
||||
return buflen;
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int opt, part = 1, width = 25, height = 6;
|
||||
struct input input = { 0 };
|
||||
|
||||
while ((opt = getopt(ac, av, "d:p:w:h:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
debug_level_set(atoi(optarg));
|
||||
break;
|
||||
case 'w':
|
||||
width = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
height = 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);
|
||||
|
||||
parse(&input);
|
||||
printf("%s : res=%d\n", *av,
|
||||
part == 1?
|
||||
part1(&input, width, height) :
|
||||
part2(&input, width, height));
|
||||
free(input.buf);
|
||||
exit(0);
|
||||
}
|
1
2019/day09/EXAMPLE.txt
Normal file
1
2019/day09/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
||||
109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99
|
1
2019/day09/EXAMPLE2.txt
Normal file
1
2019/day09/EXAMPLE2.txt
Normal file
@@ -0,0 +1 @@
|
||||
1102,34915192,34915192,7,4,7,99,0
|
1
2019/day09/EXAMPLE3.txt
Normal file
1
2019/day09/EXAMPLE3.txt
Normal file
@@ -0,0 +1 @@
|
||||
104,1125899906842624,99
|
1
2019/day09/INPUT.txt
Normal file
1
2019/day09/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
||||
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1102,3,1,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1101,20,0,1007,1101,0,197,1022,1102,475,1,1028,1102,30,1,1008,1101,25,0,1010,1102,1,23,1009,1101,0,22,1013,1101,470,0,1029,1102,24,1,1014,1102,1,39,1005,1101,31,0,1003,1101,807,0,1026,1101,0,26,1018,1102,1,804,1027,1101,0,0,1020,1102,1,38,1017,1101,0,27,1016,1102,443,1,1024,1101,0,36,1006,1102,21,1,1015,1101,28,0,1001,1102,33,1,1019,1102,1,37,1011,1102,1,190,1023,1101,0,434,1025,1101,34,0,1004,1102,1,1,1021,1101,0,29,1012,1102,1,32,1002,1101,35,0,1000,109,30,2105,1,-7,1001,64,1,64,1105,1,199,4,187,1002,64,2,64,109,-23,2101,0,-5,63,1008,63,32,63,1005,63,225,4,205,1001,64,1,64,1105,1,225,1002,64,2,64,109,7,2102,1,-5,63,1008,63,23,63,1005,63,251,4,231,1001,64,1,64,1106,0,251,1002,64,2,64,109,-16,2101,0,2,63,1008,63,33,63,1005,63,275,1001,64,1,64,1106,0,277,4,257,1002,64,2,64,109,10,21102,40,1,4,1008,1012,40,63,1005,63,299,4,283,1106,0,303,1001,64,1,64,1002,64,2,64,109,7,2102,1,-9,63,1008,63,33,63,1005,63,327,1001,64,1,64,1105,1,329,4,309,1002,64,2,64,109,-17,2107,34,2,63,1005,63,347,4,335,1105,1,351,1001,64,1,64,1002,64,2,64,109,1,1201,8,0,63,1008,63,23,63,1005,63,375,1001,64,1,64,1106,0,377,4,357,1002,64,2,64,109,-4,2108,31,8,63,1005,63,395,4,383,1105,1,399,1001,64,1,64,1002,64,2,64,109,3,1201,8,0,63,1008,63,36,63,1005,63,421,4,405,1105,1,425,1001,64,1,64,1002,64,2,64,109,25,2105,1,1,4,431,1001,64,1,64,1105,1,443,1002,64,2,64,109,-3,1205,0,459,1001,64,1,64,1106,0,461,4,449,1002,64,2,64,109,-2,2106,0,10,4,467,1106,0,479,1001,64,1,64,1002,64,2,64,109,12,1206,-9,495,1001,64,1,64,1106,0,497,4,485,1002,64,2,64,109,-39,1207,9,36,63,1005,63,519,4,503,1001,64,1,64,1105,1,519,1002,64,2,64,109,11,1202,-1,1,63,1008,63,28,63,1005,63,541,4,525,1105,1,545,1001,64,1,64,1002,64,2,64,109,6,2107,24,1,63,1005,63,565,1001,64,1,64,1106,0,567,4,551,1002,64,2,64,109,1,1207,-3,35,63,1005,63,583,1106,0,589,4,573,1001,64,1,64,1002,64,2,64,109,1,21102,41,1,5,1008,1015,40,63,1005,63,613,1001,64,1,64,1105,1,615,4,595,1002,64,2,64,109,-2,2108,22,1,63,1005,63,635,1001,64,1,64,1105,1,637,4,621,1002,64,2,64,109,-10,1208,4,33,63,1005,63,653,1106,0,659,4,643,1001,64,1,64,1002,64,2,64,109,16,1206,6,673,4,665,1106,0,677,1001,64,1,64,1002,64,2,64,109,-4,1202,-8,1,63,1008,63,35,63,1005,63,701,1001,64,1,64,1105,1,703,4,683,1002,64,2,64,109,13,21108,42,42,-8,1005,1015,721,4,709,1105,1,725,1001,64,1,64,1002,64,2,64,109,-18,21107,43,44,5,1005,1010,743,4,731,1106,0,747,1001,64,1,64,1002,64,2,64,109,-11,1208,8,32,63,1005,63,765,4,753,1106,0,769,1001,64,1,64,1002,64,2,64,109,15,21101,44,0,5,1008,1014,47,63,1005,63,789,1105,1,795,4,775,1001,64,1,64,1002,64,2,64,109,13,2106,0,5,1106,0,813,4,801,1001,64,1,64,1002,64,2,64,109,-12,21108,45,43,0,1005,1010,829,1106,0,835,4,819,1001,64,1,64,1002,64,2,64,109,-4,21107,46,45,10,1005,1016,855,1001,64,1,64,1106,0,857,4,841,1002,64,2,64,109,3,21101,47,0,5,1008,1014,47,63,1005,63,883,4,863,1001,64,1,64,1106,0,883,1002,64,2,64,109,10,1205,2,901,4,889,1001,64,1,64,1105,1,901,4,64,99,21102,27,1,1,21102,915,1,0,1106,0,922,21201,1,13433,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21101,0,942,0,1106,0,922,22102,1,1,-1,21201,-2,-3,1,21102,1,957,0,1105,1,922,22201,1,-1,-2,1106,0,968,21202,-2,1,-2,109,-3,2106,0,0
|
93
2019/day09/Makefile
Normal file
93
2019/day09/Makefile
Normal file
@@ -0,0 +1,93 @@
|
||||
# AOC daily Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
INPUT := INPUT.txt
|
||||
SHELL := /bin/bash
|
||||
|
||||
CC := gcc
|
||||
|
||||
LIB := aoc_$(shell uname -m)
|
||||
INCDIR := ../include
|
||||
LIBDIR := ../lib
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
#LDLIB := -l$(LIB) -lm
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||
--sigill-diagnostics=yes --quiet --show-error-list=yes
|
||||
|
||||
|
||||
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||
export PATH := .:$(PATH)
|
||||
|
||||
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||
|
||||
all: README.org ex1 ex2
|
||||
|
||||
memcheck: memcheck1 memcheck2
|
||||
|
||||
memcheck1: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
memcheck2: aoc-c
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) aoc-c -p 2 < $(INPUT)
|
||||
@#@valgrind -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||
|
||||
compile: aoc-c
|
||||
|
||||
assembly: aoc-c.s
|
||||
|
||||
ex1: aoc-c
|
||||
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||
|
||||
ex2: aoc-c
|
||||
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s aoc-c.i README.html
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
# generate pre-processed file (.i) and assembler (.s)
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
# generate README.org from README.html (must cleanup !)
|
||||
%.org: %.html
|
||||
@echo generating $@. Cleanup before commit !
|
||||
@pandoc $< -o $@
|
94
2019/day09/README.org
Normal file
94
2019/day09/README.org
Normal file
@@ -0,0 +1,94 @@
|
||||
** --- Day 9: Sensor Boost ---
|
||||
You've just said goodbye to the rebooted rover and left Mars when you
|
||||
receive a faint distress signal coming from the asteroid belt. It must
|
||||
be the Ceres monitoring station!
|
||||
|
||||
In order to lock on to the signal, you'll need to boost your sensors.
|
||||
The Elves send up the latest /BOOST/ program - Basic Operation Of System
|
||||
Test.
|
||||
|
||||
While BOOST (your puzzle input) is capable of boosting your sensors, for
|
||||
tenuous safety reasons, it refuses to do so until the computer it runs
|
||||
on passes some checks to demonstrate it is a /complete Intcode
|
||||
computer/.
|
||||
|
||||
[[file:5][Your existing Intcode computer]] is missing one key feature:
|
||||
it needs support for parameters in /relative mode/.
|
||||
|
||||
Parameters in mode =2=, /relative mode/, behave very similarly to
|
||||
parameters in /position mode/: the parameter is interpreted as a
|
||||
position. Like position mode, parameters in relative mode can be read
|
||||
from or written to.
|
||||
|
||||
The important difference is that relative mode parameters don't count
|
||||
from address =0=. Instead, they count from a value called the /relative
|
||||
base/. The /relative base/ starts at =0=.
|
||||
|
||||
The address a relative mode parameter refers to is itself /plus/ the
|
||||
current /relative base/. When the relative base is =0=, relative mode
|
||||
parameters and position mode parameters with the same value refer to the
|
||||
same address.
|
||||
|
||||
For example, given a relative base of =50=, a relative mode parameter of
|
||||
=-7= refers to memory address =50 + -7 = 43=.
|
||||
|
||||
The relative base is modified with the /relative base offset/
|
||||
instruction:
|
||||
|
||||
- Opcode =9= /adjusts the relative base/ by the value of its only
|
||||
parameter. The relative base increases (or decreases, if the value is
|
||||
negative) by the value of the parameter.
|
||||
|
||||
For example, if the relative base is =2000=, then after the instruction
|
||||
=109,19=, the relative base would be =2019=. If the next instruction
|
||||
were =204,-34=, then the value at address =1985= would be output.
|
||||
|
||||
Your Intcode computer will also need a few other capabilities:
|
||||
|
||||
- The computer's available memory should be much larger than the initial
|
||||
program. Memory beyond the initial program starts with the value =0=
|
||||
and can be read or written like any other memory. (It is invalid to
|
||||
try to access memory at a negative address, though.)
|
||||
- The computer should have support for large numbers. Some instructions
|
||||
near the beginning of the BOOST program will verify this capability.
|
||||
|
||||
Here are some example programs that use these features:
|
||||
|
||||
- =109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99= takes no
|
||||
input and produces a
|
||||
[[https://en.wikipedia.org/wiki/Quine_(computing)][copy of itself]] as
|
||||
output.
|
||||
- =1102,34915192,34915192,7,4,7,99,0= should output a 16-digit number.
|
||||
- =104,1125899906842624,99= should output the large number in the
|
||||
middle.
|
||||
|
||||
The BOOST program will ask for a single input; run it in test mode by
|
||||
providing it the value =1=. It will perform a series of checks on each
|
||||
opcode, output any opcodes (and the associated parameter modes) that
|
||||
seem to be functioning incorrectly, and finally output a BOOST keycode.
|
||||
|
||||
Once your Intcode computer is fully functional, the BOOST program should
|
||||
report no malfunctioning opcodes when run in test mode; it should only
|
||||
output a single value, the BOOST keycode. /What BOOST keycode does it
|
||||
produce?/
|
||||
|
||||
Your puzzle answer was =2682107844=.
|
||||
|
||||
** --- Part Two ---
|
||||
/You now have a complete Intcode computer./
|
||||
|
||||
Finally, you can lock on to the Ceres distress signal! You just need to
|
||||
boost your sensors using the BOOST program.
|
||||
|
||||
The program runs in sensor boost mode by providing the input instruction
|
||||
the value =2=. Once run, it will boost the sensors automatically, but it
|
||||
might take a few seconds to complete the operation on slower hardware.
|
||||
In sensor boost mode, the program will output a single value: /the
|
||||
coordinates of the distress signal/.
|
||||
|
||||
Run the BOOST program in sensor boost mode. /What are the coordinates of
|
||||
the distress signal?/
|
||||
|
||||
Your puzzle answer was =34738=.
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
258
2019/day09/aoc-c.c
Normal file
258
2019/day09/aoc-c.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/* aoc-c.c: Advent of Code 2019, day 9 parts 1 & 2
|
||||
*
|
||||
* Copyright (C) 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>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "br.h"
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
#include "list.h"
|
||||
#include "pool.h"
|
||||
|
||||
#define _unused __attribute__((unused))
|
||||
|
||||
/* operators codes
|
||||
*/
|
||||
typedef enum {
|
||||
ADD = 1, MUL = 2, /* CALC: add and mult */
|
||||
INP = 3, OUT = 4, /* I/O: input and output value */
|
||||
JMP_T = 5, JMP_F = 6, /* JUMPS: jump if true / if false */
|
||||
SET_LT = 7, SET_EQ = 8, /* COND SETS: set if true/false */
|
||||
ADJ_RL = 9, /* ADDRESSING: adjust relative addr */
|
||||
HLT = 99 /* HALT */
|
||||
} opcode_t;
|
||||
|
||||
/**
|
||||
* ops - array of op-codes, mnemo, and number of parameters
|
||||
* @op: An integer, the opcode
|
||||
* @length: Next instruction offset
|
||||
*/
|
||||
typedef struct {
|
||||
int op;
|
||||
u8 length;
|
||||
} ops_t;
|
||||
|
||||
typedef struct io {
|
||||
s64 val;
|
||||
struct list_head list;
|
||||
} io_t;
|
||||
|
||||
#define MAXOPS 2048
|
||||
typedef struct {
|
||||
s64 length; /* total program length */
|
||||
s64 cur; /* current instruction */
|
||||
s64 rel; /* current relative memory */
|
||||
struct list_head input; /* process input queue */
|
||||
struct list_head output; /* process output queue */
|
||||
s64 mem [MAXOPS]; /* should really be dynamic */
|
||||
} program_t;
|
||||
|
||||
static ops_t ops[] = {
|
||||
[ADD] = { ADD, 4 }, [MUL] = { MUL, 4 },
|
||||
[INP] = { INP, 2 }, [OUT] = { OUT, 2 },
|
||||
[JMP_T] = { JMP_T, 3 }, [JMP_F] = { JMP_F, 3 },
|
||||
[SET_LT] = { SET_LT, 4 }, [SET_EQ] = { SET_EQ, 4 },
|
||||
[ADJ_RL] = { ADJ_RL, 2 },
|
||||
[HLT] = { HLT, 1 }
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
IND = 0,
|
||||
DIR = 1,
|
||||
REL = 2
|
||||
} param_t;
|
||||
|
||||
static __always_inline int getop(program_t *prg, int addr)
|
||||
{
|
||||
return prg->mem[addr] % 100;
|
||||
}
|
||||
|
||||
static __always_inline param_t paramtype(program_t *prg, int addr, int param)
|
||||
{
|
||||
static int _flag_pow10[] = {1, 100, 1000, 10000};
|
||||
return prg->mem[addr] / _flag_pow10[param] % 10;
|
||||
}
|
||||
|
||||
#define DIRECT(p, i) ((p)->mem[i])
|
||||
#define INDIRECT(p, i) (DIRECT(p, DIRECT(p, i)))
|
||||
#define RELATIVE(p, i) (DIRECT(p, DIRECT(p, i) + p->rel))
|
||||
|
||||
static __always_inline s64 peek(program_t *prg, s64 cur, s64 param)
|
||||
{
|
||||
switch(paramtype(prg, cur, param)) {
|
||||
case IND:
|
||||
return INDIRECT(prg, cur + param);
|
||||
case REL:
|
||||
return RELATIVE(prg, cur + param);
|
||||
case DIR:
|
||||
return DIRECT(prg, cur + param);
|
||||
}
|
||||
return 0; /* not reached */
|
||||
}
|
||||
|
||||
static __always_inline void poke(program_t *prg, int cur, int param, s64 val)
|
||||
{
|
||||
if (paramtype(prg, cur, param) == REL)
|
||||
RELATIVE(prg, cur + param) = val;
|
||||
else
|
||||
INDIRECT(prg, cur + param) = val;
|
||||
}
|
||||
|
||||
static pool_t *pool_io;
|
||||
|
||||
static inline int prg_add_input(program_t *prg, s64 in)
|
||||
{
|
||||
io_t *input = pool_get(pool_io);
|
||||
input->val = in;
|
||||
list_add_tail(&input->list, &prg->input);
|
||||
return in;
|
||||
}
|
||||
|
||||
static inline s64 prg_add_output(program_t *prg, s64 out)
|
||||
{
|
||||
io_t *output = pool_get(pool_io);
|
||||
output->val = out;
|
||||
list_add_tail(&output->list, &prg->output);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline int prg_get_input(program_t *prg, s64 *in)
|
||||
{
|
||||
io_t *input = list_first_entry_or_null(&prg->input, io_t, list);
|
||||
if (!input)
|
||||
return 0;
|
||||
*in = input->val;
|
||||
list_del(&input->list);
|
||||
pool_add(pool_io, input);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline _unused int prg_get_output(program_t *prg, s64 *out)
|
||||
{
|
||||
io_t *output = list_first_entry_or_null(&prg->output, io_t, list);
|
||||
if (!output)
|
||||
return 0;
|
||||
*out = output->val;
|
||||
list_del(&output->list);
|
||||
pool_add(pool_io, output);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static s64 run(program_t *p, int *end)
|
||||
{
|
||||
s64 out = -1, input;
|
||||
|
||||
while (1) {
|
||||
int cur = p->cur;
|
||||
opcode_t op = getop(p, p->cur);
|
||||
|
||||
if (!(ops[op].op)) {
|
||||
fprintf(stderr, "PANIC: illegal instruction %d at %ld.\n", op, p->cur);
|
||||
return -1;
|
||||
}
|
||||
switch (op) {
|
||||
case ADD:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) + peek(p, p->cur, 2));
|
||||
break;
|
||||
case MUL:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) * peek(p, p->cur, 2));
|
||||
break;
|
||||
case INP:
|
||||
if (prg_get_input(p, &input))
|
||||
poke(p, p->cur, 1, input);
|
||||
else
|
||||
/* we need an input which is not yet avalaible, so we need
|
||||
* to put the program in "waiting mode": We stop it (and
|
||||
* return output value) without setting end flag.
|
||||
*/
|
||||
goto sleep;
|
||||
break;
|
||||
case OUT:
|
||||
prg_add_output(p, out = peek(p, p->cur, 1));
|
||||
break;
|
||||
case JMP_T:
|
||||
if (peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case JMP_F:
|
||||
if (!peek(p, p->cur, 1))
|
||||
p->cur = peek(p, p->cur, 2);
|
||||
break;
|
||||
case SET_LT:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) < peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case SET_EQ:
|
||||
poke(p, p->cur, 3, peek(p, p->cur, 1) == peek(p, p->cur, 2) ? 1: 0);
|
||||
break;
|
||||
case ADJ_RL:
|
||||
p->rel += peek(p, p->cur, 1);
|
||||
break;
|
||||
case HLT:
|
||||
*end = 1;
|
||||
sleep:
|
||||
return out;
|
||||
}
|
||||
if (p->cur == cur)
|
||||
p->cur += ops[op].length;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse(program_t *prog)
|
||||
{
|
||||
while (scanf("%ld%*c", &prog->mem[prog->length++]) > 0)
|
||||
;
|
||||
}
|
||||
|
||||
static int usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-d debug_level] [-p part] [-i input]\n", prg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int opt, part = 1;
|
||||
|
||||
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);
|
||||
|
||||
int end = 0;
|
||||
program_t p = { 0 };
|
||||
|
||||
pool_io = pool_create("i/o", 128, sizeof(io_t));
|
||||
|
||||
INIT_LIST_HEAD(&p.input);
|
||||
INIT_LIST_HEAD(&p.output);
|
||||
prg_add_input(&p, part);
|
||||
parse(&p);
|
||||
|
||||
printf("%s : res=%ld\n", *av, run(&p, &end));
|
||||
pool_destroy(pool_io);
|
||||
exit(0);
|
||||
}
|
521
2019/include/bits.h
Normal file
521
2019/include/bits.h
Normal file
@@ -0,0 +1,521 @@
|
||||
/* 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>
|
||||
*
|
||||
*/
|
||||
#ifndef BITS_H
|
||||
#define BITS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* next include will define __WORDSIZE: 32 or 64
|
||||
*/
|
||||
#include <bits/wordsize.h>
|
||||
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
/* no plan to support 32bits for now...
|
||||
*/
|
||||
#if __WORDSIZE != 64
|
||||
#error "Only 64 bits word size supported."
|
||||
#endif
|
||||
|
||||
/* fixed-size types
|
||||
*/
|
||||
typedef int64_t s64;
|
||||
typedef int32_t s32;
|
||||
typedef int16_t s16;
|
||||
typedef int8_t s8;
|
||||
|
||||
typedef uint64_t u64;
|
||||
typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
typedef uint8_t u8;
|
||||
|
||||
/* convenience types
|
||||
*/
|
||||
typedef unsigned long int ulong;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned char uchar;
|
||||
|
||||
/* char is a special case, as it can be signed or unsigned
|
||||
*/
|
||||
typedef signed char schar;
|
||||
|
||||
/* count trailing zeroes : 00101000 -> 3
|
||||
* ^^^
|
||||
*/
|
||||
static __always_inline int ctz64(u64 n)
|
||||
{
|
||||
# if __has_builtin(__builtin_ctzl)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin ctzl.\n");
|
||||
# endif
|
||||
return __builtin_ctzl(n);
|
||||
|
||||
# elif __has_builtin(__builtin_clzl)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin clzl.\n");
|
||||
# endif
|
||||
return __WORDSIZE - (__builtin_clzl(n & -n) + 1);
|
||||
|
||||
# else
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "emulated.\n");
|
||||
# endif
|
||||
return popcount64((n & −n) − 1);
|
||||
# endif
|
||||
}
|
||||
|
||||
static __always_inline int ctz32(u32 n)
|
||||
{
|
||||
# if __has_builtin(__builtin_ctz)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin ctz.\n");
|
||||
# endif
|
||||
return __builtin_ctzl(n);
|
||||
|
||||
# elif __has_builtin(__builtin_clz)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin clz.\n");
|
||||
# endif
|
||||
return __WORDSIZE - (__builtin_clz(n & -n) + 1);
|
||||
|
||||
# else
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "emulated.\n");
|
||||
# endif
|
||||
return popcount32((n & −n) − 1);
|
||||
# endif
|
||||
}
|
||||
|
||||
/* clz - count leading zeroes : 00101000 -> 2
|
||||
* ^^
|
||||
*/
|
||||
static __always_inline int clz64(u64 n)
|
||||
{
|
||||
# if __has_builtin(__builtin_clzl)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin.\n");
|
||||
# endif
|
||||
return __builtin_clzl(n);
|
||||
|
||||
# else
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "emulated.\n");
|
||||
# endif
|
||||
u64 r, q;
|
||||
|
||||
r = (n > 0xFFFFFFFF) << 5; n >>= r;
|
||||
q = (n > 0xFFFF) << 4; n >>= q; r |= q;
|
||||
q = (n > 0xFF ) << 3; n >>= q; r |= q;
|
||||
q = (n > 0xF ) << 2; n >>= q; r |= q;
|
||||
q = (n > 0x3 ) << 1; n >>= q; r |= q;
|
||||
r |= (n >> 1);
|
||||
return 64 - r - 1;
|
||||
# endif
|
||||
}
|
||||
|
||||
static __always_inline int clz32(u32 n)
|
||||
{
|
||||
# if __has_builtin(__builtin_clz)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin.\n");
|
||||
# endif
|
||||
return __builtin_clz(n);
|
||||
|
||||
# else
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "emulated.\n");
|
||||
# endif
|
||||
u32 r, q;
|
||||
|
||||
r = (n > 0xFFFF) << 4; n >>= r;
|
||||
q = (n > 0xFF ) << 3; n >>= q; r |= q;
|
||||
q = (n > 0xF ) << 2; n >>= q; r |= q;
|
||||
q = (n > 0x3 ) << 1; n >>= q; r |= q;
|
||||
r |= (n >> 1);
|
||||
return 32 - r - 1;
|
||||
# endif
|
||||
}
|
||||
|
||||
/* fls - find last set : 00101000 -> 6
|
||||
* ^
|
||||
*/
|
||||
static __always_inline int fls64(u64 n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
return 64 - clz64(n);
|
||||
}
|
||||
|
||||
static __always_inline int fls32(u32 n)
|
||||
{
|
||||
if (!n)
|
||||
return 0;
|
||||
return 32 - clz32(n);
|
||||
}
|
||||
|
||||
/* find first set : 00101000 -> 4
|
||||
* ^
|
||||
*/
|
||||
static __always_inline uint ffs64(u64 n)
|
||||
{
|
||||
# if __has_builtin(__builtin_ffsl)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin ffsl.\n");
|
||||
# endif
|
||||
return __builtin_ffsl(n);
|
||||
|
||||
# elif __has_builtin(__builtin_ctzl)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin ctzl.\n");
|
||||
# endif
|
||||
if (n == 0)
|
||||
return (0);
|
||||
return __builtin_ctzl(n) + 1;
|
||||
|
||||
# else
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "emulated.\n");
|
||||
# endif
|
||||
return popcount64(n ^ ~-n);
|
||||
# endif
|
||||
}
|
||||
|
||||
static __always_inline uint ffs32(u32 n)
|
||||
{
|
||||
# if __has_builtin(__builtin_ffs)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin ffs.\n");
|
||||
# endif
|
||||
return __builtin_ffs(n);
|
||||
|
||||
# elif __has_builtin(__builtin_ctz)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin ctz.\n");
|
||||
# endif
|
||||
if (n == 0)
|
||||
return (0);
|
||||
return __builtin_ctz(n) + 1;
|
||||
|
||||
# else
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "emulated.\n");
|
||||
# endif
|
||||
return popcount32(n ^ ~-n);
|
||||
# endif
|
||||
}
|
||||
|
||||
/* count set bits: 10101000 -> 3
|
||||
* ^ ^ ^
|
||||
*/
|
||||
static __always_inline int popcount64(u64 n)
|
||||
{
|
||||
# if __has_builtin(__builtin_popcountl)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin.\n");
|
||||
# endif
|
||||
return __builtin_popcountl(n);
|
||||
|
||||
# else
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "emulated.\n");
|
||||
# endif
|
||||
int count = 0;
|
||||
while (n) {
|
||||
count++;
|
||||
n &= (n - 1);
|
||||
}
|
||||
return count;
|
||||
# endif
|
||||
}
|
||||
|
||||
static __always_inline int popcount32(u32 n)
|
||||
{
|
||||
# if __has_builtin(__builtin_popcount)
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "builtin.\n");
|
||||
# endif
|
||||
return __builtin_popcount(n);
|
||||
|
||||
# else
|
||||
# ifdef DEBUG_BITS
|
||||
log_f(1, "emulated.\n");
|
||||
# endif
|
||||
int count = 0;
|
||||
while (n) {
|
||||
count++;
|
||||
n &= (n - 1);
|
||||
}
|
||||
return count;
|
||||
# endif
|
||||
}
|
||||
|
||||
/* rolXX are taken from kernel's <linux/bitops.h> are are:
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* rol64 - rotate a 64-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u64 rol64(u64 word, unsigned int shift)
|
||||
{
|
||||
return (word << (shift & 63)) | (word >> ((-shift) & 63));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror64 - rotate a 64-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u64 ror64(u64 word, unsigned int shift)
|
||||
{
|
||||
return (word >> (shift & 63)) | (word << ((-shift) & 63));
|
||||
}
|
||||
|
||||
/**
|
||||
* rol32 - rotate a 32-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u32 rol32(u32 word, unsigned int shift)
|
||||
{
|
||||
return (word << (shift & 31)) | (word >> ((-shift) & 31));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror32 - rotate a 32-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u32 ror32(u32 word, unsigned int shift)
|
||||
{
|
||||
return (word >> (shift & 31)) | (word << ((-shift) & 31));
|
||||
}
|
||||
|
||||
/**
|
||||
* rol16 - rotate a 16-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u16 rol16(u16 word, unsigned int shift)
|
||||
{
|
||||
return (word << (shift & 15)) | (word >> ((-shift) & 15));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror16 - rotate a 16-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u16 ror16(u16 word, unsigned int shift)
|
||||
{
|
||||
return (word >> (shift & 15)) | (word << ((-shift) & 15));
|
||||
}
|
||||
|
||||
/**
|
||||
* rol8 - rotate an 8-bit value left
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u8 rol8(u8 word, unsigned int shift)
|
||||
{
|
||||
return (word << (shift & 7)) | (word >> ((-shift) & 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* ror8 - rotate an 8-bit value right
|
||||
* @word: value to rotate
|
||||
* @shift: bits to roll
|
||||
*/
|
||||
static inline u8 ror8(u8 word, unsigned int shift)
|
||||
{
|
||||
return (word >> (shift & 7)) | (word << ((-shift) & 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* ilog2 -
|
||||
*/
|
||||
static __always_inline __attribute__((const))
|
||||
int __ilog2_u32(u32 n)
|
||||
{
|
||||
return fls32(n) - 1;
|
||||
}
|
||||
|
||||
static __always_inline __attribute__((const))
|
||||
int __ilog2_u64(u64 n)
|
||||
{
|
||||
return fls64(n) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_power_of_2() - check if a value is a power of two
|
||||
* @n: the value to check
|
||||
*
|
||||
* Determine whether some value is a power of two, where zero is
|
||||
* *not* considered a power of two.
|
||||
* Return: true if @n is a power of 2, otherwise false.
|
||||
*/
|
||||
static inline __attribute__((const))
|
||||
bool is_power_of_2(unsigned long n)
|
||||
{
|
||||
return (n != 0 && ((n & (n - 1)) == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* ilog2 - log base 2 of 32-bit or a 64-bit unsigned value
|
||||
* @n: parameter
|
||||
*
|
||||
* constant-capable log of base 2 calculation
|
||||
* - this can be used to initialise global variables from constant data, hence
|
||||
* the massive ternary operator construction
|
||||
*
|
||||
* selects the appropriately-sized optimised version depending on sizeof(n)
|
||||
*/
|
||||
#define ilog2(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? \
|
||||
((n) < 2 ? 0 : \
|
||||
63 - __builtin_clzll(n)) : \
|
||||
(sizeof(n) <= 4) ? \
|
||||
__ilog2_u32(n) : \
|
||||
__ilog2_u64(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* roundup_pow_of_two - round the given value up to nearest power of two
|
||||
* @n: parameter
|
||||
*
|
||||
* round the given value up to the nearest power of two
|
||||
* - the result is undefined when n == 0
|
||||
* - this can be used to initialise global variables from constant data
|
||||
*/
|
||||
#define roundup_pow_of_two(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
((n) == 1) ? 1 : \
|
||||
(1UL << (ilog2((n) - 1) + 1)) \
|
||||
) : \
|
||||
__roundup_pow_of_two(n) \
|
||||
)
|
||||
|
||||
/**
|
||||
* rounddown_pow_of_two - round the given value down to nearest power of two
|
||||
* @n: parameter
|
||||
*
|
||||
* round the given value down to the nearest power of two
|
||||
* - the result is undefined when n == 0
|
||||
* - this can be used to initialise global variables from constant data
|
||||
*/
|
||||
#define rounddown_pow_of_two(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
(1UL << ilog2(n))) : \
|
||||
__rounddown_pow_of_two(n) \
|
||||
)
|
||||
|
||||
static inline __attribute_const__
|
||||
int __order_base_2(unsigned long n)
|
||||
{
|
||||
return n > 1 ? ilog2(n - 1) + 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* order_base_2 - calculate the (rounded up) base 2 order of the argument
|
||||
* @n: parameter
|
||||
*
|
||||
* The first few values calculated by this routine:
|
||||
* ob2(0) = 0
|
||||
* ob2(1) = 0
|
||||
* ob2(2) = 1
|
||||
* ob2(3) = 2
|
||||
* ob2(4) = 2
|
||||
* ob2(5) = 3
|
||||
* ... and so on.
|
||||
*/
|
||||
#define order_base_2(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
((n) == 0 || (n) == 1) ? 0 : \
|
||||
ilog2((n) - 1) + 1) : \
|
||||
__order_base_2(n) \
|
||||
)
|
||||
|
||||
static inline __attribute__((const))
|
||||
int __bits_per(unsigned long n)
|
||||
{
|
||||
if (n < 2)
|
||||
return 1;
|
||||
if (is_power_of_2(n))
|
||||
return order_base_2(n) + 1;
|
||||
return order_base_2(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* bits_per - calculate the number of bits required for the argument
|
||||
* @n: parameter
|
||||
*
|
||||
* This is constant-capable and can be used for compile time
|
||||
* initializations, e.g bitfields.
|
||||
*
|
||||
* The first few values calculated by this routine:
|
||||
* bf(0) = 1
|
||||
* bf(1) = 1
|
||||
* bf(2) = 2
|
||||
* bf(3) = 2
|
||||
* bf(4) = 3
|
||||
* ... and so on.
|
||||
*/
|
||||
#define bits_per(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
((n) == 0 || (n) == 1) \
|
||||
? 1 : ilog2(n) + 1 \
|
||||
) : \
|
||||
__bits_per(n) \
|
||||
)
|
||||
|
||||
/** bit_for_each - iterate over an u64/u32 bits
|
||||
* @pos: an int used as current bit
|
||||
* @tmp: a temp u64/u32 used as temporary storage
|
||||
* @ul: the u64/u32 to loop over
|
||||
*
|
||||
* Usage:
|
||||
* u64 u=139, _t; // u=b10001011
|
||||
* int cur;
|
||||
* bit_for_each64(cur, _t, u) {
|
||||
* printf("%d\n", cur);
|
||||
* }
|
||||
* This will display the position of each bit set in ul: 1, 2, 4, 8
|
||||
*
|
||||
* I should probably re-think the implementation...
|
||||
*/
|
||||
#define bit_for_each64(pos, tmp, ul) \
|
||||
for (tmp = ul, pos = ffs64(tmp); tmp; tmp &= (tmp - 1), pos = ffs64(tmp))
|
||||
|
||||
#define bit_for_each32(pos, tmp, ul) \
|
||||
for (tmp = ul, pos = ffs32(tmp); tmp; tmp &= (tmp - 1), pos = ffs32(tmp))
|
||||
|
||||
/** or would it be more useful (counting bits from zero instead of 1) ?
|
||||
*/
|
||||
#define bit_for_each64_2(pos, tmp, ul) \
|
||||
for (tmp = ul, pos = ctz64(tmp); tmp; tmp ^= 1UL << pos, pos = ctz64(tmp))
|
||||
|
||||
#define bit_for_each32_2(pos, tmp, ul) \
|
||||
for (tmp = ul, pos = ctz32(tmp); tmp; tmp ^= 1U << pos, pos = ctz32(tmp))
|
||||
|
||||
#endif /* BITS_H */
|
211
2019/include/br.h
Normal file
211
2019/include/br.h
Normal file
@@ -0,0 +1,211 @@
|
||||
/* 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
|
||||
|
||||
/* Indirect stringification. Doing two levels allows the parameter to be a
|
||||
* macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
|
||||
* converts to "bar".
|
||||
*/
|
||||
#define __stringify_1(x...) #x
|
||||
#define __stringify(x...) __stringify_1(x)
|
||||
|
||||
/* 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__)
|
||||
|
||||
/* 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))
|
||||
|
||||
#define __pure __attribute__((__pure__))
|
||||
|
||||
/**
|
||||
* 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 */
|
71
2019/include/bug.h
Normal file
71
2019/include/bug.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _BR_BUG_H
|
||||
#define _BR_BUG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "likely.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* BUG functions inspired by Linux kernel's <asm/bug.h>
|
||||
*/
|
||||
|
||||
#define panic() exit(0xff)
|
||||
|
||||
/*
|
||||
* Don't use BUG() or BUG_ON() unless there's really no way out; one
|
||||
* example might be detecting data structure corruption in the middle
|
||||
* of an operation that can't be backed out of. If the (sub)system
|
||||
* can somehow continue operating, perhaps with reduced functionality,
|
||||
* it's probably not BUG-worthy.
|
||||
*
|
||||
* If you're tempted to BUG(), think again: is completely giving up
|
||||
* really the *only* solution? There are usually better options, where
|
||||
* users don't need to reboot ASAP and can mostly shut down cleanly.
|
||||
*/
|
||||
#define BUG() do { \
|
||||
fprintf(stderr, "BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
|
||||
panic(); \
|
||||
} while (0)
|
||||
|
||||
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
|
||||
|
||||
/*
|
||||
* WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report
|
||||
* significant kernel issues that need prompt attention if they should ever
|
||||
* appear at runtime.
|
||||
*
|
||||
* Do not use these macros when checking for invalid external inputs
|
||||
* (e.g. invalid system call arguments, or invalid data coming from
|
||||
* network/devices), and on transient conditions like ENOMEM or EAGAIN.
|
||||
* These macros should be used for recoverable kernel issues only.
|
||||
* For invalid external inputs, transient conditions, etc use
|
||||
* pr_err[_once/_ratelimited]() followed by dump_stack(), if necessary.
|
||||
* Do not include "BUG"/"WARNING" in format strings manually to make these
|
||||
* conditions distinguishable from kernel issues.
|
||||
*
|
||||
* Use the versions with printk format strings to provide better diagnostics.
|
||||
*/
|
||||
#define __WARN() do { \
|
||||
fprintf(stderr, "WARNING: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
|
||||
} while (0)
|
||||
#define __WARN_printf(arg...) do { \
|
||||
vfprintf(stderr, arg); \
|
||||
} while (0)
|
||||
|
||||
#define WARN_ON(condition) ({ \
|
||||
int __ret_warn_on = !!(condition); \
|
||||
if (unlikely(__ret_warn_on)) \
|
||||
__WARN(); \
|
||||
unlikely(__ret_warn_on); \
|
||||
})
|
||||
|
||||
#define WARN(condition, format...) ({ \
|
||||
int __ret_warn_on = !!(condition); \
|
||||
if (unlikely(__ret_warn_on)) \
|
||||
__WARN_printf(format); \
|
||||
unlikely(__ret_warn_on); \
|
||||
})
|
||||
|
||||
#endif /* _BR_BUG_H */
|
30
2019/include/container-of.h
Normal file
30
2019/include/container-of.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/* adaptation of Linux kernel's <linux/container_of.h>
|
||||
*/
|
||||
#ifndef _BR_CONTAINER_OF_H
|
||||
#define _BR_CONTAINER_OF_H
|
||||
|
||||
/* Are two types/vars the same type (ignoring qualifiers)? */
|
||||
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
|
||||
|
||||
/**
|
||||
* typeof_member -
|
||||
*/
|
||||
#define typeof_member(T, m) typeof(((T*)0)->m)
|
||||
|
||||
/**
|
||||
* container_of - cast a member of a structure out to the containing structure
|
||||
* @ptr: the pointer to the member.
|
||||
* @type: the type of the container struct this is embedded in.
|
||||
* @member: the name of the member within the struct.
|
||||
*
|
||||
*/
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
void *__mptr = (void *)(ptr); \
|
||||
_Static_assert(__same_type(*(ptr), ((type *)0)->member) || \
|
||||
__same_type(*(ptr), void), \
|
||||
"pointer type mismatch in container_of()"); \
|
||||
((type *)(__mptr - offsetof(type, member))); })
|
||||
|
||||
#endif /* BR_CONTAINER_OF_H */
|
98
2019/include/debug.h
Normal file
98
2019/include/debug.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/* debug.h - debug/log management.
|
||||
*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bits.h"
|
||||
|
||||
#define _unused __attribute__((__unused__))
|
||||
#define _printf __attribute__ ((format (printf, 6, 7)))
|
||||
|
||||
#ifdef DEBUG_DEBUG
|
||||
void debug_init(u32 level);
|
||||
void debug_level_set(u32 level);
|
||||
void _printf debug(u32 level, bool timestamp,
|
||||
u32 indent, const char *src,
|
||||
u32 line, const char *, ...);
|
||||
#else /* DEBUG_DEBUG */
|
||||
static inline void debug_init(_unused u32 level) {}
|
||||
static inline void debug_level_set(_unused u32 level) {}
|
||||
static inline void _printf debug(_unused u32 level, _unused bool timestamp,
|
||||
_unused u32 indent, _unused const char *src,
|
||||
_unused u32 line, const char *, ...) {}
|
||||
#endif /* DEBUG_DEBUG */
|
||||
#undef _unused
|
||||
#undef _printf
|
||||
|
||||
/**
|
||||
* log - simple log (no function name, no indent, no timestamp)
|
||||
* @level: log level
|
||||
* @fmt: printf format string
|
||||
* @args: subsequent arguments to printf
|
||||
*/
|
||||
#define log(level, fmt, args...) \
|
||||
debug((level), false, 0, NULL, 0, fmt, ##args)
|
||||
|
||||
/**
|
||||
* log_i - log with indent (no function name, no timestamp)
|
||||
* @level: log level
|
||||
* @fmt: printf format string
|
||||
* @args: subsequent arguments to printf
|
||||
*
|
||||
* Output example:
|
||||
* >>>>val=2
|
||||
*/
|
||||
#define log_i(level, fmt, args...) \
|
||||
debug((level), false, (level), NULL, 0, fmt, ##args)
|
||||
|
||||
/**
|
||||
* log_f - log with function name (no indent name, no timestamp)
|
||||
* @level: log level
|
||||
* @fmt: printf format string
|
||||
* @args: subsequent arguments to printf
|
||||
*
|
||||
* Output example:
|
||||
* [function] val=2
|
||||
*/
|
||||
#define log_f(level, fmt, args...) \
|
||||
debug((level), false, 0, __func__, 0, fmt, ##args)
|
||||
|
||||
/**
|
||||
* log_if - log with function name and line number (no indent name, no timestamp)
|
||||
* @level: log level
|
||||
* @fmt: printf format string
|
||||
* @args: subsequent arguments to printf
|
||||
*
|
||||
* Output example:
|
||||
* >>>> [function:15] val=2
|
||||
*/
|
||||
#define log_if(level, fmt, args...) \
|
||||
debug((level), false, (level), __func__, __LINE__, fmt, ##args)
|
||||
|
||||
/**
|
||||
* log_it - log with function name, line number, indent, and timestamp
|
||||
* @level: log level
|
||||
* @fmt: printf format string
|
||||
* @args: subsequent arguments to printf
|
||||
*
|
||||
* Output example:
|
||||
* >>>> [function:15] val=2
|
||||
*/
|
||||
#define log_it(level, fmt, args...) \
|
||||
debug((level), true, (level), __func__, __LINE__, fmt, ##args)
|
||||
|
||||
#endif /* DEBUG_H */
|
173
2019/include/hash.h
Normal file
173
2019/include/hash.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _BR_HASH_H
|
||||
#define _BR_HASH_H
|
||||
/* adaptation of Linux kernel's <linux/hash.h> and <linux/stringhash.h>
|
||||
*/
|
||||
|
||||
/* Fast hashing routine for ints, longs and pointers.
|
||||
(C) 2002 Nadia Yvette Chambers, IBM */
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <asm/bitsperlong.h>
|
||||
#include "bits.h"
|
||||
#include "br.h"
|
||||
|
||||
/*
|
||||
* The "GOLDEN_RATIO_PRIME" is used in ifs/btrfs/brtfs_inode.h and
|
||||
* fs/inode.c. It's not actually prime any more (the previous primes
|
||||
* were actively bad for hashing), but the name remains.
|
||||
*/
|
||||
#if __BITS_PER_LONG == 32
|
||||
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32
|
||||
#define hash_long(val, bits) hash_32(val, bits)
|
||||
#elif __BITS_PER_LONG == 64
|
||||
#define hash_long(val, bits) hash_64(val, bits)
|
||||
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_64
|
||||
#else
|
||||
#error Wordsize not 32 or 64
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This hash multiplies the input by a large odd number and takes the
|
||||
* high bits. Since multiplication propagates changes to the most
|
||||
* significant end only, it is essential that the high bits of the
|
||||
* product be used for the hash value.
|
||||
*
|
||||
* Chuck Lever verified the effectiveness of this technique:
|
||||
* http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
|
||||
*
|
||||
* Although a random odd number will do, it turns out that the golden
|
||||
* ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice
|
||||
* properties. (See Knuth vol 3, section 6.4, exercise 9.)
|
||||
*
|
||||
* These are the negative, (1 - phi) = phi**2 = (3 - sqrt(5))/2,
|
||||
* which is very slightly easier to multiply by and makes no
|
||||
* difference to the hash distribution.
|
||||
*/
|
||||
#define GOLDEN_RATIO_32 0x61C88647
|
||||
#define GOLDEN_RATIO_64 0x61C8864680B583EBull
|
||||
|
||||
/*
|
||||
* The _generic versions exist only so lib/test_hash.c can compare
|
||||
* the arch-optimized versions with the generic.
|
||||
*
|
||||
* Note that if you change these, any <asm/hash.h> that aren't updated
|
||||
* to match need to have their HAVE_ARCH_* define values updated so the
|
||||
* self-test will not false-positive.
|
||||
*/
|
||||
#ifndef HAVE_ARCH__HASH_32
|
||||
#define __hash_32 __hash_32_generic
|
||||
#endif
|
||||
static inline u32 __hash_32_generic(u32 val)
|
||||
{
|
||||
return val * GOLDEN_RATIO_32;
|
||||
}
|
||||
|
||||
static inline u32 hash_32(u32 val, unsigned int bits)
|
||||
{
|
||||
/* High bits are more random, so use them. */
|
||||
return __hash_32(val) >> (32 - bits);
|
||||
}
|
||||
|
||||
#ifndef HAVE_ARCH_HASH_64
|
||||
#define hash_64 hash_64_generic
|
||||
#endif
|
||||
static __always_inline u32 hash_64_generic(u64 val, unsigned int bits)
|
||||
{
|
||||
#if __BITS_PER_LONG == 64
|
||||
/* 64x64-bit multiply is efficient on all 64-bit processors */
|
||||
return val * GOLDEN_RATIO_64 >> (64 - bits);
|
||||
#else
|
||||
/* Hash 64 bits using only 32x32-bit multiply. */
|
||||
return hash_32((u32)val ^ __hash_32(val >> 32), bits);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u32 hash_ptr(const void *ptr, unsigned int bits)
|
||||
{
|
||||
return hash_long((unsigned long)ptr, bits);
|
||||
}
|
||||
|
||||
/* This really should be called fold32_ptr; it does no hashing to speak of. */
|
||||
static inline u32 hash32_ptr(const void *ptr)
|
||||
{
|
||||
unsigned long val = (unsigned long)ptr;
|
||||
|
||||
#if __BITS_PER_LONG == 64
|
||||
val ^= (val >> 32);
|
||||
#endif
|
||||
return (u32)val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines for hashing strings of bytes to a 32-bit hash value.
|
||||
*
|
||||
* These hash functions are NOT GUARANTEED STABLE between kernel
|
||||
* versions, architectures, or even repeated boots of the same kernel.
|
||||
* (E.g. they may depend on boot-time hardware detection or be
|
||||
* deliberately randomized.)
|
||||
*
|
||||
* They are also not intended to be secure against collisions caused by
|
||||
* malicious inputs; much slower hash functions are required for that.
|
||||
*
|
||||
* They are optimized for pathname components, meaning short strings.
|
||||
* Even if a majority of files have longer names, the dynamic profile of
|
||||
* pathname components skews short due to short directory names.
|
||||
* (E.g. /usr/lib/libsesquipedalianism.so.3.141.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Version 1: one byte at a time. Example of use:
|
||||
*
|
||||
* unsigned long hash = init_name_hash;
|
||||
* while (*p)
|
||||
* hash = partial_name_hash(tolower(*p++), hash);
|
||||
* hash = end_name_hash(hash);
|
||||
*
|
||||
* Although this is designed for bytes, fs/hfsplus/unicode.c
|
||||
* abuses it to hash 16-bit values.
|
||||
*/
|
||||
|
||||
/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
|
||||
#define init_name_hash(salt) (unsigned long)(salt)
|
||||
|
||||
/* partial hash update function. Assume roughly 4 bits per character */
|
||||
static inline unsigned long
|
||||
partial_name_hash(unsigned long c, unsigned long prevhash)
|
||||
{
|
||||
return (prevhash + (c << 4) + (c >> 4)) * 11;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally: cut down the number of bits to a int value (and try to avoid
|
||||
* losing bits). This also has the property (wanted by the dcache)
|
||||
* that the msbits make a good hash table index.
|
||||
*/
|
||||
static inline unsigned int end_name_hash(unsigned long hash)
|
||||
{
|
||||
return hash_long(hash, 32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Version 2: One word (32 or 64 bits) at a time.
|
||||
* If CONFIG_DCACHE_WORD_ACCESS is defined (meaning <asm/word-at-a-time.h>
|
||||
* exists, which describes major Linux platforms like x86 and ARM), then
|
||||
* this computes a different hash function much faster.
|
||||
*
|
||||
* If not set, this falls back to a wrapper around the preceding.
|
||||
*/
|
||||
extern unsigned int __pure hash_string(const void *salt, const char *, unsigned int);
|
||||
|
||||
/*
|
||||
* A hash_len is a u64 with the hash of a string in the low
|
||||
* half and the length in the high half.
|
||||
*/
|
||||
#define hashlen_hash(hashlen) ((u32)(hashlen))
|
||||
#define hashlen_len(hashlen) ((u32)((hashlen) >> 32))
|
||||
#define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash))
|
||||
|
||||
/* Return the "hash_len" (hash and length) of a null-terminated string */
|
||||
extern u64 __pure hashlen_string(const void *salt, const char *name);
|
||||
|
||||
#endif /* _BR_HASH_H */
|
204
2019/include/hashtable.h
Normal file
204
2019/include/hashtable.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* adaptation of Linux kernel's <linux/hashtable.h>
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Statically sized hash table implementation
|
||||
* (C) 2012 Sasha Levin <levinsasha928@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_HASHTABLE_H
|
||||
#define _LINUX_HASHTABLE_H
|
||||
|
||||
#include "list.h"
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "hash.h"
|
||||
//#include <linux/rculist.h>
|
||||
|
||||
#define DEFINE_HASHTABLE(name, bits) \
|
||||
struct hlist_head name[1 << (bits)] = \
|
||||
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
|
||||
|
||||
#define DEFINE_READ_MOSTLY_HASHTABLE(name, bits) \
|
||||
struct hlist_head name[1 << (bits)] __read_mostly = \
|
||||
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
|
||||
|
||||
#define DECLARE_HASHTABLE(name, bits) \
|
||||
struct hlist_head name[1 << (bits)]
|
||||
|
||||
#define HASH_SIZE(name) (ARRAY_SIZE(name))
|
||||
#define HASH_BITS(name) ilog2(HASH_SIZE(name))
|
||||
|
||||
/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
|
||||
#define hash_min(val, bits) \
|
||||
(sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
|
||||
|
||||
static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sz; i++)
|
||||
INIT_HLIST_HEAD(&ht[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash_init - initialize a hash table
|
||||
* @hashtable: hashtable to be initialized
|
||||
*
|
||||
* Calculates the size of the hashtable from the given parameter, otherwise
|
||||
* same as hash_init_size.
|
||||
*
|
||||
* This has to be a macro since HASH_BITS() will not work on pointers since
|
||||
* it calculates the size during preprocessing.
|
||||
*/
|
||||
#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))
|
||||
|
||||
/**
|
||||
* hash_add - add an object to a hashtable
|
||||
* @hashtable: hashtable to add to
|
||||
* @node: the &struct hlist_node of the object to be added
|
||||
* @key: the key of the object to be added
|
||||
*/
|
||||
#define hash_add(hashtable, node, key) \
|
||||
hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
|
||||
|
||||
/**
|
||||
* hash_add_rcu - add an object to a rcu enabled hashtable
|
||||
* @hashtable: hashtable to add to
|
||||
* @node: the &struct hlist_node of the object to be added
|
||||
* @key: the key of the object to be added
|
||||
*/
|
||||
#define hash_add_rcu(hashtable, node, key) \
|
||||
hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
|
||||
|
||||
/**
|
||||
* hash_hashed - check whether an object is in any hashtable
|
||||
* @node: the &struct hlist_node of the object to be checked
|
||||
*/
|
||||
static inline bool hash_hashed(struct hlist_node *node)
|
||||
{
|
||||
return !hlist_unhashed(node);
|
||||
}
|
||||
|
||||
static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sz; i++)
|
||||
if (!hlist_empty(&ht[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* hash_empty - check whether a hashtable is empty
|
||||
* @hashtable: hashtable to check
|
||||
*
|
||||
* This has to be a macro since HASH_BITS() will not work on pointers since
|
||||
* it calculates the size during preprocessing.
|
||||
*/
|
||||
#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable))
|
||||
|
||||
/**
|
||||
* hash_del - remove an object from a hashtable
|
||||
* @node: &struct hlist_node of the object to remove
|
||||
*/
|
||||
static inline void hash_del(struct hlist_node *node)
|
||||
{
|
||||
hlist_del_init(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash_for_each - iterate over a hashtable
|
||||
* @name: hashtable to iterate
|
||||
* @bkt: integer to use as bucket loop cursor
|
||||
* @obj: the type * to use as a loop cursor for each entry
|
||||
* @member: the name of the hlist_node within the struct
|
||||
*/
|
||||
#define hash_for_each(name, bkt, obj, member) \
|
||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
|
||||
(bkt)++)\
|
||||
hlist_for_each_entry(obj, &name[bkt], member)
|
||||
|
||||
/**
|
||||
* hash_for_each_rcu - iterate over a rcu enabled hashtable
|
||||
* @name: hashtable to iterate
|
||||
* @bkt: integer to use as bucket loop cursor
|
||||
* @obj: the type * to use as a loop cursor for each entry
|
||||
* @member: the name of the hlist_node within the struct
|
||||
*/
|
||||
#define hash_for_each_rcu(name, bkt, obj, member) \
|
||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
|
||||
(bkt)++)\
|
||||
hlist_for_each_entry_rcu(obj, &name[bkt], member)
|
||||
|
||||
/**
|
||||
* hash_for_each_safe - iterate over a hashtable safe against removal of
|
||||
* hash entry
|
||||
* @name: hashtable to iterate
|
||||
* @bkt: integer to use as bucket loop cursor
|
||||
* @tmp: a &struct hlist_node used for temporary storage
|
||||
* @obj: the type * to use as a loop cursor for each entry
|
||||
* @member: the name of the hlist_node within the struct
|
||||
*/
|
||||
#define hash_for_each_safe(name, bkt, tmp, obj, member) \
|
||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
|
||||
(bkt)++)\
|
||||
hlist_for_each_entry_safe(obj, tmp, &name[bkt], member)
|
||||
|
||||
/**
|
||||
* hash_for_each_possible - iterate over all possible objects hashing to the
|
||||
* same bucket
|
||||
* @name: hashtable to iterate
|
||||
* @obj: the type * to use as a loop cursor for each entry
|
||||
* @member: the name of the hlist_node within the struct
|
||||
* @key: the key of the objects to iterate over
|
||||
*/
|
||||
#define hash_for_each_possible(name, obj, member, key) \
|
||||
hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member)
|
||||
|
||||
/**
|
||||
* hash_for_each_possible_rcu - iterate over all possible objects hashing to the
|
||||
* same bucket in an rcu enabled hashtable
|
||||
* @name: hashtable to iterate
|
||||
* @obj: the type * to use as a loop cursor for each entry
|
||||
* @member: the name of the hlist_node within the struct
|
||||
* @key: the key of the objects to iterate over
|
||||
*/
|
||||
#define hash_for_each_possible_rcu(name, obj, member, key, cond...) \
|
||||
hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\
|
||||
member, ## cond)
|
||||
|
||||
/**
|
||||
* hash_for_each_possible_rcu_notrace - iterate over all possible objects hashing
|
||||
* to the same bucket in an rcu enabled hashtable in a rcu enabled hashtable
|
||||
* @name: hashtable to iterate
|
||||
* @obj: the type * to use as a loop cursor for each entry
|
||||
* @member: the name of the hlist_node within the struct
|
||||
* @key: the key of the objects to iterate over
|
||||
*
|
||||
* This is the same as hash_for_each_possible_rcu() except that it does
|
||||
* not do any RCU debugging or tracing.
|
||||
*/
|
||||
#define hash_for_each_possible_rcu_notrace(name, obj, member, key) \
|
||||
hlist_for_each_entry_rcu_notrace(obj, \
|
||||
&name[hash_min(key, HASH_BITS(name))], member)
|
||||
|
||||
/**
|
||||
* hash_for_each_possible_safe - iterate over all possible objects hashing to the
|
||||
* same bucket safe against removals
|
||||
* @name: hashtable to iterate
|
||||
* @obj: the type * to use as a loop cursor for each entry
|
||||
* @tmp: a &struct hlist_node used for temporary storage
|
||||
* @member: the name of the hlist_node within the struct
|
||||
* @key: the key of the objects to iterate over
|
||||
*/
|
||||
#define hash_for_each_possible_safe(name, obj, tmp, member, key) \
|
||||
hlist_for_each_entry_safe(obj, tmp,\
|
||||
&name[hash_min(key, HASH_BITS(name))], member)
|
||||
|
||||
|
||||
#endif
|
18
2019/include/likely.h
Normal file
18
2019/include/likely.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/* taken from Kernel's <linux/compiler.h
|
||||
*/
|
||||
#ifndef __LIKELY_H
|
||||
#define __LIKELY_H
|
||||
|
||||
/* See https://kernelnewbies.org/FAQ/LikelyUnlikely
|
||||
*
|
||||
* In 2 words:
|
||||
* "You should use it [likely() and unlikely()] only in cases when the likeliest
|
||||
* branch is very very very likely, or when the unlikeliest branch is very very
|
||||
* very unlikely."
|
||||
*/
|
||||
# define likely(x) __builtin_expect(!!(x), 1)
|
||||
# define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
#endif /* __LIKELY_H */
|
992
2019/include/list.h
Normal file
992
2019/include/list.h
Normal file
@@ -0,0 +1,992 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/* adaptation of kernel's <linux/list.h>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BR_LIST_H
|
||||
#define __BR_LIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "rwonce.h"
|
||||
#include "container-of.h"
|
||||
|
||||
/************ originally in <include/linux/types.h> */
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
struct hlist_head {
|
||||
struct hlist_node *first;
|
||||
};
|
||||
|
||||
struct hlist_node {
|
||||
struct hlist_node *next, **pprev;
|
||||
};
|
||||
|
||||
/************ originally in <include/linux/poison.h> */
|
||||
# define POISON_POINTER_DELTA 0
|
||||
/* These are non-NULL pointers that will result in page faults
|
||||
* under normal circumstances, used to verify that nobody uses
|
||||
* non-initialized list entries.
|
||||
*/
|
||||
#define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA)
|
||||
#define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA)
|
||||
|
||||
/*
|
||||
* Circular doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
/**
|
||||
* INIT_LIST_HEAD - Initialize a list_head structure
|
||||
* @list: list_head structure to be initialized.
|
||||
*
|
||||
* Initializes the list_head to point to itself. If it is a list header,
|
||||
* the result is an empty list.
|
||||
*/
|
||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||
{
|
||||
WRITE_ONCE(list->next, list);
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
WRITE_ONCE(prev->next, new);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
WRITE_ONCE(prev->next, next);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry and clear the 'prev' pointer.
|
||||
*
|
||||
* This is a special-purpose list clearing method used in the networking code
|
||||
* for lists allocated as per-cpu, where we don't want to incur the extra
|
||||
* WRITE_ONCE() overhead of a regular list_del_init(). The code that uses this
|
||||
* needs to check the node 'prev' pointer instead of calling list_empty().
|
||||
*/
|
||||
static inline void __list_del_clearprev(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->prev = NULL;
|
||||
}
|
||||
|
||||
static inline void __list_del_entry(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty() on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del_entry(entry);
|
||||
entry->next = LIST_POISON1;
|
||||
entry->prev = LIST_POISON2;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_replace - replace old entry by new one
|
||||
* @old : the element to be replaced
|
||||
* @new : the new element to insert
|
||||
*
|
||||
* If @old was empty, it will be overwritten.
|
||||
*/
|
||||
static inline void list_replace(struct list_head *old,
|
||||
struct list_head *new)
|
||||
{
|
||||
new->next = old->next;
|
||||
new->next->prev = new;
|
||||
new->prev = old->prev;
|
||||
new->prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_replace_init - replace old entry by new one and initialize the old one
|
||||
* @old : the element to be replaced
|
||||
* @new : the new element to insert
|
||||
*
|
||||
* If @old was empty, it will be overwritten.
|
||||
*/
|
||||
static inline void list_replace_init(struct list_head *old,
|
||||
struct list_head *new)
|
||||
{
|
||||
list_replace(old, new);
|
||||
INIT_LIST_HEAD(old);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position
|
||||
* @entry1: the location to place entry2
|
||||
* @entry2: the location to place entry1
|
||||
*/
|
||||
static inline void list_swap(struct list_head *entry1,
|
||||
struct list_head *entry2)
|
||||
{
|
||||
struct list_head *pos = entry2->prev;
|
||||
|
||||
list_del(entry2);
|
||||
list_replace(entry1, entry2);
|
||||
if (pos == entry1)
|
||||
pos = entry2;
|
||||
list_add(entry1, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del_entry(entry);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
*/
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
__list_del_entry(list);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
*/
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del_entry(list);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_bulk_move_tail - move a subsection of a list to its tail
|
||||
* @head: the head that will follow our entry
|
||||
* @first: first entry to move
|
||||
* @last: last entry to move, can be the same as first
|
||||
*
|
||||
* Move all entries between @first and including @last before @head.
|
||||
* All three entries must belong to the same linked list.
|
||||
*/
|
||||
static inline void list_bulk_move_tail(struct list_head *head,
|
||||
struct list_head *first,
|
||||
struct list_head *last)
|
||||
{
|
||||
first->prev->next = last->next;
|
||||
last->next->prev = first->prev;
|
||||
|
||||
head->prev->next = first;
|
||||
first->prev = head->prev;
|
||||
|
||||
last->next = head;
|
||||
head->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_is_first -- tests whether @list is the first entry in list @head
|
||||
* @list: the entry to test
|
||||
* @head: the head of the list
|
||||
*/
|
||||
static inline int list_is_first(const struct list_head *list,
|
||||
const struct list_head *head)
|
||||
{
|
||||
return list->prev == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_is_last - tests whether @list is the last entry in list @head
|
||||
* @list: the entry to test
|
||||
* @head: the head of the list
|
||||
*/
|
||||
static inline int list_is_last(const struct list_head *list,
|
||||
const struct list_head *head)
|
||||
{
|
||||
return list->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return READ_ONCE(head->next) == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_rotate_left - rotate the list to the left
|
||||
* @head: the head of the list
|
||||
*/
|
||||
static inline void list_rotate_left(struct list_head *head)
|
||||
{
|
||||
struct list_head *first;
|
||||
|
||||
if (!list_empty(head)) {
|
||||
first = head->next;
|
||||
list_move_tail(first, head);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_rotate_to_front() - Rotate list to specific item.
|
||||
* @list: The desired new front of the list.
|
||||
* @head: The head of the list.
|
||||
*
|
||||
* Rotates list so that @list becomes the new front of the list.
|
||||
*/
|
||||
static inline void list_rotate_to_front(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
/*
|
||||
* Deletes the list head from the list denoted by @head and
|
||||
* places it as the tail of @list, this effectively rotates the
|
||||
* list so that @list is at the front.
|
||||
*/
|
||||
list_move_tail(head, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_is_singular - tests whether a list has just one entry.
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_is_singular(const struct list_head *head)
|
||||
{
|
||||
return !list_empty(head) && (head->next == head->prev);
|
||||
}
|
||||
|
||||
static inline void __list_cut_position(struct list_head *list,
|
||||
struct list_head *head, struct list_head *entry)
|
||||
{
|
||||
struct list_head *new_first = entry->next;
|
||||
list->next = head->next;
|
||||
list->next->prev = list;
|
||||
list->prev = entry;
|
||||
entry->next = list;
|
||||
head->next = new_first;
|
||||
new_first->prev = head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_cut_position - cut a list into two
|
||||
* @list: a new list to add all removed entries
|
||||
* @head: a list with entries
|
||||
* @entry: an entry within head, could be the head itself
|
||||
* and if so we won't cut the list
|
||||
*
|
||||
* This helper moves the initial part of @head, up to and
|
||||
* including @entry, from @head to @list. You should
|
||||
* pass on @entry an element you know is on @head. @list
|
||||
* should be an empty list or a list you do not care about
|
||||
* losing its data.
|
||||
*
|
||||
*/
|
||||
static inline void list_cut_position(struct list_head *list,
|
||||
struct list_head *head, struct list_head *entry)
|
||||
{
|
||||
if (list_empty(head))
|
||||
return;
|
||||
if (list_is_singular(head) &&
|
||||
(head->next != entry && head != entry))
|
||||
return;
|
||||
if (entry == head)
|
||||
INIT_LIST_HEAD(list);
|
||||
else
|
||||
__list_cut_position(list, head, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_cut_before - cut a list into two, before given entry
|
||||
* @list: a new list to add all removed entries
|
||||
* @head: a list with entries
|
||||
* @entry: an entry within head, could be the head itself
|
||||
*
|
||||
* This helper moves the initial part of @head, up to but
|
||||
* excluding @entry, from @head to @list. You should pass
|
||||
* in @entry an element you know is on @head. @list should
|
||||
* be an empty list or a list you do not care about losing
|
||||
* its data.
|
||||
* If @entry == @head, all entries on @head are moved to
|
||||
* @list.
|
||||
*/
|
||||
static inline void list_cut_before(struct list_head *list,
|
||||
struct list_head *head,
|
||||
struct list_head *entry)
|
||||
{
|
||||
if (head->next == entry) {
|
||||
INIT_LIST_HEAD(list);
|
||||
return;
|
||||
}
|
||||
list->next = head->next;
|
||||
list->next->prev = list;
|
||||
list->prev = entry->prev;
|
||||
list->prev->next = list;
|
||||
head->next = entry;
|
||||
entry->prev = head;
|
||||
}
|
||||
|
||||
static inline void __list_splice(const struct list_head *list,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
|
||||
first->prev = prev;
|
||||
prev->next = first;
|
||||
|
||||
last->next = next;
|
||||
next->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists, this is designed for stacks
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice(const struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_tail - join two lists, each list being a queue
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head->prev, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head, head->next);
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_tail_init - join two lists and reinitialise the emptied list
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* Each of the lists is a queue.
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_tail_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head->prev, head);
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* list_first_entry - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
|
||||
/**
|
||||
* list_last_entry - get the last element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_last_entry(ptr, type, member) \
|
||||
list_entry((ptr)->prev, type, member)
|
||||
|
||||
/**
|
||||
* list_first_entry_or_null - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Note that if the list is empty, it returns NULL.
|
||||
*/
|
||||
#define list_first_entry_or_null(ptr, type, member) ({ \
|
||||
struct list_head *head__ = (ptr); \
|
||||
struct list_head *pos__ = READ_ONCE(head__->next); \
|
||||
pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
|
||||
})
|
||||
|
||||
/**
|
||||
* list_next_entry - get the next element in list
|
||||
* @pos: the type * to cursor
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_next_entry(pos, member) \
|
||||
list_entry((pos)->member.next, __typeof__(*(pos)), member)
|
||||
|
||||
/**
|
||||
* list_prev_entry - get the prev element in list
|
||||
* @pos: the type * to cursor
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_prev_entry(pos, member) \
|
||||
list_entry((pos)->member.prev, __typeof__(*(pos)), member)
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_continue - continue iteration over a list
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*
|
||||
* Continue to iterate over a list, continuing after the current position.
|
||||
*/
|
||||
#define list_for_each_continue(pos, head) \
|
||||
for (pos = pos->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_prev - iterate over a list backwards
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev; pos != (head); pos = pos->prev)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev_safe(pos, n, head) \
|
||||
for (pos = (head)->prev, n = pos->prev; \
|
||||
pos != (head); \
|
||||
pos = n, n = pos->prev)
|
||||
|
||||
/**
|
||||
* list_entry_is_head - test if the entry points to the head of the list
|
||||
* @pos: the type * to cursor
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_entry_is_head(pos, head, member) \
|
||||
(&pos->member == (head))
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_first_entry(head, __typeof__(*pos), member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = list_next_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = list_last_entry(head, __typeof__(*pos), member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = list_prev_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
||||
* @pos: the type * to use as a start point
|
||||
* @head: the head of the list
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
|
||||
*/
|
||||
#define list_prepare_entry(pos, head, member) \
|
||||
((pos) ? : list_entry(head, __typeof__(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue - continue iteration over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Continue to iterate over list of given type, continuing after
|
||||
* the current position.
|
||||
*/
|
||||
#define list_for_each_entry_continue(pos, head, member) \
|
||||
for (pos = list_next_entry(pos, member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = list_next_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue_reverse - iterate backwards from the given point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Start to iterate over list of given type backwards, continuing after
|
||||
* the current position.
|
||||
*/
|
||||
#define list_for_each_entry_continue_reverse(pos, head, member) \
|
||||
for (pos = list_prev_entry(pos, member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = list_prev_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_from - iterate over list of given type from the current point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Iterate over list of given type, continuing from current position.
|
||||
*/
|
||||
#define list_for_each_entry_from(pos, head, member) \
|
||||
for (; !list_entry_is_head(pos, head, member); \
|
||||
pos = list_next_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_from_reverse - iterate backwards over list of given type
|
||||
* from the current point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Iterate backwards over list of given type, continuing from current position.
|
||||
*/
|
||||
#define list_for_each_entry_from_reverse(pos, head, member) \
|
||||
for (; !list_entry_is_head(pos, head, member); \
|
||||
pos = list_prev_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_first_entry(head, __typeof__(*pos), member), \
|
||||
n = list_next_entry(pos, member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = n, n = list_next_entry(n, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_continue - continue list iteration safe against removal
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Iterate over list of given type, continuing after current point,
|
||||
* safe against removal of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
||||
for (pos = list_next_entry(pos, member), \
|
||||
n = list_next_entry(pos, member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = n, n = list_next_entry(n, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_from - iterate over list from current point safe against removal
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Iterate over list of given type from current point, safe against
|
||||
* removal of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_from(pos, n, head, member) \
|
||||
for (n = list_next_entry(pos, member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = n, n = list_next_entry(n, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Iterate backwards over list of given type, safe against removal
|
||||
* of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
||||
for (pos = list_last_entry(head, __typeof__(*pos), member), \
|
||||
n = list_prev_entry(pos, member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = n, n = list_prev_entry(n, member))
|
||||
|
||||
/**
|
||||
* list_safe_reset_next - reset a stale list_for_each_entry_safe loop
|
||||
* @pos: the loop cursor used in the list_for_each_entry_safe loop
|
||||
* @n: temporary storage used in list_for_each_entry_safe
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* list_safe_reset_next is not safe to use in general if the list may be
|
||||
* modified concurrently (eg. the lock is dropped in the loop body). An
|
||||
* exception to this is if the cursor element (pos) is pinned in the list,
|
||||
* and list_safe_reset_next is called after re-taking the lock and before
|
||||
* completing the current iteration of the loop body.
|
||||
*/
|
||||
#define list_safe_reset_next(pos, n, member) \
|
||||
n = list_next_entry(pos, member)
|
||||
|
||||
/*
|
||||
* Double linked lists with a single pointer list head.
|
||||
* Mostly useful for hash tables where the two pointer list head is
|
||||
* too wasteful.
|
||||
* You lose the ability to access the tail in O(1).
|
||||
*/
|
||||
|
||||
#define HLIST_HEAD_INIT { .first = NULL }
|
||||
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
|
||||
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
|
||||
static inline void INIT_HLIST_NODE(struct hlist_node *h)
|
||||
{
|
||||
h->next = NULL;
|
||||
h->pprev = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_unhashed - Has node been removed from list and reinitialized?
|
||||
* @h: Node to be checked
|
||||
*
|
||||
* Not that not all removal functions will leave a node in unhashed
|
||||
* state. For example, hlist_nulls_del_init_rcu() does leave the
|
||||
* node in unhashed state, but hlist_nulls_del() does not.
|
||||
*/
|
||||
static inline int hlist_unhashed(const struct hlist_node *h)
|
||||
{
|
||||
return !h->pprev;
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_unhashed_lockless - Version of hlist_unhashed for lockless use
|
||||
* @h: Node to be checked
|
||||
*
|
||||
* This variant of hlist_unhashed() must be used in lockless contexts
|
||||
* to avoid potential load-tearing. The READ_ONCE() is paired with the
|
||||
* various WRITE_ONCE() in hlist helpers that are defined below.
|
||||
*/
|
||||
static inline int hlist_unhashed_lockless(const struct hlist_node *h)
|
||||
{
|
||||
return !READ_ONCE(h->pprev);
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_empty - Is the specified hlist_head structure an empty hlist?
|
||||
* @h: Structure to check.
|
||||
*/
|
||||
static inline int hlist_empty(const struct hlist_head *h)
|
||||
{
|
||||
return !READ_ONCE(h->first);
|
||||
}
|
||||
|
||||
static inline void __hlist_del(struct hlist_node *n)
|
||||
{
|
||||
struct hlist_node *next = n->next;
|
||||
struct hlist_node **pprev = n->pprev;
|
||||
|
||||
WRITE_ONCE(*pprev, next);
|
||||
if (next)
|
||||
WRITE_ONCE(next->pprev, pprev);
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_del - Delete the specified hlist_node from its list
|
||||
* @n: Node to delete.
|
||||
*
|
||||
* Note that this function leaves the node in hashed state. Use
|
||||
* hlist_del_init() or similar instead to unhash @n.
|
||||
*/
|
||||
static inline void hlist_del(struct hlist_node *n)
|
||||
{
|
||||
__hlist_del(n);
|
||||
n->next = LIST_POISON1;
|
||||
n->pprev = LIST_POISON2;
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_del_init - Delete the specified hlist_node from its list and initialize
|
||||
* @n: Node to delete.
|
||||
*
|
||||
* Note that this function leaves the node in unhashed state.
|
||||
*/
|
||||
static inline void hlist_del_init(struct hlist_node *n)
|
||||
{
|
||||
if (!hlist_unhashed(n)) {
|
||||
__hlist_del(n);
|
||||
INIT_HLIST_NODE(n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_add_head - add a new entry at the beginning of the hlist
|
||||
* @n: new entry to be added
|
||||
* @h: hlist head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
||||
{
|
||||
struct hlist_node *first = h->first;
|
||||
WRITE_ONCE(n->next, first);
|
||||
if (first)
|
||||
WRITE_ONCE(first->pprev, &n->next);
|
||||
WRITE_ONCE(h->first, n);
|
||||
WRITE_ONCE(n->pprev, &h->first);
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_add_before - add a new entry before the one specified
|
||||
* @n: new entry to be added
|
||||
* @next: hlist node to add it before, which must be non-NULL
|
||||
*/
|
||||
static inline void hlist_add_before(struct hlist_node *n,
|
||||
struct hlist_node *next)
|
||||
{
|
||||
WRITE_ONCE(n->pprev, next->pprev);
|
||||
WRITE_ONCE(n->next, next);
|
||||
WRITE_ONCE(next->pprev, &n->next);
|
||||
WRITE_ONCE(*(n->pprev), n);
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_add_behind - add a new entry after the one specified
|
||||
* @n: new entry to be added
|
||||
* @prev: hlist node to add it after, which must be non-NULL
|
||||
*/
|
||||
static inline void hlist_add_behind(struct hlist_node *n,
|
||||
struct hlist_node *prev)
|
||||
{
|
||||
WRITE_ONCE(n->next, prev->next);
|
||||
WRITE_ONCE(prev->next, n);
|
||||
WRITE_ONCE(n->pprev, &prev->next);
|
||||
|
||||
if (n->next)
|
||||
WRITE_ONCE(n->next->pprev, &n->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_add_fake - create a fake hlist consisting of a single headless node
|
||||
* @n: Node to make a fake list out of
|
||||
*
|
||||
* This makes @n appear to be its own predecessor on a headless hlist.
|
||||
* The point of this is to allow things like hlist_del() to work correctly
|
||||
* in cases where there is no list.
|
||||
*/
|
||||
static inline void hlist_add_fake(struct hlist_node *n)
|
||||
{
|
||||
n->pprev = &n->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_fake: Is this node a fake hlist?
|
||||
* @h: Node to check for being a self-referential fake hlist.
|
||||
*/
|
||||
static inline bool hlist_fake(struct hlist_node *h)
|
||||
{
|
||||
return h->pprev == &h->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_is_singular_node - is node the only element of the specified hlist?
|
||||
* @n: Node to check for singularity.
|
||||
* @h: Header for potentially singular list.
|
||||
*
|
||||
* Check whether the node is the only node of the head without
|
||||
* accessing head, thus avoiding unnecessary cache misses.
|
||||
*/
|
||||
static inline bool
|
||||
hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)
|
||||
{
|
||||
return !n->next && n->pprev == &h->first;
|
||||
}
|
||||
|
||||
/**
|
||||
* hlist_move_list - Move an hlist
|
||||
* @old: hlist_head for old list.
|
||||
* @new: hlist_head for new list.
|
||||
*
|
||||
* Move a list from one list head to another. Fixup the pprev
|
||||
* reference of the first entry if it exists.
|
||||
*/
|
||||
static inline void hlist_move_list(struct hlist_head *old,
|
||||
struct hlist_head *new)
|
||||
{
|
||||
new->first = old->first;
|
||||
if (new->first)
|
||||
new->first->pprev = &new->first;
|
||||
old->first = NULL;
|
||||
}
|
||||
|
||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
||||
|
||||
#define hlist_for_each(pos, head) \
|
||||
for (pos = (head)->first; pos ; pos = pos->next)
|
||||
|
||||
#define hlist_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
||||
pos = n)
|
||||
|
||||
#define hlist_entry_safe(ptr, type, member) \
|
||||
({ __typeof__(ptr) ____ptr = (ptr); \
|
||||
____ptr ? hlist_entry(____ptr, type, member) : NULL; \
|
||||
})
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry(pos, head, member) \
|
||||
for (pos = hlist_entry_safe((head)->first, __typeof__(*(pos)), member); \
|
||||
pos; \
|
||||
pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member))
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_continue(pos, member) \
|
||||
for (pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member); \
|
||||
pos; \
|
||||
pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member))
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_from(pos, member) \
|
||||
for (; pos; \
|
||||
pos = hlist_entry_safe((pos)->member.next, __typeof__(*(pos)), member))
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: a &struct hlist_node to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = hlist_entry_safe((head)->first, __typeof__(*pos), member); \
|
||||
pos && ({ n = pos->member.next; 1; }); \
|
||||
pos = hlist_entry_safe(n, __typeof__(*pos), member))
|
||||
|
||||
#endif /* __BR_LIST_H */
|
301
2019/include/plist.h
Normal file
301
2019/include/plist.h
Normal file
@@ -0,0 +1,301 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Descending-priority-sorted double-linked list
|
||||
*
|
||||
* (C) 2002-2003 Intel Corp
|
||||
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
|
||||
*
|
||||
* 2001-2005 (c) MontaVista Software, Inc.
|
||||
* Daniel Walker <dwalker@mvista.com>
|
||||
*
|
||||
* (C) 2005 Thomas Gleixner <tglx@linutronix.de>
|
||||
*
|
||||
* Simplifications of the original code by
|
||||
* Oleg Nesterov <oleg@tv-sign.ru>
|
||||
*
|
||||
* Based on simple lists (include/linux/list.h).
|
||||
*
|
||||
* This is a priority-sorted list of nodes; each node has a
|
||||
* priority from INT_MIN (highest) to INT_MAX (lowest).
|
||||
*
|
||||
* Addition is O(K), removal is O(1), change of priority of a node is
|
||||
* O(K) and K is the number of RT priority levels used in the system.
|
||||
* (1 <= K <= 99)
|
||||
*
|
||||
* This list is really a list of lists:
|
||||
*
|
||||
* - The tier 1 list is the prio_list, different priority nodes.
|
||||
*
|
||||
* - The tier 2 list is the node_list, serialized nodes.
|
||||
*
|
||||
* Simple ASCII art explanation:
|
||||
*
|
||||
* pl:prio_list (only for plist_node)
|
||||
* nl:node_list
|
||||
* HEAD| NODE(S)
|
||||
* |
|
||||
* ||------------------------------------|
|
||||
* ||->|pl|<->|pl|<--------------->|pl|<-|
|
||||
* | |10| |21| |21| |21| |40| (prio)
|
||||
* | | | | | | | | | | |
|
||||
* | | | | | | | | | | |
|
||||
* |->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
|
||||
* |-------------------------------------------|
|
||||
*
|
||||
* The nodes on the prio_list list are sorted by priority to simplify
|
||||
* the insertion of new nodes. There are no nodes with duplicate
|
||||
* priorites on the list.
|
||||
*
|
||||
* The nodes on the node_list are ordered by priority and can contain
|
||||
* entries which have the same priority. Those entries are ordered
|
||||
* FIFO
|
||||
*
|
||||
* Addition means: look for the prio_list node in the prio_list
|
||||
* for the priority of the node and insert it before the node_list
|
||||
* entry of the next prio_list node. If it is the first node of
|
||||
* that priority, add it to the prio_list in the right position and
|
||||
* insert it into the serialized node_list list
|
||||
*
|
||||
* Removal means remove it from the node_list and remove it from
|
||||
* the prio_list if the node_list list_head is non empty. In case
|
||||
* of removal from the prio_list it must be checked whether other
|
||||
* entries of the same priority are on the list or not. If there
|
||||
* is another entry of the same priority then this entry has to
|
||||
* replace the removed entry on the prio_list. If the entry which
|
||||
* is removed is the only entry of this priority then a simple
|
||||
* remove from both list is sufficient.
|
||||
*
|
||||
* INT_MIN is the highest priority, 0 is the medium highest, INT_MAX
|
||||
* is lowest priority.
|
||||
*
|
||||
* No locking is done, up to the caller.
|
||||
*/
|
||||
#ifndef _LINUX_PLIST_H_
|
||||
#define _LINUX_PLIST_H_
|
||||
|
||||
#include "container-of.h"
|
||||
#include "list.h"
|
||||
//#include <types.h>
|
||||
|
||||
// #include <asm/bug.h>
|
||||
|
||||
struct plist_head {
|
||||
struct list_head node_list;
|
||||
};
|
||||
|
||||
struct plist_node {
|
||||
int prio;
|
||||
struct list_head prio_list;
|
||||
struct list_head node_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* PLIST_HEAD_INIT - static struct plist_head initializer
|
||||
* @head: struct plist_head variable name
|
||||
*/
|
||||
#define PLIST_HEAD_INIT(head) \
|
||||
{ \
|
||||
.node_list = LIST_HEAD_INIT((head).node_list) \
|
||||
}
|
||||
|
||||
/**
|
||||
* PLIST_HEAD - declare and init plist_head
|
||||
* @head: name for struct plist_head variable
|
||||
*/
|
||||
#define PLIST_HEAD(head) \
|
||||
struct plist_head head = PLIST_HEAD_INIT(head)
|
||||
|
||||
/**
|
||||
* PLIST_NODE_INIT - static struct plist_node initializer
|
||||
* @node: struct plist_node variable name
|
||||
* @__prio: initial node priority
|
||||
*/
|
||||
#define PLIST_NODE_INIT(node, __prio) \
|
||||
{ \
|
||||
.prio = (__prio), \
|
||||
.prio_list = LIST_HEAD_INIT((node).prio_list), \
|
||||
.node_list = LIST_HEAD_INIT((node).node_list), \
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_head_init - dynamic struct plist_head initializer
|
||||
* @head: &struct plist_head pointer
|
||||
*/
|
||||
static inline void
|
||||
plist_head_init(struct plist_head *head)
|
||||
{
|
||||
INIT_LIST_HEAD(&head->node_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_node_init - Dynamic struct plist_node initializer
|
||||
* @node: &struct plist_node pointer
|
||||
* @prio: initial node priority
|
||||
*/
|
||||
static inline void plist_node_init(struct plist_node *node, int prio)
|
||||
{
|
||||
node->prio = prio;
|
||||
INIT_LIST_HEAD(&node->prio_list);
|
||||
INIT_LIST_HEAD(&node->node_list);
|
||||
}
|
||||
|
||||
extern void plist_add(struct plist_node *node, struct plist_head *head);
|
||||
extern void plist_del(struct plist_node *node, struct plist_head *head);
|
||||
|
||||
extern void plist_requeue(struct plist_node *node, struct plist_head *head);
|
||||
|
||||
/**
|
||||
* plist_for_each - iterate over the plist
|
||||
* @pos: the type * to use as a loop counter
|
||||
* @head: the head for your list
|
||||
*/
|
||||
#define plist_for_each(pos, head) \
|
||||
list_for_each_entry(pos, &(head)->node_list, node_list)
|
||||
|
||||
/**
|
||||
* plist_for_each_continue - continue iteration over the plist
|
||||
* @pos: the type * to use as a loop cursor
|
||||
* @head: the head for your list
|
||||
*
|
||||
* Continue to iterate over plist, continuing after the current position.
|
||||
*/
|
||||
#define plist_for_each_continue(pos, head) \
|
||||
list_for_each_entry_continue(pos, &(head)->node_list, node_list)
|
||||
|
||||
/**
|
||||
* plist_for_each_safe - iterate safely over a plist of given type
|
||||
* @pos: the type * to use as a loop counter
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list
|
||||
*
|
||||
* Iterate over a plist of given type, safe against removal of list entry.
|
||||
*/
|
||||
#define plist_for_each_safe(pos, n, head) \
|
||||
list_for_each_entry_safe(pos, n, &(head)->node_list, node_list)
|
||||
|
||||
/**
|
||||
* plist_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop counter
|
||||
* @head: the head for your list
|
||||
* @mem: the name of the list_head within the struct
|
||||
*/
|
||||
#define plist_for_each_entry(pos, head, mem) \
|
||||
list_for_each_entry(pos, &(head)->node_list, mem.node_list)
|
||||
|
||||
/**
|
||||
* plist_for_each_entry_continue - continue iteration over list of given type
|
||||
* @pos: the type * to use as a loop cursor
|
||||
* @head: the head for your list
|
||||
* @m: the name of the list_head within the struct
|
||||
*
|
||||
* Continue to iterate over list of given type, continuing after
|
||||
* the current position.
|
||||
*/
|
||||
#define plist_for_each_entry_continue(pos, head, m) \
|
||||
list_for_each_entry_continue(pos, &(head)->node_list, m.node_list)
|
||||
|
||||
/**
|
||||
* plist_for_each_entry_safe - iterate safely over list of given type
|
||||
* @pos: the type * to use as a loop counter
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list
|
||||
* @m: the name of the list_head within the struct
|
||||
*
|
||||
* Iterate over list of given type, safe against removal of list entry.
|
||||
*/
|
||||
#define plist_for_each_entry_safe(pos, n, head, m) \
|
||||
list_for_each_entry_safe(pos, n, &(head)->node_list, m.node_list)
|
||||
|
||||
/**
|
||||
* plist_head_empty - return !0 if a plist_head is empty
|
||||
* @head: &struct plist_head pointer
|
||||
*/
|
||||
static inline int plist_head_empty(const struct plist_head *head)
|
||||
{
|
||||
return list_empty(&head->node_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_node_empty - return !0 if plist_node is not on a list
|
||||
* @node: &struct plist_node pointer
|
||||
*/
|
||||
static inline int plist_node_empty(const struct plist_node *node)
|
||||
{
|
||||
return list_empty(&node->node_list);
|
||||
}
|
||||
|
||||
/* All functions below assume the plist_head is not empty. */
|
||||
|
||||
/**
|
||||
* plist_first_entry - get the struct for the first entry
|
||||
* @head: the &struct plist_head pointer
|
||||
* @type: the type of the struct this is embedded in
|
||||
* @member: the name of the list_head within the struct
|
||||
*/
|
||||
#ifdef CONFIG_DEBUG_PLIST
|
||||
# define plist_first_entry(head, type, member) \
|
||||
({ \
|
||||
WARN_ON(plist_head_empty(head)); \
|
||||
container_of(plist_first(head), type, member); \
|
||||
})
|
||||
#else
|
||||
# define plist_first_entry(head, type, member) \
|
||||
container_of(plist_first(head), type, member)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* plist_last_entry - get the struct for the last entry
|
||||
* @head: the &struct plist_head pointer
|
||||
* @type: the type of the struct this is embedded in
|
||||
* @member: the name of the list_head within the struct
|
||||
*/
|
||||
#ifdef CONFIG_DEBUG_PLIST
|
||||
# define plist_last_entry(head, type, member) \
|
||||
({ \
|
||||
WARN_ON(plist_head_empty(head)); \
|
||||
container_of(plist_last(head), type, member); \
|
||||
})
|
||||
#else
|
||||
# define plist_last_entry(head, type, member) \
|
||||
container_of(plist_last(head), type, member)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* plist_next - get the next entry in list
|
||||
* @pos: the type * to cursor
|
||||
*/
|
||||
#define plist_next(pos) \
|
||||
list_next_entry(pos, node_list)
|
||||
|
||||
/**
|
||||
* plist_prev - get the prev entry in list
|
||||
* @pos: the type * to cursor
|
||||
*/
|
||||
#define plist_prev(pos) \
|
||||
list_prev_entry(pos, node_list)
|
||||
|
||||
/**
|
||||
* plist_first - return the first node (and thus, highest priority)
|
||||
* @head: the &struct plist_head pointer
|
||||
*
|
||||
* Assumes the plist is _not_ empty.
|
||||
*/
|
||||
static inline struct plist_node *plist_first(const struct plist_head *head)
|
||||
{
|
||||
return list_entry(head->node_list.next,
|
||||
struct plist_node, node_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_last - return the last node (and thus, lowest priority)
|
||||
* @head: the &struct plist_head pointer
|
||||
*
|
||||
* Assumes the plist is _not_ empty.
|
||||
*/
|
||||
static inline struct plist_node *plist_last(const struct plist_head *head)
|
||||
{
|
||||
return list_entry(head->node_list.prev,
|
||||
struct plist_node, node_list);
|
||||
}
|
||||
|
||||
#endif
|
90
2019/include/pool.h
Normal file
90
2019/include/pool.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* pool.h - A simple memory pool manager.
|
||||
*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POOL_H
|
||||
#define POOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "list.h"
|
||||
#include "bits.h"
|
||||
|
||||
#define POOL_NAME_LENGTH (16) /* max name length including trailing \0 */
|
||||
|
||||
typedef struct {
|
||||
struct list_head list_blocks; /* list of allocated blocks in pool */
|
||||
char data[]; /* objects block */
|
||||
} block_t;
|
||||
|
||||
typedef struct {
|
||||
char name[POOL_NAME_LENGTH]; /* pool name */
|
||||
size_t eltsize; /* object size */
|
||||
u32 available; /* current available elements */
|
||||
u32 allocated; /* total objects allocated */
|
||||
u32 growsize; /* number of objects per block allocated */
|
||||
u32 nblocks; /* number of blocks allocated */
|
||||
struct list_head list_available; /* available nodes */
|
||||
struct list_head list_blocks; /* allocated blocks */
|
||||
} pool_t;
|
||||
|
||||
/**
|
||||
* pool_stats - display some pool statistics
|
||||
* @pool: the pool address.
|
||||
*/
|
||||
void pool_stats(pool_t *pool);
|
||||
|
||||
/**
|
||||
* pool_create - create a new memory pool
|
||||
* @name: the name to give to the pool.
|
||||
* @grow: the number of elements to add when no more available.
|
||||
* @size: the size of an element in pool.
|
||||
*
|
||||
* The name will be truncated to 16 characters (including the final '\0').
|
||||
*
|
||||
* Return: The address of the created pool, or NULL if error.
|
||||
*/
|
||||
pool_t *pool_create(const char *name, u32 grow, size_t size);
|
||||
|
||||
/**
|
||||
* pool_get() - Get an element from a pool.
|
||||
* @pool: The pool address.
|
||||
*
|
||||
* Get an object from the pool.
|
||||
*
|
||||
* Return: The address of the object, or NULL if error.
|
||||
*/
|
||||
void *pool_get(pool_t *pool);
|
||||
|
||||
/**
|
||||
* pool_add() - Add (free) an element to a pool.
|
||||
* @pool: The pool address.
|
||||
* @elt: The address of the object to add to the pool.
|
||||
*
|
||||
* The object will be available for further pool_get().
|
||||
*
|
||||
* Return: The current number of available elements in pool (including
|
||||
* @elt).
|
||||
*/
|
||||
u32 pool_add(pool_t *pool, void *elt);
|
||||
|
||||
/**
|
||||
* pool_destroy() - destroy a pool.
|
||||
* @pool: The pool address.
|
||||
*
|
||||
* Attention: All memory is freed, but no check is done whether all pool
|
||||
* elements have been released. Referencing any pool object after this call
|
||||
* will likely imply some memory corruption.
|
||||
*/
|
||||
void pool_destroy(pool_t *pool);
|
||||
|
||||
#endif
|
128
2019/include/rwonce.h
Normal file
128
2019/include/rwonce.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/* adaptation of kernel's <asm-generic/rwonce.h>
|
||||
* See https://www.kernel.org/doc/Documentation/memory-barriers.txt
|
||||
*/
|
||||
/*
|
||||
* Prevent the compiler from merging or refetching reads or writes. The
|
||||
* compiler is also forbidden from reordering successive instances of
|
||||
* READ_ONCE and WRITE_ONCE, but only when the compiler is aware of some
|
||||
* particular ordering. One way to make the compiler aware of ordering is to
|
||||
* put the two invocations of READ_ONCE or WRITE_ONCE in different C
|
||||
* statements.
|
||||
*
|
||||
* These two macros will also work on aggregate data types like structs or
|
||||
* unions.
|
||||
*
|
||||
* Their two major use cases are: (1) Mediating communication between
|
||||
* process-level code and irq/NMI handlers, all running on the same CPU,
|
||||
* and (2) Ensuring that the compiler does not fold, spindle, or otherwise
|
||||
* mutilate accesses that either do not require ordering or that interact
|
||||
* with an explicit memory barrier or atomic instruction that provides the
|
||||
* required ordering.
|
||||
*/
|
||||
#ifndef __BR_RWONCE_H
|
||||
#define __BR_RWONCE_H
|
||||
|
||||
/************ originally in <include/linux/compiler_attributes.h> */
|
||||
#if __has_attribute(__error__)
|
||||
# define __compiletime_error(msg) __attribute__((__error__(msg)))
|
||||
#else
|
||||
# define __compiletime_error(msg)
|
||||
#endif
|
||||
|
||||
/************ originally in <include/linux/compiler_types.h> */
|
||||
/*
|
||||
* __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving
|
||||
* non-scalar types unchanged.
|
||||
*/
|
||||
/*
|
||||
* Prefer C11 _Generic for better compile-times and simpler code. Note: 'char'
|
||||
* is not type-compatible with 'signed char', and we define a separate case.
|
||||
*/
|
||||
#define __scalar_type_to_expr_cases(type) \
|
||||
unsigned type: (unsigned type)0, \
|
||||
signed type: (signed type)0
|
||||
|
||||
#define __unqual_scalar_typeof(x) \
|
||||
typeof(_Generic((x), \
|
||||
char: (char)0, \
|
||||
__scalar_type_to_expr_cases(char), \
|
||||
__scalar_type_to_expr_cases(short), \
|
||||
__scalar_type_to_expr_cases(int), \
|
||||
__scalar_type_to_expr_cases(long), \
|
||||
__scalar_type_to_expr_cases(long long), \
|
||||
default: (x)))
|
||||
|
||||
/* Is this type a native word size -- useful for atomic operations */
|
||||
#define __native_word(t) \
|
||||
(sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \
|
||||
sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
|
||||
|
||||
#ifdef __OPTIMIZE__
|
||||
# define __compiletime_assert(condition, msg, prefix, suffix) \
|
||||
do { \
|
||||
extern void prefix ## suffix(void) __compiletime_error(msg); \
|
||||
if (!(condition)) \
|
||||
prefix ## suffix(); \
|
||||
} while (0)
|
||||
#else
|
||||
# define __compiletime_assert(condition, msg, prefix, suffix) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define _compiletime_assert(condition, msg, prefix, suffix) \
|
||||
__compiletime_assert(condition, msg, prefix, suffix)
|
||||
|
||||
/**
|
||||
* compiletime_assert - break build and emit msg if condition is false
|
||||
* @condition: a compile-time constant condition to check
|
||||
* @msg: a message to emit if condition is false
|
||||
*
|
||||
* In tradition of POSIX assert, this macro will break the build if the
|
||||
* supplied condition is *false*, emitting the supplied error message if the
|
||||
* compiler has support to do so.
|
||||
*/
|
||||
#define compiletime_assert(condition, msg) \
|
||||
_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
|
||||
|
||||
#define compiletime_assert_atomic_type(t) \
|
||||
compiletime_assert(__native_word(t), \
|
||||
"Need native word sized stores/loads for atomicity.")
|
||||
|
||||
/************ originally in <asm-generic/rwonce.h> */
|
||||
/*
|
||||
* Yes, this permits 64-bit accesses on 32-bit architectures. These will
|
||||
* actually be atomic in some cases (namely Armv7 + LPAE), but for others we
|
||||
* rely on the access being split into 2x32-bit accesses for a 32-bit quantity
|
||||
* (e.g. a virtual address) and a strong prevailing wind.
|
||||
*/
|
||||
#define compiletime_assert_rwonce_type(t) \
|
||||
compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
|
||||
"Unsupported access size for {READ,WRITE}_ONCE().")
|
||||
|
||||
/*
|
||||
* Use __READ_ONCE() instead of READ_ONCE() if you do not require any
|
||||
* atomicity. Note that this may result in tears!
|
||||
*/
|
||||
#ifndef __READ_ONCE
|
||||
#define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
|
||||
#endif
|
||||
|
||||
#define READ_ONCE(x) \
|
||||
({ \
|
||||
compiletime_assert_rwonce_type(x); \
|
||||
__READ_ONCE(x); \
|
||||
})
|
||||
|
||||
#define __WRITE_ONCE(x, val) \
|
||||
do { \
|
||||
*(volatile typeof(x) *)&(x) = (val); \
|
||||
} while (0)
|
||||
|
||||
#define WRITE_ONCE(x, val) \
|
||||
do { \
|
||||
compiletime_assert_rwonce_type(x); \
|
||||
__WRITE_ONCE(x, val); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __BR_RWONCE_H */
|
111
2019/libsrc/debug.c
Normal file
111
2019/libsrc/debug.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/* debug.c - debug/log management
|
||||
*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef DEBUG_DEBUG
|
||||
#define DEBUG_DEBUG
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define NANOSEC 1000000000 /* nano sec in sec */
|
||||
#define MILLISEC 1000000 /* milli sec in sec */
|
||||
|
||||
static s64 timer_start; /* in nanosecond */
|
||||
static u32 debug_level=0;
|
||||
|
||||
void debug_level_set(u32 level)
|
||||
{
|
||||
debug_level = level;
|
||||
|
||||
log(1, "debug level set to %u\n", level);
|
||||
}
|
||||
|
||||
void debug_init(u32 level)
|
||||
{
|
||||
struct timespec timer;
|
||||
|
||||
debug_level_set(level);
|
||||
if (!clock_gettime(CLOCK_MONOTONIC, &timer)) {
|
||||
timer_start = timer.tv_sec * NANOSEC + timer.tv_nsec;
|
||||
}
|
||||
else {
|
||||
timer_start = 0;
|
||||
}
|
||||
log(0, "timer started.\n");
|
||||
}
|
||||
|
||||
inline static s64 timer_elapsed()
|
||||
{
|
||||
struct timespec timer;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &timer);
|
||||
return (timer.tv_sec * NANOSEC + timer.tv_nsec) - timer_start;
|
||||
}
|
||||
|
||||
|
||||
/* void debug - log function
|
||||
* @timestamp : boolean
|
||||
* @indent : indent level (2 spaces each)
|
||||
* @src : source file/func name (or NULL)
|
||||
* @line : line number
|
||||
*/
|
||||
void debug(u32 level, bool timestamp, u32 indent, const char *src,
|
||||
u32 line, const char *fmt, ...)
|
||||
{
|
||||
if (level > debug_level)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
|
||||
if (indent)
|
||||
printf("%*s", 2*(indent-1), "");
|
||||
|
||||
if (timestamp) {
|
||||
s64 diff = timer_elapsed();
|
||||
printf("%ld.%03ld ", diff/NANOSEC, (diff/1000000)%1000);
|
||||
printf("%010ld ", diff);
|
||||
}
|
||||
|
||||
if (src) {
|
||||
if (line)
|
||||
printf("[%s:%u] ", src, line);
|
||||
else
|
||||
printf("[%s] ", src);
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef BIN_debug
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int foo=1;
|
||||
debug_init(5);
|
||||
|
||||
log(0, "log0=%d\n", foo++);
|
||||
log(1, "log1=%d\n", foo++);
|
||||
log(2, "log2=%d\n", foo++);
|
||||
log_i(2, "log_i 2=%d\n", foo++);
|
||||
log_i(5, "log_i 5=%d\n", foo++);
|
||||
log_i(6, "log_i 6=%d\n", foo++);
|
||||
log_it(4, "log_it 4=%d\n", foo++);
|
||||
log_f(1, "log_f 5=%d\n", foo++);
|
||||
}
|
||||
#endif
|
173
2019/libsrc/plist.c
Normal file
173
2019/libsrc/plist.c
Normal file
@@ -0,0 +1,173 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* adapted from Linux kernel lib/plist.c
|
||||
*
|
||||
* Descending-priority-sorted double-linked list
|
||||
*
|
||||
* (C) 2002-2003 Intel Corp
|
||||
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
|
||||
*
|
||||
* 2001-2005 (c) MontaVista Software, Inc.
|
||||
* Daniel Walker <dwalker@mvista.com>
|
||||
*
|
||||
* (C) 2005 Thomas Gleixner <tglx@linutronix.de>
|
||||
*
|
||||
* Simplifications of the original code by
|
||||
* Oleg Nesterov <oleg@tv-sign.ru>
|
||||
*
|
||||
* Based on simple lists (include/linux/list.h).
|
||||
*
|
||||
* This file contains the add / del functions which are considered to
|
||||
* be too large to inline. See include/linux/plist.h for further
|
||||
* information.
|
||||
*/
|
||||
|
||||
#include "plist.h"
|
||||
#include "bug.h"
|
||||
|
||||
#ifdef DEBUG_PLIST
|
||||
|
||||
static struct plist_head test_head;
|
||||
|
||||
static void plist_check_prev_next(struct list_head *t, struct list_head *p,
|
||||
struct list_head *n)
|
||||
{
|
||||
WARN(n->prev != p || p->next != n,
|
||||
"top: %p, n: %p, p: %p\n"
|
||||
"prev: %p, n: %p, p: %p\n"
|
||||
"next: %p, n: %p, p: %p\n",
|
||||
t, t->next, t->prev,
|
||||
p, p->next, p->prev,
|
||||
n, n->next, n->prev);
|
||||
}
|
||||
|
||||
static void plist_check_list(struct list_head *top)
|
||||
{
|
||||
struct list_head *prev = top, *next = top->next;
|
||||
|
||||
plist_check_prev_next(top, prev, next);
|
||||
while (next != top) {
|
||||
prev = next;
|
||||
next = prev->next;
|
||||
plist_check_prev_next(top, prev, next);
|
||||
}
|
||||
}
|
||||
|
||||
static void plist_check_head(struct plist_head *head)
|
||||
{
|
||||
if (!plist_head_empty(head))
|
||||
plist_check_list(&plist_first(head)->prio_list);
|
||||
plist_check_list(&head->node_list);
|
||||
}
|
||||
|
||||
#else
|
||||
# define plist_check_head(h) do { } while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* plist_add - add @node to @head
|
||||
*
|
||||
* @node: &struct plist_node pointer
|
||||
* @head: &struct plist_head pointer
|
||||
*/
|
||||
void plist_add(struct plist_node *node, struct plist_head *head)
|
||||
{
|
||||
struct plist_node *first, *iter, *prev = NULL;
|
||||
struct list_head *node_next = &head->node_list;
|
||||
|
||||
plist_check_head(head);
|
||||
WARN_ON(!plist_node_empty(node));
|
||||
WARN_ON(!list_empty(&node->prio_list));
|
||||
|
||||
if (plist_head_empty(head))
|
||||
goto ins_node;
|
||||
|
||||
first = iter = plist_first(head);
|
||||
|
||||
do {
|
||||
if (node->prio < iter->prio) {
|
||||
node_next = &iter->node_list;
|
||||
break;
|
||||
}
|
||||
|
||||
prev = iter;
|
||||
iter = list_entry(iter->prio_list.next,
|
||||
struct plist_node, prio_list);
|
||||
} while (iter != first);
|
||||
|
||||
if (!prev || prev->prio != node->prio)
|
||||
list_add_tail(&node->prio_list, &iter->prio_list);
|
||||
ins_node:
|
||||
list_add_tail(&node->node_list, node_next);
|
||||
|
||||
plist_check_head(head);
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_del - Remove a @node from plist.
|
||||
*
|
||||
* @node: &struct plist_node pointer - entry to be removed
|
||||
* @head: &struct plist_head pointer - list head
|
||||
*/
|
||||
void plist_del(struct plist_node *node, struct plist_head *head)
|
||||
{
|
||||
plist_check_head(head);
|
||||
|
||||
if (!list_empty(&node->prio_list)) {
|
||||
if (node->node_list.next != &head->node_list) {
|
||||
struct plist_node *next;
|
||||
|
||||
next = list_entry(node->node_list.next,
|
||||
struct plist_node, node_list);
|
||||
|
||||
/* add the next plist_node into prio_list */
|
||||
if (list_empty(&next->prio_list))
|
||||
list_add(&next->prio_list, &node->prio_list);
|
||||
}
|
||||
list_del_init(&node->prio_list);
|
||||
}
|
||||
|
||||
list_del_init(&node->node_list);
|
||||
|
||||
plist_check_head(head);
|
||||
}
|
||||
|
||||
/**
|
||||
* plist_requeue - Requeue @node at end of same-prio entries.
|
||||
*
|
||||
* This is essentially an optimized plist_del() followed by
|
||||
* plist_add(). It moves an entry already in the plist to
|
||||
* after any other same-priority entries.
|
||||
*
|
||||
* @node: &struct plist_node pointer - entry to be moved
|
||||
* @head: &struct plist_head pointer - list head
|
||||
*/
|
||||
void plist_requeue(struct plist_node *node, struct plist_head *head)
|
||||
{
|
||||
struct plist_node *iter;
|
||||
struct list_head *node_next = &head->node_list;
|
||||
|
||||
plist_check_head(head);
|
||||
BUG_ON(plist_head_empty(head));
|
||||
BUG_ON(plist_node_empty(node));
|
||||
|
||||
if (node == plist_last(head))
|
||||
return;
|
||||
|
||||
iter = plist_next(node);
|
||||
|
||||
if (node->prio != iter->prio)
|
||||
return;
|
||||
|
||||
plist_del(node, head);
|
||||
|
||||
plist_for_each_continue(iter, head) {
|
||||
if (node->prio != iter->prio) {
|
||||
node_next = &iter->node_list;
|
||||
break;
|
||||
}
|
||||
}
|
||||
list_add_tail(&node->node_list, node_next);
|
||||
|
||||
plist_check_head(head);
|
||||
}
|
222
2019/libsrc/pool.c
Normal file
222
2019/libsrc/pool.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/* pool.c - A simple pool manager.
|
||||
*
|
||||
* 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>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "pool.h"
|
||||
#include "debug.h"
|
||||
#include "bits.h"
|
||||
|
||||
void pool_stats(pool_t *pool)
|
||||
{
|
||||
if (pool) {
|
||||
block_t *block;
|
||||
|
||||
log_f(1, "[%s] pool [%p]: blocks:%u avail:%u alloc:%u grow:%u eltsize:%lu\n",
|
||||
pool->name, (void *)pool, pool->nblocks, pool->available, pool->allocated,
|
||||
pool->growsize, pool->eltsize);
|
||||
log(5, "\tblocks: ");
|
||||
list_for_each_entry(block, &pool->list_blocks, list_blocks) {
|
||||
log(5, "%p ", block);
|
||||
}
|
||||
log(5, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
pool_t *pool_create(const char *name, u32 growsize, size_t eltsize)
|
||||
{
|
||||
pool_t *pool;
|
||||
|
||||
# ifdef DEBUG_POOL
|
||||
log_f(1, "name=[%s] growsize=%u eltsize=%lu\n",
|
||||
name, growsize, eltsize);
|
||||
# endif
|
||||
/* we need at least sizeof(struct list_head) space in pool elements
|
||||
*/
|
||||
if (eltsize < sizeof (struct list_head)) {
|
||||
# ifdef DEBUG_POOL
|
||||
log_f(1, "[%s]: structure size too small (%lu < %lu), adjusting to %lu.\n",
|
||||
name, eltsize, sizeof(struct list_head), sizeof(struct list_head));
|
||||
# endif
|
||||
eltsize = sizeof(struct list_head);
|
||||
}
|
||||
if ((pool = malloc(sizeof (*pool)))) {
|
||||
strncpy(pool->name, name, POOL_NAME_LENGTH - 1);
|
||||
pool->name[POOL_NAME_LENGTH - 1] = 0;
|
||||
pool->growsize = growsize;
|
||||
pool->eltsize = eltsize;
|
||||
pool->available = 0;
|
||||
pool->allocated = 0;
|
||||
pool->nblocks = 0;
|
||||
INIT_LIST_HEAD(&pool->list_available);
|
||||
INIT_LIST_HEAD(&pool->list_blocks);
|
||||
} else {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
static u32 _pool_add(pool_t *pool, struct list_head *elt)
|
||||
{
|
||||
# ifdef DEBUG_POOL
|
||||
log_f(6, "pool=%p &head=%p elt=%p off1=%lu off2=%lu\n",
|
||||
(void *)pool,
|
||||
(void *)&pool->list_available,
|
||||
(void *)elt,
|
||||
(void *)&pool->list_available-(void *)pool,
|
||||
offsetof(pool_t, list_available));
|
||||
# endif
|
||||
|
||||
list_add(elt, &pool->list_available);
|
||||
return ++pool->available;
|
||||
}
|
||||
|
||||
u32 pool_add(pool_t *pool, void *elt)
|
||||
{
|
||||
return _pool_add(pool, elt);
|
||||
}
|
||||
|
||||
static struct list_head *_pool_get(pool_t *pool)
|
||||
{
|
||||
struct list_head *res = pool->list_available.next;
|
||||
pool->available--;
|
||||
list_del(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void *pool_get(pool_t *pool)
|
||||
{
|
||||
if (!pool)
|
||||
return NULL;
|
||||
if (!pool->available) {
|
||||
block_t *block = malloc(sizeof(block_t) + pool->eltsize * pool->growsize);
|
||||
if (!block) {
|
||||
# ifdef DEBUG_POOL
|
||||
log_f(1, "[%s]: failed block allocation\n", pool->name);
|
||||
# endif
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* maintain list of allocated blocks
|
||||
*/
|
||||
list_add(&block->list_blocks, &pool->list_blocks);
|
||||
pool->nblocks++;
|
||||
|
||||
# ifdef DEBUG_POOL
|
||||
log_f(1, "[%s]: growing pool from %u to %u elements. block=%p nblocks=%u\n",
|
||||
pool->name,
|
||||
pool->allocated,
|
||||
pool->allocated + pool->growsize,
|
||||
block,
|
||||
pool->nblocks);
|
||||
# endif
|
||||
|
||||
pool->allocated += pool->growsize;
|
||||
for (u32 i = 0; i < pool->growsize; ++i) {
|
||||
void *cur = block->data + i * pool->eltsize;
|
||||
# ifdef DEBUG_POOL
|
||||
log_f(7, "alloc=%p cur=%p\n", block, cur);
|
||||
# endif
|
||||
_pool_add(pool, (struct list_head *)cur);
|
||||
}
|
||||
}
|
||||
/* this is the effective address of the object (and also the
|
||||
* pool list_head address)
|
||||
*/
|
||||
return _pool_get(pool);
|
||||
}
|
||||
|
||||
void pool_destroy(pool_t *pool)
|
||||
{
|
||||
block_t *block, *tmp;
|
||||
if (!pool)
|
||||
return;
|
||||
/* release memory blocks */
|
||||
# ifdef DEBUG_POOL
|
||||
log_f(1, "[%s]: releasing %d blocks and main structure\n", pool->name, pool->nblocks);
|
||||
log(5, "blocks:");
|
||||
# endif
|
||||
list_for_each_entry_safe(block, tmp, &pool->list_blocks, list_blocks) {
|
||||
list_del(&block->list_blocks);
|
||||
free(block);
|
||||
# ifdef DEBUG_POOL
|
||||
log(5, " %p", block);
|
||||
# endif
|
||||
}
|
||||
# ifdef DEBUG_POOL
|
||||
log(5, "\n");
|
||||
# endif
|
||||
free(pool);
|
||||
}
|
||||
|
||||
#ifdef BIN_pool
|
||||
struct d {
|
||||
u16 data1;
|
||||
char c;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static LIST_HEAD (head);
|
||||
|
||||
int main(int ac, char**av)
|
||||
{
|
||||
pool_t *pool;
|
||||
int total;
|
||||
int action=0;
|
||||
u16 icur=0;
|
||||
char ccur='z';
|
||||
struct d *elt;
|
||||
|
||||
debug_init(3);
|
||||
log_f(1, "%s: sizeof(d)=%lu sizeof(*d)=%lu off=%lu\n", *av, sizeof(elt),
|
||||
sizeof(*elt), offsetof(struct d, list));
|
||||
|
||||
if ((pool = pool_create("dummy", 3, sizeof(*elt)))) {
|
||||
pool_stats(pool);
|
||||
for (int cur=1; cur<ac; ++cur) {
|
||||
total = atoi(av[cur]);
|
||||
if (action == 0) { /* add elt to list */
|
||||
log_f(2, "adding %d elements\n", total);
|
||||
for (int i = 0; i < total; ++i) {
|
||||
elt = pool_get(pool);
|
||||
elt->data1 = icur++;
|
||||
elt->c = ccur--;
|
||||
list_add(&elt->list, &head);
|
||||
}
|
||||
pool_stats(pool);
|
||||
action = 1;
|
||||
} else { /* remove one elt from list */
|
||||
log_f(2, "deleting %d elements\n", total);
|
||||
for (int i = 0; i < total; ++i) {
|
||||
if (!list_empty(&head)) {
|
||||
elt = list_last_entry(&head, struct d, list);
|
||||
printf("elt=[%d, %c]\n", elt->data1, elt->c);
|
||||
list_del(&elt->list);
|
||||
pool_add(pool, elt);
|
||||
}
|
||||
}
|
||||
pool_stats(pool);
|
||||
action = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
pool_stats(pool);
|
||||
pool_destroy(pool);
|
||||
}
|
||||
#endif
|
@@ -1,25 +1,87 @@
|
||||
# AOC Makefile - GNU make only.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
|
||||
|
||||
SUBDIRS := $(shell echo day??)
|
||||
|
||||
EXCLUDE := --exclude 'cob-01/'
|
||||
CC = gcc
|
||||
|
||||
.PHONY: clean $(SUBDIRS)
|
||||
#LIBS = -lreadline -lncurses
|
||||
CFLAGS += -std=gnu11
|
||||
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
#CFLAGS += -pg
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
INCDIR := ./include
|
||||
LIBSRCDIR := ./libsrc
|
||||
LIBDIR := ./lib
|
||||
LIB := libaoc_$(shell uname -m)
|
||||
SLIB := $(LIBDIR)/$(LIB).a
|
||||
DLIB := $(LIBDIR)/$(LIB).so
|
||||
LIBSRC := $(wildcard $(LIBSRCDIR)/*.c)
|
||||
LIBOBJ := $(patsubst %.c,%.o,$(LIBSRC))
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
LDLIB := -l$(LIB)
|
||||
|
||||
.PHONY: clean cleanlib cleanall all redo output lib $(SUBDIRS)
|
||||
|
||||
all: lib $(SUBDIRS)
|
||||
|
||||
clean:
|
||||
for dir in $(SUBDIRS) ; do \
|
||||
make -C $$dir clean ; \
|
||||
@for dir in $(SUBDIRS) ; do \
|
||||
$(MAKE) --no-print-directory -C $$dir clean ; \
|
||||
done
|
||||
|
||||
all: $(SUBDIRS)
|
||||
cleanlib: clean
|
||||
@$(RM) -f $(SLIB) $(DLIB) $(LIBOBJ)
|
||||
|
||||
cleanall: clean cleanlib
|
||||
|
||||
redo: cleanall all
|
||||
|
||||
$(SUBDIRS):
|
||||
@echo "========================================="
|
||||
@echo "================= $@ ================="
|
||||
@echo "========================================="
|
||||
@echo
|
||||
@echo "+++++++++++++++++ ex1"
|
||||
@$(MAKE) --no-print-directory -C $@ ex1 2>&1
|
||||
@echo "+++++++++++++++++ ex2"
|
||||
@$(MAKE) --no-print-directory -C $@ ex2 2>&1
|
||||
@echo "+++++++++++++++++ part 1"
|
||||
+@$(MAKE) --no-print-directory -C $@ ex1 2>&1
|
||||
@echo "+++++++++++++++++ part 2"
|
||||
+@$(MAKE) --no-print-directory -C $@ ex2 2>&1
|
||||
|
||||
output:
|
||||
@$(MAKE) --no-print-directory all >OUTPUT 2>&1
|
||||
|
||||
lib: $(DLIB) $(SLIB)
|
||||
|
||||
$(SLIB): $(LIBOBJ)
|
||||
@echo building $@ static library.
|
||||
@mkdir -p $(LIBDIR)
|
||||
@$(AR) $(ARFLAGS) -o $@ $^
|
||||
|
||||
$(DLIB): CFLAGS += -fPIC
|
||||
$(DLIB): LDFLAGS += -shared
|
||||
$(DLIB): $(LIBOBJ)
|
||||
@echo building $@ shared library.
|
||||
@mkdir -p $(LIBDIR)
|
||||
@$(CC) $(LDFLAGS) $^ -o $@
|
||||
|
||||
.c.o:
|
||||
@echo compiling $<.
|
||||
@$(CC) -c $(CFLAGS) $(LDFLAGS) -I $(INCDIR) -o $@ $<
|
||||
|
@@ -256,21 +256,21 @@ ex2-c : size=99 res=113387824750592
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash : res=2386
|
||||
time: 0:40.81 real, 40.25 user, 0.07 sys
|
||||
context-switch: 6828+17, page-faults: 0+1317
|
||||
time: 0:33.55 real, 33.12 user, 0.42 sys
|
||||
context-switch: 179+18, page-faults: 0+1948
|
||||
|
||||
ex1-c : res=2386
|
||||
time: 0:00.03 real, 0.00 user, 0.00 sys
|
||||
context-switch: 1+2, page-faults: 0+91
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+90
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash : res=2091
|
||||
time: 1:19.37 real, 78.72 user, 0.08 sys
|
||||
context-switch: 9445+14, page-faults: 0+1717
|
||||
time: 1:08.60 real, 68.56 user, 0.02 sys
|
||||
context-switch: 530+10, page-faults: 0+1480
|
||||
|
||||
ex2-c : res=2091
|
||||
time: 0:00.04 real, 0.02 user, 0.00 sys
|
||||
context-switch: 2+2, page-faults: 0+91
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 6+1, page-faults: 0+90
|
||||
|
||||
=========================================
|
||||
================= day12 =================
|
||||
@@ -366,21 +366,21 @@ ex1-c : res[30000000]=548531
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash : res=21996
|
||||
time: 0:00.23 real, 0.16 user, 0.03 sys
|
||||
context-switch: 19+99, page-faults: 0+9381
|
||||
time: 0:00.14 real, 0.11 user, 0.02 sys
|
||||
context-switch: 12+120, page-faults: 0+7974
|
||||
|
||||
ex1-c : res=21996
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+71
|
||||
context-switch: 0+1, page-faults: 0+76
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash : res=650080463519
|
||||
time: 0:06.58 real, 6.54 user, 0.04 sys
|
||||
context-switch: 662+95, page-faults: 0+10210
|
||||
context-switch: 201+114, page-faults: 0+8893
|
||||
|
||||
ex2-c : res=650080463519
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+71
|
||||
context-switch: 0+1, page-faults: 0+74
|
||||
|
||||
=========================================
|
||||
================= day17 =================
|
||||
@@ -439,15 +439,123 @@ ex1.bash : res=285
|
||||
time: 0:00.56 real, 0.55 user, 0.00 sys
|
||||
context-switch: 12+1, page-faults: 0+5967
|
||||
|
||||
aoc-c : res=285
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+94
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash : res=412
|
||||
time: 0:03.37 real, 3.34 user, 0.03 sys
|
||||
context-switch: 19+1, page-faults: 0+11909
|
||||
|
||||
|
||||
aoc-c : res=412
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+95
|
||||
|
||||
=========================================
|
||||
================= day20 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash : res=5966506063747
|
||||
time: 0:00.54 real, 0.53 user, 0.00 sys
|
||||
context-switch: 1+1, page-faults: 0+223
|
||||
time: 0:00.56 real, 0.56 user, 0.00 sys
|
||||
context-switch: 4+1, page-faults: 0+224
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash res=1714
|
||||
time: 0:02.14 real, 2.05 user, 0.02 sys
|
||||
context-switch: 1146+1, page-faults: 0+605
|
||||
|
||||
=========================================
|
||||
================= day21 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=2211
|
||||
time: 0:01.72 real, 1.71 user, 0.00 sys
|
||||
context-switch: 9+1, page-faults: 0+1090
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=vv,nlxsmb,rnbhjk,bvnkk,ttxvphb,qmkz,trmzkcfg,jpvz
|
||||
time: 0:01.75 real, 1.74 user, 0.00 sys
|
||||
context-switch: 36+4, page-faults: 0+1388
|
||||
|
||||
=========================================
|
||||
================= day22 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=31314
|
||||
time: 0:00.07 real, 0.06 user, 0.00 sys
|
||||
context-switch: 2+1, page-faults: 0+168
|
||||
|
||||
aoc-c : res=31314
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+89
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=32760
|
||||
time: 1:21.92 real, 81.89 user, 0.01 sys
|
||||
context-switch: 462+1, page-faults: 0+5135
|
||||
|
||||
aoc-c : res=32760
|
||||
time: 0:01.11 real, 1.09 user, 0.01 sys
|
||||
context-switch: 70+1, page-faults: 0+1933
|
||||
|
||||
=========================================
|
||||
================= day23 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=75893264
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+166
|
||||
|
||||
aoc-c : res=75893264
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+83
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=38162588308
|
||||
time: 6:52.50 real, 412.30 user, 0.14 sys
|
||||
context-switch: 2219+1, page-faults: 0+30233
|
||||
|
||||
aoc-c : res=38162588308
|
||||
time: 0:01.33 real, 1.32 user, 0.01 sys
|
||||
context-switch: 3+1, page-faults: 0+3992
|
||||
|
||||
=========================================
|
||||
================= day24 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=450
|
||||
time: 0:00.17 real, 0.16 user, 0.00 sys
|
||||
context-switch: 1+1, page-faults: 0+177
|
||||
|
||||
aoc-c : res=450
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+100
|
||||
|
||||
+++++++++++++++++ ex2
|
||||
ex2.bash: res=4059
|
||||
time: 0:22.35 real, 22.22 user, 0.07 sys
|
||||
context-switch: 1102+1, page-faults: 0+858
|
||||
|
||||
aoc-c : res=4059
|
||||
time: 0:00.04 real, 0.04 user, 0.00 sys
|
||||
context-switch: 16+1, page-faults: 0+215
|
||||
|
||||
=========================================
|
||||
================= day25 =================
|
||||
=========================================
|
||||
|
||||
+++++++++++++++++ ex1
|
||||
ex1.bash: res=9620012
|
||||
time: 2:42.30 real, 162.05 user, 0.08 sys
|
||||
context-switch: 3634+1, page-faults: 0+163
|
||||
|
||||
ex1-c : res=9620012
|
||||
time: 0:00.08 real, 0.08 user, 0.00 sys
|
||||
context-switch: 2+1, page-faults: 0+79
|
@@ -28,7 +28,7 @@ ex2: ex2-c ex2-sort-cob ex2-pure-sort-cob
|
||||
@$(TIME) ex2-c < $(INPUT)
|
||||
|
||||
clean:
|
||||
@rm -f ex1-c ex2-c core ex2-galoisgirl-cob ex2-cob
|
||||
@rm -f ex1-c ex2-c core ex*-cob
|
||||
|
||||
output:
|
||||
$(MAKE) --no-print-directory all >OUTPUT 2>&1
|
||||
|
@@ -1,36 +0,0 @@
|
||||
ex1.bash : 33:1701 180:319 sum=2020 mul=542619
|
||||
time: 0:00.06 real, 0.06 user, 0.00 sys
|
||||
context-switch: 20+4, page-faults: 0+305
|
||||
|
||||
ex1-cob : res= 542619
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+172
|
||||
|
||||
ex1-c : 33:1701 180:319 sum=2020 mul=542619
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+73
|
||||
|
||||
ex2.bash : 80:1450 94:43 185:527 sum=2020 mul=32858450
|
||||
time: 0:10.00 real, 10.00 user, 0.00 sys
|
||||
context-switch: 1005+3, page-faults: 0+302
|
||||
|
||||
ex2-sort.bash : 0:43 2:527 81:1450 sum=2020 mul=32858450
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 2+7, page-faults: 0+479
|
||||
|
||||
ex2-pure-sort.bash : 0:43 2:527 81:1450 sum=2020 mul=32858450
|
||||
time: 0:00.50 real, 0.50 user, 0.00 sys
|
||||
context-switch: 62+4, page-faults: 0+311
|
||||
|
||||
ex2-sort-cob : res= 32858450
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 1+1, page-faults: 0+170
|
||||
|
||||
ex2-pure-sort-cob : res= 32858450
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 1+1, page-faults: 0+173
|
||||
|
||||
ex2-c : 80:1450 94:43 185:527 sum=2020 mul=32858450
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+75
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# ex1.bash: Advent2020 game, day 1/game 1
|
||||
|
||||
CMD=$(basename "$0")
|
||||
CMD=${0##*/}
|
||||
|
||||
readarray -t numbers
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# ex2-sort.bash: Advent2020 game, day 1/game 2, with sort.
|
||||
|
||||
CMD=$(basename "$0")
|
||||
CMD=${0##*/}
|
||||
|
||||
readarray -t numbers <<< "$(sort -n)"
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# ex2.bash: Advent2020 game, day 1/game 2
|
||||
|
||||
CMD=$(basename "$0")
|
||||
CMD=${0##*/}
|
||||
|
||||
readarray -t numbers
|
||||
|
||||
|
@@ -1,12 +0,0 @@
|
||||
ex1.bash : lines: 1000 matched:607
|
||||
time: 0:00.03 real, 0.03 user, 0.00 sys
|
||||
|
||||
ex1-c : lines: 1000 matched:607
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
|
||||
ex2.bash : lines: 1000 matched:321
|
||||
time: 0:00.03 real, 0.03 user, 0.00 sys
|
||||
|
||||
ex2-c : lines: 1000 matched:321
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
|
@@ -1,12 +0,0 @@
|
||||
ex1.bash : lines:322 pos=966 found:169
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
|
||||
ex1-c : lines:322 pos:966 found:169
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
|
||||
ex2.bash : lines=323 res=6847128288
|
||||
time: 0:00.04 real, 0.03 user, 0.00 sys
|
||||
|
||||
ex2-c : lines=323 res=6847128288
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
|
@@ -32,7 +32,7 @@ int main(ac, av)
|
||||
char **av;
|
||||
{
|
||||
int line=1, linelen=0, mod=0, i;
|
||||
unsigned long res=1;
|
||||
unsigned long long res=1;
|
||||
char str[80];
|
||||
|
||||
scanf("%s", str); /* ignore 1st line */
|
||||
@@ -51,6 +51,6 @@ int main(ac, av)
|
||||
}
|
||||
for (i=0; set[i].dx != -1; ++i)
|
||||
res*=set[i].count;
|
||||
printf ("%s : lines=%d res=%lu\n", *av, line, res);
|
||||
printf ("%s : lines=%d res=%llu\n", *av, line, res);
|
||||
exit (0);
|
||||
}
|
||||
|
@@ -1,12 +0,0 @@
|
||||
ex1.bash : valid=182/251
|
||||
time: 0:00.06 real, 0.06 user, 0.00 sys
|
||||
|
||||
ex1-c : valid=182/251
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
|
||||
ex2.bash : valid=109/251
|
||||
time: 0:00.16 real, 0.16 user, 0.00 sys
|
||||
|
||||
ex2-c : valid=109/251
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
|
@@ -1,12 +0,0 @@
|
||||
ex1.bash : lines=743 max=838
|
||||
time: 0:00.94 real, 0.62 user, 0.41 sys
|
||||
|
||||
ex1-c : lines=743 max=838
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
|
||||
ex2.bash : lines=743 seat=714
|
||||
time: 0:00.99 real, 0.65 user, 0.43 sys
|
||||
|
||||
ex2-c : lines=743 seat=714
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
|
@@ -1,24 +0,0 @@
|
||||
ex1.bash : groups=484 count=6585
|
||||
time: 0:01.42 real, 1.26 user, 0.20 sys
|
||||
context-switch: 135+1393, page-faults: 0+59578
|
||||
|
||||
ex1-bis.bash : groups=484 count=6585
|
||||
time: 0:01.22 real, 1.09 user, 0.16 sys
|
||||
context-switch: 145+1311, page-faults: 0+60076
|
||||
|
||||
ex1-c : groups=484 count=6585
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+71
|
||||
|
||||
ex2.bash : groups=484 count=3276
|
||||
time: 0:01.35 real, 1.18 user, 0.20 sys
|
||||
context-switch: 139+1360, page-faults: 0+59397
|
||||
|
||||
ex2-bis.bash : groups=484 count=3276
|
||||
time: 0:01.30 real, 1.11 user, 0.22 sys
|
||||
context-switch: 112+1356, page-faults: 0+57986
|
||||
|
||||
ex2-c : groups=484 count=3276
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+72
|
||||
|
@@ -1,4 +0,0 @@
|
||||
#! /bin/bash
|
||||
PATH=.:$PATH
|
||||
IN="$1"
|
||||
time { ex1.bash < $IN; ex2.bash < $IN; } 2>&1
|
@@ -1,5 +0,0 @@
|
||||
#! /bin/bash
|
||||
PATH=.:$PATH
|
||||
IN="$1"
|
||||
echo IN=$IN
|
||||
time for i in ex1-c ex2-c; do "$i" < "$IN"; done 2>&1
|
@@ -1,20 +0,0 @@
|
||||
ex1.bash : target=shinygold nkeys=594 res=287
|
||||
time: 0:06.99 real, 6.99 user, 0.00 sys
|
||||
context-switch: 720+1, page-faults: 0+403
|
||||
|
||||
ex1-bis.bash : target=shinygold res=287
|
||||
time: 0:00.12 real, 0.12 user, 0.00 sys
|
||||
context-switch: 14+1, page-faults: 0+209
|
||||
|
||||
ex1-c : target=shinygold nkeys=594 res=287
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+117
|
||||
|
||||
ex2.bash : target=shinygold res=48160
|
||||
time: 0:00.34 real, 0.28 user, 0.06 sys
|
||||
context-switch: 37+253, page-faults: 0+12039
|
||||
|
||||
ex2-c : target=shinygold nkeys=594 res=48160
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+118
|
||||
|
@@ -1,16 +0,0 @@
|
||||
ex1.bash : res=1594
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 0+4, page-faults: 0+303
|
||||
|
||||
ex1-c : res=1594
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 1+0, page-faults: 0+79
|
||||
|
||||
ex2.bash : res:758
|
||||
time: 0:02.26 real, 2.12 user, 0.16 sys
|
||||
context-switch: 212+1084, page-faults: 0+43039
|
||||
|
||||
ex2-c : res=758
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 1+1, page-faults: 0+78
|
||||
|
@@ -1,16 +0,0 @@
|
||||
ex1.bash : res=167829540
|
||||
time: 0:00.42 real, 0.42 user, 0.00 sys
|
||||
context-switch: 57+1, page-faults: 0+172
|
||||
|
||||
ex1-c : res=167829540
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+76
|
||||
|
||||
ex2.bash : res=167829540 sum=28045630
|
||||
time: 0:03.22 real, 3.01 user, 0.21 sys
|
||||
context-switch: 359+921, page-faults: 0+49208
|
||||
|
||||
ex2-c : res=167829540 sum=28045630
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+75
|
||||
|
@@ -1,18 +0,0 @@
|
||||
cc -w ex1-c.c -o ex1-c
|
||||
ex1.bash : diff1=71 diff2=27 res=1917
|
||||
time: 0:00.01 real, 0.00 user, 0.00 sys
|
||||
context-switch: 1+4, page-faults: 0+331
|
||||
|
||||
ex1-c : diff1=71 diff2=27 res=1917
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+73
|
||||
|
||||
cc -w ex2-c.c -o ex2-c
|
||||
ex2.bash : size=99 res=113387824750592
|
||||
time: 0:00.01 real, 0.01 user, 0.00 sys
|
||||
context-switch: 2+4, page-faults: 0+329
|
||||
|
||||
ex2-c : size=99 res=113387824750592
|
||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||
context-switch: 0+1, page-faults: 0+73
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user