diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..5b2d46270d --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.sconsign.dblite diff --git a/.gitignore b/.gitignore index 3f6de09fb9..5053090f14 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,12 @@ node_modules package-lock.json *.pyc __pycache__ +.*.swp +.*.swo +libcereal*.a +libmessaging.* +libmessaging_shared.* +services.h +.sconsign.dblite +libcereal_shared.so diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..f681dce68f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +from ubuntu:16.04 + +RUN apt-get update && apt-get install -y libzmq3-dev clang wget git autoconf libtool curl make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl + +RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash +ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" +RUN pyenv install 3.7.3 +RUN pyenv global 3.7.3 +RUN pyenv rehash +RUN pip3 install pyyaml==5.1.2 Cython==0.29.14 scons==3.1.1 pycapnp==0.6.4 + +WORKDIR /project/cereal +COPY install_capnp.sh . +RUN ./install_capnp.sh + +ENV PYTHONPATH=/project + +COPY . . +RUN scons -c && scons -j$(nproc) diff --git a/Makefile b/Makefile deleted file mode 100644 index 83318bef33..0000000000 --- a/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -PWD := $(shell pwd) - -SRCS := log.capnp car.capnp - -GENS := gen/cpp/car.capnp.c++ gen/cpp/log.capnp.c++ -JS := gen/js/car.capnp.js gen/js/log.capnp.js - -UNAME_M ?= $(shell uname -m) - -GENS += gen/c/car.capnp.c gen/c/log.capnp.c gen/c/include/c++.capnp.h gen/c/include/java.capnp.h - -ifeq ($(UNAME_M),x86_64) - -ifneq (, $(shell which capnpc-java)) -GENS += gen/java/Car.java gen/java/Log.java -else -$(warning capnpc-java not found, skipping java build) -endif - -endif - - -ifeq ($(UNAME_M),aarch64) -CAPNPC=PATH=$(PWD)/../phonelibs/capnp-cpp/aarch64/bin/:$$PATH capnpc -else -CAPNPC=capnpc -endif - -.PHONY: all -all: $(GENS) -js: $(JS) - -.PHONY: clean -clean: - rm -rf gen - rm -rf node_modules - rm -rf package-lock.json - -gen/c/%.capnp.c: %.capnp - @echo "[ CAPNPC C ] $@" - mkdir -p gen/c/ - $(CAPNPC) '$<' -o c:gen/c/ - -gen/js/%.capnp.js: %.capnp - @echo "[ CAPNPC JavaScript ] $@" - mkdir -p gen/js/ - sh ./generate_javascript.sh - -gen/cpp/%.capnp.c++: %.capnp - @echo "[ CAPNPC C++ ] $@" - mkdir -p gen/cpp/ - $(CAPNPC) '$<' -o c++:gen/cpp/ - -gen/java/Car.java gen/java/Log.java: $(SRCS) - @echo "[ CAPNPC java ] $@" - mkdir -p gen/java/ - $(CAPNPC) $^ -o java:gen/java - -# c-capnproto needs some empty headers -gen/c/include/c++.capnp.h gen/c/include/java.capnp.h: - mkdir -p gen/c/include - touch '$@' diff --git a/SConscript b/SConscript new file mode 100644 index 0000000000..789e83023a --- /dev/null +++ b/SConscript @@ -0,0 +1,68 @@ +Import('env', 'arch', 'zmq') + +gen_dir = Dir('gen') +messaging_dir = Dir('messaging') + +# TODO: remove src-prefix and cereal from command string. can we set working directory? +env.Command(["gen/c/include/c++.capnp.h", "gen/c/include/java.capnp.h"], [], "mkdir -p " + gen_dir.path + "/c/include && touch $TARGETS") +env.Command( + ['gen/c/car.capnp.c', 'gen/c/log.capnp.c', 'gen/c/car.capnp.h', 'gen/c/log.capnp.h'], + ['car.capnp', 'log.capnp'], + 'capnpc $SOURCES --src-prefix=cereal -o c:' + gen_dir.path + '/c/') +env.Command( + ['gen/cpp/car.capnp.c++', 'gen/cpp/log.capnp.c++', 'gen/cpp/car.capnp.h', 'gen/cpp/log.capnp.h'], + ['car.capnp', 'log.capnp'], + 'capnpc $SOURCES --src-prefix=cereal -o c++:' + gen_dir.path + '/cpp/') +import shutil +if shutil.which('capnpc-java'): + env.Command( + ['gen/java/Car.java', 'gen/java/Log.java'], + ['car.capnp', 'log.capnp'], + 'capnpc $SOURCES --src-prefix=cereal -o java:' + gen_dir.path + '/java/') + +# TODO: remove non shared cereal and messaging +cereal_objects = env.SharedObject([ + 'gen/c/car.capnp.c', + 'gen/c/log.capnp.c', + 'gen/cpp/car.capnp.c++', + 'gen/cpp/log.capnp.c++', + ]) + +env.Library('cereal', cereal_objects) +env.SharedLibrary('cereal_shared', cereal_objects) + +cereal_dir = Dir('.') +services_h = env.Command( + ['services.h'], + ['service_list.yaml', 'services.py'], + 'python3 ' + cereal_dir.path + '/services.py > $TARGET') + +messaging_objects = env.SharedObject([ + 'messaging/messaging.cc', + 'messaging/impl_zmq.cc', + 'messaging/impl_msgq.cc', + 'messaging/msgq.cc', +]) + +messaging_lib = env.Library('messaging', messaging_objects) +Depends('messaging/impl_zmq.cc', services_h) + +# note, this rebuilds the deps shared, zmq is statically linked to make APK happy +# TODO: get APK to load system zmq to remove the static link +shared_lib_shared_lib = [zmq, 'm', 'stdc++'] + ["gnustl_shared"] if arch == "aarch64" else [] +env.SharedLibrary('messaging_shared', messaging_objects, LIBS=shared_lib_shared_lib) + +env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[messaging_lib, 'zmq']) +Depends('messaging/bridge.cc', services_h) + +# different target? +#env.Program('messaging/demo', ['messaging/demo.cc'], LIBS=[messaging_lib, 'zmq']) + + +env.Command(['messaging/messaging_pyx.so'], + [messaging_lib, 'messaging/messaging_pyx_setup.py', 'messaging/messaging_pyx.pyx', 'messaging/messaging.pxd'], + "cd " + messaging_dir.path + " && python3 messaging_pyx_setup.py build_ext --inplace") + + +if GetOption('test'): + env.Program('messaging/test_runner', ['messaging/test_runner.cc', 'messaging/msgq_tests.cc'], LIBS=[messaging_lib]) diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000000..a72286b279 --- /dev/null +++ b/SConstruct @@ -0,0 +1,49 @@ +import os +import subprocess + +zmq = 'zmq' +arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() + +cereal_dir = Dir('.') + +cpppath = [ + cereal_dir, + '/usr/lib/include', +] + +AddOption('--test', + action='store_true', + help='build test files') + +AddOption('--asan', + action='store_true', + help='turn on ASAN') + +ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] if GetOption('asan') else [] +ldflags_asan = ["-fsanitize=address"] if GetOption('asan') else [] + +env = Environment( + ENV=os.environ, + CC='clang', + CXX='clang++', + CCFLAGS=[ + "-g", + "-fPIC", + "-O2", + "-Werror=implicit-function-declaration", + "-Werror=incompatible-pointer-types", + "-Werror=int-conversion", + "-Werror=return-type", + "-Werror=format-extra-args", + ] + ccflags_asan, + LDFLAGS=ldflags_asan, + LINKFLAGS=ldflags_asan, + + CFLAGS="-std=gnu11", + CXXFLAGS="-std=c++14", + CPPPATH=cpppath, +) + + +Export('env', 'zmq', 'arch') +SConscript(['SConscript']) diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000..c14526a5c1 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,14 @@ +pr: none + +pool: + vmImage: 'ubuntu-16.04' + +steps: +- script: | + set -e + docker build -t cereal . + docker run cereal bash -c "scons --test --asan -j$(nproc) && messaging/test_runner" + docker run cereal bash -c "ZMQ=1 python -m unittest discover ." + docker run cereal bash -c "MSGQ=1 python -m unittest discover ." + + displayName: 'Run Tests' diff --git a/car.capnp b/car.capnp index c38bc7d312..68a723206a 100644 --- a/car.capnp +++ b/car.capnp @@ -84,6 +84,10 @@ struct CarEvent @0x9b1657f34caf3ad3 { laneChange @59; invalidGiraffeToyota @60; internetConnectivityNeeded @61; + communityFeatureDisallowed @62; + lowMemory @63; + stockAeb @64; + ldw @65; } } @@ -117,6 +121,9 @@ struct CarState { steeringTorque @8 :Float32; # TODO: standardize units steeringTorqueEps @27 :Float32; # TODO: standardize units steeringPressed @9 :Bool; # if the user is using the steering wheel + steeringRateLimited @29 :Bool; # if the torque is limited by the rate limiter + stockAeb @30 :Bool; + stockFcw @31 :Bool; # cruise state cruiseState @10 :CruiseState; @@ -170,7 +177,6 @@ struct CarState { manumatic @9; } - # send on change struct ButtonEvent { pressed @0 :Bool; @@ -314,7 +320,7 @@ struct CarParams { minEnableSpeed @7 :Float32; minSteerSpeed @8 :Float32; safetyModel @9 :SafetyModel; - safetyModelPassive @42 :SafetyModel = noOutput; + safetyModelPassive @42 :SafetyModel = silent; safetyParam @10 :Int16; steerMaxBP @11 :List(Float32); @@ -324,7 +330,6 @@ struct CarParams { brakeMaxBP @15 :List(Float32); brakeMaxV @16 :List(Float32); - # things about the car in the manual mass @17 :Float32; # [kg] running weight wheelbase @18 :Float32; # [m] distance from rear to front axle @@ -345,6 +350,7 @@ struct CarParams { } steerLimitAlert @28 :Bool; + steerLimitTimer @47 :Float32; # time before steerLimitAlert is issued vEgoStopping @29 :Float32; # Speed at which the car goes into stopping state directAccelControl @30 :Bool; # Does the car have direct accel control or just gas/brake @@ -360,6 +366,9 @@ struct CarParams { isPandaBlack @39: Bool; dashcamOnly @41: Bool; transmissionType @43 :TransmissionType; + carFw @44 :List(CarFw); + radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard + communityFeature @46: Bool; # true if a community maintained feature is detected struct LateralPIDTuning { kpBP @0 :List(Float32); @@ -378,7 +387,6 @@ struct CarParams { deadzoneV @5 :List(Float32); } - struct LateralINDITuning { outerLoopGain @0 :Float32; innerLoopGain @1 :Float32; @@ -401,7 +409,7 @@ struct CarParams { } enum SafetyModel { - noOutput @0; + silent @0; honda @1; toyota @2; elm327 @3; @@ -420,6 +428,7 @@ struct CarParams { toyotaIpas @16; allOutput @17; gmAscm @18; + noOutput @19; # like silent but with silent CAN TXs } enum SteerControlType { @@ -432,4 +441,16 @@ struct CarParams { automatic @1; manual @2; } + + struct CarFw { + ecu @0 :Ecu; + fwVersion @1 :Text; + } + + enum Ecu { + eps @0; + esp @1; + fwdRadar @2; + fwdCamera @3; + } } diff --git a/install_capnp.sh b/install_capnp.sh index b83e1ffda1..cc570b60ff 100755 --- a/install_capnp.sh +++ b/install_capnp.sh @@ -8,7 +8,8 @@ tar xvf capnproto-c++-${VERSION}.tar.gz cd capnproto-c++-${VERSION} CXXFLAGS="-fPIC" ./configure -make -j4 +make -j$(nproc) +make install # manually build binaries statically g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnp src/capnp/compiler/module-loader.o src/capnp/compiler/capnp.o ./.libs/libcapnpc.a ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread @@ -18,7 +19,6 @@ g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -D g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnpc-capnp src/capnp/compiler/capnpc-capnp.o ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread cp .libs/capnp /usr/local/bin/ -ln -s /usr/local/bin/capnp /usr/local/bin/capnpc cp .libs/capnpc-c++ /usr/local/bin/ cp .libs/capnpc-capnp /usr/local/bin/ cp .libs/*.a /usr/local/lib @@ -30,7 +30,8 @@ cd c-capnproto git submodule update --init --recursive autoreconf -f -i -s CXXFLAGS="-fPIC" ./configure -make -j4 +make -j$(nproc) +make install # manually build binaries statically gcc -fPIC -o .libs/capnpc-c compiler/capnpc-c.o compiler/schema.capnp.o compiler/str.o ./.libs/libcapnp_c.a diff --git a/log.capnp b/log.capnp index 0fd5155bf6..b059218feb 100644 --- a/log.capnp +++ b/log.capnp @@ -126,6 +126,7 @@ struct FrameData { lensErr @13 :Float32; lensTruePos @14 :Float32; image @6 :Data; + gainFrac @15 :Float32; frameType @7 :FrameType; timestampSof @8 :UInt64; @@ -137,6 +138,7 @@ struct FrameData { unknown @0; neo @1; chffrAndroid @2; + front @3; } struct AndroidCaptureResult { @@ -268,6 +270,7 @@ struct ThermalData { mem @4 :UInt16; gpu @5 :UInt16; bat @6 :UInt32; + pa0 @21 :UInt16; # not thermal freeSpace @7 :Float32; @@ -285,6 +288,9 @@ struct ThermalData { chargingError @17 :Bool; chargingDisabled @18 :Bool; + memUsedPercent @19 :Int8; + cpuPerc @20 :Int8; + enum ThermalStatus { green @0; # all processes run yellow @1; # critical processes run (kill uploader), engage still allowed @@ -310,6 +316,20 @@ struct HealthData { usbPowerMode @12 :UsbPowerMode; ignitionCan @13 :Bool; safetyModel @14 :Car.CarParams.SafetyModel; + faultStatus @15 :FaultStatus; + powerSaveEnabled @16 :Bool; + uptime @17 :UInt32; + faults @18 :List(FaultType); + + enum FaultStatus { + none @0; + faultTemp @1; + faultPerm @2; + } + + enum FaultType { + relayMalfunction @0; + } enum HwType { unknown @0; @@ -509,6 +529,7 @@ struct ControlsState @0x97ff69c53601abf1 { delayedOutput @7 :Float32; delta @8 :Float32; output @9 :Float32; + saturated @10 :Bool; } struct LateralPIDState { @@ -529,6 +550,7 @@ struct ControlsState @0x97ff69c53601abf1 { i @2 :Float32; output @3 :Float32; lqrOutput @4 :Float32; + saturated @5 :Bool; } @@ -552,6 +574,7 @@ struct ModelData { settings @5 :ModelSettings; leadFuture @7 :LeadData; speed @8 :List(Float32); + meta @10 :MetaData; struct PathData { points @0 :List(Float32); @@ -582,6 +605,13 @@ struct ModelData { yuvCorrection @5 :List(Float32); inputTransform @6 :List(Float32); } + struct MetaData { + engagedProb @0 :Float32; + desirePrediction @1 :List(Float32); + brakeDisengageProb @2 :Float32; + gasDisengageProb @3 :Float32; + steerOverrideProb @4 :Float32; + } } struct CalibrationFeatures { @@ -1649,6 +1679,7 @@ struct UiLayoutState { home @0; music @1; nav @2; + settings @3; } } @@ -1725,7 +1756,7 @@ struct DriverMonitoring { rightEyeProb @7 :Float32; leftBlinkProb @8 :Float32; rightBlinkProb @9 :Float32; - irPwr @10 :Float32; + irPwrDEPRECATED @10 :Float32; } struct Boot { @@ -1857,5 +1888,6 @@ struct Event { thumbnail @66: Thumbnail; carEvents @68: List(Car.CarEvent); carParams @69: Car.CarParams; + frontFrame @70: FrameData; } } diff --git a/messaging/.gitignore b/messaging/.gitignore new file mode 100644 index 0000000000..dbbe8e22ae --- /dev/null +++ b/messaging/.gitignore @@ -0,0 +1,10 @@ +demo +bridge +test_runner +*.o +*.os +*.d +*.a +*.so +messaging_pyx.cpp +build/ diff --git a/messaging/__init__.py b/messaging/__init__.py new file mode 100644 index 0000000000..7a0d4936b3 --- /dev/null +++ b/messaging/__init__.py @@ -0,0 +1,219 @@ +# must be build with scons +from .messaging_pyx import Context, Poller, SubSocket, PubSocket # pylint: disable=no-name-in-module, import-error +from .messaging_pyx import MultiplePublishersError, MessagingError # pylint: disable=no-name-in-module, import-error + +assert MultiplePublishersError +assert MessagingError + +from cereal import log +from cereal.services import service_list + +# sec_since_boot is faster, but allow to run standalone too +try: + from common.realtime import sec_since_boot +except ImportError: + import time + sec_since_boot = time.time + print("Warning, using python time.time() instead of faster sec_since_boot") + +context = Context() + +def new_message(): + dat = log.Event.new_message() + dat.logMonoTime = int(sec_since_boot() * 1e9) + dat.valid = True + return dat + +def pub_sock(endpoint): + sock = PubSocket() + sock.connect(context, endpoint) + return sock + +def sub_sock(endpoint, poller=None, addr="127.0.0.1", conflate=False, timeout=None): + sock = SubSocket() + addr = addr.encode('utf8') + sock.connect(context, endpoint, addr, conflate) + + if timeout is not None: + sock.setTimeout(timeout) + + if poller is not None: + poller.registerSocket(sock) + return sock + + +def drain_sock_raw(sock, wait_for_one=False): + """Receive all message currently available on the queue""" + ret = [] + while 1: + if wait_for_one and len(ret) == 0: + dat = sock.receive() + else: + dat = sock.receive(non_blocking=True) + + if dat is None: + break + + ret.append(dat) + + return ret + +def drain_sock(sock, wait_for_one=False): + """Receive all message currently available on the queue""" + ret = [] + while 1: + if wait_for_one and len(ret) == 0: + dat = sock.receive() + else: + dat = sock.receive(non_blocking=True) + + if dat is None: # Timeout hit + break + + dat = log.Event.from_bytes(dat) + ret.append(dat) + + return ret + + +# TODO: print when we drop packets? +def recv_sock(sock, wait=False): + """Same as drain sock, but only returns latest message. Consider using conflate instead.""" + dat = None + + while 1: + if wait and dat is None: + rcv = sock.receive() + else: + rcv = sock.receive(non_blocking=True) + + if rcv is None: # Timeout hit + break + + dat = rcv + + if dat is not None: + dat = log.Event.from_bytes(dat) + + return dat + +def recv_one(sock): + dat = sock.receive() + if dat is not None: + dat = log.Event.from_bytes(dat) + return dat + +def recv_one_or_none(sock): + dat = sock.receive(non_blocking=True) + if dat is not None: + dat = log.Event.from_bytes(dat) + return dat + +def recv_one_retry(sock): + """Keep receiving until we get a message""" + while True: + dat = sock.receive() + if dat is not None: + return log.Event.from_bytes(dat) + +def get_one_can(logcan): + while True: + can = recv_one_retry(logcan) + if len(can.can) > 0: + return can + +class SubMaster(): + def __init__(self, services, ignore_alive=None, addr="127.0.0.1"): + self.poller = Poller() + self.frame = -1 + self.updated = {s : False for s in services} + self.rcv_time = {s : 0. for s in services} + self.rcv_frame = {s : 0 for s in services} + self.alive = {s : False for s in services} + self.sock = {} + self.freq = {} + self.data = {} + self.logMonoTime = {} + self.valid = {} + + if ignore_alive is not None: + self.ignore_alive = ignore_alive + else: + self.ignore_alive = [] + + for s in services: + if addr is not None: + self.sock[s] = sub_sock(s, poller=self.poller, addr=addr, conflate=True) + self.freq[s] = service_list[s].frequency + + data = new_message() + if s in ['can', 'sensorEvents', 'liveTracks', 'sendCan', + 'ethernetData', 'cellInfo', 'wifiScan', + 'trafficEvents', 'orbObservation', 'carEvents']: + data.init(s, 0) + else: + data.init(s) + self.data[s] = getattr(data, s) + self.logMonoTime[s] = 0 + self.valid[s] = data.valid + + def __getitem__(self, s): + return self.data[s] + + def update(self, timeout=1000): + msgs = [] + for sock in self.poller.poll(timeout): + msgs.append(recv_one_or_none(sock)) + self.update_msgs(sec_since_boot(), msgs) + + def update_msgs(self, cur_time, msgs): + # TODO: add optional input that specify the service to wait for + self.frame += 1 + self.updated = dict.fromkeys(self.updated, False) + for msg in msgs: + if msg is None: + continue + + s = msg.which() + self.updated[s] = True + self.rcv_time[s] = cur_time + self.rcv_frame[s] = self.frame + self.data[s] = getattr(msg, s) + self.logMonoTime[s] = msg.logMonoTime + self.valid[s] = msg.valid + + for s in self.data: + # arbitrary small number to avoid float comparison. If freq is 0, we can skip the check + if self.freq[s] > 1e-5: + # alive if delay is within 10x the expected frequency + self.alive[s] = (cur_time - self.rcv_time[s]) < (10. / self.freq[s]) + else: + self.alive[s] = True + + def all_alive(self, service_list=None): + if service_list is None: # check all + service_list = self.alive.keys() + return all(self.alive[s] for s in service_list if s not in self.ignore_alive) + + def all_valid(self, service_list=None): + if service_list is None: # check all + service_list = self.valid.keys() + return all(self.valid[s] for s in service_list) + + def all_alive_and_valid(self, service_list=None): + if service_list is None: # check all + service_list = self.alive.keys() + return self.all_alive(service_list=service_list) and self.all_valid(service_list=service_list) + + +class PubMaster(): + def __init__(self, services): + self.sock = {} + for s in services: + self.sock[s] = pub_sock(s) + + def send(self, s, dat): + # accept either bytes or capnp builder + if not isinstance(dat, bytes): + dat = dat.to_bytes() + self.sock[s].send(dat) diff --git a/messaging/bridge.cc b/messaging/bridge.cc new file mode 100644 index 0000000000..7abcdd09da --- /dev/null +++ b/messaging/bridge.cc @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include + +#include "services.h" + +#include "impl_msgq.hpp" +#include "impl_zmq.hpp" + +void sigpipe_handler(int sig) { + assert(sig == SIGPIPE); + std::cout << "SIGPIPE received" << std::endl; +} + +static std::vector get_services() { + std::vector name_list; + + for (const auto& it : services) { + std::string name = it.name; + if (name == "plusFrame" || name == "uiLayoutState") continue; + name_list.push_back(name); + } + + return name_list; +} + + +int main(void){ + signal(SIGPIPE, (sighandler_t)sigpipe_handler); + + auto endpoints = get_services(); + + std::map sub2pub; + + Context *zmq_context = new ZMQContext(); + Context *msgq_context = new MSGQContext(); + Poller *poller = new MSGQPoller(); + + for (auto endpoint: endpoints){ + SubSocket * msgq_sock = new MSGQSubSocket(); + msgq_sock->connect(msgq_context, endpoint, "127.0.0.1", false); + poller->registerSocket(msgq_sock); + + PubSocket * zmq_sock = new ZMQPubSocket(); + zmq_sock->connect(zmq_context, endpoint); + + sub2pub[msgq_sock] = zmq_sock; + } + + + while (true){ + for (auto sub_sock : poller->poll(100)){ + Message * msg = sub_sock->receive(); + if (msg == NULL) continue; + sub2pub[sub_sock]->sendMessage(msg); + delete msg; + } + } + return 0; +} diff --git a/messaging/catch2/catch.hpp b/messaging/catch2/catch.hpp new file mode 100644 index 0000000000..5feb2a4bea --- /dev/null +++ b/messaging/catch2/catch.hpp @@ -0,0 +1,17075 @@ +/* + * Catch v2.9.2 + * Generated: 2019-08-08 13:35:12.279703 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 9 +#define CATCH_VERSION_PATCH 2 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#ifdef __clang__ + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Check if string_view is available and usable +// The check is split apart to work around v140 (VS2015) preprocessor issue... +#if defined(__has_include) +#if __has_include() && defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW +#endif +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Check if optional is available and usable +#if defined(__has_include) +# if __has_include() && defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL +# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // __has_include + +//////////////////////////////////////////////////////////////////////////////// +// Check if byte is available and usable +#if defined(__has_include) +# if __has_include() && defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_BYTE +# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // __has_include + +//////////////////////////////////////////////////////////////////////////////// +// Check if variant is available and usable +#if defined(__has_include) +# if __has_include() && defined(CATCH_CPP17_OR_GREATER) +# if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 +# include +# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) +# define CATCH_CONFIG_NO_CPP17_VARIANT +# else +# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT +# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) +# else +# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT +# endif // defined(__clang__) && (__clang_major__ < 8) +# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // __has_include + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept; + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. c_str() must return a null terminated + /// string, however, and so the StringRef will internally take ownership + /// (taking a copy), if necessary. In theory this ownership is not externally + /// visible - but it does mean (substring) StringRefs should not be shared between + /// threads. + class StringRef { + public: + using size_type = std::size_t; + + private: + friend struct StringRefTestAccess; + + char const* m_start; + size_type m_size; + + char* m_data = nullptr; + + void takeOwnership(); + + static constexpr char const* const s_empty = ""; + + public: // construction/ assignment + StringRef() noexcept + : StringRef( s_empty, 0 ) + {} + + StringRef( StringRef const& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ) + {} + + StringRef( StringRef&& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ), + m_data( other.m_data ) + { + other.m_data = nullptr; + } + + StringRef( char const* rawChars ) noexcept; + + StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + ~StringRef() noexcept { + delete[] m_data; + } + + auto operator = ( StringRef const &other ) noexcept -> StringRef& { + delete[] m_data; + m_data = nullptr; + m_start = other.m_start; + m_size = other.m_size; + return *this; + } + + operator std::string() const; + + void swap( StringRef& other ) noexcept; + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != ( StringRef const& other ) const noexcept -> bool; + + auto operator[] ( size_type index ) const noexcept -> char; + + public: // named queries + auto empty() const noexcept -> bool { + return m_size == 0; + } + auto size() const noexcept -> size_type { + return m_size; + } + + auto numberOfCharacters() const noexcept -> size_type; + auto c_str() const -> char const*; + + public: // substrings and searches + auto substr( size_type start, size_type size ) const noexcept -> StringRef; + + // Returns the current start pointer. + // Note that the pointer can change when if the StringRef is a substring + auto currentData() const noexcept -> char const*; + + private: // ownership queries - may not be consistent between calls + auto isOwned() const noexcept -> bool; + auto isSubstring() const noexcept -> bool; + }; + + auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; + auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; + auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } + +} // namespace Catch + +inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_type_traits.hpp + + +#include + +namespace Catch{ + +#ifdef CATCH_CPP17_OR_GREATER + template + inline constexpr auto is_unique = std::true_type{}; + + template + inline constexpr auto is_unique = std::bool_constant< + (!std::is_same_v && ...) && is_unique + >{}; +#else + +template +struct is_unique : std::true_type{}; + +template +struct is_unique : std::integral_constant +::value + && is_unique::value + && is_unique::value +>{}; + +#endif +} + +// end catch_type_traits.hpp +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + \ + template class L1, typename...E1, template class L2, typename...E2> \ + constexpr auto append(L1, L2) noexcept -> L1 { return {}; }\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + constexpr auto append(L1, L2, Rest...) noexcept -> decltype(append(L1{}, Rest{}...)) { return {}; }\ + template< template class L1, typename...E1, typename...Rest>\ + constexpr auto append(L1, TypeList, Rest...) noexcept -> L1 { return {}; }\ + \ + template< template class Container, template class List, typename...elems>\ + constexpr auto rewrap(List) noexcept -> TypeList> { return {}; }\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + constexpr auto rewrap(List,Elements...) noexcept -> decltype(append(TypeList>{}, rewrap(Elements{}...))) { return {}; }\ + \ + template