...
 
Commits (219)
TAGS
.depends
.valgrind_suppressions
*.d
*.o
libccan.a
*.ok
.fast-ok
config.h
config.h.tmp
*~
tools/ccan_depends
tools/doc_extract
tools/namespacize
tools/run_tests
tools/ccanlint/ccanlint
tools/ccanlint/generated-testlist
tools/modfiles
inter-depends
test-depends
lib-depends
tools/_infotojson/infotojson
tools/ccanlint/test/run-file_analysis
tools/configurator/configurator
......
language: c
sudo: false
compiler:
- gcc
- clang
addons:
apt:
matrix:
include:
- compiler: gcc
env: CFLAGS="-std=gnu99"
- compiler: gcc-5
env: GCOV="gcov-5"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-5
- compiler: gcc-6
env: GCOV="gcov-6"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-6
- compiler: clang
addons:
apt:
packages:
- valgrind
- dist: trusty
addons:
apt:
packages:
- valgrind
env: CFLAGS="-std=gnu99"
compiler: gcc
- dist: trusty
compiler: gcc-5
env: GCOV="gcov-5"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-5
- valgrind
- dist: trusty
compiler: gcc-6
env: GCOV="gcov-6"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-6
- valgrind
- dist: trusty
compiler: clang
addons:
apt:
packages:
- libjudy-dev libvorbis-dev libportaudio-dev libtalloc-dev
- valgrind
script:
- make config.h
- make -j2
- make -j2 -k check
- make -j2 -k quiet=1
- make -k check quiet=1
# Hacky makefile to compile everything and run the tests in some kind
# of sane order.
# Main targets:
#
# check: run tests on all ccan modules (use 'make check V=--verbose' for more)
# Includes building libccan.a.
# libccan.a: A library with all the ccan modules in it.
# tools: build useful tools in tools/ dir.
# Especially tools/ccanlint/ccanlint and tools/namespacize.
# distclean: destroy everything back to pristine state
# Where make scores puts the results
SCOREDIR=scores/$(shell whoami)/$(shell uname -s)-$(shell uname -m)-$(CC)-$(shell git describe --always --dirty)
CCANLINT=tools/ccanlint/ccanlint --deps-fail-ignore
CCANLINT_FAST=$(CCANLINT) -x tests_pass_valgrind -x tests_compile_coverage
default: all_info libccan.a
ALL_DEPENDS=$(patsubst %, ccan/%/.depends, $(MODS))
# By default, we skip modules with external deps (or plaform specific)
MODS_EXCLUDE:=altstack generator jmap jset nfs ogg_to_pcm tal/talloc wwviaudio
# This randomly fails, and reliably fails under Jenkins :(
MODS_FLAKY:=altstack
MODS_RELIABLE=$(filter-out $(MODS_FLAKY),$(MODS))
include Makefile-ccan
fastcheck: $(MODS_RELIABLE:%=summary-fastcheck/%)
check: $(MODS_RELIABLE:%=summary-check/%)
distclean: clean
rm -f $(ALL_DEPENDS)
scores: $(SCOREDIR)/SUMMARY
$(SCOREDIR)/SUMMARY: $(MODS:%=$(SCOREDIR)/%.score)
git describe --always > $@
uname -a >> $@
$(CC) -v >> $@
cat $^ | grep 'Total score:' >> $@
$(SCOREDIR)/%.score: ccan/%/_info tools/ccanlint/ccanlint $(OBJFILES)
mkdir -p `dirname $@`
$(CCANLINT) -v -s ccan/$* > $@ || true
$(ALL_DEPENDS): %/.depends: %/_info tools/ccan_depends
tools/ccan_depends $* > $@ || ( rm -f $@; exit 1 )
# Actual dependencies are created in inter-depends
check/%: tools/ccanlint/ccanlint
$(CCANLINT) ccan/$*
fastcheck/%: tools/ccanlint/ccanlint
$(CCANLINT_FAST) ccan/$*
# Doesn't test dependencies, doesn't print verbose fail results.
summary-check/%: tools/ccanlint/ccanlint $(OBJFILES)
$(CCANLINT) -s ccan/$*
summary-fastcheck/%: tools/ccanlint/ccanlint $(OBJFILES)
$(CCANLINT_FAST) -s ccan/$*
ccan/%/info: ccan/%/_info config.h
$(CC) $(CCAN_CFLAGS) -I. -o $@ -x c $<
all_info: $(MODS:%=ccan/%/info)
clean: tools-clean
rm -f `find * -name '*.o'` `find * -name '.depends'` `find * -name '*.a'` `find * -name info` `find * -name '*.d'` `find ccan -name '*-Makefile'`
rm -f config.h
rm -f inter-depends lib-depends test-depends
# Creates a dependency from the tests to the object files which it needs.
inter-depends: $(ALL_DEPENDS) Makefile
for f in $(ALL_DEPENDS); do echo check-$$(basename $$(dirname $$f) ): $$(for dir in $$(cat $$f) $$(dirname $$f); do [ "$$(echo $$dir/*.c)" = "$$dir/*.c" ] || echo ccan/"$$(basename $$dir)".o; done); done > $@
# Creates dependencies between tests, so if foo depends on bar, bar is tested
# first
test-depends: $(ALL_DEPENDS) Makefile
for f in $(ALL_DEPENDS); do echo check/`basename \`dirname $$f\``: `sed -n 's,ccan/\(.*\),check/\1,p' < $$f`; done > $@
TAGS: FORCE
find * -name '*.[ch]' | xargs etags
FORCE:
# Ensure we don't end up with empty file if configurator fails!
config.h: tools/configurator/configurator Makefile Makefile-ccan
tools/configurator/configurator $(CC) $(CCAN_CFLAGS) > $@.tmp && mv $@.tmp $@
include tools/Makefile
-include inter-depends
-include test-depends
-include Makefile-web
# Makefile for CCAN
# 'make quiet=1' builds silently
QUIETEN.1 := @
PRE := $(QUIETEN.$(quiet))
all::
# Our flags for building
WARN_CFLAGS := -Wall -Wstrict-prototypes -Wold-style-definition -Wundef \
-Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wwrite-strings
DEP_CFLAGS = -MMD -MP -MF$(@:%=%.d) -MT$@
CCAN_CFLAGS := -g3 -ggdb $(WARN_CFLAGS) -DCCAN_STR_DEBUG=1 -I. $(CFLAGS)
CFLAGS_FORCE_C_SOURCE := -x c
# Anything with an _info file is a module ...
INFO_SRCS := $(wildcard ccan/*/_info ccan/*/*/_info)
ALL_INFOS := $(INFO_SRCS:%_info=%info)
ALL_MODULES := $(ALL_INFOS:%/info=%)
# ... Except stuff that needs external dependencies, which we exclude
EXCLUDE := altstack jmap jset nfs ogg_to_pcm tal/talloc wwviaudio
MODULES:= $(filter-out $(EXCLUDE:%=ccan/%), $(ALL_MODULES))
# Sources are C files in each module, objects the resulting .o files
SRCS := $(wildcard $(MODULES:%=%/*.c))
OBJS := $(SRCS:%.c=%.o)
DEPS := $(OBJS:%=%.d)
# We build all object files using our CCAN_CFLAGS, after config.h
%.o : %.c config.h
$(PRE)$(CC) $(CCAN_CFLAGS) $(DEP_CFLAGS) -c $< -o $@
# _info files are compiled into executables and don't need dependencies
%info : %_info config.h
$(PRE)$(CC) $(CCAN_CFLAGS) -I. -o $@ $(CFLAGS_FORCE_C_SOURCE) $<
# config.h is built by configurator which has no ccan dependencies
CONFIGURATOR := tools/configurator/configurator
$(CONFIGURATOR): $(CONFIGURATOR).c
$(PRE)$(CC) $(CCAN_CFLAGS) $(DEP_CFLAGS) $< -o $@
config.h: $(CONFIGURATOR) Makefile
$(PRE)$(CONFIGURATOR) $(CC) $(CCAN_CFLAGS) >$@.tmp && mv $@.tmp $@
# Tools
TOOLS := tools/ccan_depends tools/doc_extract tools/namespacize tools/modfiles
TOOLS_SRCS := $(filter-out $(TOOLS:%=%.c), $(wildcard tools/*.c))
TOOLS_DEPS := $(TOOLS_SRCS:%.c=%.d) $(TOOLS:%=%.d)
TOOLS_CCAN_MODULES := asort err foreach hash htable list membuf noerr opt rbuf \
read_write_all str take tal tal/grab_file tal/link tal/path tal/str time
TOOLS_CCAN_SRCS := $(wildcard $(TOOLS_CCAN_MODULES:%=ccan/%/*.c))
TOOLS_OBJS := $(TOOLS_SRCS:%.c=%.o) $(TOOLS_CCAN_SRCS:%.c=%.o)
tools/% : tools/%.c $(TOOLS_OBJS)
$(PRE)$(CC) $(CCAN_CFLAGS) $(DEP_CFLAGS) $< $(TOOLS_OBJS) -lm -o $@
# ccanlint
LINT := tools/ccanlint/ccanlint
LINT_OPTS.ok := -s
LINT_OPTS.fast-ok := -s -x tests_pass_valgrind -x tests_compile_coverage
LINT_SRCS := $(filter-out $(LINT).c, $(wildcard tools/ccanlint/*.c tools/ccanlint/tests/*.c))
LINT_DEPS := $(LINT_SRCS:%.c=%.d) $(LINT).d
LINT_CCAN_MODULES := autodata dgraph ilog lbalance ptr_valid strmap
LINT_CCAN_SRCS := $(wildcard $(LINT_CCAN_MODULES:%=ccan/%/*.c))
LINT_OBJS := $(LINT_SRCS:%.c=%.o) $(LINT_CCAN_SRCS:%.c=%.o) $(TOOLS_OBJS)
ifneq ($(GCOV),)
LINT_GCOV = --gcov="$(GCOV)"
endif
$(LINT): $(LINT).c $(LINT_OBJS)
$(PRE)$(CC) $(CCAN_CFLAGS) $(DEP_CFLAGS) $(LINT).c $(LINT_OBJS) -lm -o $@
# We generate dependencies for tests into a .d file
%/.d: %/info tools/gen_deps.sh tools/ccan_depends
$(PRE)tools/gen_deps.sh $* > $@ || rm -f $@
TEST_DEPS := $(MODULES:%=%/.d)
# We produce .ok files when the tests succeed
%.ok: $(LINT) %info
$(PRE)$(LINT) $(LINT_OPTS.ok) --deps-fail-ignore $(LINT_GCOV) $(LINTFLAGS) $(dir $*) && touch $@
%.fast-ok: $(LINT) %info
$(PRE)$(LINT) $(LINT_OPTS.fast-ok) --deps-fail-ignore $(LINT_GCOV) $(LINTFLAGS) $(dir $*) && touch $@
check: $(MODULES:%=%/.ok)
fastcheck: $(MODULES:%=%/.fast-ok)
ifeq ($(strip $(filter clean config.h, $(MAKECMDGOALS))),)
-include $(DEPS) $(LINT_DEPS) $(TOOLS_DEPS) $(TEST_DEPS)
endif
# Default target: object files, info files and tools
all:: $(OBJS) $(ALL_INFOS) $(CONFIGURATOR) $(LINT) $(TOOLS)
.PHONY: clean TAGS
clean:
$(PRE)find . -name "*.d" -o -name "*.o" -o -name "*.ok" | xargs -n 256 rm -f
$(PRE)rm -f $(CONFIGURATOR) $(LINT) $(TOOLS) TAGS config.h config.h.d $(ALL_INFOS)
# 'make TAGS' builds etags
TAGS:
$(PRE)find * -name '*.[ch]' | xargs etags
# Example makefile which makes a "libccan.a" of everything under ccan/.
# For simple projects you could just do:
# SRCFILES += $(wildcard ccan/*/*.c)
#CCAN_CFLAGS=-g -O3 -Wall -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wwrite-strings -Wundef -DCCAN_STR_DEBUG=1
CCAN_CFLAGS=-g3 -ggdb -Wall -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wwrite-strings -Wundef -DCCAN_STR_DEBUG=1
CFLAGS = $(CCAN_CFLAGS) -I. $(DEPGEN)
MODS := a_star \
aga \
agar \
alignof \
altstack \
antithread \
antithread/alloc \
argcheck \
array_size \
asearch \
asort \
asprintf \
autodata \
avl \
base64 \
bdelta \
bitmap \
block_pool \
breakpoint \
btree \
build_assert \
bytestring \
cast \
ccan_tokenizer \
cdump \
charset \
check_type \
ciniparser \
compiler \
container_of \
cppmagic \
cpuid \
crc \
crcsync \
crypto/ripemd160 \
crypto/sha256 \
crypto/sha512 \
crypto/shachain \
crypto/siphash24 \
daemonize \
daemon_with_notify \
darray \
deque \
dgraph \
endian \
eratosthenes \
err \
failtest \
foreach \
generator \
grab_file \
hash \
heap \
htable \
idtree \
ilog \
invbloom \
io \
isaac \
iscsi \
jacobson_karels \
jmap \
jset \
json \
lbalance \
likely \
list \
lpq \
lqueue \
lstack \
md4 \
mem \
minmax \
net \
nfs \
noerr \
ntdb \
objset \
ogg_to_pcm \
opt \
order \
permutation \
pipecmd \
pr_log \
ptrint \
ptr_valid \
pushpull \
rbtree \
rbuf \
read_write_all \
rfc822 \
rszshm \
short_types \
siphash \
sparse_bsearch \
str \
str/hex \
strgrp \
stringbuilder \
stringmap \
strmap \
strset \
structeq \
take \
tal \
tal/grab_file \
tal/link \
tal/path \
tal/stack \
tal/str \
tal/talloc \
talloc \
tally \
tap \
tcon \
time \
timer \
tlist \
tlist2 \
ttxml \
typesafe_cb \
version \
wwviaudio \
xstring
# Anything with C files needs building; dir leaves / on, sort uniquifies
MODS_WITH_SRC = $(patsubst ccan/%/, %, $(sort $(foreach m, $(MODS), $(dir $(wildcard ccan/$m/*.c)))))
default: libccan.a
# Automatic dependency generation: makes ccan/*/*.d files.
DEPGEN=-MMD
-include $(foreach m, $(MODS), ccan/$(m)/*.d)
DIRS=$(patsubst %, ccan/%, $(filter-out $(MODS_EXCLUDE), $(MODS_WITH_SRC)))
# Generate everyone's separate Makefiles.
-include $(foreach dir, $(DIRS), $(dir)-Makefile)
ccan/%-Makefile:
@echo $@: $(wildcard ccan/$*/*.[ch]) ccan/$*/_info > $@
@echo ccan/$*.o: $(patsubst %.c, %.o, $(wildcard ccan/$*/*.c)) >> $@
# We compile all the ccan/foo/*.o files together into ccan/foo.o
OBJFILES=$(DIRS:=.o)
# We create all the .o files and link them together.
$(OBJFILES): %.o:
$(LD) -r -o $@ $^
libccan.a: $(OBJFILES)
$(AR) r $@ $(OBJFILES)
default: upload
include Makefile
# This can be overridden on cmdline to generate pages elsewhere.
WEBDIR=/srv/www/ccodearchive.net
PHP=php
MODS := $(ALL_MODULES:ccan/%=%)
upload: fastcheck
git push
ALL_PAGES=$(patsubst %, $(WEBDIR)/info/%.html, $(MODS))
DIRECT_TARBALLS=$(patsubst %, $(WEBDIR)/tarballs/%.tar.bz2, $(MODS))
......@@ -10,19 +18,13 @@ JUNKPAGES=$(JUNKDIRS:%=$(WEBDIR)/%.html)
JUNKBALLS=$(JUNKDIRS:%=$(WEBDIR)/%.tar.bz2)
PRETTIFY=$(WEBDIR)/prettify/src/run_prettify.js $(WEBDIR)/prettify/src/prettify.css
upload: fastcheck modcheck
git push
# Check MODS list in Makefile-ccan matches modules we find.
modcheck:
@FOUND=$$(echo $$(find ccan -name _info | sed 's,ccan/\(.*\)/_info,\1,' | sort) ); LISTED=$$(echo $$(echo $(MODS) | tr ' ' '\012' | sort) ); if [ "$$FOUND" = "$$LISTED" ]; then exit 0; fi; while true; do a="$${FOUND%% *}"; b="$${LISTED%% *}"; if [ "$$a" != "$$b" ]; then echo "'$$a' found but '$$b' in MOD" >&2; exit 1; fi; FOUND="$${FOUND#* }"; LISTED="$${LISTED#* }"; done
clean-tree:
[ "$(WEBDEV)" ] || ! git status --porcelain | grep .
webpages: modcheck clean-tree webpages-unchecked
webpages: clean-tree webpages-unchecked
webpages-unchecked: $(WEB_SUBDIRS) $(PRETTIFY) $(WEBDIR)/index.html $(WEBDIR)/upload.html $(WEBDIR)/uploader.php $(WEBDIR)/example-config.h $(WEBDIR)/ccan.png $(WEBDIR)/ccan-bg.png $(WEBDIR)/ccan.css $(DIRECT_TARBALLS) $(DEPEND_TARBALLS) $(WEBDIR)/ccan.tar.bz2 $(WEBDIR)/Makefile-ccan $(ALL_PAGES) junkpages
webpages-unchecked: $(WEB_SUBDIRS) $(PRETTIFY) $(WEBDIR)/index.html $(WEBDIR)/upload.html $(WEBDIR)/uploader.php $(WEBDIR)/example-config.h $(WEBDIR)/ccan.png $(WEBDIR)/ccan-bg.png $(WEBDIR)/ccan.css $(DIRECT_TARBALLS) $(DEPEND_TARBALLS) $(WEBDIR)/ccan.tar.bz2 $(ALL_PAGES) junkpages
junkpages: $(WEBDIR)/list.html $(WEBDIR)/junkcode $(JUNKPAGES) $(JUNKBALLS)
$(WEB_SUBDIRS): $(WEBDIR)
......@@ -36,33 +38,30 @@ $(WEBDIR)/junkcode/%.tar.bz2: junkcode/% $(WEBDIR)/junkcode
$(WEBDIR)/junkcode/%.html: $(WEBDIR)/junkcode/%.tar.bz2
cd $(WEBDIR) && tar xfj junkcode/$*.tar.bz2
URLPREFIX=../ php5 web/staticjunkcode.php junkcode/$* $* > $@
URLPREFIX=../ $(PHP) web/staticjunkcode.php junkcode/$* $* > $@
# We want tarball to contain ccan/; we put junkcode in, but don't depend on it.
$(WEBDIR)/ccan.tar.bz2: config.h Makefile Makefile-ccan $(shell git ls-files ccan tools licenses)
$(WEBDIR)/ccan.tar.bz2: config.h Makefile $(shell git ls-files ccan tools licenses)
DIR=`pwd` && cd /tmp && ln -sf "$$DIR" ccan && tar cvfj $@ `for f in $^; do echo ccan/$$f; done` ccan/junkcode && rm ccan
$(ALL_PAGES): tools/doc_extract web/staticmoduleinfo.php
$(WEBDIR)/list.html: web/staticall.php tools/doc_extract $(DIRECT_TARBALLS) $(DEPEND_TARBALLS) $(WEBDIR)/ccan.tar.bz2 $(JUNKBALLS)
php5 web/staticall.php ccan/ junkcode/ $(WEBDIR) $(MODS) > $@
$(PHP) web/staticall.php ccan/ junkcode/ $(WEBDIR) $(MODS) > $@
$(WEBDIR)/upload.html: web/staticupload.php
php5 web/staticupload.php > $@
$(PHP) web/staticupload.php > $@
# cpp inserts gratuitous linebreaks at start of file, makes for php problems.
$(WEBDIR)/uploader.php: web/uploader.php.cpp
cpp -w -C -P $< | grep . > $@
$(WEBDIR)/index.html: web/staticindex.php
php5 web/staticindex.php > $@
$(PHP) web/staticindex.php > $@
$(WEBDIR)/example-config.h: config.h
cp $< $@
$(WEBDIR)/Makefile-ccan: Makefile-ccan
cp $< $@
$(WEBDIR)/ccan.png: web/ccan.png
cp $< $@
......@@ -74,7 +73,7 @@ $(WEBDIR)/ccan.css: web/ccan.css
$(WEBDIR)/info/%.html: $(WEBDIR)/tarballs/%.tar.bz2 $(WEBDIR)/tarballs/with-deps/%.tar.bz2
@mkdir -p `dirname $@`
URLPREFIX=../`echo $* | tr -dc '/' | sed s',/,../,g'` php5 web/staticmoduleinfo.php `pwd`/ccan/$* $* > $@
URLPREFIX=../`echo $* | tr -dc '/' | sed s',/,../,g'` $(PHP) web/staticmoduleinfo.php `pwd`/ccan/$* $* > $@
$(WEBDIR)/tarballs/%.tar.bz2: ccan/%/_info clean-tree
@mkdir -p `dirname $@`
......
# AppVeyor CI Configuration
#
# Current build status can be viewed at
# https://ci.appveyor.com/project/dgibson/ccan
#
# To build test a fork of this repository using AppVeyor:
# 1. Visit appveyor.com and create a free account.
# 2. On the Projects tab, select "New Project" then the project hosting site.
# 3. Grant OAuth permissions to your project git host.
# 4. Select the repository for your project fork.
# 5. Review build results and push updates until the desired result is reached.
version: 0.0.{build}
platform:
- x86
- amd64
build_script:
# Reset %PATH% to avoid msys/cygwin DLL conflicts which cause
# *** fatal error - cygheap base mismatch detected
- set PATH=C:\Windows\System32;C:\Windows;C:\Windows\System32\Wbem;C:\msys64\usr\bin
# Set environment variables for chosen compiler
- "\"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" %Platform%"
# Ensure config.h can be generated.
# Note: Dash options avoid POSIX path conversion by msys
- "make config.h CC=cl CCAN_CFLAGS=\"-nologo -Zi -FS -W4 -wd4200 -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS\" CFLAGS_FORCE_C_SOURCE=-TC OUTPUT_OPTION=-Fo:$@ DEPGEN= LD=link SHELL=bash"
# FIXME: Work in progress. Disabled due to unfixed compile errors.
# FIXME: -j%NUMBER_OF_PROCESSORS% won't work without DEPGEN for config.h
# It may be possible to generate .d from cl using /showIncludes
# See https://stackoverflow.com/q/37685069
#- "make tools CC=cl CCAN_CFLAGS=\"-nologo -Zi -FS -W4 -wd4200 -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS\" CFLAGS_FORCE_C_SOURCE=-TC OUTPUT_OPTION=-Fo:$@ DEPGEN= LD=link SHELL=bash"
#- "make -k CC=cl CCAN_CFLAGS=\"-nologo -Zi -FS -W4 -wd4200 -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS\" CFLAGS_FORCE_C_SOURCE=-TC OUTPUT_OPTION=-Fo:$@ DEPGEN= LD=link SHELL=bash"
test_script:
# FIXME: Work in progress. Disabled due to unfixed compile errors.
#- "make -k check CC=cl CCAN_CFLAGS=\"-nologo -Zi -FS -W4 -wd4200 -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS\" CFLAGS_FORCE_C_SOURCE=-TC OUTPUT_OPTION=-Fo:$@ DEPGEN= LD=link SHELL=bash"
......@@ -165,6 +165,12 @@ struct aga_node {
bool complete;
struct lpq_link pqlink;
} dijkstra;
struct {
aga_icost_t distance;
struct aga_node *prev;
const void *prevedge;
struct aga_node *list;
} bellman_ford;
} u;
};
......@@ -177,6 +183,11 @@ struct aga_graph {
aga_edge_info_fn edge_info;
union {
LPQ(struct aga_node, u.dijkstra.pqlink) dijkstra;
struct {
struct aga_node *nodelist;
int nnodes;
int npasses;
} bellman_ford;
} state;
};
......@@ -416,15 +427,74 @@ bool aga_dijkstra_path(struct aga_graph *g, struct aga_node *dest,
struct aga_node **prev, const void **prevedge);
/**
* aga_dijkstra_all_paths - Find shortest paths to all reachable nodes
* aga_dijkstra_complete - Find shortest paths to all reachable nodes
* @g: graph
*
* Finds shortest paths from the source node (specified in
* aga_dijkstra_start()) to all other reachable nodes in @g. No
* results are returned directly, but between calling
* aga_dijkstra_all_paths() and aga_finish, aga_dijkstra_path() is
* aga_dijkstra_all_paths() and aga_finish(), aga_dijkstra_path() is
* guaranteed to complete in O(1) time for all destinations.
*/
void aga_dijkstra_all_paths(struct aga_graph *g);
void aga_dijkstra_complete(struct aga_graph *g);
/*
* Bellman-Ford algorithm
*/
/**
* aga_bellman_ford_start - Start Bellman-Ford algorithm
* @g: graph
* @source: source node
*
* Start's the Bellman-Ford algorithm on @g to find shortest paths
* from node @source, to other nodes in @g.
*/
int aga_bellman_ford_start(struct aga_graph *g, struct aga_node *source);
/**
* aga_bellman_ford_path - Find the shortest path to a node
* @g: graph
* @dest: destination node
* @prev: Second last node in the path *output)
* @prevedge: Last edge in the path
*
* Finds the shortest path from the source node (specified in
* aga_bellman_ford_start() to @dest using Bellman_Ford's algorithm.
*
* If no path exists, return false.
*
* If a path does exist, returns true. Additionally if @total_cost is
* non-NULL, store the total cost of the path in *@total_cost, if
* @prev is non-NULL, store the node in the path immediately before
* @dest in *@prev and if @prevedge is non-NULL stores the edge which
* leads from *@prev to @dest in *@prevedge.
*
* If @dest is the same as source, 0 will be stored in @cost, and NULL
* will be stored in *@prev and *@prevedge.
*
* The full path from source to @dest can be determined by repeatedly
* calling aga_bellman_ford_path() on *@prev.
*
* NOTE: Bellman_Ford's algorithm will not work correctly on a graph
* which contains a cycle with (total) negative cost. If aga detects
* this case, it will set aga_error() to AGA_ERR_NEGATIVE_COST.
*/
bool aga_bellman_ford_path(struct aga_graph *g, struct aga_node *dest,
aga_icost_t *total_cost,
struct aga_node **prev, const void **prevedge);
/**
* aga_bellman_ford_complete - Run Bellman-Ford algorithm to completion
* @g: graph
*
* Finds shortest paths from the source node (specified in
* aga_bellman_ford_start()) to all other reachable nodes in @g. No
* results are returned directly, but between calling
* aga_bellman_ford_complete() and aga_finish(),
* aga_bellman_ford_path() is guaranteed to complete in O(1) time for
* all destinations.
*/
void aga_bellman_ford_complete(struct aga_graph *g);
#endif /* CCAN_AGA_H */
/* Licensed under LGPLv2+ - see LICENSE file for details */
#include "config.h"
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include <ccan/build_assert/build_assert.h>
#include <ccan/check_type/check_type.h>
#include <ccan/order/order.h>
#include <ccan/aga/aga.h>
#include "private.h"
/*
* The Bellman-Ford algorithm
*/
static bool candidate_path(struct aga_graph *g, struct aga_node *node,
aga_icost_t distance,
struct aga_node *prev, const void *prevedge)
{
if (aga_update_node(g, node)) {
/* New node, treat as having infinite distance */
node->u.bellman_ford.distance = distance;
node->u.bellman_ford.prev = prev;
node->u.bellman_ford.prevedge = prevedge;
node->u.bellman_ford.list = g->state.bellman_ford.nodelist;
g->state.bellman_ford.nodelist = node;
g->state.bellman_ford.nnodes++;
return true;
} else if (distance < node->u.bellman_ford.distance) {
node->u.bellman_ford.distance = distance;
node->u.bellman_ford.prev = prev;
node->u.bellman_ford.prevedge = prevedge;
}
return false;
}
int aga_bellman_ford_start(struct aga_graph *g, struct aga_node *source)
{
int rc;
/* Make sure we're actually using the right ordering for
* aga_icost_t */
BUILD_ASSERT(check_types_match(long, aga_icost_t) == 0);
rc = aga_start(g);
if (rc < 0)
return rc;
g->state.bellman_ford.nodelist = NULL;
g->state.bellman_ford.nnodes = 0;
g->state.bellman_ford.npasses = 0;
candidate_path(g, source, 0, NULL, NULL);
return 0;
}
static bool aga_bellman_ford_step(struct aga_graph *g)
{
struct aga_node *n;
const void *e;
struct aga_edge_info ei;
int err;
bool newnode = false;
if (!aga_check_state(g))
return false;
for (n = g->state.bellman_ford.nodelist;
n; n = n->u.bellman_ford.list) {
aga_for_each_edge_info(e, ei, err, g, n) {
aga_icost_t dist = n->u.bellman_ford.distance
+ ei.icost;
newnode = newnode || candidate_path(g, ei.to, dist, n, e);
}
if (err) {
aga_fail(g, err);
return false;
}
}
g->state.bellman_ford.npasses++;
return newnode || (g->state.bellman_ford.npasses
< g->state.bellman_ford.nnodes);
}
void aga_bellman_ford_complete(struct aga_graph *g)
{
struct aga_node *n;
const void *e;
struct aga_edge_info ei;
int err;
if (!aga_check_state(g))
return;
while (aga_bellman_ford_step(g))
;
/* Check for negative cycles */
for (n = g->state.bellman_ford.nodelist;
n; n = n->u.bellman_ford.list) {
aga_for_each_edge_info(e, ei, err, g, n) {
if ((n->u.bellman_ford.distance + ei.icost)
< ei.to->u.bellman_ford.distance) {
aga_fail(g, AGA_ERR_NEGATIVE_COST);
return;
}
}
if (err) {
aga_fail(g, err);
return;
}
}
}
bool aga_bellman_ford_path(struct aga_graph *g, struct aga_node *node,
aga_icost_t *total_cost,
struct aga_node **prev, const void **prevedge)
{
aga_bellman_ford_complete(g);
if (!aga_check_state(g))
return false;
if (aga_node_needs_update(g, node))
return false;
if (total_cost)
*total_cost = node->u.bellman_ford.distance;
if (prev)
*prev = node->u.bellman_ford.prev;
if (prevedge)
*prevedge = node->u.bellman_ford.prevedge;
return true;
}
......@@ -114,7 +114,7 @@ bool aga_dijkstra_path(struct aga_graph *g, struct aga_node *node,
return true;
}
void aga_dijkstra_all_paths(struct aga_graph *g)
void aga_dijkstra_complete(struct aga_graph *g)
{
if (!aga_check_state(g))
return;
......
......@@ -63,8 +63,9 @@ int main(void)
struct traversal1_graph t1g;
struct shortcut1_graph s1g;
struct shortcut2_graph s2g;
struct negacycle_graph ng;
plan_tests(2 + 7 + 35 + 30 + 30 + 42 + 9 + 30 + 9 + 9);
plan_tests(2 + 7 + 35 + 30 + 30 + 42 + 9 + 30 + 9 + 9 + 9);
trivial_graph_init(&tg);
test_adjacency("trivial", &tg.sg, trivial_adjacency);
......@@ -99,5 +100,8 @@ int main(void)
shortcut2_graph_init(&s2g);
test_adjacency("shortcut2 graph", &s2g.sg, shortcut2_adjacency);
negacycle_graph_init(&ng);
test_adjacency("negacycle graph", &ng.sg, negacycle_adjacency);
return exit_status();
}
#include "config.h"
#include <stddef.h>
#include <assert.h>
#include <stdlib.h>
#include <ccan/tap/tap.h>
#include <ccan/array_size/array_size.h>
#include <ccan/aga/aga.h>
#include "simple-graph.h"
static void test_trivial(void)
{
struct trivial_graph tg;
aga_icost_t cost;
struct aga_node *node;
const void *edge;
trivial_graph_init(&tg);
ok1(aga_bellman_ford_start(&tg.sg.g, &tg.sg.nodes[1]) == 0);
ok1(aga_bellman_ford_path(&tg.sg.g, &tg.sg.nodes[1], &cost, &node, &edge));
ok1(cost == 0);
ok1(node == NULL);
ok1(edge == NULL);
aga_finish(&tg.sg.g);
}
static void test_parallel(void)
{
struct parallel_graph pg;
aga_icost_t cost;
struct aga_node *node;
const void *edge;
parallel_graph_init(&pg, 3, 0);
ok1(aga_bellman_ford_start(&pg.sg.g, &pg.sg.nodes[1]) == 0);
ok1(aga_bellman_ford_path(&pg.sg.g, &pg.sg.nodes[1], &cost, NULL, NULL));
ok1(cost == 0);
ok1(aga_bellman_ford_path(&pg.sg.g, &pg.sg.nodes[2], &cost, &node, NULL));
ok1(cost == 2);
ok1(node == &pg.sg.nodes[1]);
aga_finish(&pg.sg.g);
ok1(aga_bellman_ford_start(&pg.sg.g, &pg.sg.nodes[2]) == 0);
ok1(aga_bellman_ford_path(&pg.sg.g, &pg.sg.nodes[2], &cost, NULL, NULL));
ok1(cost == 0);
ok1(!aga_bellman_ford_path(&pg.sg.g, &pg.sg.nodes[1], NULL, NULL, NULL));
aga_finish(&pg.sg.g);