mirror of
https://github.com/berthubert/galmon.git
synced 2026-11-09 16:39:15 -05:00
Compare commits
96 changed files with 13293 additions and 16402 deletions
12
.github/workflows/ccpp.yml
vendored
12
.github/workflows/ccpp.yml
vendored
|
|
@ -4,15 +4,15 @@ on: [push]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v1
|
||||||
with:
|
|
||||||
submodules: "recursive"
|
|
||||||
- name: deps
|
- name: deps
|
||||||
run: |
|
run: sudo apt-get install protobuf-compiler libh2o-dev libcurl4-openssl-dev libssl-dev libprotobuf-dev libh2o-evloop-dev libwslay-dev libncurses5-dev libeigen3-dev libzstd-dev
|
||||||
sudo apt-get update
|
- name: submodules
|
||||||
sudo apt-get install protobuf-compiler libh2o-dev libcurl4-openssl-dev libssl-dev libprotobuf-dev libh2o-evloop-dev libwslay-dev libncurses5-dev libeigen3-dev libzstd-dev libfec-dev libfmt-dev
|
run: git submodule update --init --recursive
|
||||||
- name: config
|
- name: config
|
||||||
run: echo WSLAY=-lwslay > Makefile.local
|
run: echo WSLAY=-lwslay > Makefile.local
|
||||||
- name: make
|
- name: make
|
||||||
|
|
|
||||||
12
.github/workflows/docker.yml
vendored
12
.github/workflows/docker.yml
vendored
|
|
@ -9,22 +9,22 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v2
|
||||||
- name: Checkout submodules
|
- name: Checkout submodules
|
||||||
run: git submodule update --init --recursive
|
run: git submodule update --init --recursive
|
||||||
- name: Set up docker qemu
|
|
||||||
id: qemu
|
|
||||||
uses: docker/setup-qemu-action@v4
|
|
||||||
- name: Set up docker buildx
|
- name: Set up docker buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v4
|
uses: crazy-max/ghaction-docker-buildx@v3
|
||||||
|
with:
|
||||||
|
buildx-version: latest
|
||||||
|
qemu-version: latest
|
||||||
- name: Login to docker registry
|
- name: Login to docker registry
|
||||||
run: |
|
run: |
|
||||||
docker login --username ${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_TOKEN }}
|
docker login --username ${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_TOKEN }}
|
||||||
- name: Run buildx
|
- name: Run buildx
|
||||||
run: |
|
run: |
|
||||||
docker buildx build \
|
docker buildx build \
|
||||||
--tag berthubert/galmon \
|
--tag galmon/galmon \
|
||||||
--platform linux/386,linux/amd64,linux/arm/v7,linux/arm64/v8 \
|
--platform linux/386,linux/amd64,linux/arm/v7,linux/arm64/v8 \
|
||||||
--output "type=registry" \
|
--output "type=registry" \
|
||||||
--build-arg MAKE_FLAGS=-j1 \
|
--build-arg MAKE_FLAGS=-j1 \
|
||||||
|
|
|
||||||
54
Dockerfile
54
Dockerfile
|
|
@ -1,41 +1,25 @@
|
||||||
#
|
FROM ubuntu:eoan
|
||||||
# First stage - builder
|
|
||||||
#
|
|
||||||
FROM debian:10-slim AS builder
|
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
ENV LC_ALL=C.UTF-8
|
ENV LC_ALL C.UTF-8
|
||||||
|
|
||||||
# This allows you to use a local Debian mirror
|
# This allows you to use a local Ubuntu mirror
|
||||||
ARG APT_URL=http://archive.debian.org/debian
|
ARG APT_URL=
|
||||||
ARG MAKE_FLAGS=-j2
|
ENV APT_URL ${APT_URL:-http://archive.ubuntu.com/ubuntu/}
|
||||||
|
RUN sed -i "s%http://archive.ubuntu.com/ubuntu/%${APT_URL}%" /etc/apt/sources.list
|
||||||
|
|
||||||
RUN sed -i "s%http://deb.debian.org/debian%${APT_URL}%" /etc/apt/sources.list
|
|
||||||
RUN apt-get update && apt-get -y upgrade \
|
# Update packages and install dependencies
|
||||||
&& apt-get install -y protobuf-compiler libh2o-dev libcurl4-openssl-dev \
|
RUN apt-get update && apt-get -y upgrade && apt-get -y clean
|
||||||
libssl-dev libprotobuf-dev libh2o-evloop-dev libwslay-dev \
|
RUN apt-get install -y protobuf-compiler libh2o-dev libcurl4-openssl-dev \
|
||||||
libeigen3-dev libzstd-dev libfmt-dev libncurses-dev libfmt-dev \
|
libssl-dev libprotobuf-dev libh2o-evloop-dev libwslay-dev libeigen3-dev libzstd-dev \
|
||||||
make gcc g++ git build-essential curl autoconf automake help2man
|
make gcc g++ git build-essential curl autoconf automake libfmt-dev libncurses5-dev \
|
||||||
|
&& apt-get -y clean
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
ADD . /galmon-src/
|
ARG MAKE_FLAGS=-j2
|
||||||
RUN cd /galmon-src/ \
|
ADD . /galmon/
|
||||||
&& make $MAKE_FLAGS \
|
WORKDIR /galmon/
|
||||||
&& prefix=/galmon make install
|
RUN make $MAKE_FLAGS
|
||||||
|
ENV PATH=/galmon:${PATH}
|
||||||
|
|
||||||
#
|
|
||||||
# Second stage - contains just the binaries
|
|
||||||
#
|
|
||||||
FROM debian:10-slim
|
|
||||||
|
|
||||||
COPY --from=builder /etc/apt/sources.list /etc/apt/sources.list
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get -y upgrade \
|
|
||||||
&& apt-get install -y libcurl4 libssl1.1 libprotobuf17 libh2o-evloop0.13 \
|
|
||||||
libncurses6 \
|
|
||||||
&& apt-get -y clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
COPY --from=builder /galmon/ /galmon/
|
|
||||||
ENV PATH=/galmon/bin:${PATH}
|
|
||||||
ENV LC_ALL=C.UTF-8
|
|
||||||
WORKDIR /galmon/bin
|
|
||||||
|
|
|
||||||
18
Dockerfile-pi
Normal file
18
Dockerfile-pi
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#FROM ubuntu:disco
|
||||||
|
FROM arm32v7/debian:unstable
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND noninteractive
|
||||||
|
ENV LC_ALL C.UTF-8
|
||||||
|
|
||||||
|
# Update packages and install dependencies
|
||||||
|
RUN apt-get update && apt-get -y upgrade && apt-get -y clean
|
||||||
|
RUN apt-get install -y protobuf-compiler libh2o-dev libcurl4-openssl-dev \
|
||||||
|
libssl-dev libprotobuf-dev libh2o-evloop-dev libwslay-dev libeigen3-dev libzstd-dev \
|
||||||
|
make clang-9 git build-essential curl autoconf automake libfmt-dev libncurses5-dev \
|
||||||
|
&& apt-get -y clean
|
||||||
|
|
||||||
|
# Build
|
||||||
|
ADD . /galmon/
|
||||||
|
WORKDIR /galmon/
|
||||||
|
RUN make
|
||||||
|
ENV PATH=/galmon:${PATH}
|
||||||
99
Makefile
99
Makefile
|
|
@ -1,7 +1,7 @@
|
||||||
CFLAGS = -O3 -Wall -ggdb
|
CFLAGS = -O3 -Wall -ggdb
|
||||||
|
|
||||||
CXXFLAGS:= -std=gnu++17 -Wall -O3 -ggdb -MMD -MP -fno-omit-frame-pointer -Iext/CLI11 \
|
CXXFLAGS:= -std=gnu++17 -Wall -O3 -ggdb -MMD -MP -fno-omit-frame-pointer -Iext/CLI11 \
|
||||||
-Iext/powerblog/ext/simplesocket -Iext/powerblog/ext/ \
|
-Iext/fmt-6.1.2/include/ -Iext/powerblog/ext/simplesocket -Iext/powerblog/ext/ \
|
||||||
-I/usr/local/opt/openssl/include/ \
|
-I/usr/local/opt/openssl/include/ \
|
||||||
-Iext/sgp4/libsgp4/ \
|
-Iext/sgp4/libsgp4/ \
|
||||||
-I/usr/local/include
|
-I/usr/local/include
|
||||||
|
|
@ -21,10 +21,11 @@ else ifneq (,$(wildcard ubxsec.o))
|
||||||
EXTRADEP = ubxsec.o
|
EXTRADEP = ubxsec.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
CHEAT_ARG := $(shell ./update-git-hash-if-necessary)
|
CHEAT_ARG := $(shell ./update-git-hash-if-necessary)
|
||||||
|
|
||||||
PROGRAMS = navparse ubxtool navnexus navcat navrecv navdump testrunner navdisplay tlecatch reporter sp3feed \
|
PROGRAMS = navparse ubxtool navnexus navcat navrecv navdump testrunner navdisplay tlecatch reporter sp3feed \
|
||||||
galmonmon rinreport rinjoin rtcmtool gndate septool navmerge
|
galmonmon rinreport rinjoin rtcmtool gndate
|
||||||
|
|
||||||
all: navmon.pb.cc $(PROGRAMS)
|
all: navmon.pb.cc $(PROGRAMS)
|
||||||
|
|
||||||
|
|
@ -39,12 +40,12 @@ navmon.pb.cc: navmon.proto
|
||||||
protoc --cpp_out=./ navmon.proto
|
protoc --cpp_out=./ navmon.proto
|
||||||
|
|
||||||
|
|
||||||
|
H2OPP=ext/powerblog/h2o-pp.o
|
||||||
SIMPLESOCKETS=ext/powerblog/ext/simplesocket/swrappers.o ext/powerblog/ext/simplesocket/sclasses.o ext/powerblog/ext/simplesocket/comboaddress.o
|
SIMPLESOCKETS=ext/powerblog/ext/simplesocket/swrappers.o ext/powerblog/ext/simplesocket/sclasses.o ext/powerblog/ext/simplesocket/comboaddress.o
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *~ *.o *.d ext/*/*.o ext/*/*.d $(PROGRAMS) navmon.pb.h navmon.pb.cc $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) $(SIMPLESOCKETS)
|
rm -f *~ *.o *.d ext/*/*.o ext/*/*.d $(PROGRAMS) navmon.pb.h navmon.pb.cc $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) $(H2OPP) $(SIMPLESOCKETS)
|
||||||
rm -f ext/sgp4/libsgp4/*.d ext/powerblog/ext/simplesocket/*.d
|
rm -f ext/fmt-6.1.2/src/format.[do] ext/sgp4/libsgp4/*.d ext/powerblog/ext/simplesocket/*.d
|
||||||
|
|
||||||
help2man:
|
help2man:
|
||||||
$(INSTALL) -m 755 -d $(DESTDIR)$(prefix)/share/man/man1
|
$(INSTALL) -m 755 -d $(DESTDIR)$(prefix)/share/man/man1
|
||||||
|
|
@ -62,76 +63,76 @@ install: $(PROGRAMS) help2man
|
||||||
mkdir -p $(DESTDIR)$(prefix)$(htdocs)/galmon
|
mkdir -p $(DESTDIR)$(prefix)$(htdocs)/galmon
|
||||||
cp -a html $(DESTDIR)$(prefix)$(htdocs)/galmon/
|
cp -a html $(DESTDIR)$(prefix)$(htdocs)/galmon/
|
||||||
|
|
||||||
decrypt: decrypt.o bits.o
|
download-debian-package:
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -lfmt
|
apt-key adv --fetch-keys https://ota.bike/public-package-signing-keys/86E7F51C04FBAAB0.asc
|
||||||
|
echo "deb https://ota.bike/debian/ buster main" > /etc/apt/sources.list.d/galmon.list
|
||||||
|
apt-get update && apt-get install -y galmon
|
||||||
|
|
||||||
navparse: navparse.o $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o trkmeas.o influxpush.o ${EXTRADEP} githash.o sbas.o rtcm.o galileo.o
|
download-raspbian-package:
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -L/usr/local/opt/openssl/lib/ -lz -lcurl -lprotobuf -lfmt
|
apt-key adv --fetch-keys https://ota.bike/public-package-signing-keys/86E7F51C04FBAAB0.asc
|
||||||
|
echo "deb https://ota.bike/raspbian/ buster main" > /etc/apt/sources.list.d/galmon.list
|
||||||
|
apt-get update && apt-get install -y galmon
|
||||||
|
|
||||||
reporter: reporter.o $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o githash.o influxpush.o
|
decrypt: decrypt.o bits.o ext/fmt-6.1.2/src/format.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -lprotobuf -lcurl -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@
|
||||||
|
|
||||||
sp3feed: sp3feed.o $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o influxpush.o githash.o sp3.o
|
navparse: navparse.o ext/fmt-6.1.2/src/format.o $(H2OPP) $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o trkmeas.o influxpush.o ${EXTRADEP} githash.o sbas.o rtcm.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -lprotobuf -lcurl -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -L/usr/local/opt/openssl/lib/ -lh2o-evloop -lssl -lcrypto -lz -lcurl -lprotobuf $(WSLAY)
|
||||||
|
|
||||||
|
reporter: reporter.o ext/fmt-6.1.2/src/format.o $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o githash.o influxpush.o
|
||||||
|
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -lprotobuf -lcurl
|
||||||
|
|
||||||
|
sp3feed: sp3feed.o ext/fmt-6.1.2/src/format.o $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o influxpush.o githash.o sp3.o
|
||||||
|
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -lprotobuf -lcurl
|
||||||
|
|
||||||
|
|
||||||
tracker: tracker.o $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o githash.o
|
tracker: tracker.o ext/fmt-6.1.2/src/format.o $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o githash.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -lprotobuf -lcurl -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -lprotobuf -lcurl
|
||||||
|
|
||||||
|
|
||||||
galmonmon: galmonmon.o $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o githash.o
|
galmonmon: galmonmon.o ext/fmt-6.1.2/src/format.o $(SIMPLESOCKETS) minicurl.o ubx.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o navmon.o coverage.o osen.o githash.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -lprotobuf -lcurl -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -pthread -L/usr/local/lib -lprotobuf -lcurl
|
||||||
|
|
||||||
|
|
||||||
# rs.o fixhunter.o
|
navdump: navdump.o ext/fmt-6.1.2/src/format.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o navmon.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o sp3.o osen.o trkmeas.o githash.o rinex.o sbas.o rtcm.o ${EXTRADEP}
|
||||||
navdump: navdump.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o navmon.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) tle.o sp3.o osen.o trkmeas.o githash.o rinex.o sbas.o rtcm.o galileo.o ${EXTRADEP}
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf -lz
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf -lz -lfmt
|
|
||||||
# -lfec
|
|
||||||
|
|
||||||
navdisplay: navdisplay.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o ephemeris.o navmon.o osen.o githash.o
|
navdisplay: navdisplay.o ext/fmt-6.1.2/src/format.o bits.o navmon.pb.o gps.o ephemeris.o beidou.o glonass.o ephemeris.o navmon.o osen.o githash.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf -lncurses -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf -lncurses
|
||||||
|
|
||||||
|
|
||||||
navnexus: navnexus.o $(SIMPLESOCKETS) bits.o navmon.pb.o storage.o githash.o
|
navnexus: navnexus.o ext/fmt-6.1.2/src/format.o $(SIMPLESOCKETS) ubx.o bits.o navmon.pb.o storage.o githash.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf
|
||||||
|
|
||||||
navcat: navcat.o $(SIMPLESOCKETS) ubx.o bits.o navmon.pb.o storage.o navmon.o githash.o
|
navcat: navcat.o ext/fmt-6.1.2/src/format.o $(SIMPLESOCKETS) ubx.o bits.o navmon.pb.o storage.o navmon.o githash.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf
|
||||||
|
|
||||||
|
|
||||||
navrecv: navrecv.o $(SIMPLESOCKETS) navmon.pb.o storage.o githash.o zstdwrap.o navmon.o
|
navrecv: navrecv.o ext/fmt-6.1.2/src/format.o $(SIMPLESOCKETS) navmon.pb.o storage.o githash.o zstdwrap.o navmon.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf -lzstd -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf -lzstd
|
||||||
|
|
||||||
navmerge: navmerge.o $(SIMPLESOCKETS) navmon.pb.o storage.o githash.o zstdwrap.o navmon.o nmmsender.o
|
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf -lzstd -lfmt
|
|
||||||
|
|
||||||
|
|
||||||
tlecatch: tlecatch.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) githash.o
|
tlecatch: tlecatch.o $(patsubst %.cc,%.o,$(wildcard ext/sgp4/libsgp4/*.cc)) githash.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -pthread -lprotobuf
|
||||||
|
|
||||||
rinreport: rinreport.o rinex.o githash.o navmon.o ephemeris.o osen.o
|
rinreport: rinreport.o rinex.o githash.o navmon.o ext/fmt-6.1.2/src/format.o ephemeris.o osen.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -lz -pthread -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -lz -pthread
|
||||||
|
|
||||||
rinjoin: rinjoin.o rinex.o githash.o navmon.o ephemeris.o osen.o
|
rinjoin: rinjoin.o rinex.o githash.o navmon.o ext/fmt-6.1.2/src/format.o ephemeris.o osen.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -lz -pthread -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -lz -pthread
|
||||||
|
|
||||||
|
|
||||||
rtcmtool: rtcmtool.o navmon.pb.o githash.o bits.o nmmsender.o $(SIMPLESOCKETS) navmon.o rtcm.o zstdwrap.o
|
rtcmtool: rtcmtool.o navmon.pb.o githash.o ext/fmt-6.1.2/src/format.o bits.o nmmsender.o $(SIMPLESOCKETS) navmon.o rtcm.o zstdwrap.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -lz -pthread -lprotobuf -lzstd -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -lz -pthread -lprotobuf -lzstd
|
||||||
|
|
||||||
|
|
||||||
ubxtool: navmon.pb.o ubxtool.o ubx.o bits.o galileo.o gps.o beidou.o navmon.o ephemeris.o $(SIMPLESOCKETS) osen.o githash.o nmmsender.o zstdwrap.o
|
ubxtool: navmon.pb.o ubxtool.o ubx.o bits.o ext/fmt-6.1.2/src/format.o galileo.o gps.o beidou.o navmon.o ephemeris.o $(SIMPLESOCKETS) osen.o githash.o nmmsender.o zstdwrap.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -lprotobuf -pthread -lzstd -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -lprotobuf -pthread -lzstd
|
||||||
|
|
||||||
septool: navmon.pb.o septool.o bits.o galileo.o gps.o beidou.o navmon.o ephemeris.o $(SIMPLESOCKETS) osen.o githash.o nmmsender.o zstdwrap.o
|
testrunner: navmon.pb.o testrunner.o ubx.o bits.o ext/fmt-6.1.2/src/format.o galileo.o gps.o beidou.o ephemeris.o sp3.o osen.o navmon.o rinex.o githash.o
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -lprotobuf -pthread -lzstd -lfmt
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -lprotobuf -lz
|
||||||
|
|
||||||
|
gndate: gndate.o githash.o ext/fmt-6.1.2/src/format.o navmon.o
|
||||||
testrunner: navmon.pb.o testrunner.o ubx.o bits.o galileo.o gps.o beidou.o ephemeris.o sp3.o osen.o navmon.o rinex.o githash.o
|
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -lprotobuf -lz -pthread -lfmt
|
|
||||||
|
|
||||||
gndate: gndate.o githash.o navmon.o
|
|
||||||
$(CXX) -std=gnu++17 $^ -o $@ -L/usr/local/lib -lfmt
|
|
||||||
|
|
||||||
check: testrunner
|
check: testrunner
|
||||||
./testrunner
|
./testrunner
|
||||||
|
|
|
||||||
137
README.md
137
README.md
|
|
@ -4,17 +4,14 @@ galileo/GPS/GLONASS/BeiDou open source monitoring. GPL3 licensed.
|
||||||
|
|
||||||
Live website: https://galmon.eu/
|
Live website: https://galmon.eu/
|
||||||
|
|
||||||
Multi-vendor, with support for U-blox 8 and 9 chipsets and many Septentrio
|
Theoretically multi-vendor, although currently only the U-blox 8 and 9
|
||||||
devices. Navilock NL-8012U receiver works really well, as does the U-blox
|
chipsets are supported. Navilock NL-8012U receiver works really well, as
|
||||||
evaluation kit for the 8MT. In addition, many stations have reported
|
does the U-blox evaluation kit for the 8MT. In addition, many stations have
|
||||||
success with this very cheap [AliExpress sourced
|
reported success with this very cheap [AliExpress sourced
|
||||||
device](https://www.aliexpress.com/item/32816656706.html).
|
device](https://www.aliexpress.com/item/32816656706.html). The best and
|
||||||
|
most high-end receiver, which does all bands, all the time, is the Ublox
|
||||||
For ublox, there is good support for the F9P, several of us use the
|
F9P, several of us use the
|
||||||
[ArdusimpleRTK2B](https://www.ardusimple.com/simplertk2b/) board. It adds
|
[ArdusimpleRTK2B](https://www.ardusimple.com/simplertk2b/) board.
|
||||||
the Galileo E5b band.
|
|
||||||
|
|
||||||
Septentrio devices support even more bands.
|
|
||||||
|
|
||||||
An annotated presentation about our project aimed at GNSS professionals can
|
An annotated presentation about our project aimed at GNSS professionals can
|
||||||
be found [here](https://berthub.eu/galileo/The%20galmon.eu%20project.pdf).
|
be found [here](https://berthub.eu/galileo/The%20galmon.eu%20project.pdf).
|
||||||
|
|
@ -27,15 +24,14 @@ be found [here](https://berthub.eu/galileo/The%20galmon.eu%20project.pdf).
|
||||||
To deliver data to the project, please read
|
To deliver data to the project, please read
|
||||||
[The Galmon GNSS Monitoring Project](https://berthub.eu/articles/posts/galmon-project/)
|
[The Galmon GNSS Monitoring Project](https://berthub.eu/articles/posts/galmon-project/)
|
||||||
and consult the rules outlined in [the operator
|
and consult the rules outlined in [the operator
|
||||||
guidelines](https://github.com/berthubert/galmon/blob/master/Operator.md).
|
guidelines](https://github.com/ahupowerdns/galmon/blob/master/Operator.md).
|
||||||
|
|
||||||
Highlights
|
Highlights
|
||||||
----------
|
----------
|
||||||
|
|
||||||
* Support for Septentrio and U-blox.
|
|
||||||
* Processes raw frames/strings/words from GPS, GLONASS, BeiDou and Galileo
|
* Processes raw frames/strings/words from GPS, GLONASS, BeiDou and Galileo
|
||||||
* All-band support (E1, E5a, E5b, B1I, B2I, Glonass L1, Glonass L2, GPS L1C/A)
|
* All-band support (E1, E5b, B1I, B2I, Glonass L1, Glonass L2, GPS L1C/A)
|
||||||
so far.
|
so far, GPS L2C and Galileo E5a pending).
|
||||||
* Calculate ephemeris positions
|
* Calculate ephemeris positions
|
||||||
* Comparison of ephemerides to independent SP3 data to determine SISE
|
* Comparison of ephemerides to independent SP3 data to determine SISE
|
||||||
* Globally, locally, worst user location
|
* Globally, locally, worst user location
|
||||||
|
|
@ -53,7 +49,7 @@ Highlights
|
||||||
Data is made available as JSON, as a user-friendly website and as a
|
Data is made available as JSON, as a user-friendly website and as a
|
||||||
time-series database. This time-series database is easily mated to the
|
time-series database. This time-series database is easily mated to the
|
||||||
industry standard Matplotlib/Pandas/Jupyter combination (details
|
industry standard Matplotlib/Pandas/Jupyter combination (details
|
||||||
[here](https://github.com/berthubert/galmon/blob/master/influxdb.md).
|
[here](https://github.com/ahupowerdns/galmon/blob/master/influxdb.md).
|
||||||
|
|
||||||
There is also tooling to extract raw frames/strings/words from specific
|
There is also tooling to extract raw frames/strings/words from specific
|
||||||
timeframes.
|
timeframes.
|
||||||
|
|
@ -72,8 +68,8 @@ Goals:
|
||||||
|
|
||||||
Works on Linux (including Raspbian Buster on Pi Zero W), OSX and OpenBSD.
|
Works on Linux (including Raspbian Buster on Pi Zero W), OSX and OpenBSD.
|
||||||
|
|
||||||
Build locally (Linux, Debian, Ubuntu)
|
Build locally
|
||||||
-------------------------------------
|
-------------
|
||||||
|
|
||||||
To get started, make sure you have a C++17 compiler (like g++ 8 or higher),
|
To get started, make sure you have a C++17 compiler (like g++ 8 or higher),
|
||||||
git, protobuf-compiler. Then run 'make ubxtool navdump' to build the
|
git, protobuf-compiler. Then run 'make ubxtool navdump' to build the
|
||||||
|
|
@ -82,48 +78,39 @@ receiver-only tools.
|
||||||
To build everything, including the webserver, try:
|
To build everything, including the webserver, try:
|
||||||
|
|
||||||
```
|
```
|
||||||
apt-get install protobuf-compiler libcurl4-openssl-dev libssl-dev libprotobuf-dev \
|
apt-get install protobuf-compiler libh2o-dev libcurl4-openssl-dev libssl-dev libprotobuf-dev \
|
||||||
libncurses5-dev libeigen3-dev libzstd-dev g++ libfmt-dev
|
libh2o-evloop-dev libwslay-dev libncurses5-dev libeigen3-dev libzstd-dev
|
||||||
git clone https://github.com/berthubert/galmon.git --recursive
|
git clone https://github.com/ahupowerdns/galmon.git --recursive
|
||||||
cd galmon
|
cd galmon
|
||||||
make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
Building on OSX
|
If this doesn't succeed with an error about h2o, make sure you have this
|
||||||
---------------
|
library installed. If you get an error about 'wslay', do the following, and run make again:
|
||||||
With thanks to a contributor from Prague. First make sure you've installed
|
|
||||||
brew, which you can get [here](https://brew.sh/). Then do:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
brew install protobuf lzlib zstd eigen
|
echo WSLAY=-lwslay > Makefile.local
|
||||||
```
|
|
||||||
|
|
||||||
And then:
|
|
||||||
```
|
|
||||||
git clone https://github.com/berthubert/galmon.git --recursive
|
|
||||||
cd galmon
|
|
||||||
make
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Running in Docker
|
Running in Docker
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
We publish official Docker images for galmon on
|
We publish official Docker images for galmon on
|
||||||
[docker hub](https://hub.docker.com/r/berthubert/galmon) for multiple architectures.
|
[docker hub](https://hub.docker.com/r/faucet/faucet) for multiple architectures.
|
||||||
|
|
||||||
To run a container with a shell in there (this will also expose a port so you
|
To run a container with a shell in there (this will also expose a port so you
|
||||||
can view the UI too and assumes a ublox GPS device too -
|
can view the UI too and assumes a ublox GPS device too -
|
||||||
you may need to tweak as necessary):
|
you may need to tweak as necessary):
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run -it --rm --device=/dev/ttyACM0 -p 10000:10000 berthubert/galmon
|
docker run -it --rm --device=/dev/ttyACM0 -p 10000:10000 galmon/galmon
|
||||||
```
|
```
|
||||||
|
|
||||||
Running a daemonized docker container reporting data to a remote server
|
Running a daemonized docker container reporting data to a remote server
|
||||||
might look like:
|
might look like:
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run -d --restart=always --device=/dev/ttyACM0 --name=galmon berthubert/galmon ubxtool --wait --port /dev/ttyACM0 --gps --galileo --glonass --destination [server] --station [station-id] --owner [owner]
|
docker run -d --restart=always --device=/dev/ttyACM0 --name=galmon galmon/galmon /galmon/ubxtool --wait --port /dev/ttyACM0 --gps --galileo --glonass --destination [server] --station [station-id] --owner [owner]
|
||||||
```
|
```
|
||||||
|
|
||||||
To make your docker container update automatically you could use a tool such as
|
To make your docker container update automatically you could use a tool such as
|
||||||
|
|
@ -131,15 +118,10 @@ To make your docker container update automatically you could use a tool such as
|
||||||
|
|
||||||
Running
|
Running
|
||||||
-------
|
-------
|
||||||
On u-blox:
|
|
||||||
Once compiled, run for example `./ubxtool --wait --port /dev/ttyACM0
|
Once compiled, run for example `./ubxtool --wait --port /dev/ttyACM0
|
||||||
--station 1 --stdout --galileo | ./navparse --bind [::1]:10000`
|
--station 1 --stdout --galileo | ./navparse --bind [::1]:10000`
|
||||||
|
|
||||||
For Septentrio, try: `nc 192.168.1.1 29000 | ./septool --station x --stdout |
|
|
||||||
./navparse --bind [::1]:10000`, assuming your Septentrio can be reached on
|
|
||||||
192.168.1.1.1 and you have defined an SBF stream on port 29000. For more
|
|
||||||
details, please see below.
|
|
||||||
|
|
||||||
Next up, browse to http://[::1]:10000 (or try http://localhost:10000/ and
|
Next up, browse to http://[::1]:10000 (or try http://localhost:10000/ and
|
||||||
you should be in business. ubxtool changes (non-permanently) the
|
you should be in business. ubxtool changes (non-permanently) the
|
||||||
configuration of your u-blox receiver so it emits the required frames for
|
configuration of your u-blox receiver so it emits the required frames for
|
||||||
|
|
@ -174,13 +156,9 @@ to stdout, add `--stdout`.
|
||||||
|
|
||||||
Tooling:
|
Tooling:
|
||||||
|
|
||||||
* ubxtool: can configure a u-blox 8/9/10 chipset, parses its output & will
|
* ubxtool: can configure a u-blox 8 chipset, parses its output & will
|
||||||
convert it into a protbuf stream of GNSS NAV frames + metadata
|
convert it into a protbuf stream of GNSS NAV frames + metadata
|
||||||
Adds 64-bit timestamps plus origin information to each message
|
Adds 64-bit timestamps plus origin information to each message
|
||||||
* septool: ingests the Septentrio binary format (SBF) and converts it to our
|
|
||||||
protobuf format. Supports same protocol as ubxtool.
|
|
||||||
* rtcmtool: ingest ntripclient output, decodes RTCM messages and converts
|
|
||||||
them to our protobuf format
|
|
||||||
* xtool: if you have another chipset, build something that extracts NAV
|
* xtool: if you have another chipset, build something that extracts NAV
|
||||||
frames & metadata. Not done yet.
|
frames & metadata. Not done yet.
|
||||||
* navrecv: receives GNSS NAV frames and stores them on disk, split out per
|
* navrecv: receives GNSS NAV frames and stores them on disk, split out per
|
||||||
|
|
@ -193,11 +171,6 @@ Tooling:
|
||||||
computations on ephemerides.
|
computations on ephemerides.
|
||||||
* grafana dashboard: makes pretty graphs
|
* grafana dashboard: makes pretty graphs
|
||||||
|
|
||||||
Per device notes
|
|
||||||
----------------
|
|
||||||
The "SparkFun GNSS L1/L5 Breakout - NEO-F10N, SMA" needs '-u1 -b 38400
|
|
||||||
--wait'.
|
|
||||||
|
|
||||||
Linux Systemd
|
Linux Systemd
|
||||||
-------------
|
-------------
|
||||||
First make sure 'ubxtool' has been compiled (run: make ubxtool). Then, as
|
First make sure 'ubxtool' has been compiled (run: make ubxtool). Then, as
|
||||||
|
|
@ -256,47 +229,6 @@ This also works for `navparse` for the pretty website and influx storage, `nc 12
|
||||||
if you have an influxdb running on localhost with a galileo database in there.
|
if you have an influxdb running on localhost with a galileo database in there.
|
||||||
The default URL is http://127.0.0.1:29599/
|
The default URL is http://127.0.0.1:29599/
|
||||||
|
|
||||||
Septentrio specifics
|
|
||||||
--------------------
|
|
||||||
Unlike `ubxtool`, our `septool` does not (re)configure your Septentrio
|
|
||||||
device. Instead, the tool expects Septentrio Binary Format (SBF) on input,
|
|
||||||
and that this stream includes at least the following messages:
|
|
||||||
|
|
||||||
* MeasEpoch
|
|
||||||
* PVTCartesian
|
|
||||||
|
|
||||||
We currently parse and understand:
|
|
||||||
* GALRawFNAV
|
|
||||||
* GALRawINAV
|
|
||||||
|
|
||||||
Support will be added soon for:
|
|
||||||
* GPSRawCA
|
|
||||||
* GPSRawL2C
|
|
||||||
* GPSRawL5
|
|
||||||
* GLORawCA
|
|
||||||
* BDSRaw
|
|
||||||
* BDSRawB1C
|
|
||||||
* BDSRawB2a
|
|
||||||
|
|
||||||
A typical invocation of `septool` looks like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
nc 192.168.1.1 29000 | ./septool --station x --destination galmon-eu-server.example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
Or to test, try:
|
|
||||||
|
|
||||||
```
|
|
||||||
nc 192.168.1.1 29000 | ./septool --station x --stdout | ./navdump
|
|
||||||
```
|
|
||||||
|
|
||||||
This is assuming that you can reach your Septentrio on 192.168.1.1 and that
|
|
||||||
you have defined a TCP server stream on port 29000.
|
|
||||||
|
|
||||||
Septool will also accept input from a serial port or basically anything that
|
|
||||||
can provide SBF. Please let us know if our tooling can make your life
|
|
||||||
easier.
|
|
||||||
|
|
||||||
Internals
|
Internals
|
||||||
---------
|
---------
|
||||||
The transport format consists of repeats of:
|
The transport format consists of repeats of:
|
||||||
|
|
@ -321,10 +253,9 @@ Documents
|
||||||
* [GLONASS CDMA](http://russianspacesystems.ru/wp-content/uploads/2016/08/ICD-GLONASS-CDMA-General.-Edition-1.0-2016.pdf)
|
* [GLONASS CDMA](http://russianspacesystems.ru/wp-content/uploads/2016/08/ICD-GLONASS-CDMA-General.-Edition-1.0-2016.pdf)
|
||||||
not actually relevant for the CDMA aspects, but has appendices on more
|
not actually relevant for the CDMA aspects, but has appendices on more
|
||||||
precise orbit determinations.
|
precise orbit determinations.
|
||||||
* [GPS](https://www.navcen.uscg.gov/sites/default/files/pdf/gps/IS-GPS-200N.pdf)
|
* [GPS](https://www.gps.gov/technical/icwg/IS-GPS-200K.pdf)
|
||||||
* [U-blox 8 interface specification](https://www.u-blox.com/sites/default/files/products/documents/u-blox8-M8_ReceiverDescrProtSpec_%28UBX-13003221%29_Public.pdf)
|
* [U-blox 8 interface specification](https://www.u-blox.com/sites/default/files/products/documents/u-blox8-M8_ReceiverDescrProtSpec_%28UBX-13003221%29_Public.pdf)
|
||||||
* [U-blox 9 interface specification](https://www.u-blox.com/sites/default/files/u-blox_ZED-F9P_InterfaceDescription_%28UBX-18010854%29.pdf)
|
* [U-blox 9 interface specification](https://www.u-blox.com/sites/default/files/u-blox_ZED-F9P_InterfaceDescription_%28UBX-18010854%29.pdf)
|
||||||
* [U-blox 10 interface specification](https://content.u-blox.com/sites/default/files/documents/u-blox-F10-SPG-6.00_InterfaceDescription_UBX-23002975.pdf)
|
|
||||||
* [U-blox 9 integration manual](https://www.u-blox.com/sites/default/files/ZED-F9P_IntegrationManual_%28UBX-18010802%29.pdf)
|
* [U-blox 9 integration manual](https://www.u-blox.com/sites/default/files/ZED-F9P_IntegrationManual_%28UBX-18010802%29.pdf)
|
||||||
|
|
||||||
Data sources
|
Data sources
|
||||||
|
|
@ -344,26 +275,16 @@ The software can interpret SP3 files, good sources:
|
||||||
to have less of a delay than the ESA ESM series.
|
to have less of a delay than the ESA ESM series.
|
||||||
* GBU = ultra rapid, still a few days delay, but much more recent.
|
* GBU = ultra rapid, still a few days delay, but much more recent.
|
||||||
|
|
||||||
|
Uncompress and concatenate all downloaded files into 'all.sp3' and run
|
||||||
|
'navdump ' on collected protobuf, and it will output 'sp3.csv' with fit data.
|
||||||
|
|
||||||
To get SP3 GBM from GFZ Potsdam for GPS week number 2111:
|
To get SP3 GBM from GFZ Potsdam for GPS week number 2111:
|
||||||
|
|
||||||
```
|
```
|
||||||
WN=2111
|
WN=2111
|
||||||
lftp -c "mget ftp://ftp.gfz-potsdam.de/GNSS/products/mgnss/${WN}/gbm*sp3.Z"
|
lftp -c "mget ftp://ftp.gfz-potsdam.de/GNSS/products/mgnss/${WN}/gbm*sp3.Z"
|
||||||
gunzip gbm*sp3.Z
|
|
||||||
```
|
```
|
||||||
|
|
||||||
To feed data, use:
|
|
||||||
|
|
||||||
```
|
|
||||||
./sp3feed --sp3src=gbm --influxdb=galileo gbm*sp3
|
|
||||||
```
|
|
||||||
|
|
||||||
This will populate the sp3 tables in the database. A subsequent run of
|
|
||||||
`reporter`, while setting the `--sp3src` parameter, will provide SP3
|
|
||||||
deviation statistics, and fill out the `sp3delta` table in there, which
|
|
||||||
stores deviations from the SP3 provided position, per sp3src.
|
|
||||||
|
|
||||||
Further interesting (ephemeris) data is on http://mgex.igs.org/IGS_MGEX_Products.php
|
|
||||||
|
|
||||||
RTCM
|
RTCM
|
||||||
----
|
----
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
#include "beidou.hh"
|
#include "beidou.hh"
|
||||||
#include "bits.hh"
|
#include "bits.hh"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
|
||||||
#include "navmon.hh"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
@ -31,7 +29,7 @@ static int checkbds(int bits)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> getCondensedBeidouMessage(const std::vector<uint8_t>& payload)
|
std::basic_string<uint8_t> getCondensedBeidouMessage(std::basic_string_view<uint8_t> payload)
|
||||||
{
|
{
|
||||||
|
|
||||||
// payload consists of 32 bit words where we have to ignore the first 2 bits of every word
|
// payload consists of 32 bit words where we have to ignore the first 2 bits of every word
|
||||||
|
|
@ -58,7 +56,7 @@ std::vector<uint8_t> getCondensedBeidouMessage(const std::vector<uint8_t>& paylo
|
||||||
setbitu(buffer, 26+22*(w-1), 22, getbitu(&payload[0], 2 + w*32, 22));
|
setbitu(buffer, 26+22*(w-1), 22, getbitu(&payload[0], 2 + w*32, 22));
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeVec(buffer, 28);
|
return std::basic_string<uint8_t>(buffer, 28);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
23
beidou.hh
23
beidou.hh
|
|
@ -4,10 +4,9 @@
|
||||||
#include "bits.hh"
|
#include "bits.hh"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
|
||||||
#include "ephemeris.hh"
|
#include "ephemeris.hh"
|
||||||
|
|
||||||
std::vector<uint8_t> getCondensedBeidouMessage(const std::vector<uint8_t>& payload);
|
std::basic_string<uint8_t> getCondensedBeidouMessage(std::basic_string_view<uint8_t> payload);
|
||||||
int beidouBitconv(int their);
|
int beidouBitconv(int their);
|
||||||
|
|
||||||
/* Geostationary, so D2, so not to be parsed by this parser:
|
/* Geostationary, so D2, so not to be parsed by this parser:
|
||||||
|
|
@ -22,7 +21,7 @@ struct BeidouMessage : GPSLikeEphemeris
|
||||||
{
|
{
|
||||||
uint8_t strtype;
|
uint8_t strtype;
|
||||||
|
|
||||||
std::vector<uint8_t> g_cond;
|
std::basic_string_view<uint8_t> g_cond;
|
||||||
int bbitu(int bit, int len)
|
int bbitu(int bit, int len)
|
||||||
{
|
{
|
||||||
return getbitu(&g_cond[0], beidouBitconv(bit), len);
|
return getbitu(&g_cond[0], beidouBitconv(bit), len);
|
||||||
|
|
@ -35,7 +34,7 @@ struct BeidouMessage : GPSLikeEphemeris
|
||||||
|
|
||||||
int fraid{-1}, sow{-1}; // part of every message (thanks!)
|
int fraid{-1}, sow{-1}; // part of every message (thanks!)
|
||||||
|
|
||||||
int parse(const std::vector<uint8_t>& cond, uint8_t* pageno)
|
int parse(std::basic_string_view<uint8_t> cond, uint8_t* pageno)
|
||||||
{
|
{
|
||||||
g_cond = cond;
|
g_cond = cond;
|
||||||
if(pageno)
|
if(pageno)
|
||||||
|
|
@ -90,7 +89,7 @@ struct BeidouMessage : GPSLikeEphemeris
|
||||||
return {factor * cur, factor * trend};
|
return {factor * cur, factor * trend};
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse1(const std::vector<uint8_t>& cond)
|
void parse1(std::basic_string_view<uint8_t> cond)
|
||||||
{
|
{
|
||||||
sath1 = bbitu(43,1);
|
sath1 = bbitu(43,1);
|
||||||
aodc = bbitu(31+13, 5);
|
aodc = bbitu(31+13, 5);
|
||||||
|
|
@ -125,7 +124,7 @@ struct BeidouMessage : GPSLikeEphemeris
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse2(const std::vector<uint8_t>& cond)
|
void parse2(std::basic_string_view<uint8_t> cond)
|
||||||
{
|
{
|
||||||
deltan = bbits(43, 16);
|
deltan = bbits(43, 16);
|
||||||
cuc = bbits(67, 18);
|
cuc = bbits(67, 18);
|
||||||
|
|
@ -152,7 +151,7 @@ struct BeidouMessage : GPSLikeEphemeris
|
||||||
double getOmega0() const { return ldexp(Omega0 * M_PI, -31); } // radians
|
double getOmega0() const { return ldexp(Omega0 * M_PI, -31); } // radians
|
||||||
double getIdot() const { return ldexp(idot * M_PI, -43); } // radians/s
|
double getIdot() const { return ldexp(idot * M_PI, -43); } // radians/s
|
||||||
double getOmega() const { return ldexp(omega * M_PI, -31); } // radians
|
double getOmega() const { return ldexp(omega * M_PI, -31); } // radians
|
||||||
void parse3(const std::vector<uint8_t>& cond)
|
void parse3(std::basic_string_view<uint8_t> cond)
|
||||||
{
|
{
|
||||||
t0eLSB = bbitu(43, 15);
|
t0eLSB = bbitu(43, 15);
|
||||||
i0 = bbits(66, 32);
|
i0 = bbits(66, 32);
|
||||||
|
|
@ -208,7 +207,7 @@ struct BeidouMessage : GPSLikeEphemeris
|
||||||
} alma;
|
} alma;
|
||||||
|
|
||||||
// 4 is all almanac
|
// 4 is all almanac
|
||||||
int parse4(const std::vector<uint8_t>& cond)
|
int parse4(std::basic_string_view<uint8_t> cond)
|
||||||
{
|
{
|
||||||
alma.sqrtA = bbitu(51, 24);
|
alma.sqrtA = bbitu(51, 24);
|
||||||
alma.a1 = bbits(91, 11);
|
alma.a1 = bbits(91, 11);
|
||||||
|
|
@ -229,8 +228,7 @@ struct BeidouMessage : GPSLikeEphemeris
|
||||||
|
|
||||||
// 2^-30 2^-50
|
// 2^-30 2^-50
|
||||||
int a0gps, a1gps, a0gal, a1gal, a0glo, a1glo, a0utc, a1utc;
|
int a0gps, a1gps, a0gal, a1gal, a0glo, a1glo, a0utc, a1utc;
|
||||||
int8_t deltaTLS, deltaTLSF;
|
int8_t deltaTLS;
|
||||||
uint8_t wnLSF, dn;
|
|
||||||
|
|
||||||
// in Beidou the offset is a0utc + SOW * a1utc
|
// in Beidou the offset is a0utc + SOW * a1utc
|
||||||
std::pair<double, double> getUTCOffset(int tow) const
|
std::pair<double, double> getUTCOffset(int tow) const
|
||||||
|
|
@ -255,7 +253,7 @@ struct BeidouMessage : GPSLikeEphemeris
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int parse5(const std::vector<uint8_t>& cond)
|
int parse5(std::basic_string_view<uint8_t> cond)
|
||||||
{
|
{
|
||||||
alma.pageno = bbitu(44, 7);
|
alma.pageno = bbitu(44, 7);
|
||||||
if(alma.pageno == 9) {
|
if(alma.pageno == 9) {
|
||||||
|
|
@ -270,9 +268,6 @@ struct BeidouMessage : GPSLikeEphemeris
|
||||||
a0utc = bbits(91, 32);
|
a0utc = bbits(91, 32);
|
||||||
a1utc = bbits(131, 24);
|
a1utc = bbits(131, 24);
|
||||||
deltaTLS = bbits(31+12+1+7, 8);
|
deltaTLS = bbits(31+12+1+7, 8);
|
||||||
deltaTLSF = bbits(61+6, 8);
|
|
||||||
wnLSF = bbits(61+6+8, 8);
|
|
||||||
dn = bbits(151+12, 8);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
alma.sqrtA = bbitu(51, 24);
|
alma.sqrtA = bbitu(51, 24);
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ double getCoordinates(double tow, const T& iod, Point* p, bool quiet=true)
|
||||||
|
|
||||||
cerr << "sqrtA = "<< sqrtA << endl;
|
cerr << "sqrtA = "<< sqrtA << endl;
|
||||||
cerr << "deltan = "<< deltan << endl;
|
cerr << "deltan = "<< deltan << endl;
|
||||||
cerr << "t0e = "<< t0e << "( rel "<<(tow - t0e)<<")"<<endl;
|
cerr << "t0e = "<< t0e << endl;
|
||||||
cerr << "m0 = "<< m0 << " ("<<todeg(m0)<<")"<<endl;
|
cerr << "m0 = "<< m0 << " ("<<todeg(m0)<<")"<<endl;
|
||||||
cerr << "e = "<< e << endl;
|
cerr << "e = "<< e << endl;
|
||||||
cerr << "omega = " << omega << " ("<<todeg(omega)<<")"<<endl;
|
cerr << "omega = " << omega << " ("<<todeg(omega)<<")"<<endl;
|
||||||
|
|
@ -122,7 +122,7 @@ double getCoordinates(double tow, const T& iod, Point* p, bool quiet=true)
|
||||||
|
|
||||||
double M = m0 + n * tk;
|
double M = m0 + n * tk;
|
||||||
if(!quiet)
|
if(!quiet)
|
||||||
cerr << " M = m0 + n * tk = "<<m0 << " + " << n << " * " << tk << " = " <<M <<endl;
|
cerr << " M = m0 + n * tk = "<<m0 << " + " << n << " * " << tk <<endl;
|
||||||
double E = M;
|
double E = M;
|
||||||
double newE;
|
double newE;
|
||||||
for(int k =0 ; k < 10; ++k) {
|
for(int k =0 ; k < 10; ++k) {
|
||||||
|
|
|
||||||
2873
ext/doctest.h
2873
ext/doctest.h
File diff suppressed because it is too large
Load diff
27
ext/fmt-6.1.2/LICENSE.rst
Normal file
27
ext/fmt-6.1.2/LICENSE.rst
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
--- Optional exception to the license ---
|
||||||
|
|
||||||
|
As an exception, if, as a result of your compiling your source code, portions
|
||||||
|
of this Software are embedded into a machine-executable object form of such
|
||||||
|
source code, you may redistribute such embedded portions in such object form
|
||||||
|
without including the above copyright and permission notices.
|
||||||
501
ext/fmt-6.1.2/README.rst
Normal file
501
ext/fmt-6.1.2/README.rst
Normal file
|
|
@ -0,0 +1,501 @@
|
||||||
|
{fmt}
|
||||||
|
=====
|
||||||
|
|
||||||
|
.. image:: https://travis-ci.org/fmtlib/fmt.png?branch=master
|
||||||
|
:target: https://travis-ci.org/fmtlib/fmt
|
||||||
|
|
||||||
|
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v
|
||||||
|
:target: https://ci.appveyor.com/project/vitaut/fmt
|
||||||
|
|
||||||
|
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/libfmt.svg
|
||||||
|
:alt: fmt is continuously fuzzed att oss-fuzz
|
||||||
|
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dlibfmt&can=1
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg
|
||||||
|
:alt: Ask questions at StackOverflow with the tag fmt
|
||||||
|
:target: http://stackoverflow.com/questions/tagged/fmt
|
||||||
|
|
||||||
|
**{fmt}** is an open-source formatting library for C++.
|
||||||
|
It can be used as a safe and fast alternative to (s)printf and iostreams.
|
||||||
|
|
||||||
|
`Documentation <https://fmt.dev/latest/>`__
|
||||||
|
|
||||||
|
Q&A: ask questions on `StackOverflow with the tag fmt <http://stackoverflow.com/questions/tagged/fmt>`_.
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
* Replacement-based `format API <https://fmt.dev/dev/api.html>`_ with
|
||||||
|
positional arguments for localization.
|
||||||
|
* `Format string syntax <https://fmt.dev/dev/syntax.html>`_ similar to the one
|
||||||
|
of `str.format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
|
||||||
|
in Python.
|
||||||
|
* Safe `printf implementation
|
||||||
|
<https://fmt.dev/latest/api.html#printf-formatting>`_ including
|
||||||
|
the POSIX extension for positional arguments.
|
||||||
|
* Implementation of `C++20 std::format <https://fmt.dev/Text%20Formatting.html>`__.
|
||||||
|
* Support for user-defined types.
|
||||||
|
* High performance: faster than common standard library implementations of
|
||||||
|
`printf <http://en.cppreference.com/w/cpp/io/c/fprintf>`_ and
|
||||||
|
iostreams. See `Speed tests`_ and `Fast integer to string conversion in C++
|
||||||
|
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||||
|
* Small code size both in terms of source code (the minimum configuration
|
||||||
|
consists of just three header files, ``core.h``, ``format.h`` and
|
||||||
|
``format-inl.h``) and compiled code. See `Compile time and code bloat`_.
|
||||||
|
* Reliability: the library has an extensive set of `unit tests
|
||||||
|
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is continuously fuzzed.
|
||||||
|
* Safety: the library is fully type safe, errors in format strings can be
|
||||||
|
reported at compile time, automatic memory management prevents buffer overflow
|
||||||
|
errors.
|
||||||
|
* Ease of use: small self-contained code base, no external dependencies,
|
||||||
|
permissive MIT `license
|
||||||
|
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_
|
||||||
|
* `Portability <https://fmt.dev/latest/index.html#portability>`_ with
|
||||||
|
consistent output across platforms and support for older compilers.
|
||||||
|
* Clean warning-free codebase even on high warning levels
|
||||||
|
(``-Wall -Wextra -pedantic``).
|
||||||
|
* Support for wide strings.
|
||||||
|
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro.
|
||||||
|
|
||||||
|
See the `documentation <https://fmt.dev/latest/>`_ for more details.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
Print ``Hello, world!`` to ``stdout``:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
fmt::print("Hello, {}!", "world"); // Python-like format string syntax
|
||||||
|
fmt::printf("Hello, %s!", "world"); // printf format string syntax
|
||||||
|
|
||||||
|
Format a string and use positional arguments:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
|
||||||
|
// s == "I'd rather be happy than right."
|
||||||
|
|
||||||
|
Check a format string at compile time:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
// test.cc
|
||||||
|
#include <fmt/format.h>
|
||||||
|
std::string s = format(FMT_STRING("{2}"), 42);
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
$ c++ -Iinclude -std=c++14 test.cc
|
||||||
|
...
|
||||||
|
test.cc:4:17: note: in instantiation of function template specialization 'fmt::v5::format<S, int>' requested here
|
||||||
|
std::string s = format(FMT_STRING("{2}"), 42);
|
||||||
|
^
|
||||||
|
include/fmt/core.h:778:19: note: non-constexpr function 'on_error' cannot be used in a constant expression
|
||||||
|
ErrorHandler::on_error(message);
|
||||||
|
^
|
||||||
|
include/fmt/format.h:2226:16: note: in call to '&checker.context_->on_error(&"argument index out of range"[0])'
|
||||||
|
context_.on_error("argument index out of range");
|
||||||
|
^
|
||||||
|
|
||||||
|
Use {fmt} as a safe portable replacement for ``itoa``
|
||||||
|
(`godbolt <https://godbolt.org/g/NXmpU4>`_):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
fmt::memory_buffer buf;
|
||||||
|
format_to(buf, "{}", 42); // replaces itoa(42, buffer, 10)
|
||||||
|
format_to(buf, "{:x}", 42); // replaces itoa(42, buffer, 16)
|
||||||
|
// access the string with to_string(buf) or buf.data()
|
||||||
|
|
||||||
|
Format objects of user-defined types via a simple `extension API
|
||||||
|
<https://fmt.dev/latest/api.html#formatting-user-defined-types>`_:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
|
struct date {
|
||||||
|
int year, month, day;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct fmt::formatter<date> {
|
||||||
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const date& d, FormatContext& ctx) {
|
||||||
|
return format_to(ctx.out(), "{}-{}-{}", d.year, d.month, d.day);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
|
||||||
|
// s == "The date is 2012-12-9"
|
||||||
|
|
||||||
|
Create your own functions similar to `format
|
||||||
|
<https://fmt.dev/latest/api.html#format>`_ and
|
||||||
|
`print <https://fmt.dev/latest/api.html#print>`_
|
||||||
|
which take arbitrary arguments (`godbolt <https://godbolt.org/g/MHjHVf>`_):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
// Prints formatted error message.
|
||||||
|
void vreport_error(const char* format, fmt::format_args args) {
|
||||||
|
fmt::print("Error: ");
|
||||||
|
fmt::vprint(format, args);
|
||||||
|
}
|
||||||
|
template <typename... Args>
|
||||||
|
void report_error(const char* format, const Args & ... args) {
|
||||||
|
vreport_error(format, fmt::make_format_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
report_error("file not found: {}", path);
|
||||||
|
|
||||||
|
Note that ``vreport_error`` is not parameterized on argument types which can
|
||||||
|
improve compile times and reduce code size compared to a fully parameterized
|
||||||
|
version.
|
||||||
|
|
||||||
|
Benchmarks
|
||||||
|
----------
|
||||||
|
|
||||||
|
Speed tests
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
================= ============= ===========
|
||||||
|
Library Method Run Time, s
|
||||||
|
================= ============= ===========
|
||||||
|
libc printf 1.04
|
||||||
|
libc++ std::ostream 3.05
|
||||||
|
{fmt} 6.1.1 fmt::print 0.75
|
||||||
|
Boost Format 1.67 boost::format 7.24
|
||||||
|
Folly Format folly::format 2.23
|
||||||
|
================= ============= ===========
|
||||||
|
|
||||||
|
{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``.
|
||||||
|
|
||||||
|
The above results were generated by building ``tinyformat_test.cpp`` on macOS
|
||||||
|
10.14.6 with ``clang++ -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of
|
||||||
|
three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
|
||||||
|
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
|
||||||
|
further details refer to the `source
|
||||||
|
<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
|
||||||
|
|
||||||
|
{fmt} is 10x faster than ``std::ostringstream`` and ``sprintf`` on floating-point
|
||||||
|
formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
||||||
|
and as fast as `double-conversion <https://github.com/google/double-conversion>`_:
|
||||||
|
|
||||||
|
.. image:: https://user-images.githubusercontent.com/576385/69767160-cdaca400-112f-11ea-9fc5-347c9f83caad.png
|
||||||
|
:target: https://fmt.dev/unknown_mac64_clang10.0.html
|
||||||
|
|
||||||
|
Compile time and code bloat
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The script `bloat-test.py
|
||||||
|
<https://github.com/fmtlib/format-benchmark/blob/master/bloat-test.py>`_
|
||||||
|
from `format-benchmark <https://github.com/fmtlib/format-benchmark>`_
|
||||||
|
tests compile time and code bloat for nontrivial projects.
|
||||||
|
It generates 100 translation units and uses ``printf()`` or its alternative
|
||||||
|
five times in each to simulate a medium sized project. The resulting
|
||||||
|
executable size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42),
|
||||||
|
macOS Sierra, best of three) is shown in the following tables.
|
||||||
|
|
||||||
|
**Optimized build (-O3)**
|
||||||
|
|
||||||
|
============= =============== ==================== ==================
|
||||||
|
Method Compile Time, s Executable size, KiB Stripped size, KiB
|
||||||
|
============= =============== ==================== ==================
|
||||||
|
printf 2.6 29 26
|
||||||
|
printf+string 16.4 29 26
|
||||||
|
iostreams 31.1 59 55
|
||||||
|
{fmt} 19.0 37 34
|
||||||
|
Boost Format 91.9 226 203
|
||||||
|
Folly Format 115.7 101 88
|
||||||
|
============= =============== ==================== ==================
|
||||||
|
|
||||||
|
As you can see, {fmt} has 60% less overhead in terms of resulting binary code
|
||||||
|
size compared to iostreams and comes pretty close to ``printf``. Boost Format
|
||||||
|
and Folly Format have the largest overheads.
|
||||||
|
|
||||||
|
``printf+string`` is the same as ``printf`` but with extra ``<string>``
|
||||||
|
include to measure the overhead of the latter.
|
||||||
|
|
||||||
|
**Non-optimized build**
|
||||||
|
|
||||||
|
============= =============== ==================== ==================
|
||||||
|
Method Compile Time, s Executable size, KiB Stripped size, KiB
|
||||||
|
============= =============== ==================== ==================
|
||||||
|
printf 2.2 33 30
|
||||||
|
printf+string 16.0 33 30
|
||||||
|
iostreams 28.3 56 52
|
||||||
|
{fmt} 18.2 59 50
|
||||||
|
Boost Format 54.1 365 303
|
||||||
|
Folly Format 79.9 445 430
|
||||||
|
============= =============== ==================== ==================
|
||||||
|
|
||||||
|
``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared libraries to
|
||||||
|
compare formatting function overhead only. Boost Format is a
|
||||||
|
header-only library so it doesn't provide any linkage options.
|
||||||
|
|
||||||
|
Running the tests
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Please refer to `Building the library`__ for the instructions on how to build
|
||||||
|
the library and run the unit tests.
|
||||||
|
|
||||||
|
__ https://fmt.dev/latest/usage.html#building-the-library
|
||||||
|
|
||||||
|
Benchmarks reside in a separate repository,
|
||||||
|
`format-benchmarks <https://github.com/fmtlib/format-benchmark>`_,
|
||||||
|
so to run the benchmarks you first need to clone this repository and
|
||||||
|
generate Makefiles with CMake::
|
||||||
|
|
||||||
|
$ git clone --recursive https://github.com/fmtlib/format-benchmark.git
|
||||||
|
$ cd format-benchmark
|
||||||
|
$ cmake .
|
||||||
|
|
||||||
|
Then you can run the speed test::
|
||||||
|
|
||||||
|
$ make speed-test
|
||||||
|
|
||||||
|
or the bloat test::
|
||||||
|
|
||||||
|
$ make bloat-test
|
||||||
|
|
||||||
|
Projects using this library
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
* `0 A.D. <http://play0ad.com/>`_: A free, open-source, cross-platform real-time
|
||||||
|
strategy game
|
||||||
|
|
||||||
|
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
||||||
|
An open-source library for mathematical programming
|
||||||
|
|
||||||
|
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft
|
||||||
|
operations suite
|
||||||
|
|
||||||
|
* `Celestia <https://celestia.space/>`_: Real-time 3D visualization of space
|
||||||
|
|
||||||
|
* `Ceph <https://ceph.com/>`_: A scalable distributed storage system
|
||||||
|
|
||||||
|
* `ccache <https://ccache.dev/>`_: A compiler cache
|
||||||
|
|
||||||
|
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater
|
||||||
|
vehicle
|
||||||
|
|
||||||
|
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
||||||
|
Player vs Player Gaming Network with tweaks
|
||||||
|
|
||||||
|
* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine
|
||||||
|
|
||||||
|
* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows
|
||||||
|
|
||||||
|
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): Home theater software
|
||||||
|
|
||||||
|
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
|
||||||
|
|
||||||
|
* `Drake <http://drake.mit.edu/>`_: A planning, control, and analysis toolbox
|
||||||
|
for nonlinear dynamical systems (MIT)
|
||||||
|
|
||||||
|
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus
|
||||||
|
(Lyft)
|
||||||
|
|
||||||
|
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
|
||||||
|
|
||||||
|
* `MongoDB <https://mongodb.com/>`_: Distributed document database
|
||||||
|
|
||||||
|
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to
|
||||||
|
generate randomized datasets
|
||||||
|
|
||||||
|
* `OpenSpace <http://openspaceproject.com/>`_: An open-source astrovisualization
|
||||||
|
framework
|
||||||
|
|
||||||
|
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
|
||||||
|
An MMO server, compatible with most Ultima Online clients
|
||||||
|
|
||||||
|
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance,
|
||||||
|
associative database
|
||||||
|
|
||||||
|
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
|
||||||
|
|
||||||
|
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster
|
||||||
|
proxy
|
||||||
|
|
||||||
|
* `rpclib <http://rpclib.net/>`_: A modern C++ msgpack-RPC server and client
|
||||||
|
library
|
||||||
|
|
||||||
|
* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_:
|
||||||
|
Small crossplatform 2D graphic engine
|
||||||
|
|
||||||
|
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
|
||||||
|
Business intelligence software
|
||||||
|
|
||||||
|
* `Scylla <http://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store
|
||||||
|
that can handle 1 million transactions per second on a single server
|
||||||
|
|
||||||
|
* `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++
|
||||||
|
framework for high-performance server applications on modern hardware
|
||||||
|
|
||||||
|
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
|
||||||
|
|
||||||
|
* `Stellar <https://www.stellar.org/>`_: Financial platform
|
||||||
|
|
||||||
|
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
|
||||||
|
|
||||||
|
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source
|
||||||
|
MMORPG framework
|
||||||
|
|
||||||
|
`More... <https://github.com/search?q=fmtlib&type=Code>`_
|
||||||
|
|
||||||
|
If you are aware of other projects using this library, please let me know
|
||||||
|
by `email <mailto:victor.zverovich@gmail.com>`_ or by submitting an
|
||||||
|
`issue <https://github.com/fmtlib/fmt/issues>`_.
|
||||||
|
|
||||||
|
Motivation
|
||||||
|
----------
|
||||||
|
|
||||||
|
So why yet another formatting library?
|
||||||
|
|
||||||
|
There are plenty of methods for doing this task, from standard ones like
|
||||||
|
the printf family of function and iostreams to Boost Format and FastFormat
|
||||||
|
libraries. The reason for creating a new library is that every existing
|
||||||
|
solution that I found either had serious issues or didn't provide
|
||||||
|
all the features I needed.
|
||||||
|
|
||||||
|
printf
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
The good thing about ``printf`` is that it is pretty fast and readily available
|
||||||
|
being a part of the C standard library. The main drawback is that it
|
||||||
|
doesn't support user-defined types. ``printf`` also has safety issues although
|
||||||
|
they are somewhat mitigated with `__attribute__ ((format (printf, ...))
|
||||||
|
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
|
||||||
|
There is a POSIX extension that adds positional arguments required for
|
||||||
|
`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_
|
||||||
|
to ``printf`` but it is not a part of C99 and may not be available on some
|
||||||
|
platforms.
|
||||||
|
|
||||||
|
iostreams
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
The main issue with iostreams is best illustrated with an example:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n";
|
||||||
|
|
||||||
|
which is a lot of typing compared to printf:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
printf("%.2f\n", 1.23456);
|
||||||
|
|
||||||
|
Matthew Wilson, the author of FastFormat, called this "chevron hell". iostreams
|
||||||
|
don't support positional arguments by design.
|
||||||
|
|
||||||
|
The good part is that iostreams support user-defined types and are safe although
|
||||||
|
error handling is awkward.
|
||||||
|
|
||||||
|
Boost Format
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This is a very powerful library which supports both ``printf``-like format
|
||||||
|
strings and positional arguments. Its main drawback is performance. According to
|
||||||
|
various benchmarks it is much slower than other methods considered here. Boost
|
||||||
|
Format also has excessive build times and severe code bloat issues (see
|
||||||
|
`Benchmarks`_).
|
||||||
|
|
||||||
|
FastFormat
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
This is an interesting library which is fast, safe and has positional
|
||||||
|
arguments. However it has significant limitations, citing its author:
|
||||||
|
|
||||||
|
Three features that have no hope of being accommodated within the
|
||||||
|
current design are:
|
||||||
|
|
||||||
|
* Leading zeros (or any other non-space padding)
|
||||||
|
* Octal/hexadecimal encoding
|
||||||
|
* Runtime width/alignment specification
|
||||||
|
|
||||||
|
It is also quite big and has a heavy dependency, STLSoft, which might be
|
||||||
|
too restrictive for using it in some projects.
|
||||||
|
|
||||||
|
Boost Spirit.Karma
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This is not really a formatting library but I decided to include it here for
|
||||||
|
completeness. As iostreams, it suffers from the problem of mixing verbatim text
|
||||||
|
with arguments. The library is pretty fast, but slower on integer formatting
|
||||||
|
than ``fmt::format_int`` on Karma's own benchmark,
|
||||||
|
see `Fast integer to string conversion in C++
|
||||||
|
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
||||||
|
|
||||||
|
FAQ
|
||||||
|
---
|
||||||
|
|
||||||
|
Q: how can I capture formatting arguments and format them later?
|
||||||
|
|
||||||
|
A: use ``std::tuple``:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
auto capture(const Args&... args) {
|
||||||
|
return std::make_tuple(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto print_message = [](const auto&... args) {
|
||||||
|
fmt::print(args...);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Capture and store arguments:
|
||||||
|
auto args = capture("{} {}", 42, "foo");
|
||||||
|
// Do formatting:
|
||||||
|
std::apply(print_message, args);
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
{fmt} is distributed under the MIT `license
|
||||||
|
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_.
|
||||||
|
|
||||||
|
The `Format String Syntax
|
||||||
|
<https://fmt.dev/latest/syntax.html>`_
|
||||||
|
section in the documentation is based on the one from Python `string module
|
||||||
|
documentation <https://docs.python.org/3/library/string.html#module-string>`_
|
||||||
|
adapted for the current library. For this reason the documentation is
|
||||||
|
distributed under the Python Software Foundation license available in
|
||||||
|
`doc/python-license.txt
|
||||||
|
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
|
||||||
|
It only applies if you distribute the documentation of fmt.
|
||||||
|
|
||||||
|
Acknowledgments
|
||||||
|
---------------
|
||||||
|
|
||||||
|
The {fmt} library is maintained by Victor Zverovich (`vitaut
|
||||||
|
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
|
||||||
|
<https://github.com/foonathan>`_) with contributions from many other people.
|
||||||
|
See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
|
||||||
|
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
|
||||||
|
Let us know if your contribution is not listed or mentioned incorrectly and
|
||||||
|
we'll make it right.
|
||||||
|
|
||||||
|
The benchmark section of this readme file and the performance tests are taken
|
||||||
|
from the excellent `tinyformat <https://github.com/c42f/tinyformat>`_ library
|
||||||
|
written by Chris Foster. Boost Format library is acknowledged transitively
|
||||||
|
since it had some influence on tinyformat.
|
||||||
|
Some ideas used in the implementation are borrowed from `Loki
|
||||||
|
<http://loki-lib.sourceforge.net/>`_ SafeFormat and `Diagnostic API
|
||||||
|
<http://clang.llvm.org/doxygen/classclang_1_1Diagnostic.html>`_ in
|
||||||
|
`Clang <http://clang.llvm.org/>`_.
|
||||||
|
Format string syntax and the documentation are based on Python's `str.format
|
||||||
|
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
|
||||||
|
Thanks `Doug Turnbull <https://github.com/softwaredoug>`_ for his valuable
|
||||||
|
comments and contribution to the design of the type-safe API and
|
||||||
|
`Gregory Czajkowski <https://github.com/gcflymoto>`_ for implementing binary
|
||||||
|
formatting. Thanks `Ruslan Baratov <https://github.com/ruslo>`_ for comprehensive
|
||||||
|
`comparison of integer formatting algorithms <https://github.com/ruslo/int-dec-format-tests>`_
|
||||||
|
and useful comments regarding performance, `Boris Kaul <https://github.com/localvoid>`_ for
|
||||||
|
`C++ counting digits benchmark <https://github.com/localvoid/cxx-benchmark-count-digits>`_.
|
||||||
|
Thanks to `CarterLi <https://github.com/CarterLi>`_ for contributing various
|
||||||
|
improvements to the code.
|
||||||
1106
ext/fmt-6.1.2/include/fmt/chrono.h
Normal file
1106
ext/fmt-6.1.2/include/fmt/chrono.h
Normal file
File diff suppressed because it is too large
Load diff
570
ext/fmt-6.1.2/include/fmt/color.h
Normal file
570
ext/fmt-6.1.2/include/fmt/color.h
Normal file
|
|
@ -0,0 +1,570 @@
|
||||||
|
// Formatting library for C++ - color support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_COLOR_H_
|
||||||
|
#define FMT_COLOR_H_
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
enum class color : uint32_t {
|
||||||
|
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||||
|
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
||||||
|
aqua = 0x00FFFF, // rgb(0,255,255)
|
||||||
|
aquamarine = 0x7FFFD4, // rgb(127,255,212)
|
||||||
|
azure = 0xF0FFFF, // rgb(240,255,255)
|
||||||
|
beige = 0xF5F5DC, // rgb(245,245,220)
|
||||||
|
bisque = 0xFFE4C4, // rgb(255,228,196)
|
||||||
|
black = 0x000000, // rgb(0,0,0)
|
||||||
|
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
|
||||||
|
blue = 0x0000FF, // rgb(0,0,255)
|
||||||
|
blue_violet = 0x8A2BE2, // rgb(138,43,226)
|
||||||
|
brown = 0xA52A2A, // rgb(165,42,42)
|
||||||
|
burly_wood = 0xDEB887, // rgb(222,184,135)
|
||||||
|
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
|
||||||
|
chartreuse = 0x7FFF00, // rgb(127,255,0)
|
||||||
|
chocolate = 0xD2691E, // rgb(210,105,30)
|
||||||
|
coral = 0xFF7F50, // rgb(255,127,80)
|
||||||
|
cornflower_blue = 0x6495ED, // rgb(100,149,237)
|
||||||
|
cornsilk = 0xFFF8DC, // rgb(255,248,220)
|
||||||
|
crimson = 0xDC143C, // rgb(220,20,60)
|
||||||
|
cyan = 0x00FFFF, // rgb(0,255,255)
|
||||||
|
dark_blue = 0x00008B, // rgb(0,0,139)
|
||||||
|
dark_cyan = 0x008B8B, // rgb(0,139,139)
|
||||||
|
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
|
||||||
|
dark_gray = 0xA9A9A9, // rgb(169,169,169)
|
||||||
|
dark_green = 0x006400, // rgb(0,100,0)
|
||||||
|
dark_khaki = 0xBDB76B, // rgb(189,183,107)
|
||||||
|
dark_magenta = 0x8B008B, // rgb(139,0,139)
|
||||||
|
dark_olive_green = 0x556B2F, // rgb(85,107,47)
|
||||||
|
dark_orange = 0xFF8C00, // rgb(255,140,0)
|
||||||
|
dark_orchid = 0x9932CC, // rgb(153,50,204)
|
||||||
|
dark_red = 0x8B0000, // rgb(139,0,0)
|
||||||
|
dark_salmon = 0xE9967A, // rgb(233,150,122)
|
||||||
|
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
|
||||||
|
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
|
||||||
|
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
|
||||||
|
dark_turquoise = 0x00CED1, // rgb(0,206,209)
|
||||||
|
dark_violet = 0x9400D3, // rgb(148,0,211)
|
||||||
|
deep_pink = 0xFF1493, // rgb(255,20,147)
|
||||||
|
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
|
||||||
|
dim_gray = 0x696969, // rgb(105,105,105)
|
||||||
|
dodger_blue = 0x1E90FF, // rgb(30,144,255)
|
||||||
|
fire_brick = 0xB22222, // rgb(178,34,34)
|
||||||
|
floral_white = 0xFFFAF0, // rgb(255,250,240)
|
||||||
|
forest_green = 0x228B22, // rgb(34,139,34)
|
||||||
|
fuchsia = 0xFF00FF, // rgb(255,0,255)
|
||||||
|
gainsboro = 0xDCDCDC, // rgb(220,220,220)
|
||||||
|
ghost_white = 0xF8F8FF, // rgb(248,248,255)
|
||||||
|
gold = 0xFFD700, // rgb(255,215,0)
|
||||||
|
golden_rod = 0xDAA520, // rgb(218,165,32)
|
||||||
|
gray = 0x808080, // rgb(128,128,128)
|
||||||
|
green = 0x008000, // rgb(0,128,0)
|
||||||
|
green_yellow = 0xADFF2F, // rgb(173,255,47)
|
||||||
|
honey_dew = 0xF0FFF0, // rgb(240,255,240)
|
||||||
|
hot_pink = 0xFF69B4, // rgb(255,105,180)
|
||||||
|
indian_red = 0xCD5C5C, // rgb(205,92,92)
|
||||||
|
indigo = 0x4B0082, // rgb(75,0,130)
|
||||||
|
ivory = 0xFFFFF0, // rgb(255,255,240)
|
||||||
|
khaki = 0xF0E68C, // rgb(240,230,140)
|
||||||
|
lavender = 0xE6E6FA, // rgb(230,230,250)
|
||||||
|
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
|
||||||
|
lawn_green = 0x7CFC00, // rgb(124,252,0)
|
||||||
|
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
|
||||||
|
light_blue = 0xADD8E6, // rgb(173,216,230)
|
||||||
|
light_coral = 0xF08080, // rgb(240,128,128)
|
||||||
|
light_cyan = 0xE0FFFF, // rgb(224,255,255)
|
||||||
|
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
|
||||||
|
light_gray = 0xD3D3D3, // rgb(211,211,211)
|
||||||
|
light_green = 0x90EE90, // rgb(144,238,144)
|
||||||
|
light_pink = 0xFFB6C1, // rgb(255,182,193)
|
||||||
|
light_salmon = 0xFFA07A, // rgb(255,160,122)
|
||||||
|
light_sea_green = 0x20B2AA, // rgb(32,178,170)
|
||||||
|
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
|
||||||
|
light_slate_gray = 0x778899, // rgb(119,136,153)
|
||||||
|
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
|
||||||
|
light_yellow = 0xFFFFE0, // rgb(255,255,224)
|
||||||
|
lime = 0x00FF00, // rgb(0,255,0)
|
||||||
|
lime_green = 0x32CD32, // rgb(50,205,50)
|
||||||
|
linen = 0xFAF0E6, // rgb(250,240,230)
|
||||||
|
magenta = 0xFF00FF, // rgb(255,0,255)
|
||||||
|
maroon = 0x800000, // rgb(128,0,0)
|
||||||
|
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
|
||||||
|
medium_blue = 0x0000CD, // rgb(0,0,205)
|
||||||
|
medium_orchid = 0xBA55D3, // rgb(186,85,211)
|
||||||
|
medium_purple = 0x9370DB, // rgb(147,112,219)
|
||||||
|
medium_sea_green = 0x3CB371, // rgb(60,179,113)
|
||||||
|
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
|
||||||
|
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
|
||||||
|
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
|
||||||
|
medium_violet_red = 0xC71585, // rgb(199,21,133)
|
||||||
|
midnight_blue = 0x191970, // rgb(25,25,112)
|
||||||
|
mint_cream = 0xF5FFFA, // rgb(245,255,250)
|
||||||
|
misty_rose = 0xFFE4E1, // rgb(255,228,225)
|
||||||
|
moccasin = 0xFFE4B5, // rgb(255,228,181)
|
||||||
|
navajo_white = 0xFFDEAD, // rgb(255,222,173)
|
||||||
|
navy = 0x000080, // rgb(0,0,128)
|
||||||
|
old_lace = 0xFDF5E6, // rgb(253,245,230)
|
||||||
|
olive = 0x808000, // rgb(128,128,0)
|
||||||
|
olive_drab = 0x6B8E23, // rgb(107,142,35)
|
||||||
|
orange = 0xFFA500, // rgb(255,165,0)
|
||||||
|
orange_red = 0xFF4500, // rgb(255,69,0)
|
||||||
|
orchid = 0xDA70D6, // rgb(218,112,214)
|
||||||
|
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
|
||||||
|
pale_green = 0x98FB98, // rgb(152,251,152)
|
||||||
|
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
|
||||||
|
pale_violet_red = 0xDB7093, // rgb(219,112,147)
|
||||||
|
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
|
||||||
|
peach_puff = 0xFFDAB9, // rgb(255,218,185)
|
||||||
|
peru = 0xCD853F, // rgb(205,133,63)
|
||||||
|
pink = 0xFFC0CB, // rgb(255,192,203)
|
||||||
|
plum = 0xDDA0DD, // rgb(221,160,221)
|
||||||
|
powder_blue = 0xB0E0E6, // rgb(176,224,230)
|
||||||
|
purple = 0x800080, // rgb(128,0,128)
|
||||||
|
rebecca_purple = 0x663399, // rgb(102,51,153)
|
||||||
|
red = 0xFF0000, // rgb(255,0,0)
|
||||||
|
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
|
||||||
|
royal_blue = 0x4169E1, // rgb(65,105,225)
|
||||||
|
saddle_brown = 0x8B4513, // rgb(139,69,19)
|
||||||
|
salmon = 0xFA8072, // rgb(250,128,114)
|
||||||
|
sandy_brown = 0xF4A460, // rgb(244,164,96)
|
||||||
|
sea_green = 0x2E8B57, // rgb(46,139,87)
|
||||||
|
sea_shell = 0xFFF5EE, // rgb(255,245,238)
|
||||||
|
sienna = 0xA0522D, // rgb(160,82,45)
|
||||||
|
silver = 0xC0C0C0, // rgb(192,192,192)
|
||||||
|
sky_blue = 0x87CEEB, // rgb(135,206,235)
|
||||||
|
slate_blue = 0x6A5ACD, // rgb(106,90,205)
|
||||||
|
slate_gray = 0x708090, // rgb(112,128,144)
|
||||||
|
snow = 0xFFFAFA, // rgb(255,250,250)
|
||||||
|
spring_green = 0x00FF7F, // rgb(0,255,127)
|
||||||
|
steel_blue = 0x4682B4, // rgb(70,130,180)
|
||||||
|
tan = 0xD2B48C, // rgb(210,180,140)
|
||||||
|
teal = 0x008080, // rgb(0,128,128)
|
||||||
|
thistle = 0xD8BFD8, // rgb(216,191,216)
|
||||||
|
tomato = 0xFF6347, // rgb(255,99,71)
|
||||||
|
turquoise = 0x40E0D0, // rgb(64,224,208)
|
||||||
|
violet = 0xEE82EE, // rgb(238,130,238)
|
||||||
|
wheat = 0xF5DEB3, // rgb(245,222,179)
|
||||||
|
white = 0xFFFFFF, // rgb(255,255,255)
|
||||||
|
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
||||||
|
yellow = 0xFFFF00, // rgb(255,255,0)
|
||||||
|
yellow_green = 0x9ACD32 // rgb(154,205,50)
|
||||||
|
}; // enum class color
|
||||||
|
|
||||||
|
enum class terminal_color : uint8_t {
|
||||||
|
black = 30,
|
||||||
|
red,
|
||||||
|
green,
|
||||||
|
yellow,
|
||||||
|
blue,
|
||||||
|
magenta,
|
||||||
|
cyan,
|
||||||
|
white,
|
||||||
|
bright_black = 90,
|
||||||
|
bright_red,
|
||||||
|
bright_green,
|
||||||
|
bright_yellow,
|
||||||
|
bright_blue,
|
||||||
|
bright_magenta,
|
||||||
|
bright_cyan,
|
||||||
|
bright_white
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class emphasis : uint8_t {
|
||||||
|
bold = 1,
|
||||||
|
italic = 1 << 1,
|
||||||
|
underline = 1 << 2,
|
||||||
|
strikethrough = 1 << 3
|
||||||
|
};
|
||||||
|
|
||||||
|
// rgb is a struct for red, green and blue colors.
|
||||||
|
// Using the name "rgb" makes some editors show the color in a tooltip.
|
||||||
|
struct rgb {
|
||||||
|
FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {}
|
||||||
|
FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {}
|
||||||
|
FMT_CONSTEXPR rgb(uint32_t hex)
|
||||||
|
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
|
||||||
|
FMT_CONSTEXPR rgb(color hex)
|
||||||
|
: r((uint32_t(hex) >> 16) & 0xFF),
|
||||||
|
g((uint32_t(hex) >> 8) & 0xFF),
|
||||||
|
b(uint32_t(hex) & 0xFF) {}
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// color is a struct of either a rgb color or a terminal color.
|
||||||
|
struct color_type {
|
||||||
|
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
|
||||||
|
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
|
||||||
|
value{} {
|
||||||
|
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
|
||||||
|
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||||
|
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
|
||||||
|
value{} {
|
||||||
|
value.term_color = static_cast<uint8_t>(term_color);
|
||||||
|
}
|
||||||
|
bool is_rgb;
|
||||||
|
union color_union {
|
||||||
|
uint8_t term_color;
|
||||||
|
uint32_t rgb_color;
|
||||||
|
} value;
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// Experimental text formatting support.
|
||||||
|
class text_style {
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
||||||
|
: set_foreground_color(),
|
||||||
|
set_background_color(),
|
||||||
|
ems(em) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
||||||
|
if (!set_foreground_color) {
|
||||||
|
set_foreground_color = rhs.set_foreground_color;
|
||||||
|
foreground_color = rhs.foreground_color;
|
||||||
|
} else if (rhs.set_foreground_color) {
|
||||||
|
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||||
|
FMT_THROW(format_error("can't OR a terminal color"));
|
||||||
|
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!set_background_color) {
|
||||||
|
set_background_color = rhs.set_background_color;
|
||||||
|
background_color = rhs.background_color;
|
||||||
|
} else if (rhs.set_background_color) {
|
||||||
|
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||||
|
FMT_THROW(format_error("can't OR a terminal color"));
|
||||||
|
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
|
||||||
|
static_cast<uint8_t>(rhs.ems));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend FMT_CONSTEXPR text_style operator|(text_style lhs,
|
||||||
|
const text_style& rhs) {
|
||||||
|
return lhs |= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) {
|
||||||
|
if (!set_foreground_color) {
|
||||||
|
set_foreground_color = rhs.set_foreground_color;
|
||||||
|
foreground_color = rhs.foreground_color;
|
||||||
|
} else if (rhs.set_foreground_color) {
|
||||||
|
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
||||||
|
FMT_THROW(format_error("can't AND a terminal color"));
|
||||||
|
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!set_background_color) {
|
||||||
|
set_background_color = rhs.set_background_color;
|
||||||
|
background_color = rhs.background_color;
|
||||||
|
} else if (rhs.set_background_color) {
|
||||||
|
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
||||||
|
FMT_THROW(format_error("can't AND a terminal color"));
|
||||||
|
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
|
||||||
|
static_cast<uint8_t>(rhs.ems));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend FMT_CONSTEXPR text_style operator&(text_style lhs,
|
||||||
|
const text_style& rhs) {
|
||||||
|
return lhs &= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
||||||
|
return set_foreground_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
||||||
|
return set_background_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
||||||
|
return static_cast<uint8_t>(ems) != 0;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
|
||||||
|
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||||
|
return foreground_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
|
||||||
|
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||||
|
return background_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
||||||
|
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||||
|
return ems;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||||
|
internal::color_type text_color) FMT_NOEXCEPT
|
||||||
|
: set_foreground_color(),
|
||||||
|
set_background_color(),
|
||||||
|
ems() {
|
||||||
|
if (is_foreground) {
|
||||||
|
foreground_color = text_color;
|
||||||
|
set_foreground_color = true;
|
||||||
|
} else {
|
||||||
|
background_color = text_color;
|
||||||
|
set_background_color = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
|
||||||
|
FMT_NOEXCEPT;
|
||||||
|
friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
|
||||||
|
FMT_NOEXCEPT;
|
||||||
|
|
||||||
|
internal::color_type foreground_color;
|
||||||
|
internal::color_type background_color;
|
||||||
|
bool set_foreground_color;
|
||||||
|
bool set_background_color;
|
||||||
|
emphasis ems;
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
|
||||||
|
return text_style(/*is_foreground=*/true, foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
|
||||||
|
return text_style(/*is_foreground=*/false, background);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
|
||||||
|
return text_style(lhs) | rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <typename Char> struct ansi_color_escape {
|
||||||
|
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
|
||||||
|
const char* esc) FMT_NOEXCEPT {
|
||||||
|
// If we have a terminal color, we need to output another escape code
|
||||||
|
// sequence.
|
||||||
|
if (!text_color.is_rgb) {
|
||||||
|
bool is_background = esc == internal::data::background_color;
|
||||||
|
uint32_t value = text_color.value.term_color;
|
||||||
|
// Background ASCII codes are the same as the foreground ones but with
|
||||||
|
// 10 more.
|
||||||
|
if (is_background) value += 10u;
|
||||||
|
|
||||||
|
std::size_t index = 0;
|
||||||
|
buffer[index++] = static_cast<Char>('\x1b');
|
||||||
|
buffer[index++] = static_cast<Char>('[');
|
||||||
|
|
||||||
|
if (value >= 100u) {
|
||||||
|
buffer[index++] = static_cast<Char>('1');
|
||||||
|
value %= 100u;
|
||||||
|
}
|
||||||
|
buffer[index++] = static_cast<Char>('0' + value / 10u);
|
||||||
|
buffer[index++] = static_cast<Char>('0' + value % 10u);
|
||||||
|
|
||||||
|
buffer[index++] = static_cast<Char>('m');
|
||||||
|
buffer[index++] = static_cast<Char>('\0');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
buffer[i] = static_cast<Char>(esc[i]);
|
||||||
|
}
|
||||||
|
rgb color(text_color.value.rgb_color);
|
||||||
|
to_esc(color.r, buffer + 7, ';');
|
||||||
|
to_esc(color.g, buffer + 11, ';');
|
||||||
|
to_esc(color.b, buffer + 15, 'm');
|
||||||
|
buffer[19] = static_cast<Char>(0);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
|
||||||
|
uint8_t em_codes[4] = {};
|
||||||
|
uint8_t em_bits = static_cast<uint8_t>(em);
|
||||||
|
if (em_bits & static_cast<uint8_t>(emphasis::bold)) em_codes[0] = 1;
|
||||||
|
if (em_bits & static_cast<uint8_t>(emphasis::italic)) em_codes[1] = 3;
|
||||||
|
if (em_bits & static_cast<uint8_t>(emphasis::underline)) em_codes[2] = 4;
|
||||||
|
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
|
||||||
|
em_codes[3] = 9;
|
||||||
|
|
||||||
|
std::size_t index = 0;
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
if (!em_codes[i]) continue;
|
||||||
|
buffer[index++] = static_cast<Char>('\x1b');
|
||||||
|
buffer[index++] = static_cast<Char>('[');
|
||||||
|
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
|
||||||
|
buffer[index++] = static_cast<Char>('m');
|
||||||
|
}
|
||||||
|
buffer[index++] = static_cast<Char>(0);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
|
||||||
|
|
||||||
|
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
|
||||||
|
FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
|
||||||
|
return buffer + std::strlen(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Char buffer[7u + 3u * 4u + 1u];
|
||||||
|
|
||||||
|
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||||
|
char delimiter) FMT_NOEXCEPT {
|
||||||
|
out[0] = static_cast<Char>('0' + c / 100);
|
||||||
|
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||||
|
out[2] = static_cast<Char>('0' + c % 10);
|
||||||
|
out[3] = static_cast<Char>(delimiter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
||||||
|
internal::color_type foreground) FMT_NOEXCEPT {
|
||||||
|
return ansi_color_escape<Char>(foreground, internal::data::foreground_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
||||||
|
internal::color_type background) FMT_NOEXCEPT {
|
||||||
|
return ansi_color_escape<Char>(background, internal::data::background_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
|
||||||
|
return ansi_color_escape<Char>(em);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
|
||||||
|
std::fputs(chars, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
|
||||||
|
std::fputws(chars, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
|
||||||
|
fputs(internal::data::reset_color, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
|
||||||
|
fputs(internal::data::wreset_color, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
|
||||||
|
const char* begin = data::reset_color;
|
||||||
|
const char* end = begin + sizeof(data::reset_color) - 1;
|
||||||
|
buffer.append(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
|
||||||
|
basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
|
bool has_style = false;
|
||||||
|
if (ts.has_emphasis()) {
|
||||||
|
has_style = true;
|
||||||
|
auto emphasis = internal::make_emphasis<Char>(ts.get_emphasis());
|
||||||
|
buf.append(emphasis.begin(), emphasis.end());
|
||||||
|
}
|
||||||
|
if (ts.has_foreground()) {
|
||||||
|
has_style = true;
|
||||||
|
auto foreground =
|
||||||
|
internal::make_foreground_color<Char>(ts.get_foreground());
|
||||||
|
buf.append(foreground.begin(), foreground.end());
|
||||||
|
}
|
||||||
|
if (ts.has_background()) {
|
||||||
|
has_style = true;
|
||||||
|
auto background =
|
||||||
|
internal::make_background_color<Char>(ts.get_background());
|
||||||
|
buf.append(background.begin(), background.end());
|
||||||
|
}
|
||||||
|
vformat_to(buf, format_str, args);
|
||||||
|
if (has_style) {
|
||||||
|
internal::reset_color<Char>(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename S, typename Char = char_t<S>>
|
||||||
|
void vprint(std::FILE* f, const text_style& ts, const S& format,
|
||||||
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
|
basic_memory_buffer<Char> buf;
|
||||||
|
internal::vformat_to(buf, ts, to_string_view(format), args);
|
||||||
|
buf.push_back(Char(0));
|
||||||
|
internal::fputs(buf.data(), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats a string and prints it to the specified file stream using ANSI
|
||||||
|
escape sequences to specify text formatting.
|
||||||
|
Example:
|
||||||
|
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||||
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
*/
|
||||||
|
template <typename S, typename... Args,
|
||||||
|
FMT_ENABLE_IF(internal::is_string<S>::value)>
|
||||||
|
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
||||||
|
const Args&... args) {
|
||||||
|
internal::check_format_string<Args...>(format_str);
|
||||||
|
using context = buffer_context<char_t<S>>;
|
||||||
|
format_arg_store<context, Args...> as{args...};
|
||||||
|
vprint(f, ts, format_str, basic_format_args<context>(as));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||||
|
specify text formatting.
|
||||||
|
Example:
|
||||||
|
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||||
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
*/
|
||||||
|
template <typename S, typename... Args,
|
||||||
|
FMT_ENABLE_IF(internal::is_string<S>::value)>
|
||||||
|
void print(const text_style& ts, const S& format_str, const Args&... args) {
|
||||||
|
return print(stdout, ts, format_str, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename Char = char_t<S>>
|
||||||
|
inline std::basic_string<Char> vformat(
|
||||||
|
const text_style& ts, const S& format_str,
|
||||||
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
|
basic_memory_buffer<Char> buf;
|
||||||
|
internal::vformat_to(buf, ts, to_string_view(format_str), args);
|
||||||
|
return fmt::to_string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Formats arguments and returns the result as a string using ANSI
|
||||||
|
escape sequences to specify text formatting.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
#include <fmt/color.h>
|
||||||
|
std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red),
|
||||||
|
"The answer is {}", 42);
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||||
|
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||||
|
const Args&... args) {
|
||||||
|
return vformat(ts, to_string_view(format_str),
|
||||||
|
{internal::make_args_checked<Args...>(format_str, args...)});
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_COLOR_H_
|
||||||
585
ext/fmt-6.1.2/include/fmt/compile.h
Normal file
585
ext/fmt-6.1.2/include/fmt/compile.h
Normal file
|
|
@ -0,0 +1,585 @@
|
||||||
|
// Formatting library for C++ - experimental format string compilation
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_COMPILE_H_
|
||||||
|
#define FMT_COMPILE_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Part of a compiled format string. It can be either literal text or a
|
||||||
|
// replacement field.
|
||||||
|
template <typename Char> struct format_part {
|
||||||
|
enum class kind { arg_index, arg_name, text, replacement };
|
||||||
|
|
||||||
|
struct replacement {
|
||||||
|
arg_ref<Char> arg_id;
|
||||||
|
dynamic_format_specs<Char> specs;
|
||||||
|
};
|
||||||
|
|
||||||
|
kind part_kind;
|
||||||
|
union value {
|
||||||
|
int arg_index;
|
||||||
|
basic_string_view<Char> str;
|
||||||
|
replacement repl;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR value(int index = 0) : arg_index(index) {}
|
||||||
|
FMT_CONSTEXPR value(basic_string_view<Char> s) : str(s) {}
|
||||||
|
FMT_CONSTEXPR value(replacement r) : repl(r) {}
|
||||||
|
} val;
|
||||||
|
// Position past the end of the argument id.
|
||||||
|
const Char* arg_id_end = nullptr;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {})
|
||||||
|
: part_kind(k), val(v) {}
|
||||||
|
|
||||||
|
static FMT_CONSTEXPR format_part make_arg_index(int index) {
|
||||||
|
return format_part(kind::arg_index, index);
|
||||||
|
}
|
||||||
|
static FMT_CONSTEXPR format_part make_arg_name(basic_string_view<Char> name) {
|
||||||
|
return format_part(kind::arg_name, name);
|
||||||
|
}
|
||||||
|
static FMT_CONSTEXPR format_part make_text(basic_string_view<Char> text) {
|
||||||
|
return format_part(kind::text, text);
|
||||||
|
}
|
||||||
|
static FMT_CONSTEXPR format_part make_replacement(replacement repl) {
|
||||||
|
return format_part(kind::replacement, repl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char> struct part_counter {
|
||||||
|
unsigned num_parts = 0;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
|
||||||
|
if (begin != end) ++num_parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_arg_id() { ++num_parts; }
|
||||||
|
FMT_CONSTEXPR void on_arg_id(int) { ++num_parts; }
|
||||||
|
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) { ++num_parts; }
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_replacement_field(const Char*) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
|
||||||
|
const Char* end) {
|
||||||
|
// Find the matching brace.
|
||||||
|
unsigned brace_counter = 0;
|
||||||
|
for (; begin != end; ++begin) {
|
||||||
|
if (*begin == '{') {
|
||||||
|
++brace_counter;
|
||||||
|
} else if (*begin == '}') {
|
||||||
|
if (brace_counter == 0u) break;
|
||||||
|
--brace_counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_error(const char*) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Counts the number of parts in a format string.
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR unsigned count_parts(basic_string_view<Char> format_str) {
|
||||||
|
part_counter<Char> counter;
|
||||||
|
parse_format_string<true>(format_str, counter);
|
||||||
|
return counter.num_parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename PartHandler>
|
||||||
|
class format_string_compiler : public error_handler {
|
||||||
|
private:
|
||||||
|
using part = format_part<Char>;
|
||||||
|
|
||||||
|
PartHandler handler_;
|
||||||
|
part part_;
|
||||||
|
basic_string_view<Char> format_str_;
|
||||||
|
basic_format_parse_context<Char> parse_context_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR format_string_compiler(basic_string_view<Char> format_str,
|
||||||
|
PartHandler handler)
|
||||||
|
: handler_(handler),
|
||||||
|
format_str_(format_str),
|
||||||
|
parse_context_(format_str) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
|
||||||
|
if (begin != end)
|
||||||
|
handler_(part::make_text({begin, to_unsigned(end - begin)}));
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_arg_id() {
|
||||||
|
part_ = part::make_arg_index(parse_context_.next_arg_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_arg_id(int id) {
|
||||||
|
parse_context_.check_arg_id(id);
|
||||||
|
part_ = part::make_arg_index(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) {
|
||||||
|
part_ = part::make_arg_name(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_replacement_field(const Char* ptr) {
|
||||||
|
part_.arg_id_end = ptr;
|
||||||
|
handler_(part_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
|
||||||
|
const Char* end) {
|
||||||
|
auto repl = typename part::replacement();
|
||||||
|
dynamic_specs_handler<basic_format_parse_context<Char>> handler(
|
||||||
|
repl.specs, parse_context_);
|
||||||
|
auto it = parse_format_specs(begin, end, handler);
|
||||||
|
if (*it != '}') on_error("missing '}' in format string");
|
||||||
|
repl.arg_id = part_.part_kind == part::kind::arg_index
|
||||||
|
? arg_ref<Char>(part_.val.arg_index)
|
||||||
|
: arg_ref<Char>(part_.val.str);
|
||||||
|
auto part = part::make_replacement(repl);
|
||||||
|
part.arg_id_end = begin;
|
||||||
|
handler_(part);
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compiles a format string and invokes handler(part) for each parsed part.
|
||||||
|
template <bool IS_CONSTEXPR, typename Char, typename PartHandler>
|
||||||
|
FMT_CONSTEXPR void compile_format_string(basic_string_view<Char> format_str,
|
||||||
|
PartHandler handler) {
|
||||||
|
parse_format_string<IS_CONSTEXPR>(
|
||||||
|
format_str,
|
||||||
|
format_string_compiler<Char, PartHandler>(format_str, handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Range, typename Context, typename Id>
|
||||||
|
void format_arg(
|
||||||
|
basic_format_parse_context<typename Range::value_type>& parse_ctx,
|
||||||
|
Context& ctx, Id arg_id) {
|
||||||
|
ctx.advance_to(
|
||||||
|
visit_format_arg(arg_formatter<Range>(ctx, &parse_ctx), ctx.arg(arg_id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// vformat_to is defined in a subnamespace to prevent ADL.
|
||||||
|
namespace cf {
|
||||||
|
template <typename Context, typename Range, typename CompiledFormat>
|
||||||
|
auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
|
||||||
|
-> typename Context::iterator {
|
||||||
|
using char_type = typename Context::char_type;
|
||||||
|
basic_format_parse_context<char_type> parse_ctx(
|
||||||
|
to_string_view(cf.format_str_));
|
||||||
|
Context ctx(out.begin(), args);
|
||||||
|
|
||||||
|
const auto& parts = cf.parts();
|
||||||
|
for (auto part_it = std::begin(parts); part_it != std::end(parts);
|
||||||
|
++part_it) {
|
||||||
|
const auto& part = *part_it;
|
||||||
|
const auto& value = part.val;
|
||||||
|
|
||||||
|
using format_part_t = format_part<char_type>;
|
||||||
|
switch (part.part_kind) {
|
||||||
|
case format_part_t::kind::text: {
|
||||||
|
const auto text = value.str;
|
||||||
|
auto output = ctx.out();
|
||||||
|
auto&& it = reserve(output, text.size());
|
||||||
|
it = std::copy_n(text.begin(), text.size(), it);
|
||||||
|
ctx.advance_to(output);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case format_part_t::kind::arg_index:
|
||||||
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
|
internal::format_arg<Range>(parse_ctx, ctx, value.arg_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case format_part_t::kind::arg_name:
|
||||||
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
|
internal::format_arg<Range>(parse_ctx, ctx, value.str);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case format_part_t::kind::replacement: {
|
||||||
|
const auto& arg_id_value = value.repl.arg_id.val;
|
||||||
|
const auto arg = value.repl.arg_id.kind == arg_id_kind::index
|
||||||
|
? ctx.arg(arg_id_value.index)
|
||||||
|
: ctx.arg(arg_id_value.name);
|
||||||
|
|
||||||
|
auto specs = value.repl.specs;
|
||||||
|
|
||||||
|
handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
|
||||||
|
handle_dynamic_spec<precision_checker>(specs.precision,
|
||||||
|
specs.precision_ref, ctx);
|
||||||
|
|
||||||
|
error_handler h;
|
||||||
|
numeric_specs_checker<error_handler> checker(h, arg.type());
|
||||||
|
if (specs.align == align::numeric) checker.require_numeric_argument();
|
||||||
|
if (specs.sign != sign::none) checker.check_sign();
|
||||||
|
if (specs.alt) checker.require_numeric_argument();
|
||||||
|
if (specs.precision >= 0) checker.check_precision();
|
||||||
|
|
||||||
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
|
ctx.advance_to(
|
||||||
|
visit_format_arg(arg_formatter<Range>(ctx, nullptr, &specs), arg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx.out();
|
||||||
|
}
|
||||||
|
} // namespace cf
|
||||||
|
|
||||||
|
struct basic_compiled_format {};
|
||||||
|
|
||||||
|
template <typename S, typename = void>
|
||||||
|
struct compiled_format_base : basic_compiled_format {
|
||||||
|
using char_type = char_t<S>;
|
||||||
|
using parts_container = std::vector<internal::format_part<char_type>>;
|
||||||
|
|
||||||
|
parts_container compiled_parts;
|
||||||
|
|
||||||
|
explicit compiled_format_base(basic_string_view<char_type> format_str) {
|
||||||
|
compile_format_string<false>(format_str,
|
||||||
|
[this](const format_part<char_type>& part) {
|
||||||
|
compiled_parts.push_back(part);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts_container& parts() const { return compiled_parts; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, unsigned N> struct format_part_array {
|
||||||
|
format_part<Char> data[N] = {};
|
||||||
|
FMT_CONSTEXPR format_part_array() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, unsigned N>
|
||||||
|
FMT_CONSTEXPR format_part_array<Char, N> compile_to_parts(
|
||||||
|
basic_string_view<Char> format_str) {
|
||||||
|
format_part_array<Char, N> parts;
|
||||||
|
unsigned counter = 0;
|
||||||
|
// This is not a lambda for compatibility with older compilers.
|
||||||
|
struct {
|
||||||
|
format_part<Char>* parts;
|
||||||
|
unsigned* counter;
|
||||||
|
FMT_CONSTEXPR void operator()(const format_part<Char>& part) {
|
||||||
|
parts[(*counter)++] = part;
|
||||||
|
}
|
||||||
|
} collector{parts.data, &counter};
|
||||||
|
compile_format_string<true>(format_str, collector);
|
||||||
|
if (counter < N) {
|
||||||
|
parts.data[counter] =
|
||||||
|
format_part<Char>::make_text(basic_string_view<Char>());
|
||||||
|
}
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> constexpr const T& constexpr_max(const T& a, const T& b) {
|
||||||
|
return (a < b) ? b : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
struct compiled_format_base<S, enable_if_t<is_compile_string<S>::value>>
|
||||||
|
: basic_compiled_format {
|
||||||
|
using char_type = char_t<S>;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR explicit compiled_format_base(basic_string_view<char_type>) {}
|
||||||
|
|
||||||
|
// Workaround for old compilers. Format string compilation will not be
|
||||||
|
// performed there anyway.
|
||||||
|
#if FMT_USE_CONSTEXPR
|
||||||
|
static FMT_CONSTEXPR_DECL const unsigned num_format_parts =
|
||||||
|
constexpr_max(count_parts(to_string_view(S())), 1u);
|
||||||
|
#else
|
||||||
|
static const unsigned num_format_parts = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using parts_container = format_part<char_type>[num_format_parts];
|
||||||
|
|
||||||
|
const parts_container& parts() const {
|
||||||
|
static FMT_CONSTEXPR_DECL const auto compiled_parts =
|
||||||
|
compile_to_parts<char_type, num_format_parts>(
|
||||||
|
internal::to_string_view(S()));
|
||||||
|
return compiled_parts.data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename S, typename... Args>
|
||||||
|
class compiled_format : private compiled_format_base<S> {
|
||||||
|
public:
|
||||||
|
using typename compiled_format_base<S>::char_type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
basic_string_view<char_type> format_str_;
|
||||||
|
|
||||||
|
template <typename Context, typename Range, typename CompiledFormat>
|
||||||
|
friend auto cf::vformat_to(Range out, CompiledFormat& cf,
|
||||||
|
basic_format_args<Context> args) ->
|
||||||
|
typename Context::iterator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
compiled_format() = delete;
|
||||||
|
explicit constexpr compiled_format(basic_string_view<char_type> format_str)
|
||||||
|
: compiled_format_base<S>(format_str), format_str_(format_str) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cpp_if_constexpr
|
||||||
|
template <typename... Args> struct type_list {};
|
||||||
|
|
||||||
|
// Returns a reference to the argument at index N from [first, rest...].
|
||||||
|
template <int N, typename T, typename... Args>
|
||||||
|
constexpr const auto& get(const T& first, const Args&... rest) {
|
||||||
|
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
|
||||||
|
if constexpr (N == 0)
|
||||||
|
return first;
|
||||||
|
else
|
||||||
|
return get<N - 1>(rest...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N, typename> struct get_type_impl;
|
||||||
|
|
||||||
|
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
||||||
|
using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <int N, typename T>
|
||||||
|
using get_type = typename get_type_impl<N, T>::type;
|
||||||
|
|
||||||
|
template <typename Char> struct text {
|
||||||
|
basic_string_view<Char> data;
|
||||||
|
using char_type = Char;
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
OutputIt format(OutputIt out, const Args&...) const {
|
||||||
|
// TODO: reserve
|
||||||
|
return copy_str<Char>(data.begin(), data.end(), out);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
|
||||||
|
size_t size) {
|
||||||
|
return {{&s[pos], size}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename OutputIt, typename T,
|
||||||
|
std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
||||||
|
OutputIt format_default(OutputIt out, T value) {
|
||||||
|
// TODO: reserve
|
||||||
|
format_int fi(value);
|
||||||
|
return std::copy(fi.data(), fi.data() + fi.size(), out);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename OutputIt>
|
||||||
|
OutputIt format_default(OutputIt out, double value) {
|
||||||
|
writer w(out);
|
||||||
|
w.write(value);
|
||||||
|
return w.out();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename OutputIt>
|
||||||
|
OutputIt format_default(OutputIt out, Char value) {
|
||||||
|
*out++ = value;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename OutputIt>
|
||||||
|
OutputIt format_default(OutputIt out, const Char* value) {
|
||||||
|
auto length = std::char_traits<Char>::length(value);
|
||||||
|
return copy_str<Char>(value, value + length, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A replacement field that refers to argument N.
|
||||||
|
template <typename Char, typename T, int N> struct field {
|
||||||
|
using char_type = Char;
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
|
// This ensures that the argument type is convertile to `const T&`.
|
||||||
|
const T& arg = get<N>(args...);
|
||||||
|
return format_default<Char>(out, arg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename L, typename R> struct concat {
|
||||||
|
L lhs;
|
||||||
|
R rhs;
|
||||||
|
using char_type = typename L::char_type;
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
|
out = lhs.format(out, args...);
|
||||||
|
return rhs.format(out, args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename L, typename R>
|
||||||
|
constexpr concat<L, R> make_concat(L lhs, R rhs) {
|
||||||
|
return {lhs, rhs};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct unknown_format {};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
|
||||||
|
for (size_t size = str.size(); pos != size; ++pos) {
|
||||||
|
if (str[pos] == '{' || str[pos] == '}') break;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Args, size_t POS, int ID, typename S>
|
||||||
|
constexpr auto compile_format_string(S format_str);
|
||||||
|
|
||||||
|
template <typename Args, size_t POS, int ID, typename T, typename S>
|
||||||
|
constexpr auto parse_tail(T head, S format_str) {
|
||||||
|
if constexpr (POS != to_string_view(format_str).size()) {
|
||||||
|
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
|
||||||
|
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
|
||||||
|
unknown_format>())
|
||||||
|
return tail;
|
||||||
|
else
|
||||||
|
return make_concat(head, tail);
|
||||||
|
} else {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiles a non-empty format string and returns the compiled representation
|
||||||
|
// or unknown_format() on unrecognized input.
|
||||||
|
template <typename Args, size_t POS, int ID, typename S>
|
||||||
|
constexpr auto compile_format_string(S format_str) {
|
||||||
|
using char_type = typename S::char_type;
|
||||||
|
constexpr basic_string_view<char_type> str = format_str;
|
||||||
|
if constexpr (str[POS] == '{') {
|
||||||
|
if (POS + 1 == str.size())
|
||||||
|
throw format_error("unmatched '{' in format string");
|
||||||
|
if constexpr (str[POS + 1] == '{') {
|
||||||
|
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||||
|
} else if constexpr (str[POS + 1] == '}') {
|
||||||
|
using type = get_type<ID, Args>;
|
||||||
|
if constexpr (std::is_same<type, int>::value) {
|
||||||
|
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
|
||||||
|
format_str);
|
||||||
|
} else {
|
||||||
|
return unknown_format();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return unknown_format();
|
||||||
|
}
|
||||||
|
} else if constexpr (str[POS] == '}') {
|
||||||
|
if (POS + 1 == str.size())
|
||||||
|
throw format_error("unmatched '}' in format string");
|
||||||
|
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||||
|
} else {
|
||||||
|
constexpr auto end = parse_text(str, POS + 1);
|
||||||
|
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
|
||||||
|
format_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // __cpp_if_constexpr
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
#if FMT_USE_CONSTEXPR
|
||||||
|
# ifdef __cpp_if_constexpr
|
||||||
|
template <typename... Args, typename S,
|
||||||
|
FMT_ENABLE_IF(is_compile_string<S>::value)>
|
||||||
|
constexpr auto compile(S format_str) {
|
||||||
|
constexpr basic_string_view<typename S::char_type> str = format_str;
|
||||||
|
if constexpr (str.size() == 0) {
|
||||||
|
return internal::make_text(str, 0, 0);
|
||||||
|
} else {
|
||||||
|
constexpr auto result =
|
||||||
|
internal::compile_format_string<internal::type_list<Args...>, 0, 0>(
|
||||||
|
format_str);
|
||||||
|
if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
|
||||||
|
internal::unknown_format>()) {
|
||||||
|
return internal::compiled_format<S, Args...>(to_string_view(format_str));
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CompiledFormat, typename... Args,
|
||||||
|
typename Char = typename CompiledFormat::char_type,
|
||||||
|
FMT_ENABLE_IF(!std::is_base_of<internal::basic_compiled_format,
|
||||||
|
CompiledFormat>::value)>
|
||||||
|
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
cf.format(std::back_inserter(buffer), args...);
|
||||||
|
return to_string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
|
FMT_ENABLE_IF(!std::is_base_of<internal::basic_compiled_format,
|
||||||
|
CompiledFormat>::value)>
|
||||||
|
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||||
|
const Args&... args) {
|
||||||
|
return cf.format(out, args...);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
template <typename... Args, typename S,
|
||||||
|
FMT_ENABLE_IF(is_compile_string<S>::value)>
|
||||||
|
constexpr auto compile(S format_str) -> internal::compiled_format<S, Args...> {
|
||||||
|
return internal::compiled_format<S, Args...>(to_string_view(format_str));
|
||||||
|
}
|
||||||
|
# endif // __cpp_if_constexpr
|
||||||
|
#endif // FMT_USE_CONSTEXPR
|
||||||
|
|
||||||
|
// Compiles the format string which must be a string literal.
|
||||||
|
template <typename... Args, typename Char, size_t N>
|
||||||
|
auto compile(const Char (&format_str)[N])
|
||||||
|
-> internal::compiled_format<const Char*, Args...> {
|
||||||
|
return internal::compiled_format<const Char*, Args...>(
|
||||||
|
basic_string_view<Char>(format_str, N - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CompiledFormat, typename... Args,
|
||||||
|
typename Char = typename CompiledFormat::char_type,
|
||||||
|
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
|
||||||
|
CompiledFormat>::value)>
|
||||||
|
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
using range = buffer_range<Char>;
|
||||||
|
using context = buffer_context<Char>;
|
||||||
|
internal::cf::vformat_to<context>(range(buffer), cf,
|
||||||
|
{make_format_args<context>(args...)});
|
||||||
|
return to_string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
|
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
|
||||||
|
CompiledFormat>::value)>
|
||||||
|
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||||
|
const Args&... args) {
|
||||||
|
using char_type = typename CompiledFormat::char_type;
|
||||||
|
using range = internal::output_range<OutputIt, char_type>;
|
||||||
|
using context = format_context_t<OutputIt, char_type>;
|
||||||
|
return internal::cf::vformat_to<context>(
|
||||||
|
range(out), cf, {make_format_args<context>(args...)});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
|
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
|
||||||
|
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
||||||
|
const CompiledFormat& cf,
|
||||||
|
const Args&... args) {
|
||||||
|
auto it =
|
||||||
|
format_to(internal::truncating_iterator<OutputIt>(out, n), cf, args...);
|
||||||
|
return {it.base(), it.count()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CompiledFormat, typename... Args>
|
||||||
|
std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
|
||||||
|
return format_to(internal::counting_iterator(), cf, args...).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_COMPILE_H_
|
||||||
1519
ext/fmt-6.1.2/include/fmt/core.h
Normal file
1519
ext/fmt-6.1.2/include/fmt/core.h
Normal file
File diff suppressed because it is too large
Load diff
1396
ext/fmt-6.1.2/include/fmt/format-inl.h
Normal file
1396
ext/fmt-6.1.2/include/fmt/format-inl.h
Normal file
File diff suppressed because it is too large
Load diff
3541
ext/fmt-6.1.2/include/fmt/format.h
Normal file
3541
ext/fmt-6.1.2/include/fmt/format.h
Normal file
File diff suppressed because it is too large
Load diff
77
ext/fmt-6.1.2/include/fmt/locale.h
Normal file
77
ext/fmt-6.1.2/include/fmt/locale.h
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Formatting library for C++ - std::locale support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_LOCALE_H_
|
||||||
|
#define FMT_LOCALE_H_
|
||||||
|
|
||||||
|
#include <locale>
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
template <typename Char>
|
||||||
|
typename buffer_context<Char>::iterator vformat_to(
|
||||||
|
const std::locale& loc, buffer<Char>& buf,
|
||||||
|
basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
|
using range = buffer_range<Char>;
|
||||||
|
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
|
||||||
|
internal::locale_ref(loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
std::basic_string<Char> vformat(const std::locale& loc,
|
||||||
|
basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
internal::vformat_to(loc, buffer, format_str, args);
|
||||||
|
return fmt::to_string(buffer);
|
||||||
|
}
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename S, typename Char = char_t<S>>
|
||||||
|
inline std::basic_string<Char> vformat(
|
||||||
|
const std::locale& loc, const S& format_str,
|
||||||
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
|
return internal::vformat(loc, to_string_view(format_str), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||||
|
inline std::basic_string<Char> format(const std::locale& loc,
|
||||||
|
const S& format_str, Args&&... args) {
|
||||||
|
return internal::vformat(
|
||||||
|
loc, to_string_view(format_str),
|
||||||
|
{internal::make_args_checked<Args...>(format_str, args...)});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename OutputIt, typename... Args,
|
||||||
|
typename Char = enable_if_t<
|
||||||
|
internal::is_output_iterator<OutputIt>::value, char_t<S>>>
|
||||||
|
inline OutputIt vformat_to(OutputIt out, const std::locale& loc,
|
||||||
|
const S& format_str,
|
||||||
|
format_args_t<OutputIt, Char> args) {
|
||||||
|
using range = internal::output_range<OutputIt, Char>;
|
||||||
|
return vformat_to<arg_formatter<range>>(
|
||||||
|
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
|
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value&&
|
||||||
|
internal::is_string<S>::value)>
|
||||||
|
inline OutputIt format_to(OutputIt out, const std::locale& loc,
|
||||||
|
const S& format_str, Args&&... args) {
|
||||||
|
internal::check_format_string<Args...>(format_str);
|
||||||
|
using context = format_context_t<OutputIt, char_t<S>>;
|
||||||
|
format_arg_store<context, Args...> as{args...};
|
||||||
|
return vformat_to(out, loc, to_string_view(format_str),
|
||||||
|
basic_format_args<context>(as));
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_LOCALE_H_
|
||||||
141
ext/fmt-6.1.2/include/fmt/ostream.h
Normal file
141
ext/fmt-6.1.2/include/fmt/ostream.h
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
// Formatting library for C++ - std::ostream support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_OSTREAM_H_
|
||||||
|
#define FMT_OSTREAM_H_
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
||||||
|
private:
|
||||||
|
using int_type = typename std::basic_streambuf<Char>::int_type;
|
||||||
|
using traits_type = typename std::basic_streambuf<Char>::traits_type;
|
||||||
|
|
||||||
|
buffer<Char>& buffer_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
formatbuf(buffer<Char>& buf) : buffer_(buf) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// The put-area is actually always empty. This makes the implementation
|
||||||
|
// simpler and has the advantage that the streambuf and the buffer are always
|
||||||
|
// in sync and sputc never writes into uninitialized memory. The obvious
|
||||||
|
// disadvantage is that each call to sputc always results in a (virtual) call
|
||||||
|
// to overflow. There is no disadvantage here for sputn since this always
|
||||||
|
// results in a call to xsputn.
|
||||||
|
|
||||||
|
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
|
||||||
|
if (!traits_type::eq_int_type(ch, traits_type::eof()))
|
||||||
|
buffer_.push_back(static_cast<Char>(ch));
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
|
||||||
|
buffer_.append(s, s + count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
||||||
|
private:
|
||||||
|
// Hide all operator<< from std::basic_ostream<Char>.
|
||||||
|
void_t<> operator<<(null<>);
|
||||||
|
void_t<> operator<<(const Char*);
|
||||||
|
|
||||||
|
template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value &&
|
||||||
|
!std::is_enum<T>::value)>
|
||||||
|
void_t<> operator<<(T);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Checks if T has a user-defined operator<< (e.g. not a member of
|
||||||
|
// std::ostream).
|
||||||
|
template <typename T, typename Char> class is_streamable {
|
||||||
|
private:
|
||||||
|
template <typename U>
|
||||||
|
static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
|
||||||
|
<< std::declval<U>()),
|
||||||
|
void_t<>>::value>
|
||||||
|
test(int);
|
||||||
|
|
||||||
|
template <typename> static std::false_type test(...);
|
||||||
|
|
||||||
|
using result = decltype(test<T>(0));
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const bool value = result::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write the content of buf to os.
|
||||||
|
template <typename Char>
|
||||||
|
void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||||
|
const Char* buf_data = buf.data();
|
||||||
|
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
||||||
|
unsigned_streamsize size = buf.size();
|
||||||
|
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
|
||||||
|
do {
|
||||||
|
unsigned_streamsize n = size <= max_size ? size : max_size;
|
||||||
|
os.write(buf_data, static_cast<std::streamsize>(n));
|
||||||
|
buf_data += n;
|
||||||
|
size -= n;
|
||||||
|
} while (size != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename T>
|
||||||
|
void format_value(buffer<Char>& buf, const T& value,
|
||||||
|
locale_ref loc = locale_ref()) {
|
||||||
|
formatbuf<Char> format_buf(buf);
|
||||||
|
std::basic_ostream<Char> output(&format_buf);
|
||||||
|
if (loc) output.imbue(loc.get<std::locale>());
|
||||||
|
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
|
output << value;
|
||||||
|
buf.resize(buf.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
||||||
|
: formatter<basic_string_view<Char>, Char> {
|
||||||
|
template <typename Context>
|
||||||
|
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
format_value(buffer, value, ctx.locale());
|
||||||
|
basic_string_view<Char> str(buffer.data(), buffer.size());
|
||||||
|
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
internal::vformat_to(buffer, format_str, args);
|
||||||
|
internal::write(os, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Prints formatted data to the stream *os*.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::print(cerr, "Don't {}!", "panic");
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename S, typename... Args,
|
||||||
|
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
|
||||||
|
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
||||||
|
vprint(os, to_string_view(format_str),
|
||||||
|
{internal::make_args_checked<Args...>(format_str, args...)});
|
||||||
|
}
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_OSTREAM_H_
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue