diff --git a/.dockerignore b/.dockerignore index ccb9344..184f027 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,8 +2,7 @@ .github .idea *.sublime-workspace -server/obj -server/sergate +server/serverstatus web/json/stats.json web/json/stats.json~ *.bak-* diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 548cbcd..2a772ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,22 +10,31 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install build dependencies - run: sudo apt-get update && sudo apt-get install -y gcc g++ make libcurl4-openssl-dev python3 + - uses: actions/setup-go@v6 + with: + go-version-file: server/go.mod + cache-dependency-path: server/go.sum - - name: Build server - run: make -C server -j2 - - - name: Check scripts + - name: Test Go server + working-directory: server run: | - python3 -m py_compile server/manage_api.py clients/client-linux.py clients/client-psutil.py plugin/bot-telegram.py - sh -n server/entrypoint-server.sh clients/entrypoint.sh status.sh + test -z "$(gofmt -l .)" + go vet ./... + go test -race ./... + CGO_ENABLED=0 go build -trimpath -o /tmp/serverstatus . + + - name: Check clients, plugins, WebUI and shell scripts + run: | + python3 -m py_compile clients/client-linux.py clients/client-psutil.py plugin/bot-telegram.py + sh -n clients/entrypoint.sh + bash -n status.sh node --check web/js/app.js - name: Validate compose files run: | docker compose -f docker-compose-server.yml config docker compose -f docker-compose-client.yml config + TG_CHAT_ID=test TG_BOT_TOKEN=test ADMIN_TOKEN=test docker compose -f plugin/docker-compose-telegram.yml config - name: Build Docker images run: | diff --git a/Dockerfile.client b/Dockerfile.client index e156121..16f577e 100644 --- a/Dockerfile.client +++ b/Dockerfile.client @@ -13,7 +13,6 @@ COPY clients/entrypoint.sh /app/entrypoint.sh ENV SERVER=127.0.0.1 \ USER=s01 \ PORT=35601 \ - PASSWORD=USER_DEFAULT_PASSWORD \ INTERVAL=1 \ PROBEPORT=80 \ PROBE_PROTOCOL_PREFER=ipv4 \ diff --git a/Dockerfile.server b/Dockerfile.server index b9a384f..0be4b77 100644 --- a/Dockerfile.server +++ b/Dockerfile.server @@ -1,42 +1,42 @@ -FROM python:3.12-slim-bookworm AS builder +FROM golang:1.25-alpine AS builder + +WORKDIR /src/server + +COPY server/go.mod server/go.sum ./ +RUN go mod download + +COPY server/*.go ./ + +ARG VERSION=2.0.0 +ARG COMMIT=none +ARG BUILD_TIME=unknown + +RUN CGO_ENABLED=0 GOOS=linux go build \ + -trimpath \ + -ldflags="-s -w -X main.version=${VERSION} -X main.commit=${COMMIT} -X main.buildTime=${BUILD_TIME}" \ + -o /out/serverstatus . + +FROM alpine:3.22 LABEL maintainer="cppla " -RUN sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources \ - && apt-get -o Acquire::Retries=3 update -y \ - && apt-get install -y --no-install-recommends gcc g++ make libcurl4-openssl-dev ca-certificates \ - && rm -rf /var/lib/apt/lists/* +RUN apk add --no-cache ca-certificates tzdata \ + && mkdir -p /app/config /app/data /app/web -COPY server/ /server/ +COPY --from=builder /out/serverstatus /usr/local/bin/serverstatus +COPY server/config.json /app/config/config.json +COPY web /app/web/ -WORKDIR /server - -RUN make -j && strip /server/sergate - -FROM debian:bookworm-slim - -COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt -RUN sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources \ - && apt-get -o Acquire::Retries=3 update -y \ - && apt-get install -y --no-install-recommends nginx-light python3 openssl libcurl4 libstdc++6 tzdata \ - && rm -rf /var/lib/apt/lists/* \ - && mkdir -p /ServerStatus/server/ \ - && ln -sf /dev/null /var/log/nginx/access.log \ - && ln -sf /dev/null /var/log/nginx/error.log \ - && rm -f /etc/nginx/sites-enabled/default - -COPY --from=builder /server/sergate /ServerStatus/server/sergate -COPY server/config.json /ServerStatus/server/config.json -COPY server/manage_api.py /ServerStatus/server/manage_api.py -COPY server/entrypoint-server.sh /ServerStatus/server/entrypoint-server.sh -COPY web /usr/share/nginx/html/ -COPY server/nginx-serverstatus.conf /etc/nginx/conf.d/default.conf - -RUN chmod +x /ServerStatus/server/entrypoint-server.sh - -ENV TZ=Asia/Shanghai -RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +ENV TZ=Asia/Shanghai \ + CONFIG_PATH=/app/config/config.json \ + STATS_PATH=/app/data/stats.json \ + WEB_DIR=/app/web \ + HTTP_ADDR=:80 \ + AGENT_ADDR=:35601 EXPOSE 80 35601 -HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD python3 -c "import os,urllib.request; pid=int(open('/tmp/serverstatus-sergate.pid').read().strip()); os.kill(pid,0); urllib.request.urlopen('http://127.0.0.1/',timeout=2).read(1)" -CMD ["/ServerStatus/server/entrypoint-server.sh"] + +HEALTHCHECK --interval=10s --timeout=3s --retries=3 \ + CMD wget -q -O /dev/null http://127.0.0.1/api/health || exit 1 + +ENTRYPOINT ["/usr/local/bin/serverstatus"] diff --git a/docker-compose-server.yml b/docker-compose-server.yml index 18e03a5..a2116ce 100644 --- a/docker-compose-server.yml +++ b/docker-compose-server.yml @@ -5,7 +5,7 @@ services: dockerfile: Dockerfile.server image: cppla/serverstatus:server healthcheck: - test: ["CMD-SHELL", "python3 -c \"import os,urllib.request; pid=int(open('/tmp/serverstatus-sergate.pid').read().strip()); os.kill(pid,0); urllib.request.urlopen('http://127.0.0.1/',timeout=2).read(1)\""] + test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/api/health"] interval: 30s timeout: 10s retries: 5 @@ -13,12 +13,14 @@ services: restart: unless-stopped environment: ADMIN_TOKEN: "${ADMIN_TOKEN:-}" + HTTP_ADDR: ":80" + AGENT_ADDR: ":35601" networks: serverstatus-network: ipv4_address: 172.23.0.2 volumes: - - ./server/config.json:/ServerStatus/server/config.json - - ./web/json:/usr/share/nginx/html/json + - ./server/config.json:/app/config/config.json + - ./web/json:/app/data ports: - 35601:35601 - 8080:80 diff --git a/plugin/docker-compose-telegram.yml b/plugin/docker-compose-telegram.yml index adbe5a7..faee779 100644 --- a/plugin/docker-compose-telegram.yml +++ b/plugin/docker-compose-telegram.yml @@ -1,21 +1,29 @@ -version: "3" services: serverstatus: build: context: .. - dockerfile: Dockerfile - image: serverstatus_server + dockerfile: Dockerfile.server + image: cppla/serverstatus:server container_name: serverstatus restart: unless-stopped + environment: + ADMIN_TOKEN: "${ADMIN_TOKEN:-}" + HTTP_ADDR: ":80" + AGENT_ADDR: ":35601" + healthcheck: + test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/api/health"] + interval: 30s + timeout: 10s + retries: 5 networks: serverstatus-network: ipv4_address: 172.23.0.2 volumes: - - ../server/config.json:/ServerStatus/server/config.json - - ../web/json:/usr/share/nginx/html/json + - ../server/config.json:/app/config/config.json + - ../web/json:/app/data ports: - - 35601:35601 - - 8080:80 + - "35601:35601" + - "8080:80" bot: build: context: . @@ -23,6 +31,9 @@ services: image: serverstatus_bot container_name: bot4sss restart: unless-stopped + depends_on: + serverstatus: + condition: service_healthy networks: serverstatus-network: ipv4_address: 172.23.0.3 diff --git a/server/.gitignore b/server/.gitignore index 6d7633f..3bc7325 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -1,2 +1,4 @@ -sergate +serverstatus +*.test +coverage.out .tags* diff --git a/server/Makefile b/server/Makefile deleted file mode 100644 index dddaedc..0000000 --- a/server/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -OUT = sergate -.DEFAULT_GOAL := $(OUT) - -#CC = clang -CC = gcc -CFLAGS = -Wall -O2 - -#CXX = clang++ -CXX = g++ -CXXFLAGS = -Wall -O2 -std=c++11 - -ODIR = obj -SDIR = src -LIBS = -pthread -lm -INC = -Iinclude - -C_SRCS := $(wildcard $(SDIR)/*.c) -CXX_SRCS := $(wildcard $(SDIR)/*.cpp) -C_OBJS := $(patsubst $(SDIR)/%.c,$(ODIR)/%.o,$(C_SRCS)) -CXX_OBJS := $(patsubst $(SDIR)/%.cpp,$(ODIR)/%.o,$(CXX_SRCS)) -OBJS := $(C_OBJS) $(CXX_OBJS) - -$(ODIR): - mkdir -p $(ODIR) - -$(ODIR)/%.o: $(SDIR)/%.c | $(ODIR) - $(CC) -c $(INC) $(CFLAGS) $< -o $@ - -$(ODIR)/%.o: $(SDIR)/%.cpp | $(ODIR) - $(CXX) -c $(INC) $(CXXFLAGS) $< -o $@ - -$(OUT): $(OBJS) - $(CXX) $(LIBS) $^ -o $(OUT) -lcurl - -.PHONY: clean - -clean: - rm -f $(ODIR)/*.o $(OUT) diff --git a/server/app.go b/server/app.go new file mode 100644 index 0000000..b29dd54 --- /dev/null +++ b/server/app.go @@ -0,0 +1,472 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "log" + "math" + "net" + "os" + "strconv" + "sync" + "sync/atomic" + "time" +) + +type Options struct { + ConfigPath string + StatsPath string + WebDir string + HTTPAddr string + AgentAddr string + AdminToken string + CORSOrigin string + InsecureCallbackTLS bool + Verbose bool +} + +type NodeState struct { + Config ServerConfig + Connected bool + Connection net.Conn + ConnectionID uint64 + Family int + Online4 bool + Online6 bool + Stats AgentStats + HasUpdate bool + LastNetworkIn int64 + LastNetworkOut int64 + LastUpdate time.Time + AlarmLast map[string]time.Time + Pong bool +} + +type App struct { + opts Options + startedAt time.Time + ctx context.Context + cancel context.CancelFunc + + mutationMu sync.Mutex + configMu sync.RWMutex + document ConfigDocument + runtime RuntimeConfig + + nodeMu sync.RWMutex + nodes map[string]*NodeState + connectionID atomic.Uint64 + generation atomic.Uint64 + agentRunning atomic.Bool + reloadWrites atomic.Int32 + + certMu sync.RWMutex + certs map[string]*CertState + + statsWake chan struct{} + persistMu sync.Mutex + logger *log.Logger +} + +func NewApp(opts Options) (*App, error) { + doc, runtime, err := readConfig(opts.ConfigPath) + if err != nil { + return nil, err + } + ctx, cancel := context.WithCancel(context.Background()) + app := &App{ + opts: opts, + startedAt: time.Now(), + ctx: ctx, + cancel: cancel, + nodes: make(map[string]*NodeState), + certs: make(map[string]*CertState), + statsWake: make(chan struct{}, 1), + logger: log.New(os.Stdout, "serverstatus ", log.LstdFlags|log.Lmicroseconds), + } + app.applyValidatedConfig(doc, runtime, false) + app.restorePersistentState() + return app, nil +} + +func (a *App) StartBackground() { + go a.statsLoop() + go a.sslLoop() + a.wakeStatsWriter() +} + +func (a *App) Close() { + a.cancel() + a.disconnectAll("Server shutting down...") + _ = a.PersistStats() +} + +func (a *App) ConfigSnapshot() ConfigDocument { + a.configMu.RLock() + defer a.configMu.RUnlock() + clone, err := cloneDocument(a.document) + if err != nil { + panic(err) + } + return clone +} + +func (a *App) RuntimeSnapshot() RuntimeConfig { + a.configMu.RLock() + defer a.configMu.RUnlock() + result := a.runtime + result.Servers = append([]ServerConfig(nil), a.runtime.Servers...) + result.Monitors = append([]MonitorConfig(nil), a.runtime.Monitors...) + result.SSLCerts = append([]SSLCertConfig(nil), a.runtime.SSLCerts...) + result.Watchdogs = append([]CompiledWatchdog(nil), a.runtime.Watchdogs...) + return result +} + +func (a *App) ReplaceConfig(input ConfigDocument) (ConfigDocument, *APIError) { + a.mutationMu.Lock() + defer a.mutationMu.Unlock() + normalized, runtime, apiErr := normalizeConfig(input) + if apiErr != nil { + return nil, apiErr + } + if err := writeConfig(a.opts.ConfigPath, normalized); err != nil { + return nil, &APIError{Status: 500, Message: "config could not be written", Details: map[string]any{"error": err.Error()}} + } + a.applyValidatedConfig(normalized, runtime, true) + return a.ConfigSnapshot(), nil +} + +func (a *App) MutateConfig(mutate func(ConfigDocument) *APIError) (ConfigDocument, *APIError) { + a.mutationMu.Lock() + defer a.mutationMu.Unlock() + doc := a.ConfigSnapshot() + if apiErr := mutate(doc); apiErr != nil { + return nil, apiErr + } + normalized, runtime, apiErr := normalizeConfig(doc) + if apiErr != nil { + return nil, apiErr + } + if err := writeConfig(a.opts.ConfigPath, normalized); err != nil { + return nil, &APIError{Status: 500, Message: "config could not be written", Details: map[string]any{"error": err.Error()}} + } + a.applyValidatedConfig(normalized, runtime, true) + return a.ConfigSnapshot(), nil +} + +func (a *App) ReloadConfig() *APIError { + a.mutationMu.Lock() + defer a.mutationMu.Unlock() + doc, runtime, err := readConfig(a.opts.ConfigPath) + if err != nil { + if apiErr, ok := err.(*APIError); ok { + return apiErr + } + return &APIError{Status: 500, Message: "config could not be reloaded", Details: map[string]any{"error": err.Error()}} + } + a.applyValidatedConfig(doc, runtime, true) + return nil +} + +func (a *App) applyValidatedConfig(doc ConfigDocument, runtime RuntimeConfig, disconnect bool) { + a.configMu.Lock() + a.nodeMu.Lock() + oldNodes := a.nodes + newNodes := make(map[string]*NodeState, len(runtime.Servers)) + connections := make([]net.Conn, 0) + for _, server := range runtime.Servers { + node := &NodeState{Config: server, AlarmLast: make(map[string]time.Time)} + if old := oldNodes[server.Username]; old != nil && sameServerIdentity(old.Config, server) { + node.LastNetworkIn = old.LastNetworkIn + node.LastNetworkOut = old.LastNetworkOut + node.Stats = old.Stats + node.HasUpdate = old.HasUpdate + node.AlarmLast = old.AlarmLast + if !disconnect { + node.Connected = old.Connected + node.Connection = old.Connection + node.ConnectionID = old.ConnectionID + node.Family = old.Family + node.Online4 = old.Online4 + node.Online6 = old.Online6 + } + } + newNodes[server.Username] = node + } + if disconnect { + for _, node := range oldNodes { + if node.Connection != nil { + connections = append(connections, node.Connection) + } + } + } + a.document = doc + a.runtime = runtime + a.nodes = newNodes + a.generation.Add(1) + a.nodeMu.Unlock() + a.configMu.Unlock() + + a.reconcileCerts(runtime.SSLCerts) + if disconnect { + for _, conn := range connections { + _, _ = conn.Write([]byte("Server reloading...\n")) + _ = conn.Close() + } + } + a.reloadWrites.Store(2) + a.wakeStatsWriter() +} + +func sameServerIdentity(left, right ServerConfig) bool { + return left.Username == right.Username && left.Name == right.Name && left.Type == right.Type && left.Host == right.Host && left.Location == right.Location +} + +func (a *App) disconnectAll(reason string) { + a.nodeMu.Lock() + connections := make([]net.Conn, 0) + for _, node := range a.nodes { + if node.Connection != nil { + connections = append(connections, node.Connection) + node.Connection = nil + node.Connected = false + node.Online4 = false + node.Online6 = false + } + } + a.nodeMu.Unlock() + for _, conn := range connections { + if reason != "" { + _, _ = conn.Write([]byte(reason + "\n")) + } + _ = conn.Close() + } +} + +func (a *App) statsLoop() { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + for { + select { + case <-a.ctx.Done(): + return + case <-ticker.C: + case <-a.statsWake: + } + if err := a.PersistStats(); err != nil { + a.logger.Printf("write stats: %v", err) + } + } +} + +func (a *App) wakeStatsWriter() { + select { + case a.statsWake <- struct{}{}: + default: + } +} + +func (a *App) SnapshotStats() map[string]any { + return a.snapshotStats(false) +} + +func (a *App) snapshotStats(consumeReload bool) map[string]any { + runtime := a.RuntimeSnapshot() + now := time.Now() + servers := make([]any, 0, len(runtime.Servers)) + a.nodeMu.Lock() + for _, server := range runtime.Servers { + if server.Disabled { + continue + } + node := a.nodes[server.Username] + if node == nil { + continue + } + base := map[string]any{ + "name": server.Name, "type": server.Type, "host": server.Host, "location": server.Location, + "online4": false, "online6": false, + } + if node.Connected && node.HasUpdate { + s := node.Stats + updateTrafficBaselines(node, s.NetworkIn, s.NetworkOut, monthResetWindow(now, server.MonthStart)) + base["online4"] = node.Online4 + base["online6"] = node.Online6 + base["uptime"] = formatUptime(s.Uptime) + base["load_1"], base["load_5"], base["load_15"] = round2(s.Load1), round2(s.Load5), round2(s.Load15) + base["ping_10010"], base["ping_189"], base["ping_10086"] = round2(s.Ping10010), round2(s.Ping189), round2(s.Ping10086) + base["time_10010"], base["time_189"], base["time_10086"] = s.Time10010, s.Time189, s.Time10086 + base["tcp_count"], base["udp_count"] = s.TCPCount, s.UDPCount + base["process_count"], base["thread_count"] = s.ProcessCount, s.ThreadCount + base["network_rx"], base["network_tx"] = s.NetworkRX, s.NetworkTX + base["network_in"], base["network_out"] = s.NetworkIn, s.NetworkOut + base["cpu"], base["cpu_cores"], base["cpu_model"] = int(s.CPU), s.CPUCores, s.CPUModel + base["memory_total"], base["memory_used"] = s.MemoryTotal, s.MemoryUsed + base["swap_total"], base["swap_used"] = s.SwapTotal, s.SwapUsed + base["hdd_total"], base["hdd_used"] = s.HDDTotal, s.HDDUsed + base["last_network_in"] = trafficBaseline(s.NetworkIn, node.LastNetworkIn) + base["last_network_out"] = trafficBaseline(s.NetworkOut, node.LastNetworkOut) + base["io_read"], base["io_write"] = s.IORead, s.IOWrite + base["custom"], base["os"] = s.Custom, s.OS + } else { + base["last_network_in"] = node.LastNetworkIn + base["last_network_out"] = node.LastNetworkOut + base["os"] = node.Stats.OS + base["cpu_model"] = node.Stats.CPUModel + } + servers = append(servers, base) + } + a.nodeMu.Unlock() + + result := map[string]any{ + "servers": servers, + "sslcerts": a.sslSnapshot(runtime.SSLCerts, now), + "updated": strconv.FormatInt(now.Unix(), 10), + } + if a.reloadWrites.Load() > 0 { + result["reload"] = true + if consumeReload { + a.reloadWrites.Add(-1) + } + } + return result +} + +func (a *App) PersistStats() error { + a.persistMu.Lock() + defer a.persistMu.Unlock() + return writeStatsFile(a.opts.StatsPath, a.snapshotStats(true)) +} + +func monthResetWindow(now time.Time, monthStart int) bool { + return now.Day() == clamp(monthStart, 1, 28) && now.Hour() == 0 && now.Minute() < 5 +} + +func trafficBaseline(current, baseline int64) int64 { + if current == 0 || baseline == 0 { + return current + } + return baseline +} + +func updateTrafficBaselines(node *NodeState, currentIn, currentOut int64, reset bool) { + if reset { + node.LastNetworkIn = currentIn + node.LastNetworkOut = currentOut + return + } + if node.LastNetworkIn == 0 || (currentIn != 0 && node.LastNetworkIn > currentIn) { + node.LastNetworkIn = currentIn + } + if node.LastNetworkOut == 0 || (currentOut != 0 && node.LastNetworkOut > currentOut) { + node.LastNetworkOut = currentOut + } +} + +func round2(value float64) float64 { + return math.Round(value*100) / 100 +} + +func formatUptime(seconds int64) string { + days := seconds / 86400 + if days > 0 { + return fmt.Sprintf("%d 天", days) + } + return fmt.Sprintf("%02d:%02d:%02d", seconds/3600, (seconds/60)%60, seconds%60) +} + +func (a *App) restorePersistentState() { + data, err := os.ReadFile(a.opts.StatsPath) + if err != nil { + data, err = os.ReadFile(a.opts.StatsPath + "~") + } + if err != nil { + return + } + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.UseNumber() + var previous struct { + Servers []map[string]any `json:"servers"` + } + if err := decoder.Decode(&previous); err != nil { + a.logger.Printf("read previous stats: %v", err) + return + } + a.nodeMu.Lock() + defer a.nodeMu.Unlock() + for _, node := range a.nodes { + for _, saved := range previous.Servers { + if fmt.Sprint(saved["name"]) != node.Config.Name || fmt.Sprint(saved["type"]) != node.Config.Type || fmt.Sprint(saved["host"]) != node.Config.Host || fmt.Sprint(saved["location"]) != node.Config.Location { + continue + } + node.LastNetworkIn = anyInt64(saved["last_network_in"]) + node.LastNetworkOut = anyInt64(saved["last_network_out"]) + node.Stats.OS = anyString(saved["os"]) + node.Stats.CPUModel = anyString(saved["cpu_model"]) + break + } + } +} + +func anyString(value any) string { + if value == nil { + return "" + } + return fmt.Sprint(value) +} + +func anyInt64(value any) int64 { + switch number := value.(type) { + case json.Number: + parsed, _ := number.Int64() + return parsed + case float64: + return int64(number) + case int64: + return number + case int: + return int64(number) + case string: + parsed, _ := strconv.ParseInt(number, 10, 64) + return parsed + default: + return 0 + } +} + +func (a *App) ResetTraffic(username string) (map[string]any, *APIError) { + a.nodeMu.Lock() + node := a.nodes[username] + if node == nil { + a.nodeMu.Unlock() + return nil, &APIError{Status: 404, Message: "server was not found", Details: map[string]any{"username": username}} + } + if !node.Connected || !node.HasUpdate { + a.nodeMu.Unlock() + return nil, &APIError{Status: 409, Message: "server has no current traffic counters; it may be offline", Details: map[string]any{"username": username}} + } + previousIn, previousOut := node.LastNetworkIn, node.LastNetworkOut + networkIn, networkOut := node.Stats.NetworkIn, node.Stats.NetworkOut + node.LastNetworkIn, node.LastNetworkOut = networkIn, networkOut + server := node.Config + a.nodeMu.Unlock() + a.wakeStatsWriter() + return map[string]any{ + "server": server, + "stats": map[string]any{ + "network_in": networkIn, "network_out": networkOut, + "previous_last_network_in": previousIn, "previous_last_network_out": previousOut, + "last_network_in": networkIn, "last_network_out": networkOut, + "month_in_before": max64(0, networkIn-previousIn), "month_out_before": max64(0, networkOut-previousOut), + }, + }, nil +} + +func max64(left, right int64) int64 { + if left > right { + return left + } + return right +} diff --git a/server/app_test.go b/server/app_test.go new file mode 100644 index 0000000..537c7d4 --- /dev/null +++ b/server/app_test.go @@ -0,0 +1,50 @@ +package main + +import ( + "net" + "testing" +) + +func TestTrafficBaselinesResetIndependently(t *testing.T) { + node := &NodeState{LastNetworkIn: 100, LastNetworkOut: 0} + updateTrafficBaselines(node, 150, 500, false) + if node.LastNetworkIn != 100 || node.LastNetworkOut != 500 { + t.Fatalf("missing outbound baseline was not initialized independently: %#v", node) + } + + node.LastNetworkOut = 700 + updateTrafficBaselines(node, 200, 50, false) + if node.LastNetworkIn != 100 || node.LastNetworkOut != 50 { + t.Fatalf("outbound counter reset changed the wrong baseline: %#v", node) + } + + updateTrafficBaselines(node, 900, 800, true) + if node.LastNetworkIn != 900 || node.LastNetworkOut != 800 { + t.Fatalf("monthly reset did not reset both baselines: %#v", node) + } +} + +func TestDisconnectPreservesOfflineDisplayMetadata(t *testing.T) { + app := newTestApp(t, minimalTestConfig()) + client, server := net.Pipe() + defer client.Close() + defer server.Close() + + app.nodeMu.Lock() + node := app.nodes["s01"] + node.Connected = true + node.Connection = server + node.ConnectionID = 42 + node.HasUpdate = true + node.Stats = AgentStats{OS: "linux", CPUModel: "Test CPU"} + app.nodeMu.Unlock() + + app.disconnectAgent("s01", server, 42) + serverStats := app.SnapshotStats()["servers"].([]any)[0].(map[string]any) + if serverStats["online4"] != false || serverStats["online6"] != false { + t.Fatalf("disconnected node remained online: %#v", serverStats) + } + if serverStats["os"] != "linux" || serverStats["cpu_model"] != "Test CPU" { + t.Fatalf("offline display metadata was discarded: %#v", serverStats) + } +} diff --git a/server/entrypoint-server.sh b/server/entrypoint-server.sh deleted file mode 100644 index a49b625..0000000 --- a/server/entrypoint-server.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh -set -eu - -: "${CONFIG_PATH:=/ServerStatus/server/config.json}" -: "${WEB_DIR:=/usr/share/nginx/html}" -: "${SERGATE_PID_FILE:=/tmp/serverstatus-sergate.pid}" -: "${ADMIN_API_BIND:=127.0.0.1}" -: "${ADMIN_API_PORT:=35602}" - -STOPPING=0 -SERGATE_PID="" -API_PID="" - -stop_all() { - STOPPING=1 - if [ -n "$SERGATE_PID" ] && kill -0 "$SERGATE_PID" 2>/dev/null; then - kill -TERM "$SERGATE_PID" 2>/dev/null || true - fi - if [ -n "$API_PID" ] && kill -0 "$API_PID" 2>/dev/null; then - kill -TERM "$API_PID" 2>/dev/null || true - fi - nginx -s quit 2>/dev/null || true -} - -trap 'stop_all; exit 0' INT TERM QUIT - -mkdir -p "$WEB_DIR/json" -nginx - -CONFIG_PATH="$CONFIG_PATH" \ -STATS_PATH="${STATS_PATH:-$WEB_DIR/json/stats.json}" \ -SERGATE_PID_FILE="$SERGATE_PID_FILE" \ -ADMIN_API_BIND="$ADMIN_API_BIND" \ -ADMIN_API_PORT="$ADMIN_API_PORT" \ -ADMIN_TOKEN="${ADMIN_TOKEN:-}" \ -ADMIN_CORS_ORIGIN="${ADMIN_CORS_ORIGIN:-}" \ - python3 /ServerStatus/server/manage_api.py & -API_PID="$!" -if [ -n "${ADMIN_TOKEN:-}" ]; then - echo "management API enabled on ${ADMIN_API_BIND}:${ADMIN_API_PORT}" -else - echo "management API running in read-only discovery mode; set ADMIN_TOKEN to enable writes" -fi - -while [ "$STOPPING" -eq 0 ]; do - /ServerStatus/server/sergate --config="$CONFIG_PATH" --web-dir="$WEB_DIR" & - SERGATE_PID="$!" - echo "$SERGATE_PID" > "$SERGATE_PID_FILE" - set +e - wait "$SERGATE_PID" - STATUS="$?" - set -e - rm -f "$SERGATE_PID_FILE" - if [ "$STOPPING" -eq 1 ]; then - exit "$STATUS" - fi - echo "sergate exited with status ${STATUS}; restarting in 1s" - sleep 1 -done diff --git a/server/fileutil.go b/server/fileutil.go new file mode 100644 index 0000000..1663921 --- /dev/null +++ b/server/fileutil.go @@ -0,0 +1,161 @@ +package main + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "syscall" + "time" +) + +func readConfig(path string) (ConfigDocument, RuntimeConfig, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, RuntimeConfig{}, err + } + doc, err := decodeDocument(data) + if err != nil { + return nil, RuntimeConfig{}, fmt.Errorf("parse %s: %w", path, err) + } + normalized, runtime, apiErr := normalizeConfig(doc) + if apiErr != nil { + return nil, RuntimeConfig{}, apiErr + } + return normalized, runtime, nil +} + +func marshalIndented(value any) ([]byte, error) { + data, err := jsonMarshalIndent(value) + if err != nil { + return nil, err + } + return append(data, '\n'), nil +} + +// jsonMarshalIndent is a variable so file-writing failure paths can be tested. +var jsonMarshalIndent = func(value any) ([]byte, error) { + return json.MarshalIndent(value, "", "\t") +} + +func writeConfig(path string, doc ConfigDocument) error { + data, err := marshalIndented(doc) + if err != nil { + return err + } + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + return err + } + mode := os.FileMode(0o644) + if info, statErr := os.Stat(path); statErr == nil { + mode = info.Mode().Perm() + backup := fmt.Sprintf("%s.bak-%s", path, time.Now().Format("20060102-150405.000000000")) + if err := copyFile(path, backup, mode); err != nil { + return fmt.Errorf("backup config: %w", err) + } + pruneBackups(path, 10) + } else if !errors.Is(statErr, os.ErrNotExist) { + return statErr + } + return atomicWrite(path, data, mode, true) +} + +func writeStatsFile(path string, value any) error { + data, err := marshalIndented(value) + if err != nil { + return err + } + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + return err + } + return atomicWrite(path, data, 0o644, false) +} + +func atomicWrite(path string, data []byte, mode os.FileMode, allowBusyFallback bool) error { + directory := filepath.Dir(path) + tmp, err := os.CreateTemp(directory, ".serverstatus-*.tmp") + if err != nil { + return err + } + tmpPath := tmp.Name() + defer os.Remove(tmpPath) + + if err := tmp.Chmod(mode); err != nil { + tmp.Close() + return err + } + if _, err := tmp.Write(data); err != nil { + tmp.Close() + return err + } + if err := tmp.Sync(); err != nil { + tmp.Close() + return err + } + if err := tmp.Close(); err != nil { + return err + } + if err := os.Rename(tmpPath, path); err == nil { + return syncDirectory(directory) + } else if !allowBusyFallback || !errors.Is(err, syscall.EBUSY) { + return err + } + + // Docker cannot rename over a single-file bind mount. The backup above is + // already durable, so truncate and sync the mounted inode as a fallback. + file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, mode) + if err != nil { + return err + } + if _, err = file.Write(data); err == nil { + err = file.Sync() + } + closeErr := file.Close() + if err != nil { + return err + } + return closeErr +} + +func copyFile(source, destination string, mode os.FileMode) error { + in, err := os.Open(source) + if err != nil { + return err + } + defer in.Close() + out, err := os.OpenFile(destination, os.O_CREATE|os.O_EXCL|os.O_WRONLY, mode) + if err != nil { + return err + } + if _, err = io.Copy(out, in); err == nil { + err = out.Sync() + } + closeErr := out.Close() + if err != nil { + return err + } + return closeErr +} + +func pruneBackups(configPath string, keep int) { + matches, err := filepath.Glob(configPath + ".bak-*") + if err != nil || len(matches) <= keep { + return + } + sort.Strings(matches) + for _, path := range matches[:len(matches)-keep] { + _ = os.Remove(path) + } +} + +func syncDirectory(directory string) error { + dir, err := os.Open(directory) + if err != nil { + return err + } + defer dir.Close() + return dir.Sync() +} diff --git a/server/go.mod b/server/go.mod new file mode 100644 index 0000000..e5519e2 --- /dev/null +++ b/server/go.mod @@ -0,0 +1,40 @@ +module github.com/cppla/serverstatus/server + +go 1.25.0 + +require ( + github.com/expr-lang/expr v1.17.8 + github.com/gin-gonic/gin v1.12.0 +) + +require ( + github.com/bytedance/gopkg v0.1.3 // indirect + github.com/bytedance/sonic v1.15.0 // indirect + github.com/bytedance/sonic/loader v0.5.0 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect + github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.30.1 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/goccy/go-yaml v1.19.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/quic-go/qpack v0.6.0 // indirect + github.com/quic-go/quic-go v0.59.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.3.1 // indirect + go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect + golang.org/x/arch v0.22.0 // indirect + golang.org/x/crypto v0.48.0 // indirect + golang.org/x/net v0.51.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.34.0 // indirect + google.golang.org/protobuf v1.36.10 // indirect +) diff --git a/server/go.sum b/server/go.sum new file mode 100644 index 0000000..35e8252 --- /dev/null +++ b/server/go.sum @@ -0,0 +1,91 @@ +github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= +github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE= +github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k= +github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE= +github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= +github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/expr-lang/expr v1.17.8 h1:W1loDTT+0PQf5YteHSTpju2qfUfNoBt4yw9+wOEU9VM= +github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= +github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8= +github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= +github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= +github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= +github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= +github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= +github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= +github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE= +go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= +golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/server/http_server.go b/server/http_server.go new file mode 100644 index 0000000..29b6f34 --- /dev/null +++ b/server/http_server.go @@ -0,0 +1,397 @@ +package main + +import ( + "crypto/subtle" + "encoding/json" + "errors" + "fmt" + "io" + "mime" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" +) + +var ( + version = "2.0.0" + commit = "none" + buildTime = "unknown" +) + +func (a *App) HTTPServer() *http.Server { + if !a.opts.Verbose { + gin.SetMode(gin.ReleaseMode) + } + return &http.Server{ + Addr: a.opts.HTTPAddr, + Handler: a.router(), + ReadHeaderTimeout: 5 * time.Second, + ReadTimeout: 30 * time.Second, + WriteTimeout: 30 * time.Second, + IdleTimeout: 60 * time.Second, + MaxHeaderBytes: 1 << 20, + } +} + +func (a *App) router() *gin.Engine { + router := gin.New() + router.Use(gin.Recovery(), a.securityHeaders(), a.corsMiddleware()) + if a.opts.Verbose { + router.Use(gin.Logger()) + } + + router.GET("/api/health", a.healthHandler) + router.GET("/api/schema", a.schemaHandler) + router.GET("/api/openapi.json", func(c *gin.Context) { + c.JSON(http.StatusOK, openAPISpec()) + }) + router.GET("/json/stats.json", func(c *gin.Context) { + c.Header("Cache-Control", "no-store") + c.JSON(http.StatusOK, a.SnapshotStats()) + }) + + api := router.Group("/api", a.authMiddleware()) + api.GET("/config", func(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{"ok": true, "config": a.ConfigSnapshot()}) + }) + api.PUT("/config", func(c *gin.Context) { + body, apiErr := decodeRequestObject(c) + if apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + doc, apiErr := a.ReplaceConfig(ConfigDocument(body)) + if apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + c.JSON(http.StatusOK, gin.H{"ok": true, "reloaded": true, "pid": os.Getpid(), "generation": a.generation.Load(), "config": doc}) + }) + + for _, collection := range []string{"servers", "monitors", "sslcerts", "watchdog"} { + key := collection + api.GET("/"+key, func(c *gin.Context) { a.getCollectionHandler(c, key) }) + api.POST("/"+key, func(c *gin.Context) { a.createCollectionHandler(c, key) }) + api.PUT("/"+key+"/:id", func(c *gin.Context) { a.updateCollectionHandler(c, key) }) + api.DELETE("/"+key+"/:id", func(c *gin.Context) { a.deleteCollectionHandler(c, key) }) + } + api.POST("/servers/:id/reset-traffic", a.resetTrafficHandler) + api.POST("/reload", func(c *gin.Context) { + if apiErr := a.ReloadConfig(); apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + c.JSON(http.StatusOK, gin.H{"ok": true, "operation": "reload", "pid": os.Getpid(), "generation": a.generation.Load()}) + }) + api.POST("/restart", func(c *gin.Context) { + if apiErr := a.ReloadConfig(); apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + c.JSON(http.StatusAccepted, gin.H{"ok": true, "operation": "restart", "mode": "in-process", "pid": os.Getpid(), "generation": a.generation.Load()}) + }) + + router.NoRoute(a.staticHandler) + return router +} + +func (a *App) securityHeaders() gin.HandlerFunc { + return func(c *gin.Context) { + c.Header("X-Content-Type-Options", "nosniff") + c.Header("X-Frame-Options", "SAMEORIGIN") + c.Header("Referrer-Policy", "same-origin") + if strings.HasPrefix(c.Request.URL.Path, "/api/") { + c.Header("Cache-Control", "no-store") + } + c.Next() + } +} + +func (a *App) corsMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + if a.opts.CORSOrigin != "" { + c.Header("Access-Control-Allow-Origin", a.opts.CORSOrigin) + c.Header("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Admin-Token") + c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") + c.Header("Vary", "Origin") + } + if c.Request.Method == http.MethodOptions && strings.HasPrefix(c.Request.URL.Path, "/api/") { + c.AbortWithStatus(http.StatusNoContent) + return + } + c.Next() + } +} + +func (a *App) authMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + if a.opts.AdminToken == "" { + a.writeAPIError(c, &APIError{Status: 503, Message: "management API is disabled; set ADMIN_TOKEN to enable it"}) + c.Abort() + return + } + token := "" + authorization := c.GetHeader("Authorization") + if len(authorization) >= 7 && strings.EqualFold(authorization[:7], "bearer ") { + token = strings.TrimSpace(authorization[7:]) + } + if token == "" { + token = strings.TrimSpace(c.GetHeader("X-Admin-Token")) + } + if len(token) != len(a.opts.AdminToken) || subtle.ConstantTimeCompare([]byte(token), []byte(a.opts.AdminToken)) != 1 { + a.writeAPIError(c, &APIError{Status: 401, Message: "invalid or missing admin token"}) + c.Abort() + return + } + c.Next() + } +} + +func (a *App) healthHandler(c *gin.Context) { + running := a.agentRunning.Load() + c.JSON(http.StatusOK, gin.H{ + "ok": true, "enabled": a.opts.AdminToken != "", + "service": gin.H{"running": true, "pid": os.Getpid(), "version": version, "uptime": int64(time.Since(a.startedAt).Seconds()), "generation": a.generation.Load()}, + "agent": gin.H{"running": running, "address": a.opts.AgentAddr}, + "configPath": a.opts.ConfigPath, + }) +} + +func (a *App) schemaHandler(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{"ok": true, "schema": apiSchema(a.opts.AdminToken != "")}) +} + +func apiSchema(enabled bool) map[string]any { + endpoints := []any{ + map[string]any{"method": "GET", "path": "/api/health", "auth": false}, + map[string]any{"method": "GET", "path": "/api/schema", "auth": false}, + map[string]any{"method": "GET", "path": "/api/openapi.json", "auth": false}, + map[string]any{"method": "GET", "path": "/api/config", "auth": true}, + map[string]any{"method": "PUT", "path": "/api/config", "auth": true, "body": "full config JSON"}, + } + for _, key := range []string{"servers", "monitors", "sslcerts", "watchdog"} { + spec := collectionSpecs[key] + endpoints = append(endpoints, + map[string]any{"method": "GET", "path": "/api/" + key, "auth": true}, + map[string]any{"method": "POST", "path": "/api/" + key, "auth": true, "body": spec.itemName + " JSON"}, + map[string]any{"method": "PUT", "path": "/api/" + key + "/{id}", "auth": true, "body": spec.itemName + " JSON"}, + map[string]any{"method": "DELETE", "path": "/api/" + key + "/{id}", "auth": true}, + ) + } + endpoints = append(endpoints, + map[string]any{"method": "POST", "path": "/api/servers/{username}/reset-traffic", "auth": true}, + map[string]any{"method": "POST", "path": "/api/reload", "auth": true}, + map[string]any{"method": "POST", "path": "/api/restart", "auth": true}, + ) + collections := make(map[string]any) + for key, spec := range collectionSpecs { + collections[key] = map[string]any{"item": spec.itemName, "idField": spec.idField, "required": spec.required, "optional": spec.optional} + } + return map[string]any{ + "version": version, + "auth": map[string]any{"type": "bearer", "header": "Authorization: Bearer ", "enabled": enabled}, + "endpoints": endpoints, "collections": collections, + } +} + +func decodeRequestObject(c *gin.Context) (map[string]any, *APIError) { + c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxRequestBody) + decoder := json.NewDecoder(c.Request.Body) + decoder.UseNumber() + var object map[string]any + if err := decoder.Decode(&object); err != nil { + status := http.StatusBadRequest + if strings.Contains(err.Error(), "request body too large") { + status = http.StatusRequestEntityTooLarge + } + return nil, &APIError{Status: status, Message: "invalid JSON body", Details: map[string]any{"error": err.Error()}} + } + if object == nil { + return nil, &APIError{Status: 400, Message: "request body must be an object"} + } + var trailing any + if err := decoder.Decode(&trailing); !errors.Is(err, io.EOF) { + return nil, &APIError{Status: 400, Message: "request body must contain one JSON value"} + } + return object, nil +} + +func (a *App) getCollectionHandler(c *gin.Context, key string) { + doc := a.ConfigSnapshot() + items, _ := doc[key].([]any) + c.JSON(http.StatusOK, gin.H{"ok": true, key: items}) +} + +func (a *App) createCollectionHandler(c *gin.Context, key string) { + item, apiErr := decodeRequestObject(c) + if apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + doc, apiErr := a.MutateConfig(func(doc ConfigDocument) *APIError { + items, _ := doc[key].([]any) + doc[key] = append(items, item) + return nil + }) + if apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + items, _ := doc[key].([]any) + created := items[len(items)-1] + c.JSON(http.StatusCreated, gin.H{"ok": true, collectionSpecs[key].itemName: created, "reloaded": true, "pid": os.Getpid(), "config": doc}) +} + +func (a *App) updateCollectionHandler(c *gin.Context, key string) { + item, apiErr := decodeRequestObject(c) + if apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + id := c.Param("id") + if id == "" { + a.writeAPIError(c, &APIError{Status: 400, Message: "item id is required"}) + return + } + var updated any + doc, apiErr := a.MutateConfig(func(doc ConfigDocument) *APIError { + items, _ := doc[key].([]any) + index, _, findErr := findCollectionItem(items, collectionSpecs[key].idField, id, key != "servers") + if findErr != nil { + return findErr + } + if index < 0 { + return &APIError{Status: 404, Message: collectionSpecs[key].itemName + " was not found", Details: map[string]any{"id": id}} + } + items[index] = item + doc[key] = items + updated = item + return nil + }) + if apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + // Return the normalized item from the resulting document. + items, _ := doc[key].([]any) + if itemMap, ok := updated.(map[string]any); ok { + idValue := fmt.Sprint(itemMap[collectionSpecs[key].idField]) + if index, normalized, _ := findCollectionItem(items, collectionSpecs[key].idField, idValue, key != "servers"); index >= 0 { + updated = normalized + } + } + c.JSON(http.StatusOK, gin.H{"ok": true, collectionSpecs[key].itemName: updated, "reloaded": true, "pid": os.Getpid(), "config": doc}) +} + +func (a *App) deleteCollectionHandler(c *gin.Context, key string) { + id := c.Param("id") + if id == "" { + a.writeAPIError(c, &APIError{Status: 400, Message: "item id is required"}) + return + } + var removed any + doc, apiErr := a.MutateConfig(func(doc ConfigDocument) *APIError { + items, _ := doc[key].([]any) + index, item, findErr := findCollectionItem(items, collectionSpecs[key].idField, id, key != "servers") + if findErr != nil { + return findErr + } + if index < 0 { + return &APIError{Status: 404, Message: collectionSpecs[key].itemName + " was not found", Details: map[string]any{"id": id}} + } + removed = item + doc[key] = append(items[:index], items[index+1:]...) + return nil + }) + if apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + c.JSON(http.StatusOK, gin.H{"ok": true, "removed": removed, "reloaded": true, "pid": os.Getpid(), "config": doc}) +} + +func findCollectionItem(items []any, idField, id string, allowIndex bool) (int, any, *APIError) { + if numeric, err := strconv.Atoi(id); allowIndex && err == nil { + if numeric >= 0 && numeric < len(items) { + return numeric, items[numeric], nil + } + return -1, nil, nil + } + matches := make([]int, 0, 1) + for index, raw := range items { + item, ok := raw.(map[string]any) + if ok && fmt.Sprint(item[idField]) == id { + matches = append(matches, index) + } + } + if len(matches) > 1 { + return -1, nil, &APIError{Status: 409, Message: "collection has duplicate " + idField + "; use numeric index instead", Details: map[string]any{"id": id}} + } + if len(matches) == 1 { + return matches[0], items[matches[0]], nil + } + return -1, nil, nil +} + +func (a *App) resetTrafficHandler(c *gin.Context) { + username := c.Param("id") + if username == "" { + a.writeAPIError(c, &APIError{Status: 400, Message: "username is required"}) + return + } + result, apiErr := a.ResetTraffic(username) + if apiErr != nil { + a.writeAPIError(c, apiErr) + return + } + result["ok"] = true + result["operation"] = "reset-traffic" + result["pid"] = os.Getpid() + c.JSON(http.StatusOK, result) +} + +func (a *App) writeAPIError(c *gin.Context, apiErr *APIError) { + payload := gin.H{"ok": false, "error": apiErr.Message} + if apiErr.Details != nil { + payload["details"] = apiErr.Details + } + c.JSON(apiErr.Status, payload) +} + +func (a *App) staticHandler(c *gin.Context) { + if strings.HasPrefix(c.Request.URL.Path, "/api/") || strings.HasPrefix(c.Request.URL.Path, "/json/") { + c.JSON(http.StatusNotFound, gin.H{"ok": false, "error": "endpoint was not found"}) + return + } + requestPath := filepath.Clean("/" + c.Request.URL.Path) + if requestPath == "/" { + requestPath = "/index.html" + } + root, err := filepath.Abs(a.opts.WebDir) + if err != nil { + c.Status(http.StatusInternalServerError) + return + } + filePath := filepath.Join(root, strings.TrimPrefix(requestPath, "/")) + if filePath != root && !strings.HasPrefix(filePath, root+string(os.PathSeparator)) { + c.Status(http.StatusNotFound) + return + } + info, err := os.Stat(filePath) + if err != nil || info.IsDir() { + c.Status(http.StatusNotFound) + return + } + if contentType := mime.TypeByExtension(filepath.Ext(filePath)); contentType != "" { + c.Header("Content-Type", contentType) + } + if filepath.Base(filePath) == "index.html" { + c.Header("Cache-Control", "no-cache") + } + http.ServeFile(c.Writer, c.Request, filePath) +} diff --git a/server/http_server_test.go b/server/http_server_test.go new file mode 100644 index 0000000..e539668 --- /dev/null +++ b/server/http_server_test.go @@ -0,0 +1,158 @@ +package main + +import ( + "encoding/json" + "net/http" + "net/url" + "os" + "strings" + "testing" +) + +func TestHTTPAPIAndStaticUI(t *testing.T) { + app := newTestApp(t, minimalTestConfig()) + router := app.router() + + response := performRequest(router, http.MethodGet, "/", "", "") + if response.Code != 200 || !strings.Contains(response.Body.String(), "test-ui") { + t.Fatalf("static UI: status=%d body=%s", response.Code, response.Body.String()) + } + response = performRequest(router, http.MethodGet, "/api/health", "", "") + if response.Code != 200 || !strings.Contains(response.Body.String(), `"enabled":true`) { + t.Fatalf("health: status=%d body=%s", response.Code, response.Body.String()) + } + response = performRequest(router, http.MethodGet, "/api/openapi.json", "", "") + if response.Code != 200 { + t.Fatalf("openapi: status=%d body=%s", response.Code, response.Body.String()) + } + var openapi map[string]any + if err := json.Unmarshal(response.Body.Bytes(), &openapi); err != nil { + t.Fatal(err) + } + paths := openapi["paths"].(map[string]any) + if openapi["openapi"] != "3.1.0" || paths["/api/servers/{username}"] == nil || paths["/api/watchdog/{id}"] == nil { + t.Fatalf("OpenAPI document is incomplete: %#v", openapi) + } + monitorOperations := paths["/api/monitors"].(map[string]any) + createResponses := monitorOperations["post"].(map[string]any)["responses"].(map[string]any) + if createResponses["201"] == nil || createResponses["200"] != nil { + t.Fatalf("OpenAPI create response must describe HTTP 201: %#v", createResponses) + } + listResponses := monitorOperations["get"].(map[string]any)["responses"].(map[string]any) + listSchema := listResponses["200"].(map[string]any)["content"].(map[string]any)["application/json"].(map[string]any)["schema"].(map[string]any) + if listSchema["properties"].(map[string]any)["monitors"] == nil { + t.Fatalf("OpenAPI list response does not expose monitors: %#v", listSchema) + } + restartResponses := paths["/api/restart"].(map[string]any)["post"].(map[string]any)["responses"].(map[string]any) + if restartResponses["202"] == nil { + t.Fatalf("OpenAPI restart response must describe HTTP 202: %#v", restartResponses) + } + response = performRequest(router, http.MethodGet, "/api/config", "", "wrong") + if response.Code != http.StatusUnauthorized { + t.Fatalf("expected 401, got %d", response.Code) + } + response = performRequest(router, http.MethodGet, "/api/config", "", "test-token") + if response.Code != 200 { + t.Fatalf("config: status=%d body=%s", response.Code, response.Body.String()) + } + + monitor := `{"name":"新增服务","host":"tcp://127.0.0.1:80","type":"tcp","interval":"30"}` + response = performRequest(router, http.MethodPost, "/api/monitors", monitor, "test-token") + if response.Code != http.StatusCreated || !strings.Contains(response.Body.String(), "新增服务") { + t.Fatalf("create monitor: status=%d body=%s", response.Code, response.Body.String()) + } + path := "/api/monitors/" + url.PathEscape("新增服务") + monitor = `{"name":"更新服务","host":"https://example.org","type":"https","interval":45}` + response = performRequest(router, http.MethodPut, path, monitor, "test-token") + if response.Code != 200 || !strings.Contains(response.Body.String(), "更新服务") { + t.Fatalf("update monitor: status=%d body=%s", response.Code, response.Body.String()) + } + response = performRequest(router, http.MethodDelete, "/api/monitors/"+url.PathEscape("更新服务"), "", "test-token") + if response.Code != 200 { + t.Fatalf("delete monitor: status=%d body=%s", response.Code, response.Body.String()) + } + percentMonitor := `{"name":"rate%check","host":"https://example.com","type":"https","interval":30}` + response = performRequest(router, http.MethodPost, "/api/monitors", percentMonitor, "test-token") + if response.Code != http.StatusCreated { + t.Fatalf("create percent monitor: status=%d body=%s", response.Code, response.Body.String()) + } + response = performRequest(router, http.MethodDelete, "/api/monitors/"+url.PathEscape("rate%check"), "", "test-token") + if response.Code != 200 { + t.Fatalf("delete percent monitor: status=%d body=%s", response.Code, response.Body.String()) + } + + server := `{"username":"s02","name":"node2","type":"kvm","host":"host2","location":"JP","password":"secret","monthstart":31}` + response = performRequest(router, http.MethodPost, "/api/servers", server, "test-token") + if response.Code != http.StatusCreated || !strings.Contains(response.Body.String(), `"monthstart":28`) { + t.Fatalf("create server: status=%d body=%s", response.Code, response.Body.String()) + } + response = performRequest(router, http.MethodDelete, "/api/servers/s02", "", "test-token") + if response.Code != 200 { + t.Fatalf("delete server: status=%d body=%s", response.Code, response.Body.String()) + } + numericServer := `{"username":"0","name":"numeric","type":"kvm","host":"host0","location":"US","password":"secret","monthstart":1}` + response = performRequest(router, http.MethodPost, "/api/servers", numericServer, "test-token") + if response.Code != http.StatusCreated { + t.Fatalf("create numeric server: status=%d body=%s", response.Code, response.Body.String()) + } + numericServer = `{"username":"0","name":"numeric-updated","type":"kvm","host":"host0","location":"US","password":"secret","monthstart":1}` + response = performRequest(router, http.MethodPut, "/api/servers/0", numericServer, "test-token") + if response.Code != 200 || !strings.Contains(response.Body.String(), "numeric-updated") { + t.Fatalf("update numeric server: status=%d body=%s", response.Code, response.Body.String()) + } + response = performRequest(router, http.MethodDelete, "/api/servers/0", "", "test-token") + if response.Code != 200 || !strings.Contains(response.Body.String(), "numeric-updated") { + t.Fatalf("delete numeric server: status=%d body=%s", response.Code, response.Body.String()) + } + if app.RuntimeSnapshot().Servers[0].Username != "s01" { + t.Fatal("numeric username operation modified the server at numeric index") + } + + response = performRequest(router, http.MethodPost, "/api/servers/s01/reset-traffic", "", "test-token") + if response.Code != http.StatusConflict { + t.Fatalf("offline reset should conflict: status=%d body=%s", response.Code, response.Body.String()) + } + response = performRequest(router, http.MethodPost, "/api/reload", "", "test-token") + if response.Code != 200 { + t.Fatalf("reload: status=%d body=%s", response.Code, response.Body.String()) + } + response = performRequest(router, http.MethodPost, "/api/restart", "", "test-token") + if response.Code != http.StatusAccepted || !strings.Contains(response.Body.String(), "in-process") { + t.Fatalf("restart: status=%d body=%s", response.Code, response.Body.String()) + } + + data, err := os.ReadFile(app.opts.ConfigPath) + if err != nil { + t.Fatal(err) + } + var persisted map[string]any + if err := json.Unmarshal(data, &persisted); err != nil { + t.Fatalf("persisted config is invalid: %v", err) + } +} + +func TestHTTPRejectsInvalidAndOversizedBodies(t *testing.T) { + app := newTestApp(t, minimalTestConfig()) + router := app.router() + response := performRequest(router, http.MethodPost, "/api/servers", `{"name":`, "test-token") + if response.Code != 400 { + t.Fatalf("invalid JSON: status=%d body=%s", response.Code, response.Body.String()) + } + response = performRequest(router, http.MethodPost, "/api/servers", `{"name":"x"}`, "test-token") + if response.Code != 400 { + t.Fatalf("missing fields: status=%d body=%s", response.Code, response.Body.String()) + } + oversized := `{"name":"` + strings.Repeat("x", maxRequestBody) + `"}` + response = performRequest(router, http.MethodPost, "/api/servers", oversized, "test-token") + if response.Code != http.StatusRequestEntityTooLarge { + t.Fatalf("oversized body: status=%d body=%s", response.Code, response.Body.String()) + } + + doc := app.ConfigSnapshot() + doc["watchdog"] = []any{map[string]any{"name": "broken", "rule": "cpu >", "interval": 10}} + data, _ := json.Marshal(doc) + response = performRequest(router, http.MethodPut, "/api/config", string(data), "test-token") + if response.Code != 400 { + t.Fatalf("invalid watchdog: status=%d body=%s", response.Code, response.Body.String()) + } +} diff --git a/server/include/argparse.h b/server/include/argparse.h deleted file mode 100644 index 4430f94..0000000 --- a/server/include/argparse.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef ARGPARSE_H -#define ARGPARSE_H - -/** - * Command-line arguments parsing library. - * - * This module is inspired by parse-options.c (git) and python's argparse - * module. - * - * Arguments parsing is common task in cli program, but traditional `getopt` - * libraries are not easy to use. This library provides high-level arguments - * parsing solutions. - * - * The program defines what arguments it requires, and `argparse` will figure - * out how to parse those out of `argc` and `argv`, it also automatically - * generates help and usage messages and issues errors when users give the - * program invalid arguments. - * - * Reserved namespaces: - * argparse - * OPT - * Author: Yecheng Fu - */ - -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct argparse; -struct argparse_option; - -typedef int argparse_callback(struct argparse *this_, - const struct argparse_option *option); - -enum argparse_flag { - ARGPARSE_STOP_AT_NON_OPTION = 1, -}; - -enum argparse_option_type { - /* special */ - ARGPARSE_OPT_END, - /* options with no arguments */ - ARGPARSE_OPT_BOOLEAN, - ARGPARSE_OPT_BIT, - /* options with arguments (optional or required) */ - ARGPARSE_OPT_INTEGER, - ARGPARSE_OPT_STRING, -}; - -enum argparse_option_flags { - OPT_NONEG = 1, /* Negation disabled. */ -}; - -/* - * Argparse option struct. - * - * `type`: - * holds the type of the option, you must have an ARGPARSE_OPT_END last in your - * array. - * - * `short_name`: - * the character to use as a short option name, '\0' if none. - * - * `long_name`: - * the long option name, without the leading dash, NULL if none. - * - * `value`: - * stores pointer to the value to be filled. - * - * `help`: - * the short help message associated to what the option does. - * Must never be NULL (except for ARGPARSE_OPT_END). - * - * `callback`: - * function is called when corresponding argument is parsed. - * - * `data`: - * associated data. Callbacks can use it like they want. - * - * `flags`: - * option flags. - * - */ -struct argparse_option { - enum argparse_option_type type; - const char short_name; - const char *long_name; - void *value; - const char *help; - argparse_callback *callback; - intptr_t data; - int flags; -}; - -/* - * argpparse - */ -struct argparse { - // user supplied - const struct argparse_option *options; - const char *usage; - int flags; - // internal context - int argc; - const char **argv; - const char **out; - int cpidx; - const char *optvalue; // current option value -}; - -// builtin callbacks -int argparse_help_cb(struct argparse *this_, - const struct argparse_option *option); - -// builtin option macros -#define OPT_END() { ARGPARSE_OPT_END, 0 } -#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ } -#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ } -#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ } -#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ } -#define OPT_HELP() OPT_BOOLEAN('h', "help", 0, "Show this help message and exit", argparse_help_cb) - -int argparse_init(struct argparse *this_, struct argparse_option *options, - const char *usage, int flags); -int argparse_parse(struct argparse *this_, int argc, const char **argv); -void argparse_usage(struct argparse *this_); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/server/include/detect.h b/server/include/detect.h deleted file mode 100644 index 0e2ef86..0000000 --- a/server/include/detect.h +++ /dev/null @@ -1,149 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#ifndef BASE_DETECT_H -#define BASE_DETECT_H - -/* - this file detected the family, platform and architecture - to compile for. -*/ - -/* platforms */ - -/* windows Family */ -#if defined(WIN64) || defined(_WIN64) - /* Hmm, is this IA64 or x86-64? */ - #define CONF_FAMILY_WINDOWS 1 - #define CONF_FAMILY_STRING "windows" - #define CONF_PLATFORM_WIN64 1 - #define CONF_PLATFORM_STRING "win64" -#elif defined(WIN32) || defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) - #define CONF_FAMILY_WINDOWS 1 - #define CONF_FAMILY_STRING "windows" - #define CONF_PLATFORM_WIN32 1 - #define CONF_PLATFORM_STRING "win32" -#endif - -/* unix family */ -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - #define CONF_FAMILY_UNIX 1 - #define CONF_FAMILY_STRING "unix" - #define CONF_PLATFORM_FREEBSD 1 - #define CONF_PLATFORM_STRING "freebsd" -#endif - -#if defined(__OpenBSD__) - #define CONF_FAMILY_UNIX 1 - #define CONF_FAMILY_STRING "unix" - #define CONF_PLATFORM_OPENBSD 1 - #define CONF_PLATFORM_STRING "openbsd" -#endif - -#if defined(__LINUX__) || defined(__linux__) - #define CONF_FAMILY_UNIX 1 - #define CONF_FAMILY_STRING "unix" - #define CONF_PLATFORM_LINUX 1 - #define CONF_PLATFORM_STRING "linux" -#endif - -#if defined(__GNU__) || defined(__gnu__) - #define CONF_FAMILY_UNIX 1 - #define CONF_FAMILY_STRING "unix" - #define CONF_PLATFORM_HURD 1 - #define CONF_PLATFORM_STRING "gnu" -#endif - -#if defined(MACOSX) || defined(__APPLE__) || defined(__DARWIN__) - #define CONF_FAMILY_UNIX 1 - #define CONF_FAMILY_STRING "unix" - #define CONF_PLATFORM_MACOSX 1 - #define CONF_PLATFORM_STRING "macosx" -#endif - -#if defined(__sun) - #define CONF_FAMILY_UNIX 1 - #define CONF_FAMILY_STRING "unix" - #define CONF_PLATFORM_SOLARIS 1 - #define CONF_PLATFORM_STRING "solaris" -#endif - -/* beos family */ -#if defined(__BeOS) || defined(__BEOS__) - #define CONF_FAMILY_BEOS 1 - #define CONF_FAMILY_STRING "beos" - #define CONF_PLATFORM_BEOS 1 - #define CONF_PLATFORM_STRING "beos" -#endif - - -/* use gcc endianness definitions when available */ -#if defined(__GNUC__) && !defined(__APPLE__) && !defined(__MINGW32__) && !defined(__sun) - #if defined(__FreeBSD__) || defined(__OpenBSD__) - #include - #else - #include - #endif - - #if __BYTE_ORDER == __LITTLE_ENDIAN - #define CONF_ARCH_ENDIAN_LITTLE 1 - #elif __BYTE_ORDER == __BIG_ENDIAN - #define CONF_ARCH_ENDIAN_BIG 1 - #endif -#endif - - -/* architectures */ -#if defined(i386) || defined(__i386__) || defined(__x86__) || defined(CONF_PLATFORM_WIN32) - #define CONF_ARCH_IA32 1 - #define CONF_ARCH_STRING "ia32" - #if !defined(CONF_ARCH_ENDIAN_LITTLE) && !defined(CONF_ARCH_ENDIAN_BIG) - #define CONF_ARCH_ENDIAN_LITTLE 1 - #endif -#endif - -#if defined(__ia64__) || defined(_M_IA64) - #define CONF_ARCH_IA64 1 - #define CONF_ARCH_STRING "ia64" - #if !defined(CONF_ARCH_ENDIAN_LITTLE) && !defined(CONF_ARCH_ENDIAN_BIG) - #define CONF_ARCH_ENDIAN_LITTLE 1 - #endif -#endif - -#if defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) - #define CONF_ARCH_AMD64 1 - #define CONF_ARCH_STRING "amd64" - #if !defined(CONF_ARCH_ENDIAN_LITTLE) && !defined(CONF_ARCH_ENDIAN_BIG) - #define CONF_ARCH_ENDIAN_LITTLE 1 - #endif -#endif - -#if defined(__powerpc__) || defined(__ppc__) - #define CONF_ARCH_PPC 1 - #define CONF_ARCH_STRING "ppc" - #if !defined(CONF_ARCH_ENDIAN_LITTLE) && !defined(CONF_ARCH_ENDIAN_BIG) - #define CONF_ARCH_ENDIAN_BIG 1 - #endif -#endif - -#if defined(__sparc__) - #define CONF_ARCH_SPARC 1 - #define CONF_ARCH_STRING "sparc" - #if !defined(CONF_ARCH_ENDIAN_LITTLE) && !defined(CONF_ARCH_ENDIAN_BIG) - #define CONF_ARCH_ENDIAN_BIG 1 - #endif -#endif - - -#ifndef CONF_FAMILY_STRING -#define CONF_FAMILY_STRING "unknown" -#endif - -#ifndef CONF_PLATFORM_STRING -#define CONF_PLATFORM_STRING "unknown" -#endif - -#ifndef CONF_ARCH_STRING -#define CONF_ARCH_STRING "unknown" -#endif - -#endif diff --git a/server/include/json.h b/server/include/json.h deleted file mode 100644 index ed1f175..0000000 --- a/server/include/json.h +++ /dev/null @@ -1,269 +0,0 @@ - -/* vim: set et ts=3 sw=3 sts=3 ft=c: - * - * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. - * https://github.com/udp/json-parser - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _JSON_H -#define _JSON_H - -#ifndef json_char - #define json_char char -#endif - -#ifndef json_int_t - #ifndef _MSC_VER - #include - #define json_int_t int64_t - #else - #define json_int_t __int64 - #endif -#endif - -#include - -#ifdef __cplusplus - - #include - - extern "C" - { - -#endif - -typedef struct -{ - unsigned long max_memory; - int settings; - - /* Custom allocator support (leave null to use malloc/free) - */ - - void * (* mem_alloc) (size_t, int zero, void * user_data); - void (* mem_free) (void *, void * user_data); - - void * user_data; /* will be passed to mem_alloc and mem_free */ - -} json_settings; - -#define json_enable_comments 0x01 - -typedef enum -{ - json_none, - json_object, - json_array, - json_integer, - json_double, - json_string, - json_boolean, - json_null - -} json_type; - -extern const struct _json_value json_value_none; - -typedef struct _json_value -{ - struct _json_value * parent; - - json_type type; - - union - { - int boolean; - json_int_t integer; - double dbl; - - struct - { - unsigned int length; - json_char * ptr; /* null terminated */ - - } string; - - struct - { - unsigned int length; - - struct - { - json_char * name; - unsigned int name_length; - - struct _json_value * value; - - } * values; - - #if defined(__cplusplus) && __cplusplus >= 201103L - decltype(values) begin () const - { return values; - } - decltype(values) end () const - { return values + length; - } - #endif - - } object; - - struct - { - unsigned int length; - struct _json_value ** values; - - #if defined(__cplusplus) && __cplusplus >= 201103L - decltype(values) begin () const - { return values; - } - decltype(values) end () const - { return values + length; - } - #endif - - } array; - - } u; - - union - { - struct _json_value * next_alloc; - void * object_mem; - - } _reserved; - - - /* Some C++ operator sugar */ - - #ifdef __cplusplus - - public: - - inline _json_value () - { memset (this, 0, sizeof (_json_value)); - } - - inline const struct _json_value &operator [] (int index) const - { - if (type != json_array || index < 0 - || ((unsigned int) index) >= u.array.length) - { - return json_value_none; - } - - return *u.array.values [index]; - } - - inline const struct _json_value &operator [] (const char * index) const - { - if (type != json_object) - return json_value_none; - - for (unsigned int i = 0; i < u.object.length; ++ i) - if (!strcmp (u.object.values [i].name, index)) - return *u.object.values [i].value; - - return json_value_none; - } - - inline operator const char * () const - { - switch (type) - { - case json_string: - return u.string.ptr; - - default: - return ""; - }; - } - - inline operator json_int_t () const - { - switch (type) - { - case json_integer: - return u.integer; - - case json_double: - return (json_int_t) u.dbl; - - default: - return 0; - }; - } - - inline operator bool () const - { - if (type != json_boolean) - return false; - - return u.boolean != 0; - } - - inline operator double () const - { - switch (type) - { - case json_integer: - return (double) u.integer; - - case json_double: - return u.dbl; - - default: - return 0; - }; - } - - #endif - -} json_value; - -json_value * json_parse (const json_char * json, - size_t length); - -#define json_error_max 128 -json_value * json_parse_ex (json_settings * settings, - const json_char * json, - size_t length, - char * error); - -void json_value_free (json_value *); - - -/* Not usually necessary, unless you used a custom mem_alloc and now want to - * use a custom mem_free. - */ -void json_value_free_ex (json_settings * settings, - json_value *); - - -#ifdef __cplusplus - } /* extern "C" */ -#endif - -#endif diff --git a/server/include/system.h b/server/include/system.h deleted file mode 100644 index 7ba0c0a..0000000 --- a/server/include/system.h +++ /dev/null @@ -1,1299 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ - -/* - Title: OS Abstraction -*/ - -#ifndef BASE_SYSTEM_H -#define BASE_SYSTEM_H - -#include "detect.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Group: Debug */ -/* - Function: dbg_assert - Breaks into the debugger based on a test. - - Parameters: - test - Result of the test. - msg - Message that should be printed if the test fails. - - Remarks: - Does nothing in release version of the library. - - See Also: - -*/ -void dbg_assert(int test, const char *msg); -#define dbg_assert(test,msg) dbg_assert_imp(__FILE__, __LINE__, test, msg) -void dbg_assert_imp(const char *filename, int line, int test, const char *msg); - - -#ifdef __clang_analyzer__ -#include -#undef dbg_assert -#define dbg_assert(test,msg) assert(test) -#endif - -/* - Function: dbg_break - Breaks into the debugger. - - Remarks: - Does nothing in release version of the library. - - See Also: - -*/ -void dbg_break(); - -/* - Function: dbg_msg - - Prints a debug message. - - Parameters: - sys - A string that describes what system the message belongs to - fmt - A printf styled format string. - - Remarks: - Does nothing in release version of the library. - - See Also: - -*/ -void dbg_msg(const char *sys, const char *fmt, ...); - -/* Group: Memory */ - -/* - Function: mem_alloc - Allocates memory. - - Parameters: - size - Size of the needed block. - alignment - Alignment for the block. - - Returns: - Returns a pointer to the newly allocated block. Returns a - null pointer if the memory couldn't be allocated. - - Remarks: - - Passing 0 to size will allocated the smallest amount possible - and return a unique pointer. - - See Also: - -*/ -void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned alignment); -#define mem_alloc(s,a) mem_alloc_debug(__FILE__, __LINE__, (s), (a)) - -/* - Function: mem_free - Frees a block allocated through . - - Remarks: - - In the debug version of the library the function will assert if - a non-valid block is passed, like a null pointer or a block that - isn't allocated. - - See Also: - -*/ -void mem_free(void *block); - -/* - Function: mem_copy - Copies a a memory block. - - Parameters: - dest - Destination. - source - Source to copy. - size - Size of the block to copy. - - Remarks: - - This functions DOES NOT handles cases where source and - destination is overlapping. - - See Also: - -*/ -void mem_copy(void *dest, const void *source, unsigned size); - -/* - Function: mem_move - Copies a a memory block - - Parameters: - dest - Destination - source - Source to copy - size - Size of the block to copy - - Remarks: - - This functions handles cases where source and destination - is overlapping - - See Also: - -*/ -void mem_move(void *dest, const void *source, unsigned size); - -/* - Function: mem_zero - Sets a complete memory block to 0 - - Parameters: - block - Pointer to the block to zero out - size - Size of the block -*/ -void mem_zero(void *block, unsigned size); - -/* - Function: mem_comp - Compares two blocks of memory - - Parameters: - a - First block of data - b - Second block of data - size - Size of the data to compare - - Returns: - <0 - Block a is lesser then block b - 0 - Block a is equal to block b - >0 - Block a is greater then block b -*/ -int mem_comp(const void *a, const void *b, int size); - -/* - Function: mem_check - Validates the heap - Will trigger a assert if memory has failed. -*/ -int mem_check_imp(); -#define mem_check() dbg_assert_imp(__FILE__, __LINE__, mem_check_imp(), "Memory check failed") - -/* Group: File IO */ -enum { - IOFLAG_READ = 1, - IOFLAG_WRITE = 2, - IOFLAG_RANDOM = 4, - - IOSEEK_START = 0, - IOSEEK_CUR = 1, - IOSEEK_END = 2 -}; - -typedef struct IOINTERNAL *IOHANDLE; - -/* - Function: io_open - Opens a file. - - Parameters: - filename - File to open. - flags - A set of flags. IOFLAG_READ, IOFLAG_WRITE, IOFLAG_RANDOM. - - Returns: - Returns a handle to the file on success and 0 on failure. - -*/ -IOHANDLE io_open(const char *filename, int flags); - -/* - Function: io_read - Reads data into a buffer from a file. - - Parameters: - io - Handle to the file to read data from. - buffer - Pointer to the buffer that will recive the data. - size - Number of bytes to read from the file. - - Returns: - Number of bytes read. - -*/ -unsigned io_read(IOHANDLE io, void *buffer, unsigned size); - -/* - Function: io_skip - Skips data in a file. - - Parameters: - io - Handle to the file. - size - Number of bytes to skip. - - Returns: - Number of bytes skipped. -*/ -unsigned io_skip(IOHANDLE io, int size); - -/* - Function: io_write - Writes data from a buffer to file. - - Parameters: - io - Handle to the file. - buffer - Pointer to the data that should be written. - size - Number of bytes to write. - - Returns: - Number of bytes written. -*/ -unsigned io_write(IOHANDLE io, const void *buffer, unsigned size); - -/* - Function: io_write_newline - Writes newline to file. - - Parameters: - io - Handle to the file. - - Returns: - Number of bytes written. -*/ -unsigned io_write_newline(IOHANDLE io); - -/* - Function: io_seek - Seeks to a specified offset in the file. - - Parameters: - io - Handle to the file. - offset - Offset from pos to stop. - origin - Position to start searching from. - - Returns: - Returns 0 on success. -*/ -int io_seek(IOHANDLE io, int offset, int origin); - -/* - Function: io_tell - Gets the current position in the file. - - Parameters: - io - Handle to the file. - - Returns: - Returns the current position. -1L if an error occured. -*/ -long int io_tell(IOHANDLE io); - -/* - Function: io_length - Gets the total length of the file. Resetting cursor to the beginning - - Parameters: - io - Handle to the file. - - Returns: - Returns the total size. -1L if an error occured. -*/ -long int io_length(IOHANDLE io); - -/* - Function: io_close - Closes a file. - - Parameters: - io - Handle to the file. - - Returns: - Returns 0 on success. -*/ -int io_close(IOHANDLE io); - -/* - Function: io_flush - Empties all buffers and writes all pending data. - - Parameters: - io - Handle to the file. - - Returns: - Returns 0 on success. -*/ -int io_flush(IOHANDLE io); - - -/* - Function: io_stdin - Returns an to the standard input. -*/ -IOHANDLE io_stdin(); - -/* - Function: io_stdout - Returns an to the standard output. -*/ -IOHANDLE io_stdout(); - -/* - Function: io_stderr - Returns an to the standard error. -*/ -IOHANDLE io_stderr(); - - -/* Group: Threads */ - -/* - Function: thread_sleep - Suspends the current thread for a given period. - - Parameters: - milliseconds - Number of milliseconds to sleep. -*/ -void thread_sleep(int milliseconds); - -/* - Function: thread_create - Creates a new thread. - - Parameters: - threadfunc - Entry point for the new thread. - user - Pointer to pass to the thread. - -*/ -void *thread_create(void (*threadfunc)(void *), void *user); - -/* - Function: thread_wait - Waits for a thread to be done or destroyed. - - Parameters: - thread - Thread to wait for. -*/ -void thread_wait(void *thread); - -/* - Function: thread_destroy - Destroys a thread. - - Parameters: - thread - Thread to destroy. -*/ -void thread_destroy(void *thread); - -/* - Function: thread_yeild - Yeild the current threads execution slice. -*/ -void thread_yield(); - -/* - Function: thread_detach - Puts the thread in the detached thread, guaranteeing that - resources of the thread will be freed immediately when the - thread terminates. - - Parameters: - thread - Thread to detach -*/ -void thread_detach(void *thread); - -/* Group: Locks */ -typedef void* LOCK; - -LOCK lock_create(); -void lock_destroy(LOCK lock); - -int lock_try(LOCK lock); -void lock_wait(LOCK lock); -void lock_release(LOCK lock); - - -/* Group: Semaphores */ - -#if !defined(CONF_PLATFORM_MACOSX) - #if defined(CONF_FAMILY_UNIX) - #include - typedef sem_t SEMAPHORE; - #elif defined(CONF_FAMILY_WINDOWS) - typedef void* SEMAPHORE; - #else - #error missing sempahore implementation - #endif - - void semaphore_init(SEMAPHORE *sem); - void semaphore_wait(SEMAPHORE *sem); - void semaphore_signal(SEMAPHORE *sem); - void semaphore_destroy(SEMAPHORE *sem); -#endif - -/* Group: Timer */ -#ifdef __GNUC__ -/* if compiled with -pedantic-errors it will complain about long - not being a C90 thing. -*/ -__extension__ typedef long long int64; -#else -typedef long long int64; -#endif -/* - Function: time_get - Fetches a sample from a high resolution timer. - - Returns: - Current value of the timer. - - Remarks: - To know how fast the timer is ticking, see . -*/ -int64 time_get(); - -/* - Function: time_freq - Returns the frequency of the high resolution timer. - - Returns: - Returns the frequency of the high resolution timer. -*/ -int64 time_freq(); - -/* - Function: time_timestamp - Retrives the current time as a UNIX timestamp - - Returns: - The time as a UNIX timestamp -*/ -int time_timestamp(); - -/* Group: Network General */ -typedef struct -{ - int type; - int ipv4sock; - int ipv6sock; -} NETSOCKET; - -enum -{ - NETADDR_MAXSTRSIZE = 1+(8*4+7)+1+1+5+1, // [XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX]:XXXXX - - NETTYPE_INVALID = 0, - NETTYPE_IPV4 = 1, - NETTYPE_IPV6 = 2, - NETTYPE_LINK_BROADCAST = 4, - NETTYPE_ALL = NETTYPE_IPV4|NETTYPE_IPV6 -}; - -typedef struct -{ - unsigned int type; - unsigned char ip[16]; - unsigned short port; -} NETADDR; - -/* - Function: net_init - Initiates network functionallity. - - Returns: - Returns 0 on success, - - Remarks: - You must call this function before using any other network - functions. -*/ -int net_init(); - -/* - Function: net_host_lookup - Does a hostname lookup by name and fills out the passed - NETADDR struct with the recieved details. - - Returns: - 0 on success. -*/ -int net_host_lookup(const char *hostname, NETADDR *addr, int types); - -/* - Function: net_addr_comp - Compares two network addresses. - - Parameters: - a - Address to compare - b - Address to compare to. - - Returns: - <0 - Address a is lesser then address b - 0 - Address a is equal to address b - >0 - Address a is greater then address b -*/ -int net_addr_comp(const NETADDR *a, const NETADDR *b); - -/* - Function: net_addr_str - Turns a network address into a representive string. - - Parameters: - addr - Address to turn into a string. - string - Buffer to fill with the string. - max_length - Maximum size of the string. - add_port - add port to string or not - - Remarks: - - The string will always be zero terminated - -*/ -void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_port); - -/* - Function: net_addr_from_str - Turns string into a network address. - - Returns: - 0 on success - - Parameters: - addr - Address to fill in. - string - String to parse. -*/ -int net_addr_from_str(NETADDR *addr, const char *string); - -/* Group: Network UDP */ - -/* - Function: net_udp_create - Creates a UDP socket and binds it to a port. - - Parameters: - bindaddr - Address to bind the socket to. - - Returns: - On success it returns an handle to the socket. On failure it - returns NETSOCKET_INVALID. -*/ -NETSOCKET net_udp_create(NETADDR bindaddr); - -/* - Function: net_udp_send - Sends a packet over an UDP socket. - - Parameters: - sock - Socket to use. - addr - Where to send the packet. - data - Pointer to the packet data to send. - size - Size of the packet. - - Returns: - On success it returns the number of bytes sent. Returns -1 - on error. -*/ -int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size); - -/* - Function: net_udp_recv - Recives a packet over an UDP socket. - - Parameters: - sock - Socket to use. - addr - Pointer to an NETADDR that will recive the address. - data - Pointer to a buffer that will recive the data. - maxsize - Maximum size to recive. - - Returns: - On success it returns the number of bytes recived. Returns -1 - on error. -*/ -int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize); - -/* - Function: net_udp_close - Closes an UDP socket. - - Parameters: - sock - Socket to close. - - Returns: - Returns 0 on success. -1 on error. -*/ -int net_udp_close(NETSOCKET sock); - - -/* Group: Network TCP */ - -/* - Function: net_tcp_create - Creates a TCP socket. - - Parameters: - bindaddr - Address to bind the socket to. - - Returns: - On success it returns an handle to the socket. On failure it returns NETSOCKET_INVALID. -*/ -NETSOCKET net_tcp_create(NETADDR bindaddr); - -/* - Function: net_tcp_listen - Makes the socket start listening for new connections. - - Parameters: - sock - Socket to start listen to. - backlog - Size of the queue of incomming connections to keep. - - Returns: - Returns 0 on success. -*/ -int net_tcp_listen(NETSOCKET sock, int backlog); - -/* - Function: net_tcp_accept - Polls a listning socket for a new connection. - - Parameters: - sock - Listning socket to poll. - new_sock - Pointer to a socket to fill in with the new socket. - addr - Pointer to an address that will be filled in the remote address (optional, can be NULL). - - Returns: - Returns a non-negative integer on success. Negative integer on failure. -*/ -int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *addr); - -/* - Function: net_tcp_connect - Connects one socket to another. - - Parameters: - sock - Socket to connect. - addr - Address to connect to. - - Returns: - Returns 0 on success. - -*/ -int net_tcp_connect(NETSOCKET sock, const NETADDR *addr); - -/* - Function: net_tcp_send - Sends data to a TCP stream. - - Parameters: - sock - Socket to send data to. - data - Pointer to the data to send. - size - Size of the data to send. - - Returns: - Number of bytes sent. Negative value on failure. -*/ -int net_tcp_send(NETSOCKET sock, const void *data, int size); - -/* - Function: net_tcp_recv - Recvives data from a TCP stream. - - Parameters: - sock - Socket to recvive data from. - data - Pointer to a buffer to write the data to - max_size - Maximum of data to write to the buffer. - - Returns: - Number of bytes recvived. Negative value on failure. When in - non-blocking mode, it returns 0 when there is no more data to - be fetched. -*/ -int net_tcp_recv(NETSOCKET sock, void *data, int maxsize); - -/* - Function: net_tcp_close - Closes a TCP socket. - - Parameters: - sock - Socket to close. - - Returns: - Returns 0 on success. Negative value on failure. -*/ -int net_tcp_close(NETSOCKET sock); - -/* Group: Strings */ - -/* - Function: str_append - Appends a string to another. - - Parameters: - dst - Pointer to a buffer that contains a string. - src - String to append. - dst_size - Size of the buffer of the dst string. - - Remarks: - - The strings are treated as zero-termineted strings. - - Garantees that dst string will contain zero-termination. -*/ -void str_append(char *dst, const char *src, int dst_size); - -/* - Function: str_copy - Copies a string to another. - - Parameters: - dst - Pointer to a buffer that shall recive the string. - src - String to be copied. - dst_size - Size of the buffer dst. - - Remarks: - - The strings are treated as zero-termineted strings. - - Garantees that dst string will contain zero-termination. -*/ -void str_copy(char *dst, const char *src, int dst_size); - -/* - Function: str_length - Returns the length of a zero terminated string. - - Parameters: - str - Pointer to the string. - - Returns: - Length of string in bytes excluding the zero termination. -*/ -int str_length(const char *str); - -/* - Function: str_format - Performs printf formating into a buffer. - - Parameters: - buffer - Pointer to the buffer to recive the formated string. - buffer_size - Size of the buffer. - format - printf formating string. - ... - Parameters for the formating. - - Remarks: - - See the C manual for syntax for the printf formating string. - - The strings are treated as zero-termineted strings. - - Garantees that dst string will contain zero-termination. -*/ -void str_format(char *buffer, int buffer_size, const char *format, ...); - -/* - Function: str_sanitize_strong - Replaces all characters below 32 and above 127 with whitespace. - - Parameters: - str - String to sanitize. - - Remarks: - - The strings are treated as zero-termineted strings. -*/ -void str_sanitize_strong(char *str); - -/* - Function: str_sanitize_cc - Replaces all characters below 32 with whitespace. - - Parameters: - str - String to sanitize. - - Remarks: - - The strings are treated as zero-termineted strings. -*/ -void str_sanitize_cc(char *str); - -/* - Function: str_sanitize - Replaces all characters below 32 with whitespace with - exception to \t, \n and \r. - - Parameters: - str - String to sanitize. - - Remarks: - - The strings are treated as zero-termineted strings. -*/ -void str_sanitize(char *str); - -/* - Function: str_skip_to_whitespace - Skips leading non-whitespace characters(all but ' ', '\t', '\n', '\r'). - - Parameters: - str - Pointer to the string. - - Returns: - Pointer to the first whitespace character found - within the string. - - Remarks: - - The strings are treated as zero-termineted strings. -*/ -char *str_skip_to_whitespace(char *str); - -/* - Function: str_skip_whitespaces - Skips leading whitespace characters(' ', '\t', '\n', '\r'). - - Parameters: - str - Pointer to the string. - - Returns: - Pointer to the first non-whitespace character found - within the string. - - Remarks: - - The strings are treated as zero-termineted strings. -*/ -char *str_skip_whitespaces(char *str); - -/* - Function: str_comp_nocase - Compares to strings case insensitive. - - Parameters: - a - String to compare. - b - String to compare. - - Returns: - <0 - String a is lesser then string b - 0 - String a is equal to string b - >0 - String a is greater then string b - - Remarks: - - Only garanted to work with a-z/A-Z. - - The strings are treated as zero-termineted strings. -*/ -int str_comp_nocase(const char *a, const char *b); - -/* - Function: str_comp_nocase_num - Compares up to num characters of two strings case insensitive. - - Parameters: - a - String to compare. - b - String to compare. - num - Maximum characters to compare - - Returns: - <0 - String a is lesser than string b - 0 - String a is equal to string b - >0 - String a is greater than string b - - Remarks: - - Only garanted to work with a-z/A-Z. - - The strings are treated as zero-termineted strings. -*/ -int str_comp_nocase_num(const char *a, const char *b, const int num); - -/* - Function: str_comp - Compares to strings case sensitive. - - Parameters: - a - String to compare. - b - String to compare. - - Returns: - <0 - String a is lesser then string b - 0 - String a is equal to string b - >0 - String a is greater then string b - - Remarks: - - The strings are treated as zero-termineted strings. -*/ -int str_comp(const char *a, const char *b); - -/* - Function: str_comp_num - Compares up to num characters of two strings case sensitive. - - Parameters: - a - String to compare. - b - String to compare. - num - Maximum characters to compare - - Returns: - <0 - String a is lesser then string b - 0 - String a is equal to string b - >0 - String a is greater then string b - - Remarks: - - The strings are treated as zero-termineted strings. -*/ -int str_comp_num(const char *a, const char *b, const int num); - -/* - Function: str_comp_filenames - Compares two strings case sensitive, digit chars will be compared as numbers. - - Parameters: - a - String to compare. - b - String to compare. - - Returns: - <0 - String a is lesser then string b - 0 - String a is equal to string b - >0 - String a is greater then string b - - Remarks: - - The strings are treated as zero-termineted strings. -*/ -int str_comp_filenames(const char *a, const char *b); - -/* - Function: str_find_nocase - Finds a string inside another string case insensitive. - - Parameters: - haystack - String to search in - needle - String to search for - - Returns: - A pointer into haystack where the needle was found. - Returns NULL of needle could not be found. - - Remarks: - - Only garanted to work with a-z/A-Z. - - The strings are treated as zero-termineted strings. -*/ -const char *str_find_nocase(const char *haystack, const char *needle); - -/* - Function: str_find - Finds a string inside another string case sensitive. - - Parameters: - haystack - String to search in - needle - String to search for - - Returns: - A pointer into haystack where the needle was found. - Returns NULL of needle could not be found. - - Remarks: - - The strings are treated as zero-termineted strings. -*/ -const char *str_find(const char *haystack, const char *needle); - -/* - Function: str_hex - Takes a datablock and generates a hexstring of it. - - Parameters: - dst - Buffer to fill with hex data - dst_size - size of the buffer - data - Data to turn into hex - data - Size of the data - - Remarks: - - The desination buffer will be zero-terminated -*/ -void str_hex(char *dst, int dst_size, const void *data, int data_size); - -/* - Function: str_timestamp - Copies a time stamp in the format year-month-day_hour-minute-second to the string. - - Parameters: - buffer - Pointer to a buffer that shall receive the time stamp string. - buffer_size - Size of the buffer. - - Remarks: - - Guarantees that buffer string will contain zero-termination. -*/ -void str_timestamp(char *buffer, int buffer_size); - -/* Group: Filesystem */ - -/* - Function: fs_listdir - Lists the files in a directory - - Parameters: - dir - Directory to list - cb - Callback function to call for each entry - type - Type of the directory - user - Pointer to give to the callback - - Returns: - Always returns 0. -*/ -typedef int (*FS_LISTDIR_CALLBACK)(const char *name, int is_dir, int dir_type, void *user); -int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user); - -/* - Function: fs_makedir - Creates a directory - - Parameters: - path - Directory to create - - Returns: - Returns 0 on success. Negative value on failure. - - Remarks: - Does not create several directories if needed. "a/b/c" will result - in a failure if b or a does not exist. -*/ -int fs_makedir(const char *path); - -/* - Function: fs_storage_path - Fetches per user configuration directory. - - Returns: - Returns 0 on success. Negative value on failure. - - Remarks: - - Returns ~/.appname on UNIX based systems - - Returns ~/Library/Applications Support/appname on Mac OS X - - Returns %APPDATA%/Appname on Windows based systems -*/ -int fs_storage_path(const char *appname, char *path, int max); - -/* - Function: fs_is_dir - Checks if directory exists - - Returns: - Returns 1 on success, 0 on failure. -*/ -int fs_is_dir(const char *path); - -/* - Function: fs_chdir - Changes current working directory - - Returns: - Returns 0 on success, 1 on failure. -*/ -int fs_chdir(const char *path); - -/* - Function: fs_getcwd - Gets the current working directory. - - Returns: - Returns a pointer to the buffer on success, 0 on failure. -*/ -char *fs_getcwd(char *buffer, int buffer_size); - -/* - Function: fs_parent_dir - Get the parent directory of a directory - - Parameters: - path - The directory string - - Returns: - Returns 0 on success, 1 on failure. - - Remarks: - - The string is treated as zero-termineted string. -*/ -int fs_parent_dir(char *path); - -/* - Function: fs_remove - Deletes the file with the specified name. - - Parameters: - filename - The file to delete - - Returns: - Returns 0 on success, 1 on failure. - - Remarks: - - The strings are treated as zero-terminated strings. -*/ -int fs_remove(const char *filename); - -/* - Function: fs_rename - Renames the file or directory. If the paths differ the file will be moved. - - Parameters: - oldname - The actual name - newname - The new name - - Returns: - Returns 0 on success, 1 on failure. - - Remarks: - - The strings are treated as zero-terminated strings. -*/ -int fs_rename(const char *oldname, const char *newname); - -/* - Group: Undocumented -*/ - - -/* - Function: net_tcp_connect_non_blocking - - DOCTODO: serp -*/ -int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr); - -/* - Function: net_set_non_blocking - - DOCTODO: serp -*/ -int net_set_non_blocking(NETSOCKET sock); - -/* - Function: net_set_non_blocking - - DOCTODO: serp -*/ -int net_set_blocking(NETSOCKET sock); - -/* - Function: net_errno - - DOCTODO: serp -*/ -int net_errno(); - -/* - Function: net_would_block - - DOCTODO: serp -*/ -int net_would_block(); - -int net_socket_read_wait(NETSOCKET sock, int time); - -void mem_debug_dump(IOHANDLE file); - -void swap_endian(void *data, unsigned elem_size, unsigned num); - - -typedef void (*DBG_LOGGER)(const char *line); -void dbg_logger(DBG_LOGGER logger); - -void dbg_logger_stdout(); -void dbg_logger_debugger(); -void dbg_logger_file(const char *filename); - -typedef struct -{ - int allocated; - int active_allocations; - int total_allocations; -} MEMSTATS; - -const MEMSTATS *mem_stats(); - -typedef struct -{ - int sent_packets; - int sent_bytes; - int recv_packets; - int recv_bytes; -} NETSTATS; - - -void net_stats(NETSTATS *stats); - -int str_toint(const char *str); -float str_tofloat(const char *str); -int str_isspace(char c); -char str_uppercase(char c); -unsigned str_quickhash(const char *str); - -/* - Function: gui_messagebox - Display plain OS-dependent message box - - Parameters: - title - title of the message box - message - text to display -*/ -void gui_messagebox(const char *title, const char *message); - - -/* - Function: str_utf8_rewind - Moves a cursor backwards in an utf8 string - - Parameters: - str - utf8 string - cursor - position in the string - - Returns: - New cursor position. - - Remarks: - - Won't move the cursor less then 0 -*/ -int str_utf8_rewind(const char *str, int cursor); - -/* - Function: str_utf8_forward - Moves a cursor forwards in an utf8 string - - Parameters: - str - utf8 string - cursor - position in the string - - Returns: - New cursor position. - - Remarks: - - Won't move the cursor beyond the zero termination marker -*/ -int str_utf8_forward(const char *str, int cursor); - -/* - Function: str_utf8_decode - Decodes an utf8 character - - Parameters: - ptr - pointer to an utf8 string. this pointer will be moved forward - - Returns: - Unicode value for the character. -1 for invalid characters and 0 for end of string. - - Remarks: - - This function will also move the pointer forward. -*/ -int str_utf8_decode(const char **ptr); - -/* - Function: str_utf8_encode - Encode an utf8 character - - Parameters: - ptr - Pointer to a buffer that should recive the data. Should be able to hold at least 4 bytes. - - Returns: - Number of bytes put into the buffer. - - Remarks: - - Does not do zero termination of the string. -*/ -int str_utf8_encode(char *ptr, int chr); - -/* - Function: str_utf8_check - Checks if a strings contains just valid utf8 characters. - - Parameters: - str - Pointer to a possible utf8 string. - - Returns: - 0 - invalid characters found. - 1 - only valid characters found. - - Remarks: - - The string is treated as zero-terminated utf8 string. -*/ -int str_utf8_check(const char *str); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/server/main.go b/server/main.go new file mode 100644 index 0000000..34adcff --- /dev/null +++ b/server/main.go @@ -0,0 +1,138 @@ +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "net" + "net/http" + "os" + "os/signal" + "path/filepath" + "strconv" + "strings" + "syscall" + "time" +) + +func main() { + var opts Options + var legacyBind string + var legacyPort int + var printVersion bool + + flag.StringVar(&opts.ConfigPath, "config", envOr("CONFIG_PATH", "config.json"), "configuration file") + flag.StringVar(&opts.ConfigPath, "c", envOr("CONFIG_PATH", "config.json"), "configuration file (shorthand)") + flag.StringVar(&opts.StatsPath, "stats", os.Getenv("STATS_PATH"), "persistent stats JSON file") + flag.StringVar(&opts.WebDir, "web-dir", envOr("WEB_DIR", "../web"), "WebUI directory") + flag.StringVar(&opts.WebDir, "d", envOr("WEB_DIR", "../web"), "WebUI directory (shorthand)") + flag.StringVar(&opts.HTTPAddr, "http", envOr("HTTP_ADDR", ":8080"), "HTTP listen address") + flag.StringVar(&opts.AgentAddr, "agent", envOr("AGENT_ADDR", ":35601"), "agent TCP listen address") + flag.StringVar(&legacyBind, "bind", "", "agent bind address (legacy compatibility)") + flag.StringVar(&legacyBind, "b", "", "agent bind address (legacy shorthand)") + flag.IntVar(&legacyPort, "port", 0, "agent TCP port (legacy compatibility)") + flag.IntVar(&legacyPort, "p", 0, "agent TCP port (legacy shorthand)") + flag.BoolVar(&opts.Verbose, "verbose", envBool("VERBOSE", false), "verbose HTTP logging") + flag.BoolVar(&opts.Verbose, "v", envBool("VERBOSE", false), "verbose HTTP logging (shorthand)") + flag.BoolVar(&printVersion, "version", false, "print version and exit") + flag.Parse() + + if printVersion { + fmt.Printf("serverstatus %s commit=%s built=%s\n", version, commit, buildTime) + return + } + if opts.StatsPath == "" { + opts.StatsPath = filepath.Join(opts.WebDir, "json", "stats.json") + } + if legacyPort != 0 || legacyBind != "" { + if legacyPort == 0 { + legacyPort = 35601 + } + opts.AgentAddr = net.JoinHostPort(legacyBind, strconv.Itoa(legacyPort)) + } + opts.AdminToken = os.Getenv("ADMIN_TOKEN") + opts.CORSOrigin = os.Getenv("ADMIN_CORS_ORIGIN") + opts.InsecureCallbackTLS = envBool("INSECURE_CALLBACK_TLS", false) + + if err := os.MkdirAll(filepath.Dir(opts.StatsPath), 0o755); err != nil { + fatalf("create stats directory: %v", err) + } + app, err := NewApp(opts) + if err != nil { + fatalf("start: %v", err) + } + app.StartBackground() + + httpServer := app.HTTPServer() + agentServer := NewAgentServer(app) + errorsChannel := make(chan error, 2) + go func() { + app.logger.Printf("HTTP listening on %s", opts.HTTPAddr) + if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + errorsChannel <- fmt.Errorf("HTTP server: %w", err) + } + }() + go func() { + if err := agentServer.ListenAndServe(); err != nil { + errorsChannel <- fmt.Errorf("agent server: %w", err) + } + }() + + reloadSignals := make(chan os.Signal, 1) + stopSignals := make(chan os.Signal, 1) + signal.Notify(reloadSignals, syscall.SIGHUP) + signal.Notify(stopSignals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + defer signal.Stop(reloadSignals) + defer signal.Stop(stopSignals) + + go func() { + for range reloadSignals { + if apiErr := app.ReloadConfig(); apiErr != nil { + app.logger.Printf("reload config: %s", apiErr.Message) + continue + } + app.logger.Printf("configuration reloaded; generation=%d", app.generation.Load()) + } + }() + + var fatalErr error + select { + case signalValue := <-stopSignals: + app.logger.Printf("received %s; shutting down", signalValue) + case fatalErr = <-errorsChannel: + app.logger.Printf("fatal: %v", fatalErr) + } + app.cancel() + shutdownContext, cancel := context.WithTimeout(context.Background(), 10*time.Second) + _ = httpServer.Shutdown(shutdownContext) + cancel() + app.Close() + if fatalErr != nil { + os.Exit(1) + } +} + +func envOr(name, fallback string) string { + if value := strings.TrimSpace(os.Getenv(name)); value != "" { + return value + } + return fallback +} + +func envBool(name string, fallback bool) bool { + value := strings.TrimSpace(os.Getenv(name)) + if value == "" { + return fallback + } + parsed, err := strconv.ParseBool(value) + if err != nil { + return fallback + } + return parsed +} + +func fatalf(format string, args ...any) { + fmt.Fprintf(os.Stderr, "serverstatus: "+format+"\n", args...) + os.Exit(1) +} diff --git a/server/manage_api.py b/server/manage_api.py deleted file mode 100644 index 2d3a9a3..0000000 --- a/server/manage_api.py +++ /dev/null @@ -1,621 +0,0 @@ -#!/usr/bin/env python3 -import json -import os -import shutil -import signal -import tempfile -import time -import errno -from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer -from urllib.parse import unquote, urlparse - - -CONFIG_PATH = os.environ.get("CONFIG_PATH", "/ServerStatus/server/config.json") -STATS_PATH = os.environ.get("STATS_PATH", "/usr/share/nginx/html/json/stats.json") -SERGATE_PID_FILE = os.environ.get("SERGATE_PID_FILE", "/tmp/serverstatus-sergate.pid") -ADMIN_TOKEN = os.environ.get("ADMIN_TOKEN", "") -API_BIND = os.environ.get("ADMIN_API_BIND", "127.0.0.1") -API_PORT = int(os.environ.get("ADMIN_API_PORT", "35602")) -CORS_ORIGIN = os.environ.get("ADMIN_CORS_ORIGIN", "") - - -class ApiError(Exception): - def __init__(self, status, message, details=None): - super().__init__(message) - self.status = status - self.message = message - self.details = details - - -def load_config(): - with open(CONFIG_PATH, "r", encoding="utf-8") as f: - return json.load(f) - - -def load_json_file(path): - with open(path, "r", encoding="utf-8") as f: - return json.load(f) - - -def load_stats_file(): - try: - return load_json_file(STATS_PATH) - except FileNotFoundError: - return load_json_file(f"{STATS_PATH}~") - - -def write_json_file(path, data): - directory = os.path.dirname(path) or "." - os.makedirs(directory, exist_ok=True) - mode = os.stat(path).st_mode if os.path.exists(path) else 0o644 - payload = json.dumps(data, ensure_ascii=False, indent="\t") + "\n" - fd, tmp_path = tempfile.mkstemp(prefix=".json.", suffix=".tmp", dir=directory) - try: - with os.fdopen(fd, "w", encoding="utf-8") as f: - f.write(payload) - f.flush() - os.fsync(f.fileno()) - os.chmod(tmp_path, mode) - os.replace(tmp_path, path) - finally: - if os.path.exists(tmp_path): - os.unlink(tmp_path) - - -def normalize_required_strings(item, required, kind, index=None): - missing = [field for field in required if item.get(field) is None or not str(item.get(field, "")).strip()] - if missing: - raise ApiError(400, f"{kind} has missing required fields", {"missing": missing, "index": index}) - normalized = dict(item) - for field in required: - normalized[field] = str(normalized[field]).strip() - return normalized - - -def normalize_optional_string(item, field): - value = item.get(field, "") - item[field] = "" if value is None else str(value).strip() - - -def normalize_int(value, field, index=None, default=None, min_value=None, max_value=None): - if value in (None, ""): - value = default - try: - value = int(value) - except (TypeError, ValueError): - raise ApiError(400, f"{field} must be an integer", {"index": index}) - if min_value is not None: - value = max(min_value, value) - if max_value is not None: - value = min(max_value, value) - return value - - -def validate_server(server, index=None): - if not isinstance(server, dict): - raise ApiError(400, "server must be an object", {"index": index}) - required = ["username", "name", "type", "host", "location", "password"] - normalized = normalize_required_strings(server, required, "server", index=index) - normalized["monthstart"] = normalize_int(normalized.get("monthstart"), "monthstart", index=index, default=1, min_value=1, max_value=28) - if "disabled" in normalized: - normalized["disabled"] = bool(normalized["disabled"]) - return normalized - - -def validate_monitor(monitor, index=None): - if not isinstance(monitor, dict): - raise ApiError(400, "monitor must be an object", {"index": index}) - normalized = normalize_required_strings(monitor, ["name", "host", "type"], "monitor", index=index) - normalized["interval"] = normalize_int(normalized.get("interval"), "interval", index=index, default=600, min_value=1) - return normalized - - -def validate_sslcert(sslcert, index=None): - if not isinstance(sslcert, dict): - raise ApiError(400, "sslcert must be an object", {"index": index}) - normalized = normalize_required_strings(sslcert, ["name", "domain"], "sslcert", index=index) - normalized["port"] = normalize_int(normalized.get("port"), "port", index=index, default=443, min_value=1, max_value=65535) - normalized["interval"] = normalize_int(normalized.get("interval"), "interval", index=index, default=7200, min_value=1) - normalize_optional_string(normalized, "callback") - return normalized - - -def validate_watchdog(watchdog, index=None): - if not isinstance(watchdog, dict): - raise ApiError(400, "watchdog must be an object", {"index": index}) - normalized = normalize_required_strings(watchdog, ["name", "rule"], "watchdog", index=index) - normalized["interval"] = normalize_int(normalized.get("interval"), "interval", index=index, default=600, min_value=1) - normalize_optional_string(normalized, "callback") - return normalized - - -COLLECTIONS = { - "servers": { - "item": "server", - "id_field": "username", - "validator": validate_server, - "required": ["username", "name", "type", "host", "location", "password"], - "optional": ["monthstart", "disabled"], - }, - "monitors": { - "item": "monitor", - "id_field": "name", - "validator": validate_monitor, - "required": ["name", "host", "type"], - "optional": ["interval"], - }, - "sslcerts": { - "item": "sslcert", - "id_field": "name", - "validator": validate_sslcert, - "required": ["name", "domain"], - "optional": ["port", "interval", "callback"], - }, - "watchdog": { - "item": "watchdog", - "id_field": "name", - "validator": validate_watchdog, - "required": ["name", "rule"], - "optional": ["interval", "callback"], - }, -} - - -def validate_config(config): - if not isinstance(config, dict): - raise ApiError(400, "config must be a JSON object") - config = dict(config) - for key, meta in COLLECTIONS.items(): - items = config.get(key, []) - if not isinstance(items, list): - raise ApiError(400, f"{key} must be an array") - normalized = [] - seen = set() - for index, item in enumerate(items): - entry = meta["validator"](item, index=index) - if key == "servers": - username = entry["username"] - if username in seen: - raise ApiError(409, "duplicate server username", {"username": username}) - seen.add(username) - normalized.append(entry) - config[key] = normalized - return config - - -def write_config(config): - config = validate_config(config) - directory = os.path.dirname(CONFIG_PATH) or "." - os.makedirs(directory, exist_ok=True) - timestamp = time.strftime("%Y%m%d-%H%M%S") - if os.path.exists(CONFIG_PATH): - shutil.copy2(CONFIG_PATH, f"{CONFIG_PATH}.bak-{timestamp}") - mode = os.stat(CONFIG_PATH).st_mode - else: - mode = 0o644 - data = json.dumps(config, ensure_ascii=False, indent="\t") + "\n" - fd, tmp_path = tempfile.mkstemp(prefix=".config.", suffix=".tmp", dir=directory) - try: - with os.fdopen(fd, "w", encoding="utf-8") as f: - f.write(data) - f.flush() - os.fsync(f.fileno()) - os.chmod(tmp_path, mode) - try: - os.replace(tmp_path, CONFIG_PATH) - except OSError as exc: - if exc.errno != errno.EBUSY: - raise - # A single-file Docker bind mount cannot be atomically replaced. - # Keep the backup above, then rewrite the mounted file in place. - with open(CONFIG_PATH, "w", encoding="utf-8") as f: - f.write(data) - f.flush() - os.fsync(f.fileno()) - finally: - if os.path.exists(tmp_path): - os.unlink(tmp_path) - return config - - -def write_and_reload(config): - config = write_config(config) - pid = signal_sergate(signal.SIGHUP) - return config, pid - - -def read_body(handler): - length = int(handler.headers.get("Content-Length", "0") or "0") - if length <= 0: - return None - if length > 1024 * 1024: - raise ApiError(413, "request body is too large") - raw = handler.rfile.read(length).decode("utf-8") - try: - return json.loads(raw) - except json.JSONDecodeError as exc: - raise ApiError(400, "invalid JSON body", {"error": str(exc)}) - - -def get_sergate_pid(): - try: - with open(SERGATE_PID_FILE, "r", encoding="utf-8") as f: - pid = int(f.read().strip()) - os.kill(pid, 0) - return pid - except Exception: - pass - proc_dir = "/proc" - if not os.path.isdir(proc_dir): - return None - for name in os.listdir(proc_dir): - if not name.isdigit(): - continue - try: - with open(os.path.join(proc_dir, name, "cmdline"), "rb") as f: - cmdline = f.read().replace(b"\x00", b" ").decode("utf-8", "ignore") - except Exception: - continue - if "sergate" in cmdline: - return int(name) - return None - - -def signal_sergate(sig): - pid = get_sergate_pid() - if not pid: - raise ApiError(503, "sergate process was not found") - os.kill(pid, sig) - return pid - - -def wait_for_pid_exit(pid, timeout=2.5): - deadline = time.time() + timeout - while time.time() < deadline: - try: - os.kill(pid, 0) - except OSError: - return True - time.sleep(0.05) - return False - - -def wait_for_sergate_pid(previous_pid=None, timeout=4.0): - deadline = time.time() + timeout - while time.time() < deadline: - pid = get_sergate_pid() - if pid and pid != previous_pid: - return pid - time.sleep(0.1) - return get_sergate_pid() - - -def find_server(config, username): - servers = config.get("servers", []) - for index, server in enumerate(servers): - if server.get("username") == username: - return index, server - return -1, None - - -def find_collection_item(config, key, item_id): - items = config.get(key, []) - if item_id.isdigit(): - index = int(item_id) - if 0 <= index < len(items): - return index, items[index] - return -1, None - id_field = COLLECTIONS[key]["id_field"] - matches = [(index, item) for index, item in enumerate(items) if str(item.get(id_field, "")) == item_id] - if len(matches) > 1: - raise ApiError(409, f"{key} has duplicate {id_field}; use numeric index instead", {"id": item_id}) - if matches: - return matches[0] - return -1, None - - -def stats_server_matches(config_server, stats_server): - return all(str(stats_server.get(field, "")) == str(config_server.get(field, "")) for field in ["name", "type", "host", "location"]) - - -def find_stats_server(stats, config_server): - servers = stats.get("servers", []) - if not isinstance(servers, list): - raise ApiError(500, "stats.json has invalid servers data") - for index, stats_server in enumerate(servers): - if isinstance(stats_server, dict) and stats_server_matches(config_server, stats_server): - return index, stats_server - return -1, None - - -def as_counter(value, field): - try: - return int(value) - except (TypeError, ValueError): - raise ApiError(409, f"{field} is missing or invalid in stats.json") - - -def require_resettable_stats(stats, server, username): - stats_index, stats_server = find_stats_server(stats, server) - if stats_index < 0: - raise ApiError(404, "server stats were not found", {"username": username}) - if "network_in" not in stats_server or "network_out" not in stats_server: - raise ApiError(409, "server has no current traffic counters; it may be offline", {"username": username}) - return stats_index, stats_server - - -def reset_server_month_traffic(username): - config = load_config() - _, server = find_server(config, username) - if server is None: - raise ApiError(404, "server was not found", {"username": username}) - - require_resettable_stats(load_stats_file(), server, username) - - old_pid = signal_sergate(signal.SIGTERM) - wait_for_pid_exit(old_pid) - - stats = load_stats_file() - stats_index, stats_server = require_resettable_stats(stats, server, username) - - network_in = as_counter(stats_server.get("network_in"), "network_in") - network_out = as_counter(stats_server.get("network_out"), "network_out") - previous_last_in = as_counter(stats_server.get("last_network_in", 0), "last_network_in") - previous_last_out = as_counter(stats_server.get("last_network_out", 0), "last_network_out") - - stats["servers"][stats_index]["last_network_in"] = network_in - stats["servers"][stats_index]["last_network_out"] = network_out - stats["updated"] = str(int(time.time())) - write_json_file(STATS_PATH, stats) - - new_pid = wait_for_sergate_pid(previous_pid=old_pid) - if new_pid: - os.kill(new_pid, signal.SIGHUP) - - return { - "server": server, - "stats": { - "network_in": network_in, - "network_out": network_out, - "previous_last_network_in": previous_last_in, - "previous_last_network_out": previous_last_out, - "last_network_in": network_in, - "last_network_out": network_out, - "month_in_before": max(0, network_in - previous_last_in), - "month_out_before": max(0, network_out - previous_last_out), - }, - "oldPid": old_pid, - "pid": new_pid, - } - - -def collection_routes(): - endpoints = [] - for key in ["monitors", "sslcerts", "watchdog"]: - endpoints.extend([ - {"method": "GET", "path": f"/api/{key}", "auth": True}, - {"method": "POST", "path": f"/api/{key}", "auth": True, "body": f"{COLLECTIONS[key]['item']} JSON"}, - {"method": "PUT", "path": f"/api/{key}/{{index-or-name}}", "auth": True, "body": f"{COLLECTIONS[key]['item']} JSON"}, - {"method": "DELETE", "path": f"/api/{key}/{{index-or-name}}", "auth": True}, - ]) - return endpoints - - -def api_schema(): - return { - "auth": { - "type": "bearer", - "header": "Authorization: Bearer ", - "enabled": bool(ADMIN_TOKEN), - }, - "endpoints": [ - {"method": "GET", "path": "/api/health", "auth": False}, - {"method": "GET", "path": "/api/schema", "auth": False}, - {"method": "GET", "path": "/api/config", "auth": True}, - {"method": "PUT", "path": "/api/config", "auth": True, "body": "full config JSON"}, - {"method": "GET", "path": "/api/servers", "auth": True}, - {"method": "POST", "path": "/api/servers", "auth": True, "body": "server JSON"}, - {"method": "PUT", "path": "/api/servers/{username}", "auth": True, "body": "server JSON"}, - {"method": "DELETE", "path": "/api/servers/{username}", "auth": True}, - {"method": "POST", "path": "/api/servers/{username}/reset-traffic", "auth": True}, - *collection_routes(), - {"method": "POST", "path": "/api/reload", "auth": True}, - {"method": "POST", "path": "/api/restart", "auth": True}, - ], - "collections": { - key: { - "item": meta["item"], - "idField": meta["id_field"], - "required": meta["required"], - "optional": meta["optional"], - } - for key, meta in COLLECTIONS.items() - }, - } - - -class Handler(BaseHTTPRequestHandler): - server_version = "ServerStatusManageAPI/1.0" - - def log_message(self, fmt, *args): - print("%s - %s" % (self.address_string(), fmt % args), flush=True) - - def end_headers(self): - self.send_header("Cache-Control", "no-store") - if CORS_ORIGIN: - self.send_header("Access-Control-Allow-Origin", CORS_ORIGIN) - self.send_header("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Admin-Token") - self.send_header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") - super().end_headers() - - def send_json(self, status, payload): - data = json.dumps(payload, ensure_ascii=False).encode("utf-8") - self.send_response(status) - self.send_header("Content-Type", "application/json; charset=utf-8") - self.send_header("Content-Length", str(len(data))) - self.end_headers() - self.wfile.write(data) - - def send_error_json(self, err): - payload = {"ok": False, "error": err.message} - if err.details is not None: - payload["details"] = err.details - self.send_json(err.status, payload) - - def route(self): - parsed = urlparse(self.path) - path = parsed.path.rstrip("/") or "/" - method = self.command.upper() - if method == "OPTIONS": - self.send_response(204) - self.end_headers() - return - try: - if path == "/api/health" and method == "GET": - pid = get_sergate_pid() - self.send_json(200, { - "ok": True, - "enabled": bool(ADMIN_TOKEN), - "sergate": {"running": bool(pid), "pid": pid}, - "configPath": CONFIG_PATH, - }) - return - if path == "/api/schema" and method == "GET": - self.send_json(200, {"ok": True, "schema": api_schema()}) - return - self.require_auth() - if path == "/api/config": - if method == "GET": - self.send_json(200, {"ok": True, "config": load_config()}) - return - if method == "PUT": - config = read_body(self) - config, pid = write_and_reload(config) - self.send_json(200, {"ok": True, "reloaded": True, "pid": pid, "config": config}) - return - if path == "/api/servers": - if method == "GET": - config = load_config() - self.send_json(200, {"ok": True, "servers": config.get("servers", [])}) - return - if method == "POST": - server = validate_server(read_body(self)) - config = load_config() - if find_server(config, server["username"])[1] is not None: - raise ApiError(409, "server username already exists", {"username": server["username"]}) - config.setdefault("servers", []).append(server) - config, pid = write_and_reload(config) - self.send_json(201, {"ok": True, "server": server, "reloaded": True, "pid": pid, "config": config}) - return - if path.startswith("/api/servers/") and path.endswith("/reset-traffic"): - username = unquote(path[len("/api/servers/"):-len("/reset-traffic")].rstrip("/")) - if not username: - raise ApiError(400, "username is required") - if method == "POST": - result = reset_server_month_traffic(username) - self.send_json(200, {"ok": True, "operation": "reset-traffic", **result}) - return - if path.startswith("/api/servers/"): - username = unquote(path[len("/api/servers/"):]) - if not username: - raise ApiError(400, "username is required") - config = load_config() - index, existing = find_server(config, username) - if index < 0: - raise ApiError(404, "server was not found", {"username": username}) - if method == "PUT": - server = validate_server(read_body(self)) - if server["username"] != username and find_server(config, server["username"])[1] is not None: - raise ApiError(409, "server username already exists", {"username": server["username"]}) - config["servers"][index] = server - config, pid = write_and_reload(config) - self.send_json(200, {"ok": True, "server": server, "reloaded": True, "pid": pid, "config": config}) - return - if method == "DELETE": - removed = config["servers"].pop(index) - config, pid = write_and_reload(config) - self.send_json(200, {"ok": True, "removed": removed, "reloaded": True, "pid": pid, "config": config}) - return - for key in ["monitors", "sslcerts", "watchdog"]: - base = f"/api/{key}" - meta = COLLECTIONS[key] - if path == base: - if method == "GET": - config = load_config() - self.send_json(200, {"ok": True, key: config.get(key, [])}) - return - if method == "POST": - item = meta["validator"](read_body(self)) - config = load_config() - config.setdefault(key, []).append(item) - config, pid = write_and_reload(config) - self.send_json(201, {"ok": True, meta["item"]: item, "reloaded": True, "pid": pid, "config": config}) - return - if path.startswith(base + "/"): - item_id = unquote(path[len(base) + 1:]) - if not item_id: - raise ApiError(400, "item id is required") - config = load_config() - index, existing = find_collection_item(config, key, item_id) - if index < 0: - raise ApiError(404, f"{meta['item']} was not found", {"id": item_id}) - if method == "PUT": - item = meta["validator"](read_body(self)) - config[key][index] = item - config, pid = write_and_reload(config) - self.send_json(200, {"ok": True, meta["item"]: item, "reloaded": True, "pid": pid, "config": config}) - return - if method == "DELETE": - removed = config[key].pop(index) - config, pid = write_and_reload(config) - self.send_json(200, {"ok": True, "removed": removed, "reloaded": True, "pid": pid, "config": config}) - return - if path == "/api/reload" and method == "POST": - pid = signal_sergate(signal.SIGHUP) - self.send_json(200, {"ok": True, "operation": "reload", "pid": pid}) - return - if path == "/api/restart" and method == "POST": - pid = signal_sergate(signal.SIGTERM) - self.send_json(202, {"ok": True, "operation": "restart", "pid": pid}) - return - raise ApiError(404, "endpoint was not found") - except ApiError as err: - self.send_error_json(err) - except Exception as exc: - self.send_error_json(ApiError(500, "internal server error", {"error": str(exc)})) - - def require_auth(self): - if not ADMIN_TOKEN: - raise ApiError(503, "management API is disabled; set ADMIN_TOKEN to enable it") - auth = self.headers.get("Authorization", "") - token = "" - if auth.lower().startswith("bearer "): - token = auth[7:].strip() - token = token or self.headers.get("X-Admin-Token", "").strip() - if token != ADMIN_TOKEN: - raise ApiError(401, "invalid or missing admin token") - - def do_GET(self): - self.route() - - def do_POST(self): - self.route() - - def do_PUT(self): - self.route() - - def do_DELETE(self): - self.route() - - def do_OPTIONS(self): - self.route() - - -def main(): - httpd = ThreadingHTTPServer((API_BIND, API_PORT), Handler) - print(f"manage-api listening on {API_BIND}:{API_PORT}", flush=True) - httpd.serve_forever() - - -if __name__ == "__main__": - main() diff --git a/server/model.go b/server/model.go new file mode 100644 index 0000000..7a07fd9 --- /dev/null +++ b/server/model.go @@ -0,0 +1,367 @@ +package main + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "math" + "strconv" + "strings" + "time" + + "github.com/expr-lang/expr/vm" +) + +const maxRequestBody = 1 << 20 + +type ConfigDocument map[string]any + +type ServerConfig struct { + Username string `json:"username"` + Name string `json:"name"` + Type string `json:"type"` + Host string `json:"host"` + Location string `json:"location"` + Password string `json:"password"` + MonthStart int `json:"monthstart"` + Disabled bool `json:"disabled,omitempty"` +} + +type MonitorConfig struct { + Name string `json:"name"` + Host string `json:"host"` + Interval int `json:"interval"` + Type string `json:"type"` +} + +type SSLCertConfig struct { + Name string `json:"name"` + Domain string `json:"domain"` + Port int `json:"port"` + Interval int `json:"interval"` + Callback string `json:"callback"` +} + +type WatchdogConfig struct { + Name string `json:"name"` + Rule string `json:"rule"` + Interval int `json:"interval"` + Callback string `json:"callback"` +} + +type CompiledWatchdog struct { + WatchdogConfig + Key string + Normalized string + Program *vm.Program +} + +type RuntimeConfig struct { + Servers []ServerConfig + Monitors []MonitorConfig + SSLCerts []SSLCertConfig + Watchdogs []CompiledWatchdog +} + +type AgentStats struct { + Uptime int64 `json:"uptime"` + Load1 float64 `json:"load_1"` + Load5 float64 `json:"load_5"` + Load15 float64 `json:"load_15"` + Ping10010 float64 `json:"ping_10010"` + Ping189 float64 `json:"ping_189"` + Ping10086 float64 `json:"ping_10086"` + Time10010 int64 `json:"time_10010"` + Time189 int64 `json:"time_189"` + Time10086 int64 `json:"time_10086"` + TCPCount int64 `json:"tcp"` + UDPCount int64 `json:"udp"` + ProcessCount int64 `json:"process"` + ThreadCount int64 `json:"thread"` + NetworkRX int64 `json:"network_rx"` + NetworkTX int64 `json:"network_tx"` + NetworkIn int64 `json:"network_in"` + NetworkOut int64 `json:"network_out"` + MemoryTotal int64 `json:"memory_total"` + MemoryUsed int64 `json:"memory_used"` + SwapTotal int64 `json:"swap_total"` + SwapUsed int64 `json:"swap_used"` + HDDTotal int64 `json:"hdd_total"` + HDDUsed int64 `json:"hdd_used"` + IORead int64 `json:"io_read"` + IOWrite int64 `json:"io_write"` + CPU float64 `json:"cpu"` + CPUCores int64 `json:"cpu_cores"` + CPUModel string `json:"cpu_model"` + Custom string `json:"custom"` + OS string `json:"os"` + Online4 *bool `json:"online4"` + Online6 *bool `json:"online6"` +} + +type APIError struct { + Status int + Message string + Details any +} + +func (e *APIError) Error() string { + if e.Details != nil { + return fmt.Sprintf("%s: %v", e.Message, e.Details) + } + return e.Message +} + +func decodeDocument(data []byte) (ConfigDocument, error) { + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.UseNumber() + var doc ConfigDocument + if err := decoder.Decode(&doc); err != nil { + return nil, err + } + if doc == nil { + return nil, fmt.Errorf("config must be a JSON object") + } + var extra any + if err := decoder.Decode(&extra); !errors.Is(err, io.EOF) { + return nil, fmt.Errorf("config contains more than one JSON value") + } + return doc, nil +} + +func cloneDocument(doc ConfigDocument) (ConfigDocument, error) { + data, err := json.Marshal(doc) + if err != nil { + return nil, err + } + return decodeDocument(data) +} + +type collectionSpec struct { + itemName string + idField string + required []string + optional []string + defaults map[string]int +} + +var collectionSpecs = map[string]collectionSpec{ + "servers": { + itemName: "server", idField: "username", + required: []string{"username", "name", "type", "host", "location", "password"}, + optional: []string{"monthstart", "disabled"}, + defaults: map[string]int{"monthstart": 1}, + }, + "monitors": { + itemName: "monitor", idField: "name", + required: []string{"name", "host", "type"}, + optional: []string{"interval"}, + defaults: map[string]int{"interval": 600}, + }, + "sslcerts": { + itemName: "sslcert", idField: "name", + required: []string{"name", "domain"}, + optional: []string{"port", "interval", "callback"}, + defaults: map[string]int{"port": 443, "interval": 7200}, + }, + "watchdog": { + itemName: "watchdog", idField: "name", + required: []string{"name", "rule"}, + optional: []string{"interval", "callback"}, + defaults: map[string]int{"interval": 600}, + }, +} + +func normalizeConfig(input ConfigDocument) (ConfigDocument, RuntimeConfig, *APIError) { + doc, err := cloneDocument(input) + if err != nil { + return nil, RuntimeConfig{}, &APIError{Status: 400, Message: "config must be a JSON object", Details: map[string]any{"error": err.Error()}} + } + + for _, key := range []string{"servers", "monitors", "sslcerts", "watchdog"} { + spec := collectionSpecs[key] + raw, exists := doc[key] + if !exists || raw == nil { + raw = []any{} + } + items, ok := raw.([]any) + if !ok { + return nil, RuntimeConfig{}, &APIError{Status: 400, Message: key + " must be an array"} + } + normalized := make([]any, 0, len(items)) + seen := make(map[string]struct{}) + for index, rawItem := range items { + item, ok := rawItem.(map[string]any) + if !ok { + return nil, RuntimeConfig{}, &APIError{Status: 400, Message: spec.itemName + " must be an object", Details: map[string]any{"index": index}} + } + missing := make([]string, 0) + for _, field := range spec.required { + value, ok := item[field] + text := "" + if ok && value != nil { + text = strings.TrimSpace(fmt.Sprint(value)) + } + if text == "" { + missing = append(missing, field) + } else { + item[field] = text + } + } + if len(missing) > 0 { + return nil, RuntimeConfig{}, &APIError{Status: 400, Message: spec.itemName + " has missing required fields", Details: map[string]any{"missing": missing, "index": index}} + } + + for field, fallback := range spec.defaults { + value, apiErr := normalizeInteger(item[field], field, index, fallback) + if apiErr != nil { + return nil, RuntimeConfig{}, apiErr + } + switch { + case key == "servers" && field == "monthstart": + value = clamp(value, 1, 28) + case key == "sslcerts" && field == "port": + value = clamp(value, 1, 65535) + default: + if value < 1 { + value = 1 + } + } + item[field] = value + } + + if key == "servers" { + if value, exists := item["disabled"]; exists { + disabled, ok := normalizeBool(value) + if !ok { + return nil, RuntimeConfig{}, &APIError{Status: 400, Message: "disabled must be a boolean", Details: map[string]any{"index": index}} + } + item["disabled"] = disabled + } + username := item["username"].(string) + if _, duplicate := seen[username]; duplicate { + return nil, RuntimeConfig{}, &APIError{Status: 409, Message: "duplicate server username", Details: map[string]any{"username": username}} + } + seen[username] = struct{}{} + } + if key == "sslcerts" || key == "watchdog" { + value := item["callback"] + if value == nil { + item["callback"] = "" + } else { + item["callback"] = strings.TrimSpace(fmt.Sprint(value)) + } + } + normalized = append(normalized, item) + } + doc[key] = normalized + } + + runtime, apiErr := buildRuntimeConfig(doc) + if apiErr != nil { + return nil, RuntimeConfig{}, apiErr + } + return doc, runtime, nil +} + +func buildRuntimeConfig(doc ConfigDocument) (RuntimeConfig, *APIError) { + data, err := json.Marshal(doc) + if err != nil { + return RuntimeConfig{}, &APIError{Status: 400, Message: "config could not be encoded", Details: map[string]any{"error": err.Error()}} + } + var raw struct { + Servers []ServerConfig `json:"servers"` + Monitors []MonitorConfig `json:"monitors"` + SSLCerts []SSLCertConfig `json:"sslcerts"` + Watchdogs []WatchdogConfig `json:"watchdog"` + } + if err := json.Unmarshal(data, &raw); err != nil { + return RuntimeConfig{}, &APIError{Status: 400, Message: "config has invalid field types", Details: map[string]any{"error": err.Error()}} + } + runtime := RuntimeConfig{Servers: raw.Servers, Monitors: raw.Monitors, SSLCerts: raw.SSLCerts} + for index, rule := range raw.Watchdogs { + compiled, err := compileWatchdog(rule, index) + if err != nil { + return RuntimeConfig{}, &APIError{Status: 400, Message: "watchdog rule is invalid", Details: map[string]any{"index": index, "name": rule.Name, "error": err.Error()}} + } + runtime.Watchdogs = append(runtime.Watchdogs, compiled) + } + return runtime, nil +} + +func normalizeInteger(raw any, field string, index, fallback int) (int, *APIError) { + if raw == nil || raw == "" { + return fallback, nil + } + var value int64 + var err error + switch v := raw.(type) { + case json.Number: + value, err = strconv.ParseInt(v.String(), 10, 64) + case float64: + if math.Trunc(v) != v { + err = fmt.Errorf("not an integer") + } else { + value = int64(v) + } + case float32: + if math.Trunc(float64(v)) != float64(v) { + err = fmt.Errorf("not an integer") + } else { + value = int64(v) + } + case int: + value = int64(v) + case int64: + value = v + case string: + value, err = strconv.ParseInt(strings.TrimSpace(v), 10, 64) + default: + err = fmt.Errorf("unsupported value") + } + if err != nil || value > math.MaxInt || value < math.MinInt { + return 0, &APIError{Status: 400, Message: field + " must be an integer", Details: map[string]any{"index": index}} + } + return int(value), nil +} + +func normalizeBool(raw any) (bool, bool) { + switch value := raw.(type) { + case bool: + return value, true + case string: + parsed, err := strconv.ParseBool(strings.TrimSpace(value)) + return parsed, err == nil + case json.Number: + if value.String() == "0" { + return false, true + } + if value.String() == "1" { + return true, true + } + } + return false, false +} + +func clamp(value, minimum, maximum int) int { + if value < minimum { + return minimum + } + if value > maximum { + return maximum + } + return value +} + +func secondsDuration(value int) time.Duration { + if value < 1 { + value = 1 + } + maxDuration := time.Duration(1<<63 - 1) + if int64(value) > int64(maxDuration/time.Second) { + return maxDuration + } + return time.Duration(value) * time.Second +} diff --git a/server/model_test.go b/server/model_test.go new file mode 100644 index 0000000..8942f7e --- /dev/null +++ b/server/model_test.go @@ -0,0 +1,85 @@ +package main + +import ( + "encoding/json" + "strings" + "testing" + "time" + + "github.com/expr-lang/expr" +) + +func TestNormalizeConfigPreservesCompatibility(t *testing.T) { + doc := minimalTestConfig() + doc["future"] = map[string]any{"enabled": true} + doc["watchdog"] = []any{ + map[string]any{"name": "legacy", "rule": "cpu>90&load_1>5&username!='s01'", "interval": "600", "callback": nil}, + map[string]any{"name": "type", "rule": "tcp_count>600&type='Oracle'", "interval": 60}, + } + doc["servers"].([]any)[0].(map[string]any)["future_field"] = "kept" + + normalized, runtime, apiErr := normalizeConfig(doc) + if apiErr != nil { + t.Fatal(apiErr) + } + if len(runtime.Watchdogs) != 2 || runtime.Watchdogs[0].Normalized != "cpu>90&&load_1>5&&username!='s01'" { + t.Fatalf("legacy rules were not normalized: %#v", runtime.Watchdogs) + } + server := normalized["servers"].([]any)[0].(map[string]any) + if server["future_field"] != "kept" || normalized["future"] == nil { + t.Fatal("unknown config fields were discarded") + } + if server["monthstart"] != json.Number("1") && server["monthstart"] != 1 { + t.Fatalf("monthstart not normalized: %#v", server["monthstart"]) + } +} + +func TestWatchdogLegacyRulesEvaluate(t *testing.T) { + rules := []string{ + "online4=0&online6=0", + "(memory_used/memory_total)*100>90&memory_total>1048576", + "tcp_count>600&type='Oracle'", + "(network_out-last_network_out)/1024/1024/1024>18&(username='aliyun1'|username='aliyun2')", + } + for index, rule := range rules { + compiled, err := compileWatchdog(WatchdogConfig{Name: "test", Rule: rule, Interval: 1}, index) + if err != nil { + t.Fatalf("rule %q: %v", rule, err) + } + environment := watchdogEnvironment(ServerConfig{Username: "aliyun1", Type: "Oracle"}, AgentStats{MemoryTotal: 2_000_000, MemoryUsed: 1_900_000, TCPCount: 700, NetworkOut: 30 << 30}, false, false, 0, 0) + if _, err := expr.Run(compiled.Program, environment); err != nil { + t.Fatalf("run %q: %v", rule, err) + } + } +} + +func TestConfigValidationErrors(t *testing.T) { + doc := minimalTestConfig() + doc["servers"] = append(doc["servers"].([]any), doc["servers"].([]any)[0]) + _, _, apiErr := normalizeConfig(doc) + if apiErr == nil || apiErr.Status != 409 { + t.Fatalf("expected duplicate username error, got %#v", apiErr) + } + + if _, err := decodeDocument([]byte(`{"servers":[]} {"servers":[]}`)); err == nil || !strings.Contains(err.Error(), "more than one") { + t.Fatalf("expected trailing JSON error, got %v", err) + } +} + +func TestFormattingHelpers(t *testing.T) { + if got := formatUptime(90061); got != "1 天" { + t.Fatalf("formatUptime=%q", got) + } + if got := formatUptime(3661); got != "01:01:01" { + t.Fatalf("formatUptime=%q", got) + } + if got, err := certificateHost("https://example.com/path"); err != nil || got != "example.com" { + t.Fatalf("certificateHost=%q", got) + } + if got := secondsDuration(0); got != time.Second { + t.Fatalf("secondsDuration(0)=%s", got) + } + if got := secondsDuration(int(^uint(0) >> 1)); got < 365*24*time.Hour { + t.Fatalf("large interval overflowed or was truncated: %s", got) + } +} diff --git a/server/nginx-serverstatus.conf b/server/nginx-serverstatus.conf deleted file mode 100644 index 0333173..0000000 --- a/server/nginx-serverstatus.conf +++ /dev/null @@ -1,26 +0,0 @@ -server { - listen 80; - server_name _; - - root /usr/share/nginx/html; - index index.html; - - location / { - try_files $uri $uri/ =404; - } - - location /json/ { - add_header Cache-Control "no-store"; - try_files $uri =404; - } - - location /api/ { - proxy_pass http://127.0.0.1:35602; - proxy_http_version 1.1; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_read_timeout 30s; - } -} diff --git a/server/obj/.gitignore b/server/obj/.gitignore deleted file mode 100644 index 1530978..0000000 --- a/server/obj/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.o \ No newline at end of file diff --git a/server/openapi.go b/server/openapi.go new file mode 100644 index 0000000..7f0c6ba --- /dev/null +++ b/server/openapi.go @@ -0,0 +1,223 @@ +package main + +import "strings" + +func openAPISpec() map[string]any { + paths := map[string]any{ + "/api/health": map[string]any{ + "get": publicOperation("health", "服务健康状态", objectResponse("Go 服务、Agent TCP 与配置状态")), + }, + "/api/schema": map[string]any{ + "get": publicOperation("schema", "ServerStatus API 简表", objectResponse("端点和集合描述")), + }, + "/api/openapi.json": map[string]any{ + "get": publicOperation("openapi", "OpenAPI 3.1 文档", objectResponse("OpenAPI document")), + }, + "/json/stats.json": map[string]any{ + "get": publicOperation("stats", "实时状态快照", objectResponse("WebUI 状态数据")), + }, + "/api/config": map[string]any{ + "get": protectedOperation("getConfig", "读取完整配置", nil, configResponse("200", "配置文档")), + "put": protectedOperation("replaceConfig", "整体校验并替换配置", requestBody("Config"), configResponse("200", "已保存并热重载的配置")), + }, + "/api/reload": map[string]any{ + "post": protectedOperation("reloadConfig", "从磁盘热重载配置", nil, objectResponse("重载结果")), + }, + "/api/restart": map[string]any{ + "post": protectedOperation("restartRuntime", "在进程内重启采集运行时", nil, statusResponse("202", "重启结果", map[string]any{ + "operation": map[string]any{"type": "string", "const": "restart"}, + "mode": map[string]any{"type": "string", "const": "in-process"}, + })), + }, + "/api/servers/{username}/reset-traffic": map[string]any{ + "post": withParameters(protectedOperation("resetServerTraffic", "重置节点本月流量基线", nil, objectResponse("流量重置结果")), pathParameter("username", "节点用户名")), + }, + } + + for _, key := range []string{"servers", "monitors", "sslcerts", "watchdog"} { + spec := collectionSpecs[key] + schemaName := map[string]string{"servers": "Server", "monitors": "Monitor", "sslcerts": "SSLCert", "watchdog": "Watchdog"}[key] + operationBase := strings.TrimSuffix(key, "s") + if key == "sslcerts" { + operationBase = "sslcert" + } + paths["/api/"+key] = map[string]any{ + "get": protectedOperation("list"+titleWord(key), "查询 "+key, nil, collectionResponse(key, schemaName, "配置集合")), + "post": protectedOperation("create"+titleWord(operationBase), "新增 "+spec.itemName, requestBody(schemaName), itemResponse("201", spec.itemName, schemaName, "创建结果")), + } + parameterName := "id" + parameterDescription := "数字下标或唯一的 " + spec.idField + if key == "servers" { + parameterName = "username" + parameterDescription = "节点用户名" + } + paths["/api/"+key+"/{"+parameterName+"}"] = map[string]any{ + "put": withParameters(protectedOperation("update"+titleWord(operationBase), "修改 "+spec.itemName, requestBody(schemaName), itemResponse("200", spec.itemName, schemaName, "修改结果")), pathParameter(parameterName, parameterDescription)), + "delete": withParameters(protectedOperation("delete"+titleWord(operationBase), "删除 "+spec.itemName, nil, itemResponse("200", "removed", schemaName, "删除结果")), pathParameter(parameterName, parameterDescription)), + } + } + + return map[string]any{ + "openapi": "3.1.0", + "info": map[string]any{ + "title": "ServerStatus HTTP API", + "version": version, + "description": "单进程 Go ServerStatus 的配置、运行状态和采集控制 API。", + }, + "servers": []any{map[string]any{"url": "/", "description": "当前 ServerStatus 实例"}}, + "paths": paths, + "components": map[string]any{ + "securitySchemes": map[string]any{ + "bearerAuth": map[string]any{"type": "http", "scheme": "bearer", "bearerFormat": "ADMIN_TOKEN"}, + }, + "schemas": openAPISchemas(), + }, + } +} + +func openAPISchemas() map[string]any { + stringProperty := func(description string) map[string]any { + return map[string]any{"type": "string", "description": description} + } + integerProperty := func(description string, minimum, maximum int) map[string]any { + property := map[string]any{"type": "integer", "description": description, "minimum": minimum} + if maximum > 0 { + property["maximum"] = maximum + } + return property + } + server := map[string]any{ + "type": "object", "required": collectionSpecs["servers"].required, + "properties": map[string]any{ + "username": stringProperty("唯一客户端用户名"), "name": stringProperty("节点显示名称"), + "type": stringProperty("虚拟化或节点类型"), "host": stringProperty("主机标识"), + "location": stringProperty("位置"), "password": stringProperty("客户端密码"), + "monthstart": integerProperty("月流量重置日", 1, 28), "disabled": map[string]any{"type": "boolean", "default": false}, + }, + } + monitor := map[string]any{ + "type": "object", "required": collectionSpecs["monitors"].required, + "properties": map[string]any{ + "name": stringProperty("监测名称"), "host": stringProperty("HTTP(S) URL 或 TCP 地址"), + "type": stringProperty("https、http 或 tcp"), "interval": integerProperty("客户端探测间隔秒数", 1, 0), + }, + } + sslcert := map[string]any{ + "type": "object", "required": collectionSpecs["sslcerts"].required, + "properties": map[string]any{ + "name": stringProperty("证书名称"), "domain": stringProperty("域名或 URL"), + "port": integerProperty("TLS 端口", 1, 65535), "interval": integerProperty("检查间隔秒数", 1, 0), + "callback": stringProperty("告警回调 URL 前缀"), + }, + } + watchdog := map[string]any{ + "type": "object", "required": collectionSpecs["watchdog"].required, + "properties": map[string]any{ + "name": stringProperty("告警名称"), "rule": stringProperty("兼容 Exprtk 的状态表达式"), + "interval": integerProperty("通知冷却秒数", 1, 0), "callback": stringProperty("告警回调 URL 前缀"), + }, + } + return map[string]any{ + "Server": server, "Monitor": monitor, "SSLCert": sslcert, "Watchdog": watchdog, + "Config": map[string]any{ + "type": "object", "required": []string{"servers", "monitors", "sslcerts", "watchdog"}, + "properties": map[string]any{ + "servers": arraySchema("Server"), "monitors": arraySchema("Monitor"), + "sslcerts": arraySchema("SSLCert"), "watchdog": arraySchema("Watchdog"), + }, + }, + "Error": map[string]any{ + "type": "object", "required": []string{"ok", "error"}, + "properties": map[string]any{"ok": map[string]any{"type": "boolean", "const": false}, "error": map[string]any{"type": "string"}, "details": map[string]any{}}, + }, + } +} + +func titleWord(value string) string { + if value == "" { + return "" + } + return strings.ToUpper(value[:1]) + value[1:] +} + +func schemaRef(name string) map[string]any { + return map[string]any{"$ref": "#/components/schemas/" + name} +} +func arraySchema(name string) map[string]any { + return map[string]any{"type": "array", "items": schemaRef(name)} +} + +func requestBody(schemaName string) map[string]any { + return map[string]any{ + "required": true, + "content": map[string]any{"application/json": map[string]any{"schema": schemaRef(schemaName)}}, + } +} + +func objectResponse(description string) map[string]any { + return map[string]any{"200": jsonResponse(description, map[string]any{"type": "object"}), "4XX": jsonResponse("请求错误", schemaRef("Error"))} +} + +func configResponse(status, description string) map[string]any { + return statusResponse(status, description, map[string]any{"config": schemaRef("Config")}) +} + +func collectionResponse(key, schemaName, description string) map[string]any { + return statusResponse("200", description, map[string]any{key: arraySchema(schemaName)}) +} + +func itemResponse(status, key, schemaName, description string) map[string]any { + return statusResponse(status, description, map[string]any{ + key: schemaRef(schemaName), + "reloaded": map[string]any{"type": "boolean", "const": true}, + "pid": map[string]any{"type": "integer", "minimum": 1}, + "config": schemaRef("Config"), + }) +} + +func statusResponse(status, description string, properties map[string]any) map[string]any { + required := []string{"ok"} + allProperties := map[string]any{"ok": map[string]any{"type": "boolean", "const": true}} + for key, property := range properties { + allProperties[key] = property + required = append(required, key) + } + return map[string]any{ + status: jsonResponse(description, map[string]any{ + "type": "object", "required": required, "properties": allProperties, + }), + "4XX": jsonResponse("请求错误", schemaRef("Error")), + } +} + +func jsonResponse(description string, schema map[string]any) map[string]any { + return map[string]any{"description": description, "content": map[string]any{"application/json": map[string]any{"schema": schema}}} +} + +func publicOperation(operationID, summary string, responses map[string]any) map[string]any { + return map[string]any{"operationId": operationID, "summary": summary, "security": []any{}, "responses": responses} +} + +func protectedOperation(operationID, summary string, body map[string]any, responses map[string]any) map[string]any { + operation := map[string]any{ + "operationId": operationID, "summary": summary, + "security": []any{map[string]any{"bearerAuth": []any{}}}, "responses": responses, + } + if body != nil { + operation["requestBody"] = body + } + return operation +} + +func withParameters(operation map[string]any, parameters ...map[string]any) map[string]any { + items := make([]any, 0, len(parameters)) + for _, parameter := range parameters { + items = append(items, parameter) + } + operation["parameters"] = items + return operation +} + +func pathParameter(name, description string) map[string]any { + return map[string]any{"name": name, "in": "path", "required": true, "description": description, "schema": map[string]any{"type": "string"}} +} diff --git a/server/src/argparse.c b/server/src/argparse.c deleted file mode 100644 index b581a2f..0000000 --- a/server/src/argparse.c +++ /dev/null @@ -1,322 +0,0 @@ -#include "argparse.h" - -#if defined(__cplusplus) -extern "C" { -#endif - -#define OPT_UNSET 1 - -static const char * -prefix_skip(const char *str, const char *prefix) -{ - size_t len = strlen(prefix); - return strncmp(str, prefix, len) ? NULL : str + len; -} - -int -prefix_cmp(const char *str, const char *prefix) -{ - for (;; str++, prefix++) - if (!*prefix) - return 0; - else if (*str != *prefix) - return (unsigned char)*prefix - (unsigned char)*str; -} - -static void -argparse_error(struct argparse *this_, const struct argparse_option *opt, - const char *reason) -{ - if (!strncmp(this_->argv[0], "--", 2)) { - fprintf(stderr, "error: option `%s` %s\n", opt->long_name, reason); - exit(-1); - } else { - fprintf(stderr, "error: option `%c` %s\n", opt->short_name, reason); - exit(-1); - } -} - -static int -argparse_getvalue(struct argparse *this_, const struct argparse_option *opt, - int flags) -{ - const char *s = NULL; - if (!opt->value) - goto skipped; - switch (opt->type) { - case ARGPARSE_OPT_BOOLEAN: - if (flags & OPT_UNSET) { - *(int *)opt->value = *(int *)opt->value - 1; - } else { - *(int *)opt->value = *(int *)opt->value + 1; - } - if (*(int *)opt->value < 0) { - *(int *)opt->value = 0; - } - break; - case ARGPARSE_OPT_BIT: - if (flags & OPT_UNSET) { - *(int *)opt->value &= ~opt->data; - } else { - *(int *)opt->value |= opt->data; - } - break; - case ARGPARSE_OPT_STRING: - if (this_->optvalue) { - *(const char **)opt->value = this_->optvalue; - this_->optvalue = NULL; - } else if (this_->argc > 1) { - this_->argc--; - *(const char **)opt->value = *++this_->argv; - } else { - argparse_error(this_, opt, "requires a value"); - } - break; - case ARGPARSE_OPT_INTEGER: - if (this_->optvalue) { - *(int *)opt->value = strtol(this_->optvalue, (char **)&s, 0); - this_->optvalue = NULL; - } else if (this_->argc > 1) { - this_->argc--; - *(int *)opt->value = strtol(*++this_->argv, (char **)&s, 0); - } else { - argparse_error(this_, opt, "requires a value"); - } - if (*s) - argparse_error(this_, opt, "expects a numerical value"); - break; - default: - assert(0); - } - -skipped: - if (opt->callback) { - return opt->callback(this_, opt); - } - - return 0; -} - -static void -argparse_options_check(const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - switch (options->type) { - case ARGPARSE_OPT_END: - case ARGPARSE_OPT_BOOLEAN: - case ARGPARSE_OPT_BIT: - case ARGPARSE_OPT_INTEGER: - case ARGPARSE_OPT_STRING: - continue; - default: - fprintf(stderr, "wrong option type: %d", options->type); - break; - } - } -} - -static int -argparse_short_opt(struct argparse *this_, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - if (options->short_name == *this_->optvalue) { - this_->optvalue = this_->optvalue[1] ? this_->optvalue + 1 : NULL; - return argparse_getvalue(this_, options, 0); - } - } - return -2; -} - -static int -argparse_long_opt(struct argparse *this_, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - const char *rest; - int opt_flags = 0; - if (!options->long_name) - continue; - - rest = prefix_skip(this_->argv[0] + 2, options->long_name); - if (!rest) { - // Negation allowed? - if (options->flags & OPT_NONEG) { - continue; - } - // Only boolean/bit allow negation. - if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != ARGPARSE_OPT_BIT) { - continue; - } - - if (!prefix_cmp(this_->argv[0] + 2, "no-")) { - rest = prefix_skip(this_->argv[0] + 2 + 3, options->long_name); - if (!rest) - continue; - opt_flags |= OPT_UNSET; - } else { - continue; - } - } - if (*rest) { - if (*rest != '=') - continue; - this_->optvalue = rest + 1; - } - return argparse_getvalue(this_, options, opt_flags); - } - return -2; -} - -int -argparse_init(struct argparse *this_, struct argparse_option *options, - const char *usage, int flags) -{ - memset(this_, 0, sizeof(*this_)); - this_->options = options; - this_->usage = usage; - this_->flags = flags; - return 0; -} - -int -argparse_parse(struct argparse *this_, int argc, const char **argv) -{ - this_->argc = argc - 1; - this_->argv = argv + 1; - this_->out = argv; - - argparse_options_check(this_->options); - - for (; this_->argc; this_->argc--, this_->argv++) { - const char *arg = this_->argv[0]; - if (arg[0] != '-' || !arg[1]) { - if (this_->flags & ARGPARSE_STOP_AT_NON_OPTION) { - goto end; - } - // if it's not option or is a single char '-', copy verbatimly - this_->out[this_->cpidx++] = this_->argv[0]; - continue; - } - // short option - if (arg[1] != '-') { - this_->optvalue = arg + 1; - switch (argparse_short_opt(this_, this_->options)) { - case -1: - break; - case -2: - goto unknown; - } - while (this_->optvalue) { - switch (argparse_short_opt(this_, this_->options)) { - case -1: - break; - case -2: - goto unknown; - } - } - continue; - } - // if '--' presents - if (!arg[2]) { - this_->argc--; - this_->argv++; - break; - } - // long option - switch (argparse_long_opt(this_, this_->options)) { - case -1: - break; - case -2: - goto unknown; - } - continue; - -unknown: - fprintf(stderr, "error: unknown option `%s`\n", this_->argv[0]); - argparse_usage(this_); - exit(0); - } - -end: - memmove(this_->out + this_->cpidx, this_->argv, - this_->argc * sizeof(*this_->out)); - this_->out[this_->cpidx + this_->argc] = NULL; - - return this_->cpidx + this_->argc; -} - -void -argparse_usage(struct argparse *this_) -{ - fprintf(stdout, "Usage: %s\n", this_->usage); - fputc('\n', stdout); - - const struct argparse_option *options; - - // figure out best width - size_t usage_opts_width = 0; - size_t len; - options = this_->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - len = 0; - if ((options)->short_name) { - len += 2; - } - if ((options)->short_name && (options)->long_name) { - len += 2; // separator ", " - } - if ((options)->long_name) { - len += strlen((options)->long_name) + 2; - } - if (options->type == ARGPARSE_OPT_INTEGER) { - len += strlen("="); - } else if (options->type == ARGPARSE_OPT_STRING) { - len += strlen("="); - } - len = ceil((float)len / 4) * 4; - if (usage_opts_width < len) { - usage_opts_width = len; - } - } - usage_opts_width += 4; // 4 spaces prefix - - options = this_->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - size_t pos; - int pad; - pos = fprintf(stdout, " "); - if (options->short_name) { - pos += fprintf(stdout, "-%c", options->short_name); - } - if (options->long_name && options->short_name) { - pos += fprintf(stdout, ", "); - } - if (options->long_name) { - pos += fprintf(stdout, "--%s", options->long_name); - } - if (options->type == ARGPARSE_OPT_INTEGER) { - pos += fprintf(stdout, "="); - } else if (options->type == ARGPARSE_OPT_STRING) { - pos += fprintf(stdout, "="); - } - if (pos <= usage_opts_width) { - pad = usage_opts_width - pos; - } else { - fputc('\n', stdout); - pad = usage_opts_width; - } - fprintf(stdout, "%*s%s\n", pad + 2, "", options->help); - } -} - -int -argparse_help_cb(struct argparse *this_, const struct argparse_option *option) -{ - (void)option; - argparse_usage(this_); - exit(0); - return 0; -} - -#if defined(__cplusplus) -} -#endif diff --git a/server/src/exprtk.hpp b/server/src/exprtk.hpp deleted file mode 100644 index da493c5..0000000 --- a/server/src/exprtk.hpp +++ /dev/null @@ -1,46066 +0,0 @@ -/* - ****************************************************************** - * C++ Mathematical Expression Toolkit Library * - * * - * Author: Arash Partow (1999-2024) * - * URL: https://www.partow.net/programming/exprtk/index.html * - * * - * Copyright notice: * - * Free use of the C++ Mathematical Expression Toolkit Library is * - * permitted under the guidelines and in accordance with the most * - * current version of the MIT License. * - * https://www.opensource.org/licenses/MIT * - * SPDX-License-Identifier: MIT * - * * - * Example expressions: * - * (00) (y + x / y) * (x - y / x) * - * (01) (x^2 / sin(2 * pi / y)) - x / 2 * - * (02) sqrt(1 - (x^2)) * - * (03) 1 - sin(2 * x) + cos(pi / y) * - * (04) a * exp(2 * t) + c * - * (05) if(((x + 2) == 3) and ((y + 5) <= 9), 1 + w, 2 / z) * - * (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x * - * (07) z := x + sin(2 * pi / y) * - * (08) u := 2 * (pi * z) / (w := x + cos(y / pi)) * - * (09) clamp(-1, sin(2 * pi * x) + cos(y / 2 * pi), +1) * - * (10) inrange(-2, m, +2) == if(({-2 <= m} and [m <= +2]), 1, 0) * - * (11) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1) * - * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] * - * * - ****************************************************************** -*/ - - -#ifndef INCLUDE_EXPRTK_HPP -#define INCLUDE_EXPRTK_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace exprtk -{ - #ifdef exprtk_enable_debugging - #define exprtk_debug(params) printf params - #else - #define exprtk_debug(params) (void)0 - #endif - - #define exprtk_error_location \ - "exprtk.hpp:" + details::to_str(__LINE__) \ - - #if __cplusplus >= 201103L - #define exprtk_override override - #define exprtk_final final - #define exprtk_delete = delete - #else - #define exprtk_override - #define exprtk_final - #define exprtk_delete - #endif - - #if __cplusplus >= 201603L - #define exprtk_fallthrough [[fallthrough]]; - #elif __cplusplus >= 201103L - #define exprtk_fallthrough [[gnu::fallthrough]]; - #else - #ifndef _MSC_VER - #define exprtk_fallthrough __attribute__ ((fallthrough)); - #else - #define exprtk_fallthrough - #endif - #endif - - namespace details - { - typedef char char_t; - typedef char_t* char_ptr; - typedef char_t const* char_cptr; - typedef unsigned char uchar_t; - typedef uchar_t* uchar_ptr; - typedef uchar_t const* uchar_cptr; - typedef unsigned long long int _uint64_t; - typedef long long int _int64_t; - - inline bool is_whitespace(const char_t c) - { - return (' ' == c) || ('\n' == c) || - ('\r' == c) || ('\t' == c) || - ('\b' == c) || ('\v' == c) || - ('\f' == c) ; - } - - inline bool is_operator_char(const char_t c) - { - return ('+' == c) || ('-' == c) || - ('*' == c) || ('/' == c) || - ('^' == c) || ('<' == c) || - ('>' == c) || ('=' == c) || - (',' == c) || ('!' == c) || - ('(' == c) || (')' == c) || - ('[' == c) || (']' == c) || - ('{' == c) || ('}' == c) || - ('%' == c) || (':' == c) || - ('?' == c) || ('&' == c) || - ('|' == c) || (';' == c) ; - } - - inline bool is_letter(const char_t c) - { - return (('a' <= c) && (c <= 'z')) || - (('A' <= c) && (c <= 'Z')) ; - } - - inline bool is_digit(const char_t c) - { - return ('0' <= c) && (c <= '9'); - } - - inline bool is_letter_or_digit(const char_t c) - { - return is_letter(c) || is_digit(c); - } - - inline bool is_left_bracket(const char_t c) - { - return ('(' == c) || ('[' == c) || ('{' == c); - } - - inline bool is_right_bracket(const char_t c) - { - return (')' == c) || (']' == c) || ('}' == c); - } - - inline bool is_bracket(const char_t c) - { - return is_left_bracket(c) || is_right_bracket(c); - } - - inline bool is_sign(const char_t c) - { - return ('+' == c) || ('-' == c); - } - - inline bool is_invalid(const char_t c) - { - return !is_whitespace (c) && - !is_operator_char(c) && - !is_letter (c) && - !is_digit (c) && - ('.' != c) && - ('_' != c) && - ('$' != c) && - ('~' != c) && - ('\'' != c); - } - - inline bool is_valid_string_char(const char_t c) - { - return std::isprint(static_cast(c)) || - is_whitespace(c); - } - - #ifndef exprtk_disable_caseinsensitivity - inline void case_normalise(std::string& s) - { - for (std::size_t i = 0; i < s.size(); ++i) - { - s[i] = static_cast(std::tolower(s[i])); - } - } - - inline bool imatch(const char_t c1, const char_t c2) - { - return std::tolower(c1) == std::tolower(c2); - } - - inline bool imatch(const std::string& s1, const std::string& s2) - { - if (s1.size() == s2.size()) - { - for (std::size_t i = 0; i < s1.size(); ++i) - { - if (std::tolower(s1[i]) != std::tolower(s2[i])) - { - return false; - } - } - - return true; - } - - return false; - } - - struct ilesscompare - { - inline bool operator() (const std::string& s1, const std::string& s2) const - { - const std::size_t length = std::min(s1.size(),s2.size()); - - for (std::size_t i = 0; i < length; ++i) - { - const char_t c1 = static_cast(std::tolower(s1[i])); - const char_t c2 = static_cast(std::tolower(s2[i])); - - if (c1 < c2) - return true; - else if (c2 < c1) - return false; - } - - return s1.size() < s2.size(); - } - }; - - #else - inline void case_normalise(std::string&) - {} - - inline bool imatch(const char_t c1, const char_t c2) - { - return c1 == c2; - } - - inline bool imatch(const std::string& s1, const std::string& s2) - { - return s1 == s2; - } - - struct ilesscompare - { - inline bool operator() (const std::string& s1, const std::string& s2) const - { - return s1 < s2; - } - }; - #endif - - inline bool is_valid_sf_symbol(const std::string& symbol) - { - // Special function: $f12 or $F34 - return (4 == symbol.size()) && - ('$' == symbol[0]) && - imatch('f',symbol[1]) && - is_digit(symbol[2]) && - is_digit(symbol[3]); - } - - inline const char_t& front(const std::string& s) - { - return s[0]; - } - - inline const char_t& back(const std::string& s) - { - return s[s.size() - 1]; - } - - inline std::string to_str(int i) - { - if (0 == i) - return std::string("0"); - - std::string result; - - const int sign = (i < 0) ? -1 : 1; - - for ( ; i; i /= 10) - { - result += '0' + static_cast(sign * (i % 10)); - } - - if (sign < 0) - { - result += '-'; - } - - std::reverse(result.begin(), result.end()); - - return result; - } - - inline std::string to_str(std::size_t i) - { - return to_str(static_cast(i)); - } - - inline bool is_hex_digit(const uchar_t digit) - { - return (('0' <= digit) && (digit <= '9')) || - (('A' <= digit) && (digit <= 'F')) || - (('a' <= digit) && (digit <= 'f')) ; - } - - inline uchar_t hex_to_bin(uchar_t h) - { - if (('0' <= h) && (h <= '9')) - return (h - '0'); - else - return static_cast(std::toupper(h) - 'A'); - } - - template - inline bool parse_hex(Iterator& itr, Iterator end, - char_t& result) - { - if ( - (end == (itr )) || - (end == (itr + 1)) || - (end == (itr + 2)) || - (end == (itr + 3)) || - ('0' != *(itr )) || - ('X' != std::toupper(*(itr + 1))) || - (!is_hex_digit(*(itr + 2))) || - (!is_hex_digit(*(itr + 3))) - ) - { - return false; - } - - result = hex_to_bin(static_cast(*(itr + 2))) << 4 | - hex_to_bin(static_cast(*(itr + 3))) ; - - return true; - } - - inline bool cleanup_escapes(std::string& s) - { - typedef std::string::iterator str_itr_t; - - str_itr_t itr1 = s.begin(); - str_itr_t itr2 = s.begin(); - str_itr_t end = s.end (); - - std::size_t removal_count = 0; - - while (end != itr1) - { - if ('\\' == (*itr1)) - { - if (end == ++itr1) - { - return false; - } - else if (parse_hex(itr1, end, *itr2)) - { - itr1 += 4; - itr2 += 1; - removal_count += 4; - } - else if ('a' == (*itr1)) { (*itr2++) = '\a'; ++itr1; ++removal_count; } - else if ('b' == (*itr1)) { (*itr2++) = '\b'; ++itr1; ++removal_count; } - else if ('f' == (*itr1)) { (*itr2++) = '\f'; ++itr1; ++removal_count; } - else if ('n' == (*itr1)) { (*itr2++) = '\n'; ++itr1; ++removal_count; } - else if ('r' == (*itr1)) { (*itr2++) = '\r'; ++itr1; ++removal_count; } - else if ('t' == (*itr1)) { (*itr2++) = '\t'; ++itr1; ++removal_count; } - else if ('v' == (*itr1)) { (*itr2++) = '\v'; ++itr1; ++removal_count; } - else if ('0' == (*itr1)) { (*itr2++) = '\0'; ++itr1; ++removal_count; } - else - { - (*itr2++) = (*itr1++); - ++removal_count; - } - - continue; - } - else - (*itr2++) = (*itr1++); - } - - if ((removal_count > s.size()) || (0 == removal_count)) - return false; - - s.resize(s.size() - removal_count); - - return true; - } - - class build_string - { - public: - - explicit build_string(const std::size_t& initial_size = 64) - { - data_.reserve(initial_size); - } - - inline build_string& operator << (const std::string& s) - { - data_ += s; - return (*this); - } - - inline build_string& operator << (char_cptr s) - { - data_ += std::string(s); - return (*this); - } - - inline operator std::string () const - { - return data_; - } - - inline std::string as_string() const - { - return data_; - } - - private: - - std::string data_; - }; - - static const std::string reserved_words[] = - { - "assert", "break", "case", "continue", "const", "default", - "false", "for", "if", "else", "ilike", "in", "like", "and", - "nand", "nor", "not", "null", "or", "repeat", "return", - "shl", "shr", "swap", "switch", "true", "until", "var", - "while", "xnor", "xor", "&", "|" - }; - - static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); - - static const std::string reserved_symbols[] = - { - "abs", "acos", "acosh", "and", "asin", "asinh", "assert", - "atan", "atanh", "atan2", "avg", "break", "case", "ceil", - "clamp", "continue", "const", "cos", "cosh", "cot", "csc", - "default", "deg2grad", "deg2rad", "equal", "erf", "erfc", - "exp", "expm1", "false", "floor", "for", "frac", "grad2deg", - "hypot", "iclamp", "if", "else", "ilike", "in", "inrange", - "like", "log", "log10", "log2", "logn", "log1p", "mand", - "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", - "not", "not_equal", "null", "or", "pow", "rad2deg", - "repeat", "return", "root", "round", "roundn", "sec", "sgn", - "shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", - "switch", "tan", "tanh", "true", "trunc", "until", "var", - "while", "xnor", "xor", "&", "|" - }; - - static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); - - static const std::string base_function_list[] = - { - "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", - "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", - "csc", "equal", "erf", "erfc", "exp", "expm1", "floor", - "frac", "hypot", "iclamp", "like", "log", "log10", "log2", - "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", - "ncdf", "pow", "root", "round", "roundn", "sec", "sgn", - "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh", - "trunc", "not_equal", "inrange", "deg2grad", "deg2rad", - "rad2deg", "grad2deg" - }; - - static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string); - - static const std::string logic_ops_list[] = - { - "and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|" - }; - - static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string); - - static const std::string cntrl_struct_list[] = - { - "if", "switch", "for", "while", "repeat", "return" - }; - - static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string); - - static const std::string arithmetic_ops_list[] = - { - "+", "-", "*", "/", "%", "^" - }; - - static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string); - - static const std::string assignment_ops_list[] = - { - ":=", "+=", "-=", - "*=", "/=", "%=" - }; - - static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string); - - static const std::string inequality_ops_list[] = - { - "<", "<=", "==", - "=", "!=", "<>", - ">=", ">" - }; - - static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / sizeof(std::string); - - inline bool is_reserved_word(const std::string& symbol) - { - for (std::size_t i = 0; i < reserved_words_size; ++i) - { - if (imatch(symbol, reserved_words[i])) - { - return true; - } - } - - return false; - } - - inline bool is_reserved_symbol(const std::string& symbol) - { - for (std::size_t i = 0; i < reserved_symbols_size; ++i) - { - if (imatch(symbol, reserved_symbols[i])) - { - return true; - } - } - - return false; - } - - inline bool is_base_function(const std::string& function_name) - { - for (std::size_t i = 0; i < base_function_list_size; ++i) - { - if (imatch(function_name, base_function_list[i])) - { - return true; - } - } - - return false; - } - - inline bool is_control_struct(const std::string& cntrl_strct) - { - for (std::size_t i = 0; i < cntrl_struct_list_size; ++i) - { - if (imatch(cntrl_strct, cntrl_struct_list[i])) - { - return true; - } - } - - return false; - } - - inline bool is_logic_opr(const std::string& lgc_opr) - { - for (std::size_t i = 0; i < logic_ops_list_size; ++i) - { - if (imatch(lgc_opr, logic_ops_list[i])) - { - return true; - } - } - - return false; - } - - struct cs_match - { - static inline bool cmp(const char_t c0, const char_t c1) - { - return (c0 == c1); - } - }; - - struct cis_match - { - static inline bool cmp(const char_t c0, const char_t c1) - { - return (std::tolower(c0) == std::tolower(c1)); - } - }; - - template - inline bool match_impl(const Iterator pattern_begin, - const Iterator pattern_end , - const Iterator data_begin , - const Iterator data_end , - const typename std::iterator_traits::value_type& zero_or_more, - const typename std::iterator_traits::value_type& exactly_one ) - { - typedef typename std::iterator_traits::value_type type; - - const Iterator null_itr(0); - - Iterator p_itr = pattern_begin; - Iterator d_itr = data_begin; - Iterator np_itr = null_itr; - Iterator nd_itr = null_itr; - - for ( ; ; ) - { - if (p_itr != pattern_end) - { - const type c = *(p_itr); - - if ((data_end != d_itr) && (Compare::cmp(c,*(d_itr)) || (exactly_one == c))) - { - ++d_itr; - ++p_itr; - continue; - } - else if (zero_or_more == c) - { - while ((pattern_end != p_itr) && (zero_or_more == *(p_itr))) - { - ++p_itr; - } - - const type d = *(p_itr); - - while ((data_end != d_itr) && !(Compare::cmp(d,*(d_itr)) || (exactly_one == d))) - { - ++d_itr; - } - - // set backtrack iterators - np_itr = p_itr - 1; - nd_itr = d_itr + 1; - - continue; - } - } - else if (data_end == d_itr) - break; - - if ((data_end == d_itr) || (null_itr == nd_itr)) - return false; - - p_itr = np_itr; - d_itr = nd_itr; - } - - return true; - } - - inline bool wc_match(const std::string& wild_card, - const std::string& str) - { - return match_impl - ( - wild_card.data(), - wild_card.data() + wild_card.size(), - str.data(), - str.data() + str.size(), - '*', '?' - ); - } - - inline bool wc_imatch(const std::string& wild_card, - const std::string& str) - { - return match_impl - ( - wild_card.data(), - wild_card.data() + wild_card.size(), - str.data(), - str.data() + str.size(), - '*', '?' - ); - } - - inline bool sequence_match(const std::string& pattern, - const std::string& str, - std::size_t& diff_index, - char_t& diff_value) - { - if (str.empty()) - { - return ("Z" == pattern); - } - else if ('*' == pattern[0]) - return false; - - typedef std::string::const_iterator itr_t; - - itr_t p_itr = pattern.begin(); - itr_t s_itr = str .begin(); - - const itr_t p_end = pattern.end(); - const itr_t s_end = str .end(); - - while ((s_end != s_itr) && (p_end != p_itr)) - { - if ('*' == (*p_itr)) - { - const char_t target = static_cast(std::toupper(*(p_itr - 1))); - - if ('*' == target) - { - diff_index = static_cast(std::distance(str.begin(),s_itr)); - diff_value = static_cast(std::toupper(*p_itr)); - - return false; - } - else - ++p_itr; - - while (s_itr != s_end) - { - if (target != std::toupper(*s_itr)) - break; - else - ++s_itr; - } - - continue; - } - else if ( - ('?' != *p_itr) && - std::toupper(*p_itr) != std::toupper(*s_itr) - ) - { - diff_index = static_cast(std::distance(str.begin(),s_itr)); - diff_value = static_cast(std::toupper(*p_itr)); - - return false; - } - - ++p_itr; - ++s_itr; - } - - return ( - (s_end == s_itr) && - ( - (p_end == p_itr) || - ('*' == *p_itr) - ) - ); - } - - template - struct set_zero_value_impl - { - static inline void process(T* base_ptr, const std::size_t size) - { - const T zero = T(0); - for (std::size_t i = 0; i < size; ++i) - { - base_ptr[i] = zero; - } - } - }; - - #define pod_set_zero_value(T) \ - template <> \ - struct set_zero_value_impl \ - { \ - static inline void process(T* base_ptr, const std::size_t size) \ - { std::memset(base_ptr, 0x00, size * sizeof(T)); } \ - }; \ - - pod_set_zero_value(float ) - pod_set_zero_value(double ) - pod_set_zero_value(long double) - - #ifdef pod_set_zero_value - #undef pod_set_zero_value - #endif - - template - inline void set_zero_value(T* data, const std::size_t size) - { - set_zero_value_impl::process(data,size); - } - - template - inline void set_zero_value(std::vector& v) - { - set_zero_value(v.data(),v.size()); - } - - static const double pow10[] = - { - 1.0, - 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, - 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, - 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, - 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 - }; - - static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); - - namespace numeric - { - namespace constant - { - static const double e = 2.71828182845904523536028747135266249775724709369996; - static const double pi = 3.14159265358979323846264338327950288419716939937510; - static const double pi_2 = 1.57079632679489661923132169163975144209858469968755; - static const double pi_4 = 0.78539816339744830961566084581987572104929234984378; - static const double pi_180 = 0.01745329251994329576923690768488612713442871888542; - static const double _1_pi = 0.31830988618379067153776752674502872406891929148091; - static const double _2_pi = 0.63661977236758134307553505349005744813783858296183; - static const double _180_pi = 57.29577951308232087679815481410517033240547246656443; - static const double log2 = 0.69314718055994530941723212145817656807550013436026; - static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695; - } - - namespace details - { - struct unknown_type_tag { unknown_type_tag() {} }; - struct real_type_tag { real_type_tag () {} }; - struct int_type_tag { int_type_tag () {} }; - - template - struct number_type - { - typedef unknown_type_tag type; - number_type() {} - }; - - #define exprtk_register_real_type_tag(T) \ - template <> struct number_type \ - { typedef real_type_tag type; number_type() {} }; \ - - #define exprtk_register_int_type_tag(T) \ - template <> struct number_type \ - { typedef int_type_tag type; number_type() {} }; \ - - exprtk_register_real_type_tag(float ) - exprtk_register_real_type_tag(double ) - exprtk_register_real_type_tag(long double) - - exprtk_register_int_type_tag(short ) - exprtk_register_int_type_tag(int ) - exprtk_register_int_type_tag(_int64_t ) - exprtk_register_int_type_tag(unsigned short) - exprtk_register_int_type_tag(unsigned int ) - exprtk_register_int_type_tag(_uint64_t ) - - #undef exprtk_register_real_type_tag - #undef exprtk_register_int_type_tag - - template - struct epsilon_type {}; - - #define exprtk_define_epsilon_type(Type, Epsilon) \ - template <> struct epsilon_type \ - { \ - static inline Type value() \ - { \ - const Type epsilon = static_cast(Epsilon); \ - return epsilon; \ - } \ - }; \ - - exprtk_define_epsilon_type(float , 0.00000100000f) - exprtk_define_epsilon_type(double , 0.000000000100) - exprtk_define_epsilon_type(long double, 0.000000000001) - - #undef exprtk_define_epsilon_type - - template - inline bool is_nan_impl(const T v, real_type_tag) - { - return std::not_equal_to()(v,v); - } - - template - inline int to_int32_impl(const T v, real_type_tag) - { - return static_cast(v); - } - - template - inline _int64_t to_int64_impl(const T v, real_type_tag) - { - return static_cast<_int64_t>(v); - } - - template - inline _uint64_t to_uint64_impl(const T v, real_type_tag) - { - return static_cast<_uint64_t>(v); - } - - template - inline bool is_true_impl(const T v) - { - return std::not_equal_to()(T(0),v); - } - - template - inline bool is_false_impl(const T v) - { - return std::equal_to()(T(0),v); - } - - template - inline T abs_impl(const T v, real_type_tag) - { - return ((v < T(0)) ? -v : v); - } - - template - inline T min_impl(const T v0, const T v1, real_type_tag) - { - return std::min(v0,v1); - } - - template - inline T max_impl(const T v0, const T v1, real_type_tag) - { - return std::max(v0,v1); - } - - template - inline T equal_impl(const T v0, const T v1, real_type_tag) - { - const T epsilon = epsilon_type::value(); - return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(T(1),std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? T(1) : T(0); - } - - inline float equal_impl(const float v0, const float v1, real_type_tag) - { - const float epsilon = epsilon_type::value(); - return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(1.0f,std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? 1.0f : 0.0f; - } - - template - inline T equal_impl(const T v0, const T v1, int_type_tag) - { - return (v0 == v1) ? 1 : 0; - } - - template - inline T expm1_impl(const T v, real_type_tag) - { - // return std::expm1(v); - if (abs_impl(v,real_type_tag()) < T(0.00001)) - return v + (T(0.5) * v * v); - else - return std::exp(v) - T(1); - } - - template - inline T expm1_impl(const T v, int_type_tag) - { - return T(std::exp(v)) - T(1); - } - - template - inline T nequal_impl(const T v0, const T v1, real_type_tag) - { - typedef real_type_tag rtg; - const T epsilon = epsilon_type::value(); - return (abs_impl(v0 - v1,rtg()) > (std::max(T(1),std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? T(1) : T(0); - } - - inline float nequal_impl(const float v0, const float v1, real_type_tag) - { - typedef real_type_tag rtg; - const float epsilon = epsilon_type::value(); - return (abs_impl(v0 - v1,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f; - } - - template - inline T nequal_impl(const T v0, const T v1, int_type_tag) - { - return (v0 != v1) ? 1 : 0; - } - - template - inline T modulus_impl(const T v0, const T v1, real_type_tag) - { - return std::fmod(v0,v1); - } - - template - inline T modulus_impl(const T v0, const T v1, int_type_tag) - { - return v0 % v1; - } - - template - inline T pow_impl(const T v0, const T v1, real_type_tag) - { - return std::pow(v0,v1); - } - - template - inline T pow_impl(const T v0, const T v1, int_type_tag) - { - return std::pow(static_cast(v0),static_cast(v1)); - } - - template - inline T logn_impl(const T v0, const T v1, real_type_tag) - { - return std::log(v0) / std::log(v1); - } - - template - inline T logn_impl(const T v0, const T v1, int_type_tag) - { - return static_cast(logn_impl(static_cast(v0),static_cast(v1),real_type_tag())); - } - - template - inline T log1p_impl(const T v, real_type_tag) - { - if (v > T(-1)) - { - if (abs_impl(v,real_type_tag()) > T(0.0001)) - { - return std::log(T(1) + v); - } - else - return (T(-0.5) * v + T(1)) * v; - } - - return std::numeric_limits::quiet_NaN(); - } - - template - inline T log1p_impl(const T v, int_type_tag) - { - if (v > T(-1)) - { - return std::log(T(1) + v); - } - - return std::numeric_limits::quiet_NaN(); - } - - template - inline T root_impl(const T v0, const T v1, real_type_tag) - { - if (v1 < T(0)) - return std::numeric_limits::quiet_NaN(); - - const std::size_t n = static_cast(v1); - - if ((v0 < T(0)) && (0 == (n % 2))) - return std::numeric_limits::quiet_NaN(); - - return std::pow(v0, T(1) / n); - } - - template - inline T root_impl(const T v0, const T v1, int_type_tag) - { - return root_impl(static_cast(v0),static_cast(v1),real_type_tag()); - } - - template - inline T round_impl(const T v, real_type_tag) - { - return ((v < T(0)) ? std::ceil(v - T(0.5)) : std::floor(v + T(0.5))); - } - - template - inline T roundn_impl(const T v0, const T v1, real_type_tag) - { - const int index = std::max(0, std::min(pow10_size - 1, static_cast(std::floor(v1)))); - const T p10 = T(pow10[index]); - - if (v0 < T(0)) - return T(std::ceil ((v0 * p10) - T(0.5)) / p10); - else - return T(std::floor((v0 * p10) + T(0.5)) / p10); - } - - template - inline T roundn_impl(const T v0, const T, int_type_tag) - { - return v0; - } - - template - inline T hypot_impl(const T v0, const T v1, real_type_tag) - { - return std::sqrt((v0 * v0) + (v1 * v1)); - } - - template - inline T hypot_impl(const T v0, const T v1, int_type_tag) - { - return static_cast(std::sqrt(static_cast((v0 * v0) + (v1 * v1)))); - } - - template - inline T atan2_impl(const T v0, const T v1, real_type_tag) - { - return std::atan2(v0,v1); - } - - template - inline T atan2_impl(const T, const T, int_type_tag) - { - return 0; - } - - template - inline T shr_impl(const T v0, const T v1, real_type_tag) - { - return v0 * (T(1) / std::pow(T(2),static_cast(static_cast(v1)))); - } - - template - inline T shr_impl(const T v0, const T v1, int_type_tag) - { - return v0 >> v1; - } - - template - inline T shl_impl(const T v0, const T v1, real_type_tag) - { - return v0 * std::pow(T(2),static_cast(static_cast(v1))); - } - - template - inline T shl_impl(const T v0, const T v1, int_type_tag) - { - return v0 << v1; - } - - template - inline T sgn_impl(const T v, real_type_tag) - { - if (v > T(0)) return T(+1); - else if (v < T(0)) return T(-1); - else return T( 0); - } - - template - inline T sgn_impl(const T v, int_type_tag) - { - if (v > T(0)) return T(+1); - else if (v < T(0)) return T(-1); - else return T( 0); - } - - template - inline T and_impl(const T v0, const T v1, real_type_tag) - { - return (is_true_impl(v0) && is_true_impl(v1)) ? T(1) : T(0); - } - - template - inline T and_impl(const T v0, const T v1, int_type_tag) - { - return v0 && v1; - } - - template - inline T nand_impl(const T v0, const T v1, real_type_tag) - { - return (is_false_impl(v0) || is_false_impl(v1)) ? T(1) : T(0); - } - - template - inline T nand_impl(const T v0, const T v1, int_type_tag) - { - return !(v0 && v1); - } - - template - inline T or_impl(const T v0, const T v1, real_type_tag) - { - return (is_true_impl(v0) || is_true_impl(v1)) ? T(1) : T(0); - } - - template - inline T or_impl(const T v0, const T v1, int_type_tag) - { - return (v0 || v1); - } - - template - inline T nor_impl(const T v0, const T v1, real_type_tag) - { - return (is_false_impl(v0) && is_false_impl(v1)) ? T(1) : T(0); - } - - template - inline T nor_impl(const T v0, const T v1, int_type_tag) - { - return !(v0 || v1); - } - - template - inline T xor_impl(const T v0, const T v1, real_type_tag) - { - return (is_false_impl(v0) != is_false_impl(v1)) ? T(1) : T(0); - } - - template - inline T xor_impl(const T v0, const T v1, int_type_tag) - { - return v0 ^ v1; - } - - template - inline T xnor_impl(const T v0, const T v1, real_type_tag) - { - const bool v0_true = is_true_impl(v0); - const bool v1_true = is_true_impl(v1); - - if ((v0_true && v1_true) || (!v0_true && !v1_true)) - return T(1); - else - return T(0); - } - - template - inline T xnor_impl(const T v0, const T v1, int_type_tag) - { - const bool v0_true = is_true_impl(v0); - const bool v1_true = is_true_impl(v1); - - if ((v0_true && v1_true) || (!v0_true && !v1_true)) - return T(1); - else - return T(0); - } - - #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) - #define exprtk_define_erf(TT, impl) \ - inline TT erf_impl(const TT v) { return impl(v); } \ - - exprtk_define_erf(float , ::erff) - exprtk_define_erf(double , ::erf ) - exprtk_define_erf(long double, ::erfl) - #undef exprtk_define_erf - #endif - - template - inline T erf_impl(const T v, real_type_tag) - { - #if defined(_MSC_VER) && (_MSC_VER < 1900) - // Credits: Abramowitz & Stegun Equations 7.1.25-28 - static const T c[] = - { - T( 1.26551223), T(1.00002368), - T( 0.37409196), T(0.09678418), - T(-0.18628806), T(0.27886807), - T(-1.13520398), T(1.48851587), - T(-0.82215223), T(0.17087277) - }; - - const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); - - const T result = T(1) - t * std::exp((-v * v) - - c[0] + t * (c[1] + t * - (c[2] + t * (c[3] + t * - (c[4] + t * (c[5] + t * - (c[6] + t * (c[7] + t * - (c[8] + t * (c[9])))))))))); - - return (v >= T(0)) ? result : -result; - #else - return erf_impl(v); - #endif - } - - template - inline T erf_impl(const T v, int_type_tag) - { - return erf_impl(static_cast(v),real_type_tag()); - } - - #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) - #define exprtk_define_erfc(TT, impl) \ - inline TT erfc_impl(const TT v) { return impl(v); } \ - - exprtk_define_erfc(float ,::erfcf) - exprtk_define_erfc(double ,::erfc ) - exprtk_define_erfc(long double,::erfcl) - #undef exprtk_define_erfc - #endif - - template - inline T erfc_impl(const T v, real_type_tag) - { - #if defined(_MSC_VER) && (_MSC_VER < 1900) - return T(1) - erf_impl(v,real_type_tag()); - #else - return erfc_impl(v); - #endif - } - - template - inline T erfc_impl(const T v, int_type_tag) - { - return erfc_impl(static_cast(v),real_type_tag()); - } - - template - inline T ncdf_impl(const T v, real_type_tag) - { - return T(0.5) * erfc_impl(-(v / T(numeric::constant::sqrt2)),real_type_tag()); - } - - template - inline T ncdf_impl(const T v, int_type_tag) - { - return ncdf_impl(static_cast(v),real_type_tag()); - } - - template - inline T sinc_impl(const T v, real_type_tag) - { - if (std::abs(v) >= std::numeric_limits::epsilon()) - return(std::sin(v) / v); - else - return T(1); - } - - template - inline T sinc_impl(const T v, int_type_tag) - { - return sinc_impl(static_cast(v),real_type_tag()); - } - - #if __cplusplus >= 201103L - template - inline T acosh_impl(const T v, real_type_tag) - { - return std::acosh(v); - } - - template - inline T asinh_impl(const T v, real_type_tag) - { - return std::asinh(v); - } - - template - inline T atanh_impl(const T v, real_type_tag) - { - return std::atanh(v); - } - #else - template - inline T acosh_impl(const T v, real_type_tag) - { - return std::log(v + std::sqrt((v * v) - T(1))); - } - - template - inline T asinh_impl(const T v, real_type_tag) - { - return std::log(v + std::sqrt((v * v) + T(1))); - } - - template - inline T atanh_impl(const T v, real_type_tag) - { - return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); - } - #endif - - template inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } - template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } - template inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } - template inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } - template inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } - template inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } - template inline T exp_impl(const T v, real_type_tag) { return std::exp (v); } - template inline T floor_impl(const T v, real_type_tag) { return std::floor(v); } - template inline T log_impl(const T v, real_type_tag) { return std::log (v); } - template inline T log10_impl(const T v, real_type_tag) { return std::log10(v); } - template inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); } - template inline T neg_impl(const T v, real_type_tag) { return -v; } - template inline T pos_impl(const T v, real_type_tag) { return +v; } - template inline T sin_impl(const T v, real_type_tag) { return std::sin (v); } - template inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); } - template inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); } - template inline T tan_impl(const T v, real_type_tag) { return std::tan (v); } - template inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); } - template inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); } - template inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); } - template inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); } - template inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } - template inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } - template inline T d2g_impl(const T v, real_type_tag) { return (v * T(10.0/9.0)); } - template inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/10.0)); } - template inline T notl_impl(const T v, real_type_tag) { return (std::not_equal_to()(T(0),v) ? T(0) : T(1)); } - template inline T frac_impl(const T v, real_type_tag) { return (v - static_cast(v)); } - template inline T trunc_impl(const T v, real_type_tag) { return T(static_cast(v)); } - - template inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); } - template inline T const_e_impl(real_type_tag) { return T(numeric::constant::e); } - template inline T const_qnan_impl(real_type_tag) { return std::numeric_limits::quiet_NaN(); } - - template inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); } - template inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } - template inline T log_impl(const T v, int_type_tag) { return std::log (v); } - template inline T log10_impl(const T v, int_type_tag) { return std::log10(v); } - template inline T log2_impl(const T v, int_type_tag) { return std::log(v)/T(numeric::constant::log2); } - template inline T neg_impl(const T v, int_type_tag) { return -v; } - template inline T pos_impl(const T v, int_type_tag) { return +v; } - template inline T ceil_impl(const T v, int_type_tag) { return v; } - template inline T floor_impl(const T v, int_type_tag) { return v; } - template inline T round_impl(const T v, int_type_tag) { return v; } - template inline T notl_impl(const T v, int_type_tag) { return !v; } - template inline T sqrt_impl(const T v, int_type_tag) { return std::sqrt (v); } - template inline T frac_impl(const T , int_type_tag) { return T(0); } - template inline T trunc_impl(const T v, int_type_tag) { return v; } - template inline T acos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T acosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T asin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T asinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T atan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T atanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T cos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T cosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T sin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T sinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T tan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T tanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T cot_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T sec_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - template inline T csc_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } - - template - inline bool is_integer_impl(const T& v, real_type_tag) - { - return std::equal_to()(T(0),std::fmod(v,T(1))); - } - - template - inline bool is_integer_impl(const T&, int_type_tag) - { - return true; - } - } - - template - struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; }; - - template <> struct numeric_info { enum { length = 10, size = 16, bound_length = 9 }; }; - template <> struct numeric_info { enum { min_exp = -38, max_exp = +38 }; }; - template <> struct numeric_info { enum { min_exp = -308, max_exp = +308 }; }; - template <> struct numeric_info { enum { min_exp = -308, max_exp = +308 }; }; - - template - inline int to_int32(const T v) - { - const typename details::number_type::type num_type; - return to_int32_impl(v, num_type); - } - - template - inline _int64_t to_int64(const T v) - { - const typename details::number_type::type num_type; - return to_int64_impl(v, num_type); - } - - template - inline _uint64_t to_uint64(const T v) - { - const typename details::number_type::type num_type; - return to_uint64_impl(v, num_type); - } - - template - inline bool is_nan(const T v) - { - const typename details::number_type::type num_type; - return is_nan_impl(v, num_type); - } - - template - inline T min(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return min_impl(v0, v1, num_type); - } - - template - inline T max(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return max_impl(v0, v1, num_type); - } - - template - inline T equal(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return equal_impl(v0, v1, num_type); - } - - template - inline T nequal(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return nequal_impl(v0, v1, num_type); - } - - template - inline T modulus(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return modulus_impl(v0, v1, num_type); - } - - template - inline T pow(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return pow_impl(v0, v1, num_type); - } - - template - inline T logn(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return logn_impl(v0, v1, num_type); - } - - template - inline T root(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return root_impl(v0, v1, num_type); - } - - template - inline T roundn(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return roundn_impl(v0, v1, num_type); - } - - template - inline T hypot(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return hypot_impl(v0, v1, num_type); - } - - template - inline T atan2(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return atan2_impl(v0, v1, num_type); - } - - template - inline T shr(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return shr_impl(v0, v1, num_type); - } - - template - inline T shl(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return shl_impl(v0, v1, num_type); - } - - template - inline T and_opr(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return and_impl(v0, v1, num_type); - } - - template - inline T nand_opr(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return nand_impl(v0, v1, num_type); - } - - template - inline T or_opr(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return or_impl(v0, v1, num_type); - } - - template - inline T nor_opr(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return nor_impl(v0, v1, num_type); - } - - template - inline T xor_opr(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return xor_impl(v0, v1, num_type); - } - - template - inline T xnor_opr(const T v0, const T v1) - { - const typename details::number_type::type num_type; - return xnor_impl(v0, v1, num_type); - } - - template - inline bool is_integer(const T v) - { - const typename details::number_type::type num_type; - return is_integer_impl(v, num_type); - } - - template - struct fast_exp - { - static inline T result(T v) - { - unsigned int k = N; - T l = T(1); - - while (k) - { - if (1 == (k % 2)) - { - l *= v; - --k; - } - - v *= v; - k /= 2; - } - - return l; - } - }; - - template struct fast_exp { static inline T result(const T v) { T v_5 = fast_exp::result(v); return v_5 * v_5; } }; - template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; - template struct fast_exp { static inline T result(const T v) { T v_4 = fast_exp::result(v); return v_4 * v_4; } }; - template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; - template struct fast_exp { static inline T result(const T v) { T v_3 = fast_exp::result(v); return v_3 * v_3; } }; - template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; - template struct fast_exp { static inline T result(const T v) { T v_2 = v * v; return v_2 * v_2; } }; - template struct fast_exp { static inline T result(const T v) { return v * v * v; } }; - template struct fast_exp { static inline T result(const T v) { return v * v; } }; - template struct fast_exp { static inline T result(const T v) { return v; } }; - template struct fast_exp { static inline T result(const T ) { return T(1); } }; - - #define exprtk_define_unary_function(FunctionName) \ - template \ - inline T FunctionName (const T v) \ - { \ - const typename details::number_type::type num_type; \ - return FunctionName##_impl(v,num_type); \ - } \ - - exprtk_define_unary_function(abs ) - exprtk_define_unary_function(acos ) - exprtk_define_unary_function(acosh) - exprtk_define_unary_function(asin ) - exprtk_define_unary_function(asinh) - exprtk_define_unary_function(atan ) - exprtk_define_unary_function(atanh) - exprtk_define_unary_function(ceil ) - exprtk_define_unary_function(cos ) - exprtk_define_unary_function(cosh ) - exprtk_define_unary_function(exp ) - exprtk_define_unary_function(expm1) - exprtk_define_unary_function(floor) - exprtk_define_unary_function(log ) - exprtk_define_unary_function(log10) - exprtk_define_unary_function(log2 ) - exprtk_define_unary_function(log1p) - exprtk_define_unary_function(neg ) - exprtk_define_unary_function(pos ) - exprtk_define_unary_function(round) - exprtk_define_unary_function(sin ) - exprtk_define_unary_function(sinc ) - exprtk_define_unary_function(sinh ) - exprtk_define_unary_function(sqrt ) - exprtk_define_unary_function(tan ) - exprtk_define_unary_function(tanh ) - exprtk_define_unary_function(cot ) - exprtk_define_unary_function(sec ) - exprtk_define_unary_function(csc ) - exprtk_define_unary_function(r2d ) - exprtk_define_unary_function(d2r ) - exprtk_define_unary_function(d2g ) - exprtk_define_unary_function(g2d ) - exprtk_define_unary_function(notl ) - exprtk_define_unary_function(sgn ) - exprtk_define_unary_function(erf ) - exprtk_define_unary_function(erfc ) - exprtk_define_unary_function(ncdf ) - exprtk_define_unary_function(frac ) - exprtk_define_unary_function(trunc) - #undef exprtk_define_unary_function - } - - template - inline T compute_pow10(T d, const int exponent) - { - static const double fract10[] = - { - 0.0, - 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010, - 1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020, - 1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030, - 1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040, - 1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050, - 1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060, - 1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070, - 1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080, - 1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090, - 1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100, - 1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110, - 1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120, - 1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130, - 1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140, - 1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150, - 1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160, - 1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170, - 1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, - 1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, - 1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, - 1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, - 1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, - 1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, - 1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, - 1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, - 1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260, - 1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270, - 1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280, - 1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290, - 1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300, - 1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308 - }; - - static const int fract10_size = static_cast(sizeof(fract10) / sizeof(double)); - - const int e = std::abs(exponent); - - if (exponent >= std::numeric_limits::min_exponent10) - { - if (e < fract10_size) - { - if (exponent > 0) - return T(d * fract10[e]); - else - return T(d / fract10[e]); - } - else - return T(d * std::pow(10.0, 10.0 * exponent)); - } - else - { - d /= T(fract10[ -std::numeric_limits::min_exponent10]); - return T(d / fract10[-exponent + std::numeric_limits::min_exponent10]); - } - } - - template - inline bool string_to_type_converter_impl_ref(Iterator& itr, const Iterator end, T& result) - { - if (itr == end) - return false; - - const bool negative = ('-' == (*itr)); - - if (negative || ('+' == (*itr))) - { - if (end == ++itr) - return false; - } - - static const uchar_t zero = static_cast('0'); - - while ((end != itr) && (zero == (*itr))) ++itr; - - bool return_result = true; - unsigned int digit = 0; - const std::size_t length = static_cast(std::distance(itr,end)); - - if (length <= 4) - { - switch (length) - { - #ifdef exprtk_use_lut - - #define exprtk_process_digit \ - if ((digit = details::digit_table[(int)*itr++]) < 10) \ - result = result * 10 + (digit); \ - else \ - { \ - return_result = false; \ - break; \ - } \ - exprtk_fallthrough \ - - #else - - #define exprtk_process_digit \ - if ((digit = (*itr++ - zero)) < 10) \ - result = result * T(10) + digit; \ - else \ - { \ - return_result = false; \ - break; \ - } \ - exprtk_fallthrough \ - - #endif - - case 4 : exprtk_process_digit - case 3 : exprtk_process_digit - case 2 : exprtk_process_digit - case 1 : if ((digit = (*itr - zero))>= 10) - { - digit = 0; - return_result = false; - } - - #undef exprtk_process_digit - } - } - else - return_result = false; - - if (length && return_result) - { - result = result * 10 + static_cast(digit); - ++itr; - } - - result = negative ? -result : result; - return return_result; - } - - template - static inline bool parse_nan(Iterator& itr, const Iterator end, T& t) - { - typedef typename std::iterator_traits::value_type type; - - static const std::size_t nan_length = 3; - - if (std::distance(itr,end) != static_cast(nan_length)) - return false; - - if (static_cast('n') == (*itr)) - { - if ( - (static_cast('a') != *(itr + 1)) || - (static_cast('n') != *(itr + 2)) - ) - { - return false; - } - } - else if ( - (static_cast('A') != *(itr + 1)) || - (static_cast('N') != *(itr + 2)) - ) - { - return false; - } - - t = std::numeric_limits::quiet_NaN(); - - return true; - } - - template - static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, const bool negative) - { - static const char_t inf_uc[] = "INFINITY"; - static const char_t inf_lc[] = "infinity"; - static const std::size_t inf_length = 8; - - const std::size_t length = static_cast(std::distance(itr,end)); - - if ((3 != length) && (inf_length != length)) - return false; - - char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; - - while (end != itr) - { - if (*inf_itr == static_cast(*itr)) - { - ++itr; - ++inf_itr; - continue; - } - else - return false; - } - - if (negative) - t = -std::numeric_limits::infinity(); - else - t = std::numeric_limits::infinity(); - - return true; - } - - template - inline bool valid_exponent(const int exponent, numeric::details::real_type_tag) - { - using namespace details::numeric; - return (numeric_info::min_exp <= exponent) && (exponent <= numeric_info::max_exp); - } - - template - inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag) - { - if (end == itr_external) return false; - - Iterator itr = itr_external; - - T d = T(0); - - const bool negative = ('-' == (*itr)); - - if (negative || '+' == (*itr)) - { - if (end == ++itr) - return false; - } - - bool instate = false; - - static const char_t zero = static_cast('0'); - - #define parse_digit_1(d) \ - if ((digit = (*itr - zero)) < 10) \ - { d = d * T(10) + digit; } \ - else \ - { break; } \ - if (end == ++itr) break; \ - - #define parse_digit_2(d) \ - if ((digit = (*itr - zero)) < 10) \ - { d = d * T(10) + digit; } \ - else \ - { break; } \ - ++itr; \ - - if ('.' != (*itr)) - { - const Iterator curr = itr; - - while ((end != itr) && (zero == (*itr))) ++itr; - - while (end != itr) - { - unsigned int digit; - parse_digit_1(d) - parse_digit_1(d) - parse_digit_2(d) - } - - if (curr != itr) instate = true; - } - - int exponent = 0; - - if (end != itr) - { - if ('.' == (*itr)) - { - const Iterator curr = ++itr; - T tmp_d = T(0); - - while (end != itr) - { - unsigned int digit; - parse_digit_1(tmp_d) - parse_digit_1(tmp_d) - parse_digit_2(tmp_d) - } - - if (curr != itr) - { - instate = true; - - const int frac_exponent = static_cast(-std::distance(curr, itr)); - - if (!valid_exponent(frac_exponent, numeric::details::real_type_tag())) - return false; - - d += compute_pow10(tmp_d, frac_exponent); - } - - #undef parse_digit_1 - #undef parse_digit_2 - } - - if (end != itr) - { - typename std::iterator_traits::value_type c = (*itr); - - if (('e' == c) || ('E' == c)) - { - int exp = 0; - - if (!details::string_to_type_converter_impl_ref(++itr, end, exp)) - { - if (end == itr) - return false; - else - c = (*itr); - } - - exponent += exp; - } - - if (end != itr) - { - if (('f' == c) || ('F' == c) || ('l' == c) || ('L' == c)) - ++itr; - else if ('#' == c) - { - if (end == ++itr) - return false; - else if (('I' <= (*itr)) && ((*itr) <= 'n')) - { - if (('i' == (*itr)) || ('I' == (*itr))) - { - return parse_inf(itr, end, t, negative); - } - else if (('n' == (*itr)) || ('N' == (*itr))) - { - return parse_nan(itr, end, t); - } - else - return false; - } - else - return false; - } - else if (('I' <= (*itr)) && ((*itr) <= 'n')) - { - if (('i' == (*itr)) || ('I' == (*itr))) - { - return parse_inf(itr, end, t, negative); - } - else if (('n' == (*itr)) || ('N' == (*itr))) - { - return parse_nan(itr, end, t); - } - else - return false; - } - else - return false; - } - } - } - - if ((end != itr) || (!instate)) - return false; - else if (!valid_exponent(exponent, numeric::details::real_type_tag())) - return false; - else if (exponent) - d = compute_pow10(d,exponent); - - t = static_cast((negative) ? -d : d); - return true; - } - - template - inline bool string_to_real(const std::string& s, T& t) - { - const typename numeric::details::number_type::type num_type; - - char_cptr begin = s.data(); - char_cptr end = s.data() + s.size(); - - return string_to_real(begin, end, t, num_type); - } - - template - struct functor_t - { - /* - Note: The following definitions for Type, may require tweaking - based on the compiler and target architecture. The benchmark - should provide enough information to make the right choice. - */ - //typedef T Type; - //typedef const T Type; - typedef const T& Type; - typedef T& RefType; - typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3); - typedef T (*tfunc_t)(Type t0, Type t1, Type t2); - typedef T (*bfunc_t)(Type t0, Type t1); - typedef T (*ufunc_t)(Type t0); - }; - - } // namespace details - - struct loop_runtime_check - { - enum loop_types - { - e_invalid = 0, - e_for_loop = 1, - e_while_loop = 2, - e_repeat_until_loop = 4, - e_all_loops = 7 - }; - - enum violation_type - { - e_unknown = 0, - e_iteration_count = 1, - e_timeout = 2 - }; - - loop_types loop_set; - - loop_runtime_check() - : loop_set(e_invalid) - , max_loop_iterations(0) - {} - - details::_uint64_t max_loop_iterations; - - struct violation_context - { - loop_types loop; - violation_type violation; - details::_uint64_t iteration_count; - }; - - virtual bool check() - { - return true; - } - - virtual void handle_runtime_violation(const violation_context&) - { - throw std::runtime_error("ExprTk Loop runtime violation."); - } - - virtual ~loop_runtime_check() - {} - }; - - typedef loop_runtime_check* loop_runtime_check_ptr; - - struct vector_access_runtime_check - { - struct violation_context - { - void* base_ptr; - void* end_ptr; - void* access_ptr; - std::size_t type_size; - }; - - virtual ~vector_access_runtime_check() - {} - - virtual bool handle_runtime_violation(violation_context& /*context*/) - { - throw std::runtime_error("ExprTk runtime vector access violation."); - #if !defined(_MSC_VER) && !defined(__NVCOMPILER) - return false; - #endif - } - }; - - typedef vector_access_runtime_check* vector_access_runtime_check_ptr; - - struct assert_check - { - struct assert_context - { - std::string condition; - std::string message; - std::string id; - std::size_t offet; - }; - - virtual ~assert_check() - {} - - virtual void handle_assert(const assert_context& /*context*/) - { - } - }; - - typedef assert_check* assert_check_ptr; - - struct compilation_check - { - struct compilation_context - { - std::string error_message; - }; - - virtual bool continue_compilation(compilation_context& /*context*/) = 0; - - virtual ~compilation_check() - {} - }; - - typedef compilation_check* compilation_check_ptr; - - namespace lexer - { - struct token - { - enum token_type - { - e_none = 0, e_error = 1, e_err_symbol = 2, - e_err_number = 3, e_err_string = 4, e_err_sfunc = 5, - e_eof = 6, e_number = 7, e_symbol = 8, - e_string = 9, e_assign = 10, e_addass = 11, - e_subass = 12, e_mulass = 13, e_divass = 14, - e_modass = 15, e_shr = 16, e_shl = 17, - e_lte = 18, e_ne = 19, e_gte = 20, - e_swap = 21, e_lt = '<', e_gt = '>', - e_eq = '=', e_rbracket = ')', e_lbracket = '(', - e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}', - e_lcrlbracket = '{', e_comma = ',', e_add = '+', - e_sub = '-', e_div = '/', e_mul = '*', - e_mod = '%', e_pow = '^', e_colon = ':', - e_ternary = '?' - }; - - token() - : type(e_none) - , value("") - , position(std::numeric_limits::max()) - {} - - void clear() - { - type = e_none; - value = ""; - position = std::numeric_limits::max(); - } - - template - inline token& set_operator(const token_type tt, - const Iterator begin, const Iterator end, - const Iterator base_begin = Iterator(0)) - { - type = tt; - value.assign(begin,end); - if (base_begin) - position = static_cast(std::distance(base_begin,begin)); - return (*this); - } - - template - inline token& set_symbol(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) - { - type = e_symbol; - value.assign(begin,end); - if (base_begin) - position = static_cast(std::distance(base_begin,begin)); - return (*this); - } - - template - inline token& set_numeric(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) - { - type = e_number; - value.assign(begin,end); - if (base_begin) - position = static_cast(std::distance(base_begin,begin)); - return (*this); - } - - template - inline token& set_string(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) - { - type = e_string; - value.assign(begin,end); - if (base_begin) - position = static_cast(std::distance(base_begin,begin)); - return (*this); - } - - inline token& set_string(const std::string& s, const std::size_t p) - { - type = e_string; - value = s; - position = p; - return (*this); - } - - template - inline token& set_error(const token_type et, - const Iterator begin, const Iterator end, - const Iterator base_begin = Iterator(0)) - { - if ( - (e_error == et) || - (e_err_symbol == et) || - (e_err_number == et) || - (e_err_string == et) || - (e_err_sfunc == et) - ) - { - type = et; - } - else - type = e_error; - - value.assign(begin,end); - - if (base_begin) - position = static_cast(std::distance(base_begin,begin)); - - return (*this); - } - - static inline std::string to_str(token_type t) - { - switch (t) - { - case e_none : return "NONE"; - case e_error : return "ERROR"; - case e_err_symbol : return "ERROR_SYMBOL"; - case e_err_number : return "ERROR_NUMBER"; - case e_err_string : return "ERROR_STRING"; - case e_eof : return "EOF"; - case e_number : return "NUMBER"; - case e_symbol : return "SYMBOL"; - case e_string : return "STRING"; - case e_assign : return ":="; - case e_addass : return "+="; - case e_subass : return "-="; - case e_mulass : return "*="; - case e_divass : return "/="; - case e_modass : return "%="; - case e_shr : return ">>"; - case e_shl : return "<<"; - case e_lte : return "<="; - case e_ne : return "!="; - case e_gte : return ">="; - case e_lt : return "<"; - case e_gt : return ">"; - case e_eq : return "="; - case e_rbracket : return ")"; - case e_lbracket : return "("; - case e_rsqrbracket : return "]"; - case e_lsqrbracket : return "["; - case e_rcrlbracket : return "}"; - case e_lcrlbracket : return "{"; - case e_comma : return ","; - case e_add : return "+"; - case e_sub : return "-"; - case e_div : return "/"; - case e_mul : return "*"; - case e_mod : return "%"; - case e_pow : return "^"; - case e_colon : return ":"; - case e_ternary : return "?"; - case e_swap : return "<=>"; - default : return "UNKNOWN"; - } - } - - static inline std::string seperator_to_str(const token_type t) - { - switch (t) - { - case e_comma : return ","; - case e_colon : return ":"; - case e_eof : return ";"; - default : return "UNKNOWN"; - } - - return "UNKNOWN"; - } - - inline bool is_error() const - { - return ( - (e_error == type) || - (e_err_symbol == type) || - (e_err_number == type) || - (e_err_string == type) || - (e_err_sfunc == type) - ); - } - - token_type type; - std::string value; - std::size_t position; - }; - - class generator - { - public: - - typedef token token_t; - typedef std::vector token_list_t; - typedef token_list_t::iterator token_list_itr_t; - typedef details::char_t char_t; - - generator() - : base_itr_(0) - , s_itr_ (0) - , s_end_ (0) - { - clear(); - } - - inline void clear() - { - base_itr_ = 0; - s_itr_ = 0; - s_end_ = 0; - token_list_.clear(); - token_itr_ = token_list_.end(); - store_token_itr_ = token_list_.end(); - } - - inline bool process(const std::string& str) - { - base_itr_ = str.data(); - s_itr_ = str.data(); - s_end_ = str.data() + str.size(); - - eof_token_.set_operator(token_t::e_eof, s_end_, s_end_, base_itr_); - token_list_.clear(); - - while (!is_end(s_itr_)) - { - scan_token(); - - if (!token_list_.empty() && token_list_.back().is_error()) - return false; - } - - return true; - } - - inline bool empty() const - { - return token_list_.empty(); - } - - inline std::size_t size() const - { - return token_list_.size(); - } - - inline void begin() - { - token_itr_ = token_list_.begin(); - store_token_itr_ = token_list_.begin(); - } - - inline void store() - { - store_token_itr_ = token_itr_; - } - - inline void restore() - { - token_itr_ = store_token_itr_; - } - - inline token_t& next_token() - { - if (token_list_.end() != token_itr_) - { - return *token_itr_++; - } - else - return eof_token_; - } - - inline token_t& peek_next_token() - { - if (token_list_.end() != token_itr_) - { - return *token_itr_; - } - else - return eof_token_; - } - - inline token_t& operator[](const std::size_t& index) - { - if (index < token_list_.size()) - { - return token_list_[index]; - } - else - return eof_token_; - } - - inline token_t operator[](const std::size_t& index) const - { - if (index < token_list_.size()) - { - return token_list_[index]; - } - else - return eof_token_; - } - - inline bool finished() const - { - return (token_list_.end() == token_itr_); - } - - inline void insert_front(token_t::token_type tk_type) - { - if ( - !token_list_.empty() && - (token_list_.end() != token_itr_) - ) - { - token_t t = *token_itr_; - - t.type = tk_type; - token_itr_ = token_list_.insert(token_itr_,t); - } - } - - inline std::string substr(const std::size_t& begin, const std::size_t& end) const - { - const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; - const details::char_cptr end_itr = ((base_itr_ + end ) < s_end_) ? (base_itr_ + end ) : s_end_; - - return std::string(begin_itr,end_itr); - } - - inline std::string remaining() const - { - if (finished()) - return ""; - else if (token_list_.begin() != token_itr_) - return std::string(base_itr_ + (token_itr_ - 1)->position, s_end_); - else - return std::string(base_itr_ + token_itr_->position, s_end_); - } - - private: - - inline bool is_end(details::char_cptr itr) const - { - return (s_end_ == itr); - } - - #ifndef exprtk_disable_comments - inline bool is_comment_start(details::char_cptr itr) const - { - const char_t c0 = *(itr + 0); - const char_t c1 = *(itr + 1); - - if ('#' == c0) - return true; - else if (!is_end(itr + 1)) - { - if (('/' == c0) && ('/' == c1)) return true; - if (('/' == c0) && ('*' == c1)) return true; - } - return false; - } - #else - inline bool is_comment_start(details::char_cptr) const - { - return false; - } - #endif - - inline void skip_whitespace() - { - while (!is_end(s_itr_) && details::is_whitespace(*s_itr_)) - { - ++s_itr_; - } - } - - inline void skip_comments() - { - #ifndef exprtk_disable_comments - // The following comment styles are supported: - // 1. // .... \n - // 2. # .... \n - // 3. /* .... */ - struct test - { - static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr) - { - mode = 0; - if ('#' == c0) { mode = 1; incr = 1; } - else if ('/' == c0) - { - if ('/' == c1) { mode = 1; incr = 2; } - else if ('*' == c1) { mode = 2; incr = 2; } - } - return (0 != mode); - } - - static inline bool comment_end(const char_t c0, const char_t c1, int& mode) - { - if ( - ((1 == mode) && ('\n' == c0)) || - ((2 == mode) && ( '*' == c0) && ('/' == c1)) - ) - { - mode = 0; - return true; - } - else - return false; - } - }; - - int mode = 0; - int increment = 0; - - if (is_end(s_itr_)) - return; - else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment)) - return; - - details::char_cptr cmt_start = s_itr_; - - s_itr_ += increment; - - while (!is_end(s_itr_)) - { - if ((1 == mode) && test::comment_end(*s_itr_, 0, mode)) - { - ++s_itr_; - return; - } - - if ((2 == mode)) - { - if (!is_end((s_itr_ + 1)) && test::comment_end(*s_itr_, *(s_itr_ + 1), mode)) - { - s_itr_ += 2; - return; - } - } - - ++s_itr_; - } - - if (2 == mode) - { - token_t t; - t.set_error(token::e_error, cmt_start, cmt_start + mode, base_itr_); - token_list_.push_back(t); - } - #endif - } - - inline bool next_is_digit(const details::char_cptr itr) const - { - return ((itr + 1) != s_end_) && - details::is_digit(*(itr + 1)); - } - - inline void scan_token() - { - const char_t c = *s_itr_; - - if (details::is_whitespace(c)) - { - skip_whitespace(); - return; - } - else if (is_comment_start(s_itr_)) - { - skip_comments(); - return; - } - else if (details::is_operator_char(c)) - { - scan_operator(); - return; - } - else if (details::is_letter(c)) - { - scan_symbol(); - return; - } - else if (('.' == c) && !next_is_digit(s_itr_)) - { - scan_operator(); - return; - } - else if (details::is_digit(c) || ('.' == c)) - { - scan_number(); - return; - } - else if ('$' == c) - { - scan_special_function(); - return; - } - #ifndef exprtk_disable_string_capabilities - else if ('\'' == c) - { - scan_string(); - return; - } - #endif - else if ('~' == c) - { - token_t t; - t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); - token_list_.push_back(t); - ++s_itr_; - return; - } - else - { - token_t t; - t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_); - token_list_.push_back(t); - ++s_itr_; - } - } - - inline void scan_operator() - { - token_t t; - - const char_t c0 = s_itr_[0]; - - if (!is_end(s_itr_ + 1)) - { - const char_t c1 = s_itr_[1]; - - if (!is_end(s_itr_ + 2)) - { - const char_t c2 = s_itr_[2]; - - if ((c0 == '<') && (c1 == '=') && (c2 == '>')) - { - t.set_operator(token_t::e_swap, s_itr_, s_itr_ + 3, base_itr_); - token_list_.push_back(t); - s_itr_ += 3; - return; - } - } - - token_t::token_type ttype = token_t::e_none; - - if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; - else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; - else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; - else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne; - else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq; - else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign; - else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl; - else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr; - else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass; - else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass; - else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass; - else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass; - else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass; - - if (token_t::e_none != ttype) - { - t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_); - token_list_.push_back(t); - s_itr_ += 2; - return; - } - } - - if ('<' == c0) - t.set_operator(token_t::e_lt , s_itr_, s_itr_ + 1, base_itr_); - else if ('>' == c0) - t.set_operator(token_t::e_gt , s_itr_, s_itr_ + 1, base_itr_); - else if (';' == c0) - t.set_operator(token_t::e_eof, s_itr_, s_itr_ + 1, base_itr_); - else if ('&' == c0) - t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); - else if ('|' == c0) - t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); - else - t.set_operator(token_t::token_type(c0), s_itr_, s_itr_ + 1, base_itr_); - - token_list_.push_back(t); - ++s_itr_; - } - - inline void scan_symbol() - { - details::char_cptr initial_itr = s_itr_; - - while (!is_end(s_itr_)) - { - if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_))) - { - if ('.' != (*s_itr_)) - break; - /* - Permit symbols that contain a 'dot' - Allowed : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123 - Disallowed: .abc, abc., abc., abc. - */ - if ( - (s_itr_ != initial_itr) && - !is_end(s_itr_ + 1) && - !details::is_letter_or_digit(*(s_itr_ + 1)) && - ('_' != (*(s_itr_ + 1))) - ) - break; - } - - ++s_itr_; - } - - token_t t; - t.set_symbol(initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - } - - inline void scan_number() - { - /* - Attempt to match a valid numeric value in one of the following formats: - (01) 123456 - (02) 123456. - (03) 123.456 - (04) 123.456e3 - (05) 123.456E3 - (06) 123.456e+3 - (07) 123.456E+3 - (08) 123.456e-3 - (09) 123.456E-3 - (00) .1234 - (11) .1234e3 - (12) .1234E+3 - (13) .1234e+3 - (14) .1234E-3 - (15) .1234e-3 - */ - - details::char_cptr initial_itr = s_itr_; - bool dot_found = false; - bool e_found = false; - bool post_e_sign_found = false; - bool post_e_digit_found = false; - token_t t; - - while (!is_end(s_itr_)) - { - if ('.' == (*s_itr_)) - { - if (dot_found) - { - t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - - dot_found = true; - ++s_itr_; - - continue; - } - else if ('e' == std::tolower(*s_itr_)) - { - const char_t& c = *(s_itr_ + 1); - - if (is_end(s_itr_ + 1)) - { - t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - else if ( - ('+' != c) && - ('-' != c) && - !details::is_digit(c) - ) - { - t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - - e_found = true; - ++s_itr_; - - continue; - } - else if (e_found && details::is_sign(*s_itr_) && !post_e_digit_found) - { - if (post_e_sign_found) - { - t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - - post_e_sign_found = true; - ++s_itr_; - - continue; - } - else if (e_found && details::is_digit(*s_itr_)) - { - post_e_digit_found = true; - ++s_itr_; - - continue; - } - else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_)) - break; - else - ++s_itr_; - } - - t.set_numeric(initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - - inline void scan_special_function() - { - details::char_cptr initial_itr = s_itr_; - token_t t; - - // $fdd(x,x,x) = at least 11 chars - if (std::distance(s_itr_,s_end_) < 11) - { - t.set_error( - token::e_err_sfunc, - initial_itr, std::min(initial_itr + 11, s_end_), - base_itr_); - token_list_.push_back(t); - - return; - } - - if ( - !(('$' == *s_itr_) && - (details::imatch ('f',*(s_itr_ + 1))) && - (details::is_digit(*(s_itr_ + 2))) && - (details::is_digit(*(s_itr_ + 3)))) - ) - { - t.set_error( - token::e_err_sfunc, - initial_itr, std::min(initial_itr + 4, s_end_), - base_itr_); - token_list_.push_back(t); - - return; - } - - s_itr_ += 4; // $fdd = 4chars - - t.set_symbol(initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - - #ifndef exprtk_disable_string_capabilities - inline void scan_string() - { - details::char_cptr initial_itr = s_itr_ + 1; - token_t t; - - if (std::distance(s_itr_,s_end_) < 2) - { - t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_); - token_list_.push_back(t); - - return; - } - - ++s_itr_; - - bool escaped_found = false; - bool escaped = false; - - while (!is_end(s_itr_)) - { - if (!details::is_valid_string_char(*s_itr_)) - { - t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - else if (!escaped && ('\\' == *s_itr_)) - { - escaped_found = true; - escaped = true; - ++s_itr_; - - continue; - } - else if (!escaped) - { - if ('\'' == *s_itr_) - break; - } - else if (escaped) - { - if ( - !is_end(s_itr_) && ('0' == *(s_itr_)) && - ((s_itr_ + 4) <= s_end_) - ) - { - const bool x_separator = ('X' == std::toupper(*(s_itr_ + 1))); - - const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) && - details::is_hex_digit(*(s_itr_ + 3)) ; - - if (!(x_separator && both_digits)) - { - t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - else - s_itr_ += 3; - } - - escaped = false; - } - - ++s_itr_; - } - - if (is_end(s_itr_)) - { - t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - - if (!escaped_found) - t.set_string(initial_itr, s_itr_, base_itr_); - else - { - std::string parsed_string(initial_itr,s_itr_); - - if (!details::cleanup_escapes(parsed_string)) - { - t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); - token_list_.push_back(t); - - return; - } - - t.set_string( - parsed_string, - static_cast(std::distance(base_itr_,initial_itr))); - } - - token_list_.push_back(t); - ++s_itr_; - - return; - } - #endif - - private: - - token_list_t token_list_; - token_list_itr_t token_itr_; - token_list_itr_t store_token_itr_; - token_t eof_token_; - details::char_cptr base_itr_; - details::char_cptr s_itr_; - details::char_cptr s_end_; - - friend class token_scanner; - friend class token_modifier; - friend class token_inserter; - friend class token_joiner; - }; // class generator - - class helper_interface - { - public: - - virtual void init() { } - virtual void reset() { } - virtual bool result() { return true; } - virtual std::size_t process(generator&) { return 0; } - virtual ~helper_interface() { } - }; - - class token_scanner : public helper_interface - { - public: - - virtual ~token_scanner() - {} - - explicit token_scanner(const std::size_t& stride) - : stride_(stride) - { - if (stride > 4) - { - throw std::invalid_argument("token_scanner() - Invalid stride value"); - } - } - - inline std::size_t process(generator& g) exprtk_override - { - if (g.token_list_.size() >= stride_) - { - for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) - { - token t; - - switch (stride_) - { - case 1 : - { - const token& t0 = g.token_list_[i]; - - if (!operator()(t0)) - { - return 0; - } - } - break; - - case 2 : - { - const token& t0 = g.token_list_[i ]; - const token& t1 = g.token_list_[i + 1]; - - if (!operator()(t0, t1)) - { - return 0; - } - } - break; - - case 3 : - { - const token& t0 = g.token_list_[i ]; - const token& t1 = g.token_list_[i + 1]; - const token& t2 = g.token_list_[i + 2]; - - if (!operator()(t0, t1, t2)) - { - return 0; - } - } - break; - - case 4 : - { - const token& t0 = g.token_list_[i ]; - const token& t1 = g.token_list_[i + 1]; - const token& t2 = g.token_list_[i + 2]; - const token& t3 = g.token_list_[i + 3]; - - if (!operator()(t0, t1, t2, t3)) - { - return 0; - } - } - break; - } - } - } - - return 0; - } - - virtual bool operator() (const token&) - { - return false; - } - - virtual bool operator() (const token&, const token&) - { - return false; - } - - virtual bool operator() (const token&, const token&, const token&) - { - return false; - } - - virtual bool operator() (const token&, const token&, const token&, const token&) - { - return false; - } - - private: - - const std::size_t stride_; - }; // class token_scanner - - class token_modifier : public helper_interface - { - public: - - inline std::size_t process(generator& g) exprtk_override - { - std::size_t changes = 0; - - for (std::size_t i = 0; i < g.token_list_.size(); ++i) - { - if (modify(g.token_list_[i])) changes++; - } - - return changes; - } - - virtual bool modify(token& t) = 0; - }; - - class token_inserter : public helper_interface - { - public: - - explicit token_inserter(const std::size_t& stride) - : stride_(stride) - { - if (stride > 5) - { - throw std::invalid_argument("token_inserter() - Invalid stride value"); - } - } - - inline std::size_t process(generator& g) exprtk_override - { - if (g.token_list_.empty()) - return 0; - else if (g.token_list_.size() < stride_) - return 0; - - std::size_t changes = 0; - - typedef std::pair insert_t; - std::vector insert_list; - insert_list.reserve(10000); - - for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) - { - int insert_index = -1; - token t; - - switch (stride_) - { - case 1 : insert_index = insert(g.token_list_[i],t); - break; - - case 2 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], t); - break; - - case 3 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], t); - break; - - case 4 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], t); - break; - - case 5 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], g.token_list_[i + 4], t); - break; - } - - if ((insert_index >= 0) && (insert_index <= (static_cast(stride_) + 1))) - { - insert_list.push_back(insert_t(i, t)); - changes++; - } - } - - if (!insert_list.empty()) - { - generator::token_list_t token_list; - - std::size_t insert_index = 0; - - for (std::size_t i = 0; i < g.token_list_.size(); ++i) - { - token_list.push_back(g.token_list_[i]); - - if ( - (insert_index < insert_list.size()) && - (insert_list[insert_index].first == i) - ) - { - token_list.push_back(insert_list[insert_index].second); - insert_index++; - } - } - - std::swap(g.token_list_,token_list); - } - - return changes; - } - - #define token_inserter_empty_body \ - { \ - return -1; \ - } \ - - inline virtual int insert(const token&, token&) - token_inserter_empty_body - - inline virtual int insert(const token&, const token&, token&) - token_inserter_empty_body - - inline virtual int insert(const token&, const token&, const token&, token&) - token_inserter_empty_body - - inline virtual int insert(const token&, const token&, const token&, const token&, token&) - token_inserter_empty_body - - inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) - token_inserter_empty_body - - #undef token_inserter_empty_body - - private: - - const std::size_t stride_; - }; - - class token_joiner : public helper_interface - { - public: - - explicit token_joiner(const std::size_t& stride) - : stride_(stride) - {} - - inline std::size_t process(generator& g) exprtk_override - { - if (g.token_list_.empty()) - return 0; - - switch (stride_) - { - case 2 : return process_stride_2(g); - case 3 : return process_stride_3(g); - default : return 0; - } - } - - virtual bool join(const token&, const token&, token&) { return false; } - virtual bool join(const token&, const token&, const token&, token&) { return false; } - - private: - - inline std::size_t process_stride_2(generator& g) - { - if (g.token_list_.size() < 2) - return 0; - - std::size_t changes = 0; - - generator::token_list_t token_list; - token_list.reserve(10000); - - for (int i = 0; i < static_cast(g.token_list_.size() - 1); ++i) - { - token t; - - for ( ; ; ) - { - if (!join(g[i], g[i + 1], t)) - { - token_list.push_back(g[i]); - break; - } - - token_list.push_back(t); - - ++changes; - - i += 2; - - if (static_cast(i) >= (g.token_list_.size() - 1)) - break; - } - } - - token_list.push_back(g.token_list_.back()); - - assert(token_list.size() <= g.token_list_.size()); - - std::swap(token_list, g.token_list_); - - return changes; - } - - inline std::size_t process_stride_3(generator& g) - { - if (g.token_list_.size() < 3) - return 0; - - std::size_t changes = 0; - - generator::token_list_t token_list; - token_list.reserve(10000); - - for (int i = 0; i < static_cast(g.token_list_.size() - 2); ++i) - { - token t; - - for ( ; ; ) - { - if (!join(g[i], g[i + 1], g[i + 2], t)) - { - token_list.push_back(g[i]); - break; - } - - token_list.push_back(t); - - ++changes; - - i += 3; - - if (static_cast(i) >= (g.token_list_.size() - 2)) - break; - } - } - - token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 2)); - token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 1)); - - assert(token_list.size() <= g.token_list_.size()); - - std::swap(token_list, g.token_list_); - - return changes; - } - - const std::size_t stride_; - }; - - namespace helper - { - - inline void dump(const lexer::generator& generator) - { - for (std::size_t i = 0; i < generator.size(); ++i) - { - const lexer::token& t = generator[i]; - printf("Token[%02d] @ %03d %6s --> '%s'\n", - static_cast(i), - static_cast(t.position), - t.to_str(t.type).c_str(), - t.value.c_str()); - } - } - - class commutative_inserter : public lexer::token_inserter - { - public: - - using lexer::token_inserter::insert; - - commutative_inserter() - : lexer::token_inserter(2) - {} - - inline void ignore_symbol(const std::string& symbol) - { - ignore_set_.insert(symbol); - } - - inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) exprtk_override - { - bool match = false; - new_token.type = lexer::token::e_mul; - new_token.value = "*"; - new_token.position = t1.position; - - if (t0.type == lexer::token::e_symbol) - { - if (ignore_set_.end() != ignore_set_.find(t0.value)) - { - return -1; - } - else if (!t0.value.empty() && ('$' == t0.value[0])) - { - return -1; - } - } - - if (t1.type == lexer::token::e_symbol) - { - if (ignore_set_.end() != ignore_set_.find(t1.value)) - { - return -1; - } - } - if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true; - else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true; - else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true; - else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true; - else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_number )) match = true; - else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_number )) match = true; - else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number )) match = true; - else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number )) match = true; - else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true; - else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true; - else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true; - else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_symbol )) match = true; - - return (match) ? 1 : -1; - } - - private: - - std::set ignore_set_; - }; - - class operator_joiner exprtk_final : public token_joiner - { - public: - - explicit operator_joiner(const std::size_t& stride) - : token_joiner(stride) - {} - - inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) exprtk_override - { - // ': =' --> ':=' - if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_assign; - t.value = ":="; - t.position = t0.position; - - return true; - } - // '+ =' --> '+=' - else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_addass; - t.value = "+="; - t.position = t0.position; - - return true; - } - // '- =' --> '-=' - else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_subass; - t.value = "-="; - t.position = t0.position; - - return true; - } - // '* =' --> '*=' - else if ((t0.type == lexer::token::e_mul) && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_mulass; - t.value = "*="; - t.position = t0.position; - - return true; - } - // '/ =' --> '/=' - else if ((t0.type == lexer::token::e_div) && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_divass; - t.value = "/="; - t.position = t0.position; - - return true; - } - // '% =' --> '%=' - else if ((t0.type == lexer::token::e_mod) && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_modass; - t.value = "%="; - t.position = t0.position; - - return true; - } - // '> =' --> '>=' - else if ((t0.type == lexer::token::e_gt) && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_gte; - t.value = ">="; - t.position = t0.position; - - return true; - } - // '< =' --> '<=' - else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_lte; - t.value = "<="; - t.position = t0.position; - - return true; - } - // '= =' --> '==' - else if ((t0.type == lexer::token::e_eq) && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_eq; - t.value = "=="; - t.position = t0.position; - - return true; - } - // '! =' --> '!=' - else if ((static_cast(t0.type) == '!') && (t1.type == lexer::token::e_eq)) - { - t.type = lexer::token::e_ne; - t.value = "!="; - t.position = t0.position; - - return true; - } - // '< >' --> '<>' - else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_gt)) - { - t.type = lexer::token::e_ne; - t.value = "<>"; - t.position = t0.position; - - return true; - } - // '<= >' --> '<=>' - else if ((t0.type == lexer::token::e_lte) && (t1.type == lexer::token::e_gt)) - { - t.type = lexer::token::e_swap; - t.value = "<=>"; - t.position = t0.position; - - return true; - } - // '+ -' --> '-' - else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_sub)) - { - t.type = lexer::token::e_sub; - t.value = "-"; - t.position = t0.position; - - return true; - } - // '- +' --> '-' - else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_add)) - { - t.type = lexer::token::e_sub; - t.value = "-"; - t.position = t0.position; - - return true; - } - // '- -' --> '+' - else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub)) - { - /* - Note: May need to reconsider this when wanting to implement - pre/postfix decrement operator - */ - t.type = lexer::token::e_add; - t.value = "+"; - t.position = t0.position; - - return true; - } - else - return false; - } - - inline bool join(const lexer::token& t0, - const lexer::token& t1, - const lexer::token& t2, - lexer::token& t) exprtk_override - { - // '[ * ]' --> '[*]' - if ( - (t0.type == lexer::token::e_lsqrbracket) && - (t1.type == lexer::token::e_mul ) && - (t2.type == lexer::token::e_rsqrbracket) - ) - { - t.type = lexer::token::e_symbol; - t.value = "[*]"; - t.position = t0.position; - - return true; - } - else - return false; - } - }; - - class bracket_checker exprtk_final : public lexer::token_scanner - { - public: - - using lexer::token_scanner::operator(); - - bracket_checker() - : token_scanner(1) - , state_(true) - {} - - bool result() exprtk_override - { - if (!stack_.empty()) - { - lexer::token t; - t.value = stack_.top().first; - t.position = stack_.top().second; - error_token_ = t; - state_ = false; - - return false; - } - else - return state_; - } - - lexer::token error_token() - { - return error_token_; - } - - void reset() exprtk_override - { - // Why? because msvc doesn't support swap properly. - stack_ = std::stack >(); - state_ = true; - error_token_.clear(); - } - - bool operator() (const lexer::token& t) exprtk_override - { - if ( - !t.value.empty() && - (lexer::token::e_string != t.type) && - (lexer::token::e_symbol != t.type) && - exprtk::details::is_bracket(t.value[0]) - ) - { - details::char_t c = t.value[0]; - - if (t.type == lexer::token::e_lbracket ) stack_.push(std::make_pair(')',t.position)); - else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); - else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); - else if (exprtk::details::is_right_bracket(c)) - { - if (stack_.empty()) - { - state_ = false; - error_token_ = t; - - return false; - } - else if (c != stack_.top().first) - { - state_ = false; - error_token_ = t; - - return false; - } - else - stack_.pop(); - } - } - - return true; - } - - private: - - bool state_; - std::stack > stack_; - lexer::token error_token_; - }; - - template - class numeric_checker exprtk_final : public lexer::token_scanner - { - public: - - using lexer::token_scanner::operator(); - - numeric_checker() - : token_scanner (1) - , current_index_(0) - {} - - bool result() exprtk_override - { - return error_list_.empty(); - } - - void reset() exprtk_override - { - error_list_.clear(); - current_index_ = 0; - } - - bool operator() (const lexer::token& t) exprtk_override - { - if (token::e_number == t.type) - { - T v; - - if (!exprtk::details::string_to_real(t.value,v)) - { - error_list_.push_back(current_index_); - } - } - - ++current_index_; - - return true; - } - - std::size_t error_count() const - { - return error_list_.size(); - } - - std::size_t error_index(const std::size_t& i) - { - if (i < error_list_.size()) - return error_list_[i]; - else - return std::numeric_limits::max(); - } - - void clear_errors() - { - error_list_.clear(); - } - - private: - - std::size_t current_index_; - std::vector error_list_; - }; - - class symbol_replacer exprtk_final : public lexer::token_modifier - { - private: - - typedef std::map,details::ilesscompare> replace_map_t; - - public: - - bool remove(const std::string& target_symbol) - { - const replace_map_t::iterator itr = replace_map_.find(target_symbol); - - if (replace_map_.end() == itr) - return false; - - replace_map_.erase(itr); - - return true; - } - - bool add_replace(const std::string& target_symbol, - const std::string& replace_symbol, - const lexer::token::token_type token_type = lexer::token::e_symbol) - { - const replace_map_t::iterator itr = replace_map_.find(target_symbol); - - if (replace_map_.end() != itr) - { - return false; - } - - replace_map_[target_symbol] = std::make_pair(replace_symbol,token_type); - - return true; - } - - void clear() - { - replace_map_.clear(); - } - - private: - - bool modify(lexer::token& t) exprtk_override - { - if (lexer::token::e_symbol == t.type) - { - if (replace_map_.empty()) - return false; - - const replace_map_t::iterator itr = replace_map_.find(t.value); - - if (replace_map_.end() != itr) - { - t.value = itr->second.first; - t.type = itr->second.second; - - return true; - } - } - - return false; - } - - replace_map_t replace_map_; - }; - - class sequence_validator exprtk_final : public lexer::token_scanner - { - private: - - typedef std::pair token_pair_t; - typedef std::set set_t; - - public: - - using lexer::token_scanner::operator(); - - sequence_validator() - : lexer::token_scanner(2) - { - add_invalid(lexer::token::e_number, lexer::token::e_number); - add_invalid(lexer::token::e_string, lexer::token::e_string); - add_invalid(lexer::token::e_number, lexer::token::e_string); - add_invalid(lexer::token::e_string, lexer::token::e_number); - - add_invalid_set1(lexer::token::e_assign ); - add_invalid_set1(lexer::token::e_shr ); - add_invalid_set1(lexer::token::e_shl ); - add_invalid_set1(lexer::token::e_lte ); - add_invalid_set1(lexer::token::e_ne ); - add_invalid_set1(lexer::token::e_gte ); - add_invalid_set1(lexer::token::e_lt ); - add_invalid_set1(lexer::token::e_gt ); - add_invalid_set1(lexer::token::e_eq ); - add_invalid_set1(lexer::token::e_comma ); - add_invalid_set1(lexer::token::e_add ); - add_invalid_set1(lexer::token::e_sub ); - add_invalid_set1(lexer::token::e_div ); - add_invalid_set1(lexer::token::e_mul ); - add_invalid_set1(lexer::token::e_mod ); - add_invalid_set1(lexer::token::e_pow ); - add_invalid_set1(lexer::token::e_colon ); - add_invalid_set1(lexer::token::e_ternary); - } - - bool result() exprtk_override - { - return error_list_.empty(); - } - - bool operator() (const lexer::token& t0, const lexer::token& t1) exprtk_override - { - const set_t::value_type p = std::make_pair(t0.type,t1.type); - - if (invalid_bracket_check(t0.type,t1.type)) - { - error_list_.push_back(std::make_pair(t0,t1)); - } - else if (invalid_comb_.find(p) != invalid_comb_.end()) - { - error_list_.push_back(std::make_pair(t0,t1)); - } - - return true; - } - - std::size_t error_count() const - { - return error_list_.size(); - } - - std::pair error(const std::size_t index) - { - if (index < error_list_.size()) - { - return error_list_[index]; - } - else - { - static const lexer::token error_token; - return std::make_pair(error_token,error_token); - } - } - - void clear_errors() - { - error_list_.clear(); - } - - private: - - void add_invalid(const lexer::token::token_type base, const lexer::token::token_type t) - { - invalid_comb_.insert(std::make_pair(base,t)); - } - - void add_invalid_set1(const lexer::token::token_type t) - { - add_invalid(t, lexer::token::e_assign); - add_invalid(t, lexer::token::e_shr ); - add_invalid(t, lexer::token::e_shl ); - add_invalid(t, lexer::token::e_lte ); - add_invalid(t, lexer::token::e_ne ); - add_invalid(t, lexer::token::e_gte ); - add_invalid(t, lexer::token::e_lt ); - add_invalid(t, lexer::token::e_gt ); - add_invalid(t, lexer::token::e_eq ); - add_invalid(t, lexer::token::e_comma ); - add_invalid(t, lexer::token::e_div ); - add_invalid(t, lexer::token::e_mul ); - add_invalid(t, lexer::token::e_mod ); - add_invalid(t, lexer::token::e_pow ); - add_invalid(t, lexer::token::e_colon ); - } - - bool invalid_bracket_check(const lexer::token::token_type base, const lexer::token::token_type t) - { - if (details::is_right_bracket(static_cast(base))) - { - switch (t) - { - case lexer::token::e_assign : return (']' != base); - case lexer::token::e_string : return (')' != base); - default : return false; - } - } - else if (details::is_left_bracket(static_cast(base))) - { - if (details::is_right_bracket(static_cast(t))) - return false; - else if (details::is_left_bracket(static_cast(t))) - return false; - else - { - switch (t) - { - case lexer::token::e_number : return false; - case lexer::token::e_symbol : return false; - case lexer::token::e_string : return false; - case lexer::token::e_add : return false; - case lexer::token::e_sub : return false; - case lexer::token::e_colon : return false; - case lexer::token::e_ternary : return false; - default : return true ; - } - } - } - else if (details::is_right_bracket(static_cast(t))) - { - switch (base) - { - case lexer::token::e_number : return false; - case lexer::token::e_symbol : return false; - case lexer::token::e_string : return false; - case lexer::token::e_eof : return false; - case lexer::token::e_colon : return false; - case lexer::token::e_ternary : return false; - default : return true ; - } - } - else if (details::is_left_bracket(static_cast(t))) - { - switch (base) - { - case lexer::token::e_rbracket : return true; - case lexer::token::e_rsqrbracket : return true; - case lexer::token::e_rcrlbracket : return true; - default : return false; - } - } - - return false; - } - - set_t invalid_comb_; - std::vector > error_list_; - }; - - class sequence_validator_3tokens exprtk_final : public lexer::token_scanner - { - private: - - typedef lexer::token::token_type token_t; - typedef std::pair > token_triplet_t; - typedef std::set set_t; - - public: - - using lexer::token_scanner::operator(); - - sequence_validator_3tokens() - : lexer::token_scanner(3) - { - add_invalid(lexer::token::e_number , lexer::token::e_number , lexer::token::e_number); - add_invalid(lexer::token::e_string , lexer::token::e_string , lexer::token::e_string); - add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma ); - - add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add ); - add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub ); - add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div ); - add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul ); - add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod ); - add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow ); - - add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add ); - add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub ); - add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div ); - add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul ); - add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod ); - add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); - } - - bool result() exprtk_override - { - return error_list_.empty(); - } - - bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) exprtk_override - { - const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type)); - - if (invalid_comb_.find(p) != invalid_comb_.end()) - { - error_list_.push_back(std::make_pair(t0,t1)); - } - - return true; - } - - std::size_t error_count() const - { - return error_list_.size(); - } - - std::pair error(const std::size_t index) - { - if (index < error_list_.size()) - { - return error_list_[index]; - } - else - { - static const lexer::token error_token; - return std::make_pair(error_token,error_token); - } - } - - void clear_errors() - { - error_list_.clear(); - } - - private: - - void add_invalid(const token_t t0, const token_t t1, const token_t t2) - { - invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2))); - } - - set_t invalid_comb_; - std::vector > error_list_; - }; - - struct helper_assembly - { - inline bool register_scanner(lexer::token_scanner* scanner) - { - if (token_scanner_list.end() != std::find(token_scanner_list.begin(), - token_scanner_list.end (), - scanner)) - { - return false; - } - - token_scanner_list.push_back(scanner); - - return true; - } - - inline bool register_modifier(lexer::token_modifier* modifier) - { - if (token_modifier_list.end() != std::find(token_modifier_list.begin(), - token_modifier_list.end (), - modifier)) - { - return false; - } - - token_modifier_list.push_back(modifier); - - return true; - } - - inline bool register_joiner(lexer::token_joiner* joiner) - { - if (token_joiner_list.end() != std::find(token_joiner_list.begin(), - token_joiner_list.end (), - joiner)) - { - return false; - } - - token_joiner_list.push_back(joiner); - - return true; - } - - inline bool register_inserter(lexer::token_inserter* inserter) - { - if (token_inserter_list.end() != std::find(token_inserter_list.begin(), - token_inserter_list.end (), - inserter)) - { - return false; - } - - token_inserter_list.push_back(inserter); - - return true; - } - - inline bool run_modifiers(lexer::generator& g) - { - error_token_modifier = reinterpret_cast(0); - - for (std::size_t i = 0; i < token_modifier_list.size(); ++i) - { - lexer::token_modifier& modifier = (*token_modifier_list[i]); - - modifier.reset(); - modifier.process(g); - - if (!modifier.result()) - { - error_token_modifier = token_modifier_list[i]; - - return false; - } - } - - return true; - } - - inline bool run_joiners(lexer::generator& g) - { - error_token_joiner = reinterpret_cast(0); - - for (std::size_t i = 0; i < token_joiner_list.size(); ++i) - { - lexer::token_joiner& joiner = (*token_joiner_list[i]); - - joiner.reset(); - joiner.process(g); - - if (!joiner.result()) - { - error_token_joiner = token_joiner_list[i]; - - return false; - } - } - - return true; - } - - inline bool run_inserters(lexer::generator& g) - { - error_token_inserter = reinterpret_cast(0); - - for (std::size_t i = 0; i < token_inserter_list.size(); ++i) - { - lexer::token_inserter& inserter = (*token_inserter_list[i]); - - inserter.reset(); - inserter.process(g); - - if (!inserter.result()) - { - error_token_inserter = token_inserter_list[i]; - - return false; - } - } - - return true; - } - - inline bool run_scanners(lexer::generator& g) - { - error_token_scanner = reinterpret_cast(0); - - for (std::size_t i = 0; i < token_scanner_list.size(); ++i) - { - lexer::token_scanner& scanner = (*token_scanner_list[i]); - - scanner.reset(); - scanner.process(g); - - if (!scanner.result()) - { - error_token_scanner = token_scanner_list[i]; - - return false; - } - } - - return true; - } - - std::vector token_scanner_list; - std::vector token_modifier_list; - std::vector token_joiner_list; - std::vector token_inserter_list; - - lexer::token_scanner* error_token_scanner; - lexer::token_modifier* error_token_modifier; - lexer::token_joiner* error_token_joiner; - lexer::token_inserter* error_token_inserter; - }; - } - - class parser_helper - { - public: - - typedef token token_t; - typedef generator generator_t; - - inline bool init(const std::string& str) - { - if (!lexer_.process(str)) - { - return false; - } - - lexer_.begin(); - - next_token(); - - return true; - } - - inline generator_t& lexer() - { - return lexer_; - } - - inline const generator_t& lexer() const - { - return lexer_; - } - - inline void store_token() - { - lexer_.store(); - store_current_token_ = current_token_; - } - - inline void restore_token() - { - lexer_.restore(); - current_token_ = store_current_token_; - } - - inline void next_token() - { - current_token_ = lexer_.next_token(); - } - - inline const token_t& current_token() const - { - return current_token_; - } - - inline const token_t& peek_next_token() - { - return lexer_.peek_next_token(); - } - - enum token_advance_mode - { - e_hold = 0, - e_advance = 1 - }; - - inline void advance_token(const token_advance_mode mode) - { - if (e_advance == mode) - { - next_token(); - } - } - - inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance) - { - if (current_token().type != ttype) - { - return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is(const token_t::token_type& ttype, - const std::string& value, - const token_advance_mode mode = e_advance) - { - if ( - (current_token().type != ttype) || - !exprtk::details::imatch(value,current_token().value) - ) - { - return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is(const std::string& value, - const token_advance_mode mode = e_advance) - { - if (!exprtk::details::imatch(value,current_token().value)) - { - return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is_arithmetic_opr(const token_advance_mode mode = e_advance) - { - switch (current_token().type) - { - case token_t::e_add : - case token_t::e_sub : - case token_t::e_div : - case token_t::e_mul : - case token_t::e_mod : - case token_t::e_pow : break; - default : return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is_ineq_opr(const token_advance_mode mode = e_advance) - { - switch (current_token().type) - { - case token_t::e_eq : - case token_t::e_lte : - case token_t::e_ne : - case token_t::e_gte : - case token_t::e_lt : - case token_t::e_gt : break; - default : return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is_left_bracket(const token_advance_mode mode = e_advance) - { - switch (current_token().type) - { - case token_t::e_lbracket : - case token_t::e_lcrlbracket : - case token_t::e_lsqrbracket : break; - default : return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is_right_bracket(const token_advance_mode mode = e_advance) - { - switch (current_token().type) - { - case token_t::e_rbracket : - case token_t::e_rcrlbracket : - case token_t::e_rsqrbracket : break; - default : return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is_bracket(const token_advance_mode mode = e_advance) - { - switch (current_token().type) - { - case token_t::e_rbracket : - case token_t::e_rcrlbracket : - case token_t::e_rsqrbracket : - case token_t::e_lbracket : - case token_t::e_lcrlbracket : - case token_t::e_lsqrbracket : break; - default : return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is_loop(const token_advance_mode mode = e_advance) - { - return token_is("for" , mode) || - token_is("while" , mode) || - token_is("repeat", mode) ; - } - - inline bool peek_token_is(const token_t::token_type& ttype) - { - return (lexer_.peek_next_token().type == ttype); - } - - inline bool peek_token_is(const std::string& s) - { - return (exprtk::details::imatch(lexer_.peek_next_token().value,s)); - } - - private: - - generator_t lexer_; - token_t current_token_; - token_t store_current_token_; - }; - } - - template - class vector_view - { - public: - - typedef T* data_ptr_t; - - vector_view(data_ptr_t data, const std::size_t& size) - : base_size_(size) - , size_(size) - , data_(data) - , data_ref_(0) - { - assert(size_ > 0); - } - - vector_view(const vector_view& vv) - : base_size_(vv.base_size_) - , size_(vv.size_) - , data_(vv.data_) - , data_ref_(0) - { - assert(size_ > 0); - } - - inline void rebase(data_ptr_t data) - { - data_ = data; - - if (!data_ref_.empty()) - { - for (std::size_t i = 0; i < data_ref_.size(); ++i) - { - (*data_ref_[i]) = data; - } - } - } - - inline data_ptr_t data() const - { - return data_; - } - - inline std::size_t base_size() const - { - return base_size_; - } - - inline std::size_t size() const - { - return size_; - } - - inline const T& operator[](const std::size_t index) const - { - assert(index < size_); - return data_[index]; - } - - inline T& operator[](const std::size_t index) - { - assert(index < size_); - return data_[index]; - } - - void set_ref(data_ptr_t* data_ref) - { - data_ref_.push_back(data_ref); - exprtk_debug(("vector_view::set_ref() - data_ref: %p data_ref_.size(): %d\n", - reinterpret_cast(data_ref), - static_cast(data_ref_.size()))); - } - - void remove_ref(data_ptr_t* data_ref) - { - data_ref_.erase( - std::remove(data_ref_.begin(), data_ref_.end(), data_ref), - data_ref_.end()); - exprtk_debug(("vector_view::remove_ref() - data_ref: %p data_ref_.size(): %d\n", - reinterpret_cast(data_ref), - static_cast(data_ref_.size()))); - } - - bool set_size(const std::size_t new_size) - { - if ((new_size > 0) && (new_size <= base_size_)) - { - size_ = new_size; - exprtk_debug(("vector_view::set_size() - data_: %p size: %lu\n", - reinterpret_cast(data_), - size_)); - return true; - } - - exprtk_debug(("vector_view::set_size() - error invalid new_size: %lu base_size: %lu\n", - new_size, - base_size_)); - return false; - } - - private: - - const std::size_t base_size_; - std::size_t size_; - data_ptr_t data_; - std::vector data_ref_; - }; - - template - inline vector_view make_vector_view(T* data, - const std::size_t size, const std::size_t offset = 0) - { - return vector_view(data + offset, size); - } - - template - inline vector_view make_vector_view(std::vector& v, - const std::size_t size, const std::size_t offset = 0) - { - return vector_view(v.data() + offset, size); - } - - template class results_context; - - template - struct type_store - { - enum store_type - { - e_unknown, - e_scalar , - e_vector , - e_string - }; - - type_store() - : data(0) - , size(0) - , type(e_unknown) - {} - - union - { - void* data; - T* vec_data; - }; - - std::size_t size; - store_type type; - - class parameter_list - { - public: - - explicit parameter_list(std::vector& pl) - : parameter_list_(pl) - {} - - inline bool empty() const - { - return parameter_list_.empty(); - } - - inline std::size_t size() const - { - return parameter_list_.size(); - } - - inline type_store& operator[](const std::size_t& index) - { - return parameter_list_[index]; - } - - inline const type_store& operator[](const std::size_t& index) const - { - return parameter_list_[index]; - } - - inline type_store& front() - { - return parameter_list_[0]; - } - - inline const type_store& front() const - { - return parameter_list_[0]; - } - - inline type_store& back() - { - return parameter_list_.back(); - } - - inline const type_store& back() const - { - return parameter_list_.back(); - } - - private: - - std::vector& parameter_list_; - - friend class results_context; - }; - - template - struct type_view - { - typedef type_store type_store_t; - typedef ViewType value_t; - - explicit type_view(type_store_t& ts) - : ts_(ts) - , data_(reinterpret_cast(ts_.data)) - {} - - explicit type_view(const type_store_t& ts) - : ts_(const_cast(ts)) - , data_(reinterpret_cast(ts_.data)) - {} - - inline std::size_t size() const - { - return ts_.size; - } - - inline value_t& operator[](const std::size_t& i) - { - return data_[i]; - } - - inline const value_t& operator[](const std::size_t& i) const - { - return data_[i]; - } - - inline const value_t* begin() const { return data_; } - inline value_t* begin() { return data_; } - - inline const value_t* end() const - { - return static_cast(data_ + ts_.size); - } - - inline value_t* end() - { - return static_cast(data_ + ts_.size); - } - - type_store_t& ts_; - value_t* data_; - }; - - typedef type_view vector_view; - typedef type_view string_view; - - struct scalar_view - { - typedef type_store type_store_t; - typedef T value_t; - - explicit scalar_view(type_store_t& ts) - : v_(*reinterpret_cast(ts.data)) - {} - - explicit scalar_view(const type_store_t& ts) - : v_(*reinterpret_cast(const_cast(ts).data)) - {} - - inline value_t& operator() () - { - return v_; - } - - inline const value_t& operator() () const - { - return v_; - } - - inline operator value_t() const - { - return v_; - } - - inline operator value_t() - { - return v_; - } - - template - inline bool to_int(IntType& i) const - { - if (!exprtk::details::numeric::is_integer(v_)) - return false; - - i = static_cast(v_); - - return true; - } - - template - inline bool to_uint(UIntType& u) const - { - if (v_ < T(0)) - return false; - else if (!exprtk::details::numeric::is_integer(v_)) - return false; - - u = static_cast(v_); - - return true; - } - - T& v_; - }; - }; - - template - inline std::string to_str(const StringView& view) - { - return std::string(view.begin(),view.size()); - } - - #ifndef exprtk_disable_return_statement - namespace details - { - template class return_node; - template class return_envelope_node; - } - #endif - - template - class results_context - { - public: - - typedef type_store type_store_t; - typedef typename type_store_t::scalar_view scalar_t; - typedef typename type_store_t::vector_view vector_t; - typedef typename type_store_t::string_view string_t; - - results_context() - : results_available_(false) - {} - - inline std::size_t count() const - { - if (results_available_) - return parameter_list_.size(); - else - return 0; - } - - inline type_store_t& operator[](const std::size_t& index) - { - return parameter_list_[index]; - } - - inline const type_store_t& operator[](const std::size_t& index) const - { - return parameter_list_[index]; - } - - inline bool get_scalar(const std::size_t& index, T& out) const - { - if ( - (index < parameter_list_.size()) && - (parameter_list_[index].type == type_store_t::e_scalar) - ) - { - const scalar_t scalar(parameter_list_[index]); - out = scalar(); - return true; - } - - return false; - } - - template - inline bool get_vector(const std::size_t& index, OutputIterator out_itr) const - { - if ( - (index < parameter_list_.size()) && - (parameter_list_[index].type == type_store_t::e_vector) - ) - { - const vector_t vector(parameter_list_[index]); - for (std::size_t i = 0; i < vector.size(); ++i) - { - *(out_itr++) = vector[i]; - } - - return true; - } - - return false; - } - - inline bool get_vector(const std::size_t& index, std::vector& out) const - { - return get_vector(index,std::back_inserter(out)); - } - - inline bool get_string(const std::size_t& index, std::string& out) const - { - if ( - (index < parameter_list_.size()) && - (parameter_list_[index].type == type_store_t::e_string) - ) - { - const string_t str(parameter_list_[index]); - out.assign(str.begin(),str.size()); - return true; - } - - return false; - } - - private: - - inline void clear() - { - results_available_ = false; - } - - typedef std::vector ts_list_t; - typedef typename type_store_t::parameter_list parameter_list_t; - - inline void assign(const parameter_list_t& pl) - { - parameter_list_ = pl.parameter_list_; - results_available_ = true; - } - - bool results_available_; - ts_list_t parameter_list_; - - #ifndef exprtk_disable_return_statement - friend class details::return_node; - friend class details::return_envelope_node; - #endif - }; - - namespace details - { - enum operator_type - { - e_default , e_null , e_add , e_sub , - e_mul , e_div , e_mod , e_pow , - e_atan2 , e_min , e_max , e_avg , - e_sum , e_prod , e_lt , e_lte , - e_eq , e_equal , e_ne , e_nequal , - e_gte , e_gt , e_and , e_nand , - e_or , e_nor , e_xor , e_xnor , - e_mand , e_mor , e_scand , e_scor , - e_shr , e_shl , e_abs , e_acos , - e_acosh , e_asin , e_asinh , e_atan , - e_atanh , e_ceil , e_cos , e_cosh , - e_exp , e_expm1 , e_floor , e_log , - e_log10 , e_log2 , e_log1p , e_logn , - e_neg , e_pos , e_round , e_roundn , - e_root , e_sqrt , e_sin , e_sinc , - e_sinh , e_sec , e_csc , e_tan , - e_tanh , e_cot , e_clamp , e_iclamp , - e_inrange , e_sgn , e_r2d , e_d2r , - e_d2g , e_g2d , e_hypot , e_notl , - e_erf , e_erfc , e_ncdf , e_frac , - e_trunc , e_assign , e_addass , e_subass , - e_mulass , e_divass , e_modass , e_in , - e_like , e_ilike , e_multi , e_smulti , - e_swap , - - // Do not add new functions/operators after this point. - e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, - e_sf04 = 1004, e_sf05 = 1005, e_sf06 = 1006, e_sf07 = 1007, - e_sf08 = 1008, e_sf09 = 1009, e_sf10 = 1010, e_sf11 = 1011, - e_sf12 = 1012, e_sf13 = 1013, e_sf14 = 1014, e_sf15 = 1015, - e_sf16 = 1016, e_sf17 = 1017, e_sf18 = 1018, e_sf19 = 1019, - e_sf20 = 1020, e_sf21 = 1021, e_sf22 = 1022, e_sf23 = 1023, - e_sf24 = 1024, e_sf25 = 1025, e_sf26 = 1026, e_sf27 = 1027, - e_sf28 = 1028, e_sf29 = 1029, e_sf30 = 1030, e_sf31 = 1031, - e_sf32 = 1032, e_sf33 = 1033, e_sf34 = 1034, e_sf35 = 1035, - e_sf36 = 1036, e_sf37 = 1037, e_sf38 = 1038, e_sf39 = 1039, - e_sf40 = 1040, e_sf41 = 1041, e_sf42 = 1042, e_sf43 = 1043, - e_sf44 = 1044, e_sf45 = 1045, e_sf46 = 1046, e_sf47 = 1047, - e_sf48 = 1048, e_sf49 = 1049, e_sf50 = 1050, e_sf51 = 1051, - e_sf52 = 1052, e_sf53 = 1053, e_sf54 = 1054, e_sf55 = 1055, - e_sf56 = 1056, e_sf57 = 1057, e_sf58 = 1058, e_sf59 = 1059, - e_sf60 = 1060, e_sf61 = 1061, e_sf62 = 1062, e_sf63 = 1063, - e_sf64 = 1064, e_sf65 = 1065, e_sf66 = 1066, e_sf67 = 1067, - e_sf68 = 1068, e_sf69 = 1069, e_sf70 = 1070, e_sf71 = 1071, - e_sf72 = 1072, e_sf73 = 1073, e_sf74 = 1074, e_sf75 = 1075, - e_sf76 = 1076, e_sf77 = 1077, e_sf78 = 1078, e_sf79 = 1079, - e_sf80 = 1080, e_sf81 = 1081, e_sf82 = 1082, e_sf83 = 1083, - e_sf84 = 1084, e_sf85 = 1085, e_sf86 = 1086, e_sf87 = 1087, - e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091, - e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095, - e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099, - e_sffinal = 1100, - e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003, - e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007, - e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011, - e_sf4ext12 = 2012, e_sf4ext13 = 2013, e_sf4ext14 = 2014, e_sf4ext15 = 2015, - e_sf4ext16 = 2016, e_sf4ext17 = 2017, e_sf4ext18 = 2018, e_sf4ext19 = 2019, - e_sf4ext20 = 2020, e_sf4ext21 = 2021, e_sf4ext22 = 2022, e_sf4ext23 = 2023, - e_sf4ext24 = 2024, e_sf4ext25 = 2025, e_sf4ext26 = 2026, e_sf4ext27 = 2027, - e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031, - e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035, - e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, - e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043, - e_sf4ext44 = 2044, e_sf4ext45 = 2045, e_sf4ext46 = 2046, e_sf4ext47 = 2047, - e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051, - e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055, - e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059, - e_sf4ext60 = 2060, e_sf4ext61 = 2061 - }; - - inline std::string to_str(const operator_type opr) - { - switch (opr) - { - case e_add : return "+" ; - case e_sub : return "-" ; - case e_mul : return "*" ; - case e_div : return "/" ; - case e_mod : return "%" ; - case e_pow : return "^" ; - case e_assign : return ":=" ; - case e_addass : return "+=" ; - case e_subass : return "-=" ; - case e_mulass : return "*=" ; - case e_divass : return "/=" ; - case e_modass : return "%=" ; - case e_lt : return "<" ; - case e_lte : return "<=" ; - case e_eq : return "==" ; - case e_equal : return "=" ; - case e_ne : return "!=" ; - case e_nequal : return "<>" ; - case e_gte : return ">=" ; - case e_gt : return ">" ; - case e_and : return "and" ; - case e_or : return "or" ; - case e_xor : return "xor" ; - case e_nand : return "nand"; - case e_nor : return "nor" ; - case e_xnor : return "xnor"; - default : return "N/A" ; - } - } - - struct base_operation_t - { - base_operation_t(const operator_type t, const unsigned int& np) - : type(t) - , num_params(np) - {} - - operator_type type; - unsigned int num_params; - }; - - namespace loop_unroll - { - const unsigned int global_loop_batch_size = - #ifndef exprtk_disable_superscalar_unroll - 16; - #else - 4; - #endif - - struct details - { - explicit details(const std::size_t& vsize, - const unsigned int loop_batch_size = global_loop_batch_size) - : batch_size(loop_batch_size ) - , remainder (vsize % batch_size) - , upper_bound(static_cast(vsize - (remainder ? loop_batch_size : 0))) - {} - - unsigned int batch_size; - int remainder; - int upper_bound; - }; - } - - #ifdef exprtk_enable_debugging - inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) - { - if (size) - exprtk_debug(("%s - addr: %p size: %d\n", - s.c_str(), - ptr, - static_cast(size))); - else - exprtk_debug(("%s - addr: %p\n", s.c_str(), ptr)); - } - - template - inline void dump_vector(const std::string& vec_name, const T* data, const std::size_t size) - { - printf("----- %s (%p) -----\n", - vec_name.c_str(), - static_cast(data)); - printf("[ "); - for (std::size_t i = 0; i < size; ++i) - { - printf("%8.3f\t", data[i]); - } - printf(" ]\n"); - printf("---------------------\n"); - } - #else - inline void dump_ptr(const std::string&, const void*) {} - inline void dump_ptr(const std::string&, const void*, const std::size_t) {} - template - inline void dump_vector(const std::string&, const T*, const std::size_t) {} - #endif - - template - class vec_data_store - { - public: - - typedef vec_data_store type; - typedef T* data_t; - - private: - - struct control_block - { - control_block() - : ref_count(1) - , size (0) - , data (0) - , destruct (true) - {} - - explicit control_block(const std::size_t& dsize) - : ref_count(1 ) - , size (dsize) - , data (0 ) - , destruct (true ) - { create_data(); } - - control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) - : ref_count(1 ) - , size (dsize ) - , data (dptr ) - , destruct (dstrct) - {} - - ~control_block() - { - if (data && destruct && (0 == ref_count)) - { - dump_ptr("~vec_data_store::control_block() data",data); - delete[] data; - data = reinterpret_cast(0); - } - } - - static inline control_block* create(const std::size_t& dsize, data_t data_ptr = data_t(0), bool dstrct = false) - { - if (dsize) - { - if (0 == data_ptr) - return (new control_block(dsize)); - else - return (new control_block(dsize, data_ptr, dstrct)); - } - else - return (new control_block); - } - - static inline void destroy(control_block*& cntrl_blck) - { - if (cntrl_blck) - { - if ( - (0 != cntrl_blck->ref_count) && - (0 == --cntrl_blck->ref_count) - ) - { - delete cntrl_blck; - } - - cntrl_blck = 0; - } - } - - std::size_t ref_count; - std::size_t size; - data_t data; - bool destruct; - - private: - - control_block(const control_block&) exprtk_delete; - control_block& operator=(const control_block&) exprtk_delete; - - inline void create_data() - { - destruct = true; - data = new T[size]; - std::fill_n(data, size, T(0)); - dump_ptr("control_block::create_data() - data", data, size); - } - }; - - public: - - vec_data_store() - : control_block_(control_block::create(0)) - {} - - explicit vec_data_store(const std::size_t& size) - : control_block_(control_block::create(size,reinterpret_cast(0),true)) - {} - - vec_data_store(const std::size_t& size, data_t data, bool dstrct = false) - : control_block_(control_block::create(size, data, dstrct)) - {} - - vec_data_store(const type& vds) - { - control_block_ = vds.control_block_; - control_block_->ref_count++; - } - - ~vec_data_store() - { - control_block::destroy(control_block_); - } - - type& operator=(const type& vds) - { - if (this != &vds) - { - const std::size_t final_size = min_size(control_block_, vds.control_block_); - - vds.control_block_->size = final_size; - control_block_->size = final_size; - - if (control_block_->destruct || (0 == control_block_->data)) - { - control_block::destroy(control_block_); - - control_block_ = vds.control_block_; - control_block_->ref_count++; - } - } - - return (*this); - } - - inline data_t data() - { - return control_block_->data; - } - - inline data_t data() const - { - return control_block_->data; - } - - inline std::size_t size() const - { - return control_block_->size; - } - - inline data_t& ref() - { - return control_block_->data; - } - - inline void dump() const - { - #ifdef exprtk_enable_debugging - exprtk_debug(("size: %d\taddress:%p\tdestruct:%c\n", - size(), - data(), - (control_block_->destruct ? 'T' : 'F'))); - - for (std::size_t i = 0; i < size(); ++i) - { - if (5 == i) - exprtk_debug(("\n")); - - exprtk_debug(("%15.10f ", data()[i])); - } - exprtk_debug(("\n")); - #endif - } - - static inline void match_sizes(type& vds0, type& vds1) - { - const std::size_t size = min_size(vds0.control_block_,vds1.control_block_); - vds0.control_block_->size = size; - vds1.control_block_->size = size; - } - - private: - - static inline std::size_t min_size(const control_block* cb0, const control_block* cb1) - { - const std::size_t size0 = cb0->size; - const std::size_t size1 = cb1->size; - - if (size0 && size1) - return std::min(size0,size1); - else - return (size0) ? size0 : size1; - } - - control_block* control_block_; - }; - - namespace numeric - { - namespace details - { - template - inline T process_impl(const operator_type operation, const T arg) - { - switch (operation) - { - case e_abs : return numeric::abs (arg); - case e_acos : return numeric::acos (arg); - case e_acosh : return numeric::acosh(arg); - case e_asin : return numeric::asin (arg); - case e_asinh : return numeric::asinh(arg); - case e_atan : return numeric::atan (arg); - case e_atanh : return numeric::atanh(arg); - case e_ceil : return numeric::ceil (arg); - case e_cos : return numeric::cos (arg); - case e_cosh : return numeric::cosh (arg); - case e_exp : return numeric::exp (arg); - case e_expm1 : return numeric::expm1(arg); - case e_floor : return numeric::floor(arg); - case e_log : return numeric::log (arg); - case e_log10 : return numeric::log10(arg); - case e_log2 : return numeric::log2 (arg); - case e_log1p : return numeric::log1p(arg); - case e_neg : return numeric::neg (arg); - case e_pos : return numeric::pos (arg); - case e_round : return numeric::round(arg); - case e_sin : return numeric::sin (arg); - case e_sinc : return numeric::sinc (arg); - case e_sinh : return numeric::sinh (arg); - case e_sqrt : return numeric::sqrt (arg); - case e_tan : return numeric::tan (arg); - case e_tanh : return numeric::tanh (arg); - case e_cot : return numeric::cot (arg); - case e_sec : return numeric::sec (arg); - case e_csc : return numeric::csc (arg); - case e_r2d : return numeric::r2d (arg); - case e_d2r : return numeric::d2r (arg); - case e_d2g : return numeric::d2g (arg); - case e_g2d : return numeric::g2d (arg); - case e_notl : return numeric::notl (arg); - case e_sgn : return numeric::sgn (arg); - case e_erf : return numeric::erf (arg); - case e_erfc : return numeric::erfc (arg); - case e_ncdf : return numeric::ncdf (arg); - case e_frac : return numeric::frac (arg); - case e_trunc : return numeric::trunc(arg); - - default : exprtk_debug(("numeric::details::process_impl - Invalid unary operation.\n")); - return std::numeric_limits::quiet_NaN(); - } - } - - template - inline T process_impl(const operator_type operation, const T arg0, const T arg1) - { - switch (operation) - { - case e_add : return (arg0 + arg1); - case e_sub : return (arg0 - arg1); - case e_mul : return (arg0 * arg1); - case e_div : return (arg0 / arg1); - case e_mod : return modulus(arg0,arg1); - case e_pow : return pow(arg0,arg1); - case e_atan2 : return atan2(arg0,arg1); - case e_min : return std::min(arg0,arg1); - case e_max : return std::max(arg0,arg1); - case e_logn : return logn(arg0,arg1); - case e_lt : return (arg0 < arg1) ? T(1) : T(0); - case e_lte : return (arg0 <= arg1) ? T(1) : T(0); - case e_eq : return std::equal_to()(arg0,arg1) ? T(1) : T(0); - case e_ne : return std::not_equal_to()(arg0,arg1) ? T(1) : T(0); - case e_gte : return (arg0 >= arg1) ? T(1) : T(0); - case e_gt : return (arg0 > arg1) ? T(1) : T(0); - case e_and : return and_opr (arg0,arg1); - case e_nand : return nand_opr(arg0,arg1); - case e_or : return or_opr (arg0,arg1); - case e_nor : return nor_opr (arg0,arg1); - case e_xor : return xor_opr (arg0,arg1); - case e_xnor : return xnor_opr(arg0,arg1); - case e_root : return root (arg0,arg1); - case e_roundn : return roundn (arg0,arg1); - case e_equal : return equal (arg0,arg1); - case e_nequal : return nequal (arg0,arg1); - case e_hypot : return hypot (arg0,arg1); - case e_shr : return shr (arg0,arg1); - case e_shl : return shl (arg0,arg1); - - default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); - return std::numeric_limits::quiet_NaN(); - } - } - - template - inline T process_impl(const operator_type operation, const T arg0, const T arg1, int_type_tag) - { - switch (operation) - { - case e_add : return (arg0 + arg1); - case e_sub : return (arg0 - arg1); - case e_mul : return (arg0 * arg1); - case e_div : return (arg0 / arg1); - case e_mod : return arg0 % arg1; - case e_pow : return pow(arg0,arg1); - case e_min : return std::min(arg0,arg1); - case e_max : return std::max(arg0,arg1); - case e_logn : return logn(arg0,arg1); - case e_lt : return (arg0 < arg1) ? T(1) : T(0); - case e_lte : return (arg0 <= arg1) ? T(1) : T(0); - case e_eq : return (arg0 == arg1) ? T(1) : T(0); - case e_ne : return (arg0 != arg1) ? T(1) : T(0); - case e_gte : return (arg0 >= arg1) ? T(1) : T(0); - case e_gt : return (arg0 > arg1) ? T(1) : T(0); - case e_and : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(1) : T(0); - case e_nand : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(0) : T(1); - case e_or : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(1) : T(0); - case e_nor : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(0) : T(1); - case e_xor : return arg0 ^ arg1; - case e_xnor : return !(arg0 ^ arg1); - case e_root : return root(arg0,arg1); - case e_equal : return arg0 == arg1; - case e_nequal : return arg0 != arg1; - case e_hypot : return hypot(arg0,arg1); - case e_shr : return arg0 >> arg1; - case e_shl : return arg0 << arg1; - - default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); - return std::numeric_limits::quiet_NaN(); - } - } - } - - template - inline T process(const operator_type operation, const T arg) - { - return exprtk::details::numeric::details::process_impl(operation,arg); - } - - template - inline T process(const operator_type operation, const T arg0, const T arg1) - { - return exprtk::details::numeric::details::process_impl(operation, arg0, arg1); - } - } - - template - struct node_collector_interface - { - typedef Node* node_ptr_t; - typedef Node** node_pp_t; - typedef std::vector noderef_list_t; - - virtual ~node_collector_interface() - {} - - virtual void collect_nodes(noderef_list_t&) - {} - }; - - template - struct node_depth_base; - - template - class expression_node : public node_collector_interface > - , public node_depth_base > - { - public: - - enum node_type - { - e_none , e_null , e_constant , e_unary , - e_binary , e_binary_ext , e_trinary , e_quaternary , - e_vararg , e_conditional , e_while , e_repeat , - e_for , e_switch , e_mswitch , e_return , - e_retenv , e_variable , e_stringvar , e_stringconst , - e_stringvarrng , e_cstringvarrng , e_strgenrange , e_strconcat , - e_stringvarsize , e_strswap , e_stringsize , e_stringvararg , - e_function , e_vafunction , e_genfunction , e_strfunction , - e_strcondition , e_strccondition , e_add , e_sub , - e_mul , e_div , e_mod , e_pow , - e_lt , e_lte , e_gt , e_gte , - e_eq , e_ne , e_and , e_nand , - e_or , e_nor , e_xor , e_xnor , - e_in , e_like , e_ilike , e_inranges , - e_ipow , e_ipowinv , e_abs , e_acos , - e_acosh , e_asin , e_asinh , e_atan , - e_atanh , e_ceil , e_cos , e_cosh , - e_exp , e_expm1 , e_floor , e_log , - e_log10 , e_log2 , e_log1p , e_neg , - e_pos , e_round , e_sin , e_sinc , - e_sinh , e_sqrt , e_tan , e_tanh , - e_cot , e_sec , e_csc , e_r2d , - e_d2r , e_d2g , e_g2d , e_notl , - e_sgn , e_erf , e_erfc , e_ncdf , - e_frac , e_trunc , e_uvouv , e_vov , - e_cov , e_voc , e_vob , e_bov , - e_cob , e_boc , e_vovov , e_vovoc , - e_vocov , e_covov , e_covoc , e_vovovov , - e_vovovoc , e_vovocov , e_vocovov , e_covovov , - e_covocov , e_vocovoc , e_covovoc , e_vococov , - e_sf3ext , e_sf4ext , e_nulleq , e_strass , - e_vector , e_vecsize , e_vecelem , e_veccelem , - e_vecelemrtc , e_veccelemrtc , e_rbvecelem , e_rbvecelemrtc , - e_rbveccelem , e_rbveccelemrtc , e_vecinit , e_vecvalass , - e_vecvecass , e_vecopvalass , e_vecopvecass , e_vecfunc , - e_vecvecswap , e_vecvecineq , e_vecvalineq , e_valvecineq , - e_vecvecarith , e_vecvalarith , e_valvecarith , e_vecunaryop , - e_vecondition , e_break , e_continue , e_swap , - e_assert - }; - - typedef T value_type; - typedef expression_node* expression_ptr; - typedef node_collector_interface > nci_t; - typedef typename nci_t::noderef_list_t noderef_list_t; - typedef node_depth_base > ndb_t; - - virtual ~expression_node() - {} - - inline virtual T value() const - { - return std::numeric_limits::quiet_NaN(); - } - - inline virtual expression_node* branch(const std::size_t& index = 0) const - { - return reinterpret_cast(index * 0); - } - - inline virtual node_type type() const - { - return e_none; - } - - inline virtual bool valid() const - { - return true; - } - }; // class expression_node - - template - inline bool is_generally_string_node(const expression_node* node); - - inline bool is_true(const double v) - { - return std::not_equal_to()(0.0,v); - } - - inline bool is_true(const long double v) - { - return std::not_equal_to()(0.0L,v); - } - - inline bool is_true(const float v) - { - return std::not_equal_to()(0.0f,v); - } - - template - inline bool is_true(const expression_node* node) - { - return std::not_equal_to()(T(0),node->value()); - } - - template - inline bool is_true(const std::pair*,bool>& node) - { - return std::not_equal_to()(T(0),node.first->value()); - } - - template - inline bool is_false(const expression_node* node) - { - return std::equal_to()(T(0),node->value()); - } - - template - inline bool is_false(const std::pair*,bool>& node) - { - return std::equal_to()(T(0),node.first->value()); - } - - template - inline bool is_literal_node(const expression_node* node) - { - return node && (details::expression_node::e_constant == node->type()); - } - - template - inline bool is_unary_node(const expression_node* node) - { - return node && (details::expression_node::e_unary == node->type()); - } - - template - inline bool is_neg_unary_node(const expression_node* node) - { - return node && (details::expression_node::e_neg == node->type()); - } - - template - inline bool is_binary_node(const expression_node* node) - { - return node && (details::expression_node::e_binary == node->type()); - } - - template - inline bool is_variable_node(const expression_node* node) - { - return node && (details::expression_node::e_variable == node->type()); - } - - template - inline bool is_ivariable_node(const expression_node* node) - { - return node && - ( - details::expression_node::e_variable == node->type() || - details::expression_node::e_vecelem == node->type() || - details::expression_node::e_veccelem == node->type() || - details::expression_node::e_vecelemrtc == node->type() || - details::expression_node::e_veccelemrtc == node->type() || - details::expression_node::e_rbvecelem == node->type() || - details::expression_node::e_rbveccelem == node->type() || - details::expression_node::e_rbvecelemrtc == node->type() || - details::expression_node::e_rbveccelemrtc == node->type() - ); - } - - template - inline bool is_vector_elem_node(const expression_node* node) - { - return node && (details::expression_node::e_vecelem == node->type()); - } - - template - inline bool is_vector_celem_node(const expression_node* node) - { - return node && (details::expression_node::e_veccelem == node->type()); - } - - template - inline bool is_vector_elem_rtc_node(const expression_node* node) - { - return node && (details::expression_node::e_vecelemrtc == node->type()); - } - - template - inline bool is_vector_celem_rtc_node(const expression_node* node) - { - return node && (details::expression_node::e_veccelemrtc == node->type()); - } - - template - inline bool is_rebasevector_elem_node(const expression_node* node) - { - return node && (details::expression_node::e_rbvecelem == node->type()); - } - - template - inline bool is_rebasevector_elem_rtc_node(const expression_node* node) - { - return node && (details::expression_node::e_rbvecelemrtc == node->type()); - } - - template - inline bool is_rebasevector_celem_rtc_node(const expression_node* node) - { - return node && (details::expression_node::e_rbveccelemrtc == node->type()); - } - - template - inline bool is_rebasevector_celem_node(const expression_node* node) - { - return node && (details::expression_node::e_rbveccelem == node->type()); - } - - template - inline bool is_vector_node(const expression_node* node) - { - return node && (details::expression_node::e_vector == node->type()); - } - - template - inline bool is_ivector_node(const expression_node* node) - { - if (node) - { - switch (node->type()) - { - case details::expression_node::e_vector : - case details::expression_node::e_vecvalass : - case details::expression_node::e_vecvecass : - case details::expression_node::e_vecopvalass : - case details::expression_node::e_vecopvecass : - case details::expression_node::e_vecvecswap : - case details::expression_node::e_vecvecarith : - case details::expression_node::e_vecvalarith : - case details::expression_node::e_valvecarith : - case details::expression_node::e_vecunaryop : - case details::expression_node::e_vecondition : return true; - default : return false; - } - } - else - return false; - } - - template - inline bool is_constant_node(const expression_node* node) - { - return node && - ( - details::expression_node::e_constant == node->type() || - details::expression_node::e_stringconst == node->type() - ); - } - - template - inline bool is_null_node(const expression_node* node) - { - return node && (details::expression_node::e_null == node->type()); - } - - template - inline bool is_break_node(const expression_node* node) - { - return node && (details::expression_node::e_break == node->type()); - } - - template - inline bool is_continue_node(const expression_node* node) - { - return node && (details::expression_node::e_continue == node->type()); - } - - template - inline bool is_swap_node(const expression_node* node) - { - return node && (details::expression_node::e_swap == node->type()); - } - - template - inline bool is_function(const expression_node* node) - { - return node && (details::expression_node::e_function == node->type()); - } - - template - inline bool is_vararg_node(const expression_node* node) - { - return node && (details::expression_node::e_vararg == node->type()); - } - - template - inline bool is_return_node(const expression_node* node) - { - return node && (details::expression_node::e_return == node->type()); - } - - template class unary_node; - - template - inline bool is_negate_node(const expression_node* node) - { - if (node && is_unary_node(node)) - { - return (details::e_neg == static_cast*>(node)->operation()); - } - else - return false; - } - - template - inline bool is_assert_node(const expression_node* node) - { - return node && (details::expression_node::e_assert == node->type()); - } - - template - inline bool branch_deletable(const expression_node* node) - { - return (0 != node) && - !is_variable_node(node) && - !is_string_node (node) ; - } - - template - inline bool all_nodes_valid(expression_node* const (&b)[N]) - { - for (std::size_t i = 0; i < N; ++i) - { - if (0 == b[i]) return false; - } - - return true; - } - - template class Sequence> - inline bool all_nodes_valid(const Sequence*,Allocator>& b) - { - for (std::size_t i = 0; i < b.size(); ++i) - { - if (0 == b[i]) return false; - } - - return true; - } - - template - inline bool all_nodes_variables(expression_node* const (&b)[N]) - { - for (std::size_t i = 0; i < N; ++i) - { - if (0 == b[i]) - return false; - else if (!is_variable_node(b[i])) - return false; - } - - return true; - } - - template class Sequence> - inline bool all_nodes_variables(const Sequence*,Allocator>& b) - { - for (std::size_t i = 0; i < b.size(); ++i) - { - if (0 == b[i]) - return false; - else if (!is_variable_node(b[i])) - return false; - } - - return true; - } - - template - class node_collection_destructor - { - public: - - typedef node_collector_interface nci_t; - - typedef typename nci_t::node_ptr_t node_ptr_t; - typedef typename nci_t::node_pp_t node_pp_t; - typedef typename nci_t::noderef_list_t noderef_list_t; - - static void delete_nodes(node_ptr_t& root) - { - std::vector node_delete_list; - node_delete_list.reserve(1000); - - collect_nodes(root, node_delete_list); - - for (std::size_t i = 0; i < node_delete_list.size(); ++i) - { - node_ptr_t& node = *node_delete_list[i]; - exprtk_debug(("ncd::delete_nodes() - deleting: %p\n", reinterpret_cast(node))); - delete node; - node = reinterpret_cast(0); - } - } - - private: - - static void collect_nodes(node_ptr_t& root, noderef_list_t& node_delete_list) - { - std::deque node_list; - node_list.push_back(root); - node_delete_list.push_back(&root); - - noderef_list_t child_node_delete_list; - child_node_delete_list.reserve(1000); - - while (!node_list.empty()) - { - node_list.front()->collect_nodes(child_node_delete_list); - - if (!child_node_delete_list.empty()) - { - for (std::size_t i = 0; i < child_node_delete_list.size(); ++i) - { - node_pp_t& node = child_node_delete_list[i]; - - if (0 == (*node)) - { - exprtk_debug(("ncd::collect_nodes() - null node encountered.\n")); - } - - node_list.push_back(*node); - } - - node_delete_list.insert( - node_delete_list.end(), - child_node_delete_list.begin(), child_node_delete_list.end()); - - child_node_delete_list.clear(); - } - - node_list.pop_front(); - } - - std::reverse(node_delete_list.begin(), node_delete_list.end()); - } - }; - - template - inline void free_all_nodes(NodeAllocator& node_allocator, expression_node* (&b)[N]) - { - for (std::size_t i = 0; i < N; ++i) - { - free_node(node_allocator,b[i]); - } - } - - template class Sequence> - inline void free_all_nodes(NodeAllocator& node_allocator, Sequence*,Allocator>& b) - { - for (std::size_t i = 0; i < b.size(); ++i) - { - free_node(node_allocator,b[i]); - } - - b.clear(); - } - - template - inline void free_node(NodeAllocator&, expression_node*& node) - { - if ((0 == node) || is_variable_node(node) || is_string_node(node)) - { - return; - } - - node_collection_destructor > - ::delete_nodes(node); - } - - template - inline void destroy_node(expression_node*& node) - { - if (0 != node) - { - node_collection_destructor > - ::delete_nodes(node); - } - } - - template - struct node_depth_base - { - typedef Node* node_ptr_t; - typedef std::pair nb_pair_t; - - node_depth_base() - : depth_set(false) - , depth(0) - {} - - virtual ~node_depth_base() - {} - - virtual std::size_t node_depth() const { return 1; } - - std::size_t compute_node_depth(const Node* const& node) const - { - if (!depth_set) - { - depth = 1 + (node ? node->node_depth() : 0); - depth_set = true; - } - - return depth; - } - - std::size_t compute_node_depth(const nb_pair_t& branch) const - { - if (!depth_set) - { - depth = 1 + (branch.first ? branch.first->node_depth() : 0); - depth_set = true; - } - - return depth; - } - - template - std::size_t compute_node_depth(const nb_pair_t (&branch)[N]) const - { - if (!depth_set) - { - depth = 0; - - for (std::size_t i = 0; i < N; ++i) - { - if (branch[i].first) - { - depth = std::max(depth,branch[i].first->node_depth()); - } - } - - depth += 1; - depth_set = true; - } - - return depth; - } - - template - std::size_t max_node_depth(const BranchType& n0, const BranchType& n1) const - { - return std::max(compute_node_depth(n0), compute_node_depth(n1)); - } - - template - std::size_t max_node_depth(const BranchType& n0, const BranchType& n1, const BranchType& n2) const - { - return std::max(compute_node_depth(n0), - std::max(compute_node_depth(n1), compute_node_depth(n2))); - } - - template - std::size_t max_node_depth(const BranchType& n0, const BranchType& n1, - const BranchType& n2, const BranchType& n3) const - { - return std::max( - std::max(compute_node_depth(n0), compute_node_depth(n1)), - std::max(compute_node_depth(n2), compute_node_depth(n3))); - } - - template - std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1) const - { - if (!depth_set) - { - depth = 1 + max_node_depth(n0, n1); - depth_set = true; - } - - return depth; - } - - template - std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, - const BranchType& n2) const - { - if (!depth_set) - { - depth = 1 + max_node_depth(n0, n1, n2); - depth_set = true; - } - - return depth; - } - - template - std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, - const BranchType& n2, const BranchType& n3) const - { - if (!depth_set) - { - depth = 1 + max_node_depth(n0, n1, n2, n3); - depth_set = true; - } - - return depth; - } - - template class Sequence> - std::size_t compute_node_depth(const Sequence& branch_list) const - { - if (!depth_set) - { - for (std::size_t i = 0; i < branch_list.size(); ++i) - { - if (branch_list[i]) - { - depth = std::max(depth, compute_node_depth(branch_list[i])); - } - } - - depth_set = true; - } - - return depth; - } - - template class Sequence> - std::size_t compute_node_depth(const Sequence& branch_list) const - { - if (!depth_set) - { - for (std::size_t i = 0; i < branch_list.size(); ++i) - { - if (branch_list[i].first) - { - depth = std::max(depth, compute_node_depth(branch_list[i].first)); - } - } - - depth_set = true; - } - - return depth; - } - - mutable bool depth_set; - mutable std::size_t depth; - - template - void collect(node_ptr_t const& node, - const bool deletable, - NodeSequence& delete_node_list) const - { - if ((0 != node) && deletable) - { - delete_node_list.push_back(const_cast(&node)); - } - } - - template - void collect(const nb_pair_t& branch, - NodeSequence& delete_node_list) const - { - collect(branch.first, branch.second, delete_node_list); - } - - template - void collect(Node*& node, - NodeSequence& delete_node_list) const - { - collect(node, branch_deletable(node), delete_node_list); - } - - template - void collect(const nb_pair_t(&branch)[N], - NodeSequence& delete_node_list) const - { - for (std::size_t i = 0; i < N; ++i) - { - collect(branch[i].first, branch[i].second, delete_node_list); - } - } - - template class Sequence, - typename NodeSequence> - void collect(const Sequence& branch, - NodeSequence& delete_node_list) const - { - for (std::size_t i = 0; i < branch.size(); ++i) - { - collect(branch[i].first, branch[i].second, delete_node_list); - } - } - - template class Sequence, - typename NodeSequence> - void collect(const Sequence& branch_list, - NodeSequence& delete_node_list) const - { - for (std::size_t i = 0; i < branch_list.size(); ++i) - { - collect(branch_list[i], branch_deletable(branch_list[i]), delete_node_list); - } - } - - template class Sequence, - typename NodeSequence> - void collect(const Sequence& branch_list, - const Sequence& branch_deletable_list, - NodeSequence& delete_node_list) const - { - for (std::size_t i = 0; i < branch_list.size(); ++i) - { - collect(branch_list[i], branch_deletable_list[i], delete_node_list); - } - } - }; - - template - class vector_holder - { - private: - - typedef Type value_type; - typedef value_type* value_ptr; - typedef const value_ptr const_value_ptr; - typedef vector_holder vector_holder_t; - - class vector_holder_base - { - public: - - virtual ~vector_holder_base() - {} - - inline value_ptr operator[](const std::size_t& index) const - { - return value_at(index); - } - - inline std::size_t size() const - { - return vector_size(); - } - - inline std::size_t base_size() const - { - return vector_base_size(); - } - - inline value_ptr data() const - { - return value_at(0); - } - - virtual inline bool rebaseable() const - { - return false; - } - - virtual void set_ref(value_ptr*) - {} - - virtual void remove_ref(value_ptr*) - {} - - virtual vector_view* rebaseable_instance() - { - return reinterpret_cast*>(0); - } - - protected: - - virtual value_ptr value_at(const std::size_t&) const = 0; - virtual std::size_t vector_size() const = 0; - virtual std::size_t vector_base_size() const = 0; - }; - - class array_vector_impl exprtk_final : public vector_holder_base - { - public: - - array_vector_impl(const Type* vec, const std::size_t& vec_size) - : vec_(vec) - , size_(vec_size) - {} - - protected: - - value_ptr value_at(const std::size_t& index) const exprtk_override - { - assert(index < size_); - return const_cast(vec_ + index); - } - - std::size_t vector_size() const exprtk_override - { - return size_; - } - - std::size_t vector_base_size() const exprtk_override - { - return vector_size(); - } - - private: - - array_vector_impl(const array_vector_impl&) exprtk_delete; - array_vector_impl& operator=(const array_vector_impl&) exprtk_delete; - - const Type* vec_; - const std::size_t size_; - }; - - template class Sequence> - class sequence_vector_impl exprtk_final : public vector_holder_base - { - public: - - typedef Sequence sequence_t; - - explicit sequence_vector_impl(sequence_t& seq) - : sequence_(seq) - {} - - protected: - - value_ptr value_at(const std::size_t& index) const exprtk_override - { - assert(index < sequence_.size()); - return (&sequence_[index]); - } - - std::size_t vector_size() const exprtk_override - { - return sequence_.size(); - } - - std::size_t vector_base_size() const exprtk_override - { - return vector_size(); - } - - private: - - sequence_vector_impl(const sequence_vector_impl&) exprtk_delete; - sequence_vector_impl& operator=(const sequence_vector_impl&) exprtk_delete; - - sequence_t& sequence_; - }; - - class vector_view_impl exprtk_final : public vector_holder_base - { - public: - - typedef exprtk::vector_view vector_view_t; - - vector_view_impl(vector_view_t& vec_view) - : vec_view_(vec_view) - { - assert(vec_view_.size() > 0); - } - - void set_ref(value_ptr* ref) exprtk_override - { - vec_view_.set_ref(ref); - } - - void remove_ref(value_ptr* ref) exprtk_override - { - vec_view_.remove_ref(ref); - } - - bool rebaseable() const exprtk_override - { - return true; - } - - vector_view* rebaseable_instance() exprtk_override - { - return &vec_view_; - } - - protected: - - value_ptr value_at(const std::size_t& index) const exprtk_override - { - assert(index < vec_view_.size()); - return (&vec_view_[index]); - } - - std::size_t vector_size() const exprtk_override - { - return vec_view_.size(); - } - - std::size_t vector_base_size() const exprtk_override - { - return vec_view_.base_size(); - } - - private: - - vector_view_impl(const vector_view_impl&) exprtk_delete; - vector_view_impl& operator=(const vector_view_impl&) exprtk_delete; - - vector_view_t& vec_view_; - }; - - class resizable_vector_impl exprtk_final : public vector_holder_base - { - public: - - resizable_vector_impl(vector_holder& vec_view_holder, - const Type* vec, - const std::size_t& vec_size) - : vec_(vec) - , size_(vec_size) - , vec_view_holder_(*vec_view_holder.rebaseable_instance()) - { - assert(vec_view_holder.rebaseable_instance()); - assert(size_ <= vector_base_size()); - } - - virtual ~resizable_vector_impl() - {} - - protected: - - value_ptr value_at(const std::size_t& index) const exprtk_override - { - assert(index < vector_size()); - return const_cast(vec_ + index); - } - - std::size_t vector_size() const exprtk_override - { - return vec_view_holder_.size(); - } - - std::size_t vector_base_size() const exprtk_override - { - return vec_view_holder_.base_size(); - } - - bool rebaseable() const exprtk_override - { - return true; - } - - virtual vector_view* rebaseable_instance() exprtk_override - { - return &vec_view_holder_; - } - - private: - - resizable_vector_impl(const resizable_vector_impl&) exprtk_delete; - resizable_vector_impl& operator=(const resizable_vector_impl&) exprtk_delete; - - const Type* vec_; - const std::size_t size_; - vector_view& vec_view_holder_; - }; - - public: - - typedef typename details::vec_data_store vds_t; - - vector_holder(Type* vec, const std::size_t& vec_size) - : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) - {} - - explicit vector_holder(const vds_t& vds) - : vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size())) - {} - - template - explicit vector_holder(std::vector& vec) - : vector_holder_base_(new(buffer)sequence_vector_impl(vec)) - {} - - explicit vector_holder(exprtk::vector_view& vec) - : vector_holder_base_(new(buffer)vector_view_impl(vec)) - {} - - explicit vector_holder(vector_holder_t& vec_holder, const vds_t& vds) - : vector_holder_base_(new(buffer)resizable_vector_impl(vec_holder, vds.data(), vds.size())) - {} - - inline value_ptr operator[](const std::size_t& index) const - { - return (*vector_holder_base_)[index]; - } - - inline std::size_t size() const - { - return vector_holder_base_->size(); - } - - inline std::size_t base_size() const - { - return vector_holder_base_->base_size(); - } - - inline value_ptr data() const - { - return vector_holder_base_->data(); - } - - void set_ref(value_ptr* ref) - { - if (rebaseable()) - { - vector_holder_base_->set_ref(ref); - } - } - - void remove_ref(value_ptr* ref) - { - if (rebaseable()) - { - vector_holder_base_->remove_ref(ref); - } - } - - bool rebaseable() const - { - return vector_holder_base_->rebaseable(); - } - - vector_view* rebaseable_instance() - { - return vector_holder_base_->rebaseable_instance(); - } - - private: - - vector_holder(const vector_holder&) exprtk_delete; - vector_holder& operator=(const vector_holder&) exprtk_delete; - - mutable vector_holder_base* vector_holder_base_; - uchar_t buffer[64]; - }; - - template - class null_node exprtk_final : public expression_node - { - public: - - inline T value() const exprtk_override - { - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_null; - } - }; - - template - inline void construct_branch_pair(std::pair*,bool> (&branch)[N], - expression_node* b, - const std::size_t& index) - { - if (b && (index < N)) - { - branch[index] = std::make_pair(b,branch_deletable(b)); - } - } - - template - inline void construct_branch_pair(std::pair*,bool>& branch, expression_node* b) - { - if (b) - { - branch = std::make_pair(b,branch_deletable(b)); - } - } - - template - inline void init_branches(std::pair*,bool> (&branch)[N], - expression_node* b0, - expression_node* b1 = reinterpret_cast*>(0), - expression_node* b2 = reinterpret_cast*>(0), - expression_node* b3 = reinterpret_cast*>(0), - expression_node* b4 = reinterpret_cast*>(0), - expression_node* b5 = reinterpret_cast*>(0), - expression_node* b6 = reinterpret_cast*>(0), - expression_node* b7 = reinterpret_cast*>(0), - expression_node* b8 = reinterpret_cast*>(0), - expression_node* b9 = reinterpret_cast*>(0)) - { - construct_branch_pair(branch, b0, 0); - construct_branch_pair(branch, b1, 1); - construct_branch_pair(branch, b2, 2); - construct_branch_pair(branch, b3, 3); - construct_branch_pair(branch, b4, 4); - construct_branch_pair(branch, b5, 5); - construct_branch_pair(branch, b6, 6); - construct_branch_pair(branch, b7, 7); - construct_branch_pair(branch, b8, 8); - construct_branch_pair(branch, b9, 9); - } - - template - class null_eq_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - explicit null_eq_node(expression_ptr branch, const bool equality = true) - : equality_(equality) - { - construct_branch_pair(branch_, branch); - assert(valid()); - } - - inline T value() const exprtk_override - { - const T v = branch_.first->value(); - const bool result = details::numeric::is_nan(v); - - if (result) - return equality_ ? T(1) : T(0); - else - return equality_ ? T(0) : T(1); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_nulleq; - } - - inline expression_node* branch(const std::size_t&) const exprtk_override - { - return branch_.first; - } - - inline bool valid() const exprtk_override - { - return branch_.first; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - bool equality_; - branch_t branch_; - }; - - template - class literal_node exprtk_final : public expression_node - { - public: - - explicit literal_node(const T& v) - : value_(v) - {} - - inline T value() const exprtk_override - { - return value_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_constant; - } - - inline expression_node* branch(const std::size_t&) const exprtk_override - { - return reinterpret_cast*>(0); - } - - private: - - literal_node(const literal_node&) exprtk_delete; - literal_node& operator=(const literal_node&) exprtk_delete; - - const T value_; - }; - - template - struct range_pack; - - template - struct range_data_type; - - template - class range_interface - { - public: - - typedef range_pack range_t; - - virtual ~range_interface() - {} - - virtual range_t& range_ref() = 0; - - virtual const range_t& range_ref() const = 0; - }; - - #ifndef exprtk_disable_string_capabilities - template - class string_base_node - { - public: - - typedef range_data_type range_data_type_t; - - virtual ~string_base_node() - {} - - virtual std::string str () const = 0; - - virtual char_cptr base() const = 0; - - virtual std::size_t size() const = 0; - }; - - template - class string_literal_node exprtk_final - : public expression_node - , public string_base_node - , public range_interface - { - public: - - typedef range_pack range_t; - - explicit string_literal_node(const std::string& v) - : value_(v) - { - rp_.n0_c = std::make_pair(true, 0); - rp_.n1_c = std::make_pair(true, v.size()); - rp_.cache.first = rp_.n0_c.second; - rp_.cache.second = rp_.n1_c.second; - } - - inline T value() const exprtk_override - { - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_stringconst; - } - - inline expression_node* branch(const std::size_t&) const exprtk_override - { - return reinterpret_cast*>(0); - } - - std::string str() const exprtk_override - { - return value_; - } - - char_cptr base() const exprtk_override - { - return value_.data(); - } - - std::size_t size() const exprtk_override - { - return value_.size(); - } - - range_t& range_ref() exprtk_override - { - return rp_; - } - - const range_t& range_ref() const exprtk_override - { - return rp_; - } - - private: - - string_literal_node(const string_literal_node&) exprtk_delete; - string_literal_node& operator=(const string_literal_node&) exprtk_delete; - - const std::string value_; - range_t rp_; - }; - #endif - - template - class unary_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - unary_node(const operator_type& opr, expression_ptr branch) - : operation_(opr) - { - construct_branch_pair(branch_,branch); - assert(valid()); - } - - inline T value() const exprtk_override - { - return numeric::process - (operation_,branch_.first->value()); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_unary; - } - - inline operator_type operation() - { - return operation_; - } - - inline expression_node* branch(const std::size_t&) const exprtk_override - { - return branch_.first; - } - - inline bool valid() const exprtk_override - { - return branch_.first && branch_.first->valid(); - } - - inline void release() - { - branch_.second = false; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_final - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - operator_type operation_; - branch_t branch_; - }; - - template - class binary_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - binary_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : operation_(opr) - { - init_branches<2>(branch_, branch0, branch1); - assert(valid()); - } - - inline T value() const exprtk_override - { - return numeric::process - ( - operation_, - branch_[0].first->value(), - branch_[1].first->value() - ); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_binary; - } - - inline operator_type operation() - { - return operation_; - } - - inline expression_node* branch(const std::size_t& index = 0) const exprtk_override - { - assert(index < 2); - return branch_[index].first; - } - - inline bool valid() const exprtk_override - { - return - branch_[0].first && branch_[0].first->valid() && - branch_[1].first && branch_[1].first->valid() ; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_final - { - return expression_node::ndb_t::template compute_node_depth<2>(branch_); - } - - private: - - operator_type operation_; - branch_t branch_[2]; - }; - - template - class binary_ext_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - binary_ext_node(expression_ptr branch0, expression_ptr branch1) - { - init_branches<2>(branch_, branch0, branch1); - assert(valid()); - } - - inline T value() const exprtk_override - { - const T arg0 = branch_[0].first->value(); - const T arg1 = branch_[1].first->value(); - return Operation::process(arg0,arg1); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_binary_ext; - } - - inline operator_type operation() - { - return Operation::operation(); - } - - inline expression_node* branch(const std::size_t& index = 0) const exprtk_override - { - assert(index < 2); - return branch_[index].first; - } - - inline bool valid() const exprtk_override - { - return - branch_[0].first && branch_[0].first->valid() && - branch_[1].first && branch_[1].first->valid() ; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::template compute_node_depth<2>(branch_); - } - - protected: - - branch_t branch_[2]; - }; - - template - class trinary_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - trinary_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1, - expression_ptr branch2) - : operation_(opr) - { - init_branches<3>(branch_, branch0, branch1, branch2); - assert(valid()); - } - - inline T value() const exprtk_override - { - const T arg0 = branch_[0].first->value(); - const T arg1 = branch_[1].first->value(); - const T arg2 = branch_[2].first->value(); - - switch (operation_) - { - case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1)); - - case e_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1); - - case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) - return arg1; - else - return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); - - default : exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); - return std::numeric_limits::quiet_NaN(); - } - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_trinary; - } - - inline bool valid() const exprtk_override - { - return - branch_[0].first && branch_[0].first->valid() && - branch_[1].first && branch_[1].first->valid() && - branch_[2].first && branch_[2].first->valid() ; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override exprtk_final - { - return expression_node::ndb_t::template compute_node_depth<3>(branch_); - } - - protected: - - operator_type operation_; - branch_t branch_[3]; - }; - - template - class quaternary_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - quaternary_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1, - expression_ptr branch2, - expression_ptr branch3) - : operation_(opr) - { - init_branches<4>(branch_, branch0, branch1, branch2, branch3); - } - - inline T value() const exprtk_override - { - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_quaternary; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override exprtk_final - { - return expression_node::ndb_t::template compute_node_depth<4>(branch_); - } - - inline bool valid() const exprtk_override - { - return - branch_[0].first && branch_[0].first->valid() && - branch_[1].first && branch_[1].first->valid() && - branch_[2].first && branch_[2].first->valid() && - branch_[3].first && branch_[3].first->valid() ; - } - - protected: - - operator_type operation_; - branch_t branch_[4]; - }; - - template - class conditional_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - conditional_node(expression_ptr condition, - expression_ptr consequent, - expression_ptr alternative) - { - construct_branch_pair(condition_ , condition ); - construct_branch_pair(consequent_ , consequent ); - construct_branch_pair(alternative_, alternative); - assert(valid()); - } - - inline T value() const exprtk_override - { - if (is_true(condition_)) - return consequent_.first->value(); - else - return alternative_.first->value(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_conditional; - } - - inline bool valid() const exprtk_override - { - return - condition_ .first && condition_ .first->valid() && - consequent_ .first && consequent_ .first->valid() && - alternative_.first && alternative_.first->valid() ; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(condition_ , node_delete_list); - expression_node::ndb_t::collect(consequent_ , node_delete_list); - expression_node::ndb_t::collect(alternative_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth - (condition_, consequent_, alternative_); - } - - private: - - branch_t condition_; - branch_t consequent_; - branch_t alternative_; - }; - - template - class cons_conditional_node exprtk_final : public expression_node - { - public: - - // Consequent only conditional statement node - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - cons_conditional_node(expression_ptr condition, - expression_ptr consequent) - { - construct_branch_pair(condition_ , condition ); - construct_branch_pair(consequent_, consequent); - assert(valid()); - } - - inline T value() const exprtk_override - { - if (is_true(condition_)) - return consequent_.first->value(); - else - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_conditional; - } - - inline bool valid() const exprtk_override - { - return - condition_ .first && condition_ .first->valid() && - consequent_.first && consequent_.first->valid() ; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(condition_ , node_delete_list); - expression_node::ndb_t::collect(consequent_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t:: - compute_node_depth(condition_, consequent_); - } - - private: - - branch_t condition_; - branch_t consequent_; - }; - - #ifndef exprtk_disable_break_continue - template - class break_exception - { - public: - - explicit break_exception(const T& v) - : value(v) - {} - - T value; - }; - - class continue_exception {}; - - template - class break_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - explicit break_node(expression_ptr ret = expression_ptr(0)) - { - construct_branch_pair(return_, ret); - } - - inline T value() const exprtk_override - { - const T result = return_.first ? - return_.first->value() : - std::numeric_limits::quiet_NaN(); - - throw break_exception(result); - - #if !defined(_MSC_VER) && !defined(__NVCOMPILER) - return std::numeric_limits::quiet_NaN(); - #endif - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_break; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(return_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(return_); - } - - private: - - branch_t return_; - }; - - template - class continue_node exprtk_final : public expression_node - { - public: - - inline T value() const exprtk_override - { - throw continue_exception(); - #if !defined(_MSC_VER) && !defined(__NVCOMPILER) - return std::numeric_limits::quiet_NaN(); - #endif - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_break; - } - }; - #endif - - struct loop_runtime_checker - { - loop_runtime_checker(loop_runtime_check_ptr loop_runtime_check, - loop_runtime_check::loop_types lp_typ = loop_runtime_check::e_invalid) - : iteration_count_(0) - , loop_runtime_check_(loop_runtime_check) - , max_loop_iterations_(loop_runtime_check_->max_loop_iterations) - , loop_type_(lp_typ) - { - assert(loop_runtime_check_); - } - - inline void reset(const _uint64_t initial_value = 0) const - { - iteration_count_ = initial_value; - } - - inline bool check() const - { - assert(loop_runtime_check_); - - if ( - (++iteration_count_ <= max_loop_iterations_) && - loop_runtime_check_->check() - ) - { - return true; - } - - loop_runtime_check::violation_context ctxt; - ctxt.loop = loop_type_; - ctxt.violation = loop_runtime_check::e_iteration_count; - - loop_runtime_check_->handle_runtime_violation(ctxt); - - return false; - } - - bool valid() const - { - return 0 != loop_runtime_check_; - } - - mutable _uint64_t iteration_count_; - mutable loop_runtime_check_ptr loop_runtime_check_; - const details::_uint64_t& max_loop_iterations_; - loop_runtime_check::loop_types loop_type_; - }; - - template - class while_loop_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - while_loop_node(expression_ptr condition, - expression_ptr loop_body) - { - construct_branch_pair(condition_, condition); - construct_branch_pair(loop_body_, loop_body); - assert(valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - while (is_true(condition_)) - { - result = loop_body_.first->value(); - } - - return result; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_while; - } - - inline bool valid() const exprtk_override - { - return - condition_.first && condition_.first->valid() && - loop_body_.first && loop_body_.first->valid() ; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(condition_ , node_delete_list); - expression_node::ndb_t::collect(loop_body_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); - } - - protected: - - branch_t condition_; - branch_t loop_body_; - }; - - template - class while_loop_rtc_node exprtk_final - : public while_loop_node - , public loop_runtime_checker - { - public: - - typedef while_loop_node parent_t; - typedef expression_node* expression_ptr; - - while_loop_rtc_node(expression_ptr condition, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk) - : parent_t(condition, loop_body) - , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - - T result = T(0); - - loop_runtime_checker::reset(); - - while (is_true(parent_t::condition_) && loop_runtime_checker::check()) - { - result = parent_t::loop_body_.first->value(); - } - - return result; - } - - using parent_t::valid; - - bool valid() const exprtk_override exprtk_final - { - return parent_t::valid() && - loop_runtime_checker::valid(); - } - }; - - template - class repeat_until_loop_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - repeat_until_loop_node(expression_ptr condition, - expression_ptr loop_body) - { - construct_branch_pair(condition_, condition); - construct_branch_pair(loop_body_, loop_body); - assert(valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - do - { - result = loop_body_.first->value(); - } - while (is_false(condition_.first)); - - return result; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_repeat; - } - - inline bool valid() const exprtk_override - { - return - condition_.first && condition_.first->valid() && - loop_body_.first && loop_body_.first->valid() ; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(condition_ , node_delete_list); - expression_node::ndb_t::collect(loop_body_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); - } - - protected: - - branch_t condition_; - branch_t loop_body_; - }; - - template - class repeat_until_loop_rtc_node exprtk_final - : public repeat_until_loop_node - , public loop_runtime_checker - { - public: - - typedef repeat_until_loop_node parent_t; - typedef expression_node* expression_ptr; - - repeat_until_loop_rtc_node(expression_ptr condition, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk) - : parent_t(condition, loop_body) - , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - loop_runtime_checker::reset(1); - - do - { - result = parent_t::loop_body_.first->value(); - } - while (is_false(parent_t::condition_.first) && loop_runtime_checker::check()); - - return result; - } - - using parent_t::valid; - - inline bool valid() const exprtk_override exprtk_final - { - return parent_t::valid() && - loop_runtime_checker::valid(); - } - }; - - template - class for_loop_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - for_loop_node(expression_ptr initialiser, - expression_ptr condition, - expression_ptr incrementor, - expression_ptr loop_body) - { - construct_branch_pair(initialiser_, initialiser); - construct_branch_pair(condition_ , condition ); - construct_branch_pair(incrementor_, incrementor); - construct_branch_pair(loop_body_ , loop_body ); - assert(valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - if (initialiser_.first) - initialiser_.first->value(); - - if (incrementor_.first) - { - while (is_true(condition_)) - { - result = loop_body_.first->value(); - incrementor_.first->value(); - } - } - else - { - while (is_true(condition_)) - { - result = loop_body_.first->value(); - } - } - - return result; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_for; - } - - inline bool valid() const exprtk_override - { - return condition_.first && loop_body_.first; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(initialiser_ , node_delete_list); - expression_node::ndb_t::collect(condition_ , node_delete_list); - expression_node::ndb_t::collect(incrementor_ , node_delete_list); - expression_node::ndb_t::collect(loop_body_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth - (initialiser_, condition_, incrementor_, loop_body_); - } - - protected: - - branch_t initialiser_; - branch_t condition_ ; - branch_t incrementor_; - branch_t loop_body_ ; - }; - - template - class for_loop_rtc_node exprtk_final - : public for_loop_node - , public loop_runtime_checker - { - public: - - typedef for_loop_node parent_t; - typedef expression_node* expression_ptr; - - for_loop_rtc_node(expression_ptr initialiser, - expression_ptr condition, - expression_ptr incrementor, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk) - : parent_t(initialiser, condition, incrementor, loop_body) - , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - loop_runtime_checker::reset(); - - if (parent_t::initialiser_.first) - parent_t::initialiser_.first->value(); - - if (parent_t::incrementor_.first) - { - while (is_true(parent_t::condition_) && loop_runtime_checker::check()) - { - result = parent_t::loop_body_.first->value(); - parent_t::incrementor_.first->value(); - } - } - else - { - while (is_true(parent_t::condition_) && loop_runtime_checker::check()) - { - result = parent_t::loop_body_.first->value(); - } - } - - return result; - } - - using parent_t::valid; - - inline bool valid() const exprtk_override exprtk_final - { - return parent_t::valid() && - loop_runtime_checker::valid(); - } - }; - - #ifndef exprtk_disable_break_continue - template - class while_loop_bc_node : public while_loop_node - { - public: - - typedef while_loop_node parent_t; - typedef expression_node* expression_ptr; - - while_loop_bc_node(expression_ptr condition, - expression_ptr loop_body) - : parent_t(condition, loop_body) - { - assert(parent_t::valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - while (is_true(parent_t::condition_)) - { - try - { - result = parent_t::loop_body_.first->value(); - } - catch(const break_exception& e) - { - return e.value; - } - catch(const continue_exception&) - {} - } - - return result; - } - }; - - template - class while_loop_bc_rtc_node exprtk_final - : public while_loop_bc_node - , public loop_runtime_checker - { - public: - - typedef while_loop_bc_node parent_t; - typedef expression_node* expression_ptr; - - while_loop_bc_rtc_node(expression_ptr condition, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk) - : parent_t(condition, loop_body) - , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - loop_runtime_checker::reset(); - - while (is_true(parent_t::condition_) && loop_runtime_checker::check()) - { - try - { - result = parent_t::loop_body_.first->value(); - } - catch(const break_exception& e) - { - return e.value; - } - catch(const continue_exception&) - {} - } - - return result; - } - - using parent_t::valid; - - inline bool valid() const exprtk_override exprtk_final - { - return parent_t::valid() && - loop_runtime_checker::valid(); - } - }; - - template - class repeat_until_loop_bc_node : public repeat_until_loop_node - { - public: - - typedef repeat_until_loop_node parent_t; - typedef expression_node* expression_ptr; - - repeat_until_loop_bc_node(expression_ptr condition, - expression_ptr loop_body) - : parent_t(condition, loop_body) - { - assert(parent_t::valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - do - { - try - { - result = parent_t::loop_body_.first->value(); - } - catch(const break_exception& e) - { - return e.value; - } - catch(const continue_exception&) - {} - } - while (is_false(parent_t::condition_.first)); - - return result; - } - }; - - template - class repeat_until_loop_bc_rtc_node exprtk_final - : public repeat_until_loop_bc_node - , public loop_runtime_checker - { - public: - - typedef repeat_until_loop_bc_node parent_t; - typedef expression_node* expression_ptr; - - repeat_until_loop_bc_rtc_node(expression_ptr condition, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk) - : parent_t(condition, loop_body) - , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - loop_runtime_checker::reset(); - - do - { - try - { - result = parent_t::loop_body_.first->value(); - } - catch(const break_exception& e) - { - return e.value; - } - catch(const continue_exception&) - {} - } - while (is_false(parent_t::condition_.first) && loop_runtime_checker::check()); - - return result; - } - - using parent_t::valid; - - inline bool valid() const exprtk_override exprtk_final - { - return parent_t::valid() && - loop_runtime_checker::valid(); - } - }; - - template - class for_loop_bc_node : public for_loop_node - { - public: - - typedef for_loop_node parent_t; - typedef expression_node* expression_ptr; - - for_loop_bc_node(expression_ptr initialiser, - expression_ptr condition, - expression_ptr incrementor, - expression_ptr loop_body) - : parent_t(initialiser, condition, incrementor, loop_body) - { - assert(parent_t::valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - if (parent_t::initialiser_.first) - parent_t::initialiser_.first->value(); - - if (parent_t::incrementor_.first) - { - while (is_true(parent_t::condition_)) - { - try - { - result = parent_t::loop_body_.first->value(); - } - catch(const break_exception& e) - { - return e.value; - } - catch(const continue_exception&) - {} - - parent_t::incrementor_.first->value(); - } - } - else - { - while (is_true(parent_t::condition_)) - { - try - { - result = parent_t::loop_body_.first->value(); - } - catch(const break_exception& e) - { - return e.value; - } - catch(const continue_exception&) - {} - } - } - - return result; - } - }; - - template - class for_loop_bc_rtc_node exprtk_final - : public for_loop_bc_node - , public loop_runtime_checker - { - public: - - typedef for_loop_bc_node parent_t; - typedef expression_node* expression_ptr; - - for_loop_bc_rtc_node(expression_ptr initialiser, - expression_ptr condition, - expression_ptr incrementor, - expression_ptr loop_body, - loop_runtime_check_ptr loop_rt_chk) - : parent_t(initialiser, condition, incrementor, loop_body) - , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - T result = T(0); - - loop_runtime_checker::reset(); - - if (parent_t::initialiser_.first) - parent_t::initialiser_.first->value(); - - if (parent_t::incrementor_.first) - { - while (is_true(parent_t::condition_) && loop_runtime_checker::check()) - { - try - { - result = parent_t::loop_body_.first->value(); - } - catch(const break_exception& e) - { - return e.value; - } - catch(const continue_exception&) - {} - - parent_t::incrementor_.first->value(); - } - } - else - { - while (is_true(parent_t::condition_) && loop_runtime_checker::check()) - { - try - { - result = parent_t::loop_body_.first->value(); - } - catch(const break_exception& e) - { - return e.value; - } - catch(const continue_exception&) - {} - } - } - - return result; - } - - using parent_t::valid; - - inline bool valid() const exprtk_override exprtk_final - { - return parent_t::valid() && - loop_runtime_checker::valid(); - } - }; - #endif - - template - class switch_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - template class Sequence> - explicit switch_node(const Sequence& arg_list) - { - if (1 != (arg_list.size() & 1)) - return; - - arg_list_.resize(arg_list.size()); - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (arg_list[i] && arg_list[i]->valid()) - { - construct_branch_pair(arg_list_[i], arg_list[i]); - } - else - { - arg_list_.clear(); - return; - } - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - const std::size_t upper_bound = (arg_list_.size() - 1); - - for (std::size_t i = 0; i < upper_bound; i += 2) - { - expression_ptr condition = arg_list_[i ].first; - expression_ptr consequent = arg_list_[i + 1].first; - - if (is_true(condition)) - { - return consequent->value(); - } - } - - return arg_list_[upper_bound].first->value(); - } - - inline typename expression_node::node_type type() const exprtk_override exprtk_final - { - return expression_node::e_switch; - } - - inline bool valid() const exprtk_override - { - return !arg_list_.empty(); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(arg_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override exprtk_final - { - return expression_node::ndb_t::compute_node_depth(arg_list_); - } - - protected: - - std::vector arg_list_; - }; - - template - class switch_n_node exprtk_final : public switch_node - { - public: - - typedef expression_node* expression_ptr; - - template class Sequence> - explicit switch_n_node(const Sequence& arg_list) - : switch_node(arg_list) - {} - - inline T value() const exprtk_override - { - return Switch_N::process(switch_node::arg_list_); - } - }; - - template - class multi_switch_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - template class Sequence> - explicit multi_switch_node(const Sequence& arg_list) - { - if (0 != (arg_list.size() & 1)) - return; - - arg_list_.resize(arg_list.size()); - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (arg_list[i] && arg_list[i]->valid()) - { - construct_branch_pair(arg_list_[i], arg_list[i]); - } - else - { - arg_list_.clear(); - return; - } - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - const std::size_t upper_bound = (arg_list_.size() - 1); - - T result = T(0); - - for (std::size_t i = 0; i < upper_bound; i += 2) - { - expression_ptr condition = arg_list_[i ].first; - expression_ptr consequent = arg_list_[i + 1].first; - - if (is_true(condition)) - { - result = consequent->value(); - } - } - - return result; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_mswitch; - } - - inline bool valid() const exprtk_override - { - return !arg_list_.empty() && (0 == (arg_list_.size() % 2)); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(arg_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override exprtk_final - { - return expression_node::ndb_t::compute_node_depth(arg_list_); - } - - private: - - std::vector arg_list_; - }; - - template - class ivariable - { - public: - - virtual ~ivariable() - {} - - virtual T& ref() = 0; - virtual const T& ref() const = 0; - }; - - template - class variable_node exprtk_final - : public expression_node - , public ivariable - { - public: - - static T null_value; - - explicit variable_node() - : value_(&null_value) - {} - - explicit variable_node(T& v) - : value_(&v) - {} - - inline bool operator <(const variable_node& v) const - { - return this < (&v); - } - - inline T value() const exprtk_override - { - return (*value_); - } - - inline T& ref() exprtk_override - { - return (*value_); - } - - inline const T& ref() const exprtk_override - { - return (*value_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_variable; - } - - private: - - T* value_; - }; - - template - T variable_node::null_value = T(std::numeric_limits::quiet_NaN()); - - template - struct range_pack - { - typedef expression_node* expression_node_ptr; - typedef std::pair cached_range_t; - - range_pack() - : n0_e (std::make_pair(false,expression_node_ptr(0))) - , n1_e (std::make_pair(false,expression_node_ptr(0))) - , n0_c (std::make_pair(false,0)) - , n1_c (std::make_pair(false,0)) - , cache(std::make_pair(0,0)) - {} - - void clear() - { - n0_e = std::make_pair(false,expression_node_ptr(0)); - n1_e = std::make_pair(false,expression_node_ptr(0)); - n0_c = std::make_pair(false,0); - n1_c = std::make_pair(false,0); - cache = std::make_pair(0,0); - } - - void free() - { - if (n0_e.first && n0_e.second) - { - n0_e.first = false; - - if ( - !is_variable_node(n0_e.second) && - !is_string_node (n0_e.second) - ) - { - destroy_node(n0_e.second); - } - } - - if (n1_e.first && n1_e.second) - { - n1_e.first = false; - - if ( - !is_variable_node(n1_e.second) && - !is_string_node (n1_e.second) - ) - { - destroy_node(n1_e.second); - } - } - } - - bool const_range() const - { - return ( n0_c.first && n1_c.first) && - (!n0_e.first && !n1_e.first); - } - - bool var_range() const - { - return ( n0_e.first && n1_e.first) && - (!n0_c.first && !n1_c.first); - } - - bool operator() (std::size_t& r0, std::size_t& r1, - const std::size_t& size = std::numeric_limits::max()) const - { - if (n0_c.first) - r0 = n0_c.second; - else if (n0_e.first) - { - r0 = static_cast(details::numeric::to_int64(n0_e.second->value())); - } - else - return false; - - if (n1_c.first) - r1 = n1_c.second; - else if (n1_e.first) - { - r1 = static_cast(details::numeric::to_int64(n1_e.second->value())); - } - else - return false; - - if ( - (std::numeric_limits::max() != size) && - (std::numeric_limits::max() == r1 ) - ) - { - r1 = size; - } - - cache.first = r0; - cache.second = r1; - - #ifndef exprtk_enable_range_runtime_checks - return (r0 <= r1); - #else - return range_runtime_check(r0, r1, size); - #endif - } - - inline std::size_t const_size() const - { - return (n1_c.second - n0_c.second); - } - - inline std::size_t cache_size() const - { - return (cache.second - cache.first); - } - - std::pair n0_e; - std::pair n1_e; - std::pair n0_c; - std::pair n1_c; - mutable cached_range_t cache; - - #ifdef exprtk_enable_range_runtime_checks - bool range_runtime_check(const std::size_t r0, - const std::size_t r1, - const std::size_t size) const - { - if (r0 > size) - { - throw std::runtime_error("range error: (r0 < 0) || (r0 > size)"); - #if !defined(_MSC_VER) && !defined(__NVCOMPILER) - return false; - #endif - } - - if (r1 > size) - { - throw std::runtime_error("range error: (r1 < 0) || (r1 > size)"); - #if !defined(_MSC_VER) && !defined(__NVCOMPILER) - return false; - #endif - } - - return (r0 <= r1); - } - #endif - }; - - template - class string_base_node; - - template - struct range_data_type - { - typedef range_pack range_t; - typedef string_base_node* strbase_ptr_t; - - range_data_type() - : range(0) - , data (0) - , size (0) - , type_size(0) - , str_node (0) - {} - - range_t* range; - void* data; - std::size_t size; - std::size_t type_size; - strbase_ptr_t str_node; - }; - - template class vector_node; - - template - class vector_interface - { - public: - - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - virtual ~vector_interface() - {} - - virtual std::size_t size () const = 0; - - virtual std::size_t base_size() const = 0; - - virtual vector_node_ptr vec () const = 0; - - virtual vector_node_ptr vec () = 0; - - virtual vds_t& vds () = 0; - - virtual const vds_t& vds () const = 0; - - virtual bool side_effect () const { return false; } - }; - - template - class vector_node exprtk_final - : public expression_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - explicit vector_node(vector_holder_t* vh) - : vector_holder_(vh) - , vds_((*vector_holder_).size(),(*vector_holder_)[0]) - { - vector_holder_->set_ref(&vds_.ref()); - } - - vector_node(const vds_t& vds, vector_holder_t* vh) - : vector_holder_(vh) - , vds_(vds) - {} - - ~vector_node() - { - assert(valid()); - vector_holder_->remove_ref(&vds_.ref()); - } - - inline T value() const exprtk_override - { - return vds().data()[0]; - } - - vector_node_ptr vec() const exprtk_override - { - return const_cast(this); - } - - vector_node_ptr vec() exprtk_override - { - return this; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vector; - } - - inline bool valid() const exprtk_override - { - return vector_holder_; - } - - std::size_t size() const exprtk_override - { - return vec_holder().size(); - } - - std::size_t base_size() const exprtk_override - { - return vec_holder().base_size(); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - inline vector_holder_t& vec_holder() const - { - return (*vector_holder_); - } - - private: - - vector_holder_t* vector_holder_; - vds_t vds_; - }; - - template - class vector_size_node exprtk_final - : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - - explicit vector_size_node(vector_holder_t* vh) - : vector_holder_(vh) - {} - - ~vector_size_node() - { - assert(valid()); - } - - inline T value() const exprtk_override - { - assert(vector_holder_); - return static_cast(vector_holder_->size()); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecsize; - } - - inline bool valid() const exprtk_override - { - return vector_holder_ && vector_holder_->size(); - } - - inline vector_holder_t* vec_holder() - { - return vector_holder_; - } - - private: - - vector_holder_t* vector_holder_; - }; - - template - class vector_elem_node exprtk_final - : public expression_node - , public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef std::pair branch_t; - - vector_elem_node(expression_ptr vec_node, - expression_ptr index, - vector_holder_ptr vec_holder) - : vector_holder_(vec_holder) - , vector_base_((*vec_holder)[0]) - { - construct_branch_pair(vector_node_, vec_node); - construct_branch_pair(index_ , index ); - assert(valid()); - } - - inline T value() const exprtk_override - { - return *access_vector(); - } - - inline T& ref() exprtk_override - { - return *access_vector(); - } - - inline const T& ref() const exprtk_override - { - return *access_vector(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecelem; - } - - inline bool valid() const exprtk_override - { - return - vector_holder_ && - index_.first && - vector_node_.first && - index_.first->valid() && - vector_node_.first->valid(); - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(vector_node_, node_delete_list); - expression_node::ndb_t::collect(index_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth - (vector_node_, index_); - } - - private: - - inline T* access_vector() const - { - vector_node_.first->value(); - return (vector_base_ + details::numeric::to_uint64(index_.first->value())); - } - - vector_holder_ptr vector_holder_; - T* vector_base_; - branch_t vector_node_; - branch_t index_; - }; - - template - class vector_celem_node exprtk_final - : public expression_node - , public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef std::pair branch_t; - - vector_celem_node(expression_ptr vec_node, - const std::size_t index, - vector_holder_ptr vec_holder) - : index_(index) - , vector_holder_(vec_holder) - , vector_base_((*vec_holder)[0]) - { - construct_branch_pair(vector_node_, vec_node); - assert(valid()); - } - - inline T value() const exprtk_override - { - return *access_vector(); - } - - inline T& ref() exprtk_override - { - return *access_vector(); - } - - inline const T& ref() const exprtk_override - { - return *access_vector(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_veccelem; - } - - inline bool valid() const exprtk_override - { - return - vector_holder_ && - vector_node_.first && - vector_node_.first->valid(); - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(vector_node_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(vector_node_); - } - - private: - - inline T* access_vector() const - { - vector_node_.first->value(); - return (vector_base_ + index_); - } - - const std::size_t index_; - vector_holder_ptr vector_holder_; - T* vector_base_; - branch_t vector_node_; - }; - - template - class vector_elem_rtc_node exprtk_final - : public expression_node - , public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef std::pair branch_t; - - vector_elem_rtc_node(expression_ptr vec_node, - expression_ptr index, - vector_holder_ptr vec_holder, - vector_access_runtime_check_ptr vec_rt_chk) - : vector_holder_(vec_holder) - , vector_base_((*vec_holder)[0]) - , vec_rt_chk_(vec_rt_chk) - , max_vector_index_(vector_holder_->size() - 1) - { - construct_branch_pair(vector_node_, vec_node); - construct_branch_pair(index_ , index ); - assert(valid()); - } - - inline T value() const exprtk_override - { - return *access_vector(); - } - - inline T& ref() exprtk_override - { - return *access_vector(); - } - - inline const T& ref() const exprtk_override - { - return *access_vector(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecelemrtc; - } - - inline bool valid() const exprtk_override - { - return - vector_holder_ && - index_.first && - vector_node_.first && - index_.first->valid() && - vector_node_.first->valid(); - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(vector_node_, node_delete_list); - expression_node::ndb_t::collect(index_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth - (vector_node_, index_); - } - - private: - - inline T* access_vector() const - { - const _uint64_t index = details::numeric::to_uint64(index_.first->value()); - vector_node_.first->value(); - - if (index <= max_vector_index_) - { - return (vector_holder_->data() + index); - } - - assert(vec_rt_chk_); - - vector_access_runtime_check::violation_context context; - context.base_ptr = reinterpret_cast(vector_base_); - context.end_ptr = reinterpret_cast(vector_base_ + vector_holder_->size()); - context.access_ptr = reinterpret_cast(vector_base_ + index); - context.type_size = sizeof(T); - - return vec_rt_chk_->handle_runtime_violation(context) ? - reinterpret_cast(context.access_ptr) : - vector_base_ ; - } - - vector_holder_ptr vector_holder_; - T* vector_base_; - branch_t vector_node_; - branch_t index_; - vector_access_runtime_check_ptr vec_rt_chk_; - const std::size_t max_vector_index_; - }; - - template - class vector_celem_rtc_node exprtk_final - : public expression_node - , public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef std::pair branch_t; - - vector_celem_rtc_node(expression_ptr vec_node, - const std::size_t index, - vector_holder_ptr vec_holder, - vector_access_runtime_check_ptr vec_rt_chk) - : index_(index) - , max_vector_index_(vec_holder->size() - 1) - , vector_holder_(vec_holder) - , vector_base_((*vec_holder)[0]) - , vec_rt_chk_(vec_rt_chk) - { - construct_branch_pair(vector_node_, vec_node); - assert(valid()); - } - - inline T value() const exprtk_override - { - return *access_vector(); - } - - inline T& ref() exprtk_override - { - return *access_vector(); - } - - inline const T& ref() const exprtk_override - { - return *access_vector(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_veccelemrtc; - } - - inline bool valid() const exprtk_override - { - return - vector_holder_ && - vector_node_.first && - vector_node_.first->valid(); - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(vector_node_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(vector_node_); - } - - private: - - inline T* access_vector() const - { - vector_node_.first->value(); - - if (index_ <= max_vector_index_) - { - return (vector_holder_->data() + index_); - } - - assert(vec_rt_chk_); - - vector_access_runtime_check::violation_context context; - context.base_ptr = reinterpret_cast(vector_base_); - context.end_ptr = reinterpret_cast(vector_base_ + vector_holder_->size()); - context.access_ptr = reinterpret_cast(vector_base_ + index_); - context.type_size = sizeof(T); - - return vec_rt_chk_->handle_runtime_violation(context) ? - reinterpret_cast(context.access_ptr) : - vector_base_ ; - } - - const std::size_t index_; - const std::size_t max_vector_index_; - vector_holder_ptr vector_holder_; - T* vector_base_; - branch_t vector_node_; - vector_access_runtime_check_ptr vec_rt_chk_; - }; - - template - class rebasevector_elem_node exprtk_final - : public expression_node - , public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; - typedef std::pair branch_t; - - rebasevector_elem_node(expression_ptr vec_node, - expression_ptr index, - vector_holder_ptr vec_holder) - : vector_holder_(vec_holder) - { - construct_branch_pair(vector_node_, vec_node); - construct_branch_pair(index_ , index ); - assert(valid()); - } - - inline T value() const exprtk_override - { - return *access_vector(); - } - - inline T& ref() exprtk_override - { - return *access_vector(); - } - - inline const T& ref() const exprtk_override - { - return *access_vector(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_rbvecelem; - } - - inline bool valid() const exprtk_override - { - return - vector_holder_ && - index_.first && - vector_node_.first && - index_.first->valid() && - vector_node_.first->valid(); - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(vector_node_, node_delete_list); - expression_node::ndb_t::collect(index_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth - (vector_node_, index_); - } - - private: - - inline T* access_vector() const - { - vector_node_.first->value(); - return (vector_holder_->data() + details::numeric::to_uint64(index_.first->value())); - } - - vector_holder_ptr vector_holder_; - branch_t vector_node_; - branch_t index_; - }; - - template - class rebasevector_celem_node exprtk_final - : public expression_node - , public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef std::pair branch_t; - - rebasevector_celem_node(expression_ptr vec_node, - const std::size_t index, - vector_holder_ptr vec_holder) - : index_(index) - , vector_holder_(vec_holder) - { - construct_branch_pair(vector_node_, vec_node); - assert(valid()); - } - - inline T value() const exprtk_override - { - vector_node_.first->value(); - return ref();; - } - - inline T& ref() exprtk_override - { - return *(vector_holder_->data() + index_); - } - - inline const T& ref() const exprtk_override - { - return *(vector_holder_->data() + index_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_rbveccelem; - } - - inline bool valid() const exprtk_override - { - return - vector_holder_ && - vector_node_.first && - vector_node_.first->valid(); - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(vector_node_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(vector_node_); - } - - private: - - const std::size_t index_; - vector_holder_ptr vector_holder_; - branch_t vector_node_; - }; - - template - class rebasevector_elem_rtc_node exprtk_final - : public expression_node - , public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef std::pair branch_t; - - rebasevector_elem_rtc_node(expression_ptr vec_node, - expression_ptr index, - vector_holder_ptr vec_holder, - vector_access_runtime_check_ptr vec_rt_chk) - : vector_holder_(vec_holder) - , vec_rt_chk_(vec_rt_chk) - { - construct_branch_pair(vector_node_, vec_node); - construct_branch_pair(index_ , index ); - assert(valid()); - } - - inline T value() const exprtk_override - { - return *access_vector(); - } - - inline T& ref() exprtk_override - { - return *access_vector(); - } - - inline const T& ref() const exprtk_override - { - return *access_vector(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_rbvecelemrtc; - } - - inline bool valid() const exprtk_override - { - return - vector_holder_ && - index_.first && - vector_node_.first && - index_.first->valid() && - vector_node_.first->valid(); - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(vector_node_, node_delete_list); - expression_node::ndb_t::collect(index_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth - (vector_node_, index_); - } - - private: - - inline T* access_vector() const - { - vector_node_.first->value(); - const _uint64_t index = details::numeric::to_uint64(index_.first->value()); - - if (index <= (vector_holder_->size() - 1)) - { - return (vector_holder_->data() + index); - } - - assert(vec_rt_chk_); - - vector_access_runtime_check::violation_context context; - context.base_ptr = reinterpret_cast(vector_holder_->data()); - context.end_ptr = reinterpret_cast(vector_holder_->data() + vector_holder_->size()); - context.access_ptr = reinterpret_cast(vector_holder_->data() + index); - context.type_size = sizeof(T); - - return vec_rt_chk_->handle_runtime_violation(context) ? - reinterpret_cast(context.access_ptr) : - vector_holder_->data() ; - } - - vector_holder_ptr vector_holder_; - branch_t vector_node_; - branch_t index_; - vector_access_runtime_check_ptr vec_rt_chk_; - }; - - template - class rebasevector_celem_rtc_node exprtk_final - : public expression_node - , public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef std::pair branch_t; - - rebasevector_celem_rtc_node(expression_ptr vec_node, - const std::size_t index, - vector_holder_ptr vec_holder, - vector_access_runtime_check_ptr vec_rt_chk) - : index_(index) - , vector_holder_(vec_holder) - , vector_base_((*vec_holder)[0]) - , vec_rt_chk_(vec_rt_chk) - { - construct_branch_pair(vector_node_, vec_node); - assert(valid()); - } - - inline T value() const exprtk_override - { - return *access_vector(); - } - - inline T& ref() exprtk_override - { - return *access_vector(); - } - - inline const T& ref() const exprtk_override - { - return *access_vector(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_rbveccelemrtc; - } - - inline bool valid() const exprtk_override - { - return - vector_holder_ && - vector_node_.first && - vector_node_.first->valid(); - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(vector_node_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(vector_node_); - } - - private: - - inline T* access_vector() const - { - vector_node_.first->value(); - - if (index_ <= vector_holder_->size() - 1) - { - return (vector_holder_->data() + index_); - } - - assert(vec_rt_chk_); - - vector_access_runtime_check::violation_context context; - context.base_ptr = reinterpret_cast(vector_base_); - context.end_ptr = reinterpret_cast(vector_base_ + vector_holder_->size()); - context.access_ptr = reinterpret_cast(vector_base_ + index_); - context.type_size = sizeof(T); - - return vec_rt_chk_->handle_runtime_violation(context) ? - reinterpret_cast(context.access_ptr) : - vector_base_ ; - } - - const std::size_t index_; - vector_holder_ptr vector_holder_; - T* vector_base_; - branch_t vector_node_; - vector_access_runtime_check_ptr vec_rt_chk_; - }; - - template - class vector_initialisation_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vector_initialisation_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list, - const bool single_value_initialse) - : vector_base_(vector_base) - , initialiser_list_(initialiser_list) - , size_(size) - , single_value_initialse_(single_value_initialse) - , zero_value_initialse_(false) - , const_nonzero_literal_value_initialse_(false) - , single_initialiser_value_(T(0)) - { - if (single_value_initialse_) - { - if (initialiser_list_.empty()) - zero_value_initialse_ = true; - else if ( - (initialiser_list_.size() == 1) && - details::is_constant_node(initialiser_list_[0]) && - (T(0) == initialiser_list_[0]->value()) - ) - { - zero_value_initialse_ = true; - } - else - { - assert(initialiser_list_.size() == 1); - - if (details::is_constant_node(initialiser_list_[0])) - { - const_nonzero_literal_value_initialse_ = true; - single_initialiser_value_ = initialiser_list_[0]->value(); - assert(T(0) != single_initialiser_value_); - } - } - } - } - - inline T value() const exprtk_override - { - if (single_value_initialse_) - { - if (zero_value_initialse_) - { - details::set_zero_value(vector_base_, size_); - } - else if (const_nonzero_literal_value_initialse_) - { - for (std::size_t i = 0; i < size_; ++i) - { - *(vector_base_ + i) = single_initialiser_value_; - } - } - else - { - for (std::size_t i = 0; i < size_; ++i) - { - *(vector_base_ + i) = initialiser_list_[0]->value(); - } - } - } - else - { - const std::size_t initialiser_list_size = initialiser_list_.size(); - - for (std::size_t i = 0; i < initialiser_list_size; ++i) - { - *(vector_base_ + i) = initialiser_list_[i]->value(); - } - - if (initialiser_list_size < size_) - { - details::set_zero_value( - vector_base_ + initialiser_list_size, - (size_ - initialiser_list_size)); - } - } - - return *(vector_base_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecinit; - } - - inline bool valid() const exprtk_override - { - return vector_base_; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); - } - - private: - - vector_initialisation_node(const vector_initialisation_node&) exprtk_delete; - vector_initialisation_node& operator=(const vector_initialisation_node&) exprtk_delete; - - mutable T* vector_base_; - std::vector initialiser_list_; - const std::size_t size_; - const bool single_value_initialse_; - bool zero_value_initialse_; - bool const_nonzero_literal_value_initialse_; - T single_initialiser_value_; - }; - - template - class vector_init_zero_value_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vector_init_zero_value_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list) - : vector_base_(vector_base) - , size_(size) - , initialiser_list_(initialiser_list) - {} - - inline T value() const exprtk_override - { - details::set_zero_value(vector_base_, size_); - return *(vector_base_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecinit; - } - - inline bool valid() const exprtk_override - { - return vector_base_; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); - } - - private: - - vector_init_zero_value_node(const vector_init_zero_value_node&) exprtk_delete; - vector_init_zero_value_node& operator=(const vector_init_zero_value_node&) exprtk_delete; - - mutable T* vector_base_; - const std::size_t size_; - std::vector initialiser_list_; - }; - - template - class vector_init_single_constvalue_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vector_init_single_constvalue_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list) - : vector_base_(vector_base) - , size_(size) - , initialiser_list_(initialiser_list) - { - single_initialiser_value_ = initialiser_list_[0]->value(); - assert(valid()); - } - - inline T value() const exprtk_override - { - for (std::size_t i = 0; i < size_; ++i) - { - *(vector_base_ + i) = single_initialiser_value_; - } - - return *(vector_base_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecinit; - } - - inline bool valid() const exprtk_override - { - return vector_base_ && - (initialiser_list_.size() == 1) && - (details::is_constant_node(initialiser_list_[0])) && - (single_initialiser_value_ != T(0)); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); - } - - private: - - vector_init_single_constvalue_node(const vector_init_single_constvalue_node&) exprtk_delete; - vector_init_single_constvalue_node& operator=(const vector_init_single_constvalue_node&) exprtk_delete; - - mutable T* vector_base_; - const std::size_t size_; - std::vector initialiser_list_; - T single_initialiser_value_; - }; - - template - class vector_init_single_value_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vector_init_single_value_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list) - : vector_base_(vector_base) - , size_(size) - , initialiser_list_(initialiser_list) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - expression_node& node = *initialiser_list_[0]; - - for (std::size_t i = 0; i < size_; ++i) - { - *(vector_base_ + i) = node.value(); - } - - return *(vector_base_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecinit; - } - - inline bool valid() const exprtk_override - { - return vector_base_ && - (initialiser_list_.size() == 1) && - !details::is_constant_node(initialiser_list_[0]); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); - } - - private: - - vector_init_single_value_node(const vector_init_single_value_node&) exprtk_delete; - vector_init_single_value_node& operator=(const vector_init_single_value_node&) exprtk_delete; - - mutable T* vector_base_; - const std::size_t size_; - std::vector initialiser_list_; - }; - - template - class vector_init_iota_constconst_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vector_init_iota_constconst_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list) - : vector_base_(vector_base) - , size_(size) - , initialiser_list_(initialiser_list) - { - base_value_ = initialiser_list_[0]->value(); - increment_value_ = initialiser_list_[1]->value(); - - assert(valid()); - } - - inline T value() const exprtk_override - { - T value = base_value_; - - for (std::size_t i = 0; i < size_; ++i, value += increment_value_) - { - *(vector_base_ + i) = value; - } - - return *(vector_base_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecinit; - } - - inline bool valid() const exprtk_override - { - return vector_base_ && - (initialiser_list_.size() == 2) && - (details::is_constant_node(initialiser_list_[0])) && - (details::is_constant_node(initialiser_list_[1])) ; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); - } - - private: - - vector_init_iota_constconst_node(const vector_init_iota_constconst_node&) exprtk_delete; - vector_init_iota_constconst_node& operator=(const vector_init_iota_constconst_node&) exprtk_delete; - - mutable T* vector_base_; - const std::size_t size_; - std::vector initialiser_list_; - T base_value_; - T increment_value_; - }; - - template - class vector_init_iota_constnconst_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vector_init_iota_constnconst_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list) - : vector_base_(vector_base) - , size_(size) - , initialiser_list_(initialiser_list) - { - assert(valid()); - base_value_ = initialiser_list_[0]->value(); - } - - inline T value() const exprtk_override - { - T value = base_value_; - expression_node& increment = *initialiser_list_[1]; - - for (std::size_t i = 0; i < size_; ++i, value += increment.value()) - { - *(vector_base_ + i) = value; - } - - return *(vector_base_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecinit; - } - - inline bool valid() const exprtk_override - { - return vector_base_ && - (initialiser_list_.size() == 2) && - ( details::is_constant_node(initialiser_list_[0])) && - (!details::is_constant_node(initialiser_list_[1])); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); - } - - private: - - vector_init_iota_constnconst_node(const vector_init_iota_constnconst_node&) exprtk_delete; - vector_init_iota_constnconst_node& operator=(const vector_init_iota_constnconst_node&) exprtk_delete; - - mutable T* vector_base_; - const std::size_t size_; - std::vector initialiser_list_; - T base_value_; - }; - - template - class vector_init_iota_nconstconst_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vector_init_iota_nconstconst_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list) - : vector_base_(vector_base) - , size_(size) - , initialiser_list_(initialiser_list) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - T value = initialiser_list_[0]->value(); - const T increment = initialiser_list_[1]->value(); - - for (std::size_t i = 0; i < size_; ++i, value += increment) - { - *(vector_base_ + i) = value; - } - - return *(vector_base_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecinit; - } - - inline bool valid() const exprtk_override - { - return vector_base_ && - (initialiser_list_.size() == 2) && - (!details::is_constant_node(initialiser_list_[0])) && - (details::is_constant_node(initialiser_list_[1])); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); - } - - private: - - vector_init_iota_nconstconst_node(const vector_init_iota_nconstconst_node&) exprtk_delete; - vector_init_iota_nconstconst_node& operator=(const vector_init_iota_nconstconst_node&) exprtk_delete; - - mutable T* vector_base_; - const std::size_t size_; - std::vector initialiser_list_; - }; - - template - class vector_init_iota_nconstnconst_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vector_init_iota_nconstnconst_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list) - : vector_base_(vector_base) - , size_(size) - , initialiser_list_(initialiser_list) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - T value = initialiser_list_[0]->value(); - expression_node& increment = *initialiser_list_[1]; - - for (std::size_t i = 0; i < size_; ++i, value += increment.value()) - { - *(vector_base_ + i) = value; - } - - return *(vector_base_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecinit; - } - - inline bool valid() const exprtk_override - { - return vector_base_ && - (initialiser_list_.size() == 2) && - (!details::is_constant_node(initialiser_list_[0])) && - (!details::is_constant_node(initialiser_list_[1])); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(initialiser_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(initialiser_list_); - } - - private: - - vector_init_iota_nconstnconst_node(const vector_init_iota_nconstnconst_node&) exprtk_delete; - vector_init_iota_nconstnconst_node& operator=(const vector_init_iota_nconstnconst_node&) exprtk_delete; - - mutable T* vector_base_; - const std::size_t size_; - std::vector initialiser_list_; - }; - - template - class swap_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef variable_node* variable_node_ptr; - - swap_node(variable_node_ptr var0, variable_node_ptr var1) - : var0_(var0) - , var1_(var1) - {} - - inline T value() const exprtk_override - { - std::swap(var0_->ref(),var1_->ref()); - return var1_->ref(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_swap; - } - - private: - - variable_node_ptr var0_; - variable_node_ptr var1_; - }; - - template - class swap_generic_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - typedef ivariable* ivariable_ptr; - - swap_generic_node(expression_ptr var0, expression_ptr var1) - : binary_node(details::e_swap, var0, var1) - , var0_(dynamic_cast(var0)) - , var1_(dynamic_cast(var1)) - {} - - inline T value() const exprtk_override - { - std::swap(var0_->ref(),var1_->ref()); - return var1_->ref(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_swap; - } - - private: - - ivariable_ptr var0_; - ivariable_ptr var1_; - }; - - template - class swap_vecvec_node exprtk_final - : public binary_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node * vector_node_ptr; - typedef vec_data_store vds_t; - - using binary_node::branch; - - swap_vecvec_node(expression_ptr branch0, - expression_ptr branch1) - : binary_node(details::e_swap, branch0, branch1) - , vec0_node_ptr_(0) - , vec1_node_ptr_(0) - , initialised_ (false) - { - if (is_ivector_node(branch(0))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(0)))) - { - vec0_node_ptr_ = vi->vec(); - vds() = vi->vds(); - } - } - - if (is_ivector_node(branch(1))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(1)))) - { - vec1_node_ptr_ = vi->vec(); - } - } - - if (vec0_node_ptr_ && vec1_node_ptr_) - { - initialised_ = size() <= base_size(); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - binary_node::branch(0)->value(); - binary_node::branch(1)->value(); - - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - - assert(size() <= base_size()); - const std::size_t n = size(); - - for (std::size_t i = 0; i < n; ++i) - { - std::swap(vec0[i],vec1[i]); - } - - return vec1_node_ptr_->value(); - } - - vector_node_ptr vec() const exprtk_override - { - return vec0_node_ptr_; - } - - vector_node_ptr vec() exprtk_override - { - return vec0_node_ptr_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecvecswap; - } - - inline bool valid() const exprtk_override - { - return initialised_ && binary_node::valid(); - } - - std::size_t size() const exprtk_override - { - return std::min( - vec0_node_ptr_->vec_holder().size(), - vec1_node_ptr_->vec_holder().size()); - } - - std::size_t base_size() const exprtk_override - { - return std::min( - vec0_node_ptr_->vec_holder().base_size(), - vec1_node_ptr_->vec_holder().base_size()); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - private: - - vector_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - bool initialised_; - vds_t vds_; - }; - - #ifndef exprtk_disable_string_capabilities - template - class stringvar_node exprtk_final - : public expression_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - - static std::string null_value; - - explicit stringvar_node() - : value_(&null_value) - {} - - explicit stringvar_node(std::string& v) - : value_(&v) - { - rp_.n0_c = std::make_pair(true,0); - rp_.n1_c = std::make_pair(true,v.size()); - rp_.cache.first = rp_.n0_c.second; - rp_.cache.second = rp_.n1_c.second; - } - - inline bool operator <(const stringvar_node& v) const - { - return this < (&v); - } - - inline T value() const exprtk_override - { - rp_.n1_c.second = (*value_).size(); - rp_.cache.second = rp_.n1_c.second; - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return ref(); - } - - char_cptr base() const exprtk_override - { - return &(*value_)[0]; - } - - std::size_t size() const exprtk_override - { - return ref().size(); - } - - std::string& ref() - { - return (*value_); - } - - const std::string& ref() const - { - return (*value_); - } - - range_t& range_ref() exprtk_override - { - return rp_; - } - - const range_t& range_ref() const exprtk_override - { - return rp_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_stringvar; - } - - void rebase(std::string& s) - { - value_ = &s; - rp_.n0_c = std::make_pair(true,0); - rp_.n1_c = std::make_pair(true,value_->size() - 1); - rp_.cache.first = rp_.n0_c.second; - rp_.cache.second = rp_.n1_c.second; - } - - private: - - std::string* value_; - mutable range_t rp_; - }; - - template - std::string stringvar_node::null_value = std::string(""); - - template - class string_range_node exprtk_final - : public expression_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - - static std::string null_value; - - explicit string_range_node(std::string& v, const range_t& rp) - : value_(&v) - , rp_(rp) - {} - - virtual ~string_range_node() - { - rp_.free(); - } - - inline bool operator <(const string_range_node& v) const - { - return this < (&v); - } - - inline T value() const exprtk_override - { - return std::numeric_limits::quiet_NaN(); - } - - inline std::string str() const exprtk_override - { - return (*value_); - } - - char_cptr base() const exprtk_override - { - return &(*value_)[0]; - } - - std::size_t size() const exprtk_override - { - return ref().size(); - } - - inline range_t range() const - { - return rp_; - } - - inline virtual std::string& ref() - { - return (*value_); - } - - inline virtual const std::string& ref() const - { - return (*value_); - } - - inline range_t& range_ref() exprtk_override - { - return rp_; - } - - inline const range_t& range_ref() const exprtk_override - { - return rp_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_stringvarrng; - } - - private: - - std::string* value_; - range_t rp_; - }; - - template - std::string string_range_node::null_value = std::string(""); - - template - class const_string_range_node exprtk_final - : public expression_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - - explicit const_string_range_node(const std::string& v, const range_t& rp) - : value_(v) - , rp_(rp) - {} - - ~const_string_range_node() - { - rp_.free(); - } - - inline T value() const exprtk_override - { - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return value_; - } - - char_cptr base() const exprtk_override - { - return value_.data(); - } - - std::size_t size() const exprtk_override - { - return value_.size(); - } - - range_t range() const - { - return rp_; - } - - range_t& range_ref() exprtk_override - { - return rp_; - } - - const range_t& range_ref() const exprtk_override - { - return rp_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_cstringvarrng; - } - - private: - - const_string_range_node(const const_string_range_node&) exprtk_delete; - const_string_range_node& operator=(const const_string_range_node&) exprtk_delete; - - const std::string value_; - range_t rp_; - }; - - template - class generic_string_range_node exprtk_final - : public expression_node - , public string_base_node - , public range_interface - { - public: - - typedef expression_node * expression_ptr; - typedef stringvar_node * strvar_node_ptr; - typedef string_base_node* str_base_ptr; - typedef typename range_interface::range_t range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef std::pair branch_t; - - generic_string_range_node(expression_ptr str_branch, const range_t& brange) - : initialised_(false) - , str_base_ptr_ (0) - , str_range_ptr_(0) - , base_range_(brange) - { - range_.n0_c = std::make_pair(true,0); - range_.n1_c = std::make_pair(true,0); - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; - - construct_branch_pair(branch_, str_branch); - - if (is_generally_string_node(branch_.first)) - { - str_base_ptr_ = dynamic_cast(branch_.first); - - if (0 == str_base_ptr_) - return; - - str_range_ptr_ = dynamic_cast(branch_.first); - - if (0 == str_range_ptr_) - return; - } - - initialised_ = (str_base_ptr_ && str_range_ptr_); - assert(valid()); - } - - ~generic_string_range_node() - { - base_range_.free(); - } - - inline T value() const exprtk_override - { - branch_.first->value(); - - std::size_t str_r0 = 0; - std::size_t str_r1 = 0; - - std::size_t r0 = 0; - std::size_t r1 = 0; - - const range_t& range = str_range_ptr_->range_ref(); - - const std::size_t base_str_size = str_base_ptr_->size(); - - if ( - range (str_r0, str_r1, base_str_size ) && - base_range_(r0 , r1 , base_str_size - str_r0) - ) - { - const std::size_t size = r1 - r0; - - range_.n1_c.second = size; - range_.cache.second = range_.n1_c.second; - - value_.assign(str_base_ptr_->base() + str_r0 + r0, size); - } - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return value_; - } - - char_cptr base() const exprtk_override - { - return &value_[0]; - } - - std::size_t size() const exprtk_override - { - return value_.size(); - } - - range_t& range_ref() exprtk_override - { - return range_; - } - - const range_t& range_ref() const exprtk_override - { - return range_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strgenrange; - } - - inline bool valid() const exprtk_override - { - return initialised_ && branch_.first; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - bool initialised_; - branch_t branch_; - str_base_ptr str_base_ptr_; - irange_ptr str_range_ptr_; - mutable range_t base_range_; - mutable range_t range_; - mutable std::string value_; - }; - - template - class string_concat_node exprtk_final - : public binary_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef range_t* range_ptr; - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - - using binary_node::branch; - - string_concat_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , initialised_(false) - , str0_base_ptr_ (0) - , str1_base_ptr_ (0) - , str0_range_ptr_(0) - , str1_range_ptr_(0) - { - range_.n0_c = std::make_pair(true,0); - range_.n1_c = std::make_pair(true,0); - - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; - - if (is_generally_string_node(branch(0))) - { - str0_base_ptr_ = dynamic_cast(branch(0)); - - if (0 == str0_base_ptr_) - return; - - str0_range_ptr_ = dynamic_cast(branch(0)); - - if (0 == str0_range_ptr_) - return; - } - - if (is_generally_string_node(branch(1))) - { - str1_base_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_base_ptr_) - return; - - str1_range_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_range_ptr_) - return; - } - - initialised_ = str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ ; - - assert(valid()); - } - - inline T value() const exprtk_override - { - branch(0)->value(); - branch(1)->value(); - - std::size_t str0_r0 = 0; - std::size_t str0_r1 = 0; - - std::size_t str1_r0 = 0; - std::size_t str1_r1 = 0; - - const range_t& range0 = str0_range_ptr_->range_ref(); - const range_t& range1 = str1_range_ptr_->range_ref(); - - if ( - range0(str0_r0, str0_r1, str0_base_ptr_->size()) && - range1(str1_r0, str1_r1, str1_base_ptr_->size()) - ) - { - const std::size_t size0 = (str0_r1 - str0_r0); - const std::size_t size1 = (str1_r1 - str1_r0); - - value_.assign(str0_base_ptr_->base() + str0_r0, size0); - value_.append(str1_base_ptr_->base() + str1_r0, size1); - - range_.n1_c.second = value_.size(); - range_.cache.second = range_.n1_c.second; - } - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return value_; - } - - char_cptr base() const exprtk_override - { - return &value_[0]; - } - - std::size_t size() const exprtk_override - { - return value_.size(); - } - - range_t& range_ref() exprtk_override - { - return range_; - } - - const range_t& range_ref() const exprtk_override - { - return range_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strconcat; - } - - inline bool valid() const exprtk_override - { - return initialised_ && binary_node::valid(); - } - - private: - - bool initialised_; - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - irange_ptr str0_range_ptr_; - irange_ptr str1_range_ptr_; - mutable range_t range_; - mutable std::string value_; - }; - - template - class swap_string_node exprtk_final - : public binary_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef expression_node * expression_ptr; - typedef stringvar_node * strvar_node_ptr; - typedef string_base_node* str_base_ptr; - - using binary_node::branch; - - swap_string_node(expression_ptr branch0, expression_ptr branch1) - : binary_node(details::e_swap, branch0, branch1) - , initialised_(false) - , str0_node_ptr_(0) - , str1_node_ptr_(0) - { - if (is_string_node(branch(0))) - { - str0_node_ptr_ = static_cast(branch(0)); - } - - if (is_string_node(branch(1))) - { - str1_node_ptr_ = static_cast(branch(1)); - } - - initialised_ = (str0_node_ptr_ && str1_node_ptr_); - assert(valid()); - } - - inline T value() const exprtk_override - { - branch(0)->value(); - branch(1)->value(); - - std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return str0_node_ptr_->str(); - } - - char_cptr base() const exprtk_override - { - return str0_node_ptr_->base(); - } - - std::size_t size() const exprtk_override - { - return str0_node_ptr_->size(); - } - - range_t& range_ref() exprtk_override - { - return str0_node_ptr_->range_ref(); - } - - const range_t& range_ref() const exprtk_override - { - return str0_node_ptr_->range_ref(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strswap; - } - - inline bool valid() const exprtk_override - { - return initialised_ && binary_node::valid(); - } - - private: - - bool initialised_; - strvar_node_ptr str0_node_ptr_; - strvar_node_ptr str1_node_ptr_; - }; - - template - class swap_genstrings_node exprtk_final : public binary_node - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - - using binary_node::branch; - - swap_genstrings_node(expression_ptr branch0, - expression_ptr branch1) - : binary_node(details::e_default, branch0, branch1) - , str0_base_ptr_ (0) - , str1_base_ptr_ (0) - , str0_range_ptr_(0) - , str1_range_ptr_(0) - , initialised_(false) - { - if (is_generally_string_node(branch(0))) - { - str0_base_ptr_ = dynamic_cast(branch(0)); - - if (0 == str0_base_ptr_) - return; - - irange_ptr range = dynamic_cast(branch(0)); - - if (0 == range) - return; - - str0_range_ptr_ = &(range->range_ref()); - } - - if (is_generally_string_node(branch(1))) - { - str1_base_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_base_ptr_) - return; - - irange_ptr range = dynamic_cast(branch(1)); - - if (0 == range) - return; - - str1_range_ptr_ = &(range->range_ref()); - } - - initialised_ = str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ ; - - assert(valid()); - } - - inline T value() const exprtk_override - { - branch(0)->value(); - branch(1)->value(); - - std::size_t str0_r0 = 0; - std::size_t str0_r1 = 0; - - std::size_t str1_r0 = 0; - std::size_t str1_r1 = 0; - - const range_t& range0 = (*str0_range_ptr_); - const range_t& range1 = (*str1_range_ptr_); - - if ( - range0(str0_r0, str0_r1, str0_base_ptr_->size()) && - range1(str1_r0, str1_r1, str1_base_ptr_->size()) - ) - { - const std::size_t size0 = range0.cache_size(); - const std::size_t size1 = range1.cache_size(); - const std::size_t max_size = std::min(size0,size1); - - char_ptr s0 = const_cast(str0_base_ptr_->base() + str0_r0); - char_ptr s1 = const_cast(str1_base_ptr_->base() + str1_r0); - - loop_unroll::details lud(max_size); - char_cptr upper_bound = s0 + lud.upper_bound; - - while (s0 < upper_bound) - { - #define exprtk_loop(N) \ - std::swap(s0[N], s1[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - s0 += lud.batch_size; - s1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { std::swap(s0[i], s1[i]); ++i; } \ - exprtk_fallthrough \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - default: break; - } - - #undef exprtk_loop - #undef case_stmt - } - - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strswap; - } - - inline bool valid() const exprtk_override - { - return initialised_ && binary_node::valid(); - } - - private: - - swap_genstrings_node(const swap_genstrings_node&) exprtk_delete; - swap_genstrings_node& operator=(const swap_genstrings_node&) exprtk_delete; - - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - range_ptr str0_range_ptr_; - range_ptr str1_range_ptr_; - bool initialised_; - }; - - template - class stringvar_size_node exprtk_final : public expression_node - { - public: - - static const std::string null_value; - - explicit stringvar_size_node() - : value_(&null_value) - {} - - explicit stringvar_size_node(std::string& v) - : value_(&v) - {} - - inline T value() const exprtk_override - { - return T((*value_).size()); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_stringvarsize; - } - - private: - - const std::string* value_; - }; - - template - const std::string stringvar_size_node::null_value = std::string(""); - - template - class string_size_node exprtk_final : public expression_node - { - public: - - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - typedef std::pair branch_t; - - explicit string_size_node(expression_ptr branch) - : str_base_ptr_(0) - { - construct_branch_pair(branch_, branch); - - if (is_generally_string_node(branch_.first)) - { - str_base_ptr_ = dynamic_cast(branch_.first); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - branch_.first->value(); - return T(str_base_ptr_->size()); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_stringsize; - } - - inline bool valid() const exprtk_override - { - return str_base_ptr_; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - branch_t branch_; - str_base_ptr str_base_ptr_; - }; - - struct asn_assignment - { - static inline void execute(std::string& s, char_cptr data, const std::size_t size) - { s.assign(data,size); } - }; - - struct asn_addassignment - { - static inline void execute(std::string& s, char_cptr data, const std::size_t size) - { s.append(data,size); } - }; - - template - class assignment_string_node exprtk_final - : public binary_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef expression_node * expression_ptr; - typedef stringvar_node * strvar_node_ptr; - typedef string_base_node* str_base_ptr; - - using binary_node::branch; - - assignment_string_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , initialised_(false) - , str0_base_ptr_ (0) - , str1_base_ptr_ (0) - , str0_node_ptr_ (0) - , str1_range_ptr_(0) - { - if (is_string_node(branch(0))) - { - str0_node_ptr_ = static_cast(branch(0)); - str0_base_ptr_ = dynamic_cast(branch(0)); - } - - if (is_generally_string_node(branch(1))) - { - str1_base_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_base_ptr_) - return; - - irange_ptr range = dynamic_cast(branch(1)); - - if (0 == range) - return; - - str1_range_ptr_ = &(range->range_ref()); - } - - initialised_ = str0_base_ptr_ && - str1_base_ptr_ && - str0_node_ptr_ && - str1_range_ptr_ ; - - assert(valid()); - } - - inline T value() const exprtk_override - { - branch(1)->value(); - - std::size_t r0 = 0; - std::size_t r1 = 0; - - const range_t& range = (*str1_range_ptr_); - - if (range(r0, r1, str1_base_ptr_->size())) - { - AssignmentProcess::execute( - str0_node_ptr_->ref(), - str1_base_ptr_->base() + r0, (r1 - r0)); - - branch(0)->value(); - } - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return str0_node_ptr_->str(); - } - - char_cptr base() const exprtk_override - { - return str0_node_ptr_->base(); - } - - std::size_t size() const exprtk_override - { - return str0_node_ptr_->size(); - } - - range_t& range_ref() exprtk_override - { - return str0_node_ptr_->range_ref(); - } - - const range_t& range_ref() const exprtk_override - { - return str0_node_ptr_->range_ref(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strass; - } - - inline bool valid() const exprtk_override - { - return initialised_ && binary_node::valid(); - } - - private: - - bool initialised_; - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - strvar_node_ptr str0_node_ptr_; - range_ptr str1_range_ptr_; - }; - - template - class assignment_string_range_node exprtk_final - : public binary_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef expression_node * expression_ptr; - typedef stringvar_node * strvar_node_ptr; - typedef string_range_node* str_rng_node_ptr; - typedef string_base_node * str_base_ptr; - - using binary_node::branch; - - assignment_string_range_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , initialised_(false) - , str0_base_ptr_ (0) - , str1_base_ptr_ (0) - , str0_rng_node_ptr_(0) - , str0_range_ptr_ (0) - , str1_range_ptr_ (0) - { - if (is_string_range_node(branch(0))) - { - str0_rng_node_ptr_ = static_cast(branch(0)); - str0_base_ptr_ = dynamic_cast(branch(0)); - irange_ptr range = dynamic_cast(branch(0)); - - if (0 == range) - return; - - str0_range_ptr_ = &(range->range_ref()); - } - - if (is_generally_string_node(branch(1))) - { - str1_base_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_base_ptr_) - return; - - irange_ptr range = dynamic_cast(branch(1)); - - if (0 == range) - return; - - str1_range_ptr_ = &(range->range_ref()); - } - - initialised_ = str0_base_ptr_ && - str1_base_ptr_ && - str0_rng_node_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ ; - - assert(valid()); - } - - inline T value() const exprtk_override - { - branch(0)->value(); - branch(1)->value(); - - std::size_t s0_r0 = 0; - std::size_t s0_r1 = 0; - - std::size_t s1_r0 = 0; - std::size_t s1_r1 = 0; - - const range_t& range0 = (*str0_range_ptr_); - const range_t& range1 = (*str1_range_ptr_); - - if ( - range0(s0_r0, s0_r1, str0_base_ptr_->size()) && - range1(s1_r0, s1_r1, str1_base_ptr_->size()) - ) - { - const std::size_t size = std::min((s0_r1 - s0_r0), (s1_r1 - s1_r0)); - - std::copy( - str1_base_ptr_->base() + s1_r0, - str1_base_ptr_->base() + s1_r0 + size, - const_cast(base() + s0_r0)); - } - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return str0_base_ptr_->str(); - } - - char_cptr base() const exprtk_override - { - return str0_base_ptr_->base(); - } - - std::size_t size() const exprtk_override - { - return str0_base_ptr_->size(); - } - - range_t& range_ref() exprtk_override - { - return str0_rng_node_ptr_->range_ref(); - } - - const range_t& range_ref() const exprtk_override - { - return str0_rng_node_ptr_->range_ref(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strass; - } - - inline bool valid() const exprtk_override - { - return initialised_ && binary_node::valid(); - } - - private: - - bool initialised_; - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - str_rng_node_ptr str0_rng_node_ptr_; - range_ptr str0_range_ptr_; - range_ptr str1_range_ptr_; - }; - - template - class conditional_string_node exprtk_final - : public trinary_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - - conditional_string_node(expression_ptr condition, - expression_ptr consequent, - expression_ptr alternative) - : trinary_node(details::e_default, consequent, alternative, condition) - , initialised_(false) - , str0_base_ptr_ (0) - , str1_base_ptr_ (0) - , str0_range_ptr_(0) - , str1_range_ptr_(0) - , condition_ (condition ) - , consequent_ (consequent ) - , alternative_(alternative) - { - range_.n0_c = std::make_pair(true,0); - range_.n1_c = std::make_pair(true,0); - - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; - - if (is_generally_string_node(trinary_node::branch_[0].first)) - { - str0_base_ptr_ = dynamic_cast(trinary_node::branch_[0].first); - - if (0 == str0_base_ptr_) - return; - - str0_range_ptr_ = dynamic_cast(trinary_node::branch_[0].first); - - if (0 == str0_range_ptr_) - return; - } - - if (is_generally_string_node(trinary_node::branch_[1].first)) - { - str1_base_ptr_ = dynamic_cast(trinary_node::branch_[1].first); - - if (0 == str1_base_ptr_) - return; - - str1_range_ptr_ = dynamic_cast(trinary_node::branch_[1].first); - - if (0 == str1_range_ptr_) - return; - } - - initialised_ = str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ ; - - assert(valid()); - } - - inline T value() const exprtk_override - { - std::size_t r0 = 0; - std::size_t r1 = 0; - - if (is_true(condition_)) - { - consequent_->value(); - - const range_t& range = str0_range_ptr_->range_ref(); - - if (range(r0, r1, str0_base_ptr_->size())) - { - const std::size_t size = (r1 - r0); - - value_.assign(str0_base_ptr_->base() + r0, size); - - range_.n1_c.second = value_.size(); - range_.cache.second = range_.n1_c.second; - - return T(1); - } - } - else - { - alternative_->value(); - - const range_t& range = str1_range_ptr_->range_ref(); - - if (range(r0, r1, str1_base_ptr_->size())) - { - const std::size_t size = (r1 - r0); - - value_.assign(str1_base_ptr_->base() + r0, size); - - range_.n1_c.second = value_.size(); - range_.cache.second = range_.n1_c.second; - - return T(0); - } - } - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return value_; - } - - char_cptr base() const exprtk_override - { - return &value_[0]; - } - - std::size_t size() const exprtk_override - { - return value_.size(); - } - - range_t& range_ref() exprtk_override - { - return range_; - } - - const range_t& range_ref() const exprtk_override - { - return range_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strcondition; - } - - inline bool valid() const exprtk_override - { - return - initialised_ && - condition_ && condition_ ->valid() && - consequent_ && consequent_ ->valid() && - alternative_&& alternative_->valid() ; - } - - private: - - bool initialised_; - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - irange_ptr str0_range_ptr_; - irange_ptr str1_range_ptr_; - mutable range_t range_; - mutable std::string value_; - - expression_ptr condition_; - expression_ptr consequent_; - expression_ptr alternative_; - }; - - template - class cons_conditional_str_node exprtk_final - : public binary_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - - using binary_node::branch; - - cons_conditional_str_node(expression_ptr condition, - expression_ptr consequent) - : binary_node(details::e_default, consequent, condition) - , initialised_(false) - , str0_base_ptr_ (0) - , str0_range_ptr_(0) - , condition_ (condition ) - , consequent_(consequent) - { - range_.n0_c = std::make_pair(true,0); - range_.n1_c = std::make_pair(true,0); - - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; - - if (is_generally_string_node(branch(0))) - { - str0_base_ptr_ = dynamic_cast(branch(0)); - - if (0 == str0_base_ptr_) - return; - - str0_range_ptr_ = dynamic_cast(branch(0)); - - if (0 == str0_range_ptr_) - return; - } - - initialised_ = str0_base_ptr_ && str0_range_ptr_ ; - assert(valid()); - } - - inline T value() const exprtk_override - { - if (is_true(condition_)) - { - consequent_->value(); - - const range_t& range = str0_range_ptr_->range_ref(); - - std::size_t r0 = 0; - std::size_t r1 = 0; - - if (range(r0, r1, str0_base_ptr_->size())) - { - const std::size_t size = (r1 - r0); - - value_.assign(str0_base_ptr_->base() + r0, size); - - range_.n1_c.second = value_.size(); - range_.cache.second = range_.n1_c.second; - - return T(1); - } - } - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const - { - return value_; - } - - char_cptr base() const - { - return &value_[0]; - } - - std::size_t size() const - { - return value_.size(); - } - - range_t& range_ref() - { - return range_; - } - - const range_t& range_ref() const - { - return range_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strccondition; - } - - inline bool valid() const exprtk_override - { - return - initialised_ && - condition_ && condition_ ->valid() && - consequent_ && consequent_ ->valid() ; - } - - private: - - bool initialised_; - str_base_ptr str0_base_ptr_; - irange_ptr str0_range_ptr_; - mutable range_t range_; - mutable std::string value_; - - expression_ptr condition_; - expression_ptr consequent_; - }; - - template - class str_vararg_node exprtk_final - : public expression_node - , public string_base_node - , public range_interface - { - public: - - typedef typename range_interface::range_t range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - typedef std::pair branch_t; - - template class Sequence> - explicit str_vararg_node(const Sequence& arg_list) - : initialised_(false) - , str_base_ptr_ (0) - , str_range_ptr_(0) - { - construct_branch_pair(final_node_, const_cast(arg_list.back())); - - if (0 == final_node_.first) - return; - else if (!is_generally_string_node(final_node_.first)) - return; - - str_base_ptr_ = dynamic_cast(final_node_.first); - - if (0 == str_base_ptr_) - return; - - str_range_ptr_ = dynamic_cast(final_node_.first); - - if (0 == str_range_ptr_) - return; - - if (arg_list.size() > 1) - { - const std::size_t arg_list_size = arg_list.size() - 1; - - arg_list_.resize(arg_list_size); - - for (std::size_t i = 0; i < arg_list_size; ++i) - { - if (arg_list[i] && arg_list[i]->valid()) - { - construct_branch_pair(arg_list_[i], arg_list[i]); - } - else - { - arg_list_.clear(); - return; - } - } - - initialised_ = true; - } - - initialised_ &= str_base_ptr_ && str_range_ptr_; - assert(valid()); - } - - inline T value() const exprtk_override - { - if (!arg_list_.empty()) - { - VarArgFunction::process(arg_list_); - } - - final_node_.first->value(); - - return std::numeric_limits::quiet_NaN(); - } - - std::string str() const exprtk_override - { - return str_base_ptr_->str(); - } - - char_cptr base() const exprtk_override - { - return str_base_ptr_->base(); - } - - std::size_t size() const exprtk_override - { - return str_base_ptr_->size(); - } - - range_t& range_ref() exprtk_override - { - return str_range_ptr_->range_ref(); - } - - const range_t& range_ref() const exprtk_override - { - return str_range_ptr_->range_ref(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_stringvararg; - } - - inline bool valid() const exprtk_override - { - return - initialised_ && - final_node_.first && final_node_.first->valid(); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(final_node_ , node_delete_list); - expression_node::ndb_t::collect(arg_list_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return std::max( - expression_node::ndb_t::compute_node_depth(final_node_), - expression_node::ndb_t::compute_node_depth(arg_list_ )); - } - - private: - - bool initialised_; - branch_t final_node_; - str_base_ptr str_base_ptr_; - irange_ptr str_range_ptr_; - std::vector arg_list_; - }; - #endif - - template - class assert_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef string_base_node* str_base_ptr; - typedef assert_check::assert_context assert_context_t; - - assert_node(expression_ptr assert_condition_node, - expression_ptr assert_message_node, - assert_check_ptr assert_check, - assert_context_t context) - : assert_message_str_base_(0) - , assert_check_(assert_check) - , context_(context) - { - construct_branch_pair(assert_condition_node_, assert_condition_node); - construct_branch_pair(assert_message_node_ , assert_message_node ); - - #ifndef exprtk_disable_string_capabilities - if ( - assert_message_node_.first && - details::is_generally_string_node(assert_message_node_.first) - ) - { - assert_message_str_base_ = dynamic_cast(assert_message_node_.first); - } - #endif - - assert(valid()); - } - - inline T value() const exprtk_override - { - if (details::is_true(assert_condition_node_.first->value())) - { - return T(1); - } - - #ifndef exprtk_disable_string_capabilities - if (assert_message_node_.first) - { - assert_message_node_.first->value(); - assert(assert_message_str_base_); - context_.message = assert_message_str_base_->str(); - } - #endif - - assert_check_->handle_assert(context_); - return T(0); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_assert; - } - - inline bool valid() const exprtk_override - { - return ( - assert_check_ && - assert_condition_node_.first && - assert_condition_node_.first->valid() - ) && - ( - (0 == assert_message_node_.first) || - ( - assert_message_node_.first && - assert_message_str_base_ && - assert_message_node_.first->valid() && - details::is_generally_string_node(assert_message_node_.first) - ) - ); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(assert_condition_node_, node_delete_list); - expression_node::ndb_t::collect(assert_message_node_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth - (assert_condition_node_, assert_message_node_); - } - - private: - - branch_t assert_condition_node_; - branch_t assert_message_node_; - str_base_ptr assert_message_str_base_; - assert_check_ptr assert_check_; - mutable assert_context_t context_; - }; - - template - inline T axn(const T a, const T x) - { - // a*x^n - return a * exprtk::details::numeric::fast_exp::result(x); - } - - template - inline T axnb(const T a, const T x, const T b) - { - // a*x^n+b - return a * exprtk::details::numeric::fast_exp::result(x) + b; - } - - template - struct sf_base - { - typedef typename details::functor_t::Type Type; - typedef typename details::functor_t functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; - }; - - #define define_sfop3(NN, OP0, OP1) \ - template \ - struct sf##NN##_op : public sf_base \ - { \ - typedef typename sf_base::Type const Type; \ - static inline T process(Type x, Type y, Type z) \ - { \ - return (OP0); \ - } \ - static inline std::string id() \ - { \ - return (OP1); \ - } \ - }; \ - - define_sfop3(00,(x + y) / z ,"(t+t)/t") - define_sfop3(01,(x + y) * z ,"(t+t)*t") - define_sfop3(02,(x + y) - z ,"(t+t)-t") - define_sfop3(03,(x + y) + z ,"(t+t)+t") - define_sfop3(04,(x - y) + z ,"(t-t)+t") - define_sfop3(05,(x - y) / z ,"(t-t)/t") - define_sfop3(06,(x - y) * z ,"(t-t)*t") - define_sfop3(07,(x * y) + z ,"(t*t)+t") - define_sfop3(08,(x * y) - z ,"(t*t)-t") - define_sfop3(09,(x * y) / z ,"(t*t)/t") - define_sfop3(10,(x * y) * z ,"(t*t)*t") - define_sfop3(11,(x / y) + z ,"(t/t)+t") - define_sfop3(12,(x / y) - z ,"(t/t)-t") - define_sfop3(13,(x / y) / z ,"(t/t)/t") - define_sfop3(14,(x / y) * z ,"(t/t)*t") - define_sfop3(15,x / (y + z) ,"t/(t+t)") - define_sfop3(16,x / (y - z) ,"t/(t-t)") - define_sfop3(17,x / (y * z) ,"t/(t*t)") - define_sfop3(18,x / (y / z) ,"t/(t/t)") - define_sfop3(19,x * (y + z) ,"t*(t+t)") - define_sfop3(20,x * (y - z) ,"t*(t-t)") - define_sfop3(21,x * (y * z) ,"t*(t*t)") - define_sfop3(22,x * (y / z) ,"t*(t/t)") - define_sfop3(23,x - (y + z) ,"t-(t+t)") - define_sfop3(24,x - (y - z) ,"t-(t-t)") - define_sfop3(25,x - (y / z) ,"t-(t/t)") - define_sfop3(26,x - (y * z) ,"t-(t*t)") - define_sfop3(27,x + (y * z) ,"t+(t*t)") - define_sfop3(28,x + (y / z) ,"t+(t/t)") - define_sfop3(29,x + (y + z) ,"t+(t+t)") - define_sfop3(30,x + (y - z) ,"t+(t-t)") - define_sfop3(31,(axnb(x,y,z))," ") - define_sfop3(32,(axnb(x,y,z))," ") - define_sfop3(33,(axnb(x,y,z))," ") - define_sfop3(34,(axnb(x,y,z))," ") - define_sfop3(35,(axnb(x,y,z))," ") - define_sfop3(36,(axnb(x,y,z))," ") - define_sfop3(37,(axnb(x,y,z))," ") - define_sfop3(38,(axnb(x,y,z))," ") - define_sfop3(39,x * numeric::log(y) + z,"") - define_sfop3(40,x * numeric::log(y) - z,"") - define_sfop3(41,x * numeric::log10(y) + z,"") - define_sfop3(42,x * numeric::log10(y) - z,"") - define_sfop3(43,x * numeric::sin(y) + z ,"") - define_sfop3(44,x * numeric::sin(y) - z ,"") - define_sfop3(45,x * numeric::cos(y) + z ,"") - define_sfop3(46,x * numeric::cos(y) - z ,"") - define_sfop3(47,details::is_true(x) ? y : z,"") - - #define define_sfop4(NN, OP0, OP1) \ - template \ - struct sf##NN##_op : public sf_base \ - { \ - typedef typename sf_base::Type const Type; \ - static inline T process(Type x, Type y, Type z, Type w) \ - { \ - return (OP0); \ - } \ - static inline std::string id() \ - { \ - return (OP1); \ - } \ - }; \ - - define_sfop4(48,(x + ((y + z) / w)),"t+((t+t)/t)") - define_sfop4(49,(x + ((y + z) * w)),"t+((t+t)*t)") - define_sfop4(50,(x + ((y - z) / w)),"t+((t-t)/t)") - define_sfop4(51,(x + ((y - z) * w)),"t+((t-t)*t)") - define_sfop4(52,(x + ((y * z) / w)),"t+((t*t)/t)") - define_sfop4(53,(x + ((y * z) * w)),"t+((t*t)*t)") - define_sfop4(54,(x + ((y / z) + w)),"t+((t/t)+t)") - define_sfop4(55,(x + ((y / z) / w)),"t+((t/t)/t)") - define_sfop4(56,(x + ((y / z) * w)),"t+((t/t)*t)") - define_sfop4(57,(x - ((y + z) / w)),"t-((t+t)/t)") - define_sfop4(58,(x - ((y + z) * w)),"t-((t+t)*t)") - define_sfop4(59,(x - ((y - z) / w)),"t-((t-t)/t)") - define_sfop4(60,(x - ((y - z) * w)),"t-((t-t)*t)") - define_sfop4(61,(x - ((y * z) / w)),"t-((t*t)/t)") - define_sfop4(62,(x - ((y * z) * w)),"t-((t*t)*t)") - define_sfop4(63,(x - ((y / z) / w)),"t-((t/t)/t)") - define_sfop4(64,(x - ((y / z) * w)),"t-((t/t)*t)") - define_sfop4(65,(((x + y) * z) - w),"((t+t)*t)-t") - define_sfop4(66,(((x - y) * z) - w),"((t-t)*t)-t") - define_sfop4(67,(((x * y) * z) - w),"((t*t)*t)-t") - define_sfop4(68,(((x / y) * z) - w),"((t/t)*t)-t") - define_sfop4(69,(((x + y) / z) - w),"((t+t)/t)-t") - define_sfop4(70,(((x - y) / z) - w),"((t-t)/t)-t") - define_sfop4(71,(((x * y) / z) - w),"((t*t)/t)-t") - define_sfop4(72,(((x / y) / z) - w),"((t/t)/t)-t") - define_sfop4(73,((x * y) + (z * w)),"(t*t)+(t*t)") - define_sfop4(74,((x * y) - (z * w)),"(t*t)-(t*t)") - define_sfop4(75,((x * y) + (z / w)),"(t*t)+(t/t)") - define_sfop4(76,((x * y) - (z / w)),"(t*t)-(t/t)") - define_sfop4(77,((x / y) + (z / w)),"(t/t)+(t/t)") - define_sfop4(78,((x / y) - (z / w)),"(t/t)-(t/t)") - define_sfop4(79,((x / y) - (z * w)),"(t/t)-(t*t)") - define_sfop4(80,(x / (y + (z * w))),"t/(t+(t*t))") - define_sfop4(81,(x / (y - (z * w))),"t/(t-(t*t))") - define_sfop4(82,(x * (y + (z * w))),"t*(t+(t*t))") - define_sfop4(83,(x * (y - (z * w))),"t*(t-(t*t))") - - define_sfop4(84,(axn(x,y) + axn(z,w)),"") - define_sfop4(85,(axn(x,y) + axn(z,w)),"") - define_sfop4(86,(axn(x,y) + axn(z,w)),"") - define_sfop4(87,(axn(x,y) + axn(z,w)),"") - define_sfop4(88,(axn(x,y) + axn(z,w)),"") - define_sfop4(89,(axn(x,y) + axn(z,w)),"") - define_sfop4(90,(axn(x,y) + axn(z,w)),"") - define_sfop4(91,(axn(x,y) + axn(z,w)),"") - define_sfop4(92,((details::is_true(x) && details::is_true(y)) ? z : w),"") - define_sfop4(93,((details::is_true(x) || details::is_true(y)) ? z : w),"") - define_sfop4(94,((x < y) ? z : w),"") - define_sfop4(95,((x <= y) ? z : w),"") - define_sfop4(96,((x > y) ? z : w),"") - define_sfop4(97,((x >= y) ? z : w),"") - define_sfop4(98,(details::is_true(numeric::equal(x,y)) ? z : w),"") - define_sfop4(99,(x * numeric::sin(y) + z * numeric::cos(w)),"") - - define_sfop4(ext00,((x + y) - (z * w)),"(t+t)-(t*t)") - define_sfop4(ext01,((x + y) - (z / w)),"(t+t)-(t/t)") - define_sfop4(ext02,((x + y) + (z * w)),"(t+t)+(t*t)") - define_sfop4(ext03,((x + y) + (z / w)),"(t+t)+(t/t)") - define_sfop4(ext04,((x - y) + (z * w)),"(t-t)+(t*t)") - define_sfop4(ext05,((x - y) + (z / w)),"(t-t)+(t/t)") - define_sfop4(ext06,((x - y) - (z * w)),"(t-t)-(t*t)") - define_sfop4(ext07,((x - y) - (z / w)),"(t-t)-(t/t)") - define_sfop4(ext08,((x + y) - (z - w)),"(t+t)-(t-t)") - define_sfop4(ext09,((x + y) + (z - w)),"(t+t)+(t-t)") - define_sfop4(ext10,((x + y) + (z + w)),"(t+t)+(t+t)") - define_sfop4(ext11,((x + y) * (z - w)),"(t+t)*(t-t)") - define_sfop4(ext12,((x + y) / (z - w)),"(t+t)/(t-t)") - define_sfop4(ext13,((x - y) - (z + w)),"(t-t)-(t+t)") - define_sfop4(ext14,((x - y) + (z + w)),"(t-t)+(t+t)") - define_sfop4(ext15,((x - y) * (z + w)),"(t-t)*(t+t)") - define_sfop4(ext16,((x - y) / (z + w)),"(t-t)/(t+t)") - define_sfop4(ext17,((x * y) - (z + w)),"(t*t)-(t+t)") - define_sfop4(ext18,((x / y) - (z + w)),"(t/t)-(t+t)") - define_sfop4(ext19,((x * y) + (z + w)),"(t*t)+(t+t)") - define_sfop4(ext20,((x / y) + (z + w)),"(t/t)+(t+t)") - define_sfop4(ext21,((x * y) + (z - w)),"(t*t)+(t-t)") - define_sfop4(ext22,((x / y) + (z - w)),"(t/t)+(t-t)") - define_sfop4(ext23,((x * y) - (z - w)),"(t*t)-(t-t)") - define_sfop4(ext24,((x / y) - (z - w)),"(t/t)-(t-t)") - define_sfop4(ext25,((x + y) * (z * w)),"(t+t)*(t*t)") - define_sfop4(ext26,((x + y) * (z / w)),"(t+t)*(t/t)") - define_sfop4(ext27,((x + y) / (z * w)),"(t+t)/(t*t)") - define_sfop4(ext28,((x + y) / (z / w)),"(t+t)/(t/t)") - define_sfop4(ext29,((x - y) / (z * w)),"(t-t)/(t*t)") - define_sfop4(ext30,((x - y) / (z / w)),"(t-t)/(t/t)") - define_sfop4(ext31,((x - y) * (z * w)),"(t-t)*(t*t)") - define_sfop4(ext32,((x - y) * (z / w)),"(t-t)*(t/t)") - define_sfop4(ext33,((x * y) * (z + w)),"(t*t)*(t+t)") - define_sfop4(ext34,((x / y) * (z + w)),"(t/t)*(t+t)") - define_sfop4(ext35,((x * y) / (z + w)),"(t*t)/(t+t)") - define_sfop4(ext36,((x / y) / (z + w)),"(t/t)/(t+t)") - define_sfop4(ext37,((x * y) / (z - w)),"(t*t)/(t-t)") - define_sfop4(ext38,((x / y) / (z - w)),"(t/t)/(t-t)") - define_sfop4(ext39,((x * y) * (z - w)),"(t*t)*(t-t)") - define_sfop4(ext40,((x * y) / (z * w)),"(t*t)/(t*t)") - define_sfop4(ext41,((x / y) * (z / w)),"(t/t)*(t/t)") - define_sfop4(ext42,((x / y) * (z - w)),"(t/t)*(t-t)") - define_sfop4(ext43,((x * y) * (z * w)),"(t*t)*(t*t)") - define_sfop4(ext44,(x + (y * (z / w))),"t+(t*(t/t))") - define_sfop4(ext45,(x - (y * (z / w))),"t-(t*(t/t))") - define_sfop4(ext46,(x + (y / (z * w))),"t+(t/(t*t))") - define_sfop4(ext47,(x - (y / (z * w))),"t-(t/(t*t))") - define_sfop4(ext48,(((x - y) - z) * w),"((t-t)-t)*t") - define_sfop4(ext49,(((x - y) - z) / w),"((t-t)-t)/t") - define_sfop4(ext50,(((x - y) + z) * w),"((t-t)+t)*t") - define_sfop4(ext51,(((x - y) + z) / w),"((t-t)+t)/t") - define_sfop4(ext52,((x + (y - z)) * w),"(t+(t-t))*t") - define_sfop4(ext53,((x + (y - z)) / w),"(t+(t-t))/t") - define_sfop4(ext54,((x + y) / (z + w)),"(t+t)/(t+t)") - define_sfop4(ext55,((x - y) / (z - w)),"(t-t)/(t-t)") - define_sfop4(ext56,((x + y) * (z + w)),"(t+t)*(t+t)") - define_sfop4(ext57,((x - y) * (z - w)),"(t-t)*(t-t)") - define_sfop4(ext58,((x - y) + (z - w)),"(t-t)+(t-t)") - define_sfop4(ext59,((x - y) - (z - w)),"(t-t)-(t-t)") - define_sfop4(ext60,((x / y) + (z * w)),"(t/t)+(t*t)") - define_sfop4(ext61,(((x * y) * z) / w),"((t*t)*t)/t") - - #undef define_sfop3 - #undef define_sfop4 - - template - class sf3_node exprtk_final : public trinary_node - { - public: - - typedef expression_node* expression_ptr; - - sf3_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1, - expression_ptr branch2) - : trinary_node(opr, branch0, branch1, branch2) - {} - - inline T value() const exprtk_override - { - const T x = trinary_node::branch_[0].first->value(); - const T y = trinary_node::branch_[1].first->value(); - const T z = trinary_node::branch_[2].first->value(); - - return SpecialFunction::process(x, y, z); - } - }; - - template - class sf4_node exprtk_final : public quaternary_node - { - public: - - typedef expression_node* expression_ptr; - - sf4_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1, - expression_ptr branch2, - expression_ptr branch3) - : quaternary_node(opr, branch0, branch1, branch2, branch3) - {} - - inline T value() const exprtk_override - { - const T x = quaternary_node::branch_[0].first->value(); - const T y = quaternary_node::branch_[1].first->value(); - const T z = quaternary_node::branch_[2].first->value(); - const T w = quaternary_node::branch_[3].first->value(); - - return SpecialFunction::process(x, y, z, w); - } - }; - - template - class sf3_var_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - sf3_var_node(const T& v0, const T& v1, const T& v2) - : v0_(v0) - , v1_(v1) - , v2_(v2) - {} - - inline T value() const exprtk_override - { - return SpecialFunction::process(v0_, v1_, v2_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_trinary; - } - - private: - - sf3_var_node(const sf3_var_node&) exprtk_delete; - sf3_var_node& operator=(const sf3_var_node&) exprtk_delete; - - const T& v0_; - const T& v1_; - const T& v2_; - }; - - template - class sf4_var_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3) - : v0_(v0) - , v1_(v1) - , v2_(v2) - , v3_(v3) - {} - - inline T value() const exprtk_override - { - return SpecialFunction::process(v0_, v1_, v2_, v3_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_trinary; - } - - private: - - sf4_var_node(const sf4_var_node&) exprtk_delete; - sf4_var_node& operator=(const sf4_var_node&) exprtk_delete; - - const T& v0_; - const T& v1_; - const T& v2_; - const T& v3_; - }; - - template - class vararg_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - template class Sequence> - explicit vararg_node(const Sequence& arg_list) - : initialised_(false) - { - arg_list_.resize(arg_list.size()); - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (arg_list[i] && arg_list[i]->valid()) - { - construct_branch_pair(arg_list_[i],arg_list[i]); - } - else - { - arg_list_.clear(); - return; - } - } - - initialised_ = (arg_list_.size() == arg_list.size()); - assert(valid()); - } - - inline T value() const exprtk_override - { - return VarArgFunction::process(arg_list_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vararg; - } - - inline bool valid() const exprtk_override - { - return initialised_; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(arg_list_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(arg_list_); - } - - std::size_t size() const - { - return arg_list_.size(); - } - - expression_ptr operator[](const std::size_t& index) const - { - return arg_list_[index].first; - } - - private: - - std::vector arg_list_; - bool initialised_; - }; - - template - class vararg_varnode exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - template class Sequence> - explicit vararg_varnode(const Sequence& arg_list) - : initialised_(false) - { - arg_list_.resize(arg_list.size()); - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (arg_list[i] && arg_list[i]->valid() && is_variable_node(arg_list[i])) - { - variable_node* var_node_ptr = static_cast*>(arg_list[i]); - arg_list_[i] = (&var_node_ptr->ref()); - } - else - { - arg_list_.clear(); - return; - } - } - - initialised_ = (arg_list.size() == arg_list_.size()); - assert(valid()); - } - - inline T value() const exprtk_override - { - return VarArgFunction::process(arg_list_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vararg; - } - - inline bool valid() const exprtk_override - { - return initialised_; - } - - private: - - std::vector arg_list_; - bool initialised_; - }; - - template - class vectorize_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - explicit vectorize_node(const expression_ptr v) - : ivec_ptr_(0) - { - construct_branch_pair(v_, v); - - if (is_ivector_node(v_.first)) - { - ivec_ptr_ = dynamic_cast*>(v_.first); - } - } - - inline T value() const exprtk_override - { - v_.first->value(); - return VecFunction::process(ivec_ptr_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecfunc; - } - - inline bool valid() const exprtk_override - { - return ivec_ptr_ && v_.first && v_.first->valid(); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(v_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(v_); - } - - private: - - vector_interface* ivec_ptr_; - branch_t v_; - }; - - template - class assignment_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , var_node_ptr_(0) - { - if (is_variable_node(branch(0))) - { - var_node_ptr_ = static_cast*>(branch(0)); - } - } - - inline T value() const exprtk_override - { - T& result = var_node_ptr_->ref(); - result = branch(1)->value(); - - return result; - } - - inline bool valid() const exprtk_override - { - return var_node_ptr_ && binary_node::valid(); - } - - private: - - variable_node* var_node_ptr_; - }; - - template - class assignment_vec_elem_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_vec_elem_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec_node_ptr_(0) - { - if (is_vector_elem_node(branch(0))) - { - vec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& result = vec_node_ptr_->ref(); - result = branch(1)->value(); - - return result; - } - - inline bool valid() const exprtk_override - { - return vec_node_ptr_ && binary_node::valid(); - } - - private: - - vector_elem_node* vec_node_ptr_; - }; - - template - class assignment_vec_elem_rtc_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_vec_elem_rtc_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec_node_ptr_(0) - { - if (is_vector_elem_rtc_node(branch(0))) - { - vec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& result = vec_node_ptr_->ref(); - result = branch(1)->value(); - - return result; - } - - inline bool valid() const exprtk_override - { - return vec_node_ptr_ && binary_node::valid(); - } - - private: - - vector_elem_rtc_node* vec_node_ptr_; - }; - - template - class assignment_rebasevec_elem_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using expression_node::branch; - - assignment_rebasevec_elem_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , rbvec_node_ptr_(0) - { - if (is_rebasevector_elem_node(branch(0))) - { - rbvec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& result = rbvec_node_ptr_->ref(); - result = branch(1)->value(); - - return result; - } - - inline bool valid() const exprtk_override - { - return rbvec_node_ptr_ && binary_node::valid(); - } - - private: - - rebasevector_elem_node* rbvec_node_ptr_; - }; - - template - class assignment_rebasevec_elem_rtc_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using expression_node::branch; - - assignment_rebasevec_elem_rtc_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , rbvec_node_ptr_(0) - { - if (is_rebasevector_elem_rtc_node(branch(0))) - { - rbvec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& result = rbvec_node_ptr_->ref(); - result = branch(1)->value(); - - return result; - } - - inline bool valid() const exprtk_override - { - return rbvec_node_ptr_ && binary_node::valid(); - } - - private: - - rebasevector_elem_rtc_node* rbvec_node_ptr_; - }; - - template - class assignment_rebasevec_celem_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_rebasevec_celem_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , rbvec_node_ptr_(0) - { - if (is_rebasevector_celem_node(branch(0))) - { - rbvec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& result = rbvec_node_ptr_->ref(); - result = branch(1)->value(); - - return result; - } - - inline bool valid() const exprtk_override - { - return rbvec_node_ptr_ && binary_node::valid(); - } - - private: - - rebasevector_celem_node* rbvec_node_ptr_; - }; - - template - class assignment_vec_node exprtk_final - : public binary_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - using binary_node::branch; - - assignment_vec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec_node_ptr_(0) - { - if (is_vector_node(branch(0))) - { - vec_node_ptr_ = static_cast*>(branch(0)); - vds() = vec_node_ptr_->vds(); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - const T v = branch(1)->value(); - - T* vec = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec + lud.upper_bound; - - while (vec < upper_bound) - { - #define exprtk_loop(N) \ - vec[N] = v; \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec += lud.batch_size; - } - - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : *vec++ = v; \ - exprtk_fallthrough \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case 1 : *vec++ = v; - } - - #undef exprtk_loop - #undef case_stmt - - return vec_node_ptr_->value(); - } - - vector_node_ptr vec() const exprtk_override - { - return vec_node_ptr_; - } - - vector_node_ptr vec() exprtk_override - { - return vec_node_ptr_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecvalass; - } - - inline bool valid() const exprtk_override - { - return - vec_node_ptr_ && - (vds().size() <= vec_node_ptr_->vec_holder().base_size()) && - binary_node::valid(); - } - - std::size_t size() const exprtk_override - { - return vec_node_ptr_->vec_holder().size(); - } - - std::size_t base_size() const exprtk_override - { - return vec_node_ptr_->vec_holder().base_size(); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - private: - - vector_node* vec_node_ptr_; - vds_t vds_; - }; - - template - class assignment_vecvec_node exprtk_final - : public binary_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - using binary_node::branch; - - assignment_vecvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec0_node_ptr_(0) - , vec1_node_ptr_(0) - , initialised_(false) - , src_is_ivec_(false) - { - if (is_vector_node(branch(0))) - { - vec0_node_ptr_ = static_cast*>(branch(0)); - vds() = vec0_node_ptr_->vds(); - } - - if (is_vector_node(branch(1))) - { - vec1_node_ptr_ = static_cast*>(branch(1)); - vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); - } - else if (is_ivector_node(branch(1))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(1)))) - { - vec1_node_ptr_ = vi->vec(); - - if (!vi->side_effect()) - { - vi->vds() = vds(); - src_is_ivec_ = true; - } - else - vds_t::match_sizes(vds(),vi->vds()); - } - } - - initialised_ = - vec0_node_ptr_ && - vec1_node_ptr_ && - (size() <= base_size()) && - (vds_.size() <= base_size()) && - binary_node::valid(); - - assert(valid()); - } - - inline T value() const exprtk_override - { - branch(1)->value(); - - if (src_is_ivec_) - return vec0_node_ptr_->value(); - - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec0[N] = vec1[N]; \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - switch (lud.remainder) - { - #define case_stmt(N,fall_through) \ - case N : *vec0++ = *vec1++; \ - fall_through \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) - case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) - case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) - case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) - case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) - case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) - #endif - case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) - case_stmt( 1, (void)0;) - } - - #undef exprtk_loop - #undef case_stmt - - return vec0_node_ptr_->value(); - } - - vector_node_ptr vec() exprtk_override - { - return vec0_node_ptr_; - } - - vector_node_ptr vec() const exprtk_override - { - return vec0_node_ptr_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecvecass; - } - - inline bool valid() const exprtk_override - { - return initialised_; - } - - std::size_t size() const exprtk_override - { - return std::min( - vec0_node_ptr_->vec_holder().size(), - vec1_node_ptr_->vec_holder().size()); - } - - std::size_t base_size() const exprtk_override - { - return std::min( - vec0_node_ptr_->vec_holder().base_size(), - vec1_node_ptr_->vec_holder().base_size()); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - private: - - vector_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - bool initialised_; - bool src_is_ivec_; - vds_t vds_; - }; - - template - class assignment_op_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , var_node_ptr_(0) - { - if (is_variable_node(branch(0))) - { - var_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& v = var_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); - - return v; - } - - inline bool valid() const exprtk_override - { - return var_node_ptr_ && binary_node::valid(); - } - - private: - - variable_node* var_node_ptr_; - }; - - template - class assignment_vec_elem_op_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_vec_elem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec_node_ptr_(0) - { - if (is_vector_elem_node(branch(0))) - { - vec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& v = vec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); - - return v; - } - - inline bool valid() const exprtk_override - { - return vec_node_ptr_ && binary_node::valid(); - } - - private: - - vector_elem_node* vec_node_ptr_; - }; - - template - class assignment_vec_elem_op_rtc_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_vec_elem_op_rtc_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec_node_ptr_(0) - { - if (is_vector_elem_rtc_node(branch(0))) - { - vec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& v = vec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); - - return v; - } - - inline bool valid() const exprtk_override - { - return vec_node_ptr_ && binary_node::valid(); - } - - private: - - vector_elem_rtc_node* vec_node_ptr_; - }; - - template - class assignment_vec_celem_op_rtc_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_vec_celem_op_rtc_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec_node_ptr_(0) - { - if (is_vector_celem_rtc_node(branch(0))) - { - vec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& v = vec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); - - return v; - } - - inline bool valid() const exprtk_override - { - return vec_node_ptr_ && binary_node::valid(); - } - - private: - - vector_celem_rtc_node* vec_node_ptr_; - }; - - template - class assignment_rebasevec_elem_op_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_rebasevec_elem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , rbvec_node_ptr_(0) - { - if (is_rebasevector_elem_node(branch(0))) - { - rbvec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); - - return v; - } - - inline bool valid() const exprtk_override - { - return rbvec_node_ptr_ && binary_node::valid(); - } - - private: - - rebasevector_elem_node* rbvec_node_ptr_; - }; - - template - class assignment_rebasevec_celem_op_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_rebasevec_celem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , rbvec_node_ptr_(0) - { - if (is_rebasevector_celem_node(branch(0))) - { - rbvec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); - - return v; - } - - inline bool valid() const exprtk_override - { - return rbvec_node_ptr_ && binary_node::valid(); - } - - private: - - rebasevector_celem_node* rbvec_node_ptr_; - }; - - template - class assignment_rebasevec_elem_op_rtc_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_rebasevec_elem_op_rtc_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , rbvec_node_ptr_(0) - { - if (is_rebasevector_elem_rtc_node(branch(0))) - { - rbvec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); - - return v; - } - - inline bool valid() const exprtk_override - { - return rbvec_node_ptr_ && binary_node::valid(); - } - - private: - - rebasevector_elem_rtc_node* rbvec_node_ptr_; - }; - - template - class assignment_rebasevec_celem_op_rtc_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - assignment_rebasevec_celem_op_rtc_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , rbvec_node_ptr_(0) - { - if (is_rebasevector_celem_rtc_node(branch(0))) - { - rbvec_node_ptr_ = static_cast*>(branch(0)); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,branch(1)->value()); - - return v; - } - - inline bool valid() const exprtk_override - { - return rbvec_node_ptr_ && binary_node::valid(); - } - - private: - - rebasevector_celem_rtc_node* rbvec_node_ptr_; - }; - - template - class assignment_vec_op_node exprtk_final - : public binary_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - using binary_node::branch; - - assignment_vec_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec_node_ptr_(0) - { - if (is_vector_node(branch(0))) - { - vec_node_ptr_ = static_cast*>(branch(0)); - vds() = vec_node_ptr_->vds(); - } - - assert(valid()); - } - - inline T value() const exprtk_override - { - const T v = branch(1)->value(); - - T* vec = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec + lud.upper_bound; - - while (vec < upper_bound) - { - #define exprtk_loop(N) \ - Operation::assign(vec[N],v); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec += lud.batch_size; - } - - switch (lud.remainder) - { - #define case_stmt(N,fall_through) \ - case N : Operation::assign(*vec++,v); \ - fall_through \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) - case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) - case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) - case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) - case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) - case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) - #endif - case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) - case_stmt( 1, (void)0;) - } - - #undef exprtk_loop - #undef case_stmt - - return vec_node_ptr_->value(); - } - - vector_node_ptr vec() const exprtk_override - { - return vec_node_ptr_; - } - - vector_node_ptr vec() exprtk_override - { - return vec_node_ptr_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecopvalass; - } - - inline bool valid() const exprtk_override - { - return - vec_node_ptr_ && - (size() <= base_size()) && - binary_node::valid() ; - } - - std::size_t size() const exprtk_override - { - return vec_node_ptr_->vec_holder().size(); - } - - std::size_t base_size() const exprtk_override - { - return vec_node_ptr_->vec_holder().base_size(); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - bool side_effect() const exprtk_override - { - return true; - } - - private: - - vector_node* vec_node_ptr_; - vds_t vds_; - }; - - template - class assignment_vecvec_op_node exprtk_final - : public binary_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - using binary_node::branch; - - assignment_vecvec_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec0_node_ptr_(0) - , vec1_node_ptr_(0) - , initialised_(false) - { - if (is_vector_node(branch(0))) - { - vec0_node_ptr_ = static_cast*>(branch(0)); - vds() = vec0_node_ptr_->vds(); - } - - if (is_vector_node(branch(1))) - { - vec1_node_ptr_ = static_cast*>(branch(1)); - vec1_node_ptr_->vds() = vds(); - } - else if (is_ivector_node(branch(1))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(1)))) - { - vec1_node_ptr_ = vi->vec(); - vec1_node_ptr_->vds() = vi->vds(); - } - else - vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); - } - - initialised_ = - vec0_node_ptr_ && - vec1_node_ptr_ && - (size() <= base_size()) && - binary_node::valid(); - - assert(valid()); - } - - inline T value() const exprtk_override - { - branch(0)->value(); - branch(1)->value(); - - T* vec0 = vec0_node_ptr_->vds().data(); - const T* vec1 = vec1_node_ptr_->vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec0[N] = Operation::process(vec0[N], vec1[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { - #define case_stmt(N,fall_through) \ - case N : { vec0[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ - fall_through \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) - case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) - case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) - case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) - case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) - case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) - #endif - case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) - case_stmt( 1, (void)0;) - } - - #undef exprtk_loop - #undef case_stmt - - return vec0_node_ptr_->value(); - } - - vector_node_ptr vec() const exprtk_override - { - return vec0_node_ptr_; - } - - vector_node_ptr vec() exprtk_override - { - return vec0_node_ptr_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecopvecass; - } - - inline bool valid() const exprtk_override - { - return initialised_; - } - - std::size_t size() const exprtk_override - { - return std::min( - vec0_node_ptr_->vec_holder().size(), - vec1_node_ptr_->vec_holder().size()); - } - - std::size_t base_size() const exprtk_override - { - return std::min( - vec0_node_ptr_->vec_holder().base_size(), - vec1_node_ptr_->vec_holder().base_size()); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - bool side_effect() const exprtk_override - { - return true; - } - - private: - - vector_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - bool initialised_; - vds_t vds_; - }; - - template - struct memory_context_t - { - typedef vector_node* vector_node_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - - memory_context_t() - : temp_(0) - , temp_vec_node_(0) - {} - - void clear() - { - delete temp_vec_node_; - delete temp_; - } - - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; - }; - - template - inline memory_context_t make_memory_context(vector_holder& vec_holder, - vec_data_store& vds) - { - memory_context_t result_ctxt; - result_ctxt.temp_ = (vec_holder.rebaseable()) ? - new vector_holder(vec_holder,vds) : - new vector_holder(vds) ; - result_ctxt.temp_vec_node_ = new vector_node (vds,result_ctxt.temp_); - return result_ctxt; - } - - template - inline memory_context_t make_memory_context(vector_holder& vec_holder0, - vector_holder& vec_holder1, - vec_data_store& vds) - { - memory_context_t result_ctxt; - - if (!vec_holder0.rebaseable() && !vec_holder1.rebaseable()) - result_ctxt.temp_ = new vector_holder(vds); - else if (vec_holder0.rebaseable() && !vec_holder1.rebaseable()) - result_ctxt.temp_ = new vector_holder(vec_holder0,vds); - else if (!vec_holder0.rebaseable() && vec_holder1.rebaseable()) - result_ctxt.temp_ = new vector_holder(vec_holder1,vds); - else - { - result_ctxt.temp_ = (vec_holder0.base_size() >= vec_holder1.base_size()) ? - new vector_holder(vec_holder0, vds) : - new vector_holder(vec_holder1, vds) ; - } - - result_ctxt.temp_vec_node_ = new vector_node (vds,result_ctxt.temp_); - return result_ctxt; - } - - template - class vec_binop_vecvec_node exprtk_final - : public binary_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; - typedef memory_context_t memory_context; - - using binary_node::branch; - - vec_binop_vecvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec0_node_ptr_(0) - , vec1_node_ptr_(0) - , initialised_(false) - { - bool v0_is_ivec = false; - bool v1_is_ivec = false; - - if (is_vector_node(branch(0))) - { - vec0_node_ptr_ = static_cast(branch(0)); - } - else if (is_ivector_node(branch(0))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(0)))) - { - vec0_node_ptr_ = vi->vec(); - v0_is_ivec = true; - } - } - - if (is_vector_node(branch(1))) - { - vec1_node_ptr_ = static_cast(branch(1)); - } - else if (is_ivector_node(branch(1))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(1)))) - { - vec1_node_ptr_ = vi->vec(); - v1_is_ivec = true; - } - } - - if (vec0_node_ptr_ && vec1_node_ptr_) - { - vector_holder& vec0 = vec0_node_ptr_->vec_holder(); - vector_holder& vec1 = vec1_node_ptr_->vec_holder(); - - if (v0_is_ivec && (vec0.base_size() <= vec1.base_size())) - { - vds_ = vds_t(vec0_node_ptr_->vds()); - } - else if (v1_is_ivec && (vec1.base_size() <= vec0.base_size())) - { - vds_ = vds_t(vec1_node_ptr_->vds()); - } - else - { - vds_ = vds_t(std::min(vec0.base_size(),vec1.base_size())); - } - - memory_context_ = make_memory_context(vec0, vec1, vds()); - - initialised_ = - (size() <= base_size()) && - binary_node::valid(); - } - - assert(valid()); - } - - ~vec_binop_vecvec_node() - { - memory_context_.clear(); - } - - inline T value() const exprtk_override - { - branch(0)->value(); - branch(1)->value(); - - const T* vec0 = vec0_node_ptr_->vds().data(); - const T* vec1 = vec1_node_ptr_->vds().data(); - T* vec2 = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec2 + lud.upper_bound; - - while (vec2 < upper_bound) - { - #define exprtk_loop(N) \ - vec2[N] = Operation::process(vec0[N], vec1[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - vec2 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ - exprtk_fallthrough \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - default: break; - } - - #undef exprtk_loop - #undef case_stmt - - return (vds().data())[0]; - } - - vector_node_ptr vec() const exprtk_override - { - return memory_context_.temp_vec_node_; - } - - vector_node_ptr vec() exprtk_override - { - return memory_context_.temp_vec_node_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecvecarith; - } - - inline bool valid() const exprtk_override - { - return initialised_; - } - - std::size_t size() const exprtk_override - { - return std::min( - vec0_node_ptr_->vec_holder().size(), - vec1_node_ptr_->vec_holder().size()); - } - - std::size_t base_size() const exprtk_override - { - return std::min( - vec0_node_ptr_->vec_holder().base_size(), - vec1_node_ptr_->vec_holder().base_size()); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - private: - - vector_node_ptr vec0_node_ptr_; - vector_node_ptr vec1_node_ptr_; - bool initialised_; - vds_t vds_; - memory_context memory_context_; - }; - - template - class vec_binop_vecval_node exprtk_final - : public binary_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; - typedef memory_context_t memory_context; - - using binary_node::branch; - - vec_binop_vecval_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec0_node_ptr_(0) - { - bool v0_is_ivec = false; - - if (is_vector_node(branch(0))) - { - vec0_node_ptr_ = static_cast(branch(0)); - } - else if (is_ivector_node(branch(0))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(0)))) - { - vec0_node_ptr_ = vi->vec(); - v0_is_ivec = true; - } - } - - if (vec0_node_ptr_) - { - if (v0_is_ivec) - vds() = vec0_node_ptr_->vds(); - else - vds() = vds_t(vec0_node_ptr_->base_size()); - - memory_context_ = make_memory_context(vec0_node_ptr_->vec_holder(), vds()); - } - - assert(valid()); - } - - ~vec_binop_vecval_node() - { - memory_context_.clear(); - } - - inline T value() const exprtk_override - { - branch(0)->value(); - const T v = branch(1)->value(); - - const T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec1[N] = Operation::process(vec0[N], v); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { - #define case_stmt(N,fall_through) \ - case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ - fall_through \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) - case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) - case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) - case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) - case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) - case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) - #endif - case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) - case_stmt( 1, (void)0;) - } - - #undef exprtk_loop - #undef case_stmt - - return (vds().data())[0]; - } - - vector_node_ptr vec() const exprtk_override - { - return memory_context_.temp_vec_node_; - } - - vector_node_ptr vec() exprtk_override - { - return memory_context_.temp_vec_node_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecvalarith; - } - - inline bool valid() const exprtk_override - { - return - vec0_node_ptr_ && - (size() <= base_size()) && - binary_node::valid(); - } - - std::size_t size() const exprtk_override - { - return vec0_node_ptr_->size(); - } - - std::size_t base_size() const exprtk_override - { - return vec0_node_ptr_->vec_holder().base_size(); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - private: - - vector_node_ptr vec0_node_ptr_; - vds_t vds_; - memory_context memory_context_; - }; - - template - class vec_binop_valvec_node exprtk_final - : public binary_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; - typedef memory_context_t memory_context; - - using binary_node::branch; - - vec_binop_valvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , vec1_node_ptr_(0) - { - bool v1_is_ivec = false; - - if (is_vector_node(branch(1))) - { - vec1_node_ptr_ = static_cast(branch(1)); - } - else if (is_ivector_node(branch(1))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(1)))) - { - vec1_node_ptr_ = vi->vec(); - v1_is_ivec = true; - } - } - - if (vec1_node_ptr_) - { - if (v1_is_ivec) - vds() = vec1_node_ptr_->vds(); - else - vds() = vds_t(vec1_node_ptr_->base_size()); - - memory_context_ = make_memory_context(vec1_node_ptr_->vec_holder(), vds()); - } - - assert(valid()); - } - - ~vec_binop_valvec_node() - { - memory_context_.clear(); - } - - inline T value() const exprtk_override - { - const T v = branch(0)->value(); - branch(1)->value(); - - T* vec0 = vds().data(); - const T* vec1 = vec1_node_ptr_->vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec0[N] = Operation::process(v, vec1[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { - #define case_stmt(N,fall_through) \ - case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \ - fall_through \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) - case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) - case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) - case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) - case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) - case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) - #endif - case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) - case_stmt( 1, (void)0;) - } - - #undef exprtk_loop - #undef case_stmt - - return (vds().data())[0]; - } - - vector_node_ptr vec() const exprtk_override - { - return memory_context_.temp_vec_node_; - } - - vector_node_ptr vec() exprtk_override - { - return memory_context_.temp_vec_node_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecvalarith; - } - - inline bool valid() const exprtk_override - { - return - vec1_node_ptr_ && - (size() <= base_size()) && - (vds_.size() <= base_size()) && - binary_node::valid(); - } - - std::size_t size() const exprtk_override - { - return vec1_node_ptr_->vec_holder().size(); - } - - std::size_t base_size() const exprtk_override - { - return vec1_node_ptr_->vec_holder().base_size(); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - private: - - vector_node_ptr vec1_node_ptr_; - vds_t vds_; - memory_context memory_context_; - }; - - template - class unary_vector_node exprtk_final - : public unary_node - , public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; - typedef memory_context_t memory_context; - - using expression_node::branch; - - unary_vector_node(const operator_type& opr, expression_ptr branch0) - : unary_node(opr, branch0) - , vec0_node_ptr_(0) - { - bool vec0_is_ivec = false; - - if (is_vector_node(branch(0))) - { - vec0_node_ptr_ = static_cast(branch(0)); - } - else if (is_ivector_node(branch(0))) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(branch(0)))) - { - vec0_node_ptr_ = vi->vec(); - vec0_is_ivec = true; - } - } - - if (vec0_node_ptr_) - { - if (vec0_is_ivec) - vds_ = vec0_node_ptr_->vds(); - else - vds_ = vds_t(vec0_node_ptr_->base_size()); - - memory_context_ = make_memory_context(vec0_node_ptr_->vec_holder(), vds()); - } - - assert(valid()); - } - - ~unary_vector_node() - { - memory_context_.clear(); - } - - inline T value() const exprtk_override - { - branch()->value(); - - const T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { - #define exprtk_loop(N) \ - vec1[N] = Operation::process(vec0[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { - #define case_stmt(N) \ - case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ - exprtk_fallthrough \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) - #endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - default: break; - } - - #undef exprtk_loop - #undef case_stmt - - return (vds().data())[0]; - } - - vector_node_ptr vec() const exprtk_override - { - return memory_context_.temp_vec_node_; - } - - vector_node_ptr vec() exprtk_override - { - return memory_context_.temp_vec_node_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecunaryop; - } - - inline bool valid() const exprtk_override - { - return vec0_node_ptr_ && unary_node::valid(); - } - - std::size_t size() const exprtk_override - { - return vec0_node_ptr_->vec_holder().size(); - } - - std::size_t base_size() const exprtk_override - { - return vec0_node_ptr_->vec_holder().base_size(); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - private: - - vector_node_ptr vec0_node_ptr_; - vds_t vds_; - memory_context memory_context_; - }; - - template - class conditional_vector_node exprtk_final - : public expression_node - , public vector_interface - { - public: - - typedef expression_node * expression_ptr; - typedef vector_interface* vec_interface_ptr; - typedef vector_node * vector_node_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; - typedef memory_context_t memory_context; - typedef std::pair branch_t; - - conditional_vector_node(expression_ptr condition, - expression_ptr consequent, - expression_ptr alternative) - : consequent_node_ptr_ (0) - , alternative_node_ptr_(0) - , temp_vec_node_ (0) - , temp_ (0) - , result_vec_size_ (0) - , initialised_ (false) - { - construct_branch_pair(condition_ , condition ); - construct_branch_pair(consequent_ , consequent ); - construct_branch_pair(alternative_, alternative); - - if (details::is_ivector_node(consequent_.first)) - { - vec_interface_ptr ivec_ptr = dynamic_cast(consequent_.first); - - if (0 != ivec_ptr) - { - consequent_node_ptr_ = ivec_ptr->vec(); - } - } - - if (details::is_ivector_node(alternative_.first)) - { - vec_interface_ptr ivec_ptr = dynamic_cast(alternative_.first); - - if (0 != ivec_ptr) - { - alternative_node_ptr_ = ivec_ptr->vec(); - } - } - - if (consequent_node_ptr_ && alternative_node_ptr_) - { - const std::size_t vec_size = - std::max(consequent_node_ptr_ ->vec_holder().base_size(), - alternative_node_ptr_->vec_holder().base_size()); - - vds_ = vds_t(vec_size); - memory_context_ = make_memory_context( - consequent_node_ptr_ ->vec_holder(), - alternative_node_ptr_->vec_holder(), - vds()); - - initialised_ = (vec_size > 0); - } - - assert(initialised_); - } - - ~conditional_vector_node() - { - memory_context_.clear(); - } - - inline T value() const exprtk_override - { - T result = T(0); - T* source_vector = 0; - T* result_vector = vds().data(); - - if (is_true(condition_)) - { - result = consequent_.first->value(); - source_vector = consequent_node_ptr_->vds().data(); - result_vec_size_ = consequent_node_ptr_->size(); - } - else - { - result = alternative_.first->value(); - source_vector = alternative_node_ptr_->vds().data(); - result_vec_size_ = alternative_node_ptr_->size(); - } - - for (std::size_t i = 0; i < result_vec_size_; ++i) - { - result_vector[i] = source_vector[i]; - } - - return result; - } - - vector_node_ptr vec() const exprtk_override - { - return memory_context_.temp_vec_node_; - } - - vector_node_ptr vec() exprtk_override - { - return memory_context_.temp_vec_node_; - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vecondition; - } - - inline bool valid() const exprtk_override - { - return - initialised_ && - condition_ .first && condition_ .first->valid() && - consequent_ .first && consequent_ .first->valid() && - alternative_.first && alternative_.first->valid() && - size() <= base_size(); - } - - std::size_t size() const exprtk_override - { - return result_vec_size_; - } - - std::size_t base_size() const exprtk_override - { - return std::min( - consequent_node_ptr_ ->vec_holder().base_size(), - alternative_node_ptr_->vec_holder().base_size()); - } - - vds_t& vds() exprtk_override - { - return vds_; - } - - const vds_t& vds() const exprtk_override - { - return vds_; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(condition_ , node_delete_list); - expression_node::ndb_t::collect(consequent_ , node_delete_list); - expression_node::ndb_t::collect(alternative_ , node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth - (condition_, consequent_, alternative_); - } - - private: - - branch_t condition_; - branch_t consequent_; - branch_t alternative_; - vector_node_ptr consequent_node_ptr_; - vector_node_ptr alternative_node_ptr_; - vector_node_ptr temp_vec_node_; - vector_holder_ptr temp_; - vds_t vds_; - mutable std::size_t result_vec_size_; - bool initialised_; - memory_context memory_context_; - }; - - template - class scand_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - scand_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - { - assert(binary_node::valid()); - } - - inline T value() const exprtk_override - { - return ( - std::not_equal_to() - (T(0),branch(0)->value()) && - std::not_equal_to() - (T(0),branch(1)->value()) - ) ? T(1) : T(0); - } - }; - - template - class scor_node exprtk_final : public binary_node - { - public: - - typedef expression_node* expression_ptr; - using binary_node::branch; - - scor_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - { - assert(binary_node::valid()); - } - - inline T value() const exprtk_override - { - return ( - std::not_equal_to() - (T(0),branch(0)->value()) || - std::not_equal_to() - (T(0),branch(1)->value()) - ) ? T(1) : T(0); - } - }; - - template - class function_N_node exprtk_final : public expression_node - { - public: - - // Function of N parameters. - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef IFunction ifunction; - - explicit function_N_node(ifunction* func) - : function_((N == func->param_count) ? func : reinterpret_cast(0)) - , parameter_count_(func->param_count) - , initialised_(false) - {} - - template - bool init_branches(expression_ptr (&b)[NumBranches]) - { - // Needed for incompetent and broken msvc compiler versions - #ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable: 4127) - #endif - - if (N != NumBranches) - { - return false; - } - - for (std::size_t i = 0; i < NumBranches; ++i) - { - if (b[i] && b[i]->valid()) - branch_[i] = std::make_pair(b[i],branch_deletable(b[i])); - else - return false; - } - - initialised_ = function_; - assert(valid()); - return initialised_; - - #ifdef _MSC_VER - #pragma warning(pop) - #endif - } - - inline bool operator <(const function_N_node& fn) const - { - return this < (&fn); - } - - inline T value() const exprtk_override - { - // Needed for incompetent and broken msvc compiler versions - #ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable: 4127) - #endif - - T v[N]; - evaluate_branches::execute(v,branch_); - return invoke::execute(*function_,v); - - #ifdef _MSC_VER - #pragma warning(pop) - #endif - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_function; - } - - inline bool valid() const exprtk_override - { - return initialised_; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::template compute_node_depth(branch_); - } - - template - struct evaluate_branches - { - static inline void execute(T_ (&v)[BranchCount], const branch_t (&b)[BranchCount]) - { - for (std::size_t i = 0; i < BranchCount; ++i) - { - v[i] = b[i].first->value(); - } - } - }; - - template - struct evaluate_branches - { - static inline void execute(T_ (&v)[6], const branch_t (&b)[6]) - { - v[0] = b[0].first->value(); - v[1] = b[1].first->value(); - v[2] = b[2].first->value(); - v[3] = b[3].first->value(); - v[4] = b[4].first->value(); - v[5] = b[5].first->value(); - } - }; - - template - struct evaluate_branches - { - static inline void execute(T_ (&v)[5], const branch_t (&b)[5]) - { - v[0] = b[0].first->value(); - v[1] = b[1].first->value(); - v[2] = b[2].first->value(); - v[3] = b[3].first->value(); - v[4] = b[4].first->value(); - } - }; - - template - struct evaluate_branches - { - static inline void execute(T_ (&v)[4], const branch_t (&b)[4]) - { - v[0] = b[0].first->value(); - v[1] = b[1].first->value(); - v[2] = b[2].first->value(); - v[3] = b[3].first->value(); - } - }; - - template - struct evaluate_branches - { - static inline void execute(T_ (&v)[3], const branch_t (&b)[3]) - { - v[0] = b[0].first->value(); - v[1] = b[1].first->value(); - v[2] = b[2].first->value(); - } - }; - - template - struct evaluate_branches - { - static inline void execute(T_ (&v)[2], const branch_t (&b)[2]) - { - v[0] = b[0].first->value(); - v[1] = b[1].first->value(); - } - }; - - template - struct evaluate_branches - { - static inline void execute(T_ (&v)[1], const branch_t (&b)[1]) - { - v[0] = b[0].first->value(); - } - }; - - template - struct invoke { static inline T execute(ifunction&, branch_t (&)[ParamCount]) { return std::numeric_limits::quiet_NaN(); } }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[20]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18],v[19]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[19]) - { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[18]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[17]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[16]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[15]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[14]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[13]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[12]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[11]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[10]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[9]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[8]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[7]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[6]) - { return f(v[0], v[1], v[2], v[3], v[4], v[5]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[5]) - { return f(v[0], v[1], v[2], v[3], v[4]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[4]) - { return f(v[0], v[1], v[2], v[3]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[3]) - { return f(v[0], v[1], v[2]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[2]) - { return f(v[0], v[1]); } - }; - - template - struct invoke - { - static inline T_ execute(ifunction& f, T_ (&v)[1]) - { return f(v[0]); } - }; - - private: - - ifunction* function_; - std::size_t parameter_count_; - branch_t branch_[N]; - bool initialised_; - }; - - template - class function_N_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef IFunction ifunction; - - explicit function_N_node(ifunction* func) - : function_((0 == func->param_count) ? func : reinterpret_cast(0)) - { - assert(valid()); - } - - inline bool operator <(const function_N_node& fn) const - { - return this < (&fn); - } - - inline T value() const exprtk_override - { - return (*function_)(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_function; - } - - inline bool valid() const exprtk_override - { - return function_; - } - - private: - - ifunction* function_; - }; - - template - class vararg_function_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vararg_function_node(VarArgFunction* func, - const std::vector& arg_list) - : function_(func) - , arg_list_(arg_list) - { - value_list_.resize(arg_list.size(),std::numeric_limits::quiet_NaN()); - assert(valid()); - } - - inline bool operator <(const vararg_function_node& fn) const - { - return this < (&fn); - } - - inline T value() const exprtk_override - { - populate_value_list(); - return (*function_)(value_list_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_vafunction; - } - - inline bool valid() const exprtk_override - { - return function_; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - for (std::size_t i = 0; i < arg_list_.size(); ++i) - { - if (arg_list_[i] && !details::is_variable_node(arg_list_[i])) - { - node_delete_list.push_back(&arg_list_[i]); - } - } - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(arg_list_); - } - - private: - - inline void populate_value_list() const - { - for (std::size_t i = 0; i < arg_list_.size(); ++i) - { - value_list_[i] = arg_list_[i]->value(); - } - } - - VarArgFunction* function_; - std::vector arg_list_; - mutable std::vector value_list_; - }; - - template - class generic_function_node : public expression_node - { - public: - - typedef type_store type_store_t; - typedef expression_node* expression_ptr; - typedef variable_node variable_node_t; - typedef vector_node vector_node_t; - typedef variable_node_t* variable_node_ptr_t; - typedef vector_node_t* vector_node_ptr_t; - typedef range_interface range_interface_t; - typedef range_data_type range_data_type_t; - typedef typename range_interface::range_t range_t; - - typedef std::pair branch_t; - typedef vector_holder* vh_t; - typedef vector_view* vecview_t; - - typedef std::vector tmp_vs_t; - typedef std::vector typestore_list_t; - typedef std::vector range_list_t; - - explicit generic_function_node(const std::vector& arg_list, - GenericFunction* func = reinterpret_cast(0)) - : function_(func) - , arg_list_(arg_list) - {} - - virtual ~generic_function_node() - { - for (std::size_t i = 0; i < vv_list_.size(); ++i) - { - vecview_t& vv = vv_list_[i]; - if (vv && typestore_list_[i].vec_data) - { - vv->remove_ref(&typestore_list_[i].vec_data); - typestore_list_[i].vec_data = 0; - } - } - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override exprtk_final - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - virtual bool init_branches() - { - expr_as_vec1_store_.resize(arg_list_.size(), T(0) ); - typestore_list_ .resize(arg_list_.size(), type_store_t() ); - range_list_ .resize(arg_list_.size(), range_data_type_t()); - branch_ .resize(arg_list_.size(), branch_t(reinterpret_cast(0),false)); - vv_list_ .resize(arg_list_.size(), vecview_t(0)); - - for (std::size_t i = 0; i < arg_list_.size(); ++i) - { - type_store_t& ts = typestore_list_[i]; - - if (0 == arg_list_[i]) - return false; - else if (is_ivector_node(arg_list_[i])) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 == (vi = dynamic_cast*>(arg_list_[i]))) - return false; - - ts.size = vi->size(); - ts.data = vi->vds().data(); - ts.type = type_store_t::e_vector; - - if ( - vi->vec()->vec_holder().rebaseable() && - vi->vec()->vec_holder().rebaseable_instance() - ) - { - vv_list_[i] = vi->vec()->vec_holder().rebaseable_instance(); - vv_list_[i]->set_ref(&ts.vec_data); - } - } - #ifndef exprtk_disable_string_capabilities - else if (is_generally_string_node(arg_list_[i])) - { - string_base_node* sbn = reinterpret_cast*>(0); - - if (0 == (sbn = dynamic_cast*>(arg_list_[i]))) - return false; - - ts.size = sbn->size(); - ts.data = reinterpret_cast(const_cast(sbn->base())); - ts.type = type_store_t::e_string; - - range_list_[i].data = ts.data; - range_list_[i].size = ts.size; - range_list_[i].type_size = sizeof(char); - range_list_[i].str_node = sbn; - - range_interface_t* ri = reinterpret_cast(0); - - if (0 == (ri = dynamic_cast(arg_list_[i]))) - return false; - - const range_t& rp = ri->range_ref(); - - if ( - rp.const_range() && - is_const_string_range_node(arg_list_[i]) - ) - { - ts.size = rp.const_size(); - ts.data = static_cast(ts.data) + rp.n0_c.second; - range_list_[i].range = reinterpret_cast(0); - } - else - { - range_list_[i].range = &(ri->range_ref()); - range_param_list_.push_back(i); - } - } - #endif - else if (is_variable_node(arg_list_[i])) - { - variable_node_ptr_t var = variable_node_ptr_t(0); - - if (0 == (var = dynamic_cast(arg_list_[i]))) - return false; - - ts.size = 1; - ts.data = &var->ref(); - ts.type = type_store_t::e_scalar; - } - else - { - ts.size = 1; - ts.data = reinterpret_cast(&expr_as_vec1_store_[i]); - ts.type = type_store_t::e_scalar; - } - - branch_[i] = std::make_pair(arg_list_[i],branch_deletable(arg_list_[i])); - } - - return true; - } - - inline bool operator <(const generic_function_node& fn) const - { - return this < (&fn); - } - - inline T value() const exprtk_override - { - if (populate_value_list()) - { - typedef typename GenericFunction::parameter_list_t parameter_list_t; - - return (*function_)(parameter_list_t(typestore_list_)); - } - - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_genfunction; - } - - inline bool valid() const exprtk_override - { - return function_; - } - - protected: - - inline virtual bool populate_value_list() const - { - for (std::size_t i = 0; i < branch_.size(); ++i) - { - expr_as_vec1_store_[i] = branch_[i].first->value(); - } - - if (!range_param_list_.empty()) - { - assert(range_param_list_.size() <= branch_.size()); - - for (std::size_t i = 0; i < range_param_list_.size(); ++i) - { - const std::size_t index = range_param_list_[i]; - range_data_type_t& rdt = range_list_[index]; - - const range_t& rp = (*rdt.range); - std::size_t r0 = 0; - std::size_t r1 = 0; - - const std::size_t data_size = - #ifndef exprtk_disable_string_capabilities - rdt.str_node ? rdt.str_node->size() : rdt.size; - #else - rdt.size; - #endif - - if (!rp(r0, r1, data_size)) - { - return false; - } - - type_store_t& ts = typestore_list_[index]; - - ts.size = rp.cache_size(); - #ifndef exprtk_disable_string_capabilities - if (ts.type == type_store_t::e_string) - ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; - else - #endif - ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); - } - } - - return true; - } - - GenericFunction* function_; - mutable typestore_list_t typestore_list_; - - private: - - std::vector arg_list_; - std::vector branch_; - std::vector vv_list_; - mutable tmp_vs_t expr_as_vec1_store_; - mutable range_list_t range_list_; - std::vector range_param_list_; - }; - - #ifndef exprtk_disable_string_capabilities - template - class string_function_node : public generic_function_node - , public string_base_node - , public range_interface - { - public: - - typedef generic_function_node gen_function_t; - typedef typename range_interface::range_t range_t; - - string_function_node(StringFunction* func, - const std::vector& arg_list) - : gen_function_t(arg_list,func) - { - range_.n0_c = std::make_pair(true,0); - range_.n1_c = std::make_pair(true,0); - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; - assert(valid()); - } - - inline bool operator <(const string_function_node& fn) const - { - return this < (&fn); - } - - inline T value() const exprtk_override - { - if (gen_function_t::populate_value_list()) - { - typedef typename StringFunction::parameter_list_t parameter_list_t; - - const T result = - (*gen_function_t::function_) - ( - ret_string_, - parameter_list_t(gen_function_t::typestore_list_) - ); - - range_.n1_c.second = ret_string_.size(); - range_.cache.second = range_.n1_c.second; - - return result; - } - - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strfunction; - } - - inline bool valid() const exprtk_override - { - return gen_function_t::function_; - } - - std::string str() const exprtk_override - { - return ret_string_; - } - - char_cptr base() const exprtk_override - { - return &ret_string_[0]; - } - - std::size_t size() const exprtk_override - { - return ret_string_.size(); - } - - range_t& range_ref() exprtk_override - { - return range_; - } - - const range_t& range_ref() const exprtk_override - { - return range_; - } - - protected: - - mutable range_t range_; - mutable std::string ret_string_; - }; - #endif - - template - class multimode_genfunction_node : public generic_function_node - { - public: - - typedef generic_function_node gen_function_t; - typedef typename gen_function_t::range_t range_t; - - multimode_genfunction_node(GenericFunction* func, - const std::size_t& param_seq_index, - const std::vector& arg_list) - : gen_function_t(arg_list,func) - , param_seq_index_(param_seq_index) - {} - - inline T value() const exprtk_override - { - assert(gen_function_t::valid()); - - if (gen_function_t::populate_value_list()) - { - typedef typename GenericFunction::parameter_list_t parameter_list_t; - - return - (*gen_function_t::function_) - ( - param_seq_index_, - parameter_list_t(gen_function_t::typestore_list_) - ); - } - - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override exprtk_final - { - return expression_node::e_genfunction; - } - - private: - - std::size_t param_seq_index_; - }; - - #ifndef exprtk_disable_string_capabilities - template - class multimode_strfunction_node exprtk_final : public string_function_node - { - public: - - typedef string_function_node str_function_t; - typedef typename str_function_t::range_t range_t; - - multimode_strfunction_node(StringFunction* func, - const std::size_t& param_seq_index, - const std::vector& arg_list) - : str_function_t(func,arg_list) - , param_seq_index_(param_seq_index) - {} - - inline T value() const exprtk_override - { - if (str_function_t::populate_value_list()) - { - typedef typename StringFunction::parameter_list_t parameter_list_t; - - const T result = - (*str_function_t::function_) - ( - param_seq_index_, - str_function_t::ret_string_, - parameter_list_t(str_function_t::typestore_list_) - ); - - str_function_t::range_.n1_c.second = str_function_t::ret_string_.size(); - str_function_t::range_.cache.second = str_function_t::range_.n1_c.second; - - return result; - } - - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_strfunction; - } - - private: - - const std::size_t param_seq_index_; - }; - #endif - - class return_exception {}; - - template - class null_igenfunc - { - public: - - virtual ~null_igenfunc() - {} - - typedef type_store generic_type; - typedef typename generic_type::parameter_list parameter_list_t; - - inline virtual T operator() (parameter_list_t) - { - return std::numeric_limits::quiet_NaN(); - } - }; - - #ifndef exprtk_disable_return_statement - template - class return_node exprtk_final : public generic_function_node > - { - public: - - typedef results_context results_context_t; - typedef null_igenfunc igeneric_function_t; - typedef igeneric_function_t* igeneric_function_ptr; - typedef generic_function_node gen_function_t; - - return_node(const std::vector& arg_list, - results_context_t& rc) - : gen_function_t (arg_list) - , results_context_(&rc) - { - assert(valid()); - } - - inline T value() const exprtk_override - { - if (gen_function_t::populate_value_list()) - { - typedef typename type_store::parameter_list parameter_list_t; - - results_context_-> - assign(parameter_list_t(gen_function_t::typestore_list_)); - - throw return_exception(); - } - - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_return; - } - - inline bool valid() const exprtk_override - { - return results_context_; - } - - private: - - results_context_t* results_context_; - }; - - template - class return_envelope_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef results_context results_context_t; - typedef std::pair branch_t; - - return_envelope_node(expression_ptr body, results_context_t& rc) - : results_context_(&rc ) - , return_invoked_ (false) - { - construct_branch_pair(body_, body); - assert(valid()); - } - - inline T value() const exprtk_override - { - try - { - return_invoked_ = false; - results_context_->clear(); - - return body_.first->value(); - } - catch(const return_exception&) - { - return_invoked_ = true; - - return std::numeric_limits::quiet_NaN(); - } - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_retenv; - } - - inline bool valid() const exprtk_override - { - return results_context_ && body_.first; - } - - inline bool* retinvk_ptr() - { - return &return_invoked_; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(body_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(body_); - } - - private: - - results_context_t* results_context_; - mutable bool return_invoked_; - branch_t body_; - }; - #endif - - #define exprtk_define_unary_op(OpName) \ - template \ - struct OpName##_op \ - { \ - typedef typename functor_t::Type Type; \ - typedef typename expression_node::node_type node_t; \ - \ - static inline T process(Type v) \ - { \ - return numeric:: OpName (v); \ - } \ - \ - static inline node_t type() \ - { \ - return expression_node::e_##OpName; \ - } \ - \ - static inline details::operator_type operation() \ - { \ - return details::e_##OpName; \ - } \ - }; \ - - exprtk_define_unary_op(abs ) - exprtk_define_unary_op(acos ) - exprtk_define_unary_op(acosh) - exprtk_define_unary_op(asin ) - exprtk_define_unary_op(asinh) - exprtk_define_unary_op(atan ) - exprtk_define_unary_op(atanh) - exprtk_define_unary_op(ceil ) - exprtk_define_unary_op(cos ) - exprtk_define_unary_op(cosh ) - exprtk_define_unary_op(cot ) - exprtk_define_unary_op(csc ) - exprtk_define_unary_op(d2g ) - exprtk_define_unary_op(d2r ) - exprtk_define_unary_op(erf ) - exprtk_define_unary_op(erfc ) - exprtk_define_unary_op(exp ) - exprtk_define_unary_op(expm1) - exprtk_define_unary_op(floor) - exprtk_define_unary_op(frac ) - exprtk_define_unary_op(g2d ) - exprtk_define_unary_op(log ) - exprtk_define_unary_op(log10) - exprtk_define_unary_op(log2 ) - exprtk_define_unary_op(log1p) - exprtk_define_unary_op(ncdf ) - exprtk_define_unary_op(neg ) - exprtk_define_unary_op(notl ) - exprtk_define_unary_op(pos ) - exprtk_define_unary_op(r2d ) - exprtk_define_unary_op(round) - exprtk_define_unary_op(sec ) - exprtk_define_unary_op(sgn ) - exprtk_define_unary_op(sin ) - exprtk_define_unary_op(sinc ) - exprtk_define_unary_op(sinh ) - exprtk_define_unary_op(sqrt ) - exprtk_define_unary_op(tan ) - exprtk_define_unary_op(tanh ) - exprtk_define_unary_op(trunc) - #undef exprtk_define_unary_op - - template - struct opr_base - { - typedef typename details::functor_t::Type Type; - typedef typename details::functor_t::RefType RefType; - typedef typename details::functor_t functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; - }; - - template - struct add_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - - static inline T process(Type t1, Type t2) { return t1 + t2; } - static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; } - static inline void assign(RefType t1, Type t2) { t1 += t2; } - static inline typename expression_node::node_type type() { return expression_node::e_add; } - static inline details::operator_type operation() { return details::e_add; } - }; - - template - struct mul_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - - static inline T process(Type t1, Type t2) { return t1 * t2; } - static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; } - static inline void assign(RefType t1, Type t2) { t1 *= t2; } - static inline typename expression_node::node_type type() { return expression_node::e_mul; } - static inline details::operator_type operation() { return details::e_mul; } - }; - - template - struct sub_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - - static inline T process(Type t1, Type t2) { return t1 - t2; } - static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; } - static inline void assign(RefType t1, Type t2) { t1 -= t2; } - static inline typename expression_node::node_type type() { return expression_node::e_sub; } - static inline details::operator_type operation() { return details::e_sub; } - }; - - template - struct div_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - - static inline T process(Type t1, Type t2) { return t1 / t2; } - static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; } - static inline void assign(RefType t1, Type t2) { t1 /= t2; } - static inline typename expression_node::node_type type() { return expression_node::e_div; } - static inline details::operator_type operation() { return details::e_div; } - }; - - template - struct mod_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - - static inline T process(Type t1, Type t2) { return numeric::modulus(t1,t2); } - static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus(t1,t2); } - static inline typename expression_node::node_type type() { return expression_node::e_mod; } - static inline details::operator_type operation() { return details::e_mod; } - }; - - template - struct pow_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - - static inline T process(Type t1, Type t2) { return numeric::pow(t1,t2); } - static inline void assign(RefType t1, Type t2) { t1 = numeric::pow(t1,t2); } - static inline typename expression_node::node_type type() { return expression_node::e_pow; } - static inline details::operator_type operation() { return details::e_pow; } - }; - - template - struct lt_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return ((t1 < t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_lt; } - static inline details::operator_type operation() { return details::e_lt; } - }; - - template - struct lte_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return ((t1 <= t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_lte; } - static inline details::operator_type operation() { return details::e_lte; } - }; - - template - struct gt_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return ((t1 > t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_gt; } - static inline details::operator_type operation() { return details::e_gt; } - }; - - template - struct gte_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return ((t1 >= t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_gte; } - static inline details::operator_type operation() { return details::e_gte; } - }; - - template - struct eq_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return (std::equal_to()(t1,t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_eq; } - static inline details::operator_type operation() { return details::e_eq; } - }; - - template - struct equal_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return numeric::equal(t1,t2); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_eq; } - static inline details::operator_type operation() { return details::e_equal; } - }; - - template - struct ne_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return (std::not_equal_to()(t1,t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_ne; } - static inline details::operator_type operation() { return details::e_ne; } - }; - - template - struct and_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); } - static inline typename expression_node::node_type type() { return expression_node::e_and; } - static inline details::operator_type operation() { return details::e_and; } - }; - - template - struct nand_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); } - static inline typename expression_node::node_type type() { return expression_node::e_nand; } - static inline details::operator_type operation() { return details::e_nand; } - }; - - template - struct or_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); } - static inline typename expression_node::node_type type() { return expression_node::e_or; } - static inline details::operator_type operation() { return details::e_or; } - }; - - template - struct nor_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); } - static inline typename expression_node::node_type type() { return expression_node::e_nor; } - static inline details::operator_type operation() { return details::e_nor; } - }; - - template - struct xor_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return numeric::xor_opr(t1,t2); } - static inline typename expression_node::node_type type() { return expression_node::e_nor; } - static inline details::operator_type operation() { return details::e_xor; } - }; - - template - struct xnor_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(Type t1, Type t2) { return numeric::xnor_opr(t1,t2); } - static inline typename expression_node::node_type type() { return expression_node::e_nor; } - static inline details::operator_type operation() { return details::e_xnor; } - }; - - template - struct in_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } - static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_in; } - static inline details::operator_type operation() { return details::e_in; } - }; - - template - struct like_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } - static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_like; } - static inline details::operator_type operation() { return details::e_like; } - }; - - template - struct ilike_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } - static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_ilike; } - static inline details::operator_type operation() { return details::e_ilike; } - }; - - template - struct inrange_op : public opr_base - { - typedef typename opr_base::Type Type; - - static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } - static inline T process(const std::string& t0, const std::string& t1, const std::string& t2) - { - return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); - } - static inline typename expression_node::node_type type() { return expression_node::e_inranges; } - static inline details::operator_type operation() { return details::e_inrange; } - }; - - template - inline T value(details::expression_node* n) - { - return n->value(); - } - - template - inline T value(std::pair*,bool> n) - { - return n.first->value(); - } - - template - inline T value(const T* t) - { - return (*t); - } - - template - inline T value(const T& t) - { - return t; - } - - template - struct vararg_add_op exprtk_final : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 0 : return T(0); - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - default : - { - T result = T(0); - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - result += value(arg_list[i]); - } - - return result; - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return value(arg_list[0]); - } - - template - static inline T process_2(const Sequence& arg_list) - { - return value(arg_list[0]) + value(arg_list[1]); - } - - template - static inline T process_3(const Sequence& arg_list) - { - return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]) ; - } - - template - static inline T process_4(const Sequence& arg_list) - { - return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]) + value(arg_list[3]) ; - } - - template - static inline T process_5(const Sequence& arg_list) - { - return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]) + value(arg_list[3]) + - value(arg_list[4]) ; - } - }; - - template - struct vararg_mul_op exprtk_final : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 0 : return T(0); - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - default : - { - T result = T(value(arg_list[0])); - - for (std::size_t i = 1; i < arg_list.size(); ++i) - { - result *= value(arg_list[i]); - } - - return result; - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return value(arg_list[0]); - } - - template - static inline T process_2(const Sequence& arg_list) - { - return value(arg_list[0]) * value(arg_list[1]); - } - - template - static inline T process_3(const Sequence& arg_list) - { - return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]) ; - } - - template - static inline T process_4(const Sequence& arg_list) - { - return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]) * value(arg_list[3]) ; - } - - template - static inline T process_5(const Sequence& arg_list) - { - return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]) * value(arg_list[3]) * - value(arg_list[4]) ; - } - }; - - template - struct vararg_avg_op exprtk_final : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 0 : return T(0); - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - default : return vararg_add_op::process(arg_list) / T(arg_list.size()); - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return value(arg_list[0]); - } - - template - static inline T process_2(const Sequence& arg_list) - { - return (value(arg_list[0]) + value(arg_list[1])) / T(2); - } - - template - static inline T process_3(const Sequence& arg_list) - { - return (value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2])) / T(3); - } - - template - static inline T process_4(const Sequence& arg_list) - { - return (value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]) + value(arg_list[3])) / T(4); - } - - template - static inline T process_5(const Sequence& arg_list) - { - return (value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]) + value(arg_list[3]) + - value(arg_list[4])) / T(5); - } - }; - - template - struct vararg_min_op exprtk_final : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 0 : return T(0); - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - default : - { - T result = T(value(arg_list[0])); - - for (std::size_t i = 1; i < arg_list.size(); ++i) - { - const T v = value(arg_list[i]); - - if (v < result) - result = v; - } - - return result; - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return value(arg_list[0]); - } - - template - static inline T process_2(const Sequence& arg_list) - { - return std::min(value(arg_list[0]),value(arg_list[1])); - } - - template - static inline T process_3(const Sequence& arg_list) - { - return std::min(std::min(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); - } - - template - static inline T process_4(const Sequence& arg_list) - { - return std::min( - std::min(value(arg_list[0]), value(arg_list[1])), - std::min(value(arg_list[2]), value(arg_list[3]))); - } - - template - static inline T process_5(const Sequence& arg_list) - { - return std::min( - std::min(std::min(value(arg_list[0]), value(arg_list[1])), - std::min(value(arg_list[2]), value(arg_list[3]))), - value(arg_list[4])); - } - }; - - template - struct vararg_max_op exprtk_final : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 0 : return T(0); - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - default : - { - T result = T(value(arg_list[0])); - - for (std::size_t i = 1; i < arg_list.size(); ++i) - { - const T v = value(arg_list[i]); - - if (v > result) - result = v; - } - - return result; - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return value(arg_list[0]); - } - - template - static inline T process_2(const Sequence& arg_list) - { - return std::max(value(arg_list[0]),value(arg_list[1])); - } - - template - static inline T process_3(const Sequence& arg_list) - { - return std::max(std::max(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); - } - - template - static inline T process_4(const Sequence& arg_list) - { - return std::max( - std::max(value(arg_list[0]), value(arg_list[1])), - std::max(value(arg_list[2]), value(arg_list[3]))); - } - - template - static inline T process_5(const Sequence& arg_list) - { - return std::max( - std::max(std::max(value(arg_list[0]), value(arg_list[1])), - std::max(value(arg_list[2]), value(arg_list[3]))), - value(arg_list[4])); - } - }; - - template - struct vararg_mand_op exprtk_final : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - default : - { - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (std::equal_to()(T(0), value(arg_list[i]))) - return T(0); - } - - return T(1); - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return std::not_equal_to() - (T(0), value(arg_list[0])) ? T(1) : T(0); - } - - template - static inline T process_2(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0), value(arg_list[0])) && - std::not_equal_to()(T(0), value(arg_list[1])) - ) ? T(1) : T(0); - } - - template - static inline T process_3(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0), value(arg_list[0])) && - std::not_equal_to()(T(0), value(arg_list[1])) && - std::not_equal_to()(T(0), value(arg_list[2])) - ) ? T(1) : T(0); - } - - template - static inline T process_4(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0), value(arg_list[0])) && - std::not_equal_to()(T(0), value(arg_list[1])) && - std::not_equal_to()(T(0), value(arg_list[2])) && - std::not_equal_to()(T(0), value(arg_list[3])) - ) ? T(1) : T(0); - } - - template - static inline T process_5(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0), value(arg_list[0])) && - std::not_equal_to()(T(0), value(arg_list[1])) && - std::not_equal_to()(T(0), value(arg_list[2])) && - std::not_equal_to()(T(0), value(arg_list[3])) && - std::not_equal_to()(T(0), value(arg_list[4])) - ) ? T(1) : T(0); - } - }; - - template - struct vararg_mor_op exprtk_final : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - default : - { - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (std::not_equal_to()(T(0), value(arg_list[i]))) - return T(1); - } - - return T(0); - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return std::not_equal_to() - (T(0), value(arg_list[0])) ? T(1) : T(0); - } - - template - static inline T process_2(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0), value(arg_list[0])) || - std::not_equal_to()(T(0), value(arg_list[1])) - ) ? T(1) : T(0); - } - - template - static inline T process_3(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0), value(arg_list[0])) || - std::not_equal_to()(T(0), value(arg_list[1])) || - std::not_equal_to()(T(0), value(arg_list[2])) - ) ? T(1) : T(0); - } - - template - static inline T process_4(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0), value(arg_list[0])) || - std::not_equal_to()(T(0), value(arg_list[1])) || - std::not_equal_to()(T(0), value(arg_list[2])) || - std::not_equal_to()(T(0), value(arg_list[3])) - ) ? T(1) : T(0); - } - - template - static inline T process_5(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0), value(arg_list[0])) || - std::not_equal_to()(T(0), value(arg_list[1])) || - std::not_equal_to()(T(0), value(arg_list[2])) || - std::not_equal_to()(T(0), value(arg_list[3])) || - std::not_equal_to()(T(0), value(arg_list[4])) - ) ? T(1) : T(0); - } - }; - - template - struct vararg_multi_op exprtk_final : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 0 : return std::numeric_limits::quiet_NaN(); - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - case 6 : return process_6(arg_list); - case 7 : return process_7(arg_list); - case 8 : return process_8(arg_list); - default : - { - for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) - { - value(arg_list[i]); - } - return value(arg_list.back()); - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return value(arg_list[0]); - } - - template - static inline T process_2(const Sequence& arg_list) - { - value(arg_list[0]); - return value(arg_list[1]); - } - - template - static inline T process_3(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - return value(arg_list[2]); - } - - template - static inline T process_4(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - return value(arg_list[3]); - } - - template - static inline T process_5(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - value(arg_list[3]); - return value(arg_list[4]); - } - - template - static inline T process_6(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - value(arg_list[3]); - value(arg_list[4]); - return value(arg_list[5]); - } - - template - static inline T process_7(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - value(arg_list[3]); - value(arg_list[4]); - value(arg_list[5]); - return value(arg_list[6]); - } - - template - static inline T process_8(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - value(arg_list[3]); - value(arg_list[4]); - value(arg_list[5]); - value(arg_list[6]); - return value(arg_list[7]); - } - }; - - template - struct vec_add_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->size(); - - loop_unroll::details lud(vec_size); - - if (vec_size <= static_cast(lud.batch_size)) - { - T result = T(0); - int i = 0; - - switch (vec_size) - { - #define case_stmt(N,fall_through) \ - case N : result += vec[i++]; \ - fall_through \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(16, exprtk_fallthrough) case_stmt(15, exprtk_fallthrough) - case_stmt(14, exprtk_fallthrough) case_stmt(13, exprtk_fallthrough) - case_stmt(12, exprtk_fallthrough) case_stmt(11, exprtk_fallthrough) - case_stmt(10, exprtk_fallthrough) case_stmt( 9, exprtk_fallthrough) - case_stmt( 8, exprtk_fallthrough) case_stmt( 7, exprtk_fallthrough) - case_stmt( 6, exprtk_fallthrough) case_stmt( 5, exprtk_fallthrough) - - #endif - case_stmt( 4, exprtk_fallthrough) case_stmt( 3, exprtk_fallthrough) - case_stmt( 2, exprtk_fallthrough) case_stmt( 1, (void)0;) - } - - #undef case_stmt - - return result; - } - - T r[] = { - T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), - T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0) - }; - - const T* upper_bound = vec + lud.upper_bound; - - while (vec < upper_bound) - { - #define exprtk_loop(N) \ - r[N] += vec[N]; \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { - #define case_stmt(N,fall_through) \ - case N : r[0] += vec[i++]; \ - fall_through \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) - case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) - case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) - case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) - case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) - case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) - #endif - case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) - case_stmt( 1, (void)0;) - } - - #undef exprtk_loop - #undef case_stmt - - return (r[ 0] + r[ 1] + r[ 2] + r[ 3]) - #ifndef exprtk_disable_superscalar_unroll - + (r[ 4] + r[ 5] + r[ 6] + r[ 7]) - + (r[ 8] + r[ 9] + r[10] + r[11]) - + (r[12] + r[13] + r[14] + r[15]) - #endif - ; - } - }; - - template - struct vec_mul_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->size(); - - loop_unroll::details lud(vec_size); - - if (vec_size <= static_cast(lud.batch_size)) - { - T result = T(1); - int i = 0; - - switch (vec_size) - { - #define case_stmt(N,fall_through) \ - case N : result *= vec[i++]; \ - fall_through \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(16, exprtk_fallthrough) case_stmt(15, exprtk_fallthrough) - case_stmt(14, exprtk_fallthrough) case_stmt(13, exprtk_fallthrough) - case_stmt(12, exprtk_fallthrough) case_stmt(11, exprtk_fallthrough) - case_stmt(10, exprtk_fallthrough) case_stmt( 9, exprtk_fallthrough) - case_stmt( 8, exprtk_fallthrough) case_stmt( 7, exprtk_fallthrough) - case_stmt( 6, exprtk_fallthrough) case_stmt( 5, exprtk_fallthrough) - #endif - case_stmt( 4, exprtk_fallthrough) case_stmt( 3, exprtk_fallthrough) - case_stmt( 2, exprtk_fallthrough) case_stmt( 1, (void)0;) - } - - #undef case_stmt - - return result; - } - - T r[] = { - T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1), - T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1) - }; - - const T* upper_bound = vec + lud.upper_bound; - - while (vec < upper_bound) - { - #define exprtk_loop(N) \ - r[N] *= vec[N]; \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) - #ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) - #endif - - vec += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { - #define case_stmt(N,fall_through) \ - case N : r[0] *= vec[i++]; \ - fall_through \ - - #ifndef exprtk_disable_superscalar_unroll - case_stmt(15, exprtk_fallthrough) case_stmt(14, exprtk_fallthrough) - case_stmt(13, exprtk_fallthrough) case_stmt(12, exprtk_fallthrough) - case_stmt(11, exprtk_fallthrough) case_stmt(10, exprtk_fallthrough) - case_stmt( 9, exprtk_fallthrough) case_stmt( 8, exprtk_fallthrough) - case_stmt( 7, exprtk_fallthrough) case_stmt( 6, exprtk_fallthrough) - case_stmt( 5, exprtk_fallthrough) case_stmt( 4, exprtk_fallthrough) - #endif - case_stmt( 3, exprtk_fallthrough) case_stmt( 2, exprtk_fallthrough) - case_stmt( 1, (void)0;) - } - - #undef exprtk_loop - #undef case_stmt - - return (r[ 0] * r[ 1] * r[ 2] * r[ 3]) - #ifndef exprtk_disable_superscalar_unroll - * (r[ 4] * r[ 5] * r[ 6] * r[ 7]) - * (r[ 8] * r[ 9] * r[10] * r[11]) - * (r[12] * r[13] * r[14] * r[15]) - #endif - ; - } - }; - - template - struct vec_avg_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const T vec_size = T(v->vec()->size()); - return vec_add_op::process(v) / vec_size; - } - }; - - template - struct vec_min_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->size(); - - T result = vec[0]; - - for (std::size_t i = 1; i < vec_size; ++i) - { - const T v_i = vec[i]; - - if (v_i < result) - result = v_i; - } - - return result; - } - }; - - template - struct vec_max_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->size(); - - T result = vec[0]; - - for (std::size_t i = 1; i < vec_size; ++i) - { - const T v_i = vec[i]; - - if (v_i > result) - result = v_i; - } - - return result; - } - }; - - template - class vov_base_node : public expression_node - { - public: - - virtual ~vov_base_node() - {} - - inline virtual operator_type operation() const - { - return details::e_default; - } - - virtual const T& v0() const = 0; - - virtual const T& v1() const = 0; - }; - - template - class cov_base_node : public expression_node - { - public: - - virtual ~cov_base_node() - {} - - inline virtual operator_type operation() const - { - return details::e_default; - } - - virtual const T c() const = 0; - - virtual const T& v() const = 0; - }; - - template - class voc_base_node : public expression_node - { - public: - - virtual ~voc_base_node() - {} - - inline virtual operator_type operation() const - { - return details::e_default; - } - - virtual const T c() const = 0; - - virtual const T& v() const = 0; - }; - - template - class vob_base_node : public expression_node - { - public: - - virtual ~vob_base_node() - {} - - virtual const T& v() const = 0; - }; - - template - class bov_base_node : public expression_node - { - public: - - virtual ~bov_base_node() - {} - - virtual const T& v() const = 0; - }; - - template - class cob_base_node : public expression_node - { - public: - - virtual ~cob_base_node() - {} - - inline virtual operator_type operation() const - { - return details::e_default; - } - - virtual const T c() const = 0; - - virtual void set_c(const T) = 0; - - virtual expression_node* move_branch(const std::size_t& index) = 0; - }; - - template - class boc_base_node : public expression_node - { - public: - - virtual ~boc_base_node() - {} - - inline virtual operator_type operation() const - { - return details::e_default; - } - - virtual const T c() const = 0; - - virtual void set_c(const T) = 0; - - virtual expression_node* move_branch(const std::size_t& index) = 0; - }; - - template - class uv_base_node : public expression_node - { - public: - - virtual ~uv_base_node() - {} - - inline virtual operator_type operation() const - { - return details::e_default; - } - - virtual const T& v() const = 0; - }; - - template - class sos_base_node : public expression_node - { - public: - - virtual ~sos_base_node() - {} - - inline virtual operator_type operation() const - { - return details::e_default; - } - }; - - template - class sosos_base_node : public expression_node - { - public: - - virtual ~sosos_base_node() - {} - - inline virtual operator_type operation() const - { - return details::e_default; - } - }; - - template - class T0oT1oT2_base_node : public expression_node - { - public: - - virtual ~T0oT1oT2_base_node() - {} - - virtual std::string type_id() const = 0; - }; - - template - class T0oT1oT2oT3_base_node : public expression_node - { - public: - - virtual ~T0oT1oT2oT3_base_node() - {} - - virtual std::string type_id() const = 0; - }; - - template - class unary_variable_node exprtk_final : public uv_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef Operation operation_t; - - explicit unary_variable_node(const T& var) - : v_(var) - {} - - inline T value() const exprtk_override - { - return Operation::process(v_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline const T& v() const exprtk_override - { - return v_; - } - - private: - - unary_variable_node(const unary_variable_node&) exprtk_delete; - unary_variable_node& operator=(const unary_variable_node&) exprtk_delete; - - const T& v_; - }; - - template - class uvouv_node exprtk_final : public expression_node - { - public: - - // UOpr1(v0) Op UOpr2(v1) - typedef typename details::functor_t functor_t; - typedef typename functor_t::bfunc_t bfunc_t; - typedef typename functor_t::ufunc_t ufunc_t; - typedef expression_node* expression_ptr; - - explicit uvouv_node(const T& var0,const T& var1, - ufunc_t uf0, ufunc_t uf1, bfunc_t bf) - : v0_(var0) - , v1_(var1) - , u0_(uf0 ) - , u1_(uf1 ) - , f_ (bf ) - {} - - inline T value() const exprtk_override - { - return f_(u0_(v0_),u1_(v1_)); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_uvouv; - } - - inline const T& v0() - { - return v0_; - } - - inline const T& v1() - { - return v1_; - } - - inline ufunc_t u0() - { - return u0_; - } - - inline ufunc_t u1() - { - return u1_; - } - - inline ufunc_t f() - { - return f_; - } - - private: - - uvouv_node(const uvouv_node&) exprtk_delete; - uvouv_node& operator=(const uvouv_node&) exprtk_delete; - - const T& v0_; - const T& v1_; - const ufunc_t u0_; - const ufunc_t u1_; - const bfunc_t f_; - }; - - template - class unary_branch_node exprtk_final : public expression_node - { - public: - - typedef Operation operation_t; - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - explicit unary_branch_node(expression_ptr branch) - { - construct_branch_pair(branch_, branch); - } - - inline T value() const exprtk_override - { - return Operation::process(branch_.first->value()); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline bool valid() const exprtk_override - { - return branch_.first && branch_.first->valid(); - } - - inline operator_type operation() - { - return Operation::operation(); - } - - inline expression_node* branch(const std::size_t&) const exprtk_override - { - return branch_.first; - } - - inline void release() - { - branch_.second = false; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - unary_branch_node(const unary_branch_node&) exprtk_delete; - unary_branch_node& operator=(const unary_branch_node&) exprtk_delete; - - branch_t branch_; - }; - - template struct is_const { enum {result = 0}; }; - template struct is_const { enum {result = 1}; }; - template struct is_const_ref { enum {result = 0}; }; - template struct is_const_ref { enum {result = 1}; }; - template struct is_ref { enum {result = 0}; }; - template struct is_ref { enum {result = 1}; }; - template struct is_ref { enum {result = 0}; }; - - template - struct param_to_str { static std::string result() { static const std::string r("v"); return r; } }; - - template <> - struct param_to_str<0> { static std::string result() { static const std::string r("c"); return r; } }; - - #define exprtk_crtype(Type) \ - param_to_str::result>::result() \ - - template - struct T0oT1oT2process - { - typedef typename details::functor_t functor_t; - typedef typename functor_t::bfunc_t bfunc_t; - - struct mode0 - { - static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) - { - // (T0 o0 T1) o1 T2 - return bf1(bf0(t0,t1),t2); - } - - template - static inline std::string id() - { - static const std::string result = "(" + exprtk_crtype(T0) + "o" + - exprtk_crtype(T1) + ")o(" + - exprtk_crtype(T2) + ")" ; - return result; - } - }; - - struct mode1 - { - static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) - { - // T0 o0 (T1 o1 T2) - return bf0(t0,bf1(t1,t2)); - } - - template - static inline std::string id() - { - static const std::string result = "(" + exprtk_crtype(T0) + ")o(" + - exprtk_crtype(T1) + "o" + - exprtk_crtype(T2) + ")" ; - return result; - } - }; - }; - - template - struct T0oT1oT20T3process - { - typedef typename details::functor_t functor_t; - typedef typename functor_t::bfunc_t bfunc_t; - - struct mode0 - { - static inline T process(const T& t0, const T& t1, - const T& t2, const T& t3, - const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) - { - // (T0 o0 T1) o1 (T2 o2 T3) - return bf1(bf0(t0,t1),bf2(t2,t3)); - } - - template - static inline std::string id() - { - static const std::string result = "(" + exprtk_crtype(T0) + "o" + - exprtk_crtype(T1) + ")o" + - "(" + exprtk_crtype(T2) + "o" + - exprtk_crtype(T3) + ")" ; - return result; - } - }; - - struct mode1 - { - static inline T process(const T& t0, const T& t1, - const T& t2, const T& t3, - const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) - { - // (T0 o0 (T1 o1 (T2 o2 T3)) - return bf0(t0,bf1(t1,bf2(t2,t3))); - } - template - static inline std::string id() - { - static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + - exprtk_crtype(T1) + ")o(" + - exprtk_crtype(T2) + "o" + - exprtk_crtype(T3) + "))" ; - return result; - } - }; - - struct mode2 - { - static inline T process(const T& t0, const T& t1, - const T& t2, const T& t3, - const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) - { - // (T0 o0 ((T1 o1 T2) o2 T3) - return bf0(t0,bf2(bf1(t1,t2),t3)); - } - - template - static inline std::string id() - { - static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + - exprtk_crtype(T1) + "o" + - exprtk_crtype(T2) + ")o(" + - exprtk_crtype(T3) + "))" ; - return result; - } - }; - - struct mode3 - { - static inline T process(const T& t0, const T& t1, - const T& t2, const T& t3, - const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) - { - // (((T0 o0 T1) o1 T2) o2 T3) - return bf2(bf1(bf0(t0,t1),t2),t3); - } - - template - static inline std::string id() - { - static const std::string result = "((" + exprtk_crtype(T0) + "o" + - exprtk_crtype(T1) + ")o(" + - exprtk_crtype(T2) + "))o(" + - exprtk_crtype(T3) + ")"; - return result; - } - }; - - struct mode4 - { - static inline T process(const T& t0, const T& t1, - const T& t2, const T& t3, - const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) - { - // ((T0 o0 (T1 o1 T2)) o2 T3 - return bf2(bf0(t0,bf1(t1,t2)),t3); - } - - template - static inline std::string id() - { - static const std::string result = "((" + exprtk_crtype(T0) + ")o(" + - exprtk_crtype(T1) + "o" + - exprtk_crtype(T2) + "))o(" + - exprtk_crtype(T3) + ")" ; - return result; - } - }; - }; - - #undef exprtk_crtype - - template - struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; - template - const typename expression_node::node_type nodetype_T0oT1::result = expression_node::e_none; - - #define synthesis_node_type_define(T0_, T1_, v_) \ - template \ - struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; \ - template \ - const typename expression_node::node_type nodetype_T0oT1::result = expression_node:: v_; \ - - synthesis_node_type_define(const T0&, const T1&, e_vov) - synthesis_node_type_define(const T0&, const T1 , e_voc) - synthesis_node_type_define(const T0 , const T1&, e_cov) - synthesis_node_type_define( T0&, T1&, e_none) - synthesis_node_type_define(const T0 , const T1 , e_none) - synthesis_node_type_define( T0&, const T1 , e_none) - synthesis_node_type_define(const T0 , T1&, e_none) - synthesis_node_type_define(const T0&, T1&, e_none) - synthesis_node_type_define( T0&, const T1&, e_none) - #undef synthesis_node_type_define - - template - struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; - template - const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node::e_none; - - #define synthesis_node_type_define(T0_, T1_, T2_, v_) \ - template \ - struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; \ - template \ - const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node:: v_; \ - - synthesis_node_type_define(const T0&, const T1&, const T2&, e_vovov) - synthesis_node_type_define(const T0&, const T1&, const T2 , e_vovoc) - synthesis_node_type_define(const T0&, const T1 , const T2&, e_vocov) - synthesis_node_type_define(const T0 , const T1&, const T2&, e_covov) - synthesis_node_type_define(const T0 , const T1&, const T2 , e_covoc) - synthesis_node_type_define(const T0 , const T1 , const T2 , e_none ) - synthesis_node_type_define(const T0 , const T1 , const T2&, e_none ) - synthesis_node_type_define(const T0&, const T1 , const T2 , e_none ) - synthesis_node_type_define( T0&, T1&, T2&, e_none ) - #undef synthesis_node_type_define - - template - struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; - template - const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node::e_none; - - #define synthesis_node_type_define(T0_, T1_, T2_, T3_, v_) \ - template \ - struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; \ - template \ - const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node:: v_; \ - - synthesis_node_type_define(const T0&, const T1&, const T2&, const T3&, e_vovovov) - synthesis_node_type_define(const T0&, const T1&, const T2&, const T3 , e_vovovoc) - synthesis_node_type_define(const T0&, const T1&, const T2 , const T3&, e_vovocov) - synthesis_node_type_define(const T0&, const T1 , const T2&, const T3&, e_vocovov) - synthesis_node_type_define(const T0 , const T1&, const T2&, const T3&, e_covovov) - synthesis_node_type_define(const T0 , const T1&, const T2 , const T3&, e_covocov) - synthesis_node_type_define(const T0&, const T1 , const T2&, const T3 , e_vocovoc) - synthesis_node_type_define(const T0 , const T1&, const T2&, const T3 , e_covovoc) - synthesis_node_type_define(const T0&, const T1 , const T2 , const T3&, e_vococov) - synthesis_node_type_define(const T0 , const T1 , const T2 , const T3 , e_none ) - synthesis_node_type_define(const T0 , const T1 , const T2 , const T3&, e_none ) - synthesis_node_type_define(const T0 , const T1 , const T2&, const T3 , e_none ) - synthesis_node_type_define(const T0 , const T1&, const T2 , const T3 , e_none ) - synthesis_node_type_define(const T0&, const T1 , const T2 , const T3 , e_none ) - synthesis_node_type_define(const T0 , const T1 , const T2&, const T3&, e_none ) - synthesis_node_type_define(const T0&, const T1&, const T2 , const T3 , e_none ) - #undef synthesis_node_type_define - - template - class T0oT1 exprtk_final : public expression_node - { - public: - - typedef typename details::functor_t functor_t; - typedef typename functor_t::bfunc_t bfunc_t; - typedef T value_type; - typedef T0oT1 node_type; - - T0oT1(T0 p0, T1 p1, const bfunc_t p2) - : t0_(p0) - , t1_(p1) - , f_ (p2) - {} - - inline typename expression_node::node_type type() const exprtk_override - { - static const typename expression_node::node_type result = nodetype_T0oT1::result; - return result; - } - - inline operator_type operation() const exprtk_override - { - return e_default; - } - - inline T value() const exprtk_override - { - return f_(t0_,t1_); - } - - inline T0 t0() const - { - return t0_; - } - - inline T1 t1() const - { - return t1_; - } - - inline bfunc_t f() const - { - return f_; - } - - template - static inline expression_node* allocate(Allocator& allocator, - T0 p0, T1 p1, - bfunc_t p2) - { - return allocator - .template allocate_type - (p0, p1, p2); - } - - private: - - T0oT1(const T0oT1&) exprtk_delete; - T0oT1& operator=(const T0oT1&) { return (*this); } - - T0 t0_; - T1 t1_; - const bfunc_t f_; - }; - - template - class T0oT1oT2 exprtk_final : public T0oT1oT2_base_node - { - public: - - typedef typename details::functor_t functor_t; - typedef typename functor_t::bfunc_t bfunc_t; - typedef T value_type; - typedef T0oT1oT2 node_type; - typedef ProcessMode process_mode_t; - - T0oT1oT2(T0 p0, T1 p1, T2 p2, const bfunc_t p3, const bfunc_t p4) - : t0_(p0) - , t1_(p1) - , t2_(p2) - , f0_(p3) - , f1_(p4) - {} - - inline typename expression_node::node_type type() const exprtk_override - { - static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; - return result; - } - - inline operator_type operation() - { - return e_default; - } - - inline T value() const exprtk_override - { - return ProcessMode::process(t0_, t1_, t2_, f0_, f1_); - } - - inline T0 t0() const - { - return t0_; - } - - inline T1 t1() const - { - return t1_; - } - - inline T2 t2() const - { - return t2_; - } - - bfunc_t f0() const - { - return f0_; - } - - bfunc_t f1() const - { - return f1_; - } - - std::string type_id() const exprtk_override - { - return id(); - } - - static inline std::string id() - { - return process_mode_t::template id(); - } - - template - static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4) - { - return allocator - .template allocate_type - (p0, p1, p2, p3, p4); - } - - private: - - T0oT1oT2(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - - T0 t0_; - T1 t1_; - T2 t2_; - const bfunc_t f0_; - const bfunc_t f1_; - }; - - template - class T0oT1oT2oT3 exprtk_final : public T0oT1oT2oT3_base_node - { - public: - - typedef typename details::functor_t functor_t; - typedef typename functor_t::bfunc_t bfunc_t; - typedef T value_type; - typedef T0_ T0; - typedef T1_ T1; - typedef T2_ T2; - typedef T3_ T3; - typedef T0oT1oT2oT3 node_type; - typedef ProcessMode process_mode_t; - - T0oT1oT2oT3(T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6) - : t0_(p0) - , t1_(p1) - , t2_(p2) - , t3_(p3) - , f0_(p4) - , f1_(p5) - , f2_(p6) - {} - - inline T value() const exprtk_override - { - return ProcessMode::process(t0_, t1_, t2_, t3_, f0_, f1_, f2_); - } - - inline T0 t0() const - { - return t0_; - } - - inline T1 t1() const - { - return t1_; - } - - inline T2 t2() const - { - return t2_; - } - - inline T3 t3() const - { - return t3_; - } - - inline bfunc_t f0() const - { - return f0_; - } - - inline bfunc_t f1() const - { - return f1_; - } - - inline bfunc_t f2() const - { - return f2_; - } - - inline std::string type_id() const exprtk_override - { - return id(); - } - - static inline std::string id() - { - return process_mode_t::template id(); - } - - template - static inline expression_node* allocate(Allocator& allocator, - T0 p0, T1 p1, T2 p2, T3 p3, - bfunc_t p4, bfunc_t p5, bfunc_t p6) - { - return allocator - .template allocate_type - (p0, p1, p2, p3, p4, p5, p6); - } - - private: - - T0oT1oT2oT3(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - - T0 t0_; - T1 t1_; - T2 t2_; - T3 t3_; - const bfunc_t f0_; - const bfunc_t f1_; - const bfunc_t f2_; - }; - - template - class T0oT1oT2_sf3 exprtk_final : public T0oT1oT2_base_node - { - public: - - typedef typename details::functor_t functor_t; - typedef typename functor_t::tfunc_t tfunc_t; - typedef T value_type; - typedef T0oT1oT2_sf3 node_type; - - T0oT1oT2_sf3(T0 p0, T1 p1, T2 p2, const tfunc_t p3) - : t0_(p0) - , t1_(p1) - , t2_(p2) - , f_ (p3) - {} - - inline typename expression_node::node_type type() const exprtk_override - { - static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; - return result; - } - - inline operator_type operation() const exprtk_override - { - return e_default; - } - - inline T value() const exprtk_override - { - return f_(t0_, t1_, t2_); - } - - inline T0 t0() const - { - return t0_; - } - - inline T1 t1() const - { - return t1_; - } - - inline T2 t2() const - { - return t2_; - } - - tfunc_t f() const - { - return f_; - } - - std::string type_id() const - { - return id(); - } - - static inline std::string id() - { - return "sf3"; - } - - template - static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3) - { - return allocator - .template allocate_type - (p0, p1, p2, p3); - } - - private: - - T0oT1oT2_sf3(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - - T0 t0_; - T1 t1_; - T2 t2_; - const tfunc_t f_; - }; - - template - class sf3ext_type_node : public T0oT1oT2_base_node - { - public: - - virtual ~sf3ext_type_node() - {} - - virtual T0 t0() const = 0; - - virtual T1 t1() const = 0; - - virtual T2 t2() const = 0; - }; - - template - class T0oT1oT2_sf3ext exprtk_final : public sf3ext_type_node - { - public: - - typedef T value_type; - typedef T0oT1oT2_sf3ext node_type; - - T0oT1oT2_sf3ext(T0 p0, T1 p1, T2 p2) - : t0_(p0) - , t1_(p1) - , t2_(p2) - {} - - inline typename expression_node::node_type type() const exprtk_override - { - static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; - return result; - } - - inline operator_type operation() - { - return e_default; - } - - inline T value() const exprtk_override - { - return SF3Operation::process(t0_, t1_, t2_); - } - - T0 t0() const exprtk_override - { - return t0_; - } - - T1 t1() const exprtk_override - { - return t1_; - } - - T2 t2() const exprtk_override - { - return t2_; - } - - std::string type_id() const exprtk_override - { - return id(); - } - - static inline std::string id() - { - return SF3Operation::id(); - } - - template - static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2) - { - return allocator - .template allocate_type - (p0, p1, p2); - } - - private: - - T0oT1oT2_sf3ext(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - - T0 t0_; - T1 t1_; - T2 t2_; - }; - - template - inline bool is_sf3ext_node(const expression_node* n) - { - switch (n->type()) - { - case expression_node::e_vovov : return true; - case expression_node::e_vovoc : return true; - case expression_node::e_vocov : return true; - case expression_node::e_covov : return true; - case expression_node::e_covoc : return true; - default : return false; - } - } - - template - class T0oT1oT2oT3_sf4 exprtk_final : public T0oT1oT2_base_node - { - public: - - typedef typename details::functor_t functor_t; - typedef typename functor_t::qfunc_t qfunc_t; - typedef T value_type; - typedef T0oT1oT2oT3_sf4 node_type; - - T0oT1oT2oT3_sf4(T0 p0, T1 p1, T2 p2, T3 p3, const qfunc_t p4) - : t0_(p0) - , t1_(p1) - , t2_(p2) - , t3_(p3) - , f_ (p4) - {} - - inline typename expression_node::node_type type() const exprtk_override - { - static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; - return result; - } - - inline operator_type operation() const exprtk_override - { - return e_default; - } - - inline T value() const exprtk_override - { - return f_(t0_, t1_, t2_, t3_); - } - - inline T0 t0() const - { - return t0_; - } - - inline T1 t1() const - { - return t1_; - } - - inline T2 t2() const - { - return t2_; - } - - inline T3 t3() const - { - return t3_; - } - - qfunc_t f() const - { - return f_; - } - - std::string type_id() const - { - return id(); - } - - static inline std::string id() - { - return "sf4"; - } - - template - static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4) - { - return allocator - .template allocate_type - (p0, p1, p2, p3, p4); - } - - private: - - T0oT1oT2oT3_sf4(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - - T0 t0_; - T1 t1_; - T2 t2_; - T3 t3_; - const qfunc_t f_; - }; - - template - class T0oT1oT2oT3_sf4ext exprtk_final : public T0oT1oT2oT3_base_node - { - public: - - typedef T value_type; - typedef T0oT1oT2oT3_sf4ext node_type; - - T0oT1oT2oT3_sf4ext(T0 p0, T1 p1, T2 p2, T3 p3) - : t0_(p0) - , t1_(p1) - , t2_(p2) - , t3_(p3) - {} - - inline typename expression_node::node_type type() const exprtk_override - { - static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; - return result; - } - - inline T value() const exprtk_override - { - return SF4Operation::process(t0_, t1_, t2_, t3_); - } - - inline T0 t0() const - { - return t0_; - } - - inline T1 t1() const - { - return t1_; - } - - inline T2 t2() const - { - return t2_; - } - - inline T3 t3() const - { - return t3_; - } - - std::string type_id() const exprtk_override - { - return id(); - } - - static inline std::string id() - { - return SF4Operation::id(); - } - - template - static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3) - { - return allocator - .template allocate_type - (p0, p1, p2, p3); - } - - private: - - T0oT1oT2oT3_sf4ext(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - - T0 t0_; - T1 t1_; - T2 t2_; - T3 t3_; - }; - - template - inline bool is_sf4ext_node(const expression_node* n) - { - switch (n->type()) - { - case expression_node::e_vovovov : return true; - case expression_node::e_vovovoc : return true; - case expression_node::e_vovocov : return true; - case expression_node::e_vocovov : return true; - case expression_node::e_covovov : return true; - case expression_node::e_covocov : return true; - case expression_node::e_vocovoc : return true; - case expression_node::e_covovoc : return true; - case expression_node::e_vococov : return true; - default : return false; - } - } - - template - struct T0oT1_define - { - typedef details::T0oT1 type0; - }; - - template - struct T0oT1oT2_define - { - typedef details::T0oT1oT2::mode0> type0; - typedef details::T0oT1oT2::mode1> type1; - typedef details::T0oT1oT2_sf3 sf3_type; - typedef details::sf3ext_type_node sf3_type_node; - }; - - template - struct T0oT1oT2oT3_define - { - typedef details::T0oT1oT2oT3::mode0> type0; - typedef details::T0oT1oT2oT3::mode1> type1; - typedef details::T0oT1oT2oT3::mode2> type2; - typedef details::T0oT1oT2oT3::mode3> type3; - typedef details::T0oT1oT2oT3::mode4> type4; - typedef details::T0oT1oT2oT3_sf4 sf4_type; - }; - - template - class vov_node exprtk_final : public vov_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef Operation operation_t; - - // variable op variable node - explicit vov_node(const T& var0, const T& var1) - : v0_(var0) - , v1_(var1) - {} - - inline T value() const exprtk_override - { - return Operation::process(v0_,v1_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline const T& v0() const exprtk_override - { - return v0_; - } - - inline const T& v1() const exprtk_override - { - return v1_; - } - - protected: - - const T& v0_; - const T& v1_; - - private: - - vov_node(const vov_node&) exprtk_delete; - vov_node& operator=(const vov_node&) exprtk_delete; - }; - - template - class cov_node exprtk_final : public cov_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef Operation operation_t; - - // constant op variable node - explicit cov_node(const T& const_var, const T& var) - : c_(const_var) - , v_(var) - {} - - inline T value() const exprtk_override - { - return Operation::process(c_,v_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline const T c() const exprtk_override - { - return c_; - } - - inline const T& v() const exprtk_override - { - return v_; - } - - protected: - - const T c_; - const T& v_; - - private: - - cov_node(const cov_node&) exprtk_delete; - cov_node& operator=(const cov_node&) exprtk_delete; - }; - - template - class voc_node exprtk_final : public voc_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef Operation operation_t; - - // variable op constant node - explicit voc_node(const T& var, const T& const_var) - : v_(var) - , c_(const_var) - {} - - inline T value() const exprtk_override - { - return Operation::process(v_,c_); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline const T c() const exprtk_override - { - return c_; - } - - inline const T& v() const exprtk_override - { - return v_; - } - - protected: - - const T& v_; - const T c_; - - private: - - voc_node(const voc_node&) exprtk_delete; - voc_node& operator=(const voc_node&) exprtk_delete; - }; - - template - class vob_node exprtk_final : public vob_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef Operation operation_t; - - // variable op binary node - explicit vob_node(const T& var, const expression_ptr branch) - : v_(var) - { - construct_branch_pair(branch_, branch); - assert(valid()); - } - - inline T value() const exprtk_override - { - return Operation::process(v_,branch_.first->value()); - } - - inline const T& v() const exprtk_override - { - return v_; - } - - inline bool valid() const exprtk_override - { - return branch_.first && branch_.first->valid(); - } - - inline expression_node* branch(const std::size_t&) const exprtk_override - { - return branch_.first; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - vob_node(const vob_node&) exprtk_delete; - vob_node& operator=(const vob_node&) exprtk_delete; - - const T& v_; - branch_t branch_; - }; - - template - class bov_node exprtk_final : public bov_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef Operation operation_t; - - // binary node op variable node - explicit bov_node(const expression_ptr branch, const T& var) - : v_(var) - { - construct_branch_pair(branch_, branch); - assert(valid()); - } - - inline T value() const exprtk_override - { - return Operation::process(branch_.first->value(),v_); - } - - inline const T& v() const exprtk_override - { - return v_; - } - - inline bool valid() const exprtk_override - { - return branch_.first && branch_.first->valid(); - } - - inline expression_node* branch(const std::size_t&) const exprtk_override - { - return branch_.first; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - bov_node(const bov_node&) exprtk_delete; - bov_node& operator=(const bov_node&) exprtk_delete; - - const T& v_; - branch_t branch_; - }; - - template - class cob_node exprtk_final : public cob_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef Operation operation_t; - - // constant op variable node - explicit cob_node(const T const_var, const expression_ptr branch) - : c_(const_var) - { - construct_branch_pair(branch_, branch); - assert(valid()); - } - - inline T value() const exprtk_override - { - return Operation::process(c_,branch_.first->value()); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline const T c() const exprtk_override - { - return c_; - } - - inline void set_c(const T new_c) exprtk_override - { - (*const_cast(&c_)) = new_c; - } - - inline bool valid() const exprtk_override - { - return branch_.first && branch_.first->valid(); - } - - inline expression_node* branch(const std::size_t&) const exprtk_override - { - return branch_.first; - } - - inline expression_node* move_branch(const std::size_t&) exprtk_override - { - branch_.second = false; - return branch_.first; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - cob_node(const cob_node&) exprtk_delete; - cob_node& operator=(const cob_node&) exprtk_delete; - - const T c_; - branch_t branch_; - }; - - template - class boc_node exprtk_final : public boc_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef Operation operation_t; - - // binary node op constant node - explicit boc_node(const expression_ptr branch, const T const_var) - : c_(const_var) - { - construct_branch_pair(branch_, branch); - assert(valid()); - } - - inline T value() const exprtk_override - { - return Operation::process(branch_.first->value(),c_); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline const T c() const exprtk_override - { - return c_; - } - - inline void set_c(const T new_c) exprtk_override - { - (*const_cast(&c_)) = new_c; - } - - inline bool valid() const exprtk_override - { - return branch_.first && branch_.first->valid(); - } - - inline expression_node* branch(const std::size_t&) const exprtk_override - { - return branch_.first; - } - - inline expression_node* move_branch(const std::size_t&) exprtk_override - { - branch_.second = false; - return branch_.first; - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - boc_node(const boc_node&) exprtk_delete; - boc_node& operator=(const boc_node&) exprtk_delete; - - const T c_; - branch_t branch_; - }; - - #ifndef exprtk_disable_string_capabilities - template - class sos_node exprtk_final : public sos_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef Operation operation_t; - - // string op string node - explicit sos_node(SType0 p0, SType1 p1) - : s0_(p0) - , s1_(p1) - {} - - inline T value() const exprtk_override - { - return Operation::process(s0_,s1_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline std::string& s0() - { - return s0_; - } - - inline std::string& s1() - { - return s1_; - } - - protected: - - SType0 s0_; - SType1 s1_; - - private: - - sos_node(const sos_node&) exprtk_delete; - sos_node& operator=(const sos_node&) exprtk_delete; - }; - - template - class str_xrox_node exprtk_final : public sos_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef Operation operation_t; - typedef str_xrox_node node_type; - - // string-range op string node - explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0) - : s0_ (p0 ) - , s1_ (p1 ) - , rp0_(rp0) - {} - - ~str_xrox_node() - { - rp0_.free(); - } - - inline T value() const exprtk_override - { - std::size_t r0 = 0; - std::size_t r1 = 0; - - if (rp0_(r0, r1, s0_.size())) - return Operation::process(s0_.substr(r0, (r1 - r0) + 1), s1_); - else - return T(0); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline std::string& s0() - { - return s0_; - } - - inline std::string& s1() - { - return s1_; - } - - protected: - - SType0 s0_; - SType1 s1_; - RangePack rp0_; - - private: - - str_xrox_node(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - }; - - template - class str_xoxr_node exprtk_final : public sos_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef Operation operation_t; - typedef str_xoxr_node node_type; - - // string op string range node - explicit str_xoxr_node(SType0 p0, SType1 p1, RangePack rp1) - : s0_ (p0 ) - , s1_ (p1 ) - , rp1_(rp1) - {} - - ~str_xoxr_node() - { - rp1_.free(); - } - - inline T value() const exprtk_override - { - std::size_t r0 = 0; - std::size_t r1 = 0; - - if (rp1_(r0, r1, s1_.size())) - { - return Operation::process - ( - s0_, - s1_.substr(r0, (r1 - r0) + 1) - ); - } - else - return T(0); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline std::string& s0() - { - return s0_; - } - - inline std::string& s1() - { - return s1_; - } - - protected: - - SType0 s0_; - SType1 s1_; - RangePack rp1_; - - private: - - str_xoxr_node(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - }; - - template - class str_xroxr_node exprtk_final : public sos_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef Operation operation_t; - typedef str_xroxr_node node_type; - - // string-range op string-range node - explicit str_xroxr_node(SType0 p0, SType1 p1, RangePack rp0, RangePack rp1) - : s0_ (p0 ) - , s1_ (p1 ) - , rp0_(rp0) - , rp1_(rp1) - {} - - ~str_xroxr_node() - { - rp0_.free(); - rp1_.free(); - } - - inline T value() const exprtk_override - { - std::size_t r0_0 = 0; - std::size_t r0_1 = 0; - std::size_t r1_0 = 0; - std::size_t r1_1 = 0; - - if ( - rp0_(r0_0, r1_0, s0_.size()) && - rp1_(r0_1, r1_1, s1_.size()) - ) - { - return Operation::process - ( - s0_.substr(r0_0, (r1_0 - r0_0) + 1), - s1_.substr(r0_1, (r1_1 - r0_1) + 1) - ); - } - else - return T(0); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline std::string& s0() - { - return s0_; - } - - inline std::string& s1() - { - return s1_; - } - - protected: - - SType0 s0_; - SType1 s1_; - RangePack rp0_; - RangePack rp1_; - - private: - - str_xroxr_node(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - }; - - template - class str_sogens_node exprtk_final : public binary_node - { - public: - - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - typedef range_pack range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - - using binary_node::branch; - - str_sogens_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr, branch0, branch1) - , str0_base_ptr_ (0) - , str1_base_ptr_ (0) - , str0_range_ptr_(0) - , str1_range_ptr_(0) - , initialised_ (false) - { - if (is_generally_string_node(branch(0))) - { - str0_base_ptr_ = dynamic_cast(branch(0)); - - if (0 == str0_base_ptr_) - return; - - irange_ptr range = dynamic_cast(branch(0)); - - if (0 == range) - return; - - str0_range_ptr_ = &(range->range_ref()); - } - - if (is_generally_string_node(branch(1))) - { - str1_base_ptr_ = dynamic_cast(branch(1)); - - if (0 == str1_base_ptr_) - return; - - irange_ptr range = dynamic_cast(branch(1)); - - if (0 == range) - return; - - str1_range_ptr_ = &(range->range_ref()); - } - - initialised_ = - str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_; - - assert(valid()); - } - - inline T value() const exprtk_override - { - branch(0)->value(); - branch(1)->value(); - - std::size_t str0_r0 = 0; - std::size_t str0_r1 = 0; - - std::size_t str1_r0 = 0; - std::size_t str1_r1 = 0; - - const range_t& range0 = (*str0_range_ptr_); - const range_t& range1 = (*str1_range_ptr_); - - if ( - range0(str0_r0, str0_r1, str0_base_ptr_->size()) && - range1(str1_r0, str1_r1, str1_base_ptr_->size()) - ) - { - return Operation::process - ( - str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0)), - str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0)) - ); - } - - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline bool valid() const exprtk_override - { - return initialised_; - } - - private: - - str_sogens_node(const str_sogens_node&) exprtk_delete; - str_sogens_node& operator=(const str_sogens_node&) exprtk_delete; - - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - range_ptr str0_range_ptr_; - range_ptr str1_range_ptr_; - bool initialised_; - }; - - template - class sosos_node exprtk_final : public sosos_base_node - { - public: - - typedef expression_node* expression_ptr; - typedef Operation operation_t; - typedef sosos_node node_type; - - // string op string op string node - explicit sosos_node(SType0 p0, SType1 p1, SType2 p2) - : s0_(p0) - , s1_(p1) - , s2_(p2) - {} - - inline T value() const exprtk_override - { - return Operation::process(s0_, s1_, s2_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return Operation::type(); - } - - inline operator_type operation() const exprtk_override - { - return Operation::operation(); - } - - inline std::string& s0() - { - return s0_; - } - - inline std::string& s1() - { - return s1_; - } - - inline std::string& s2() - { - return s2_; - } - - protected: - - SType0 s0_; - SType1 s1_; - SType2 s2_; - - private: - - sosos_node(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) exprtk_delete; - }; - #endif - - template - class ipow_node exprtk_final: public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef PowOp operation_t; - - explicit ipow_node(const T& v) - : v_(v) - {} - - inline T value() const exprtk_override - { - return PowOp::result(v_); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_ipow; - } - - private: - - ipow_node(const ipow_node&) exprtk_delete; - ipow_node& operator=(const ipow_node&) exprtk_delete; - - const T& v_; - }; - - template - class bipow_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef PowOp operation_t; - - explicit bipow_node(expression_ptr branch) - { - construct_branch_pair(branch_, branch); - assert(valid()); - } - - inline T value() const exprtk_override - { - return PowOp::result(branch_.first->value()); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_ipow; - } - - inline bool valid() const exprtk_override - { - return branch_.first && branch_.first->valid(); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - bipow_node(const bipow_node&) exprtk_delete; - bipow_node& operator=(const bipow_node&) exprtk_delete; - - branch_t branch_; - }; - - template - class ipowinv_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef PowOp operation_t; - - explicit ipowinv_node(const T& v) - : v_(v) - {} - - inline T value() const exprtk_override - { - return (T(1) / PowOp::result(v_)); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_ipowinv; - } - - private: - - ipowinv_node(const ipowinv_node&) exprtk_delete; - ipowinv_node& operator=(const ipowinv_node&) exprtk_delete; - - const T& v_; - }; - - template - class bipowinv_node exprtk_final : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef PowOp operation_t; - - explicit bipowinv_node(expression_ptr branch) - { - construct_branch_pair(branch_, branch); - assert(valid()); - } - - inline T value() const exprtk_override - { - return (T(1) / PowOp::result(branch_.first->value())); - } - - inline typename expression_node::node_type type() const exprtk_override - { - return expression_node::e_ipowinv; - } - - inline bool valid() const exprtk_override - { - return branch_.first && branch_.first->valid(); - } - - void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override - { - expression_node::ndb_t::collect(branch_, node_delete_list); - } - - std::size_t node_depth() const exprtk_override - { - return expression_node::ndb_t::compute_node_depth(branch_); - } - - private: - - bipowinv_node(const bipowinv_node&) exprtk_delete; - bipowinv_node& operator=(const bipowinv_node&) exprtk_delete; - - branch_t branch_; - }; - - template - inline bool is_vov_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_cov_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_voc_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_cob_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_boc_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_t0ot1ot2_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_t0ot1ot2ot3_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_uv_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_string_node(const expression_node* node) - { - return node && (expression_node::e_stringvar == node->type()); - } - - template - inline bool is_string_range_node(const expression_node* node) - { - return node && (expression_node::e_stringvarrng == node->type()); - } - - template - inline bool is_const_string_node(const expression_node* node) - { - return node && (expression_node::e_stringconst == node->type()); - } - - template - inline bool is_const_string_range_node(const expression_node* node) - { - return node && (expression_node::e_cstringvarrng == node->type()); - } - - template - inline bool is_string_assignment_node(const expression_node* node) - { - return node && (expression_node::e_strass == node->type()); - } - - template - inline bool is_string_concat_node(const expression_node* node) - { - return node && (expression_node::e_strconcat == node->type()); - } - - template - inline bool is_string_function_node(const expression_node* node) - { - return node && (expression_node::e_strfunction == node->type()); - } - - template - inline bool is_string_condition_node(const expression_node* node) - { - return node && (expression_node::e_strcondition == node->type()); - } - - template - inline bool is_string_ccondition_node(const expression_node* node) - { - return node && (expression_node::e_strccondition == node->type()); - } - - template - inline bool is_string_vararg_node(const expression_node* node) - { - return node && (expression_node::e_stringvararg == node->type()); - } - - template - inline bool is_genricstring_range_node(const expression_node* node) - { - return node && (expression_node::e_strgenrange == node->type()); - } - - template - inline bool is_generally_string_node(const expression_node* node) - { - if (node) - { - switch (node->type()) - { - case expression_node::e_stringvar : - case expression_node::e_stringconst : - case expression_node::e_stringvarrng : - case expression_node::e_cstringvarrng : - case expression_node::e_strgenrange : - case expression_node::e_strass : - case expression_node::e_strconcat : - case expression_node::e_strfunction : - case expression_node::e_strcondition : - case expression_node::e_strccondition : - case expression_node::e_stringvararg : return true; - default : return false; - } - } - - return false; - } - - template - inline bool is_loop_node(const expression_node* node) - { - if (node) - { - switch (node->type()) - { - case expression_node::e_for : - case expression_node::e_repeat : - case expression_node::e_while : return true; - default : return false; - } - } - - return false; - } - - template - inline bool is_block_node(const expression_node* node) - { - if (node) - { - if (is_loop_node(node)) - { - return true; - } - - switch (node->type()) - { - case expression_node::e_conditional : - case expression_node::e_mswitch : - case expression_node::e_switch : - case expression_node::e_vararg : return true; - default : return false; - } - } - - return false; - } - - class node_allocator - { - public: - - template - inline expression_node* allocate(OpType& operation, ExprNode (&branch)[1]) - { - expression_node* result = - allocate(operation, branch[0]); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(OpType& operation, ExprNode (&branch)[2]) - { - expression_node* result = - allocate(operation, branch[0], branch[1]); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(OpType& operation, ExprNode (&branch)[3]) - { - expression_node* result = - allocate(operation, branch[0], branch[1], branch[2]); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(OpType& operation, ExprNode (&branch)[4]) - { - expression_node* result = - allocate(operation, branch[0], branch[1], branch[2], branch[3]); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(OpType& operation, ExprNode (&branch)[5]) - { - expression_node* result = - allocate(operation, branch[0],branch[1], branch[2], branch[3], branch[4]); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(OpType& operation, ExprNode (&branch)[6]) - { - expression_node* result = - allocate(operation, branch[0], branch[1], branch[2], branch[3], branch[4], branch[5]); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate() const - { - return (new node_type()); - } - - template class Sequence> - inline expression_node* allocate(const Sequence& seq) const - { - expression_node* - result = (new node_type(seq)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(T1& t1) const - { - expression_node* - result = (new node_type(t1)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_c(const T1& t1) const - { - expression_node* - result = (new node_type(t1)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(const T1& t1, const T2& t2) const - { - expression_node* - result = (new node_type(t1, t2)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_cr(const T1& t1, T2& t2) const - { - expression_node* - result = (new node_type(t1, t2)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_rc(T1& t1, const T2& t2) const - { - expression_node* - result = (new node_type(t1, t2)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_rr(T1& t1, T2& t2) const - { - expression_node* - result = (new node_type(t1, t2)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_tt(T1 t1, T2 t2) const - { - expression_node* - result = (new node_type(t1, t2)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_ttt(T1 t1, T2 t2, T3 t3) const - { - expression_node* - result = (new node_type(t1, t2, t3)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_tttt(T1 t1, T2 t2, T3 t3, T4 t4) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_rrr(T1& t1, T2& t2, T3& t3) const - { - expression_node* - result = (new node_type(t1, t2, t3)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_rrrr(T1& t1, T2& t2, T3& t3, T4& t4) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_rrrrr(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(const T1& t1, const T2& t2, - const T3& t3) const - { - expression_node* - result = (new node_type(t1, t2, t3)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(const T1& t1, const T2& t2, - const T3& t3, const T4& t4) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(const T1& t1, const T2& t2, - const T3& t3, const T4& t4, - const T5& t5) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(const T1& t1, const T2& t2, - const T3& t3, const T4& t4, - const T5& t5, const T6& t6) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5, t6)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(const T1& t1, const T2& t2, - const T3& t3, const T4& t4, - const T5& t5, const T6& t6, - const T7& t7) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(const T1& t1, const T2& t2, - const T3& t3, const T4& t4, - const T5& t5, const T6& t6, - const T7& t7, const T8& t8) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(const T1& t1, const T2& t2, - const T3& t3, const T4& t4, - const T5& t5, const T6& t6, - const T7& t7, const T8& t8, - const T9& t9) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate(const T1& t1, const T2& t2, - const T3& t3, const T4& t4, - const T5& t5, const T6& t6, - const T7& t7, const T8& t8, - const T9& t9, const T10& t10) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3) const - { - expression_node* - result = (new node_type(t1, t2, t3)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_type(T1 t1, T2 t2, - T3 t3, T4 t4) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_type(T1 t1, T2 t2, - T3 t3, T4 t4, - T5 t5) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_type(T1 t1, T2 t2, - T3 t3, T4 t4, - T5 t5, T6 t6) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5, t6)); - result->node_depth(); - return result; - } - - template - inline expression_node* allocate_type(T1 t1, T2 t2, - T3 t3, T4 t4, - T5 t5, T6 t6, - T7 t7) const - { - expression_node* - result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); - result->node_depth(); - return result; - } - - template - void inline free(expression_node*& e) const - { - exprtk_debug(("node_allocator::free() - deleting expression_node " - "type: %03d addr: %p\n", - static_cast(e->type()), - reinterpret_cast(e))); - delete e; - e = 0; - } - }; - - inline void load_operations_map(std::multimap& m) - { - #define register_op(Symbol, Type, Args) \ - m.insert(std::make_pair(std::string(Symbol),details::base_operation_t(Type,Args))); \ - - register_op("abs" , e_abs , 1) - register_op("acos" , e_acos , 1) - register_op("acosh" , e_acosh , 1) - register_op("asin" , e_asin , 1) - register_op("asinh" , e_asinh , 1) - register_op("atan" , e_atan , 1) - register_op("atanh" , e_atanh , 1) - register_op("ceil" , e_ceil , 1) - register_op("cos" , e_cos , 1) - register_op("cosh" , e_cosh , 1) - register_op("exp" , e_exp , 1) - register_op("expm1" , e_expm1 , 1) - register_op("floor" , e_floor , 1) - register_op("log" , e_log , 1) - register_op("log10" , e_log10 , 1) - register_op("log2" , e_log2 , 1) - register_op("log1p" , e_log1p , 1) - register_op("round" , e_round , 1) - register_op("sin" , e_sin , 1) - register_op("sinc" , e_sinc , 1) - register_op("sinh" , e_sinh , 1) - register_op("sec" , e_sec , 1) - register_op("csc" , e_csc , 1) - register_op("sqrt" , e_sqrt , 1) - register_op("tan" , e_tan , 1) - register_op("tanh" , e_tanh , 1) - register_op("cot" , e_cot , 1) - register_op("rad2deg" , e_r2d , 1) - register_op("deg2rad" , e_d2r , 1) - register_op("deg2grad" , e_d2g , 1) - register_op("grad2deg" , e_g2d , 1) - register_op("sgn" , e_sgn , 1) - register_op("not" , e_notl , 1) - register_op("erf" , e_erf , 1) - register_op("erfc" , e_erfc , 1) - register_op("ncdf" , e_ncdf , 1) - register_op("frac" , e_frac , 1) - register_op("trunc" , e_trunc , 1) - register_op("atan2" , e_atan2 , 2) - register_op("mod" , e_mod , 2) - register_op("logn" , e_logn , 2) - register_op("pow" , e_pow , 2) - register_op("root" , e_root , 2) - register_op("roundn" , e_roundn , 2) - register_op("equal" , e_equal , 2) - register_op("not_equal" , e_nequal , 2) - register_op("hypot" , e_hypot , 2) - register_op("shr" , e_shr , 2) - register_op("shl" , e_shl , 2) - register_op("clamp" , e_clamp , 3) - register_op("iclamp" , e_iclamp , 3) - register_op("inrange" , e_inrange , 3) - #undef register_op - } - - } // namespace details - - class function_traits - { - public: - - function_traits() - : allow_zero_parameters_(false) - , has_side_effects_(true) - , min_num_args_(0) - , max_num_args_(std::numeric_limits::max()) - {} - - inline bool& allow_zero_parameters() - { - return allow_zero_parameters_; - } - - inline bool& has_side_effects() - { - return has_side_effects_; - } - - std::size_t& min_num_args() - { - return min_num_args_; - } - - std::size_t& max_num_args() - { - return max_num_args_; - } - - private: - - bool allow_zero_parameters_; - bool has_side_effects_; - std::size_t min_num_args_; - std::size_t max_num_args_; - }; - - template - void enable_zero_parameters(FunctionType& func) - { - func.allow_zero_parameters() = true; - - if (0 != func.min_num_args()) - { - func.min_num_args() = 0; - } - } - - template - void disable_zero_parameters(FunctionType& func) - { - func.allow_zero_parameters() = false; - } - - template - void enable_has_side_effects(FunctionType& func) - { - func.has_side_effects() = true; - } - - template - void disable_has_side_effects(FunctionType& func) - { - func.has_side_effects() = false; - } - - template - void set_min_num_args(FunctionType& func, const std::size_t& num_args) - { - func.min_num_args() = num_args; - - if ((0 != func.min_num_args()) && func.allow_zero_parameters()) - func.allow_zero_parameters() = false; - } - - template - void set_max_num_args(FunctionType& func, const std::size_t& num_args) - { - func.max_num_args() = num_args; - } - - template - class ifunction : public function_traits - { - public: - - explicit ifunction(const std::size_t& pc) - : param_count(pc) - {} - - virtual ~ifunction() - {} - - #define empty_method_body(N) \ - { \ - exprtk_debug(("ifunction::operator() - Operator(" #N ") has not been overridden\n")); \ - return std::numeric_limits::quiet_NaN(); \ - } \ - - inline virtual T operator() () - empty_method_body(0) - - inline virtual T operator() (const T&) - empty_method_body(1) - - inline virtual T operator() (const T&,const T&) - empty_method_body(2) - - inline virtual T operator() (const T&, const T&, const T&) - empty_method_body(3) - - inline virtual T operator() (const T&, const T&, const T&, const T&) - empty_method_body(4) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&) - empty_method_body(5) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(6) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(7) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(8) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(9) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(10) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&) - empty_method_body(11) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&) - empty_method_body(12) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&) - empty_method_body(13) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&) - empty_method_body(14) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&) - empty_method_body(15) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(16) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(17) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(18) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(19) - - inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body(20) - - #undef empty_method_body - - std::size_t param_count; - }; - - template - class ivararg_function : public function_traits - { - public: - - virtual ~ivararg_function() - {} - - inline virtual T operator() (const std::vector&) - { - exprtk_debug(("ivararg_function::operator() - Operator has not been overridden\n")); - return std::numeric_limits::quiet_NaN(); - } - }; - - template - class igeneric_function : public function_traits - { - public: - - enum return_type - { - e_rtrn_scalar = 0, - e_rtrn_string = 1, - e_rtrn_overload = 2 - }; - - typedef T type; - typedef type_store generic_type; - typedef typename generic_type::parameter_list parameter_list_t; - - explicit igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) - : parameter_sequence(param_seq) - , rtrn_type(rtr_type) - {} - - virtual ~igeneric_function() - {} - - #define igeneric_function_empty_body(N) \ - { \ - exprtk_debug(("igeneric_function::operator() - Operator(" #N ") has not been overridden\n")); \ - return std::numeric_limits::quiet_NaN(); \ - } \ - - // f(i_0,i_1,....,i_N) --> Scalar - inline virtual T operator() (parameter_list_t) - igeneric_function_empty_body(1) - - // f(i_0,i_1,....,i_N) --> String - inline virtual T operator() (std::string&, parameter_list_t) - igeneric_function_empty_body(2) - - // f(psi,i_0,i_1,....,i_N) --> Scalar - inline virtual T operator() (const std::size_t&, parameter_list_t) - igeneric_function_empty_body(3) - - // f(psi,i_0,i_1,....,i_N) --> String - inline virtual T operator() (const std::size_t&, std::string&, parameter_list_t) - igeneric_function_empty_body(4) - - #undef igeneric_function_empty_body - - std::string parameter_sequence; - return_type rtrn_type; - }; - - #ifndef exprtk_disable_string_capabilities - template - class stringvar_base - { - public: - - typedef typename details::stringvar_node stringvar_node_t; - - stringvar_base(const std::string& name, stringvar_node_t* svn) - : name_(name) - , string_varnode_(svn) - {} - - bool valid() const - { - return !name_.empty() && (0 != string_varnode_); - } - - std::string name() const - { - assert(string_varnode_); - return name_; - } - - void rebase(std::string& s) - { - assert(string_varnode_); - string_varnode_->rebase(s); - } - - private: - - std::string name_; - stringvar_node_t* string_varnode_; - }; - #endif - - template class parser; - template class expression_helper; - - template - class symbol_table - { - public: - - enum symtab_mutability_type - { - e_unknown = 0, - e_mutable = 1, - e_immutable = 2 - }; - - typedef T (*ff00_functor)(); - typedef T (*ff01_functor)(T); - typedef T (*ff02_functor)(T, T); - typedef T (*ff03_functor)(T, T, T); - typedef T (*ff04_functor)(T, T, T, T); - typedef T (*ff05_functor)(T, T, T, T, T); - typedef T (*ff06_functor)(T, T, T, T, T, T); - typedef T (*ff07_functor)(T, T, T, T, T, T, T); - typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); - typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); - typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); - typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); - - protected: - - struct freefunc00 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc00(ff00_functor ff) : exprtk::ifunction(0), f(ff) {} - inline T operator() () exprtk_override - { return f(); } - ff00_functor f; - }; - - struct freefunc01 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc01(ff01_functor ff) : exprtk::ifunction(1), f(ff) {} - inline T operator() (const T& v0) exprtk_override - { return f(v0); } - ff01_functor f; - }; - - struct freefunc02 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc02(ff02_functor ff) : exprtk::ifunction(2), f(ff) {} - inline T operator() (const T& v0, const T& v1) exprtk_override - { return f(v0, v1); } - ff02_functor f; - }; - - struct freefunc03 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc03(ff03_functor ff) : exprtk::ifunction(3), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2) exprtk_override - { return f(v0, v1, v2); } - ff03_functor f; - }; - - struct freefunc04 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc04(ff04_functor ff) : exprtk::ifunction(4), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) exprtk_override - { return f(v0, v1, v2, v3); } - ff04_functor f; - }; - - struct freefunc05 : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc05(ff05_functor ff) : exprtk::ifunction(5), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) exprtk_override - { return f(v0, v1, v2, v3, v4); } - ff05_functor f; - }; - - struct freefunc06 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc06(ff06_functor ff) : exprtk::ifunction(6), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) exprtk_override - { return f(v0, v1, v2, v3, v4, v5); } - ff06_functor f; - }; - - struct freefunc07 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc07(ff07_functor ff) : exprtk::ifunction(7), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6) exprtk_override - { return f(v0, v1, v2, v3, v4, v5, v6); } - ff07_functor f; - }; - - struct freefunc08 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc08(ff08_functor ff) : exprtk::ifunction(8), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7) exprtk_override - { return f(v0, v1, v2, v3, v4, v5, v6, v7); } - ff08_functor f; - }; - - struct freefunc09 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc09(ff09_functor ff) : exprtk::ifunction(9), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8) exprtk_override - { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8); } - ff09_functor f; - }; - - struct freefunc10 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc10(ff10_functor ff) : exprtk::ifunction(10), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) exprtk_override - { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); } - ff10_functor f; - }; - - struct freefunc11 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc11(ff11_functor ff) : exprtk::ifunction(11), f(ff) {} - inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, - const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) exprtk_override - { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } - ff11_functor f; - }; - - struct freefunc12 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc12(ff12_functor ff) : exprtk::ifunction(12), f(ff) {} - inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, - const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11) exprtk_override - { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11); } - ff12_functor f; - }; - - struct freefunc13 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc13(ff13_functor ff) : exprtk::ifunction(13), f(ff) {} - inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, - const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12) exprtk_override - { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12); } - ff13_functor f; - }; - - struct freefunc14 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc14(ff14_functor ff) : exprtk::ifunction(14), f(ff) {} - inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, - const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12, const T& v13) exprtk_override - { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13); } - ff14_functor f; - }; - - struct freefunc15 exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - explicit freefunc15(ff15_functor ff) : exprtk::ifunction(15), f(ff) {} - inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, - const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, - const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) exprtk_override - { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14); } - ff15_functor f; - }; - - template - struct type_store - { - typedef details::expression_node* expression_ptr; - typedef typename details::variable_node variable_node_t; - typedef ifunction ifunction_t; - typedef ivararg_function ivararg_function_t; - typedef igeneric_function igeneric_function_t; - typedef details::vector_holder vector_t; - #ifndef exprtk_disable_string_capabilities - typedef typename details::stringvar_node stringvar_node_t; - #endif - - typedef Type type_t; - typedef type_t* type_ptr; - typedef std::pair type_pair_t; - typedef std::map type_map_t; - typedef typename type_map_t::iterator tm_itr_t; - typedef typename type_map_t::const_iterator tm_const_itr_t; - - enum { lut_size = 256 }; - - type_map_t map; - std::size_t size; - - type_store() - : size(0) - {} - - struct deleter - { - #define exprtk_define_process(Type) \ - static inline void process(std::pair& n) \ - { \ - delete n.second; \ - } \ - - exprtk_define_process(variable_node_t ) - exprtk_define_process(vector_t ) - #ifndef exprtk_disable_string_capabilities - exprtk_define_process(stringvar_node_t) - #endif - - #undef exprtk_define_process - - template - static inline void process(std::pair&) - {} - }; - - inline bool symbol_exists(const std::string& symbol_name) const - { - if (symbol_name.empty()) - return false; - else if (map.end() != map.find(symbol_name)) - return true; - else - return false; - } - - template - inline std::string entity_name(const PtrType& ptr) const - { - if (map.empty()) - return std::string(); - - tm_const_itr_t itr = map.begin(); - - while (map.end() != itr) - { - if (itr->second.second == ptr) - { - return itr->first; - } - else - ++itr; - } - - return std::string(); - } - - inline bool is_constant(const std::string& symbol_name) const - { - if (symbol_name.empty()) - return false; - else - { - const tm_const_itr_t itr = map.find(symbol_name); - - if (map.end() == itr) - return false; - else - return (*itr).second.first; - } - } - - template - inline bool add_impl(const std::string& symbol_name, RType t, const bool is_const) - { - if (symbol_name.size() > 1) - { - for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) - { - if (details::imatch(symbol_name, details::reserved_symbols[i])) - { - return false; - } - } - } - - const tm_itr_t itr = map.find(symbol_name); - - if (map.end() == itr) - { - map[symbol_name] = Tie::make(t,is_const); - ++size; - } - - return true; - } - - struct tie_array - { - static inline std::pair make(std::pair v, const bool is_const = false) - { - return std::make_pair(is_const, new vector_t(v.first, v.second)); - } - }; - - struct tie_stdvec - { - template - static inline std::pair make(std::vector& v, const bool is_const = false) - { - return std::make_pair(is_const, new vector_t(v)); - } - }; - - struct tie_vecview - { - static inline std::pair make(exprtk::vector_view& v, const bool is_const = false) - { - return std::make_pair(is_const, new vector_t(v)); - } - }; - - struct tie_stddeq - { - template - static inline std::pair make(std::deque& v, const bool is_const = false) - { - return std::make_pair(is_const, new vector_t(v)); - } - }; - - template - inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false) - { - return add_impl > - (symbol_name, std::make_pair(v,v_size), is_const); - } - - inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_const = false) - { - return add_impl > - (symbol_name, std::make_pair(v,v_size), is_const); - } - - template - inline bool add(const std::string& symbol_name, std::vector& v, const bool is_const = false) - { - return add_impl&> - (symbol_name, v, is_const); - } - - inline bool add(const std::string& symbol_name, exprtk::vector_view& v, const bool is_const = false) - { - return add_impl&> - (symbol_name, v, is_const); - } - - template - inline bool add(const std::string& symbol_name, std::deque& v, const bool is_const = false) - { - return add_impl&> - (symbol_name, v, is_const); - } - - inline bool add(const std::string& symbol_name, RawType& t_, const bool is_const = false) - { - struct tie - { - static inline std::pair make(T& t, const bool is_constant = false) - { - return std::make_pair(is_constant, new variable_node_t(t)); - } - - #ifndef exprtk_disable_string_capabilities - static inline std::pair make(std::string& t, const bool is_constant = false) - { - return std::make_pair(is_constant, new stringvar_node_t(t)); - } - #endif - - static inline std::pair make(function_t& t, const bool is_constant = false) - { - return std::make_pair(is_constant,&t); - } - - static inline std::pair make(vararg_function_t& t, const bool is_constant = false) - { - return std::make_pair(is_constant,&t); - } - - static inline std::pair make(generic_function_t& t, const bool is_constant = false) - { - return std::make_pair(is_constant,&t); - } - }; - - const tm_itr_t itr = map.find(symbol_name); - - if (map.end() == itr) - { - map[symbol_name] = tie::make(t_,is_const); - ++size; - } - - return true; - } - - inline type_ptr get(const std::string& symbol_name) const - { - const tm_const_itr_t itr = map.find(symbol_name); - - if (map.end() == itr) - return reinterpret_cast(0); - else - return itr->second.second; - } - - template - struct ptr_match - { - static inline bool test(const PtrType, const void*) - { - return false; - } - }; - - template - struct ptr_match - { - static inline bool test(const variable_node_t* p, const void* ptr) - { - exprtk_debug(("ptr_match::test() - %p <--> %p\n", reinterpret_cast(&(p->ref())), ptr)); - return (&(p->ref()) == ptr); - } - }; - - inline type_ptr get_from_varptr(const void* ptr) const - { - tm_const_itr_t itr = map.begin(); - - while (map.end() != itr) - { - type_ptr ret_ptr = itr->second.second; - - if (ptr_match::test(ret_ptr,ptr)) - { - return ret_ptr; - } - - ++itr; - } - - return type_ptr(0); - } - - inline bool remove(const std::string& symbol_name, const bool delete_node = true) - { - const tm_itr_t itr = map.find(symbol_name); - - if (map.end() != itr) - { - if (delete_node) - { - deleter::process((*itr).second); - } - - map.erase(itr); - --size; - - return true; - } - else - return false; - } - - inline RawType& type_ref(const std::string& symbol_name) - { - struct init_type - { - static inline double set(double) { return (0.0); } - static inline double set(long double) { return (0.0); } - static inline float set(float) { return (0.0f); } - static inline std::string set(std::string) { return std::string(""); } - }; - - static RawType null_type = init_type::set(RawType()); - - const tm_const_itr_t itr = map.find(symbol_name); - - if (map.end() == itr) - return null_type; - else - return itr->second.second->ref(); - } - - inline void clear(const bool delete_node = true) - { - if (!map.empty()) - { - if (delete_node) - { - tm_itr_t itr = map.begin(); - tm_itr_t end = map.end (); - - while (end != itr) - { - deleter::process((*itr).second); - ++itr; - } - } - - map.clear(); - } - - size = 0; - } - - template class Sequence> - inline std::size_t get_list(Sequence,Allocator>& list) const - { - std::size_t count = 0; - - if (!map.empty()) - { - tm_const_itr_t itr = map.begin(); - tm_const_itr_t end = map.end (); - - while (end != itr) - { - list.push_back(std::make_pair((*itr).first,itr->second.second->ref())); - ++itr; - ++count; - } - } - - return count; - } - - template class Sequence> - inline std::size_t get_list(Sequence& vlist) const - { - std::size_t count = 0; - - if (!map.empty()) - { - tm_const_itr_t itr = map.begin(); - tm_const_itr_t end = map.end (); - - while (end != itr) - { - vlist.push_back((*itr).first); - ++itr; - ++count; - } - } - - return count; - } - }; - - typedef details::expression_node* expression_ptr; - typedef typename details::variable_node variable_t; - typedef typename details::vector_holder vector_holder_t; - typedef variable_t* variable_ptr; - #ifndef exprtk_disable_string_capabilities - typedef typename details::stringvar_node stringvar_t; - typedef stringvar_t* stringvar_ptr; - #endif - typedef ifunction function_t; - typedef ivararg_function vararg_function_t; - typedef igeneric_function generic_function_t; - typedef function_t* function_ptr; - typedef vararg_function_t* vararg_function_ptr; - typedef generic_function_t* generic_function_ptr; - - static const std::size_t lut_size = 256; - - // Symbol Table Holder - struct control_block - { - struct st_data - { - type_store variable_store; - type_store function_store; - type_store vararg_function_store; - type_store generic_function_store; - type_store string_function_store; - type_store overload_function_store; - type_store vector_store; - #ifndef exprtk_disable_string_capabilities - type_store stringvar_store; - #endif - - st_data() - { - for (std::size_t i = 0; i < details::reserved_words_size; ++i) - { - reserved_symbol_table_.insert(details::reserved_words[i]); - } - - for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) - { - reserved_symbol_table_.insert(details::reserved_symbols[i]); - } - } - - ~st_data() - { - for (std::size_t i = 0; i < free_function_list_.size(); ++i) - { - delete free_function_list_[i]; - } - } - - inline bool is_reserved_symbol(const std::string& symbol) const - { - return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); - } - - static inline st_data* create() - { - return (new st_data); - } - - static inline void destroy(st_data*& sd) - { - delete sd; - sd = reinterpret_cast(0); - } - - std::list local_symbol_list_; - std::list local_stringvar_list_; - std::set reserved_symbol_table_; - std::vector*> free_function_list_; - }; - - control_block() - : ref_count(1) - , data_(st_data::create()) - , mutability_(e_mutable) - {} - - explicit control_block(st_data* data) - : ref_count(1) - , data_(data) - , mutability_(e_mutable) - {} - - ~control_block() - { - if (data_ && (0 == ref_count)) - { - st_data::destroy(data_); - } - } - - static inline control_block* create() - { - return (new control_block); - } - - template - static inline void destroy(control_block*& cntrl_blck, SymTab* sym_tab) - { - if (cntrl_blck) - { - if ( - (0 != cntrl_blck->ref_count) && - (0 == --cntrl_blck->ref_count) - ) - { - if (sym_tab) - sym_tab->clear(); - - delete cntrl_blck; - } - - cntrl_blck = 0; - } - } - - void set_mutability(const symtab_mutability_type mutability) - { - mutability_ = mutability; - } - - std::size_t ref_count; - st_data* data_; - symtab_mutability_type mutability_; - }; - - public: - - explicit symbol_table(const symtab_mutability_type mutability = e_mutable) - : control_block_(control_block::create()) - { - control_block_->set_mutability(mutability); - clear(); - } - - ~symbol_table() - { - exprtk::details::dump_ptr("~symbol_table", this); - control_block::destroy(control_block_, this); - } - - symbol_table(const symbol_table& st) - { - control_block_ = st.control_block_; - control_block_->ref_count++; - } - - inline symbol_table& operator=(const symbol_table& st) - { - if (this != &st) - { - control_block::destroy(control_block_,reinterpret_cast*>(0)); - - control_block_ = st.control_block_; - control_block_->ref_count++; - } - - return (*this); - } - - inline bool operator==(const symbol_table& st) const - { - return (this == &st) || (control_block_ == st.control_block_); - } - - inline symtab_mutability_type mutability() const - { - return valid() ? control_block_->mutability_ : e_unknown; - } - - inline void clear_variables(const bool delete_node = true) - { - local_data().variable_store.clear(delete_node); - } - - inline void clear_functions() - { - local_data().function_store.clear(); - } - - inline void clear_strings() - { - #ifndef exprtk_disable_string_capabilities - local_data().stringvar_store.clear(); - #endif - } - - inline void clear_vectors() - { - local_data().vector_store.clear(); - } - - inline void clear_local_constants() - { - local_data().local_symbol_list_.clear(); - } - - inline void clear() - { - if (!valid()) return; - clear_variables (); - clear_functions (); - clear_strings (); - clear_vectors (); - clear_local_constants(); - } - - inline std::size_t variable_count() const - { - if (valid()) - return local_data().variable_store.size; - else - return 0; - } - - #ifndef exprtk_disable_string_capabilities - inline std::size_t stringvar_count() const - { - if (valid()) - return local_data().stringvar_store.size; - else - return 0; - } - #endif - - inline std::size_t function_count() const - { - if (valid()) - return local_data().function_store.size; - else - return 0; - } - - inline std::size_t vector_count() const - { - if (valid()) - return local_data().vector_store.size; - else - return 0; - } - - inline variable_ptr get_variable(const std::string& variable_name) const - { - if (!valid()) - return reinterpret_cast(0); - else if (!valid_symbol(variable_name)) - return reinterpret_cast(0); - else - return local_data().variable_store.get(variable_name); - } - - inline variable_ptr get_variable(const T& var_ref) const - { - if (!valid()) - return reinterpret_cast(0); - else - return local_data().variable_store.get_from_varptr( - reinterpret_cast(&var_ref)); - } - - #ifndef exprtk_disable_string_capabilities - inline stringvar_ptr get_stringvar(const std::string& string_name) const - { - if (!valid()) - return reinterpret_cast(0); - else if (!valid_symbol(string_name)) - return reinterpret_cast(0); - else - return local_data().stringvar_store.get(string_name); - } - - inline stringvar_base get_stringvar_base(const std::string& string_name) const - { - static stringvar_base null_stringvar_base("",reinterpret_cast(0)); - if (!valid()) - return null_stringvar_base; - else if (!valid_symbol(string_name)) - return null_stringvar_base; - - stringvar_ptr stringvar = local_data().stringvar_store.get(string_name); - - if (0 == stringvar) - { - return null_stringvar_base; - } - - return stringvar_base(string_name,stringvar); - } - #endif - - inline function_ptr get_function(const std::string& function_name) const - { - if (!valid()) - return reinterpret_cast(0); - else if (!valid_symbol(function_name)) - return reinterpret_cast(0); - else - return local_data().function_store.get(function_name); - } - - inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const - { - if (!valid()) - return reinterpret_cast(0); - else if (!valid_symbol(vararg_function_name)) - return reinterpret_cast(0); - else - return local_data().vararg_function_store.get(vararg_function_name); - } - - inline generic_function_ptr get_generic_function(const std::string& function_name) const - { - if (!valid()) - return reinterpret_cast(0); - else if (!valid_symbol(function_name)) - return reinterpret_cast(0); - else - return local_data().generic_function_store.get(function_name); - } - - inline generic_function_ptr get_string_function(const std::string& function_name) const - { - if (!valid()) - return reinterpret_cast(0); - else if (!valid_symbol(function_name)) - return reinterpret_cast(0); - else - return local_data().string_function_store.get(function_name); - } - - inline generic_function_ptr get_overload_function(const std::string& function_name) const - { - if (!valid()) - return reinterpret_cast(0); - else if (!valid_symbol(function_name)) - return reinterpret_cast(0); - else - return local_data().overload_function_store.get(function_name); - } - - typedef vector_holder_t* vector_holder_ptr; - - inline vector_holder_ptr get_vector(const std::string& vector_name) const - { - if (!valid()) - return reinterpret_cast(0); - else if (!valid_symbol(vector_name)) - return reinterpret_cast(0); - else - return local_data().vector_store.get(vector_name); - } - - inline T& variable_ref(const std::string& symbol_name) - { - static T null_var = T(0); - if (!valid()) - return null_var; - else if (!valid_symbol(symbol_name)) - return null_var; - else - return local_data().variable_store.type_ref(symbol_name); - } - - #ifndef exprtk_disable_string_capabilities - inline std::string& stringvar_ref(const std::string& symbol_name) - { - static std::string null_stringvar; - if (!valid()) - return null_stringvar; - else if (!valid_symbol(symbol_name)) - return null_stringvar; - else - return local_data().stringvar_store.type_ref(symbol_name); - } - #endif - - inline bool is_constant_node(const std::string& symbol_name) const - { - if (!valid()) - return false; - else if (!valid_symbol(symbol_name)) - return false; - else - return local_data().variable_store.is_constant(symbol_name); - } - - #ifndef exprtk_disable_string_capabilities - inline bool is_constant_string(const std::string& symbol_name) const - { - if (!valid()) - return false; - else if (!valid_symbol(symbol_name)) - return false; - else if (!local_data().stringvar_store.symbol_exists(symbol_name)) - return false; - else - return local_data().stringvar_store.is_constant(symbol_name); - } - #endif - - inline bool create_variable(const std::string& variable_name, const T& value = T(0)) - { - if (!valid()) - return false; - else if (!valid_symbol(variable_name)) - return false; - else if (symbol_exists(variable_name)) - return false; - - local_data().local_symbol_list_.push_back(value); - T& t = local_data().local_symbol_list_.back(); - - return add_variable(variable_name,t); - } - - #ifndef exprtk_disable_string_capabilities - inline bool create_stringvar(const std::string& stringvar_name, const std::string& value = std::string("")) - { - if (!valid()) - return false; - else if (!valid_symbol(stringvar_name)) - return false; - else if (symbol_exists(stringvar_name)) - return false; - - local_data().local_stringvar_list_.push_back(value); - std::string& s = local_data().local_stringvar_list_.back(); - - return add_stringvar(stringvar_name,s); - } - #endif - - inline bool add_variable(const std::string& variable_name, T& t, const bool is_constant = false) - { - if (!valid()) - return false; - else if (!valid_symbol(variable_name)) - return false; - else if (symbol_exists(variable_name)) - return false; - else - return local_data().variable_store.add(variable_name, t, is_constant); - } - - inline bool add_constant(const std::string& constant_name, const T& value) - { - if (!valid()) - return false; - else if (!valid_symbol(constant_name)) - return false; - else if (symbol_exists(constant_name)) - return false; - - local_data().local_symbol_list_.push_back(value); - T& t = local_data().local_symbol_list_.back(); - - return add_variable(constant_name, t, true); - } - - #ifndef exprtk_disable_string_capabilities - inline bool add_stringvar(const std::string& stringvar_name, std::string& s, const bool is_constant = false) - { - if (!valid()) - return false; - else if (!valid_symbol(stringvar_name)) - return false; - else if (symbol_exists(stringvar_name)) - return false; - else - return local_data().stringvar_store.add(stringvar_name, s, is_constant); - } - #endif - - inline bool add_function(const std::string& function_name, function_t& function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name)) - return false; - else if (symbol_exists(function_name)) - return false; - else - return local_data().function_store.add(function_name,function); - } - - inline bool add_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) - { - if (!valid()) - return false; - else if (!valid_symbol(vararg_function_name)) - return false; - else if (symbol_exists(vararg_function_name)) - return false; - else - return local_data().vararg_function_store.add(vararg_function_name,vararg_function); - } - - inline bool add_function(const std::string& function_name, generic_function_t& function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name)) - return false; - else if (symbol_exists(function_name)) - return false; - else - { - switch (function.rtrn_type) - { - case generic_function_t::e_rtrn_scalar : - return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? - local_data().generic_function_store.add(function_name,function) : false; - - case generic_function_t::e_rtrn_string : - return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? - local_data().string_function_store.add(function_name,function) : false; - - case generic_function_t::e_rtrn_overload : - return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? - local_data().overload_function_store.add(function_name,function) : false; - } - } - - return false; - } - - #define exprtk_define_freefunction(NN) \ - inline bool add_function(const std::string& function_name, ff##NN##_functor function) \ - { \ - if (!valid()) \ - { return false; } \ - if (!valid_symbol(function_name)) \ - { return false; } \ - if (symbol_exists(function_name)) \ - { return false; } \ - \ - exprtk::ifunction* ifunc = new freefunc##NN(function); \ - \ - local_data().free_function_list_.push_back(ifunc); \ - \ - return add_function(function_name,(*local_data().free_function_list_.back())); \ - } \ - - exprtk_define_freefunction(00) exprtk_define_freefunction(01) - exprtk_define_freefunction(02) exprtk_define_freefunction(03) - exprtk_define_freefunction(04) exprtk_define_freefunction(05) - exprtk_define_freefunction(06) exprtk_define_freefunction(07) - exprtk_define_freefunction(08) exprtk_define_freefunction(09) - exprtk_define_freefunction(10) exprtk_define_freefunction(11) - exprtk_define_freefunction(12) exprtk_define_freefunction(13) - exprtk_define_freefunction(14) exprtk_define_freefunction(15) - - #undef exprtk_define_freefunction - - inline bool add_reserved_function(const std::string& function_name, function_t& function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name,false)) - return false; - else if (symbol_exists(function_name,false)) - return false; - else - return local_data().function_store.add(function_name,function); - } - - inline bool add_reserved_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) - { - if (!valid()) - return false; - else if (!valid_symbol(vararg_function_name,false)) - return false; - else if (symbol_exists(vararg_function_name,false)) - return false; - else - return local_data().vararg_function_store.add(vararg_function_name,vararg_function); - } - - inline bool add_reserved_function(const std::string& function_name, generic_function_t& function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name,false)) - return false; - else if (symbol_exists(function_name,false)) - return false; - else - { - switch (function.rtrn_type) - { - case generic_function_t::e_rtrn_scalar : - return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? - local_data().generic_function_store.add(function_name,function) : false; - - case generic_function_t::e_rtrn_string : - return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? - local_data().string_function_store.add(function_name,function) : false; - - case generic_function_t::e_rtrn_overload : - return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? - local_data().overload_function_store.add(function_name,function) : false; - } - } - - return false; - } - - #define exprtk_define_reserved_function(NN) \ - inline bool add_reserved_function(const std::string& function_name, ff##NN##_functor function) \ - { \ - if (!valid()) \ - { return false; } \ - if (!valid_symbol(function_name,false)) \ - { return false; } \ - if (symbol_exists(function_name,false)) \ - { return false; } \ - \ - exprtk::ifunction* ifunc = new freefunc##NN(function); \ - \ - local_data().free_function_list_.push_back(ifunc); \ - \ - return add_reserved_function(function_name,(*local_data().free_function_list_.back())); \ - } \ - - exprtk_define_reserved_function(00) exprtk_define_reserved_function(01) - exprtk_define_reserved_function(02) exprtk_define_reserved_function(03) - exprtk_define_reserved_function(04) exprtk_define_reserved_function(05) - exprtk_define_reserved_function(06) exprtk_define_reserved_function(07) - exprtk_define_reserved_function(08) exprtk_define_reserved_function(09) - exprtk_define_reserved_function(10) exprtk_define_reserved_function(11) - exprtk_define_reserved_function(12) exprtk_define_reserved_function(13) - exprtk_define_reserved_function(14) exprtk_define_reserved_function(15) - - #undef exprtk_define_reserved_function - - template - inline bool add_vector(const std::string& vector_name, T (&v)[N]) - { - if (!valid()) - return false; - else if (!valid_symbol(vector_name)) - return false; - else if (symbol_exists(vector_name)) - return false; - else - return local_data().vector_store.add(vector_name,v); - } - - inline bool add_vector(const std::string& vector_name, T* v, const std::size_t& v_size) - { - if (!valid()) - return false; - else if (!valid_symbol(vector_name)) - return false; - else if (symbol_exists(vector_name)) - return false; - else if (0 == v_size) - return false; - else - return local_data().vector_store.add(vector_name, v, v_size); - } - - template - inline bool add_vector(const std::string& vector_name, std::vector& v) - { - if (!valid()) - return false; - else if (!valid_symbol(vector_name)) - return false; - else if (symbol_exists(vector_name)) - return false; - else if (0 == v.size()) - return false; - else - return local_data().vector_store.add(vector_name,v); - } - - inline bool add_vector(const std::string& vector_name, exprtk::vector_view& v) - { - if (!valid()) - return false; - else if (!valid_symbol(vector_name)) - return false; - else if (symbol_exists(vector_name)) - return false; - else if (0 == v.size()) - return false; - else - return local_data().vector_store.add(vector_name,v); - } - - inline bool remove_variable(const std::string& variable_name, const bool delete_node = true) - { - if (!valid()) - return false; - else - return local_data().variable_store.remove(variable_name, delete_node); - } - - #ifndef exprtk_disable_string_capabilities - inline bool remove_stringvar(const std::string& string_name) - { - if (!valid()) - return false; - else - return local_data().stringvar_store.remove(string_name); - } - #endif - - inline bool remove_function(const std::string& function_name) - { - if (!valid()) - return false; - else - return local_data().function_store.remove(function_name); - } - - inline bool remove_vararg_function(const std::string& vararg_function_name) - { - if (!valid()) - return false; - else - return local_data().vararg_function_store.remove(vararg_function_name); - } - - inline bool remove_vector(const std::string& vector_name) - { - if (!valid()) - return false; - else - return local_data().vector_store.remove(vector_name); - } - - inline bool add_constants() - { - return add_pi () && - add_epsilon () && - add_infinity() ; - } - - inline bool add_pi() - { - const typename details::numeric::details::number_type::type num_type; - static const T local_pi = details::numeric::details::const_pi_impl(num_type); - return add_constant("pi",local_pi); - } - - inline bool add_epsilon() - { - static const T local_epsilon = details::numeric::details::epsilon_type::value(); - return add_constant("epsilon",local_epsilon); - } - - inline bool add_infinity() - { - static const T local_infinity = std::numeric_limits::infinity(); - return add_constant("inf",local_infinity); - } - - template - inline bool add_package(Package& package) - { - return package.register_package(*this); - } - - template class Sequence> - inline std::size_t get_variable_list(Sequence,Allocator>& vlist) const - { - if (!valid()) - return 0; - else - return local_data().variable_store.get_list(vlist); - } - - template class Sequence> - inline std::size_t get_variable_list(Sequence& vlist) const - { - if (!valid()) - return 0; - else - return local_data().variable_store.get_list(vlist); - } - - #ifndef exprtk_disable_string_capabilities - template class Sequence> - inline std::size_t get_stringvar_list(Sequence,Allocator>& svlist) const - { - if (!valid()) - return 0; - else - return local_data().stringvar_store.get_list(svlist); - } - - template class Sequence> - inline std::size_t get_stringvar_list(Sequence& svlist) const - { - if (!valid()) - return 0; - else - return local_data().stringvar_store.get_list(svlist); - } - #endif - - template class Sequence> - inline std::size_t get_vector_list(Sequence& vec_list) const - { - if (!valid()) - return 0; - else - return local_data().vector_store.get_list(vec_list); - } - - template class Sequence> - inline std::size_t get_function_list(Sequence& function_list) const - { - if (!valid()) - return 0; - - std::vector function_names; - std::size_t count = 0; - - count += local_data().function_store .get_list(function_names); - count += local_data().vararg_function_store .get_list(function_names); - count += local_data().generic_function_store .get_list(function_names); - count += local_data().string_function_store .get_list(function_names); - count += local_data().overload_function_store.get_list(function_names); - - std::set function_set; - - for (std::size_t i = 0; i < function_names.size(); ++i) - { - function_set.insert(function_names[i]); - } - - std::copy(function_set.begin(), function_set.end(), - std::back_inserter(function_list)); - - return count; - } - - inline std::vector get_function_list() const - { - std::vector result; - get_function_list(result); - return result; - } - - inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const - { - /* - Function will return true if symbol_name exists as either a - reserved symbol, variable, stringvar, vector or function name - in any of the type stores. - */ - if (!valid()) - return false; - else if (local_data().variable_store.symbol_exists(symbol_name)) - return true; - #ifndef exprtk_disable_string_capabilities - else if (local_data().stringvar_store.symbol_exists(symbol_name)) - return true; - #endif - else if (local_data().vector_store.symbol_exists(symbol_name)) - return true; - else if (local_data().function_store.symbol_exists(symbol_name)) - return true; - else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) - return true; - else - return false; - } - - inline bool is_variable(const std::string& variable_name) const - { - if (!valid()) - return false; - else - return local_data().variable_store.symbol_exists(variable_name); - } - - #ifndef exprtk_disable_string_capabilities - inline bool is_stringvar(const std::string& stringvar_name) const - { - if (!valid()) - return false; - else - return local_data().stringvar_store.symbol_exists(stringvar_name); - } - - inline bool is_conststr_stringvar(const std::string& symbol_name) const - { - if (!valid()) - return false; - else if (!valid_symbol(symbol_name)) - return false; - else if (!local_data().stringvar_store.symbol_exists(symbol_name)) - return false; - - return ( - local_data().stringvar_store.symbol_exists(symbol_name) || - local_data().stringvar_store.is_constant (symbol_name) - ); - } - #endif - - inline bool is_function(const std::string& function_name) const - { - if (!valid()) - return false; - else - return local_data().function_store.symbol_exists(function_name); - } - - inline bool is_vararg_function(const std::string& vararg_function_name) const - { - if (!valid()) - return false; - else - return local_data().vararg_function_store.symbol_exists(vararg_function_name); - } - - inline bool is_vector(const std::string& vector_name) const - { - if (!valid()) - return false; - else - return local_data().vector_store.symbol_exists(vector_name); - } - - inline std::string get_variable_name(const expression_ptr& ptr) const - { - return local_data().variable_store.entity_name(ptr); - } - - inline std::string get_vector_name(const vector_holder_ptr& ptr) const - { - return local_data().vector_store.entity_name(ptr); - } - - #ifndef exprtk_disable_string_capabilities - inline std::string get_stringvar_name(const expression_ptr& ptr) const - { - return local_data().stringvar_store.entity_name(ptr); - } - - inline std::string get_conststr_stringvar_name(const expression_ptr& ptr) const - { - return local_data().stringvar_store.entity_name(ptr); - } - #endif - - inline bool valid() const - { - // Symbol table sanity check. - return control_block_ && control_block_->data_; - } - - inline void load_from(const symbol_table& st) - { - { - std::vector name_list; - - st.local_data().function_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - exprtk::ifunction& ifunc = *st.get_function(name_list[i]); - add_function(name_list[i],ifunc); - } - } - } - - { - std::vector name_list; - - st.local_data().vararg_function_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - exprtk::ivararg_function& ivafunc = *st.get_vararg_function(name_list[i]); - add_function(name_list[i],ivafunc); - } - } - } - - { - std::vector name_list; - - st.local_data().generic_function_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - exprtk::igeneric_function& ifunc = *st.get_generic_function(name_list[i]); - add_function(name_list[i],ifunc); - } - } - } - - { - std::vector name_list; - - st.local_data().string_function_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - exprtk::igeneric_function& ifunc = *st.get_string_function(name_list[i]); - add_function(name_list[i],ifunc); - } - } - } - - { - std::vector name_list; - - st.local_data().overload_function_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - exprtk::igeneric_function& ifunc = *st.get_overload_function(name_list[i]); - add_function(name_list[i],ifunc); - } - } - } - } - - inline void load_variables_from(const symbol_table& st) - { - std::vector name_list; - - st.local_data().variable_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - T& variable = st.get_variable(name_list[i])->ref(); - add_variable(name_list[i], variable); - } - } - } - - inline void load_vectors_from(const symbol_table& st) - { - std::vector name_list; - - st.local_data().vector_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - vector_holder_t& vecholder = *st.get_vector(name_list[i]); - add_vector(name_list[i], vecholder.data(), vecholder.size()); - } - } - } - - private: - - inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const - { - if (symbol.empty()) - return false; - else if (!details::is_letter(symbol[0])) - return false; - else if (symbol.size() > 1) - { - for (std::size_t i = 1; i < symbol.size(); ++i) - { - if ( - !details::is_letter_or_digit(symbol[i]) && - ('_' != symbol[i]) - ) - { - if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) - continue; - else - return false; - } - } - } - - return (check_reserved_symb) ? (!local_data().is_reserved_symbol(symbol)) : true; - } - - inline bool valid_function(const std::string& symbol) const - { - if (symbol.empty()) - return false; - else if (!details::is_letter(symbol[0])) - return false; - else if (symbol.size() > 1) - { - for (std::size_t i = 1; i < symbol.size(); ++i) - { - if ( - !details::is_letter_or_digit(symbol[i]) && - ('_' != symbol[i]) - ) - { - if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) - continue; - else - return false; - } - } - } - - return true; - } - - typedef typename control_block::st_data local_data_t; - - inline local_data_t& local_data() - { - return *(control_block_->data_); - } - - inline const local_data_t& local_data() const - { - return *(control_block_->data_); - } - - control_block* control_block_; - - friend class parser; - }; // class symbol_table - - template - class function_compositor; - - template - class expression - { - private: - - typedef details::expression_node* expression_ptr; - typedef details::vector_holder* vector_holder_ptr; - typedef std::vector > symtab_list_t; - - struct control_block - { - enum data_type - { - e_unknown , - e_expr , - e_vecholder, - e_data , - e_vecdata , - e_string - }; - - static std::string to_str(data_type dt) - { - switch(dt) - { - case e_unknown : return "e_unknown "; - case e_expr : return "e_expr" ; - case e_vecholder : return "e_vecholder"; - case e_data : return "e_data" ; - case e_vecdata : return "e_vecdata" ; - case e_string : return "e_string" ; - } - - return ""; - } - - struct data_pack - { - data_pack() - : pointer(0) - , type(e_unknown) - , size(0) - {} - - data_pack(void* ptr, const data_type dt, const std::size_t sz = 0) - : pointer(ptr) - , type(dt) - , size(sz) - {} - - void* pointer; - data_type type; - std::size_t size; - }; - - typedef std::vector local_data_list_t; - typedef results_context results_context_t; - typedef control_block* cntrl_blck_ptr_t; - - control_block() - : ref_count(0) - , expr (0) - , results (0) - , retinv_null(false) - , return_invoked(&retinv_null) - {} - - explicit control_block(expression_ptr e) - : ref_count(1) - , expr (e) - , results (0) - , retinv_null(false) - , return_invoked(&retinv_null) - {} - - ~control_block() - { - if (expr && details::branch_deletable(expr)) - { - destroy_node(expr); - } - - if (!local_data_list.empty()) - { - for (std::size_t i = 0; i < local_data_list.size(); ++i) - { - switch (local_data_list[i].type) - { - case e_expr : delete reinterpret_cast(local_data_list[i].pointer); - break; - - case e_vecholder : delete reinterpret_cast(local_data_list[i].pointer); - break; - - case e_data : delete reinterpret_cast(local_data_list[i].pointer); - break; - - case e_vecdata : delete [] reinterpret_cast(local_data_list[i].pointer); - break; - - case e_string : delete reinterpret_cast(local_data_list[i].pointer); - break; - - default : break; - } - } - } - - if (results) - { - delete results; - } - } - - static inline cntrl_blck_ptr_t create(expression_ptr e) - { - return new control_block(e); - } - - static inline void destroy(cntrl_blck_ptr_t& cntrl_blck) - { - if (cntrl_blck) - { - if ( - (0 != cntrl_blck->ref_count) && - (0 == --cntrl_blck->ref_count) - ) - { - delete cntrl_blck; - } - - cntrl_blck = 0; - } - } - - std::size_t ref_count; - expression_ptr expr; - local_data_list_t local_data_list; - results_context_t* results; - bool retinv_null; - bool* return_invoked; - - friend class function_compositor; - }; - - public: - - expression() - : control_block_(0) - { - set_expression(new details::null_node()); - } - - expression(const expression& e) - : control_block_ (e.control_block_ ) - , symbol_table_list_(e.symbol_table_list_) - { - control_block_->ref_count++; - } - - explicit expression(const symbol_table& symbol_table) - : control_block_(0) - { - set_expression(new details::null_node()); - symbol_table_list_.push_back(symbol_table); - } - - inline expression& operator=(const expression& e) - { - if (this != &e) - { - if (control_block_) - { - if ( - (0 != control_block_->ref_count) && - (0 == --control_block_->ref_count) - ) - { - delete control_block_; - } - - control_block_ = 0; - } - - control_block_ = e.control_block_; - control_block_->ref_count++; - symbol_table_list_ = e.symbol_table_list_; - } - - return *this; - } - - inline bool operator==(const expression& e) const - { - return (this == &e); - } - - inline bool operator!() const - { - return ( - (0 == control_block_ ) || - (0 == control_block_->expr) - ); - } - - inline expression& release() - { - exprtk::details::dump_ptr("expression::release", this); - control_block::destroy(control_block_); - - return (*this); - } - - ~expression() - { - control_block::destroy(control_block_); - } - - inline T value() const - { - assert(control_block_ ); - assert(control_block_->expr); - - return control_block_->expr->value(); - } - - inline T operator() () const - { - return value(); - } - - inline operator T() const - { - return value(); - } - - inline operator bool() const - { - return details::is_true(value()); - } - - inline bool register_symbol_table(symbol_table& st) - { - for (std::size_t i = 0; i < symbol_table_list_.size(); ++i) - { - if (st == symbol_table_list_[i]) - { - return false; - } - } - - symbol_table_list_.push_back(st); - return true; - } - - inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const - { - return symbol_table_list_[index]; - } - - inline symbol_table& get_symbol_table(const std::size_t& index = 0) - { - return symbol_table_list_[index]; - } - - std::size_t num_symbol_tables() const - { - return symbol_table_list_.size(); - } - - typedef results_context results_context_t; - - inline const results_context_t& results() const - { - if (control_block_->results) - return (*control_block_->results); - else - { - static const results_context_t null_results; - return null_results; - } - } - - inline bool return_invoked() const - { - return (*control_block_->return_invoked); - } - - private: - - inline symtab_list_t get_symbol_table_list() const - { - return symbol_table_list_; - } - - inline void set_expression(const expression_ptr expr) - { - if (expr) - { - if (control_block_) - { - if (0 == --control_block_->ref_count) - { - delete control_block_; - } - } - - control_block_ = control_block::create(expr); - } - } - - inline void register_local_var(expression_ptr expr) - { - if (expr) - { - if (control_block_) - { - control_block_-> - local_data_list.push_back( - typename expression::control_block:: - data_pack(reinterpret_cast(expr), - control_block::e_expr)); - } - } - } - - inline void register_local_var(vector_holder_ptr vec_holder) - { - if (vec_holder) - { - if (control_block_) - { - control_block_-> - local_data_list.push_back( - typename expression::control_block:: - data_pack(reinterpret_cast(vec_holder), - control_block::e_vecholder)); - } - } - } - - inline void register_local_data(void* data, const std::size_t& size = 0, const std::size_t data_mode = 0) - { - if (data) - { - if (control_block_) - { - typename control_block::data_type dt = control_block::e_data; - - switch (data_mode) - { - case 0 : dt = control_block::e_data; break; - case 1 : dt = control_block::e_vecdata; break; - case 2 : dt = control_block::e_string; break; - } - - control_block_-> - local_data_list.push_back( - typename expression::control_block:: - data_pack(reinterpret_cast(data), dt, size)); - } - } - } - - inline const typename control_block::local_data_list_t& local_data_list() - { - if (control_block_) - { - return control_block_->local_data_list; - } - else - { - static typename control_block::local_data_list_t null_local_data_list; - return null_local_data_list; - } - } - - inline void register_return_results(results_context_t* rc) - { - if (control_block_ && rc) - { - control_block_->results = rc; - } - } - - inline void set_retinvk(bool* retinvk_ptr) - { - if (control_block_) - { - control_block_->return_invoked = retinvk_ptr; - } - } - - control_block* control_block_; - symtab_list_t symbol_table_list_; - - friend class parser; - friend class expression_helper; - friend class function_compositor; - template - friend bool is_valid(const expression& expr); - }; // class expression - - template - class expression_helper - { - public: - - enum node_types - { - e_literal, - e_variable, - e_string, - e_unary, - e_binary, - e_function, - e_vararg, - e_null, - e_assert, - e_sf3ext, - e_sf4ext - }; - - static inline bool is_literal(const expression& expr) - { - return expr.control_block_ && details::is_literal_node(expr.control_block_->expr); - } - - static inline bool is_variable(const expression& expr) - { - return expr.control_block_ && details::is_variable_node(expr.control_block_->expr); - } - - static inline bool is_string(const expression& expr) - { - return expr.control_block_ && details::is_generally_string_node(expr.control_block_->expr); - } - - static inline bool is_unary(const expression& expr) - { - return expr.control_block_ && details::is_unary_node(expr.control_block_->expr); - } - - static inline bool is_binary(const expression& expr) - { - return expr.control_block_ && details::is_binary_node(expr.control_block_->expr); - } - - static inline bool is_function(const expression& expr) - { - return expr.control_block_ && details::is_function(expr.control_block_->expr); - } - - static inline bool is_vararg(const expression& expr) - { - return expr.control_block_ && details::is_vararg_node(expr.control_block_->expr); - } - - static inline bool is_null(const expression& expr) - { - return expr.control_block_ && details::is_null_node(expr.control_block_->expr); - } - - static inline bool is_assert(const expression& expr) - { - return expr.control_block_ && details::is_assert_node(expr.control_block_->expr); - } - - static inline bool is_sf3ext(const expression& expr) - { - return expr.control_block_ && details::is_sf3ext_node(expr.control_block_->expr); - } - - static inline bool is_sf4ext(const expression& expr) - { - return expr.control_block_ && details::is_sf4ext_node(expr.control_block_->expr); - } - - static inline bool is_type(const expression& expr, const node_types node_type) - { - if (0 == expr.control_block_) - { - return false; - } - - switch (node_type) - { - case e_literal : return is_literal_node(expr); - case e_variable : return is_variable (expr); - case e_string : return is_string (expr); - case e_unary : return is_unary (expr); - case e_binary : return is_binary (expr); - case e_function : return is_function (expr); - case e_null : return is_null (expr); - case e_assert : return is_assert (expr); - case e_sf3ext : return is_sf3ext (expr); - case e_sf4ext : return is_sf4ext (expr); - }; - - return false; - } - - static inline bool match_type_sequence(const expression& expr, const std::vector& type_seq) - { - if ((0 == expr.control_block_) || !is_vararg(expr)) - { - return false; - } - - typedef details::vararg_node > mo_vararg_t; - - mo_vararg_t* vnode = dynamic_cast(expr.control_block_->expr); - - if ( - (0 == vnode) || - type_seq.empty() || - (vnode->size() < type_seq.size()) - ) - { - return false; - } - - for (std::size_t i = 0; i < type_seq.size(); ++i) - { - assert((*vnode)[i]); - - switch(type_seq[i]) - { - case e_literal : { if (details::is_literal_node ((*vnode)[i])) continue; } break; - case e_variable : { if (details::is_variable_node ((*vnode)[i])) continue; } break; - case e_string : { if (details::is_generally_string_node((*vnode)[i])) continue; } break; - case e_unary : { if (details::is_unary_node ((*vnode)[i])) continue; } break; - case e_binary : { if (details::is_binary_node ((*vnode)[i])) continue; } break; - case e_function : { if (details::is_function ((*vnode)[i])) continue; } break; - case e_null : { if (details::is_null_node ((*vnode)[i])) continue; } break; - case e_assert : { if (details::is_assert_node ((*vnode)[i])) continue; } break; - case e_sf3ext : { if (details::is_sf3ext_node ((*vnode)[i])) continue; } break; - case e_sf4ext : { if (details::is_sf4ext_node ((*vnode)[i])) continue; } break; - case e_vararg : break; - } - - return false; - } - - return true; - } - }; - - template - inline bool is_valid(const expression& expr) - { - return expr.control_block_ && !expression_helper::is_null(expr); - } - - namespace parser_error - { - enum error_mode - { - e_unknown = 0, - e_syntax = 1, - e_token = 2, - e_numeric = 4, - e_symtab = 5, - e_lexer = 6, - e_synthesis = 7, - e_helper = 8, - e_parser = 9 - }; - - struct type - { - type() - : mode(parser_error::e_unknown) - , line_no (0) - , column_no(0) - {} - - lexer::token token; - error_mode mode; - std::string diagnostic; - std::string src_location; - std::string error_line; - std::size_t line_no; - std::size_t column_no; - }; - - inline type make_error(const error_mode mode, - const std::string& diagnostic = "", - const std::string& src_location = "") - { - type t; - t.mode = mode; - t.token.type = lexer::token::e_error; - t.diagnostic = diagnostic; - t.src_location = src_location; - exprtk_debug(("%s\n", diagnostic .c_str())); - return t; - } - - inline type make_error(const error_mode mode, - const lexer::token& tk, - const std::string& diagnostic = "", - const std::string& src_location = "") - { - type t; - t.mode = mode; - t.token = tk; - t.diagnostic = diagnostic; - t.src_location = src_location; - exprtk_debug(("%s\n", diagnostic .c_str())); - return t; - } - - inline std::string to_str(error_mode mode) - { - switch (mode) - { - case e_unknown : return std::string("Unknown Error"); - case e_syntax : return std::string("Syntax Error" ); - case e_token : return std::string("Token Error" ); - case e_numeric : return std::string("Numeric Error"); - case e_symtab : return std::string("Symbol Error" ); - case e_lexer : return std::string("Lexer Error" ); - case e_helper : return std::string("Helper Error" ); - case e_parser : return std::string("Parser Error" ); - default : return std::string("Unknown Error"); - } - } - - inline bool update_error(type& error, const std::string& expression) - { - if ( - expression.empty() || - (error.token.position > expression.size()) || - (std::numeric_limits::max() == error.token.position) - ) - { - return false; - } - - std::size_t error_line_start = 0; - - for (std::size_t i = error.token.position; i > 0; --i) - { - const details::char_t c = expression[i]; - - if (('\n' == c) || ('\r' == c)) - { - error_line_start = i + 1; - break; - } - } - - std::size_t next_nl_position = std::min(expression.size(), - expression.find_first_of('\n',error.token.position + 1)); - - error.column_no = error.token.position - error_line_start; - error.error_line = expression.substr(error_line_start, - next_nl_position - error_line_start); - - error.line_no = 0; - - for (std::size_t i = 0; i < next_nl_position; ++i) - { - if ('\n' == expression[i]) - ++error.line_no; - } - - return true; - } - - inline void dump_error(const type& error) - { - printf("Position: %02d Type: [%s] Msg: %s\n", - static_cast(error.token.position), - exprtk::parser_error::to_str(error.mode).c_str(), - error.diagnostic.c_str()); - } - } - - namespace details - { - template - inline void disable_type_checking(Parser& p) - { - p.state_.type_check_enabled = false; - } - } - - template - class parser : public lexer::parser_helper - { - private: - - enum precedence_level - { - e_level00, e_level01, e_level02, e_level03, e_level04, - e_level05, e_level06, e_level07, e_level08, e_level09, - e_level10, e_level11, e_level12, e_level13, e_level14 - }; - - typedef const T& cref_t; - typedef const T const_t; - typedef ifunction F; - typedef ivararg_function VAF; - typedef igeneric_function GF; - typedef ifunction ifunction_t; - typedef ivararg_function ivararg_function_t; - typedef igeneric_function igeneric_function_t; - typedef details::expression_node expression_node_t; - typedef details::literal_node literal_node_t; - typedef details::unary_node unary_node_t; - typedef details::binary_node binary_node_t; - typedef details::trinary_node trinary_node_t; - typedef details::quaternary_node quaternary_node_t; - typedef details::conditional_node conditional_node_t; - typedef details::cons_conditional_node cons_conditional_node_t; - typedef details::while_loop_node while_loop_node_t; - typedef details::repeat_until_loop_node repeat_until_loop_node_t; - typedef details::for_loop_node for_loop_node_t; - typedef details::while_loop_rtc_node while_loop_rtc_node_t; - typedef details::repeat_until_loop_rtc_node repeat_until_loop_rtc_node_t; - typedef details::for_loop_rtc_node for_loop_rtc_node_t; - #ifndef exprtk_disable_break_continue - typedef details::while_loop_bc_node while_loop_bc_node_t; - typedef details::repeat_until_loop_bc_node repeat_until_loop_bc_node_t; - typedef details::for_loop_bc_node for_loop_bc_node_t; - typedef details::while_loop_bc_rtc_node while_loop_bc_rtc_node_t; - typedef details::repeat_until_loop_bc_rtc_node repeat_until_loop_bc_rtc_node_t; - typedef details::for_loop_bc_rtc_node for_loop_bc_rtc_node_t; - #endif - typedef details::switch_node switch_node_t; - typedef details::variable_node variable_node_t; - typedef details::vector_elem_node vector_elem_node_t; - typedef details::vector_celem_node vector_celem_node_t; - typedef details::vector_elem_rtc_node vector_elem_rtc_node_t; - typedef details::vector_celem_rtc_node vector_celem_rtc_node_t; - typedef details::rebasevector_elem_node rebasevector_elem_node_t; - typedef details::rebasevector_celem_node rebasevector_celem_node_t; - typedef details::rebasevector_elem_rtc_node rebasevector_elem_rtc_node_t; - typedef details::rebasevector_celem_rtc_node rebasevector_celem_rtc_node_t; - typedef details::vector_node vector_node_t; - typedef details::vector_size_node vector_size_node_t; - typedef details::range_pack range_t; - #ifndef exprtk_disable_string_capabilities - typedef details::stringvar_node stringvar_node_t; - typedef details::string_literal_node string_literal_node_t; - typedef details::string_range_node string_range_node_t; - typedef details::const_string_range_node const_string_range_node_t; - typedef details::generic_string_range_node generic_string_range_node_t; - typedef details::string_concat_node string_concat_node_t; - typedef details::assignment_string_node assignment_string_node_t; - typedef details::assignment_string_range_node assignment_string_range_node_t; - typedef details::conditional_string_node conditional_string_node_t; - typedef details::cons_conditional_str_node cons_conditional_str_node_t; - #endif - typedef details::assignment_node assignment_node_t; - typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; - typedef details::assignment_vec_elem_rtc_node assignment_vec_elem_rtc_node_t; - typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; - typedef details::assignment_rebasevec_elem_rtc_node assignment_rebasevec_elem_rtc_node_t; - typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; - typedef details::assignment_vec_node assignment_vec_node_t; - typedef details::assignment_vecvec_node assignment_vecvec_node_t; - typedef details::conditional_vector_node conditional_vector_node_t; - typedef details::scand_node scand_node_t; - typedef details::scor_node scor_node_t; - typedef lexer::token token_t; - typedef expression_node_t* expression_node_ptr; - typedef expression expression_t; - typedef symbol_table symbol_table_t; - typedef typename expression::symtab_list_t symbol_table_list_t; - typedef details::vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - - typedef typename details::functor_t functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; - - typedef details::operator_type operator_t; - - typedef std::map unary_op_map_t; - typedef std::map binary_op_map_t; - typedef std::map trinary_op_map_t; - - typedef std::map > sf3_map_t; - typedef std::map > sf4_map_t; - - typedef std::map inv_binary_op_map_t; - typedef std::multimap base_ops_map_t; - typedef std::set disabled_func_set_t; - - typedef details::T0oT1_define vov_t; - typedef details::T0oT1_define cov_t; - typedef details::T0oT1_define voc_t; - - typedef details::T0oT1oT2_define vovov_t; - typedef details::T0oT1oT2_define vovoc_t; - typedef details::T0oT1oT2_define vocov_t; - typedef details::T0oT1oT2_define covov_t; - typedef details::T0oT1oT2_define covoc_t; - typedef details::T0oT1oT2_define cocov_t; - typedef details::T0oT1oT2_define vococ_t; - - typedef details::T0oT1oT2oT3_define vovovov_t; - typedef details::T0oT1oT2oT3_define vovovoc_t; - typedef details::T0oT1oT2oT3_define vovocov_t; - typedef details::T0oT1oT2oT3_define vocovov_t; - typedef details::T0oT1oT2oT3_define covovov_t; - - typedef details::T0oT1oT2oT3_define covocov_t; - typedef details::T0oT1oT2oT3_define vocovoc_t; - typedef details::T0oT1oT2oT3_define covovoc_t; - typedef details::T0oT1oT2oT3_define vococov_t; - - typedef results_context results_context_t; - - typedef parser_helper prsrhlpr_t; - - struct scope_element - { - enum element_type - { - e_none , - e_literal , - e_variable, - e_vector , - e_vecelem , - e_string - }; - - typedef details::vector_holder vector_holder_t; - typedef literal_node_t* literal_node_ptr; - typedef variable_node_t* variable_node_ptr; - typedef vector_holder_t* vector_holder_ptr; - typedef expression_node_t* expression_node_ptr; - #ifndef exprtk_disable_string_capabilities - typedef stringvar_node_t* stringvar_node_ptr; - #endif - - scope_element() - : name("???") - , size (std::numeric_limits::max()) - , index(std::numeric_limits::max()) - , depth(std::numeric_limits::max()) - , ref_count(0) - , ip_index (0) - , type (e_none) - , active (false) - , data (0) - , var_node (0) - , vec_node (0) - #ifndef exprtk_disable_string_capabilities - , str_node(0) - #endif - {} - - bool operator < (const scope_element& se) const - { - if (ip_index < se.ip_index) - return true; - else if (ip_index > se.ip_index) - return false; - else if (depth < se.depth) - return true; - else if (depth > se.depth) - return false; - else if (index < se.index) - return true; - else if (index > se.index) - return false; - else - return (name < se.name); - } - - void clear() - { - name = "???"; - size = std::numeric_limits::max(); - index = std::numeric_limits::max(); - depth = std::numeric_limits::max(); - type = e_none; - active = false; - ref_count = 0; - ip_index = 0; - data = 0; - var_node = 0; - vec_node = 0; - #ifndef exprtk_disable_string_capabilities - str_node = 0; - #endif - } - - std::string name; - std::size_t size; - std::size_t index; - std::size_t depth; - std::size_t ref_count; - std::size_t ip_index; - element_type type; - bool active; - void* data; - expression_node_ptr var_node; - vector_holder_ptr vec_node; - #ifndef exprtk_disable_string_capabilities - stringvar_node_ptr str_node; - #endif - }; - - class scope_element_manager - { - public: - - typedef expression_node_t* expression_node_ptr; - typedef variable_node_t* variable_node_ptr; - typedef parser parser_t; - - explicit scope_element_manager(parser& p) - : parser_(p) - , input_param_cnt_(0) - {} - - inline std::size_t size() const - { - return element_.size(); - } - - inline bool empty() const - { - return element_.empty(); - } - - inline scope_element& get_element(const std::size_t& index) - { - if (index < element_.size()) - return element_[index]; - else - return null_element_; - } - - inline scope_element& get_element(const std::string& var_name, - const std::size_t index = std::numeric_limits::max()) - { - const std::size_t current_depth = parser_.state_.scope_depth; - - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& se = element_[i]; - - if (se.depth > current_depth) - continue; - else if ( - details::imatch(se.name, var_name) && - (se.index == index) - ) - return se; - } - - return null_element_; - } - - inline scope_element& get_active_element(const std::string& var_name, - const std::size_t index = std::numeric_limits::max()) - { - const std::size_t current_depth = parser_.state_.scope_depth; - - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& se = element_[i]; - - if (se.depth > current_depth) - continue; - else if ( - details::imatch(se.name, var_name) && - (se.index == index) && - (se.active) - ) - return se; - } - - return null_element_; - } - - inline bool add_element(const scope_element& se) - { - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& cse = element_[i]; - - if ( - details::imatch(cse.name, se.name) && - (cse.depth <= se.depth) && - (cse.index == se.index) && - (cse.size == se.size ) && - (cse.type == se.type ) && - (cse.active) - ) - return false; - } - - element_.push_back(se); - std::sort(element_.begin(),element_.end()); - - return true; - } - - inline void deactivate(const std::size_t& scope_depth) - { - exprtk_debug(("deactivate() - Scope depth: %d\n", - static_cast(parser_.state_.scope_depth))); - - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& se = element_[i]; - - if (se.active && (se.depth >= scope_depth)) - { - exprtk_debug(("deactivate() - element[%02d] '%s'\n", - static_cast(i), - se.name.c_str())); - - se.active = false; - } - } - } - - inline void free_element(scope_element& se) - { - exprtk_debug(("free_element() - se[%s]\n", se.name.c_str())); - - switch (se.type) - { - case scope_element::e_literal : delete reinterpret_cast(se.data); - delete se.var_node; - break; - - case scope_element::e_variable : delete reinterpret_cast(se.data); - delete se.var_node; - break; - - case scope_element::e_vector : delete[] reinterpret_cast(se.data); - delete se.vec_node; - break; - - case scope_element::e_vecelem : delete se.var_node; - break; - - #ifndef exprtk_disable_string_capabilities - case scope_element::e_string : delete reinterpret_cast(se.data); - delete se.str_node; - break; - #endif - - default : return; - } - - se.clear(); - } - - inline void cleanup() - { - for (std::size_t i = 0; i < element_.size(); ++i) - { - free_element(element_[i]); - } - - element_.clear(); - - input_param_cnt_ = 0; - } - - inline std::size_t next_ip_index() - { - return ++input_param_cnt_; - } - - inline expression_node_ptr get_variable(const T& v) - { - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& se = element_[i]; - - if ( - se.active && - se.var_node && - details::is_variable_node(se.var_node) - ) - { - variable_node_ptr vn = reinterpret_cast(se.var_node); - - if (&(vn->ref()) == (&v)) - { - return se.var_node; - } - } - } - - return expression_node_ptr(0); - } - - inline std::string get_vector_name(const T* data) - { - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& se = element_[i]; - - if ( - se.active && - se.vec_node && - (se.vec_node->data() == data) - ) - { - return se.name; - } - } - - return "neo-vector"; - } - - private: - - scope_element_manager(const scope_element_manager&) exprtk_delete; - scope_element_manager& operator=(const scope_element_manager&) exprtk_delete; - - parser_t& parser_; - std::vector element_; - scope_element null_element_; - std::size_t input_param_cnt_; - }; - - class scope_handler - { - public: - - typedef parser parser_t; - - explicit scope_handler(parser& p) - : parser_(p) - { - parser_.state_.scope_depth++; - #ifdef exprtk_enable_debugging - const std::string depth(2 * parser_.state_.scope_depth,'-'); - exprtk_debug(("%s> Scope Depth: %02d\n", - depth.c_str(), - static_cast(parser_.state_.scope_depth))); - #endif - } - - ~scope_handler() - { - parser_.sem_.deactivate(parser_.state_.scope_depth); - parser_.state_.scope_depth--; - #ifdef exprtk_enable_debugging - const std::string depth(2 * parser_.state_.scope_depth,'-'); - exprtk_debug(("<%s Scope Depth: %02d\n", - depth.c_str(), - static_cast(parser_.state_.scope_depth))); - #endif - } - - private: - - scope_handler(const scope_handler&) exprtk_delete; - scope_handler& operator=(const scope_handler&) exprtk_delete; - - parser_t& parser_; - }; - - template - struct halfopen_range_policy - { - static inline bool is_within(const T_& v, const T_& begin, const T_& end) - { - assert(begin <= end); - return (begin <= v) && (v < end); - } - - static inline bool is_less(const T_& v, const T_& begin) - { - return (v < begin); - } - - static inline bool is_greater(const T_& v, const T_& end) - { - return (end <= v); - } - - static inline bool end_inclusive() - { - return false; - } - }; - - template - struct closed_range_policy - { - static inline bool is_within(const T_& v, const T_& begin, const T_& end) - { - assert(begin <= end); - return (begin <= v) && (v <= end); - } - - static inline bool is_less(const T_& v, const T_& begin) - { - return (v < begin); - } - - static inline bool is_greater(const T_& v, const T_& end) - { - return (end < v); - } - - static inline bool end_inclusive() - { - return true; - } - }; - - template > - class interval_container_t - { - public: - - typedef IntervalPointType interval_point_t; - typedef std::pair interval_t; - typedef std::map interval_map_t; - typedef typename interval_map_t::const_iterator interval_map_citr_t; - - std::size_t size() const - { - return interval_map_.size(); - } - - void reset() - { - interval_map_.clear(); - } - - bool in_interval(const interval_point_t point, interval_t& interval) const - { - interval_map_citr_t itr = RangePolicy::end_inclusive() ? - interval_map_.lower_bound(point): - interval_map_.upper_bound(point); - - for (; itr != interval_map_.end(); ++itr) - { - const interval_point_t& begin = itr->second.first; - const interval_point_t& end = itr->second.second; - - if (RangePolicy::is_within(point, begin, end)) - { - interval = interval_t(begin,end); - return true; - } - else if (RangePolicy::is_greater(point, end)) - { - break; - } - } - - return false; - } - - bool in_interval(const interval_point_t point) const - { - interval_t interval; - return in_interval(point,interval); - } - - bool add_interval(const interval_point_t begin, const interval_point_t end) - { - if ((end <= begin) || in_interval(begin) || in_interval(end)) - { - return false; - } - - interval_map_[end] = std::make_pair(begin, end); - - return true; - } - - bool add_interval(const interval_t interval) - { - return add_interval(interval.first, interval.second); - } - - private: - - interval_map_t interval_map_; - }; - - class stack_limit_handler - { - public: - - typedef parser parser_t; - - explicit stack_limit_handler(parser& p) - : parser_(p) - , limit_exceeded_(false) - { - if (++parser_.state_.stack_depth > parser_.settings_.max_stack_depth_) - { - limit_exceeded_ = true; - parser_.set_error(make_error( - parser_error::e_parser, - "ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + - " exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), - exprtk_error_location)); - } - } - - ~stack_limit_handler() - { - assert(parser_.state_.stack_depth > 0); - parser_.state_.stack_depth--; - } - - bool operator!() - { - return limit_exceeded_; - } - - private: - - stack_limit_handler(const stack_limit_handler&) exprtk_delete; - stack_limit_handler& operator=(const stack_limit_handler&) exprtk_delete; - - parser_t& parser_; - bool limit_exceeded_; - }; - - struct symtab_store - { - symbol_table_list_t symtab_list_; - - typedef typename symbol_table_t::local_data_t local_data_t; - typedef typename symbol_table_t::variable_ptr variable_ptr; - typedef typename symbol_table_t::function_ptr function_ptr; - #ifndef exprtk_disable_string_capabilities - typedef typename symbol_table_t::stringvar_ptr stringvar_ptr; - #endif - typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; - typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; - typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; - - struct variable_context - { - variable_context() - : symbol_table(0) - , variable(0) - {} - - const symbol_table_t* symbol_table; - variable_ptr variable; - }; - - struct vector_context - { - vector_context() - : symbol_table(0) - , vector_holder(0) - {} - - const symbol_table_t* symbol_table; - vector_holder_ptr vector_holder; - }; - - #ifndef exprtk_disable_string_capabilities - struct string_context - { - string_context() - : symbol_table(0) - , str_var(0) - {} - - const symbol_table_t* symbol_table; - stringvar_ptr str_var; - }; - #endif - - inline bool empty() const - { - return symtab_list_.empty(); - } - - inline void clear() - { - symtab_list_.clear(); - } - - inline bool valid() const - { - if (!empty()) - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (symtab_list_[i].valid()) - return true; - } - } - - return false; - } - - inline bool valid_symbol(const std::string& symbol) const - { - if (!symtab_list_.empty()) - return symtab_list_[0].valid_symbol(symbol); - else - return false; - } - - inline bool valid_function_name(const std::string& symbol) const - { - if (!symtab_list_.empty()) - return symtab_list_[0].valid_function(symbol); - else - return false; - } - - inline variable_context get_variable_context(const std::string& variable_name) const - { - variable_context result; - - if (valid_symbol(variable_name)) - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - { - continue; - } - - result.variable = local_data(i) - .variable_store.get(variable_name); - if (result.variable) - { - result.symbol_table = &symtab_list_[i]; - break; - } - } - } - - return result; - } - - inline variable_ptr get_variable(const std::string& variable_name) const - { - if (!valid_symbol(variable_name)) - return reinterpret_cast(0); - - variable_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .variable_store.get(variable_name); - - if (result) break; - } - - return result; - } - - inline variable_ptr get_variable(const T& var_ref) const - { - variable_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i).variable_store - .get_from_varptr(reinterpret_cast(&var_ref)); - - if (result) break; - } - - return result; - } - - #ifndef exprtk_disable_string_capabilities - inline string_context get_string_context(const std::string& string_name) const - { - string_context result; - - if (!valid_symbol(string_name)) - return result; - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - { - continue; - } - - result.str_var = local_data(i).stringvar_store.get(string_name); - - if (result.str_var) - { - result.symbol_table = &symtab_list_[i]; - break; - } - } - - return result; - } - - inline stringvar_ptr get_stringvar(const std::string& string_name) const - { - if (!valid_symbol(string_name)) - return reinterpret_cast(0); - - stringvar_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .stringvar_store.get(string_name); - - if (result) break; - } - - return result; - } - #endif - - inline function_ptr get_function(const std::string& function_name) const - { - if (!valid_function_name(function_name)) - return reinterpret_cast(0); - - function_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .function_store.get(function_name); - - if (result) break; - } - - return result; - } - - inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const - { - if (!valid_function_name(vararg_function_name)) - return reinterpret_cast(0); - - vararg_function_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .vararg_function_store.get(vararg_function_name); - - if (result) break; - } - - return result; - } - - inline generic_function_ptr get_generic_function(const std::string& function_name) const - { - if (!valid_function_name(function_name)) - return reinterpret_cast(0); - - generic_function_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .generic_function_store.get(function_name); - - if (result) break; - } - - return result; - } - - inline generic_function_ptr get_string_function(const std::string& function_name) const - { - if (!valid_function_name(function_name)) - return reinterpret_cast(0); - - generic_function_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = - local_data(i).string_function_store.get(function_name); - - if (result) break; - } - - return result; - } - - inline generic_function_ptr get_overload_function(const std::string& function_name) const - { - if (!valid_function_name(function_name)) - return reinterpret_cast(0); - - generic_function_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = - local_data(i).overload_function_store.get(function_name); - - if (result) break; - } - - return result; - } - - inline vector_context get_vector_context(const std::string& vector_name) const - { - vector_context result; - if (!valid_symbol(vector_name)) - return result; - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - { - continue; - } - - result.vector_holder = local_data(i).vector_store.get(vector_name); - - if (result.vector_holder) - { - result.symbol_table = &symtab_list_[i]; - break; - } - } - - return result; - } - - inline vector_holder_ptr get_vector(const std::string& vector_name) const - { - if (!valid_symbol(vector_name)) - return reinterpret_cast(0); - - vector_holder_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - { - continue; - } - - result = local_data(i).vector_store.get(vector_name); - - if (result) - { - break; - } - } - - return result; - } - - inline bool is_constant_node(const std::string& symbol_name) const - { - if (!valid_symbol(symbol_name)) - return false; - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - { - continue; - } - - if (local_data(i).variable_store.is_constant(symbol_name)) - { - return true; - } - } - - return false; - } - - #ifndef exprtk_disable_string_capabilities - inline bool is_constant_string(const std::string& symbol_name) const - { - if (!valid_symbol(symbol_name)) - return false; - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if (!local_data(i).stringvar_store.symbol_exists(symbol_name)) - continue; - else if (local_data(i).stringvar_store.is_constant(symbol_name)) - return true; - } - - return false; - } - #endif - - inline bool symbol_exists(const std::string& symbol) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - { - continue; - } - - if (symtab_list_[i].symbol_exists(symbol)) - { - return true; - } - } - - return false; - } - - inline bool is_variable(const std::string& variable_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - symtab_list_[i].local_data().variable_store - .symbol_exists(variable_name) - ) - return true; - } - - return false; - } - - #ifndef exprtk_disable_string_capabilities - inline bool is_stringvar(const std::string& stringvar_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - symtab_list_[i].local_data().stringvar_store - .symbol_exists(stringvar_name) - ) - return true; - } - - return false; - } - - inline bool is_conststr_stringvar(const std::string& symbol_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - symtab_list_[i].local_data().stringvar_store - .symbol_exists(symbol_name) - ) - { - return ( - local_data(i).stringvar_store.symbol_exists(symbol_name) || - local_data(i).stringvar_store.is_constant (symbol_name) - ); - - } - } - - return false; - } - #endif - - inline bool is_function(const std::string& function_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - local_data(i).vararg_function_store - .symbol_exists(function_name) - ) - return true; - } - - return false; - } - - inline bool is_vararg_function(const std::string& vararg_function_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - local_data(i).vararg_function_store - .symbol_exists(vararg_function_name) - ) - return true; - } - - return false; - } - - inline bool is_vector(const std::string& vector_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - local_data(i).vector_store - .symbol_exists(vector_name) - ) - return true; - } - - return false; - } - - inline std::string get_variable_name(const expression_node_ptr& ptr) const - { - return local_data().variable_store.entity_name(ptr); - } - - inline std::string get_vector_name(const vector_holder_ptr& ptr) const - { - return local_data().vector_store.entity_name(ptr); - } - - #ifndef exprtk_disable_string_capabilities - inline std::string get_stringvar_name(const expression_node_ptr& ptr) const - { - return local_data().stringvar_store.entity_name(ptr); - } - - inline std::string get_conststr_stringvar_name(const expression_node_ptr& ptr) const - { - return local_data().stringvar_store.entity_name(ptr); - } - #endif - - inline local_data_t& local_data(const std::size_t& index = 0) - { - return symtab_list_[index].local_data(); - } - - inline const local_data_t& local_data(const std::size_t& index = 0) const - { - return symtab_list_[index].local_data(); - } - - inline symbol_table_t& get_symbol_table(const std::size_t& index = 0) - { - return symtab_list_[index]; - } - }; - - struct parser_state - { - parser_state() - : type_check_enabled(true) - { - reset(); - } - - void reset() - { - parsing_return_stmt = false; - parsing_break_stmt = false; - parsing_assert_stmt = false; - return_stmt_present = false; - side_effect_present = false; - scope_depth = 0; - stack_depth = 0; - parsing_loop_stmt_count = 0; - } - - #ifndef exprtk_enable_debugging - void activate_side_effect(const std::string&) - #else - void activate_side_effect(const std::string& source) - #endif - { - if (!side_effect_present) - { - side_effect_present = true; - - exprtk_debug(("activate_side_effect() - caller: %s\n", source.c_str())); - } - } - - bool parsing_return_stmt; - bool parsing_break_stmt; - bool parsing_assert_stmt; - bool return_stmt_present; - bool side_effect_present; - bool type_check_enabled; - std::size_t scope_depth; - std::size_t stack_depth; - std::size_t parsing_loop_stmt_count; - }; - - public: - - struct unknown_symbol_resolver - { - - enum usr_symbol_type - { - e_usr_unknown_type = 0, - e_usr_variable_type = 1, - e_usr_constant_type = 2 - }; - - enum usr_mode - { - e_usrmode_default = 0, - e_usrmode_extended = 1 - }; - - usr_mode mode; - - unknown_symbol_resolver(const usr_mode m = e_usrmode_default) - : mode(m) - {} - - virtual ~unknown_symbol_resolver() - {} - - virtual bool process(const std::string& /*unknown_symbol*/, - usr_symbol_type& st, - T& default_value, - std::string& error_message) - { - if (e_usrmode_default != mode) - return false; - - st = e_usr_variable_type; - default_value = T(0); - error_message.clear(); - - return true; - } - - virtual bool process(const std::string& /* unknown_symbol */, - symbol_table_t& /* symbol_table */, - std::string& /* error_message */) - { - return false; - } - }; - - enum collect_type - { - e_ct_none = 0, - e_ct_variables = 1, - e_ct_functions = 2, - e_ct_assignments = 4 - }; - - enum symbol_type - { - e_st_unknown = 0, - e_st_variable = 1, - e_st_vector = 2, - e_st_vecelem = 3, - e_st_string = 4, - e_st_function = 5, - e_st_local_variable = 6, - e_st_local_vector = 7, - e_st_local_string = 8 - }; - - class dependent_entity_collector - { - public: - - typedef std::pair symbol_t; - typedef std::vector symbol_list_t; - - dependent_entity_collector(const std::size_t options = e_ct_none) - : options_(options) - , collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ) - , collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ) - , collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments) - , return_present_ (false) - , final_stmt_return_(false) - {} - - template class Sequence> - inline std::size_t symbols(Sequence& symbols_list) - { - if (!collect_variables_ && !collect_functions_) - return 0; - else if (symbol_name_list_.empty()) - return 0; - - for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) - { - details::case_normalise(symbol_name_list_[i].first); - } - - std::sort(symbol_name_list_.begin(), symbol_name_list_.end()); - - std::unique_copy - ( - symbol_name_list_.begin(), - symbol_name_list_.end (), - std::back_inserter(symbols_list) - ); - - return symbols_list.size(); - } - - template class Sequence> - inline std::size_t assignment_symbols(Sequence& assignment_list) - { - if (!collect_assignments_) - return 0; - else if (assignment_name_list_.empty()) - return 0; - - for (std::size_t i = 0; i < assignment_name_list_.size(); ++i) - { - details::case_normalise(assignment_name_list_[i].first); - } - - std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); - - std::unique_copy - ( - assignment_name_list_.begin(), - assignment_name_list_.end (), - std::back_inserter(assignment_list) - ); - - return assignment_list.size(); - } - - void clear() - { - symbol_name_list_ .clear(); - assignment_name_list_.clear(); - retparam_list_ .clear(); - return_present_ = false; - final_stmt_return_ = false; - } - - bool& collect_variables() - { - return collect_variables_; - } - - bool& collect_functions() - { - return collect_functions_; - } - - bool& collect_assignments() - { - return collect_assignments_; - } - - bool return_present() const - { - return return_present_; - } - - bool final_stmt_return() const - { - return final_stmt_return_; - } - - typedef std::vector retparam_list_t; - - retparam_list_t return_param_type_list() const - { - return retparam_list_; - } - - private: - - inline void add_symbol(const std::string& symbol, const symbol_type st) - { - switch (st) - { - case e_st_variable : - case e_st_vector : - case e_st_string : - case e_st_local_variable : - case e_st_local_vector : - case e_st_local_string : if (collect_variables_) - symbol_name_list_ - .push_back(std::make_pair(symbol, st)); - break; - - case e_st_function : if (collect_functions_) - symbol_name_list_ - .push_back(std::make_pair(symbol, st)); - break; - - default : return; - } - } - - inline void add_assignment(const std::string& symbol, const symbol_type st) - { - switch (st) - { - case e_st_variable : - case e_st_vector : - case e_st_string : if (collect_assignments_) - assignment_name_list_ - .push_back(std::make_pair(symbol, st)); - break; - - default : return; - } - } - - std::size_t options_; - bool collect_variables_; - bool collect_functions_; - bool collect_assignments_; - bool return_present_; - bool final_stmt_return_; - symbol_list_t symbol_name_list_; - symbol_list_t assignment_name_list_; - retparam_list_t retparam_list_; - - friend class parser; - }; - - class settings_store - { - private: - - typedef std::set disabled_entity_set_t; - typedef disabled_entity_set_t::iterator des_itr_t; - - public: - - enum settings_compilation_options - { - e_unknown = 0, - e_replacer = 1, - e_joiner = 2, - e_numeric_check = 4, - e_bracket_check = 8, - e_sequence_check = 16, - e_commutative_check = 32, - e_strength_reduction = 64, - e_disable_vardef = 128, - e_collect_vars = 256, - e_collect_funcs = 512, - e_collect_assings = 1024, - e_disable_usr_on_rsrvd = 2048, - e_disable_zero_return = 4096 - }; - - enum settings_base_funcs - { - e_bf_unknown = 0, - e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , - e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , - e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , - e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , - e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , - e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , - e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , - e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , - e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , - e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , - e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , - e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , - e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , - e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad , - e_bf_rad2deg , e_bf_grad2deg - }; - - enum settings_control_structs - { - e_ctrl_unknown = 0, - e_ctrl_ifelse, - e_ctrl_switch, - e_ctrl_for_loop, - e_ctrl_while_loop, - e_ctrl_repeat_loop, - e_ctrl_return - }; - - enum settings_logic_opr - { - e_logic_unknown = 0, - e_logic_and, e_logic_nand , e_logic_nor , - e_logic_not, e_logic_or , e_logic_xnor, - e_logic_xor, e_logic_scand, e_logic_scor - }; - - enum settings_arithmetic_opr - { - e_arith_unknown = 0, - e_arith_add, e_arith_sub, e_arith_mul, - e_arith_div, e_arith_mod, e_arith_pow - }; - - enum settings_assignment_opr - { - e_assign_unknown = 0, - e_assign_assign, e_assign_addass, e_assign_subass, - e_assign_mulass, e_assign_divass, e_assign_modass - }; - - enum settings_inequality_opr - { - e_ineq_unknown = 0, - e_ineq_lt , e_ineq_lte, e_ineq_eq , - e_ineq_equal, e_ineq_ne , e_ineq_nequal, - e_ineq_gte , e_ineq_gt - }; - - static const std::size_t default_compile_all_opts = - e_replacer + - e_joiner + - e_numeric_check + - e_bracket_check + - e_sequence_check + - e_commutative_check + - e_strength_reduction; - - settings_store(const std::size_t compile_options = default_compile_all_opts) - : max_stack_depth_(400) - , max_node_depth_(10000) - , max_local_vector_size_(2000000000) - { - load_compile_options(compile_options); - } - - settings_store& enable_all_base_functions() - { - disabled_func_set_.clear(); - return (*this); - } - - settings_store& enable_all_control_structures() - { - disabled_ctrl_set_.clear(); - return (*this); - } - - settings_store& enable_all_logic_ops() - { - disabled_logic_set_.clear(); - return (*this); - } - - settings_store& enable_all_arithmetic_ops() - { - disabled_arithmetic_set_.clear(); - return (*this); - } - - settings_store& enable_all_assignment_ops() - { - disabled_assignment_set_.clear(); - return (*this); - } - - settings_store& enable_all_inequality_ops() - { - disabled_inequality_set_.clear(); - return (*this); - } - - settings_store& enable_local_vardef() - { - disable_vardef_ = false; - return (*this); - } - - settings_store& enable_commutative_check() - { - enable_commutative_check_ = true; - return (*this); - } - - settings_store& enable_strength_reduction() - { - enable_strength_reduction_ = true; - return (*this); - } - - settings_store& disable_all_base_functions() - { - std::copy(details::base_function_list, - details::base_function_list + details::base_function_list_size, - std::insert_iterator - (disabled_func_set_, disabled_func_set_.begin())); - return (*this); - } - - settings_store& disable_all_control_structures() - { - std::copy(details::cntrl_struct_list, - details::cntrl_struct_list + details::cntrl_struct_list_size, - std::insert_iterator - (disabled_ctrl_set_, disabled_ctrl_set_.begin())); - return (*this); - } - - settings_store& disable_all_logic_ops() - { - std::copy(details::logic_ops_list, - details::logic_ops_list + details::logic_ops_list_size, - std::insert_iterator - (disabled_logic_set_, disabled_logic_set_.begin())); - return (*this); - } - - settings_store& disable_all_arithmetic_ops() - { - std::copy(details::arithmetic_ops_list, - details::arithmetic_ops_list + details::arithmetic_ops_list_size, - std::insert_iterator - (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); - return (*this); - } - - settings_store& disable_all_assignment_ops() - { - std::copy(details::assignment_ops_list, - details::assignment_ops_list + details::assignment_ops_list_size, - std::insert_iterator - (disabled_assignment_set_, disabled_assignment_set_.begin())); - return (*this); - } - - settings_store& disable_all_inequality_ops() - { - std::copy(details::inequality_ops_list, - details::inequality_ops_list + details::inequality_ops_list_size, - std::insert_iterator - (disabled_inequality_set_, disabled_inequality_set_.begin())); - return (*this); - } - - settings_store& disable_local_vardef() - { - disable_vardef_ = true; - return (*this); - } - - settings_store& disable_commutative_check() - { - enable_commutative_check_ = false; - return (*this); - } - - settings_store& disable_strength_reduction() - { - enable_strength_reduction_ = false; - return (*this); - } - - bool replacer_enabled () const { return enable_replacer_; } - bool commutative_check_enabled () const { return enable_commutative_check_; } - bool joiner_enabled () const { return enable_joiner_; } - bool numeric_check_enabled () const { return enable_numeric_check_; } - bool bracket_check_enabled () const { return enable_bracket_check_; } - bool sequence_check_enabled () const { return enable_sequence_check_; } - bool strength_reduction_enabled () const { return enable_strength_reduction_; } - bool collect_variables_enabled () const { return enable_collect_vars_; } - bool collect_functions_enabled () const { return enable_collect_funcs_; } - bool collect_assignments_enabled() const { return enable_collect_assings_; } - bool vardef_disabled () const { return disable_vardef_; } - bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } - bool zero_return_disabled () const { return disable_zero_return_; } - - bool function_enabled(const std::string& function_name) const - { - if (disabled_func_set_.empty()) - return true; - else - return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); - } - - bool control_struct_enabled(const std::string& control_struct) const - { - if (disabled_ctrl_set_.empty()) - return true; - else - return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); - } - - bool logic_enabled(const std::string& logic_operation) const - { - if (disabled_logic_set_.empty()) - return true; - else - return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); - } - - bool arithmetic_enabled(const details::operator_type& arithmetic_operation) const - { - if (disabled_logic_set_.empty()) - return true; - else - return disabled_arithmetic_set_.end() == disabled_arithmetic_set_ - .find(arith_opr_to_string(arithmetic_operation)); - } - - bool assignment_enabled(const details::operator_type& assignment) const - { - if (disabled_assignment_set_.empty()) - return true; - else - return disabled_assignment_set_.end() == disabled_assignment_set_ - .find(assign_opr_to_string(assignment)); - } - - bool inequality_enabled(const details::operator_type& inequality) const - { - if (disabled_inequality_set_.empty()) - return true; - else - return disabled_inequality_set_.end() == disabled_inequality_set_ - .find(inequality_opr_to_string(inequality)); - } - - bool function_disabled(const std::string& function_name) const - { - if (disabled_func_set_.empty()) - return false; - else - return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); - } - - bool control_struct_disabled(const std::string& control_struct) const - { - if (disabled_ctrl_set_.empty()) - return false; - else - return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); - } - - bool logic_disabled(const std::string& logic_operation) const - { - if (disabled_logic_set_.empty()) - return false; - else - return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); - } - - bool assignment_disabled(const details::operator_type assignment_operation) const - { - if (disabled_assignment_set_.empty()) - return false; - else - return disabled_assignment_set_.end() != disabled_assignment_set_ - .find(assign_opr_to_string(assignment_operation)); - } - - bool logic_disabled(const details::operator_type logic_operation) const - { - if (disabled_logic_set_.empty()) - return false; - else - return disabled_logic_set_.end() != disabled_logic_set_ - .find(logic_opr_to_string(logic_operation)); - } - - bool arithmetic_disabled(const details::operator_type arithmetic_operation) const - { - if (disabled_arithmetic_set_.empty()) - return false; - else - return disabled_arithmetic_set_.end() != disabled_arithmetic_set_ - .find(arith_opr_to_string(arithmetic_operation)); - } - - bool inequality_disabled(const details::operator_type& inequality) const - { - if (disabled_inequality_set_.empty()) - return false; - else - return disabled_inequality_set_.end() != disabled_inequality_set_ - .find(inequality_opr_to_string(inequality)); - } - - settings_store& disable_base_function(const settings_base_funcs bf) - { - if ( - (e_bf_unknown != bf) && - (static_cast(bf) < (details::base_function_list_size + 1)) - ) - { - disabled_func_set_.insert(details::base_function_list[bf - 1]); - } - - return (*this); - } - - settings_store& disable_control_structure(const settings_control_structs ctrl_struct) - { - if ( - (e_ctrl_unknown != ctrl_struct) && - (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) - ) - { - disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); - } - - return (*this); - } - - settings_store& disable_logic_operation(const settings_logic_opr logic) - { - if ( - (e_logic_unknown != logic) && - (static_cast(logic) < (details::logic_ops_list_size + 1)) - ) - { - disabled_logic_set_.insert(details::logic_ops_list[logic - 1]); - } - - return (*this); - } - - settings_store& disable_arithmetic_operation(const settings_arithmetic_opr arithmetic) - { - if ( - (e_arith_unknown != arithmetic) && - (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) - ) - { - disabled_arithmetic_set_.insert(details::arithmetic_ops_list[arithmetic - 1]); - } - - return (*this); - } - - settings_store& disable_assignment_operation(const settings_assignment_opr assignment) - { - if ( - (e_assign_unknown != assignment) && - (static_cast(assignment) < (details::assignment_ops_list_size + 1)) - ) - { - disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); - } - - return (*this); - } - - settings_store& disable_inequality_operation(const settings_inequality_opr inequality) - { - if ( - (e_ineq_unknown != inequality) && - (static_cast(inequality) < (details::inequality_ops_list_size + 1)) - ) - { - disabled_inequality_set_.insert(details::inequality_ops_list[inequality - 1]); - } - - return (*this); - } - - settings_store& enable_base_function(const settings_base_funcs bf) - { - if ( - (e_bf_unknown != bf) && - (static_cast(bf) < (details::base_function_list_size + 1)) - ) - { - const des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); - - if (disabled_func_set_.end() != itr) - { - disabled_func_set_.erase(itr); - } - } - - return (*this); - } - - settings_store& enable_control_structure(const settings_control_structs ctrl_struct) - { - if ( - (e_ctrl_unknown != ctrl_struct) && - (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) - ) - { - const des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); - - if (disabled_ctrl_set_.end() != itr) - { - disabled_ctrl_set_.erase(itr); - } - } - - return (*this); - } - - settings_store& enable_logic_operation(const settings_logic_opr logic) - { - if ( - (e_logic_unknown != logic) && - (static_cast(logic) < (details::logic_ops_list_size + 1)) - ) - { - const des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); - - if (disabled_logic_set_.end() != itr) - { - disabled_logic_set_.erase(itr); - } - } - - return (*this); - } - - settings_store& enable_arithmetic_operation(const settings_arithmetic_opr arithmetic) - { - if ( - (e_arith_unknown != arithmetic) && - (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) - ) - { - const des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); - - if (disabled_arithmetic_set_.end() != itr) - { - disabled_arithmetic_set_.erase(itr); - } - } - - return (*this); - } - - settings_store& enable_assignment_operation(const settings_assignment_opr assignment) - { - if ( - (e_assign_unknown != assignment) && - (static_cast(assignment) < (details::assignment_ops_list_size + 1)) - ) - { - const des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); - - if (disabled_assignment_set_.end() != itr) - { - disabled_assignment_set_.erase(itr); - } - } - - return (*this); - } - - settings_store& enable_inequality_operation(const settings_inequality_opr inequality) - { - if ( - (e_ineq_unknown != inequality) && - (static_cast(inequality) < (details::inequality_ops_list_size + 1)) - ) - { - const des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); - - if (disabled_inequality_set_.end() != itr) - { - disabled_inequality_set_.erase(itr); - } - } - - return (*this); - } - - void set_max_stack_depth(const std::size_t max_stack_depth) - { - max_stack_depth_ = max_stack_depth; - } - - void set_max_node_depth(const std::size_t max_node_depth) - { - max_node_depth_ = max_node_depth; - } - - void set_max_local_vector_size(const std::size_t max_local_vector_size) - { - max_local_vector_size_ = max_local_vector_size; - } - - std::size_t max_stack_depth() const - { - return max_stack_depth_; - } - - std::size_t max_node_depth() const - { - return max_node_depth_; - } - - std::size_t max_local_vector_size() const - { - return max_local_vector_size_; - } - - private: - - void load_compile_options(const std::size_t compile_options) - { - enable_replacer_ = (compile_options & e_replacer ) == e_replacer; - enable_joiner_ = (compile_options & e_joiner ) == e_joiner; - enable_numeric_check_ = (compile_options & e_numeric_check ) == e_numeric_check; - enable_bracket_check_ = (compile_options & e_bracket_check ) == e_bracket_check; - enable_sequence_check_ = (compile_options & e_sequence_check ) == e_sequence_check; - enable_commutative_check_ = (compile_options & e_commutative_check ) == e_commutative_check; - enable_strength_reduction_ = (compile_options & e_strength_reduction ) == e_strength_reduction; - enable_collect_vars_ = (compile_options & e_collect_vars ) == e_collect_vars; - enable_collect_funcs_ = (compile_options & e_collect_funcs ) == e_collect_funcs; - enable_collect_assings_ = (compile_options & e_collect_assings ) == e_collect_assings; - disable_vardef_ = (compile_options & e_disable_vardef ) == e_disable_vardef; - disable_rsrvd_sym_usr_ = (compile_options & e_disable_usr_on_rsrvd) == e_disable_usr_on_rsrvd; - disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; - } - - std::string assign_opr_to_string(details::operator_type opr) const - { - switch (opr) - { - case details::e_assign : return ":="; - case details::e_addass : return "+="; - case details::e_subass : return "-="; - case details::e_mulass : return "*="; - case details::e_divass : return "/="; - case details::e_modass : return "%="; - default : return "" ; - } - } - - std::string arith_opr_to_string(details::operator_type opr) const - { - switch (opr) - { - case details::e_add : return "+"; - case details::e_sub : return "-"; - case details::e_mul : return "*"; - case details::e_div : return "/"; - case details::e_mod : return "%"; - case details::e_pow : return "^"; - default : return "" ; - } - } - - std::string inequality_opr_to_string(details::operator_type opr) const - { - switch (opr) - { - case details::e_lt : return "<" ; - case details::e_lte : return "<="; - case details::e_eq : return "=="; - case details::e_equal : return "=" ; - case details::e_ne : return "!="; - case details::e_nequal: return "<>"; - case details::e_gte : return ">="; - case details::e_gt : return ">" ; - default : return "" ; - } - } - - std::string logic_opr_to_string(details::operator_type opr) const - { - switch (opr) - { - case details::e_and : return "and" ; - case details::e_or : return "or" ; - case details::e_xor : return "xor" ; - case details::e_nand : return "nand"; - case details::e_nor : return "nor" ; - case details::e_xnor : return "xnor"; - case details::e_notl : return "not" ; - default : return "" ; - } - } - - bool enable_replacer_; - bool enable_joiner_; - bool enable_numeric_check_; - bool enable_bracket_check_; - bool enable_sequence_check_; - bool enable_commutative_check_; - bool enable_strength_reduction_; - bool enable_collect_vars_; - bool enable_collect_funcs_; - bool enable_collect_assings_; - bool disable_vardef_; - bool disable_rsrvd_sym_usr_; - bool disable_zero_return_; - - disabled_entity_set_t disabled_func_set_ ; - disabled_entity_set_t disabled_ctrl_set_ ; - disabled_entity_set_t disabled_logic_set_; - disabled_entity_set_t disabled_arithmetic_set_; - disabled_entity_set_t disabled_assignment_set_; - disabled_entity_set_t disabled_inequality_set_; - - std::size_t max_stack_depth_; - std::size_t max_node_depth_; - std::size_t max_local_vector_size_; - - friend class parser; - }; - - typedef settings_store settings_t; - - explicit parser(const settings_t& settings = settings_t()) - : settings_(settings) - , resolve_unknown_symbol_(false) - , results_context_(0) - , unknown_symbol_resolver_(reinterpret_cast(0)) - #ifdef _MSC_VER - #pragma warning(push) - #pragma warning (disable:4355) - #endif - , sem_(*this) - #ifdef _MSC_VER - #pragma warning(pop) - #endif - , operator_joiner_2_(2) - , operator_joiner_3_(3) - , loop_runtime_check_(0) - , vector_access_runtime_check_(0) - , compilation_check_ptr_(0) - , assert_check_(0) - { - init_precompilation(); - - load_operations_map (base_ops_map_ ); - load_unary_operations_map (unary_op_map_ ); - load_binary_operations_map (binary_op_map_ ); - load_inv_binary_operations_map(inv_binary_op_map_); - load_sf3_map (sf3_map_ ); - load_sf4_map (sf4_map_ ); - - expression_generator_.init_synthesize_map(); - expression_generator_.set_parser(*this); - expression_generator_.set_uom (unary_op_map_ ); - expression_generator_.set_bom (binary_op_map_ ); - expression_generator_.set_ibom(inv_binary_op_map_); - expression_generator_.set_sf3m(sf3_map_ ); - expression_generator_.set_sf4m(sf4_map_ ); - expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); - } - - ~parser() - {} - - inline void init_precompilation() - { - dec_.collect_variables() = - settings_.collect_variables_enabled(); - - dec_.collect_functions() = - settings_.collect_functions_enabled(); - - dec_.collect_assignments() = - settings_.collect_assignments_enabled(); - - if (settings_.replacer_enabled()) - { - symbol_replacer_.clear(); - symbol_replacer_.add_replace("true" , "1", lexer::token::e_number); - symbol_replacer_.add_replace("false", "0", lexer::token::e_number); - helper_assembly_.token_modifier_list.clear(); - helper_assembly_.register_modifier(&symbol_replacer_); - } - - if (settings_.commutative_check_enabled()) - { - for (std::size_t i = 0; i < details::reserved_words_size; ++i) - { - commutative_inserter_.ignore_symbol(details::reserved_words[i]); - } - - helper_assembly_.token_inserter_list.clear(); - helper_assembly_.register_inserter(&commutative_inserter_); - } - - if (settings_.joiner_enabled()) - { - helper_assembly_.token_joiner_list.clear(); - helper_assembly_.register_joiner(&operator_joiner_2_); - helper_assembly_.register_joiner(&operator_joiner_3_); - } - - if ( - settings_.numeric_check_enabled () || - settings_.bracket_check_enabled () || - settings_.sequence_check_enabled() - ) - { - helper_assembly_.token_scanner_list.clear(); - - if (settings_.numeric_check_enabled()) - { - helper_assembly_.register_scanner(&numeric_checker_); - } - - if (settings_.bracket_check_enabled()) - { - helper_assembly_.register_scanner(&bracket_checker_); - } - - if (settings_.sequence_check_enabled()) - { - helper_assembly_.register_scanner(&sequence_validator_ ); - helper_assembly_.register_scanner(&sequence_validator_3tkns_); - } - } - } - - inline bool compile(const std::string& expression_string, expression& expr) - { - state_ .reset(); - error_list_ .clear(); - brkcnt_list_ .clear(); - synthesis_error_ .clear(); - immutable_memory_map_.reset(); - immutable_symtok_map_.clear(); - current_state_stack_ .clear(); - assert_ids_ .clear(); - sem_ .cleanup(); - - return_cleanup(); - - expression_generator_.set_allocator(node_allocator_); - - if (expression_string.empty()) - { - set_error(make_error( - parser_error::e_syntax, - "ERR001 - Empty expression!", - exprtk_error_location)); - - return false; - } - - if (!init(expression_string)) - { - process_lexer_errors(); - return false; - } - - if (lexer().empty()) - { - set_error(make_error( - parser_error::e_syntax, - "ERR002 - Empty expression!", - exprtk_error_location)); - - return false; - } - - if (halt_compilation_check()) - { - exprtk_debug(("halt_compilation_check() - compile checkpoint 0\n")); - return false; - } - - if (!run_assemblies()) - { - return false; - } - - if (halt_compilation_check()) - { - exprtk_debug(("halt_compilation_check() - compile checkpoint 1\n")); - return false; - } - - symtab_store_.symtab_list_ = expr.get_symbol_table_list(); - dec_.clear(); - - lexer().begin(); - - next_token(); - - expression_node_ptr e = parse_corpus(); - - if ((0 != e) && (token_t::e_eof == current_token().type)) - { - bool* retinvk_ptr = 0; - - if (state_.return_stmt_present) - { - dec_.return_present_ = true; - - e = expression_generator_ - .return_envelope(e, results_context_, retinvk_ptr); - } - - expr.set_expression(e); - expr.set_retinvk(retinvk_ptr); - - register_local_vars(expr); - register_return_results(expr); - - return !(!expr); - } - else - { - if (error_list_.empty()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR003 - Invalid expression encountered", - exprtk_error_location)); - } - - if ((0 != e) && branch_deletable(e)) - { - destroy_node(e); - } - - dec_.clear (); - sem_.cleanup (); - return_cleanup(); - - return false; - } - } - - inline expression_t compile(const std::string& expression_string, symbol_table_t& symtab) - { - expression_t expression; - expression.register_symbol_table(symtab); - compile(expression_string,expression); - return expression; - } - - void process_lexer_errors() - { - for (std::size_t i = 0; i < lexer().size(); ++i) - { - if (lexer()[i].is_error()) - { - std::string diagnostic = "ERR004 - "; - - switch (lexer()[i].type) - { - case lexer::token::e_error : diagnostic += "General token error"; - break; - - case lexer::token::e_err_symbol : diagnostic += "Symbol error"; - break; - - case lexer::token::e_err_number : diagnostic += "Invalid numeric token"; - break; - - case lexer::token::e_err_string : diagnostic += "Invalid string token"; - break; - - case lexer::token::e_err_sfunc : diagnostic += "Invalid special function token"; - break; - - default : diagnostic += "Unknown compiler error"; - } - - set_error(make_error( - parser_error::e_lexer, - lexer()[i], - diagnostic + ": " + lexer()[i].value, - exprtk_error_location)); - } - } - } - - inline bool run_assemblies() - { - if (settings_.commutative_check_enabled()) - { - helper_assembly_.run_inserters(lexer()); - } - - if (settings_.joiner_enabled()) - { - helper_assembly_.run_joiners(lexer()); - } - - if (settings_.replacer_enabled()) - { - helper_assembly_.run_modifiers(lexer()); - } - - if ( - settings_.numeric_check_enabled () || - settings_.bracket_check_enabled () || - settings_.sequence_check_enabled() - ) - { - if (!helper_assembly_.run_scanners(lexer())) - { - if (helper_assembly_.error_token_scanner) - { - lexer::helper::bracket_checker* bracket_checker_ptr = 0; - lexer::helper::numeric_checker* numeric_checker_ptr = 0; - lexer::helper::sequence_validator* sequence_validator_ptr = 0; - lexer::helper::sequence_validator_3tokens* sequence_validator3_ptr = 0; - - if (0 != (bracket_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) - { - set_error(make_error( - parser_error::e_token, - bracket_checker_ptr->error_token(), - "ERR005 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", - exprtk_error_location)); - } - else if (0 != (numeric_checker_ptr = dynamic_cast*>(helper_assembly_.error_token_scanner))) - { - for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) - { - lexer::token error_token = lexer()[numeric_checker_ptr->error_index(i)]; - - set_error(make_error( - parser_error::e_token, - error_token, - "ERR006 - Invalid numeric token: '" + error_token.value + "'", - exprtk_error_location)); - } - - if (numeric_checker_ptr->error_count()) - { - numeric_checker_ptr->clear_errors(); - } - } - else if (0 != (sequence_validator_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) - { - for (std::size_t i = 0; i < sequence_validator_ptr->error_count(); ++i) - { - std::pair error_token = sequence_validator_ptr->error(i); - - set_error(make_error( - parser_error::e_token, - error_token.first, - "ERR007 - Invalid token sequence: '" + - error_token.first.value + "' and '" + - error_token.second.value + "'", - exprtk_error_location)); - } - - if (sequence_validator_ptr->error_count()) - { - sequence_validator_ptr->clear_errors(); - } - } - else if (0 != (sequence_validator3_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) - { - for (std::size_t i = 0; i < sequence_validator3_ptr->error_count(); ++i) - { - std::pair error_token = sequence_validator3_ptr->error(i); - - set_error(make_error( - parser_error::e_token, - error_token.first, - "ERR008 - Invalid token sequence: '" + - error_token.first.value + "' and '" + - error_token.second.value + "'", - exprtk_error_location)); - } - - if (sequence_validator3_ptr->error_count()) - { - sequence_validator3_ptr->clear_errors(); - } - } - } - - return false; - } - } - - return true; - } - - inline settings_store& settings() - { - return settings_; - } - - inline parser_error::type get_error(const std::size_t& index) const - { - if (index < error_list_.size()) - { - return error_list_[index]; - } - - throw std::invalid_argument("parser::get_error() - Invalid error index specified"); - } - - inline std::string error() const - { - if (!error_list_.empty()) - { - return error_list_[0].diagnostic; - } - else - return std::string("No Error"); - } - - inline std::size_t error_count() const - { - return error_list_.size(); - } - - inline dependent_entity_collector& dec() - { - return dec_; - } - - inline bool replace_symbol(const std::string& old_symbol, const std::string& new_symbol) - { - if (!settings_.replacer_enabled()) - return false; - else if (details::is_reserved_word(old_symbol)) - return false; - else - return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol); - } - - inline bool remove_replace_symbol(const std::string& symbol) - { - if (!settings_.replacer_enabled()) - return false; - else if (details::is_reserved_word(symbol)) - return false; - else - return symbol_replacer_.remove(symbol); - } - - inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast(0)) - { - resolve_unknown_symbol_ = true; - - if (usr) - unknown_symbol_resolver_ = usr; - else - unknown_symbol_resolver_ = &default_usr_; - } - - inline void enable_unknown_symbol_resolver(unknown_symbol_resolver& usr) - { - enable_unknown_symbol_resolver(&usr); - } - - inline void disable_unknown_symbol_resolver() - { - resolve_unknown_symbol_ = false; - unknown_symbol_resolver_ = &default_usr_; - } - - inline void register_loop_runtime_check(loop_runtime_check& lrtchk) - { - loop_runtime_check_ = &lrtchk; - } - - inline void register_vector_access_runtime_check(vector_access_runtime_check& vartchk) - { - vector_access_runtime_check_ = &vartchk; - } - - inline void register_compilation_timeout_check(compilation_check& compchk) - { - compilation_check_ptr_ = &compchk; - } - - inline void register_assert_check(assert_check& assrt_chck) - { - assert_check_ = &assrt_chck; - } - - inline void clear_loop_runtime_check() - { - loop_runtime_check_ = loop_runtime_check_ptr(0); - } - - inline void clear_vector_access_runtime_check() - { - vector_access_runtime_check_ = vector_access_runtime_check_ptr(0); - } - - inline void clear_compilation_timeout_check() - { - compilation_check_ptr_ = compilation_check_ptr(0); - } - - inline void clear_assert_check() - { - assert_check_ = assert_check_ptr(0); - } - - private: - - inline bool valid_base_operation(const std::string& symbol) const - { - const std::size_t length = symbol.size(); - - if ( - (length < 3) || // Shortest base op symbol length - (length > 9) // Longest base op symbol length - ) - return false; - else - return settings_.function_enabled(symbol) && - (base_ops_map_.end() != base_ops_map_.find(symbol)); - } - - inline bool valid_vararg_operation(const std::string& symbol) const - { - static const std::string s_sum = "sum" ; - static const std::string s_mul = "mul" ; - static const std::string s_avg = "avg" ; - static const std::string s_min = "min" ; - static const std::string s_max = "max" ; - static const std::string s_mand = "mand"; - static const std::string s_mor = "mor" ; - static const std::string s_multi = "~" ; - static const std::string s_mswitch = "[*]" ; - - return - ( - details::imatch(symbol,s_sum ) || - details::imatch(symbol,s_mul ) || - details::imatch(symbol,s_avg ) || - details::imatch(symbol,s_min ) || - details::imatch(symbol,s_max ) || - details::imatch(symbol,s_mand ) || - details::imatch(symbol,s_mor ) || - details::imatch(symbol,s_multi ) || - details::imatch(symbol,s_mswitch) - ) && - settings_.function_enabled(symbol); - } - - bool is_invalid_logic_operation(const details::operator_type operation) const - { - return settings_.logic_disabled(operation); - } - - bool is_invalid_arithmetic_operation(const details::operator_type operation) const - { - return settings_.arithmetic_disabled(operation); - } - - bool is_invalid_assignment_operation(const details::operator_type operation) const - { - return settings_.assignment_disabled(operation); - } - - bool is_invalid_inequality_operation(const details::operator_type operation) const - { - return settings_.inequality_disabled(operation); - } - - #ifdef exprtk_enable_debugging - inline void next_token() - { - const std::string ct_str = current_token().value; - const std::size_t ct_pos = current_token().position; - parser_helper::next_token(); - const std::string depth(2 * state_.scope_depth,' '); - exprtk_debug(("%s" - "prev[%s | %04d] --> curr[%s | %04d] stack_level: %3d\n", - depth.c_str(), - ct_str.c_str(), - static_cast(ct_pos), - current_token().value.c_str(), - static_cast(current_token().position), - static_cast(state_.stack_depth))); - } - #endif - - inline expression_node_ptr parse_corpus() - { - std::vector arg_list; - std::vector side_effect_list; - - scoped_vec_delete sdd((*this),arg_list); - - lexer::token begin_token; - lexer::token end_token; - - for ( ; ; ) - { - state_.side_effect_present = false; - - begin_token = current_token(); - - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - { - if (error_list_.empty()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR009 - Invalid expression encountered", - exprtk_error_location)); - } - - return error_node(); - } - else - { - arg_list.push_back(arg); - - side_effect_list.push_back(state_.side_effect_present); - - end_token = current_token(); - - const std::string sub_expr = construct_subexpr(begin_token, end_token); - - exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", - static_cast(arg_list.size() - 1), - sub_expr.c_str())); - - exprtk_debug(("parse_corpus(%02d) - Side effect present: %s\n", - static_cast(arg_list.size() - 1), - state_.side_effect_present ? "true" : "false")); - - exprtk_debug(("-------------------------------------------------\n")); - } - - if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) - { - if (lexer().finished()) - break; - else - next_token(); - } - else if ( - !settings_.commutative_check_enabled() && - ( - current_token().type == token_t::e_symbol || - current_token().type == token_t::e_number || - current_token().type == token_t::e_string || - token_is_bracket(prsrhlpr_t::e_hold) - ) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR010 - Invalid syntax '" + current_token().value + "' possible missing operator or context", - exprtk_error_location)); - - return error_node(); - } - } - - if ( - !arg_list.empty() && - is_return_node(arg_list.back()) - ) - { - dec_.final_stmt_return_ = true; - } - - const expression_node_ptr result = simplify(arg_list,side_effect_list); - - sdd.delete_ptr = (0 == result); - - return result; - } - - std::string construct_subexpr(lexer::token& begin_token, - lexer::token& end_token, - const bool cleanup_whitespace = true) - { - std::string result = lexer().substr(begin_token.position,end_token.position); - if (cleanup_whitespace) - { - for (std::size_t i = 0; i < result.size(); ++i) - { - if (details::is_whitespace(result[i])) result[i] = ' '; - } - } - - return result; - } - - static const precedence_level default_precedence = e_level00; - - struct state_t - { - inline void set(const precedence_level& l, - const precedence_level& r, - const details::operator_type& o, - const token_t tkn = token_t()) - { - left = l; - right = r; - operation = o; - token = tkn; - } - - inline void reset() - { - left = e_level00; - right = e_level00; - operation = details::e_default; - } - - precedence_level left; - precedence_level right; - details::operator_type operation; - token_t token; - }; - - inline void push_current_state(const state_t current_state) - { - current_state_stack_.push_back(current_state); - } - - inline void pop_current_state() - { - if (!current_state_stack_.empty()) - { - current_state_stack_.pop_back(); - } - } - - inline state_t current_state() const - { - return (!current_state_stack_.empty()) ? - current_state_stack_.back() : - state_t(); - } - - inline bool halt_compilation_check() - { - compilation_check::compilation_context context; - - if (compilation_check_ptr_ && !compilation_check_ptr_->continue_compilation(context)) - { - const std::string error_message = - !context.error_message.empty() ? " Details: " + context.error_message : ""; - - set_error(make_error( - parser_error::e_parser, - token_t(), - "ERR011 - Internal compilation check failed." + error_message, - exprtk_error_location)); - - return true; - } - - return false; - } - - inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) - { - if (halt_compilation_check()) - { - exprtk_debug(("halt_compilation_check() - parse_expression checkpoint 2\n")); - return error_node(); - } - - stack_limit_handler slh(*this); - - if (!slh) - { - return error_node(); - } - - expression_node_ptr expression = parse_branch(precedence); - - if (0 == expression) - { - return error_node(); - } - - if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) - { - return expression; - } - - bool break_loop = false; - - state_t current_state; - - for ( ; ; ) - { - current_state.reset(); - - switch (current_token().type) - { - case token_t::e_assign : current_state.set(e_level00, e_level00, details::e_assign, current_token()); break; - case token_t::e_addass : current_state.set(e_level00, e_level00, details::e_addass, current_token()); break; - case token_t::e_subass : current_state.set(e_level00, e_level00, details::e_subass, current_token()); break; - case token_t::e_mulass : current_state.set(e_level00, e_level00, details::e_mulass, current_token()); break; - case token_t::e_divass : current_state.set(e_level00, e_level00, details::e_divass, current_token()); break; - case token_t::e_modass : current_state.set(e_level00, e_level00, details::e_modass, current_token()); break; - case token_t::e_swap : current_state.set(e_level00, e_level00, details::e_swap , current_token()); break; - case token_t::e_lt : current_state.set(e_level05, e_level06, details::e_lt , current_token()); break; - case token_t::e_lte : current_state.set(e_level05, e_level06, details::e_lte , current_token()); break; - case token_t::e_eq : current_state.set(e_level05, e_level06, details::e_eq , current_token()); break; - case token_t::e_ne : current_state.set(e_level05, e_level06, details::e_ne , current_token()); break; - case token_t::e_gte : current_state.set(e_level05, e_level06, details::e_gte , current_token()); break; - case token_t::e_gt : current_state.set(e_level05, e_level06, details::e_gt , current_token()); break; - case token_t::e_add : current_state.set(e_level07, e_level08, details::e_add , current_token()); break; - case token_t::e_sub : current_state.set(e_level07, e_level08, details::e_sub , current_token()); break; - case token_t::e_div : current_state.set(e_level10, e_level11, details::e_div , current_token()); break; - case token_t::e_mul : current_state.set(e_level10, e_level11, details::e_mul , current_token()); break; - case token_t::e_mod : current_state.set(e_level10, e_level11, details::e_mod , current_token()); break; - case token_t::e_pow : current_state.set(e_level12, e_level12, details::e_pow , current_token()); break; - default : - if (token_t::e_symbol == current_token().type) - { - static const std::string s_and = "and" ; - static const std::string s_nand = "nand" ; - static const std::string s_or = "or" ; - static const std::string s_nor = "nor" ; - static const std::string s_xor = "xor" ; - static const std::string s_xnor = "xnor" ; - static const std::string s_in = "in" ; - static const std::string s_like = "like" ; - static const std::string s_ilike = "ilike"; - static const std::string s_and1 = "&" ; - static const std::string s_or1 = "|" ; - static const std::string s_not = "not" ; - - if (details::imatch(current_token().value,s_and)) - { - current_state.set(e_level03, e_level04, details::e_and, current_token()); - break; - } - else if (details::imatch(current_token().value,s_and1)) - { - #ifndef exprtk_disable_sc_andor - current_state.set(e_level03, e_level04, details::e_scand, current_token()); - #else - current_state.set(e_level03, e_level04, details::e_and, current_token()); - #endif - break; - } - else if (details::imatch(current_token().value,s_nand)) - { - current_state.set(e_level03, e_level04, details::e_nand, current_token()); - break; - } - else if (details::imatch(current_token().value,s_or)) - { - current_state.set(e_level01, e_level02, details::e_or, current_token()); - break; - } - else if (details::imatch(current_token().value,s_or1)) - { - #ifndef exprtk_disable_sc_andor - current_state.set(e_level01, e_level02, details::e_scor, current_token()); - #else - current_state.set(e_level01, e_level02, details::e_or, current_token()); - #endif - break; - } - else if (details::imatch(current_token().value,s_nor)) - { - current_state.set(e_level01, e_level02, details::e_nor, current_token()); - break; - } - else if (details::imatch(current_token().value,s_xor)) - { - current_state.set(e_level01, e_level02, details::e_xor, current_token()); - break; - } - else if (details::imatch(current_token().value,s_xnor)) - { - current_state.set(e_level01, e_level02, details::e_xnor, current_token()); - break; - } - else if (details::imatch(current_token().value,s_in)) - { - current_state.set(e_level04, e_level04, details::e_in, current_token()); - break; - } - else if (details::imatch(current_token().value,s_like)) - { - current_state.set(e_level04, e_level04, details::e_like, current_token()); - break; - } - else if (details::imatch(current_token().value,s_ilike)) - { - current_state.set(e_level04, e_level04, details::e_ilike, current_token()); - break; - } - else if (details::imatch(current_token().value,s_not)) - { - break; - } - } - - break_loop = true; - } - - if (break_loop) - { - parse_pending_string_rangesize(expression); - break; - } - else if (current_state.left < precedence) - break; - - const lexer::token prev_token = current_token(); - - next_token(); - - expression_node_ptr right_branch = error_node(); - expression_node_ptr new_expression = error_node(); - - if (is_invalid_logic_operation(current_state.operation)) - { - free_node(node_allocator_, expression); - - set_error(make_error( - parser_error::e_syntax, - prev_token, - "ERR012 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); - - return error_node(); - } - else if (is_invalid_arithmetic_operation(current_state.operation)) - { - free_node(node_allocator_, expression); - - set_error(make_error( - parser_error::e_syntax, - prev_token, - "ERR013 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); - - return error_node(); - } - else if (is_invalid_inequality_operation(current_state.operation)) - { - free_node(node_allocator_, expression); - - set_error(make_error( - parser_error::e_syntax, - prev_token, - "ERR014 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); - - return error_node(); - } - else if (is_invalid_assignment_operation(current_state.operation)) - { - free_node(node_allocator_, expression); - - set_error(make_error( - parser_error::e_syntax, - prev_token, - "ERR015 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", - exprtk_error_location)); - - return error_node(); - } - - if (0 != (right_branch = parse_expression(current_state.right))) - { - if ( - details::is_return_node(expression ) || - details::is_return_node(right_branch) - ) - { - free_node(node_allocator_, expression ); - free_node(node_allocator_, right_branch); - - set_error(make_error( - parser_error::e_syntax, - prev_token, - "ERR016 - Return statements cannot be part of sub-expressions", - exprtk_error_location)); - - return error_node(); - } - - push_current_state(current_state); - - new_expression = expression_generator_ - ( - current_state.operation, - expression, - right_branch - ); - - pop_current_state(); - } - - if (0 == new_expression) - { - if (error_list_.empty()) - { - set_error(make_error( - parser_error::e_syntax, - prev_token, - !synthesis_error_.empty() ? - synthesis_error_ : - "ERR017 - General parsing error at token: '" + prev_token.value + "'", - exprtk_error_location)); - } - - free_node(node_allocator_, expression ); - free_node(node_allocator_, right_branch); - - return error_node(); - } - else - { - if ( - token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && - (e_level00 == precedence) - ) - { - expression = parse_ternary_conditional_statement(new_expression); - } - else - expression = new_expression; - - parse_pending_string_rangesize(expression); - } - } - - if ((0 != expression) && (expression->node_depth() > settings_.max_node_depth_)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR018 - Expression depth of " + details::to_str(static_cast(expression->node_depth())) + - " exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), - exprtk_error_location)); - - free_node(node_allocator_, expression); - - return error_node(); - } - else if ( - !settings_.commutative_check_enabled() && - !details::is_logic_opr(current_token().value) && - (current_state.operation == details::e_default) && - ( - current_token().type == token_t::e_symbol || - current_token().type == token_t::e_number || - current_token().type == token_t::e_string - ) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR019 - Invalid syntax '" + current_token().value + "' possible missing operator or context", - exprtk_error_location)); - - free_node(node_allocator_, expression); - - return error_node(); - } - - return expression; - } - - bool simplify_unary_negation_branch(expression_node_ptr& node) - { - { - typedef details::unary_branch_node > ubn_t; - ubn_t* n = dynamic_cast(node); - - if (n) - { - expression_node_ptr un_r = n->branch(0); - n->release(); - free_node(node_allocator_, node); - node = un_r; - - return true; - } - } - - { - typedef details::unary_variable_node > uvn_t; - - uvn_t* n = dynamic_cast(node); - - if (n) - { - const T& v = n->v(); - expression_node_ptr return_node = error_node(); - - if ( - (0 != (return_node = symtab_store_.get_variable(v))) || - (0 != (return_node = sem_ .get_variable(v))) - ) - { - free_node(node_allocator_, node); - node = return_node; - - return true; - } - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR020 - Failed to find variable node in symbol table", - exprtk_error_location)); - - free_node(node_allocator_, node); - - return false; - } - } - } - - return false; - } - - static inline expression_node_ptr error_node() - { - return reinterpret_cast(0); - } - - struct scoped_expression_delete - { - scoped_expression_delete(parser& pr, expression_node_ptr& expression) - : delete_ptr(true) - , parser_(pr) - , expression_(expression) - {} - - ~scoped_expression_delete() - { - if (delete_ptr) - { - free_node(parser_.node_allocator_, expression_); - } - } - - bool delete_ptr; - parser& parser_; - expression_node_ptr& expression_; - - private: - - scoped_expression_delete(const scoped_expression_delete&) exprtk_delete; - scoped_expression_delete& operator=(const scoped_expression_delete&) exprtk_delete; - }; - - template - struct scoped_delete - { - typedef Type* ptr_t; - - scoped_delete(parser& pr, ptr_t& p) - : delete_ptr(true) - , parser_(pr) - , p_(&p) - {} - - scoped_delete(parser& pr, ptr_t (&p)[N]) - : delete_ptr(true) - , parser_(pr) - , p_(&p[0]) - {} - - ~scoped_delete() - { - if (delete_ptr) - { - for (std::size_t i = 0; i < N; ++i) - { - free_node(parser_.node_allocator_, p_[i]); - } - } - } - - bool delete_ptr; - parser& parser_; - ptr_t* p_; - - private: - - scoped_delete(const scoped_delete&) exprtk_delete; - scoped_delete& operator=(const scoped_delete&) exprtk_delete; - }; - - template - struct scoped_deq_delete - { - typedef Type* ptr_t; - - scoped_deq_delete(parser& pr, std::deque& deq) - : delete_ptr(true) - , parser_(pr) - , deq_(deq) - {} - - ~scoped_deq_delete() - { - if (delete_ptr && !deq_.empty()) - { - for (std::size_t i = 0; i < deq_.size(); ++i) - { - exprtk_debug(("~scoped_deq_delete() - deleting node: %p\n", reinterpret_cast(deq_[i]))); - free_node(parser_.node_allocator_,deq_[i]); - } - - deq_.clear(); - } - } - - bool delete_ptr; - parser& parser_; - std::deque& deq_; - - private: - - scoped_deq_delete(const scoped_deq_delete&) exprtk_delete; - scoped_deq_delete& operator=(const scoped_deq_delete&) exprtk_delete; - }; - - template - struct scoped_vec_delete - { - typedef Type* ptr_t; - - scoped_vec_delete(parser& pr, std::vector& vec) - : delete_ptr(true) - , parser_(pr) - , vec_(vec) - {} - - ~scoped_vec_delete() - { - if (delete_ptr && !vec_.empty()) - { - for (std::size_t i = 0; i < vec_.size(); ++i) - { - exprtk_debug(("~scoped_vec_delete() - deleting node: %p\n", reinterpret_cast(vec_[i]))); - free_node(parser_.node_allocator_,vec_[i]); - } - - vec_.clear(); - } - } - - ptr_t operator[](const std::size_t index) - { - return vec_[index]; - } - - bool delete_ptr; - parser& parser_; - std::vector& vec_; - - private: - - scoped_vec_delete(const scoped_vec_delete&) exprtk_delete; - scoped_vec_delete& operator=(const scoped_vec_delete&) exprtk_delete; - }; - - struct scoped_bool_negator - { - explicit scoped_bool_negator(bool& bb) - : b(bb) - { b = !b; } - - ~scoped_bool_negator() - { b = !b; } - - bool& b; - }; - - struct scoped_bool_or_restorer - { - explicit scoped_bool_or_restorer(bool& bb) - : b(bb) - , original_value_(bb) - {} - - ~scoped_bool_or_restorer() - { - b = b || original_value_; - } - - bool& b; - bool original_value_; - }; - - struct scoped_inc_dec - { - explicit scoped_inc_dec(std::size_t& v) - : v_(v) - { ++v_; } - - ~scoped_inc_dec() - { - assert(v_ > 0); - --v_; - } - - std::size_t& v_; - }; - - inline expression_node_ptr parse_function_invocation(ifunction* function, const std::string& function_name) - { - expression_node_ptr func_node = reinterpret_cast(0); - - switch (function->param_count) - { - case 0 : func_node = parse_function_call_0 (function,function_name); break; - case 1 : func_node = parse_function_call< 1>(function,function_name); break; - case 2 : func_node = parse_function_call< 2>(function,function_name); break; - case 3 : func_node = parse_function_call< 3>(function,function_name); break; - case 4 : func_node = parse_function_call< 4>(function,function_name); break; - case 5 : func_node = parse_function_call< 5>(function,function_name); break; - case 6 : func_node = parse_function_call< 6>(function,function_name); break; - case 7 : func_node = parse_function_call< 7>(function,function_name); break; - case 8 : func_node = parse_function_call< 8>(function,function_name); break; - case 9 : func_node = parse_function_call< 9>(function,function_name); break; - case 10 : func_node = parse_function_call<10>(function,function_name); break; - case 11 : func_node = parse_function_call<11>(function,function_name); break; - case 12 : func_node = parse_function_call<12>(function,function_name); break; - case 13 : func_node = parse_function_call<13>(function,function_name); break; - case 14 : func_node = parse_function_call<14>(function,function_name); break; - case 15 : func_node = parse_function_call<15>(function,function_name); break; - case 16 : func_node = parse_function_call<16>(function,function_name); break; - case 17 : func_node = parse_function_call<17>(function,function_name); break; - case 18 : func_node = parse_function_call<18>(function,function_name); break; - case 19 : func_node = parse_function_call<19>(function,function_name); break; - case 20 : func_node = parse_function_call<20>(function,function_name); break; - default : { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR021 - Invalid number of parameters for function: '" + function_name + "'", - exprtk_error_location)); - - return error_node(); - } - } - - if (func_node) - return func_node; - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR022 - Failed to generate call to function: '" + function_name + "'", - exprtk_error_location)); - - return error_node(); - } - } - - template - inline expression_node_ptr parse_function_call(ifunction* function, const std::string& function_name) - { - #ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable: 4127) - #endif - if (0 == NumberofParameters) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR023 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", - exprtk_error_location)); - - return error_node(); - } - #ifdef _MSC_VER - #pragma warning(pop) - #endif - - expression_node_ptr branch[NumberofParameters]; - expression_node_ptr result = error_node(); - - std::fill_n(branch, NumberofParameters, reinterpret_cast(0)); - - scoped_delete sd((*this),branch); - - next_token(); - - if (!token_is(token_t::e_lbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR024 - Expecting argument list for function: '" + function_name + "'", - exprtk_error_location)); - - return error_node(); - } - - for (int i = 0; i < static_cast(NumberofParameters); ++i) - { - branch[i] = parse_expression(); - - if (0 == branch[i]) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR025 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (i < static_cast(NumberofParameters - 1)) - { - if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR026 - Invalid number of arguments for function: '" + function_name + "'", - exprtk_error_location)); - - return error_node(); - } - } - } - - if (!token_is(token_t::e_rbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR027 - Invalid number of arguments for function: '" + function_name + "'", - exprtk_error_location)); - - return error_node(); - } - else - result = expression_generator_.function(function,branch); - - sd.delete_ptr = (0 == result); - - return result; - } - - inline expression_node_ptr parse_function_call_0(ifunction* function, const std::string& function_name) - { - expression_node_ptr result = expression_generator_.function(function); - - state_.side_effect_present = function->has_side_effects(); - - next_token(); - - if ( - token_is(token_t::e_lbracket) && - !token_is(token_t::e_rbracket) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR028 - Expecting '()' to proceed call to function: '" + function_name + "'", - exprtk_error_location)); - - free_node(node_allocator_, result); - - return error_node(); - } - else - return result; - } - - template - inline std::size_t parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters], const std::string& function_name = "") - { - std::fill_n(param_list, MaxNumberofParameters, reinterpret_cast(0)); - - scoped_delete sd((*this),param_list); - - next_token(); - - if (!token_is(token_t::e_lbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR029 - Expected a '(' at start of function call to '" + function_name + - "', instead got: '" + current_token().value + "'", - exprtk_error_location)); - - return 0; - } - - if (token_is(token_t::e_rbracket, e_hold)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR030 - Expected at least one input parameter for function call '" + function_name + "'", - exprtk_error_location)); - - return 0; - } - - std::size_t param_index = 0; - - for (; param_index < MaxNumberofParameters; ++param_index) - { - param_list[param_index] = parse_expression(); - - if (0 == param_list[param_index]) - return 0; - else if (token_is(token_t::e_rbracket)) - { - sd.delete_ptr = false; - break; - } - else if (token_is(token_t::e_comma)) - continue; - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR031 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", - exprtk_error_location)); - - return 0; - } - } - - if (sd.delete_ptr) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR032 - Invalid number of input parameters passed to function '" + function_name + "'", - exprtk_error_location)); - - return 0; - } - - return (param_index + 1); - } - - inline expression_node_ptr parse_base_operation() - { - typedef std::pair map_range_t; - - const std::string operation_name = current_token().value; - const token_t diagnostic_token = current_token(); - - map_range_t itr_range = base_ops_map_.equal_range(operation_name); - - if (0 == std::distance(itr_range.first,itr_range.second)) - { - set_error(make_error( - parser_error::e_syntax, - diagnostic_token, - "ERR033 - No entry found for base operation: " + operation_name, - exprtk_error_location)); - - return error_node(); - } - - static const std::size_t MaxNumberofParameters = 4; - expression_node_ptr param_list[MaxNumberofParameters] = {0}; - - const std::size_t parameter_count = parse_base_function_call(param_list, operation_name); - - if ((parameter_count > 0) && (parameter_count <= MaxNumberofParameters)) - { - for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) - { - const details::base_operation_t& operation = itr->second; - - if (operation.num_params == parameter_count) - { - switch (parameter_count) - { - #define base_opr_case(N) \ - case N : { \ - expression_node_ptr pl##N[N] = {0}; \ - std::copy(param_list, param_list + N, pl##N); \ - lodge_symbol(operation_name, e_st_function); \ - return expression_generator_(operation.type, pl##N); \ - } \ - - base_opr_case(1) - base_opr_case(2) - base_opr_case(3) - base_opr_case(4) - #undef base_opr_case - } - } - } - } - - for (std::size_t i = 0; i < MaxNumberofParameters; ++i) - { - free_node(node_allocator_, param_list[i]); - } - - set_error(make_error( - parser_error::e_syntax, - diagnostic_token, - "ERR034 - Invalid number of input parameters for call to function: '" + operation_name + "'", - exprtk_error_location)); - - return error_node(); - } - - inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition) - { - // Parse: [if][(][condition][,][consequent][,][alternative][)] - - expression_node_ptr consequent = error_node(); - expression_node_ptr alternative = error_node(); - - bool result = true; - - if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR035 - Expected ',' between if-statement condition and consequent", - exprtk_error_location)); - - result = false; - } - else if (0 == (consequent = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR036 - Failed to parse consequent for if-statement", - exprtk_error_location)); - - result = false; - } - else if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR037 - Expected ',' between if-statement consequent and alternative", - exprtk_error_location)); - - result = false; - } - else if (0 == (alternative = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR038 - Failed to parse alternative for if-statement", - exprtk_error_location)); - - result = false; - } - else if (!token_is(token_t::e_rbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR039 - Expected ')' at the end of if-statement", - exprtk_error_location)); - - result = false; - } - - #ifndef exprtk_disable_string_capabilities - if (result) - { - const bool consq_is_str = is_generally_string_node(consequent ); - const bool alter_is_str = is_generally_string_node(alternative); - - if (consq_is_str || alter_is_str) - { - if (consq_is_str && alter_is_str) - { - expression_node_ptr result_node = - expression_generator_ - .conditional_string(condition, consequent, alternative); - - if (result_node && result_node->valid()) - { - return result_node; - } - - set_error(make_error( - parser_error::e_synthesis, - current_token(), - "ERR040 - Failed to synthesize node: conditional_string", - exprtk_error_location)); - - free_node(node_allocator_, result_node); - return error_node(); - } - - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR041 - Return types of if-statement differ: string/non-string", - exprtk_error_location)); - - result = false; - } - } - #endif - - if (result) - { - const bool consq_is_vec = is_ivector_node(consequent ); - const bool alter_is_vec = is_ivector_node(alternative); - - if (consq_is_vec || alter_is_vec) - { - if (consq_is_vec && alter_is_vec) - { - return expression_generator_ - .conditional_vector(condition, consequent, alternative); - } - - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR042 - Return types of if-statement differ: vector/non-vector", - exprtk_error_location)); - - result = false; - } - } - - if (!result) - { - free_node(node_allocator_, condition ); - free_node(node_allocator_, consequent ); - free_node(node_allocator_, alternative); - - return error_node(); - } - else - return expression_generator_ - .conditional(condition, consequent, alternative); - } - - inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) - { - expression_node_ptr consequent = error_node(); - expression_node_ptr alternative = error_node(); - - bool result = true; - - if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) - { - if (0 == (consequent = parse_multi_sequence("if-statement-01"))) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR043 - Failed to parse body of consequent for if-statement", - exprtk_error_location)); - - result = false; - } - else if - ( - !settings_.commutative_check_enabled() && - !token_is("else",prsrhlpr_t::e_hold) && - !token_is_loop(prsrhlpr_t::e_hold) && - !token_is_arithmetic_opr(prsrhlpr_t::e_hold) && - !token_is_right_bracket (prsrhlpr_t::e_hold) && - !token_is_ineq_opr (prsrhlpr_t::e_hold) && - !token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && - !token_is(token_t::e_eof ,prsrhlpr_t::e_hold) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR044 - Expected ';' at the end of the consequent for if-statement (1)", - exprtk_error_location)); - - result = false; - } - } - else - { - if ( - settings_.commutative_check_enabled() && - token_is(token_t::e_mul,prsrhlpr_t::e_hold) - ) - { - next_token(); - } - - if (0 != (consequent = parse_expression())) - { - if (!token_is(token_t::e_eof, prsrhlpr_t::e_hold)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR045 - Expected ';' at the end of the consequent for if-statement (2)", - exprtk_error_location)); - - result = false; - } - } - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR046 - Failed to parse body of consequent for if-statement", - exprtk_error_location)); - - result = false; - } - } - - if (result) - { - if ( - details::imatch(current_token().value,"else") || - (token_is(token_t::e_eof, prsrhlpr_t::e_hold) && peek_token_is("else")) - ) - { - next_token(); - - if (details::imatch(current_token().value,"else")) - { - next_token(); - } - - if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) - { - if (0 == (alternative = parse_multi_sequence("else-statement-01"))) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR047 - Failed to parse body of the 'else' for if-statement", - exprtk_error_location)); - - result = false; - } - } - else if (details::imatch(current_token().value,"if")) - { - if (0 == (alternative = parse_conditional_statement())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR048 - Failed to parse body of if-else statement", - exprtk_error_location)); - - result = false; - } - } - else if (0 != (alternative = parse_expression())) - { - if ( - !token_is(token_t::e_ternary , prsrhlpr_t::e_hold) && - !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && - !token_is(token_t::e_eof) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR049 - Expected ';' at the end of the 'else-if' for the if-statement", - exprtk_error_location)); - - result = false; - } - } - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR050 - Failed to parse body of the 'else' for if-statement", - exprtk_error_location)); - - result = false; - } - } - } - - #ifndef exprtk_disable_string_capabilities - if (result) - { - const bool consq_is_str = is_generally_string_node(consequent ); - const bool alter_is_str = is_generally_string_node(alternative); - - if (consq_is_str || alter_is_str) - { - if (consq_is_str && alter_is_str) - { - return expression_generator_ - .conditional_string(condition, consequent, alternative); - } - - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR051 - Return types of if-statement differ: string/non-string", - exprtk_error_location)); - - result = false; - } - } - #endif - - if (result) - { - const bool consq_is_vec = is_ivector_node(consequent ); - const bool alter_is_vec = is_ivector_node(alternative); - - if (consq_is_vec || alter_is_vec) - { - if (consq_is_vec && alter_is_vec) - { - return expression_generator_ - .conditional_vector(condition, consequent, alternative); - } - - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR052 - Return types of if-statement differ: vector/non-vector", - exprtk_error_location)); - - result = false; - } - } - - if (!result) - { - free_node(node_allocator_, condition ); - free_node(node_allocator_, consequent ); - free_node(node_allocator_, alternative); - - return error_node(); - } - else - return expression_generator_ - .conditional(condition, consequent, alternative); - } - - inline expression_node_ptr parse_conditional_statement() - { - expression_node_ptr condition = error_node(); - - next_token(); - - if (!token_is(token_t::e_lbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR053 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", - exprtk_error_location)); - - return error_node(); - } - else if (0 == (condition = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR054 - Failed to parse condition for if-statement", - exprtk_error_location)); - - return error_node(); - } - else if (token_is(token_t::e_comma,prsrhlpr_t::e_hold)) - { - // if (x,y,z) - return parse_conditional_statement_01(condition); - } - else if (token_is(token_t::e_rbracket)) - { - /* - 00. if (x) y; - 01. if (x) y; else z; - 02. if (x) y; else {z0; ... zn;} - 03. if (x) y; else if (z) w; - 04. if (x) y; else if (z) w; else u; - 05. if (x) y; else if (z) w; else {u0; ... un;} - 06. if (x) y; else if (z) {w0; ... wn;} - 07. if (x) {y0; ... yn;} - 08. if (x) {y0; ... yn;} else z; - 09. if (x) {y0; ... yn;} else {z0; ... zn;}; - 10. if (x) {y0; ... yn;} else if (z) w; - 11. if (x) {y0; ... yn;} else if (z) w; else u; - 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} - 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} - */ - return parse_conditional_statement_02(condition); - } - - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR055 - Invalid if-statement", - exprtk_error_location)); - - free_node(node_allocator_, condition); - - return error_node(); - } - - inline expression_node_ptr parse_ternary_conditional_statement(expression_node_ptr condition) - { - // Parse: [condition][?][consequent][:][alternative] - expression_node_ptr consequent = error_node(); - expression_node_ptr alternative = error_node(); - - bool result = true; - - if (0 == condition) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR056 - Encountered invalid condition branch for ternary if-statement", - exprtk_error_location)); - - return error_node(); - } - else if (!token_is(token_t::e_ternary)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR057 - Expected '?' after condition of ternary if-statement", - exprtk_error_location)); - - result = false; - } - else if (0 == (consequent = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR058 - Failed to parse consequent for ternary if-statement", - exprtk_error_location)); - - result = false; - } - else if (!token_is(token_t::e_colon)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR059 - Expected ':' between ternary if-statement consequent and alternative", - exprtk_error_location)); - - result = false; - } - else if (0 == (alternative = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR060 - Failed to parse alternative for ternary if-statement", - exprtk_error_location)); - - result = false; - } - - #ifndef exprtk_disable_string_capabilities - if (result) - { - const bool consq_is_str = is_generally_string_node(consequent ); - const bool alter_is_str = is_generally_string_node(alternative); - - if (consq_is_str || alter_is_str) - { - if (consq_is_str && alter_is_str) - { - return expression_generator_ - .conditional_string(condition, consequent, alternative); - } - - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR061 - Return types of ternary differ: string/non-string", - exprtk_error_location)); - - result = false; - } - } - #endif - - if (result) - { - const bool consq_is_vec = is_ivector_node(consequent ); - const bool alter_is_vec = is_ivector_node(alternative); - - if (consq_is_vec || alter_is_vec) - { - if (consq_is_vec && alter_is_vec) - { - return expression_generator_ - .conditional_vector(condition, consequent, alternative); - } - - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR062 - Return types of ternary differ: vector/non-vector", - exprtk_error_location)); - - result = false; - } - } - - if (!result) - { - free_node(node_allocator_, condition ); - free_node(node_allocator_, consequent ); - free_node(node_allocator_, alternative); - - return error_node(); - } - else - return expression_generator_ - .conditional(condition, consequent, alternative); - } - - inline expression_node_ptr parse_not_statement() - { - if (settings_.logic_disabled("not")) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR063 - Invalid or disabled logic operation 'not'", - exprtk_error_location)); - - return error_node(); - } - - return parse_base_operation(); - } - - void handle_brkcnt_scope_exit() - { - assert(!brkcnt_list_.empty()); - brkcnt_list_.pop_front(); - } - - inline expression_node_ptr parse_while_loop() - { - // Parse: [while][(][test expr][)][{][expression][}] - expression_node_ptr condition = error_node(); - expression_node_ptr branch = error_node(); - expression_node_ptr result_node = error_node(); - - bool result = true; - - next_token(); - - if (!token_is(token_t::e_lbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR064 - Expected '(' at start of while-loop condition statement", - exprtk_error_location)); - - return error_node(); - } - else if (0 == (condition = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR065 - Failed to parse condition for while-loop", - exprtk_error_location)); - - return error_node(); - } - else if (!token_is(token_t::e_rbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR066 - Expected ')' at end of while-loop condition statement", - exprtk_error_location)); - - result = false; - } - - brkcnt_list_.push_front(false); - - if (result) - { - scoped_inc_dec sid(state_.parsing_loop_stmt_count); - - if (0 == (branch = parse_multi_sequence("while-loop", true))) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR067 - Failed to parse body of while-loop")); - result = false; - } - else if (0 == (result_node = expression_generator_.while_loop(condition, - branch, - brkcnt_list_.front()))) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR068 - Failed to synthesize while-loop", - exprtk_error_location)); - - result = false; - } - } - - handle_brkcnt_scope_exit(); - - if (!result) - { - free_node(node_allocator_, branch ); - free_node(node_allocator_, condition ); - free_node(node_allocator_, result_node); - - return error_node(); - } - - if (result_node && result_node->valid()) - { - return result_node; - } - - set_error(make_error( - parser_error::e_synthesis, - current_token(), - "ERR069 - Failed to synthesize 'valid' while-loop", - exprtk_error_location)); - - free_node(node_allocator_, result_node); - - return error_node(); - } - - inline expression_node_ptr parse_repeat_until_loop() - { - // Parse: [repeat][{][expression][}][until][(][test expr][)] - expression_node_ptr condition = error_node(); - expression_node_ptr branch = error_node(); - next_token(); - - std::vector arg_list; - std::vector side_effect_list; - - scoped_vec_delete sdd((*this),arg_list); - - brkcnt_list_.push_front(false); - - if (details::imatch(current_token().value,"until")) - { - next_token(); - branch = node_allocator_.allocate >(); - } - else - { - const token_t::token_type separator = token_t::e_eof; - - scope_handler sh(*this); - - scoped_bool_or_restorer sbr(state_.side_effect_present); - - scoped_inc_dec sid(state_.parsing_loop_stmt_count); - - for ( ; ; ) - { - state_.side_effect_present = false; - - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - else - { - arg_list.push_back(arg); - side_effect_list.push_back(state_.side_effect_present); - } - - if (details::imatch(current_token().value,"until")) - { - next_token(); - break; - } - - const bool is_next_until = peek_token_is(token_t::e_symbol) && - peek_token_is("until"); - - if (!token_is(separator) && is_next_until) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR070 - Expected '" + token_t::to_str(separator) + "' in body of repeat until loop", - exprtk_error_location)); - - return error_node(); - } - - if (details::imatch(current_token().value,"until")) - { - next_token(); - break; - } - } - - branch = simplify(arg_list,side_effect_list); - - sdd.delete_ptr = (0 == branch); - - if (sdd.delete_ptr) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR071 - Failed to parse body of repeat until loop", - exprtk_error_location)); - - return error_node(); - } - } - - if (!token_is(token_t::e_lbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR072 - Expected '(' before condition statement of repeat until loop", - exprtk_error_location)); - - free_node(node_allocator_, branch); - return error_node(); - } - else if (0 == (condition = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR073 - Failed to parse condition for repeat until loop", - exprtk_error_location)); - - free_node(node_allocator_, branch); - return error_node(); - } - else if (!token_is(token_t::e_rbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR074 - Expected ')' after condition of repeat until loop", - exprtk_error_location)); - - free_node(node_allocator_, branch ); - free_node(node_allocator_, condition); - - return error_node(); - } - - expression_node_ptr result_node = - expression_generator_ - .repeat_until_loop( - condition, - branch, - brkcnt_list_.front()); - - if (0 == result_node) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR075 - Failed to synthesize repeat until loop", - exprtk_error_location)); - - free_node(node_allocator_, condition); - - return error_node(); - } - - handle_brkcnt_scope_exit(); - - if (result_node && result_node->valid()) - { - return result_node; - } - - set_error(make_error( - parser_error::e_synthesis, - current_token(), - "ERR076 - Failed to synthesize 'valid' repeat until loop", - exprtk_error_location)); - - free_node(node_allocator_, result_node); - - return error_node(); - } - - inline expression_node_ptr parse_for_loop() - { - expression_node_ptr initialiser = error_node(); - expression_node_ptr condition = error_node(); - expression_node_ptr incrementor = error_node(); - expression_node_ptr loop_body = error_node(); - - scope_element* se = 0; - bool result = true; - - next_token(); - - scope_handler sh(*this); - - if (!token_is(token_t::e_lbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR077 - Expected '(' at start of for-loop", - exprtk_error_location)); - - return error_node(); - } - - if (!token_is(token_t::e_eof)) - { - if ( - !token_is(token_t::e_symbol,prsrhlpr_t::e_hold) && - details::imatch(current_token().value,"var") - ) - { - next_token(); - - if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR078 - Expected a variable at the start of initialiser section of for-loop", - exprtk_error_location)); - - return error_node(); - } - else if (!peek_token_is(token_t::e_assign)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR079 - Expected variable assignment of initialiser section of for-loop", - exprtk_error_location)); - - return error_node(); - } - - const std::string loop_counter_symbol = current_token().value; - - se = &sem_.get_element(loop_counter_symbol); - - if ((se->name == loop_counter_symbol) && se->active) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR080 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", - exprtk_error_location)); - - return error_node(); - } - else if (!symtab_store_.is_variable(loop_counter_symbol)) - { - if ( - !se->active && - (se->name == loop_counter_symbol) && - (se->type == scope_element::e_variable) - ) - { - se->active = true; - se->ref_count++; - } - else - { - scope_element nse; - nse.name = loop_counter_symbol; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_variable; - nse.depth = state_.scope_depth; - nse.data = new T(T(0)); - nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); - - if (!sem_.add_element(nse)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR081 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", - exprtk_error_location)); - - sem_.free_element(nse); - - result = false; - } - else - { - exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n", nse.name.c_str())); - - state_.activate_side_effect("parse_for_loop()"); - } - } - } - } - - if (0 == (initialiser = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR082 - Failed to parse initialiser of for-loop", - exprtk_error_location)); - - result = false; - } - else if (!token_is(token_t::e_eof)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR083 - Expected ';' after initialiser of for-loop", - exprtk_error_location)); - - result = false; - } - } - - if (!token_is(token_t::e_eof)) - { - if (0 == (condition = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR084 - Failed to parse condition of for-loop", - exprtk_error_location)); - - result = false; - } - else if (!token_is(token_t::e_eof)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR085 - Expected ';' after condition section of for-loop", - exprtk_error_location)); - - result = false; - } - } - - if (!token_is(token_t::e_rbracket)) - { - if (0 == (incrementor = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR086 - Failed to parse incrementor of for-loop", - exprtk_error_location)); - - result = false; - } - else if (!token_is(token_t::e_rbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR087 - Expected ')' after incrementor section of for-loop", - exprtk_error_location)); - - result = false; - } - } - - if (result) - { - brkcnt_list_.push_front(false); - - scoped_inc_dec sid(state_.parsing_loop_stmt_count); - - if (0 == (loop_body = parse_multi_sequence("for-loop", true))) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR088 - Failed to parse body of for-loop", - exprtk_error_location)); - - result = false; - } - } - - if (!result) - { - if (se) - { - se->ref_count--; - } - - free_node(node_allocator_, initialiser); - free_node(node_allocator_, condition ); - free_node(node_allocator_, incrementor); - free_node(node_allocator_, loop_body ); - return error_node(); - } - - expression_node_ptr result_node = - expression_generator_.for_loop(initialiser, - condition, - incrementor, - loop_body, - brkcnt_list_.front()); - handle_brkcnt_scope_exit(); - - if (result_node && result_node->valid()) - { - return result_node; - } - - set_error(make_error( - parser_error::e_synthesis, - current_token(), - "ERR089 - Failed to synthesize 'valid' for-loop", - exprtk_error_location)); - - free_node(node_allocator_, result_node); - - return error_node(); - } - - inline expression_node_ptr parse_switch_statement() - { - std::vector arg_list; - expression_node_ptr result = error_node(); - - if (!details::imatch(current_token().value,"switch")) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR090 - Expected keyword 'switch'", - exprtk_error_location)); - - return error_node(); - } - - scoped_vec_delete svd((*this),arg_list); - - next_token(); - - if (!token_is(token_t::e_lcrlbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR091 - Expected '{' for call to switch statement", - exprtk_error_location)); - - return error_node(); - } - - expression_node_ptr default_statement = error_node(); - - scoped_expression_delete defstmt_delete((*this), default_statement); - - for ( ; ; ) - { - if (details::imatch("case",current_token().value)) - { - next_token(); - - expression_node_ptr condition = parse_expression(); - - if (0 == condition) - return error_node(); - else if (!token_is(token_t::e_colon)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR092 - Expected ':' for case of switch statement", - exprtk_error_location)); - - free_node(node_allocator_, condition); - - return error_node(); - } - - expression_node_ptr consequent = - (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) ? - parse_multi_sequence("switch-consequent") : - parse_expression(); - - if (0 == consequent) - { - free_node(node_allocator_, condition); - - return error_node(); - } - else if (!token_is(token_t::e_eof)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR093 - Expected ';' at end of case for switch statement", - exprtk_error_location)); - - free_node(node_allocator_, condition ); - free_node(node_allocator_, consequent); - - return error_node(); - } - - // Can we optimise away the case statement? - if (is_constant_node(condition) && is_false(condition)) - { - free_node(node_allocator_, condition ); - free_node(node_allocator_, consequent); - } - else - { - arg_list.push_back(condition ); - arg_list.push_back(consequent); - } - - } - else if (details::imatch("default",current_token().value)) - { - if (0 != default_statement) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR094 - Multiple default cases for switch statement", - exprtk_error_location)); - - return error_node(); - } - - next_token(); - - if (!token_is(token_t::e_colon)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR095 - Expected ':' for default of switch statement", - exprtk_error_location)); - - return error_node(); - } - - default_statement = - (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) ? - parse_multi_sequence("switch-default"): - parse_expression(); - - if (0 == default_statement) - return error_node(); - else if (!token_is(token_t::e_eof)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR096 - Expected ';' at end of default for switch statement", - exprtk_error_location)); - - return error_node(); - } - } - else if (token_is(token_t::e_rcrlbracket)) - break; - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR097 - Expected '}' at end of switch statement", - exprtk_error_location)); - - return error_node(); - } - } - - const bool default_statement_present = (0 != default_statement); - - if (default_statement_present) - { - arg_list.push_back(default_statement); - } - else - { - arg_list.push_back(node_allocator_.allocate_c(std::numeric_limits::quiet_NaN())); - } - - result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); - - svd.delete_ptr = (0 == result); - defstmt_delete.delete_ptr = (0 == result); - - return result; - } - - inline expression_node_ptr parse_multi_switch_statement() - { - std::vector arg_list; - - if (!details::imatch(current_token().value,"[*]")) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR098 - Expected token '[*]'", - exprtk_error_location)); - - return error_node(); - } - - scoped_vec_delete svd((*this),arg_list); - - next_token(); - - if (!token_is(token_t::e_lcrlbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR099 - Expected '{' for call to [*] statement", - exprtk_error_location)); - - return error_node(); - } - - for ( ; ; ) - { - if (!details::imatch("case",current_token().value)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR100 - Expected a 'case' statement for multi-switch", - exprtk_error_location)); - - return error_node(); - } - - next_token(); - - expression_node_ptr condition = parse_expression(); - - if (0 == condition) - return error_node(); - - if (!token_is(token_t::e_colon)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR101 - Expected ':' for case of [*] statement", - exprtk_error_location)); - - return error_node(); - } - - expression_node_ptr consequent = - (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) ? - parse_multi_sequence("multi-switch-consequent") : - parse_expression(); - - if (0 == consequent) - return error_node(); - - if (!token_is(token_t::e_eof)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR102 - Expected ';' at end of case for [*] statement", - exprtk_error_location)); - - return error_node(); - } - - // Can we optimise away the case statement? - if (is_constant_node(condition) && is_false(condition)) - { - free_node(node_allocator_, condition ); - free_node(node_allocator_, consequent); - } - else - { - arg_list.push_back(condition ); - arg_list.push_back(consequent); - } - - if (token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold)) - { - break; - } - } - - if (!token_is(token_t::e_rcrlbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR103 - Expected '}' at end of [*] statement", - exprtk_error_location)); - - return error_node(); - } - - const expression_node_ptr result = expression_generator_.multi_switch_statement(arg_list); - - svd.delete_ptr = (0 == result); - - return result; - } - - inline expression_node_ptr parse_vararg_function() - { - std::vector arg_list; - - details::operator_type opt_type = details::e_default; - const std::string symbol = current_token().value; - - if (details::imatch(symbol,"~")) - { - next_token(); - return check_block_statement_closure(parse_multi_sequence()); - } - else if (details::imatch(symbol,"[*]")) - { - return check_block_statement_closure(parse_multi_switch_statement()); - } - else if (details::imatch(symbol, "avg" )) opt_type = details::e_avg ; - else if (details::imatch(symbol, "mand")) opt_type = details::e_mand; - else if (details::imatch(symbol, "max" )) opt_type = details::e_max ; - else if (details::imatch(symbol, "min" )) opt_type = details::e_min ; - else if (details::imatch(symbol, "mor" )) opt_type = details::e_mor ; - else if (details::imatch(symbol, "mul" )) opt_type = details::e_prod; - else if (details::imatch(symbol, "sum" )) opt_type = details::e_sum ; - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR104 - Unsupported built-in vararg function: " + symbol, - exprtk_error_location)); - - return error_node(); - } - - scoped_vec_delete sdd((*this),arg_list); - - lodge_symbol(symbol, e_st_function); - - next_token(); - - if (!token_is(token_t::e_lbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR105 - Expected '(' for call to vararg function: " + symbol, - exprtk_error_location)); - - return error_node(); - } - - if (token_is(token_t::e_rbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR106 - vararg function: " + symbol + - " requires at least one input parameter", - exprtk_error_location)); - - return error_node(); - } - - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - else - arg_list.push_back(arg); - - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR107 - Expected ',' for call to vararg function: " + symbol, - exprtk_error_location)); - - return error_node(); - } - } - - const expression_node_ptr result = expression_generator_.vararg_function(opt_type,arg_list); - - sdd.delete_ptr = (0 == result); - return result; - } - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression) - { - if (!token_is(token_t::e_lsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR108 - Expected '[' as start of string range definition", - exprtk_error_location)); - - free_node(node_allocator_, expression); - - return error_node(); - } - else if (token_is(token_t::e_rsqrbracket)) - { - return node_allocator_.allocate >(expression); - } - - range_t rp; - - if (!parse_range(rp,true)) - { - free_node(node_allocator_, expression); - - return error_node(); - } - - expression_node_ptr result = expression_generator_(expression,rp); - - if (0 == result) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR109 - Failed to generate string range node", - exprtk_error_location)); - - free_node(node_allocator_, expression); - rp.free(); - } - - rp.clear(); - - if (result && result->valid()) - { - return result; - } - - set_error(make_error( - parser_error::e_synthesis, - current_token(), - "ERR110 - Failed to synthesize node: string_range_node", - exprtk_error_location)); - - free_node(node_allocator_, result); - rp.free(); - return error_node(); - } - #else - inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) - { - return error_node(); - } - #endif - - inline bool parse_pending_string_rangesize(expression_node_ptr& expression) - { - // Allow no more than 100 range calls, eg: s[][][]...[][] - const std::size_t max_rangesize_parses = 100; - - std::size_t i = 0; - - while - ( - (0 != expression) && - (i++ < max_rangesize_parses) && - error_list_.empty() && - is_generally_string_node(expression) && - token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold) - ) - { - expression = parse_string_range_statement(expression); - } - - return (i > 1); - } - - inline void parse_pending_vector_index_operator(expression_node_ptr& expression) - { - if - ( - (0 != expression) && - error_list_.empty() && - is_ivector_node(expression) - ) - { - if ( - settings_.commutative_check_enabled() && - token_is(token_t::e_mul,prsrhlpr_t::e_hold) && - peek_token_is(token_t::e_lsqrbracket) - ) - { - token_is(token_t::e_mul); - token_is(token_t::e_lsqrbracket); - } - else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) - { - token_is(token_t::e_lsqrbracket); - } - else if ( - token_is(token_t::e_rbracket,prsrhlpr_t::e_hold) && - peek_token_is(token_t::e_lsqrbracket) - ) - { - token_is(token_t::e_rbracket ); - token_is(token_t::e_lsqrbracket); - } - else - return; - - details::vector_interface* vi = dynamic_cast*>(expression); - - if (vi) - { - details::vector_holder& vec = vi->vec()->vec_holder(); - const std::string vector_name = sem_.get_vector_name(vec.data()); - expression_node_ptr index = parse_vector_index(vector_name); - - if (index) - { - expression = synthesize_vector_element(vector_name, &vec, expression, index); - return; - } - } - - free_node(node_allocator_, expression); - expression = error_node(); - } - } - - template class Sequence> - inline expression_node_ptr simplify(Sequence& expression_list, - Sequence& side_effect_list, - const bool specialise_on_final_type = false) - { - if (expression_list.empty()) - return error_node(); - else if (1 == expression_list.size()) - return expression_list[0]; - - Sequence tmp_expression_list; - - exprtk_debug(("simplify() - expression_list.size: %d side_effect_list.size(): %d\n", - static_cast(expression_list .size()), - static_cast(side_effect_list.size()))); - - bool return_node_present = false; - - for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) - { - if (is_variable_node(expression_list[i])) - continue; - else if ( - is_return_node (expression_list[i]) || - is_break_node (expression_list[i]) || - is_continue_node(expression_list[i]) - ) - { - tmp_expression_list.push_back(expression_list[i]); - - // Remove all subexpressions after first short-circuit - // node has been encountered. - - for (std::size_t j = i + 1; j < expression_list.size(); ++j) - { - free_node(node_allocator_, expression_list[j]); - } - - return_node_present = true; - - break; - } - else if ( - is_constant_node(expression_list[i]) || - is_null_node (expression_list[i]) || - !side_effect_list[i] - ) - { - free_node(node_allocator_, expression_list[i]); - continue; - } - else - tmp_expression_list.push_back(expression_list[i]); - } - - if (!return_node_present) - { - tmp_expression_list.push_back(expression_list.back()); - } - - expression_list.swap(tmp_expression_list); - - if (tmp_expression_list.size() > expression_list.size()) - { - exprtk_debug(("simplify() - Reduced subexpressions from %d to %d\n", - static_cast(tmp_expression_list.size()), - static_cast(expression_list .size()))); - } - - if ( - return_node_present || - side_effect_list.back() || - (expression_list.size() > 1) - ) - state_.activate_side_effect("simplify()"); - - if (1 == expression_list.size()) - return expression_list[0]; - else if (specialise_on_final_type && is_generally_string_node(expression_list.back())) - return expression_generator_.vararg_function(details::e_smulti,expression_list); - else - return expression_generator_.vararg_function(details::e_multi,expression_list); - } - - inline expression_node_ptr parse_multi_sequence(const std::string& source = "", - const bool enforce_crlbrackets = false) - { - token_t::token_type open_bracket = token_t::e_lcrlbracket; - token_t::token_type close_bracket = token_t::e_rcrlbracket; - token_t::token_type separator = token_t::e_eof; - - if (!token_is(open_bracket)) - { - if (!enforce_crlbrackets && token_is(token_t::e_lbracket)) - { - open_bracket = token_t::e_lbracket; - close_bracket = token_t::e_rbracket; - separator = token_t::e_comma; - } - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR111 - Expected '" + token_t::to_str(open_bracket) + "' for call to multi-sequence" + - ((!source.empty()) ? std::string(" section of " + source): ""), - exprtk_error_location)); - - return error_node(); - } - } - else if (token_is(close_bracket)) - { - return node_allocator_.allocate >(); - } - - std::vector arg_list; - std::vector side_effect_list; - - expression_node_ptr result = error_node(); - - scoped_vec_delete sdd((*this),arg_list); - - scope_handler sh(*this); - - scoped_bool_or_restorer sbr(state_.side_effect_present); - - for ( ; ; ) - { - state_.side_effect_present = false; - - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - else - { - arg_list.push_back(arg); - side_effect_list.push_back(state_.side_effect_present); - } - - if (token_is(close_bracket)) - break; - - const bool is_next_close = peek_token_is(close_bracket); - - if (!token_is(separator) && is_next_close) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR112 - Expected '" + lexer::token::seperator_to_str(separator) + "' for call to multi-sequence section of " + source, - exprtk_error_location)); - - return error_node(); - } - - if (token_is(close_bracket)) - break; - } - - result = simplify(arg_list, side_effect_list, source.empty()); - - sdd.delete_ptr = (0 == result); - return result; - } - - inline bool parse_range(range_t& rp, const bool skip_lsqr = false) - { - // Examples of valid ranges: - // 1. [1:5] -> [1,5) - // 2. [ :5] -> [0,5) - // 3. [1: ] -> [1,end) - // 4. [x:y] -> [x,y) where x <= y - // 5. [x+1:y/2] -> [x+1,y/2) where x+1 <= y/2 - // 6. [ :y] -> [0,y) where 0 <= y - // 7. [x: ] -> [x,end) where x <= end - - rp.clear(); - - if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR113 - Expected '[' for start of range", - exprtk_error_location)); - - return false; - } - - if (token_is(token_t::e_colon)) - { - rp.n0_c.first = true; - rp.n0_c.second = 0; - rp.cache.first = 0; - } - else - { - expression_node_ptr r0 = parse_expression(); - - if (0 == r0) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR114 - Failed parse begin section of range", - exprtk_error_location)); - - return false; - } - else if (is_constant_node(r0)) - { - const T r0_value = r0->value(); - - if (r0_value >= T(0)) - { - rp.n0_c.first = true; - rp.n0_c.second = static_cast(details::numeric::to_int64(r0_value)); - rp.cache.first = rp.n0_c.second; - } - - free_node(node_allocator_, r0); - - if (r0_value < T(0)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR115 - Range lower bound less than zero! Constraint: r0 >= 0", - exprtk_error_location)); - - return false; - } - } - else - { - rp.n0_e.first = true; - rp.n0_e.second = r0; - } - - if (!token_is(token_t::e_colon)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR116 - Expected ':' for break in range", - exprtk_error_location)); - - rp.free(); - - return false; - } - } - - if (token_is(token_t::e_rsqrbracket)) - { - rp.n1_c.first = true; - rp.n1_c.second = std::numeric_limits::max(); - } - else - { - expression_node_ptr r1 = parse_expression(); - - if (0 == r1) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR117 - Failed parse end section of range", - exprtk_error_location)); - - rp.free(); - - return false; - } - else if (is_constant_node(r1)) - { - const T r1_value = r1->value(); - - if (r1_value >= T(0)) - { - rp.n1_c.first = true; - rp.n1_c.second = static_cast(details::numeric::to_int64(r1_value)); - rp.cache.second = rp.n1_c.second; - } - - free_node(node_allocator_, r1); - - if (r1_value < T(0)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR118 - Range upper bound less than zero! Constraint: r1 >= 0", - exprtk_error_location)); - - rp.free(); - - return false; - } - } - else - { - rp.n1_e.first = true; - rp.n1_e.second = r1; - } - - if (!token_is(token_t::e_rsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR119 - Expected ']' for start of range", - exprtk_error_location)); - - rp.free(); - - return false; - } - } - - if (rp.const_range()) - { - std::size_t r0 = 0; - std::size_t r1 = 0; - - bool rp_result = false; - - try - { - rp_result = rp(r0, r1); - } - catch (std::runtime_error&) - {} - - if (!rp_result || (r0 > r1)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR120 - Invalid range, Constraint: r0 <= r1", - exprtk_error_location)); - - return false; - } - } - - return true; - } - - inline void lodge_symbol(const std::string& symbol, - const symbol_type st) - { - dec_.add_symbol(symbol,st); - } - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_string() - { - const std::string symbol = current_token().value; - - typedef details::stringvar_node* strvar_node_t; - - expression_node_ptr result = error_node(); - strvar_node_t const_str_node = static_cast(0); - - scope_element& se = sem_.get_active_element(symbol); - - if (scope_element::e_string == se.type) - { - se.active = true; - result = se.str_node; - lodge_symbol(symbol, e_st_local_string); - } - else - { - typedef typename symtab_store::string_context str_ctxt_t; - str_ctxt_t str_ctx = symtab_store_.get_string_context(symbol); - - if ((0 == str_ctx.str_var) || !symtab_store_.is_conststr_stringvar(symbol)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR121 - Unknown string symbol", - exprtk_error_location)); - - return error_node(); - } - - assert(str_ctx.str_var != 0); - assert(str_ctx.symbol_table != 0); - - result = str_ctx.str_var; - - if (symtab_store_.is_constant_string(symbol)) - { - const_str_node = static_cast(result); - result = expression_generator_(const_str_node->str()); - } - else if (symbol_table_t::e_immutable == str_ctx.symbol_table->mutability()) - { - lodge_immutable_symbol( - current_token(), - make_memory_range(str_ctx.str_var->base(), str_ctx.str_var->size())); - } - - lodge_symbol(symbol, e_st_string); - } - - if (peek_token_is(token_t::e_lsqrbracket)) - { - next_token(); - - if (peek_token_is(token_t::e_rsqrbracket)) - { - next_token(); - next_token(); - - if (const_str_node) - { - free_node(node_allocator_, result); - - return expression_generator_(T(const_str_node->size())); - } - else - return node_allocator_.allocate > - (static_cast*>(result)->ref()); - } - - range_t rp; - - if (!parse_range(rp)) - { - free_node(node_allocator_, result); - - return error_node(); - } - else if (const_str_node) - { - free_node(node_allocator_, result); - result = expression_generator_(const_str_node->ref(),rp); - } - else - result = expression_generator_(static_cast*> - (result)->ref(), rp); - - if (result) - rp.clear(); - } - else - next_token(); - - return result; - } - #else - inline expression_node_ptr parse_string() - { - return error_node(); - } - #endif - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_const_string() - { - const std::string const_str = current_token().value; - expression_node_ptr result = expression_generator_(const_str); - - if (peek_token_is(token_t::e_lsqrbracket)) - { - next_token(); - - if (peek_token_is(token_t::e_rsqrbracket)) - { - next_token(); - next_token(); - - free_node(node_allocator_, result); - - return expression_generator_(T(const_str.size())); - } - - range_t rp; - - if (!parse_range(rp)) - { - free_node(node_allocator_, result); - rp.free(); - - return error_node(); - } - - free_node(node_allocator_, result); - - if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits::max())) - { - rp.n1_c.second = const_str.size() - 1; - rp.cache.second = rp.n1_c.second; - } - - if ( - (rp.n0_c.first && (rp.n0_c.second >= const_str.size())) || - (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR122 - Overflow in range for string: '" + const_str + "'[" + - (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + - (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", - exprtk_error_location)); - - rp.free(); - - return error_node(); - } - - result = expression_generator_(const_str,rp); - - if (result) - rp.clear(); - } - else - next_token(); - - return result; - } - #else - inline expression_node_ptr parse_const_string() - { - return error_node(); - } - #endif - - inline expression_node_ptr parse_vector_index(const std::string& vector_name = "") - { - expression_node_ptr index_expr = error_node(); - - if (0 == (index_expr = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR123 - Failed to parse index for vector: '" + vector_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (!token_is(token_t::e_rsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR124 - Expected ']' for index of vector: '" + vector_name + "'", - exprtk_error_location)); - - free_node(node_allocator_, index_expr); - - return error_node(); - } - - return index_expr; - } - - inline expression_node_ptr parse_vector() - { - const std::string vector_name = current_token().value; - - vector_holder_ptr vec = vector_holder_ptr(0); - - const scope_element& se = sem_.get_active_element(vector_name); - - if ( - !details::imatch(se.name, vector_name) || - (se.depth > state_.scope_depth) || - (scope_element::e_vector != se.type) - ) - { - typedef typename symtab_store::vector_context vec_ctxt_t; - vec_ctxt_t vec_ctx = symtab_store_.get_vector_context(vector_name); - - if (0 == vec_ctx.vector_holder) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR125 - Symbol '" + vector_name + " not a vector", - exprtk_error_location)); - - return error_node(); - } - - assert(0 != vec_ctx.vector_holder); - assert(0 != vec_ctx.symbol_table ); - - vec = vec_ctx.vector_holder; - - if (symbol_table_t::e_immutable == vec_ctx.symbol_table->mutability()) - { - lodge_immutable_symbol( - current_token(), - make_memory_range(vec->data(), vec->size())); - } - } - else - { - vec = se.vec_node; - } - - assert(0 != vec); - - next_token(); - - if (!token_is(token_t::e_lsqrbracket)) - { - return node_allocator_.allocate(vec); - } - else if (token_is(token_t::e_rsqrbracket)) - { - return (vec->rebaseable()) ? - node_allocator_.allocate(vec) : - expression_generator_(T(vec->size())); - } - - expression_node_ptr index_expr = parse_vector_index(vector_name); - - if (index_expr) - { - expression_node_ptr vec_node = node_allocator_.allocate(vec); - - return synthesize_vector_element(vector_name, vec, vec_node, index_expr); - } - - return error_node(); - } - - inline expression_node_ptr synthesize_vector_element(const std::string& vector_name, - vector_holder_ptr vec, - expression_node_ptr vec_node, - expression_node_ptr index_expr) - { - // Perform compile-time range check - if (details::is_constant_node(index_expr)) - { - const std::size_t index = static_cast(details::numeric::to_int32(index_expr->value())); - const std::size_t vec_size = vec->size(); - - if (index >= vec_size) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR126 - Index of " + details::to_str(index) + " out of range for " - "vector '" + vector_name + "' of size " + details::to_str(vec_size), - exprtk_error_location)); - - free_node(node_allocator_, vec_node ); - free_node(node_allocator_, index_expr); - - return error_node(); - } - } - - return expression_generator_.vector_element(vector_name, vec, vec_node, index_expr); - } - - inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) - { - std::vector arg_list; - - expression_node_ptr result = error_node(); - - scoped_vec_delete sdd((*this),arg_list); - - next_token(); - - if (token_is(token_t::e_lbracket)) - { - if (token_is(token_t::e_rbracket)) - { - if (!vararg_function->allow_zero_parameters()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR127 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed", - exprtk_error_location)); - - return error_node(); - } - } - else - { - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - else - arg_list.push_back(arg); - - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR128 - Expected ',' for call to vararg function: " - + vararg_function_name, - exprtk_error_location)); - - return error_node(); - } - } - } - } - else if (!vararg_function->allow_zero_parameters()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR129 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed", - exprtk_error_location)); - - return error_node(); - } - - if (arg_list.size() < vararg_function->min_num_args()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR130 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require at least " - + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters", - exprtk_error_location)); - - return error_node(); - } - else if (arg_list.size() > vararg_function->max_num_args()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR131 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require no more than " - + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters", - exprtk_error_location)); - - return error_node(); - } - - result = expression_generator_.vararg_function_call(vararg_function,arg_list); - - sdd.delete_ptr = (0 == result); - - return result; - } - - class type_checker - { - public: - - enum return_type_t - { - e_overload = ' ', - e_numeric = 'T', - e_string = 'S' - }; - - struct function_prototype_t - { - return_type_t return_type; - std::string param_seq; - }; - - typedef parser parser_t; - typedef std::vector function_definition_list_t; - - type_checker(parser_t& p, - const std::string& func_name, - const std::string& func_prototypes, - const return_type_t default_return_type) - : invalid_state_(true) - , parser_(p) - , function_name_(func_name) - , default_return_type_(default_return_type) - { - parse_function_prototypes(func_prototypes); - } - - bool verify(const std::string& param_seq, std::size_t& pseq_index) - { - if (function_definition_list_.empty()) - return true; - - std::vector > error_list; - - for (std::size_t i = 0; i < function_definition_list_.size(); ++i) - { - details::char_t diff_value = 0; - std::size_t diff_index = 0; - - const bool result = details::sequence_match(function_definition_list_[i].param_seq, - param_seq, - diff_index, diff_value); - - if (result) - { - pseq_index = i; - return true; - } - else - error_list.push_back(std::make_pair(diff_index, diff_value)); - } - - if (1 == error_list.size()) - { - parser_.set_error(make_error( - parser_error::e_syntax, - parser_.current_token(), - "ERR132 - Failed parameter type check for function '" + function_name_ + "', " - "Expected '" + function_definition_list_[0].param_seq + - "' call set: '" + param_seq + "'", - exprtk_error_location)); - } - else - { - // find first with largest diff_index; - std::size_t max_diff_index = 0; - - for (std::size_t i = 1; i < error_list.size(); ++i) - { - if (error_list[i].first > error_list[max_diff_index].first) - { - max_diff_index = i; - } - } - - parser_.set_error(make_error( - parser_error::e_syntax, - parser_.current_token(), - "ERR133 - Failed parameter type check for function '" + function_name_ + "', " - "Best match: '" + function_definition_list_[max_diff_index].param_seq + - "' call set: '" + param_seq + "'", - exprtk_error_location)); - } - - return false; - } - - std::size_t paramseq_count() const - { - return function_definition_list_.size(); - } - - std::string paramseq(const std::size_t& index) const - { - return function_definition_list_[index].param_seq; - } - - return_type_t return_type(const std::size_t& index) const - { - return function_definition_list_[index].return_type; - } - - bool invalid() const - { - return !invalid_state_; - } - - bool allow_zero_parameters() const - { - - for (std::size_t i = 0; i < function_definition_list_.size(); ++i) - { - if (std::string::npos != function_definition_list_[i].param_seq.find("Z")) - { - return true; - } - } - - return false; - } - - private: - - std::vector split_param_seq(const std::string& param_seq, const details::char_t delimiter = '|') const - { - std::string::const_iterator current_begin = param_seq.begin(); - std::string::const_iterator iter = param_seq.begin(); - - std::vector result; - - while (iter != param_seq.end()) - { - if (*iter == delimiter) - { - result.push_back(std::string(current_begin, iter)); - current_begin = ++iter; - } - else - ++iter; - } - - if (current_begin != iter) - { - result.push_back(std::string(current_begin, iter)); - } - - return result; - } - - inline bool is_valid_token(std::string param_seq, - function_prototype_t& funcproto) const - { - // Determine return type - funcproto.return_type = default_return_type_; - - if (param_seq.size() > 2) - { - if (':' == param_seq[1]) - { - // Note: Only overloaded igeneric functions can have return - // type definitions. - if (type_checker::e_overload != default_return_type_) - return false; - - switch (param_seq[0]) - { - case 'T' : funcproto.return_type = type_checker::e_numeric; - break; - - case 'S' : funcproto.return_type = type_checker::e_string; - break; - - default : return false; - } - - param_seq.erase(0,2); - } - } - - if ( - (std::string::npos != param_seq.find("?*")) || - (std::string::npos != param_seq.find("**")) - ) - { - return false; - } - else if ( - (std::string::npos == param_seq.find_first_not_of("STV*?|")) || - ("Z" == param_seq) - ) - { - funcproto.param_seq = param_seq; - return true; - } - - return false; - } - - void parse_function_prototypes(const std::string& func_prototypes) - { - if (func_prototypes.empty()) - return; - - std::vector param_seq_list = split_param_seq(func_prototypes); - - typedef std::map param_seq_map_t; - param_seq_map_t param_seq_map; - - for (std::size_t i = 0; i < param_seq_list.size(); ++i) - { - function_prototype_t func_proto; - - if (!is_valid_token(param_seq_list[i], func_proto)) - { - invalid_state_ = false; - - parser_.set_error(make_error( - parser_error::e_syntax, - parser_.current_token(), - "ERR134 - Invalid parameter sequence of '" + param_seq_list[i] + - "' for function: " + function_name_, - exprtk_error_location)); - return; - } - - param_seq_map_t::const_iterator seq_itr = param_seq_map.find(param_seq_list[i]); - - if (param_seq_map.end() != seq_itr) - { - invalid_state_ = false; - - parser_.set_error(make_error( - parser_error::e_syntax, - parser_.current_token(), - "ERR135 - Function '" + function_name_ + "' has a parameter sequence conflict between " + - "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + - "pseq_idx[" + details::to_str(i) + "] " + - "param seq: " + param_seq_list[i], - exprtk_error_location)); - return; - } - - function_definition_list_.push_back(func_proto); - } - } - - type_checker(const type_checker&) exprtk_delete; - type_checker& operator=(const type_checker&) exprtk_delete; - - bool invalid_state_; - parser_t& parser_; - std::string function_name_; - const return_type_t default_return_type_; - function_definition_list_t function_definition_list_; - }; - - inline expression_node_ptr parse_generic_function_call(igeneric_function* function, const std::string& function_name) - { - std::vector arg_list; - - scoped_vec_delete sdd((*this),arg_list); - - next_token(); - - std::string param_type_list; - - type_checker tc( - (*this), - function_name, - function->parameter_sequence, - type_checker::e_string); - - if (tc.invalid()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR136 - Type checker instantiation failure for generic function: " + function_name, - exprtk_error_location)); - - return error_node(); - } - - if (token_is(token_t::e_lbracket)) - { - if (token_is(token_t::e_rbracket)) - { - if ( - !function->allow_zero_parameters() && - !tc .allow_zero_parameters() - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR137 - Zero parameter call to generic function: " - + function_name + " not allowed", - exprtk_error_location)); - - return error_node(); - } - } - else - { - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - - if (is_ivector_node(arg)) - param_type_list += 'V'; - else if (is_generally_string_node(arg)) - param_type_list += 'S'; - else // Everything else is assumed to be a scalar returning expression - param_type_list += 'T'; - - arg_list.push_back(arg); - - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR138 - Expected ',' for call to generic function: " + function_name, - exprtk_error_location)); - - return error_node(); - } - } - } - } - else if ( - !function->parameter_sequence.empty() && - function->allow_zero_parameters () && - !tc .allow_zero_parameters () - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR139 - Zero parameter call to generic function: " - + function_name + " not allowed", - exprtk_error_location)); - - return error_node(); - } - - std::size_t param_seq_index = 0; - - if ( - state_.type_check_enabled && - !tc.verify(param_type_list, param_seq_index) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR140 - Invalid input parameter sequence for call to generic function: " + function_name, - exprtk_error_location)); - - return error_node(); - } - - expression_node_ptr result = error_node(); - - result = (tc.paramseq_count() <= 1) ? - expression_generator_ - .generic_function_call(function, arg_list) : - expression_generator_ - .generic_function_call(function, arg_list, param_seq_index); - - sdd.delete_ptr = (0 == result); - - return result; - } - - inline bool parse_igeneric_function_params(std::string& param_type_list, - std::vector& arg_list, - const std::string& function_name, - igeneric_function* function, - const type_checker& tc) - { - if (token_is(token_t::e_lbracket)) - { - if (token_is(token_t::e_rbracket)) - { - if ( - !function->allow_zero_parameters() && - !tc .allow_zero_parameters() - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR141 - Zero parameter call to generic function: " - + function_name + " not allowed", - exprtk_error_location)); - - return false; - } - } - else - { - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return false; - - if (is_ivector_node(arg)) - param_type_list += 'V'; - else if (is_generally_string_node(arg)) - param_type_list += 'S'; - else // Everything else is a scalar returning expression - param_type_list += 'T'; - - arg_list.push_back(arg); - - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR142 - Expected ',' for call to string function: " + function_name, - exprtk_error_location)); - - return false; - } - } - } - - return true; - } - else - return false; - } - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_string_function_call(igeneric_function* function, const std::string& function_name) - { - // Move pass the function name - next_token(); - - std::string param_type_list; - - type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); - - if ( - (!function->parameter_sequence.empty()) && - (0 == tc.paramseq_count()) - ) - { - return error_node(); - } - - std::vector arg_list; - scoped_vec_delete sdd((*this),arg_list); - - if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) - { - return error_node(); - } - - std::size_t param_seq_index = 0; - - if (!tc.verify(param_type_list, param_seq_index)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR143 - Invalid input parameter sequence for call to string function: " + function_name, - exprtk_error_location)); - - return error_node(); - } - - expression_node_ptr result = error_node(); - - result = (tc.paramseq_count() <= 1) ? - expression_generator_ - .string_function_call(function, arg_list) : - expression_generator_ - .string_function_call(function, arg_list, param_seq_index); - - sdd.delete_ptr = (0 == result); - - return result; - } - - inline expression_node_ptr parse_overload_function_call(igeneric_function* function, const std::string& function_name) - { - // Move pass the function name - next_token(); - - std::string param_type_list; - - type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_overload); - - if ( - (!function->parameter_sequence.empty()) && - (0 == tc.paramseq_count()) - ) - { - return error_node(); - } - - std::vector arg_list; - scoped_vec_delete sdd((*this),arg_list); - - if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) - { - return error_node(); - } - - std::size_t param_seq_index = 0; - - if (!tc.verify(param_type_list, param_seq_index)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR144 - Invalid input parameter sequence for call to overloaded function: " + function_name, - exprtk_error_location)); - - return error_node(); - } - - expression_node_ptr result = error_node(); - - if (type_checker::e_numeric == tc.return_type(param_seq_index)) - { - if (tc.paramseq_count() <= 1) - result = expression_generator_ - .generic_function_call(function, arg_list); - else - result = expression_generator_ - .generic_function_call(function, arg_list, param_seq_index); - } - else if (type_checker::e_string == tc.return_type(param_seq_index)) - { - if (tc.paramseq_count() <= 1) - result = expression_generator_ - .string_function_call(function, arg_list); - else - result = expression_generator_ - .string_function_call(function, arg_list, param_seq_index); - } - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR145 - Invalid return type for call to overloaded function: " + function_name, - exprtk_error_location)); - } - - sdd.delete_ptr = (0 == result); - return result; - } - #endif - - template - struct parse_special_function_impl - { - static inline expression_node_ptr process(parser& p, const details::operator_type opt_type, const std::string& sf_name) - { - expression_node_ptr branch[NumberOfParameters]; - expression_node_ptr result = error_node(); - - std::fill_n(branch, NumberOfParameters, reinterpret_cast(0)); - - scoped_delete sd(p,branch); - - p.next_token(); - - if (!p.token_is(token_t::e_lbracket)) - { - p.set_error(make_error( - parser_error::e_syntax, - p.current_token(), - "ERR146 - Expected '(' for special function '" + sf_name + "'", - exprtk_error_location)); - - return error_node(); - } - - for (std::size_t i = 0; i < NumberOfParameters; ++i) - { - branch[i] = p.parse_expression(); - - if (0 == branch[i]) - { - return p.error_node(); - } - else if (i < (NumberOfParameters - 1)) - { - if (!p.token_is(token_t::e_comma)) - { - p.set_error(make_error( - parser_error::e_syntax, - p.current_token(), - "ERR147 - Expected ',' before next parameter of special function '" + sf_name + "'", - exprtk_error_location)); - - return p.error_node(); - } - } - } - - if (!p.token_is(token_t::e_rbracket)) - { - p.set_error(make_error( - parser_error::e_syntax, - p.current_token(), - "ERR148 - Invalid number of parameters for special function '" + sf_name + "'", - exprtk_error_location)); - - return p.error_node(); - } - else - result = p.expression_generator_.special_function(opt_type,branch); - - sd.delete_ptr = (0 == result); - - return result; - } - }; - - inline expression_node_ptr parse_special_function() - { - const std::string sf_name = current_token().value; - - // Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) - if ( - !details::is_digit(sf_name[2]) || - !details::is_digit(sf_name[3]) - ) - { - set_error(make_error( - parser_error::e_token, - current_token(), - "ERR149 - Invalid special function[1]: " + sf_name, - exprtk_error_location)); - - return error_node(); - } - - const int id = (sf_name[2] - '0') * 10 + - (sf_name[3] - '0'); - - if (id >= details::e_sffinal) - { - set_error(make_error( - parser_error::e_token, - current_token(), - "ERR150 - Invalid special function[2]: " + sf_name, - exprtk_error_location)); - - return error_node(); - } - - const int sf_3_to_4 = details::e_sf48; - const details::operator_type opt_type = details::operator_type(id + 1000); - const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3U : 4U; - - switch (NumberOfParameters) - { - case 3 : return parse_special_function_impl::process((*this), opt_type, sf_name); - case 4 : return parse_special_function_impl::process((*this), opt_type, sf_name); - default : return error_node(); - } - } - - inline expression_node_ptr parse_null_statement() - { - next_token(); - return node_allocator_.allocate >(); - } - - #ifndef exprtk_disable_break_continue - inline expression_node_ptr parse_break_statement() - { - if (state_.parsing_break_stmt) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR151 - Invoking 'break' within a break call is not allowed", - exprtk_error_location)); - - return error_node(); - } - else if (0 == state_.parsing_loop_stmt_count) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR152 - Invalid use of 'break', allowed only in the scope of a loop", - exprtk_error_location)); - - return error_node(); - } - - scoped_bool_negator sbn(state_.parsing_break_stmt); - - if (!brkcnt_list_.empty()) - { - next_token(); - - brkcnt_list_.front() = true; - - expression_node_ptr return_expr = error_node(); - - if (token_is(token_t::e_lsqrbracket)) - { - if (0 == (return_expr = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR153 - Failed to parse return expression for 'break' statement", - exprtk_error_location)); - - return error_node(); - } - else if (!token_is(token_t::e_rsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR154 - Expected ']' at the completion of break's return expression", - exprtk_error_location)); - - free_node(node_allocator_, return_expr); - - return error_node(); - } - } - - state_.activate_side_effect("parse_break_statement()"); - - return node_allocator_.allocate >(return_expr); - } - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR155 - Invalid use of 'break', allowed only in the scope of a loop", - exprtk_error_location)); - } - - return error_node(); - } - - inline expression_node_ptr parse_continue_statement() - { - if (0 == state_.parsing_loop_stmt_count) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR156 - Invalid use of 'continue', allowed only in the scope of a loop", - exprtk_error_location)); - - return error_node(); - } - else - { - next_token(); - - brkcnt_list_.front() = true; - state_.activate_side_effect("parse_continue_statement()"); - - return node_allocator_.allocate >(); - } - } - #endif - - inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) - { - expression_node_ptr size_expression_node = error_node(); - - if (!token_is(token_t::e_lsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR157 - Expected '[' as part of vector size definition", - exprtk_error_location)); - - return error_node(); - } - else if (0 == (size_expression_node = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR158 - Failed to determine size of vector '" + vec_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (!is_constant_node(size_expression_node)) - { - const bool is_rebaseble_vector = - (size_expression_node->type() == details::expression_node::e_vecsize) && - static_cast*>(size_expression_node)->vec_holder()->rebaseable(); - - free_node(node_allocator_, size_expression_node); - - const std::string error_msg = (is_rebaseble_vector) ? - std::string("Rebasable/Resizable vector cannot be used to define the size of vector") : - std::string("Expected a constant literal number as size of vector"); - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR159 - " + error_msg + " '" + vec_name + "'", - exprtk_error_location)); - - return error_node(); - } - - const T vector_size = size_expression_node->value(); - - free_node(node_allocator_, size_expression_node); - - const std::size_t max_vector_size = settings_.max_local_vector_size(); - - if ( - (vector_size <= T(0)) || - std::not_equal_to() - (T(0),vector_size - details::numeric::trunc(vector_size)) || - (static_cast(vector_size) > max_vector_size) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR160 - Invalid vector size. Must be an integer in the " - "range [0," + details::to_str(static_cast(max_vector_size)) + "], size: " + - details::to_str(details::numeric::to_int32(vector_size)), - exprtk_error_location)); - - return error_node(); - } - - typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); - - const std::size_t vec_size = static_cast(details::numeric::to_int32(vector_size)); - - scope_element& se = sem_.get_element(vec_name); - - if (se.name == vec_name) - { - if (se.active) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR161 - Illegal redefinition of local vector: '" + vec_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if ( - (se.size == vec_size) && - (scope_element::e_vector == se.type) - ) - { - vec_holder = se.vec_node; - se.active = true; - se.depth = state_.scope_depth; - se.ref_count++; - } - } - - if (0 == vec_holder) - { - scope_element nse; - nse.name = vec_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_vector; - nse.depth = state_.scope_depth; - nse.size = vec_size; - nse.data = new T[vec_size]; - nse.vec_node = new typename scope_element::vector_holder_t(reinterpret_cast(nse.data),nse.size); - - details::set_zero_value(reinterpret_cast(nse.data),vec_size); - - if (!sem_.add_element(nse)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR162 - Failed to add new local vector '" + vec_name + "' to SEM", - exprtk_error_location)); - - sem_.free_element(nse); - - return error_node(); - } - - vec_holder = nse.vec_node; - - exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", - nse.name.c_str(), - static_cast(nse.size))); - } - - state_.activate_side_effect("parse_define_vector_statement()"); - - lodge_symbol(vec_name, e_st_local_vector); - - std::vector vec_initilizer_list; - - scoped_vec_delete svd((*this),vec_initilizer_list); - - bool single_value_initialiser = false; - bool range_value_initialiser = false; - bool vec_to_vec_initialiser = false; - bool null_initialisation = false; - - if (!token_is(token_t::e_rsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR163 - Expected ']' as part of vector size definition", - exprtk_error_location)); - - return error_node(); - } - else if (!token_is(token_t::e_eof, prsrhlpr_t::e_hold)) - { - if (!token_is(token_t::e_assign)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR164 - Expected ':=' as part of vector definition", - exprtk_error_location)); - - return error_node(); - } - else if (token_is(token_t::e_lsqrbracket)) - { - expression_node_ptr initialiser_component = parse_expression(); - - if (0 == initialiser_component) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR165 - Failed to parse first component of vector initialiser for vector: " + vec_name, - exprtk_error_location)); - - return error_node(); - } - - vec_initilizer_list.push_back(initialiser_component); - - if (token_is(token_t::e_colon)) - { - initialiser_component = parse_expression(); - - if (0 == initialiser_component) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR166 - Failed to parse second component of vector initialiser for vector: " + vec_name, - exprtk_error_location)); - - return error_node(); - } - - vec_initilizer_list.push_back(initialiser_component); - } - - if (!token_is(token_t::e_rsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR167 - Expected ']' to close single value vector initialiser", - exprtk_error_location)); - - return error_node(); - } - - switch (vec_initilizer_list.size()) - { - case 1 : single_value_initialiser = true; break; - case 2 : range_value_initialiser = true; break; - } - } - else if (!token_is(token_t::e_lcrlbracket)) - { - expression_node_ptr initialiser = error_node(); - - // Is this a vector to vector assignment and initialisation? - if (token_t::e_symbol == current_token().type) - { - // Is it a locally defined vector? - const scope_element& lcl_se = sem_.get_active_element(current_token().value); - - if (scope_element::e_vector == lcl_se.type) - { - if (0 != (initialiser = parse_expression())) - vec_initilizer_list.push_back(initialiser); - else - return error_node(); - } - // Are we dealing with a user defined vector? - else if (symtab_store_.is_vector(current_token().value)) - { - lodge_symbol(current_token().value, e_st_vector); - - if (0 != (initialiser = parse_expression())) - vec_initilizer_list.push_back(initialiser); - else - return error_node(); - } - // Are we dealing with a null initialisation vector definition? - else if (token_is(token_t::e_symbol,"null")) - null_initialisation = true; - } - - if (!null_initialisation) - { - if (0 == initialiser) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR168 - Expected '{' as part of vector initialiser list", - exprtk_error_location)); - - return error_node(); - } - else - vec_to_vec_initialiser = true; - } - } - else if (!token_is(token_t::e_rcrlbracket)) - { - for ( ; ; ) - { - expression_node_ptr initialiser = parse_expression(); - - if (0 == initialiser) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR169 - Expected '{' as part of vector initialiser list", - exprtk_error_location)); - - return error_node(); - } - else - vec_initilizer_list.push_back(initialiser); - - if (token_is(token_t::e_rcrlbracket)) - break; - - const bool is_next_close = peek_token_is(token_t::e_rcrlbracket); - - if (!token_is(token_t::e_comma) && is_next_close) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR170 - Expected ',' between vector initialisers", - exprtk_error_location)); - - return error_node(); - } - - if (token_is(token_t::e_rcrlbracket)) - break; - } - } - - if ( - !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && - !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && - !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) - ) - { - if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR171 - Expected ';' at end of vector definition", - exprtk_error_location)); - - return error_node(); - } - } - - if ( - !single_value_initialiser && - !range_value_initialiser && - (T(vec_initilizer_list.size()) > vector_size) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR172 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", - exprtk_error_location)); - - return error_node(); - } - } - - expression_node_ptr result = error_node(); - - if ( - (vec_initilizer_list.size() == 1) && - single_value_initialiser - ) - { - if (details::is_constant_node(vec_initilizer_list[0])) - { - // vector_init_zero_value_node var v[10] := [0] - if (T(0) == vec_initilizer_list[0]->value()) - { - result = node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list); - } - else - { - // vector_init_single_constvalue_node var v[10] := [123] - result = node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list); - } - } - else - { - // vector_init_single_value_node var v[10] := [123 + (x / y)] - result = node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list); - } - } - else if ( - (vec_initilizer_list.size() == 2) && - range_value_initialiser - ) - { - bool base_const = details::is_constant_node(vec_initilizer_list[0]); - bool inc_const = details::is_constant_node(vec_initilizer_list[1]); - - if (base_const && inc_const) - { - // vector_init_single_value_node var v[10] := [1 : 3.5] - result = node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list); - } - else if (base_const && !inc_const) - { - // vector_init_single_value_node var v[10] := [1 : x + y] - result = node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list); - } - else if (!base_const && inc_const) - { - // vector_init_single_value_node var v[10] := [x + y : 3] - result = node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list); - } - else if (!base_const && !inc_const) - { - // vector_init_single_value_node var v[10] := [x + y : z / w] - result = node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list); - } - } - else if (null_initialisation) - result = expression_generator_(T(0.0)); - else if (vec_to_vec_initialiser) - { - expression_node_ptr vec_node = node_allocator_.allocate(vec_holder); - - result = expression_generator_( - details::e_assign, - vec_node, - vec_initilizer_list[0]); - } - else - { - result = node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list, - single_value_initialiser); - } - - svd.delete_ptr = false; - - if (result && result->valid()) - { - return result; - } - - details::free_node(node_allocator_, result); - - set_error(make_error( - parser_error::e_synthesis, - current_token(), - "ERR173 - Failed to generate initialisation node for vector: " + vec_name, - exprtk_error_location)); - - return error_node(); - } - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_define_string_statement(const std::string& str_name, expression_node_ptr initialisation_expression) - { - stringvar_node_t* str_node = reinterpret_cast(0); - - scope_element& se = sem_.get_element(str_name); - - if (se.name == str_name) - { - if (se.active) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR174 - Illegal redefinition of local variable: '" + str_name + "'", - exprtk_error_location)); - - free_node(node_allocator_, initialisation_expression); - - return error_node(); - } - else if (scope_element::e_string == se.type) - { - str_node = se.str_node; - se.active = true; - se.depth = state_.scope_depth; - se.ref_count++; - } - } - - if (0 == str_node) - { - scope_element nse; - nse.name = str_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_string; - nse.depth = state_.scope_depth; - nse.data = new std::string; - nse.str_node = new stringvar_node_t(*reinterpret_cast(nse.data)); - - if (!sem_.add_element(nse)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR175 - Failed to add new local string variable '" + str_name + "' to SEM", - exprtk_error_location)); - - free_node(node_allocator_, initialisation_expression); - - sem_.free_element(nse); - - return error_node(); - } - - str_node = nse.str_node; - - exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n", nse.name.c_str())); - } - - lodge_symbol(str_name, e_st_local_string); - - state_.activate_side_effect("parse_define_string_statement()"); - - expression_node_ptr branch[2] = {0}; - - branch[0] = str_node; - branch[1] = initialisation_expression; - - return expression_generator_(details::e_assign,branch); - } - #else - inline expression_node_ptr parse_define_string_statement(const std::string&, expression_node_ptr) - { - return error_node(); - } - #endif - - inline bool local_variable_is_shadowed(const std::string& symbol) - { - const scope_element& se = sem_.get_element(symbol); - return (se.name == symbol) && se.active; - } - - inline expression_node_ptr parse_define_var_statement() - { - if (settings_.vardef_disabled()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR176 - Illegal variable definition", - exprtk_error_location)); - - return error_node(); - } - else if (!details::imatch(current_token().value,"var")) - { - return error_node(); - } - else - next_token(); - - const std::string var_name = current_token().value; - - expression_node_ptr initialisation_expression = error_node(); - - if (!token_is(token_t::e_symbol)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR177 - Expected a symbol for variable definition", - exprtk_error_location)); - - return error_node(); - } - else if (details::is_reserved_symbol(var_name)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR178 - Illegal redefinition of reserved keyword: '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (symtab_store_.symbol_exists(var_name)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR179 - Illegal redefinition of variable '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (local_variable_is_shadowed(var_name)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR180 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) - { - return parse_define_vector_statement(var_name); - } - else if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) - { - return parse_uninitialised_var_statement(var_name); - } - else if (token_is(token_t::e_assign)) - { - if (0 == (initialisation_expression = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR181 - Failed to parse initialisation expression for variable '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - } - - if ( - !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && - !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && - !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) - ) - { - if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR182 - Expected ';' after variable '" + var_name + "' definition", - exprtk_error_location)); - - free_node(node_allocator_, initialisation_expression); - - return error_node(); - } - } - - if ( - (0 != initialisation_expression) && - details::is_generally_string_node(initialisation_expression) - ) - { - return parse_define_string_statement(var_name,initialisation_expression); - } - - expression_node_ptr var_node = reinterpret_cast(0); - - scope_element& se = sem_.get_element(var_name); - - if (se.name == var_name) - { - if (se.active) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR183 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); - - free_node(node_allocator_, initialisation_expression); - - return error_node(); - } - else if (scope_element::e_variable == se.type) - { - var_node = se.var_node; - se.active = true; - se.depth = state_.scope_depth; - se.ref_count++; - } - } - - if (0 == var_node) - { - scope_element nse; - nse.name = var_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_variable; - nse.depth = state_.scope_depth; - nse.data = new T(T(0)); - nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); - - if (!sem_.add_element(nse)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR184 - Failed to add new local variable '" + var_name + "' to SEM", - exprtk_error_location)); - - free_node(node_allocator_, initialisation_expression); - - sem_.free_element(nse); - - return error_node(); - } - - var_node = nse.var_node; - - exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n", nse.name.c_str())); - } - - state_.activate_side_effect("parse_define_var_statement()"); - - lodge_symbol(var_name, e_st_local_variable); - - expression_node_ptr branch[2] = {0}; - - branch[0] = var_node; - branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); - - return expression_generator_(details::e_assign,branch); - } - - inline expression_node_ptr parse_define_constvar_statement() - { - if (settings_.vardef_disabled()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR185 - Illegal const variable definition", - exprtk_error_location)); - - return error_node(); - } - else if (!token_is("const")) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR186 - Expected 'const' keyword for const-variable definition", - exprtk_error_location)); - - return error_node(); - } - else if (!token_is("var")) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR187 - Expected 'var' keyword for const-variable definition", - exprtk_error_location)); - - return error_node(); - } - - const std::string var_name = current_token().value; - - expression_node_ptr initialisation_expression = error_node(); - - if (!token_is(token_t::e_symbol)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR188 - Expected a symbol for const-variable definition", - exprtk_error_location)); - - return error_node(); - } - else if (details::is_reserved_symbol(var_name)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR189 - Illegal redefinition of reserved keyword: '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (symtab_store_.symbol_exists(var_name)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR190 - Illegal redefinition of variable '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (local_variable_is_shadowed(var_name)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR191 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (token_is(token_t::e_assign)) - { - if (0 == (initialisation_expression = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR192 - Failed to parse initialisation expression for const-variable: '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (!details::is_literal_node(initialisation_expression)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR193 - initialisation expression for const-variable: '" + var_name + "' must be a constant/literal", - exprtk_error_location)); - - free_node(node_allocator_, initialisation_expression); - - return error_node(); - } - } - - const T init_value = initialisation_expression->value(); - - free_node(node_allocator_, initialisation_expression); - - expression_node_ptr var_node = reinterpret_cast(0); - - scope_element& se = sem_.get_element(var_name); - - if (se.name == var_name) - { - if (se.active) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR194 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (scope_element::e_literal == se.type) - { - var_node = se.var_node; - se.active = true; - se.depth = state_.scope_depth; - se.ref_count++; - } - } - - if (0 == var_node) - { - scope_element nse; - nse.name = var_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_literal; - nse.depth = state_.scope_depth; - nse.data = 0; - nse.var_node = node_allocator_.allocate(init_value); - - if (!sem_.add_element(nse)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR195 - Failed to add new local const-variable '" + var_name + "' to SEM", - exprtk_error_location)); - - sem_.free_element(nse); - - return error_node(); - } - - var_node = nse.var_node; - - exprtk_debug(("parse_define_constvar_statement() - INFO - Added new local const-variable: %s\n", nse.name.c_str())); - } - - state_.activate_side_effect("parse_define_constvar_statement()"); - - lodge_symbol(var_name, e_st_local_variable); - - return expression_generator_(var_node->value()); - } - - inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) - { - if ( - !token_is(token_t::e_lcrlbracket) || - !token_is(token_t::e_rcrlbracket) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR196 - Expected a '{}' for uninitialised var definition", - exprtk_error_location)); - - return error_node(); - } - else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR197 - Expected ';' after uninitialised variable definition", - exprtk_error_location)); - - return error_node(); - } - - expression_node_ptr var_node = reinterpret_cast(0); - - scope_element& se = sem_.get_element(var_name); - - if (se.name == var_name) - { - if (se.active) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR198 - Illegal redefinition of local variable: '" + var_name + "'", - exprtk_error_location)); - - return error_node(); - } - else if (scope_element::e_variable == se.type) - { - var_node = se.var_node; - se.active = true; - se.ref_count++; - } - } - - if (0 == var_node) - { - scope_element nse; - nse.name = var_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_variable; - nse.depth = state_.scope_depth; - nse.ip_index = sem_.next_ip_index(); - nse.data = new T(T(0)); - nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); - - if (!sem_.add_element(nse)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR199 - Failed to add new local variable '" + var_name + "' to SEM", - exprtk_error_location)); - - sem_.free_element(nse); - - return error_node(); - } - - exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n", - nse.name.c_str())); - } - - lodge_symbol(var_name, e_st_local_variable); - - state_.activate_side_effect("parse_uninitialised_var_statement()"); - - return expression_generator_(T(0)); - } - - inline expression_node_ptr parse_swap_statement() - { - if (!details::imatch(current_token().value,"swap")) - { - return error_node(); - } - else - next_token(); - - if (!token_is(token_t::e_lbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR200 - Expected '(' at start of swap statement", - exprtk_error_location)); - - return error_node(); - } - - expression_node_ptr variable0 = error_node(); - expression_node_ptr variable1 = error_node(); - - bool variable0_generated = false; - bool variable1_generated = false; - - const std::string var0_name = current_token().value; - - if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR201 - Expected a symbol for variable or vector element definition", - exprtk_error_location)); - - return error_node(); - } - else if (peek_token_is(token_t::e_lsqrbracket)) - { - if (0 == (variable0 = parse_vector())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR202 - First parameter to swap is an invalid vector element: '" + var0_name + "'", - exprtk_error_location)); - - return error_node(); - } - - variable0_generated = true; - } - else - { - if (symtab_store_.is_variable(var0_name)) - { - variable0 = symtab_store_.get_variable(var0_name); - } - - const scope_element& se = sem_.get_element(var0_name); - - if ( - (se.active) && - (se.name == var0_name) && - (scope_element::e_variable == se.type) - ) - { - variable0 = se.var_node; - } - - lodge_symbol(var0_name, e_st_variable); - - if (0 == variable0) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR203 - First parameter to swap is an invalid variable: '" + var0_name + "'", - exprtk_error_location)); - - return error_node(); - } - else - next_token(); - } - - if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR204 - Expected ',' between parameters to swap", - exprtk_error_location)); - - if (variable0_generated) - { - free_node(node_allocator_, variable0); - } - - return error_node(); - } - - const std::string var1_name = current_token().value; - - if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR205 - Expected a symbol for variable or vector element definition", - exprtk_error_location)); - - if (variable0_generated) - { - free_node(node_allocator_, variable0); - } - - return error_node(); - } - else if (peek_token_is(token_t::e_lsqrbracket)) - { - if (0 == (variable1 = parse_vector())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR206 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", - exprtk_error_location)); - - if (variable0_generated) - { - free_node(node_allocator_, variable0); - } - - return error_node(); - } - - variable1_generated = true; - } - else - { - if (symtab_store_.is_variable(var1_name)) - { - variable1 = symtab_store_.get_variable(var1_name); - } - - const scope_element& se = sem_.get_element(var1_name); - - if ( - (se.active) && - (se.name == var1_name) && - (scope_element::e_variable == se.type) - ) - { - variable1 = se.var_node; - } - - lodge_symbol(var1_name, e_st_variable); - - if (0 == variable1) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR207 - Second parameter to swap is an invalid variable: '" + var1_name + "'", - exprtk_error_location)); - - if (variable0_generated) - { - free_node(node_allocator_, variable0); - } - - return error_node(); - } - else - next_token(); - } - - if (!token_is(token_t::e_rbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR208 - Expected ')' at end of swap statement", - exprtk_error_location)); - - if (variable0_generated) - { - free_node(node_allocator_, variable0); - } - - if (variable1_generated) - { - free_node(node_allocator_, variable1); - } - - return error_node(); - } - - typedef details::variable_node* variable_node_ptr; - - variable_node_ptr v0 = variable_node_ptr(0); - variable_node_ptr v1 = variable_node_ptr(0); - - expression_node_ptr result = error_node(); - - if ( - (0 != (v0 = dynamic_cast(variable0))) && - (0 != (v1 = dynamic_cast(variable1))) - ) - { - result = node_allocator_.allocate >(v0, v1); - - if (variable0_generated) - { - free_node(node_allocator_, variable0); - } - - if (variable1_generated) - { - free_node(node_allocator_, variable1); - } - } - else - result = node_allocator_.allocate > - (variable0, variable1); - - state_.activate_side_effect("parse_swap_statement()"); - - return result; - } - - #ifndef exprtk_disable_return_statement - inline expression_node_ptr parse_return_statement() - { - if (state_.parsing_return_stmt) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR209 - Return call within a return call is not allowed", - exprtk_error_location)); - - return error_node(); - } - - scoped_bool_negator sbn(state_.parsing_return_stmt); - - std::vector arg_list; - - scoped_vec_delete sdd((*this),arg_list); - - if (!details::imatch(current_token().value,"return")) - { - return error_node(); - } - else - next_token(); - - if (!token_is(token_t::e_lsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR210 - Expected '[' at start of return statement", - exprtk_error_location)); - - return error_node(); - } - else if (!token_is(token_t::e_rsqrbracket)) - { - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - - arg_list.push_back(arg); - - if (token_is(token_t::e_rsqrbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR211 - Expected ',' between values during call to return", - exprtk_error_location)); - - return error_node(); - } - } - } - else if (settings_.zero_return_disabled()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR212 - Zero parameter return statement not allowed", - exprtk_error_location)); - - return error_node(); - } - - const lexer::token prev_token = current_token(); - - if (token_is(token_t::e_rsqrbracket)) - { - if (!arg_list.empty()) - { - set_error(make_error( - parser_error::e_syntax, - prev_token, - "ERR213 - Invalid ']' found during return call", - exprtk_error_location)); - - return error_node(); - } - } - - std::string ret_param_type_list; - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (0 == arg_list[i]) - return error_node(); - else if (is_ivector_node(arg_list[i])) - ret_param_type_list += 'V'; - else if (is_generally_string_node(arg_list[i])) - ret_param_type_list += 'S'; - else - ret_param_type_list += 'T'; - } - - dec_.retparam_list_.push_back(ret_param_type_list); - - expression_node_ptr result = expression_generator_.return_call(arg_list); - - sdd.delete_ptr = (0 == result); - - state_.return_stmt_present = true; - - state_.activate_side_effect("parse_return_statement()"); - - return result; - } - #else - inline expression_node_ptr parse_return_statement() - { - return error_node(); - } - #endif - - inline expression_node_ptr parse_assert_statement() - { - assert(details::imatch(current_token().value, "assert")); - - if (state_.parsing_assert_stmt) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR214 - Assert statement within an assert statement is not allowed", - exprtk_error_location)); - - return error_node(); - } - - scoped_bool_negator sbn(state_.parsing_assert_stmt); - - next_token(); - - std::vector assert_arg_list(3, error_node()); - scoped_vec_delete sdd((*this), assert_arg_list); - - expression_node_ptr& assert_condition = assert_arg_list[0]; - expression_node_ptr& assert_message = assert_arg_list[1]; - expression_node_ptr& assert_id = assert_arg_list[2]; - - if (!token_is(token_t::e_lbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR215 - Expected '(' at start of assert statement", - exprtk_error_location)); - - return error_node(); - } - - const token_t start_token = current_token(); - - // Parse the assert condition - if (0 == (assert_condition = parse_expression())) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR216 - Failed to parse condition for assert statement", - exprtk_error_location)); - - return error_node(); - } - - const token_t end_token = current_token(); - - if (!token_is(token_t::e_rbracket)) - { - if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR217 - Expected ',' between condition and message for assert statement", - exprtk_error_location)); - - return error_node(); - } - // Parse the assert message - else if ( - (0 == (assert_message = parse_expression())) || - !details::is_generally_string_node(assert_message) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR218 - " + - (assert_message ? - std::string("Expected string for assert message") : - std::string("Failed to parse message for assert statement")), - exprtk_error_location)); - - return error_node(); - } - else if (!token_is(token_t::e_rbracket)) - { - if (!token_is(token_t::e_comma)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR219 - Expected ',' between message and ID for assert statement", - exprtk_error_location)); - - return error_node(); - } - // Parse assert ID - else if ( - (0 == (assert_id = parse_expression())) || - !details::is_const_string_node(assert_id) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR220 - " + - (assert_id ? - std::string("Expected literal string for assert ID") : - std::string("Failed to parse string for assert ID")), - exprtk_error_location)); - - return error_node(); - } - else if (!token_is(token_t::e_rbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR221 - Expected ')' at start of assert statement", - exprtk_error_location)); - - return error_node(); - } - } - } - - exprtk::assert_check::assert_context context; - context.condition = lexer().substr(start_token.position, end_token.position); - context.offet = start_token.position; - - if (0 == assert_check_) - { - exprtk_debug(("parse_assert_statement() - assert functionality is disabled. assert condition: %s\n", - context.condition.c_str())); - - return new details::null_node(); - } - - #ifndef exprtk_disable_string_capabilities - if (assert_message && details::is_const_string_node(assert_message)) - { - context.message = dynamic_cast*>(assert_message)->str(); - } - - if (assert_id && details::is_const_string_node(assert_id)) - { - context.id = dynamic_cast*>(assert_id)->str(); - - if (assert_ids_.end() != assert_ids_.find(context.id)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR222 - Duplicate assert ID: " + context.id, - exprtk_error_location)); - - return error_node(); - } - - assert_ids_.insert(context.id); - free_node(node_allocator_, assert_id); - } - #endif - - expression_node_ptr result_node = - expression_generator_.assert_call( - assert_condition, - assert_message, - context); - - exprtk_debug(("parse_assert_statement() - assert condition: [%s]\n", context.condition.c_str() )); - exprtk_debug(("parse_assert_statement() - assert message: [%s]\n", context.message .c_str() )); - exprtk_debug(("parse_assert_statement() - assert id: [%s]\n", context.id .c_str() )); - exprtk_debug(("parse_assert_statement() - assert offset: [%d]\n", static_cast(context.offet))); - - if (0 == result_node) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR223 - Failed to synthesize assert", - exprtk_error_location)); - - return error_node(); - } - - sdd.delete_ptr = false; - return result_node; - } - - inline bool post_variable_process(const std::string& symbol) - { - if ( - peek_token_is(token_t::e_lbracket ) || - peek_token_is(token_t::e_lcrlbracket) || - peek_token_is(token_t::e_lsqrbracket) - ) - { - if (!settings_.commutative_check_enabled()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR224 - Invalid sequence of variable '" + symbol + "' and bracket", - exprtk_error_location)); - - return false; - } - - lexer().insert_front(token_t::e_mul); - } - - return true; - } - - inline bool post_bracket_process(const typename token_t::token_type& token, expression_node_ptr& branch) - { - bool implied_mul = false; - - if (details::is_generally_string_node(branch)) - return true; - - if (details::is_ivector_node(branch)) - return true; - - const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; - - switch (token) - { - case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket , hold) || - token_is(token_t::e_lcrlbracket, hold) || - token_is(token_t::e_lsqrbracket, hold) ; - break; - - case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket , hold) || - token_is(token_t::e_lcrlbracket, hold) || - token_is(token_t::e_lsqrbracket, hold) ; - break; - - case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket , hold) || - token_is(token_t::e_lcrlbracket, hold) || - token_is(token_t::e_lsqrbracket, hold) ; - break; - - default : return true; - } - - if (implied_mul) - { - if (!settings_.commutative_check_enabled()) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR225 - Invalid sequence of brackets", - exprtk_error_location)); - - return false; - } - else if (token_t::e_eof != current_token().type) - { - lexer().insert_front(current_token().type); - lexer().insert_front(token_t::e_mul); - next_token(); - } - } - - return true; - } - - typedef typename interval_container_t::interval_t interval_t; - typedef interval_container_t immutable_memory_map_t; - typedef std::map immutable_symtok_map_t; - - inline interval_t make_memory_range(const T& t) - { - const T* begin = reinterpret_cast(&t); - const T* end = begin + 1; - return interval_t(begin, end); - } - - inline interval_t make_memory_range(const T* begin, const std::size_t size) - { - return interval_t(begin, begin + size); - } - - inline interval_t make_memory_range(details::char_cptr begin, const std::size_t size) - { - return interval_t(begin, begin + size); - } - - void lodge_immutable_symbol(const lexer::token& token, const interval_t interval) - { - immutable_memory_map_.add_interval(interval); - immutable_symtok_map_[interval] = token; - } - - inline expression_node_ptr parse_symtab_symbol() - { - const std::string symbol = current_token().value; - - // Are we dealing with a variable or a special constant? - typedef typename symtab_store::variable_context var_ctxt_t; - var_ctxt_t var_ctx = symtab_store_.get_variable_context(symbol); - - if (var_ctx.variable) - { - assert(var_ctx.symbol_table); - - expression_node_ptr result_variable = var_ctx.variable; - - if (symtab_store_.is_constant_node(symbol)) - { - result_variable = expression_generator_(var_ctx.variable->value()); - } - else if (symbol_table_t::e_immutable == var_ctx.symbol_table->mutability()) - { - lodge_immutable_symbol(current_token(), make_memory_range(var_ctx.variable->ref())); - result_variable = var_ctx.variable; - } - - if (!post_variable_process(symbol)) - return error_node(); - - lodge_symbol(symbol, e_st_variable); - - next_token(); - - return result_variable; - } - - // Are we dealing with a locally defined variable, vector or string? - if (!sem_.empty()) - { - scope_element& se = sem_.get_active_element(symbol); - - if (se.active && details::imatch(se.name, symbol)) - { - if ( - (scope_element::e_variable == se.type) || - (scope_element::e_literal == se.type) - ) - { - se.active = true; - lodge_symbol(symbol, e_st_local_variable); - - if (!post_variable_process(symbol)) - return error_node(); - - next_token(); - - return (scope_element::e_variable == se.type) ? - se.var_node : - expression_generator_(se.var_node->value()); - } - else if (scope_element::e_vector == se.type) - { - return parse_vector(); - } - #ifndef exprtk_disable_string_capabilities - else if (scope_element::e_string == se.type) - { - return parse_string(); - } - #endif - } - } - - #ifndef exprtk_disable_string_capabilities - // Are we dealing with a string variable? - if (symtab_store_.is_stringvar(symbol)) - { - return parse_string(); - } - #endif - - { - // Are we dealing with a function? - ifunction* function = symtab_store_.get_function(symbol); - - if (function) - { - lodge_symbol(symbol, e_st_function); - - expression_node_ptr func_node = - parse_function_invocation(function,symbol); - - if (func_node) - return func_node; - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR226 - Failed to generate node for function: '" + symbol + "'", - exprtk_error_location)); - - return error_node(); - } - } - } - - { - // Are we dealing with a vararg function? - ivararg_function* vararg_function = symtab_store_.get_vararg_function(symbol); - - if (vararg_function) - { - lodge_symbol(symbol, e_st_function); - - expression_node_ptr vararg_func_node = - parse_vararg_function_call(vararg_function, symbol); - - if (vararg_func_node) - return vararg_func_node; - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR227 - Failed to generate node for vararg function: '" + symbol + "'", - exprtk_error_location)); - - return error_node(); - } - } - } - - { - // Are we dealing with a vararg generic function? - igeneric_function* generic_function = symtab_store_.get_generic_function(symbol); - - if (generic_function) - { - lodge_symbol(symbol, e_st_function); - - expression_node_ptr genericfunc_node = - parse_generic_function_call(generic_function, symbol); - - if (genericfunc_node) - return genericfunc_node; - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR228 - Failed to generate node for generic function: '" + symbol + "'", - exprtk_error_location)); - - return error_node(); - } - } - } - - #ifndef exprtk_disable_string_capabilities - { - // Are we dealing with a vararg string returning function? - igeneric_function* string_function = symtab_store_.get_string_function(symbol); - - if (string_function) - { - lodge_symbol(symbol, e_st_function); - - expression_node_ptr stringfunc_node = - parse_string_function_call(string_function, symbol); - - if (stringfunc_node) - return stringfunc_node; - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR229 - Failed to generate node for string function: '" + symbol + "'", - exprtk_error_location)); - - return error_node(); - } - } - } - - { - // Are we dealing with a vararg overloaded scalar/string returning function? - igeneric_function* overload_function = symtab_store_.get_overload_function(symbol); - - if (overload_function) - { - lodge_symbol(symbol, e_st_function); - - expression_node_ptr overloadfunc_node = - parse_overload_function_call(overload_function, symbol); - - if (overloadfunc_node) - return overloadfunc_node; - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR230 - Failed to generate node for overload function: '" + symbol + "'", - exprtk_error_location)); - - return error_node(); - } - } - } - #endif - - // Are we dealing with a vector? - if (symtab_store_.is_vector(symbol)) - { - lodge_symbol(symbol, e_st_vector); - return parse_vector(); - } - - if (details::is_reserved_symbol(symbol)) - { - if ( - settings_.function_enabled(symbol) || - !details::is_base_function(symbol) - ) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR231 - Invalid use of reserved symbol '" + symbol + "'", - exprtk_error_location)); - - return error_node(); - } - } - - // Should we handle unknown symbols? - if (resolve_unknown_symbol_ && unknown_symbol_resolver_) - { - if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) - { - symbol_table_t& symtab = symtab_store_.get_symbol_table(); - - std::string error_message; - - if (unknown_symbol_resolver::e_usrmode_default == unknown_symbol_resolver_->mode) - { - T default_value = T(0); - - typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type = unknown_symbol_resolver::e_usr_unknown_type; - - if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message)) - { - bool create_result = false; - - switch (usr_symbol_type) - { - case unknown_symbol_resolver::e_usr_variable_type : - create_result = symtab.create_variable(symbol, default_value); - break; - - case unknown_symbol_resolver::e_usr_constant_type : - create_result = symtab.add_constant(symbol, default_value); - break; - - default : create_result = false; - } - - if (create_result) - { - expression_node_ptr var = symtab_store_.get_variable(symbol); - - if (var) - { - if (symtab_store_.is_constant_node(symbol)) - { - var = expression_generator_(var->value()); - } - - lodge_symbol(symbol, e_st_variable); - - if (!post_variable_process(symbol)) - return error_node(); - - next_token(); - - return var; - } - } - } - - set_error(make_error( - parser_error::e_symtab, - current_token(), - "ERR232 - Failed to create variable: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message), - exprtk_error_location)); - - } - else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) - { - if (unknown_symbol_resolver_->process(symbol, symtab, error_message)) - { - expression_node_ptr result = parse_symtab_symbol(); - - if (result) - { - return result; - } - } - - set_error(make_error( - parser_error::e_symtab, - current_token(), - "ERR233 - Failed to resolve symbol: '" + symbol + "'" + - (error_message.empty() ? "" : " - " + error_message), - exprtk_error_location)); - } - - return error_node(); - } - } - - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR234 - Undefined symbol: '" + symbol + "'", - exprtk_error_location)); - - return error_node(); - } - - inline expression_node_ptr check_block_statement_closure(expression_node_ptr expression) - { - if ( - expression && - ( - (current_token().type == token_t::e_symbol) || - (current_token().type == token_t::e_number) - ) - ) - { - free_node(node_allocator_, expression); - - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR235 - Invalid syntax '" + current_token().value + "' possible missing operator or context", - exprtk_error_location)); - - return error_node(); - } - - return expression; - } - - inline expression_node_ptr parse_symbol() - { - static const std::string symbol_if = "if" ; - static const std::string symbol_while = "while" ; - static const std::string symbol_repeat = "repeat" ; - static const std::string symbol_for = "for" ; - static const std::string symbol_switch = "switch" ; - static const std::string symbol_null = "null" ; - static const std::string symbol_break = "break" ; - static const std::string symbol_continue = "continue"; - static const std::string symbol_var = "var" ; - static const std::string symbol_const = "const" ; - static const std::string symbol_swap = "swap" ; - static const std::string symbol_return = "return" ; - static const std::string symbol_not = "not" ; - static const std::string symbol_assert = "assert" ; - - const std::string symbol = current_token().value; - - if (valid_vararg_operation(symbol)) - { - return parse_vararg_function(); - } - else if (details::imatch(symbol, symbol_not)) - { - return parse_not_statement(); - } - else if (valid_base_operation(symbol)) - { - return parse_base_operation(); - } - else if ( - details::imatch(symbol, symbol_if) && - settings_.control_struct_enabled(symbol) - ) - { - return parse_conditional_statement(); - } - else if ( - details::imatch(symbol, symbol_while) && - settings_.control_struct_enabled(symbol) - ) - { - return check_block_statement_closure(parse_while_loop()); - } - else if ( - details::imatch(symbol, symbol_repeat) && - settings_.control_struct_enabled(symbol) - ) - { - return check_block_statement_closure(parse_repeat_until_loop()); - } - else if ( - details::imatch(symbol, symbol_for) && - settings_.control_struct_enabled(symbol) - ) - { - return check_block_statement_closure(parse_for_loop()); - } - else if ( - details::imatch(symbol, symbol_switch) && - settings_.control_struct_enabled(symbol) - ) - { - return check_block_statement_closure(parse_switch_statement()); - } - else if (details::is_valid_sf_symbol(symbol)) - { - return parse_special_function(); - } - else if (details::imatch(symbol, symbol_null)) - { - return parse_null_statement(); - } - #ifndef exprtk_disable_break_continue - else if (details::imatch(symbol, symbol_break)) - { - return parse_break_statement(); - } - else if (details::imatch(symbol, symbol_continue)) - { - return parse_continue_statement(); - } - #endif - else if (details::imatch(symbol, symbol_var)) - { - return parse_define_var_statement(); - } - else if (details::imatch(symbol, symbol_const)) - { - return parse_define_constvar_statement(); - } - else if (details::imatch(symbol, symbol_swap)) - { - return parse_swap_statement(); - } - #ifndef exprtk_disable_return_statement - else if ( - details::imatch(symbol, symbol_return) && - settings_.control_struct_enabled(symbol) - ) - { - return check_block_statement_closure(parse_return_statement()); - } - #endif - else if (details::imatch(symbol, symbol_assert)) - { - return parse_assert_statement(); - } - else if (symtab_store_.valid() || !sem_.empty()) - { - return parse_symtab_symbol(); - } - else - { - set_error(make_error( - parser_error::e_symtab, - current_token(), - "ERR236 - Unknown variable or function encountered. Symbol table(s) " - "is either invalid or does not contain symbol: '" + symbol + "'", - exprtk_error_location)); - - return error_node(); - } - } - - inline expression_node_ptr parse_branch(precedence_level precedence = e_level00) - { - stack_limit_handler slh(*this); - - if (!slh) - { - return error_node(); - } - - expression_node_ptr branch = error_node(); - - if (token_t::e_number == current_token().type) - { - T numeric_value = T(0); - - if (details::string_to_real(current_token().value, numeric_value)) - { - expression_node_ptr literal_exp = expression_generator_(numeric_value); - - if (0 == literal_exp) - { - set_error(make_error( - parser_error::e_numeric, - current_token(), - "ERR237 - Failed generate node for scalar: '" + current_token().value + "'", - exprtk_error_location)); - - return error_node(); - } - - next_token(); - branch = literal_exp; - } - else - { - set_error(make_error( - parser_error::e_numeric, - current_token(), - "ERR238 - Failed to convert '" + current_token().value + "' to a number", - exprtk_error_location)); - - return error_node(); - } - } - else if (token_t::e_symbol == current_token().type) - { - branch = parse_symbol(); - } - #ifndef exprtk_disable_string_capabilities - else if (token_t::e_string == current_token().type) - { - branch = parse_const_string(); - } - #endif - else if (token_t::e_lbracket == current_token().type) - { - next_token(); - - if (0 == (branch = parse_expression())) - { - return error_node(); - } - - token_is(token_t::e_eof); - - if (!token_is(token_t::e_rbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR239 - Expected ')' instead of: '" + current_token().value + "'", - exprtk_error_location)); - - details::free_node(node_allocator_, branch); - - return error_node(); - } - else if (!post_bracket_process(token_t::e_lbracket,branch)) - { - details::free_node(node_allocator_, branch); - - return error_node(); - } - - parse_pending_vector_index_operator(branch); - } - else if (token_t::e_lsqrbracket == current_token().type) - { - next_token(); - - if (0 == (branch = parse_expression())) - return error_node(); - else if (!token_is(token_t::e_rsqrbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR240 - Expected ']' instead of: '" + current_token().value + "'", - exprtk_error_location)); - - details::free_node(node_allocator_, branch); - - return error_node(); - } - else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) - { - details::free_node(node_allocator_, branch); - - return error_node(); - } - } - else if (token_t::e_lcrlbracket == current_token().type) - { - next_token(); - - if (0 == (branch = parse_expression())) - return error_node(); - else if (!token_is(token_t::e_rcrlbracket)) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR241 - Expected '}' instead of: '" + current_token().value + "'", - exprtk_error_location)); - - details::free_node(node_allocator_, branch); - - return error_node(); - } - else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) - { - details::free_node(node_allocator_, branch); - - return error_node(); - } - } - else if (token_t::e_sub == current_token().type) - { - next_token(); - branch = parse_expression(e_level11); - - if ( - branch && - !( - details::is_neg_unary_node (branch) && - simplify_unary_negation_branch(branch) - ) - ) - { - expression_node_ptr result = expression_generator_(details::e_neg,branch); - - if (0 == result) - { - details::free_node(node_allocator_, branch); - - return error_node(); - } - else - branch = result; - } - } - else if (token_t::e_add == current_token().type) - { - next_token(); - branch = parse_expression(e_level13); - } - else if (token_t::e_eof == current_token().type) - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR242 - Premature end of expression[1]", - exprtk_error_location)); - - return error_node(); - } - else - { - set_error(make_error( - parser_error::e_syntax, - current_token(), - "ERR243 - Premature end of expression[2]", - exprtk_error_location)); - - return error_node(); - } - - if ( - branch && - (e_level00 == precedence) && - token_is(token_t::e_ternary,prsrhlpr_t::e_hold) - ) - { - branch = parse_ternary_conditional_statement(branch); - } - - parse_pending_string_rangesize(branch); - - return branch; - } - - template - class expression_generator - { - public: - - typedef details::expression_node* expression_node_ptr; - typedef expression_node_ptr (*synthesize_functor_t)(expression_generator&, const details::operator_type& operation, expression_node_ptr (&branch)[2]); - typedef std::map synthesize_map_t; - typedef typename exprtk::parser parser_t; - typedef const Type& vtype; - typedef const Type ctype; - - inline void init_synthesize_map() - { - #ifndef exprtk_disable_enhanced_features - synthesize_map_["(v)o(v)"] = synthesize_vov_expression::process; - synthesize_map_["(c)o(v)"] = synthesize_cov_expression::process; - synthesize_map_["(v)o(c)"] = synthesize_voc_expression::process; - - #define register_synthezier(S) \ - synthesize_map_[S ::node_type::id()] = S ::process; \ - - register_synthezier(synthesize_vovov_expression0) - register_synthezier(synthesize_vovov_expression1) - register_synthezier(synthesize_vovoc_expression0) - register_synthezier(synthesize_vovoc_expression1) - register_synthezier(synthesize_vocov_expression0) - register_synthezier(synthesize_vocov_expression1) - register_synthezier(synthesize_covov_expression0) - register_synthezier(synthesize_covov_expression1) - register_synthezier(synthesize_covoc_expression0) - register_synthezier(synthesize_covoc_expression1) - register_synthezier(synthesize_cocov_expression1) - register_synthezier(synthesize_vococ_expression0) - - register_synthezier(synthesize_vovovov_expression0) - register_synthezier(synthesize_vovovoc_expression0) - register_synthezier(synthesize_vovocov_expression0) - register_synthezier(synthesize_vocovov_expression0) - register_synthezier(synthesize_covovov_expression0) - register_synthezier(synthesize_covocov_expression0) - register_synthezier(synthesize_vocovoc_expression0) - register_synthezier(synthesize_covovoc_expression0) - register_synthezier(synthesize_vococov_expression0) - - register_synthezier(synthesize_vovovov_expression1) - register_synthezier(synthesize_vovovoc_expression1) - register_synthezier(synthesize_vovocov_expression1) - register_synthezier(synthesize_vocovov_expression1) - register_synthezier(synthesize_covovov_expression1) - register_synthezier(synthesize_covocov_expression1) - register_synthezier(synthesize_vocovoc_expression1) - register_synthezier(synthesize_covovoc_expression1) - register_synthezier(synthesize_vococov_expression1) - - register_synthezier(synthesize_vovovov_expression2) - register_synthezier(synthesize_vovovoc_expression2) - register_synthezier(synthesize_vovocov_expression2) - register_synthezier(synthesize_vocovov_expression2) - register_synthezier(synthesize_covovov_expression2) - register_synthezier(synthesize_covocov_expression2) - register_synthezier(synthesize_vocovoc_expression2) - register_synthezier(synthesize_covovoc_expression2) - - register_synthezier(synthesize_vovovov_expression3) - register_synthezier(synthesize_vovovoc_expression3) - register_synthezier(synthesize_vovocov_expression3) - register_synthezier(synthesize_vocovov_expression3) - register_synthezier(synthesize_covovov_expression3) - register_synthezier(synthesize_covocov_expression3) - register_synthezier(synthesize_vocovoc_expression3) - register_synthezier(synthesize_covovoc_expression3) - register_synthezier(synthesize_vococov_expression3) - - register_synthezier(synthesize_vovovov_expression4) - register_synthezier(synthesize_vovovoc_expression4) - register_synthezier(synthesize_vovocov_expression4) - register_synthezier(synthesize_vocovov_expression4) - register_synthezier(synthesize_covovov_expression4) - register_synthezier(synthesize_covocov_expression4) - register_synthezier(synthesize_vocovoc_expression4) - register_synthezier(synthesize_covovoc_expression4) - - #undef register_synthezier - #endif - } - - inline void set_parser(parser_t& p) - { - parser_ = &p; - } - - inline void set_uom(unary_op_map_t& unary_op_map) - { - unary_op_map_ = &unary_op_map; - } - - inline void set_bom(binary_op_map_t& binary_op_map) - { - binary_op_map_ = &binary_op_map; - } - - inline void set_ibom(inv_binary_op_map_t& inv_binary_op_map) - { - inv_binary_op_map_ = &inv_binary_op_map; - } - - inline void set_sf3m(sf3_map_t& sf3_map) - { - sf3_map_ = &sf3_map; - } - - inline void set_sf4m(sf4_map_t& sf4_map) - { - sf4_map_ = &sf4_map; - } - - inline void set_allocator(details::node_allocator& na) - { - node_allocator_ = &na; - } - - inline void set_strength_reduction_state(const bool enabled) - { - strength_reduction_enabled_ = enabled; - } - - inline bool strength_reduction_enabled() const - { - return strength_reduction_enabled_; - } - - inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) - { - typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); - - if (binary_op_map_->end() == bop_itr) - return false; - - bop = bop_itr->second; - - return true; - } - - inline bool valid_operator(const details::operator_type& operation, unary_functor_t& uop) - { - typename unary_op_map_t::iterator uop_itr = unary_op_map_->find(operation); - - if ((*unary_op_map_).end() == uop_itr) - return false; - - uop = uop_itr->second; - - return true; - } - - inline details::operator_type get_operator(const binary_functor_t& bop) const - { - return (*inv_binary_op_map_).find(bop)->second; - } - - inline expression_node_ptr operator() (const Type& v) const - { - return node_allocator_->allocate(v); - } - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr operator() (const std::string& s) const - { - return node_allocator_->allocate(s); - } - - inline expression_node_ptr operator() (std::string& s, range_t& rp) const - { - return node_allocator_->allocate_rr(s,rp); - } - - inline expression_node_ptr operator() (const std::string& s, range_t& rp) const - { - return node_allocator_->allocate_tt(s,rp); - } - - inline expression_node_ptr operator() (expression_node_ptr branch, range_t& rp) const - { - if (is_generally_string_node(branch)) - return node_allocator_->allocate_tt(branch,rp); - else - return error_node(); - } - #endif - - inline bool unary_optimisable(const details::operator_type& operation) const - { - return (details::e_abs == operation) || (details::e_acos == operation) || - (details::e_acosh == operation) || (details::e_asin == operation) || - (details::e_asinh == operation) || (details::e_atan == operation) || - (details::e_atanh == operation) || (details::e_ceil == operation) || - (details::e_cos == operation) || (details::e_cosh == operation) || - (details::e_exp == operation) || (details::e_expm1 == operation) || - (details::e_floor == operation) || (details::e_log == operation) || - (details::e_log10 == operation) || (details::e_log2 == operation) || - (details::e_log1p == operation) || (details::e_neg == operation) || - (details::e_pos == operation) || (details::e_round == operation) || - (details::e_sin == operation) || (details::e_sinc == operation) || - (details::e_sinh == operation) || (details::e_sqrt == operation) || - (details::e_tan == operation) || (details::e_tanh == operation) || - (details::e_cot == operation) || (details::e_sec == operation) || - (details::e_csc == operation) || (details::e_r2d == operation) || - (details::e_d2r == operation) || (details::e_d2g == operation) || - (details::e_g2d == operation) || (details::e_notl == operation) || - (details::e_sgn == operation) || (details::e_erf == operation) || - (details::e_erfc == operation) || (details::e_ncdf == operation) || - (details::e_frac == operation) || (details::e_trunc == operation) ; - } - - inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) const - { - typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); - - if (sf3_map_->end() == itr) - return false; - else - tfunc = itr->second.first; - - return true; - } - - inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) const - { - typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); - - if (sf4_map_->end() == itr) - return false; - else - qfunc = itr->second.first; - - return true; - } - - inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) const - { - typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); - - if (sf3_map_->end() == itr) - return false; - else - operation = itr->second.second; - - return true; - } - - inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) const - { - typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); - - if (sf4_map_->end() == itr) - return false; - else - operation = itr->second.second; - - return true; - } - - inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[1]) - { - if (0 == branch[0]) - { - return error_node(); - } - else if (details::is_null_node(branch[0])) - { - return branch[0]; - } - else if (details::is_break_node(branch[0])) - { - return error_node(); - } - else if (details::is_continue_node(branch[0])) - { - return error_node(); - } - else if (details::is_constant_node(branch[0])) - { - return synthesize_expression(operation,branch); - } - else if (unary_optimisable(operation) && details::is_variable_node(branch[0])) - { - return synthesize_uv_expression(operation,branch); - } - else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) - { - return synthesize_uvec_expression(operation,branch); - } - else - return synthesize_unary_expression(operation,branch); - } - - inline bool is_assignment_operation(const details::operator_type& operation) const - { - return ( - (details::e_addass == operation) || - (details::e_subass == operation) || - (details::e_mulass == operation) || - (details::e_divass == operation) || - (details::e_modass == operation) - ) && - parser_->settings_.assignment_enabled(operation); - } - - #ifndef exprtk_disable_string_capabilities - inline bool valid_string_operation(const details::operator_type& operation) const - { - return (details::e_add == operation) || - (details::e_lt == operation) || - (details::e_lte == operation) || - (details::e_gt == operation) || - (details::e_gte == operation) || - (details::e_eq == operation) || - (details::e_ne == operation) || - (details::e_in == operation) || - (details::e_like == operation) || - (details::e_ilike == operation) || - (details::e_assign == operation) || - (details::e_addass == operation) || - (details::e_swap == operation) ; - } - #else - inline bool valid_string_operation(const details::operator_type&) const - { - return false; - } - #endif - - inline std::string to_str(const details::operator_type& operation) const - { - switch (operation) - { - case details::e_add : return "+" ; - case details::e_sub : return "-" ; - case details::e_mul : return "*" ; - case details::e_div : return "/" ; - case details::e_mod : return "%" ; - case details::e_pow : return "^" ; - case details::e_lt : return "<" ; - case details::e_lte : return "<=" ; - case details::e_gt : return ">" ; - case details::e_gte : return ">=" ; - case details::e_eq : return "==" ; - case details::e_ne : return "!=" ; - case details::e_and : return "and" ; - case details::e_nand : return "nand" ; - case details::e_or : return "or" ; - case details::e_nor : return "nor" ; - case details::e_xor : return "xor" ; - case details::e_xnor : return "xnor" ; - default : return "UNKNOWN"; - } - } - - inline bool operation_optimisable(const details::operator_type& operation) const - { - return (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) || - (details::e_mod == operation) || - (details::e_pow == operation) || - (details::e_lt == operation) || - (details::e_lte == operation) || - (details::e_gt == operation) || - (details::e_gte == operation) || - (details::e_eq == operation) || - (details::e_ne == operation) || - (details::e_and == operation) || - (details::e_nand == operation) || - (details::e_or == operation) || - (details::e_nor == operation) || - (details::e_xor == operation) || - (details::e_xnor == operation) ; - } - - inline std::string branch_to_id(expression_node_ptr branch) const - { - static const std::string null_str ("(null)" ); - static const std::string const_str ("(c)" ); - static const std::string var_str ("(v)" ); - static const std::string vov_str ("(vov)" ); - static const std::string cov_str ("(cov)" ); - static const std::string voc_str ("(voc)" ); - static const std::string str_str ("(s)" ); - static const std::string strrng_str ("(rngs)" ); - static const std::string cs_str ("(cs)" ); - static const std::string cstrrng_str("(crngs)"); - - if (details::is_null_node(branch)) - return null_str; - else if (details::is_constant_node(branch)) - return const_str; - else if (details::is_variable_node(branch)) - return var_str; - else if (details::is_vov_node(branch)) - return vov_str; - else if (details::is_cov_node(branch)) - return cov_str; - else if (details::is_voc_node(branch)) - return voc_str; - else if (details::is_string_node(branch)) - return str_str; - else if (details::is_const_string_node(branch)) - return cs_str; - else if (details::is_string_range_node(branch)) - return strrng_str; - else if (details::is_const_string_range_node(branch)) - return cstrrng_str; - else if (details::is_t0ot1ot2_node(branch)) - return "(" + dynamic_cast*>(branch)->type_id() + ")"; - else if (details::is_t0ot1ot2ot3_node(branch)) - return "(" + dynamic_cast*>(branch)->type_id() + ")"; - else - return "ERROR"; - } - - inline std::string branch_to_id(expression_node_ptr (&branch)[2]) const - { - return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); - } - - inline bool cov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return details::is_constant_node(branch[0]) && - details::is_variable_node(branch[1]) ; - } - - inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return details::is_variable_node(branch[0]) && - details::is_constant_node(branch[1]) ; - } - - inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return details::is_variable_node(branch[0]) && - details::is_variable_node(branch[1]) ; - } - - inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return details::is_constant_node(branch[0]) && - !details::is_constant_node(branch[1]) ; - } - - inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return !details::is_constant_node(branch[0]) && - details::is_constant_node(branch[1]) ; - } - - inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) || - (details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])) ; - } - else - return false; - } - - inline bool coboc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) || - (details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])) ; - } - else - return false; - } - - inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return details::is_uv_node(branch[0]) && - details::is_uv_node(branch[1]) ; - } - - inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return details::is_variable_node(branch[0]) && - !details::is_variable_node(branch[1]) ; - } - - inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return !details::is_variable_node(branch[0]) && - details::is_variable_node(branch[1]) ; - } - - inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return !details::is_constant_node(branch[0]) || - !details::is_constant_node(branch[1]) ; - } - - inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (is_assignment_operation(operation)) - { - const bool b1_is_genstring = details::is_generally_string_node(branch[1]); - - if (details::is_string_node(branch[0])) - return !b1_is_genstring; - else if (details::is_literal_node(branch[0])) - return true; - else - return ( - !details::is_variable_node (branch[0]) && - !details::is_vector_elem_node (branch[0]) && - !details::is_vector_celem_node (branch[0]) && - !details::is_vector_elem_rtc_node (branch[0]) && - !details::is_vector_celem_rtc_node (branch[0]) && - !details::is_rebasevector_elem_node (branch[0]) && - !details::is_rebasevector_celem_node (branch[0]) && - !details::is_rebasevector_elem_rtc_node (branch[0]) && - !details::is_rebasevector_celem_rtc_node(branch[0]) && - !details::is_vector_node (branch[0]) - ) - || b1_is_genstring; - } - else - return false; - } - - inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) const - { - if ( - !details::is_constant_node(branch[1]) || - details::is_constant_node(branch[0]) || - details::is_variable_node(branch[0]) || - details::is_vector_node (branch[0]) || - details::is_generally_string_node(branch[0]) - ) - return false; - - const Type c = static_cast*>(branch[1])->value(); - - return cardinal_pow_optimisable(operation, c); - } - - inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) const - { - return ( - details::is_break_node (branch[0]) || - details::is_break_node (branch[1]) || - details::is_continue_node(branch[0]) || - details::is_continue_node(branch[1]) - ); - } - - inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - const bool b0_string = is_generally_string_node(branch[0]); - const bool b1_string = is_generally_string_node(branch[1]); - - bool result = false; - - if (b0_string != b1_string) - result = true; - else if (!valid_string_operation(operation) && b0_string && b1_string) - result = true; - - if (result) - { - parser_->set_synthesis_error("Invalid string operation"); - } - - return result; - } - - inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const - { - const bool b0_string = is_generally_string_node(branch[0]); - const bool b1_string = is_generally_string_node(branch[1]); - const bool b2_string = is_generally_string_node(branch[2]); - - bool result = false; - - if ((b0_string != b1_string) || (b1_string != b2_string)) - result = true; - else if ((details::e_inrange != operation) && b0_string && b1_string && b2_string) - result = true; - - if (result) - { - parser_->set_synthesis_error("Invalid string operation"); - } - - return result; - } - - inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - const bool b0_string = is_generally_string_node(branch[0]); - const bool b1_string = is_generally_string_node(branch[1]); - - return (b0_string && b1_string && valid_string_operation(operation)); - } - - inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const - { - const bool b0_string = is_generally_string_node(branch[0]); - const bool b1_string = is_generally_string_node(branch[1]); - const bool b2_string = is_generally_string_node(branch[2]); - - return (b0_string && b1_string && b2_string && (details::e_inrange == operation)); - } - - #ifndef exprtk_disable_sc_andor - inline bool is_shortcircuit_expression(const details::operator_type& operation) const - { - return ( - (details::e_scand == operation) || - (details::e_scor == operation) - ); - } - #else - inline bool is_shortcircuit_expression(const details::operator_type&) const - { - return false; - } - #endif - - inline bool is_null_present(expression_node_ptr (&branch)[2]) const - { - return ( - details::is_null_node(branch[0]) || - details::is_null_node(branch[1]) - ); - } - - inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) - return false; - else - return ( - (details::e_lt == operation) || - (details::e_lte == operation) || - (details::e_gt == operation) || - (details::e_gte == operation) || - (details::e_eq == operation) || - (details::e_ne == operation) || - (details::e_equal == operation) || - (details::e_and == operation) || - (details::e_nand == operation) || - (details::e_or == operation) || - (details::e_nor == operation) || - (details::e_xor == operation) || - (details::e_xnor == operation) - ); - } - - inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) - return false; - else - return ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) || - (details::e_pow == operation) - ); - } - - inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - if ((0 == branch[0]) || (0 == branch[1])) - { - parser_->set_error(parser_error::make_error( - parser_error::e_syntax, - parser_->current_state().token, - "ERR244 - Invalid branches received for operator '" + details::to_str(operation) + "'", - exprtk_error_location)); - - return error_node(); - } - else if (is_invalid_string_op(operation,branch)) - { - parser_->set_error(parser_error::make_error( - parser_error::e_syntax, - parser_->current_state().token, - "ERR245 - Invalid branch pair for string operator '" + details::to_str(operation) + "'", - exprtk_error_location)); - - return error_node(); - } - else if (is_invalid_assignment_op(operation,branch)) - { - parser_->set_error(parser_error::make_error( - parser_error::e_syntax, - parser_->current_state().token, - "ERR246 - Invalid branch pair for assignment operator '" + details::to_str(operation) + "'", - exprtk_error_location)); - - return error_node(); - } - else if (is_invalid_break_continue_op(branch)) - { - parser_->set_error(parser_error::make_error( - parser_error::e_syntax, - parser_->current_state().token, - "ERR247 - Invalid branch pair for break/continue operator '" + details::to_str(operation) + "'", - exprtk_error_location)); - - return error_node(); - } - else if (details::e_assign == operation) - { - return synthesize_assignment_expression(operation, branch); - } - else if (details::e_swap == operation) - { - return synthesize_swap_expression(branch); - } - else if (is_assignment_operation(operation)) - { - return synthesize_assignment_operation_expression(operation, branch); - } - else if (is_vector_eqineq_logic_operation(operation, branch)) - { - return synthesize_veceqineqlogic_operation_expression(operation, branch); - } - else if (is_vector_arithmetic_operation(operation, branch)) - { - return synthesize_vecarithmetic_operation_expression(operation, branch); - } - else if (is_shortcircuit_expression(operation)) - { - return synthesize_shortcircuit_expression(operation, branch); - } - else if (is_string_operation(operation, branch)) - { - return synthesize_string_expression(operation, branch); - } - else if (is_null_present(branch)) - { - return synthesize_null_expression(operation, branch); - } - #ifndef exprtk_disable_cardinal_pow_optimisation - else if (is_constpow_operation(operation, branch)) - { - return cardinal_pow_optimisation(branch); - } - #endif - - expression_node_ptr result = error_node(); - - #ifndef exprtk_disable_enhanced_features - if (synthesize_expression(operation, branch, result)) - { - return result; - } - else - #endif - - { - /* - Possible reductions: - 1. c o cob -> cob - 2. cob o c -> cob - 3. c o boc -> boc - 4. boc o c -> boc - */ - result = error_node(); - - if (cocob_optimisable(operation, branch)) - { - result = synthesize_cocob_expression::process((*this), operation, branch); - } - else if (coboc_optimisable(operation, branch) && (0 == result)) - { - result = synthesize_coboc_expression::process((*this), operation, branch); - } - - if (result) - return result; - } - - if (uvouv_optimisable(operation, branch)) - { - return synthesize_uvouv_expression(operation, branch); - } - else if (vob_optimisable(operation, branch)) - { - return synthesize_vob_expression::process((*this), operation, branch); - } - else if (bov_optimisable(operation, branch)) - { - return synthesize_bov_expression::process((*this), operation, branch); - } - else if (cob_optimisable(operation, branch)) - { - return synthesize_cob_expression::process((*this), operation, branch); - } - else if (boc_optimisable(operation, branch)) - { - return synthesize_boc_expression::process((*this), operation, branch); - } - #ifndef exprtk_disable_enhanced_features - else if (cov_optimisable(operation, branch)) - { - return synthesize_cov_expression::process((*this), operation, branch); - } - #endif - else if (binext_optimisable(operation, branch)) - { - return synthesize_binary_ext_expression::process((*this), operation, branch); - } - else - return synthesize_expression(operation, branch); - } - - inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[3]) - { - if ( - (0 == branch[0]) || - (0 == branch[1]) || - (0 == branch[2]) - ) - { - details::free_all_nodes(*node_allocator_,branch); - - parser_->set_error(parser_error::make_error( - parser_error::e_syntax, - parser_->current_state().token, - "ERR248 - Invalid branches operator '" + details::to_str(operation) + "'", - exprtk_error_location)); - - return error_node(); - } - else if (is_invalid_string_op(operation, branch)) - { - parser_->set_error(parser_error::make_error( - parser_error::e_syntax, - parser_->current_state().token, - "ERR249 - Invalid branches for string operator '" + details::to_str(operation) + "'", - exprtk_error_location)); - - return error_node(); - } - else if (is_string_operation(operation, branch)) - { - return synthesize_string_expression(operation, branch); - } - else - return synthesize_expression(operation, branch); - } - - inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - return synthesize_expression(operation,branch); - } - - inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr b0) - { - expression_node_ptr branch[1] = { b0 }; - return (*this)(operation,branch); - } - - inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr& b0, expression_node_ptr& b1) - { - expression_node_ptr result = error_node(); - - if ((0 != b0) && (0 != b1)) - { - expression_node_ptr branch[2] = { b0, b1 }; - result = expression_generator::operator()(operation, branch); - b0 = branch[0]; - b1 = branch[1]; - } - - return result; - } - - inline expression_node_ptr conditional(expression_node_ptr condition, - expression_node_ptr consequent, - expression_node_ptr alternative) const - { - if ((0 == condition) || (0 == consequent)) - { - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, consequent ); - details::free_node(*node_allocator_, alternative); - - const std::string invalid_branches = - ((0 == condition ) ? std::string("condition ") : "") + - ((0 == consequent) ? std::string("consequent") : "") ; - - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - parser_->current_state().token, - "ERR250 - Invalid " + invalid_branches + " for conditional statement", - exprtk_error_location)); - - return error_node(); - } - // Can the condition be immediately evaluated? if so optimise. - else if (details::is_constant_node(condition)) - { - // True branch - if (details::is_true(condition)) - { - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, alternative); - - return consequent; - } - // False branch - else - { - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, consequent); - - if (alternative) - return alternative; - else - return node_allocator_->allocate >(); - } - } - - expression_node_ptr result = error_node(); - std::string node_name = "Unknown!"; - - if ((0 != consequent) && (0 != alternative)) - { - result = node_allocator_->allocate(condition, consequent, alternative); - node_name = "conditional_node_t"; - } - else - { - result = node_allocator_->allocate(condition, consequent); - node_name = "cons_conditional_node_t"; - } - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - token_t(), - "ERR251 - Failed to synthesize node: " + node_name, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr conditional_string(expression_node_ptr condition, - expression_node_ptr consequent, - expression_node_ptr alternative) const - { - if ((0 == condition) || (0 == consequent)) - { - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, consequent ); - details::free_node(*node_allocator_, alternative); - - const std::string invalid_branches = - ((0 == condition ) ? std::string("condition ") : "") + - ((0 == consequent) ? std::string("consequent") : "") ; - - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - parser_->current_state().token, - "ERR252 - Invalid " + invalid_branches + " for string conditional statement", - exprtk_error_location)); - - return error_node(); - } - // Can the condition be immediately evaluated? if so optimise. - else if (details::is_constant_node(condition)) - { - // True branch - if (details::is_true(condition)) - { - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, alternative); - - return consequent; - } - // False branch - else - { - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, consequent); - - if (alternative) - return alternative; - else - return node_allocator_-> - allocate_c >(""); - } - } - else if ((0 != consequent) && (0 != alternative)) - { - expression_node_ptr result = - node_allocator_->allocate(condition, consequent, alternative); - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - token_t(), - "ERR253 - Failed to synthesize node: conditional_string_node_t", - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - } - - return error_node(); - } - #else - inline expression_node_ptr conditional_string(expression_node_ptr, - expression_node_ptr, - expression_node_ptr) const - { - return error_node(); - } - #endif - - inline expression_node_ptr conditional_vector(expression_node_ptr condition, - expression_node_ptr consequent, - expression_node_ptr alternative) const - { - if ((0 == condition) || (0 == consequent)) - { - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, consequent ); - details::free_node(*node_allocator_, alternative); - - const std::string invalid_branches = - ((0 == condition ) ? std::string("condition ") : "") + - ((0 == consequent) ? std::string("consequent") : "") ; - - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - parser_->current_state().token, - "ERR254 - Invalid " + invalid_branches + " for vector conditional statement", - exprtk_error_location)); - - return error_node(); - } - // Can the condition be immediately evaluated? if so optimise. - else if (details::is_constant_node(condition)) - { - // True branch - if (details::is_true(condition)) - { - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, alternative); - - return consequent; - } - // False branch - else - { - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, consequent); - - if (alternative) - return alternative; - else - return node_allocator_->allocate >(); - - } - } - else if ((0 != consequent) && (0 != alternative)) - { - return node_allocator_-> - allocate(condition, consequent, alternative); - } - else - return error_node(); - } - - inline loop_runtime_check_ptr get_loop_runtime_check(const loop_runtime_check::loop_types loop_type) const - { - if ( - parser_->loop_runtime_check_ && - (loop_type == (parser_->loop_runtime_check_->loop_set & loop_type)) - ) - { - return parser_->loop_runtime_check_; - } - - return loop_runtime_check_ptr(0); - } - - inline vector_access_runtime_check_ptr get_vector_access_runtime_check() const - { - return parser_->vector_access_runtime_check_; - } - - inline expression_node_ptr while_loop(expression_node_ptr& condition, - expression_node_ptr& branch, - const bool break_continue_present = false) const - { - if ( - !break_continue_present && - !parser_->state_.return_stmt_present && - details::is_constant_node(condition) - ) - { - expression_node_ptr result = error_node(); - if (details::is_true(condition)) - { - // Infinite loops are not allowed. - - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - parser_->current_state().token, - "ERR255 - Infinite loop condition without 'break' or 'return' not allowed in while-loops", - exprtk_error_location)); - - result = error_node(); - } - else - result = node_allocator_->allocate >(); - - details::free_node(*node_allocator_, condition); - details::free_node(*node_allocator_, branch ); - - return result; - } - else if (details::is_null_node(condition)) - { - details::free_node(*node_allocator_,condition); - - return branch; - } - - loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_while_loop); - - if (!break_continue_present) - { - if (rtc) - return node_allocator_->allocate - (condition, branch, rtc); - else - return node_allocator_->allocate - (condition, branch); - } - #ifndef exprtk_disable_break_continue - else - { - if (rtc) - return node_allocator_->allocate - (condition, branch, rtc); - else - return node_allocator_->allocate - (condition, branch); - } - #else - return error_node(); - #endif - } - - inline expression_node_ptr repeat_until_loop(expression_node_ptr& condition, - expression_node_ptr& branch, - const bool break_continue_present = false) const - { - if (!break_continue_present && details::is_constant_node(condition)) - { - if ( - details::is_true(condition) && - details::is_constant_node(branch) - ) - { - free_node(*node_allocator_,condition); - - return branch; - } - - details::free_node(*node_allocator_, condition); - details::free_node(*node_allocator_, branch ); - - return error_node(); - } - else if (details::is_null_node(condition)) - { - details::free_node(*node_allocator_,condition); - - return branch; - } - - loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop); - - if (!break_continue_present) - { - if (rtc) - return node_allocator_->allocate - (condition, branch, rtc); - else - return node_allocator_->allocate - (condition, branch); - } - #ifndef exprtk_disable_break_continue - else - { - if (rtc) - return node_allocator_->allocate - (condition, branch, rtc); - else - return node_allocator_->allocate - (condition, branch); - } - #else - return error_node(); - #endif - } - - inline expression_node_ptr for_loop(expression_node_ptr& initialiser, - expression_node_ptr& condition, - expression_node_ptr& incrementor, - expression_node_ptr& loop_body, - bool break_continue_present = false) const - { - if ( - !break_continue_present && - !parser_->state_.return_stmt_present && - details::is_constant_node(condition) - ) - { - expression_node_ptr result = error_node(); - - if (details::is_true(condition)) - { - // Infinite loops are not allowed. - - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - parser_->current_state().token, - "ERR256 - Infinite loop condition without 'break' or 'return' not allowed in for-loop", - exprtk_error_location)); - - result = error_node(); - } - else - result = node_allocator_->allocate >(); - - details::free_node(*node_allocator_, initialiser); - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, incrementor); - details::free_node(*node_allocator_, loop_body ); - - return result; - } - else if (details::is_null_node(condition) || (0 == condition)) - { - details::free_node(*node_allocator_, initialiser); - details::free_node(*node_allocator_, condition ); - details::free_node(*node_allocator_, incrementor); - - return loop_body; - } - - loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_for_loop); - - if (!break_continue_present) - { - if (rtc) - return node_allocator_->allocate - ( - initialiser, - condition, - incrementor, - loop_body, - rtc - ); - else - return node_allocator_->allocate - ( - initialiser, - condition, - incrementor, - loop_body - ); - } - #ifndef exprtk_disable_break_continue - else - { - if (rtc) - return node_allocator_->allocate - ( - initialiser, - condition, - incrementor, - loop_body, - rtc - ); - else - return node_allocator_->allocate - ( - initialiser, - condition, - incrementor, - loop_body - ); - } - #else - return error_node(); - #endif - } - - template class Sequence> - inline expression_node_ptr const_optimise_switch(Sequence& arg_list) - { - expression_node_ptr result = error_node(); - - for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) - { - expression_node_ptr condition = arg_list[(2 * i) ]; - expression_node_ptr consequent = arg_list[(2 * i) + 1]; - - if ((0 == result) && details::is_true(condition)) - { - result = consequent; - break; - } - } - - if (0 == result) - { - result = arg_list.back(); - } - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - expression_node_ptr current_expr = arg_list[i]; - - if (current_expr && (current_expr != result)) - { - free_node(*node_allocator_,current_expr); - } - } - - return result; - } - - template class Sequence> - inline expression_node_ptr const_optimise_mswitch(Sequence& arg_list) - { - expression_node_ptr result = error_node(); - - for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) - { - expression_node_ptr condition = arg_list[(2 * i) ]; - expression_node_ptr consequent = arg_list[(2 * i) + 1]; - - if (details::is_true(condition)) - { - result = consequent; - } - } - - if (0 == result) - { - const T zero = T(0); - result = node_allocator_->allocate(zero); - } - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - expression_node_ptr& current_expr = arg_list[i]; - - if (current_expr && (current_expr != result)) - { - details::free_node(*node_allocator_,current_expr); - } - } - - return result; - } - - struct switch_nodes - { - typedef std::vector > arg_list_t; - - #define case_stmt(N) \ - if (is_true(arg[(2 * N)].first)) { return arg[(2 * N) + 1].first->value(); } \ - - struct switch_impl_1 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) - - assert(arg.size() == ((2 * 1) + 1)); - - return arg.back().first->value(); - } - }; - - struct switch_impl_2 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - - assert(arg.size() == ((2 * 2) + 1)); - - return arg.back().first->value(); - } - }; - - struct switch_impl_3 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) - - assert(arg.size() == ((2 * 3) + 1)); - - return arg.back().first->value(); - } - }; - - struct switch_impl_4 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) case_stmt(3) - - assert(arg.size() == ((2 * 4) + 1)); - - return arg.back().first->value(); - } - }; - - struct switch_impl_5 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) case_stmt(3) - case_stmt(4) - - assert(arg.size() == ((2 * 5) + 1)); - - return arg.back().first->value(); - } - }; - - struct switch_impl_6 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) case_stmt(3) - case_stmt(4) case_stmt(5) - - assert(arg.size() == ((2 * 6) + 1)); - - return arg.back().first->value(); - } - }; - - struct switch_impl_7 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) case_stmt(3) - case_stmt(4) case_stmt(5) - case_stmt(6) - - assert(arg.size() == ((2 * 7) + 1)); - - return arg.back().first->value(); - } - }; - - #undef case_stmt - }; - - template class Sequence> - inline expression_node_ptr switch_statement(Sequence& arg_list, const bool default_statement_present) - { - if (arg_list.empty()) - return error_node(); - else if ( - !all_nodes_valid(arg_list) || - (!default_statement_present && (arg_list.size() < 2)) - ) - { - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - else if (is_constant_foldable(arg_list)) - return const_optimise_switch(arg_list); - - switch ((arg_list.size() - 1) / 2) - { - #define case_stmt(N) \ - case N : \ - return node_allocator_-> \ - allocate >(arg_list); \ - - case_stmt(1) - case_stmt(2) - case_stmt(3) - case_stmt(4) - case_stmt(5) - case_stmt(6) - case_stmt(7) - #undef case_stmt - - default : return node_allocator_->allocate >(arg_list); - } - } - - template class Sequence> - inline expression_node_ptr multi_switch_statement(Sequence& arg_list) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - else if (is_constant_foldable(arg_list)) - return const_optimise_mswitch(arg_list); - else - return node_allocator_->allocate >(arg_list); - } - - inline expression_node_ptr assert_call(expression_node_ptr& assert_condition, - expression_node_ptr& assert_message, - const assert_check::assert_context& context) - { - typedef details::assert_node alloc_type; - - expression_node_ptr result = node_allocator_->allocate_rrrr - (assert_condition, assert_message, parser_->assert_check_, context); - - if (result && result->valid()) - { - parser_->state_.activate_side_effect("assert_call()"); - return result; - } - - details::free_node(*node_allocator_, result ); - details::free_node(*node_allocator_, assert_condition); - details::free_node(*node_allocator_, assert_message ); - - return error_node(); - } - - #define unary_opr_switch_statements \ - case_stmt(details::e_abs , details::abs_op ) \ - case_stmt(details::e_acos , details::acos_op ) \ - case_stmt(details::e_acosh , details::acosh_op) \ - case_stmt(details::e_asin , details::asin_op ) \ - case_stmt(details::e_asinh , details::asinh_op) \ - case_stmt(details::e_atan , details::atan_op ) \ - case_stmt(details::e_atanh , details::atanh_op) \ - case_stmt(details::e_ceil , details::ceil_op ) \ - case_stmt(details::e_cos , details::cos_op ) \ - case_stmt(details::e_cosh , details::cosh_op ) \ - case_stmt(details::e_exp , details::exp_op ) \ - case_stmt(details::e_expm1 , details::expm1_op) \ - case_stmt(details::e_floor , details::floor_op) \ - case_stmt(details::e_log , details::log_op ) \ - case_stmt(details::e_log10 , details::log10_op) \ - case_stmt(details::e_log2 , details::log2_op ) \ - case_stmt(details::e_log1p , details::log1p_op) \ - case_stmt(details::e_neg , details::neg_op ) \ - case_stmt(details::e_pos , details::pos_op ) \ - case_stmt(details::e_round , details::round_op) \ - case_stmt(details::e_sin , details::sin_op ) \ - case_stmt(details::e_sinc , details::sinc_op ) \ - case_stmt(details::e_sinh , details::sinh_op ) \ - case_stmt(details::e_sqrt , details::sqrt_op ) \ - case_stmt(details::e_tan , details::tan_op ) \ - case_stmt(details::e_tanh , details::tanh_op ) \ - case_stmt(details::e_cot , details::cot_op ) \ - case_stmt(details::e_sec , details::sec_op ) \ - case_stmt(details::e_csc , details::csc_op ) \ - case_stmt(details::e_r2d , details::r2d_op ) \ - case_stmt(details::e_d2r , details::d2r_op ) \ - case_stmt(details::e_d2g , details::d2g_op ) \ - case_stmt(details::e_g2d , details::g2d_op ) \ - case_stmt(details::e_notl , details::notl_op ) \ - case_stmt(details::e_sgn , details::sgn_op ) \ - case_stmt(details::e_erf , details::erf_op ) \ - case_stmt(details::e_erfc , details::erfc_op ) \ - case_stmt(details::e_ncdf , details::ncdf_op ) \ - case_stmt(details::e_frac , details::frac_op ) \ - case_stmt(details::e_trunc , details::trunc_op) \ - - inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[1]) - { - T& v = static_cast*>(branch[0])->ref(); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate > >(v); \ - - unary_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr synthesize_uvec_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[1]) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate > > \ - (operation, branch[0]); \ - - unary_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[1]) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate > >(branch[0]); \ - - unary_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation, - expression_node_ptr (&branch)[3]) - { - expression_node_ptr temp_node = error_node(); - - switch (operation) - { - #define case_stmt(op) \ - case details::e_sf##op : temp_node = node_allocator_-> \ - allocate > > \ - (operation, branch); \ - break; \ - - case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) - case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) - case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) - case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) - case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) - case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) - case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) - case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) - case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) - case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) - case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) - case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) - #undef case_stmt - default : return error_node(); - } - - assert(temp_node); - - const T v = temp_node->value(); - - details::free_node(*node_allocator_,temp_node); - - return node_allocator_->allocate(v); - } - - inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) - { - typedef details::variable_node* variable_ptr; - - const Type& v0 = static_cast(branch[0])->ref(); - const Type& v1 = static_cast(branch[1])->ref(); - const Type& v2 = static_cast(branch[2])->ref(); - - switch (operation) - { - #define case_stmt(op) \ - case details::e_sf##op : return node_allocator_-> \ - allocate_rrr > > \ - (v0, v1, v2); \ - - case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) - case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) - case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) - case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) - case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) - case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) - case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) - case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) - case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) - case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) - case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) - case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) - #undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) - { - if (!all_nodes_valid(branch)) - return error_node(); - else if (is_constant_foldable(branch)) - return const_optimise_sf3(operation,branch); - else if (all_nodes_variables(branch)) - return varnode_optimise_sf3(operation,branch); - else - { - switch (operation) - { - #define case_stmt(op) \ - case details::e_sf##op : return node_allocator_-> \ - allocate > > \ - (operation, branch); \ - - case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) - case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) - case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) - case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) - case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) - case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) - case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) - case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) - case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) - case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) - case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) - case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) - #undef case_stmt - default : return error_node(); - } - } - } - - inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - expression_node_ptr temp_node = error_node(); - - switch (operation) - { - #define case_stmt(op) \ - case details::e_sf##op : temp_node = node_allocator_-> \ - allocate > > \ - (operation, branch); \ - break; \ - - case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) - case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) - case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) - case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) - case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) - case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) - case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) - case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) - case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) - case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) - case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) - case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) - case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) - #undef case_stmt - default : return error_node(); - } - - assert(temp_node); - - const T v = temp_node->value(); - - details::free_node(*node_allocator_,temp_node); - - return node_allocator_->allocate(v); - } - - inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - typedef details::variable_node* variable_ptr; - - const Type& v0 = static_cast(branch[0])->ref(); - const Type& v1 = static_cast(branch[1])->ref(); - const Type& v2 = static_cast(branch[2])->ref(); - const Type& v3 = static_cast(branch[3])->ref(); - - switch (operation) - { - #define case_stmt(op) \ - case details::e_sf##op : return node_allocator_-> \ - allocate_rrrr > > \ - (v0, v1, v2, v3); \ - - case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) - case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) - case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) - case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) - case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) - case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) - case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) - case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) - case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) - case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) - case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) - case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) - case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) - #undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - if (!all_nodes_valid(branch)) - return error_node(); - else if (is_constant_foldable(branch)) - return const_optimise_sf4(operation,branch); - else if (all_nodes_variables(branch)) - return varnode_optimise_sf4(operation,branch); - switch (operation) - { - #define case_stmt(op) \ - case details::e_sf##op : return node_allocator_-> \ - allocate > > \ - (operation, branch); \ - - case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) - case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) - case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) - case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) - case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) - case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) - case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) - case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) - case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) - case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) - case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) - case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) - case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) - #undef case_stmt - default : return error_node(); - } - } - - template class Sequence> - inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) - { - expression_node_ptr temp_node = error_node(); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : temp_node = node_allocator_-> \ - allocate > > \ - (arg_list); \ - break; \ - - case_stmt(details::e_sum , details::vararg_add_op ) - case_stmt(details::e_prod , details::vararg_mul_op ) - case_stmt(details::e_avg , details::vararg_avg_op ) - case_stmt(details::e_min , details::vararg_min_op ) - case_stmt(details::e_max , details::vararg_max_op ) - case_stmt(details::e_mand , details::vararg_mand_op ) - case_stmt(details::e_mor , details::vararg_mor_op ) - case_stmt(details::e_multi , details::vararg_multi_op) - #undef case_stmt - default : return error_node(); - } - - const T v = temp_node->value(); - - details::free_node(*node_allocator_,temp_node); - - return node_allocator_->allocate(v); - } - - inline bool special_one_parameter_vararg(const details::operator_type& operation) const - { - return ( - (details::e_sum == operation) || - (details::e_prod == operation) || - (details::e_avg == operation) || - (details::e_min == operation) || - (details::e_max == operation) - ); - } - - template class Sequence> - inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, - Sequence& arg_list) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate > >(arg_list); \ - - case_stmt(details::e_sum , details::vararg_add_op ) - case_stmt(details::e_prod , details::vararg_mul_op ) - case_stmt(details::e_avg , details::vararg_avg_op ) - case_stmt(details::e_min , details::vararg_min_op ) - case_stmt(details::e_max , details::vararg_max_op ) - case_stmt(details::e_mand , details::vararg_mand_op ) - case_stmt(details::e_mor , details::vararg_mor_op ) - case_stmt(details::e_multi , details::vararg_multi_op) - #undef case_stmt - default : return error_node(); - } - } - - template class Sequence> - inline expression_node_ptr vectorize_func(const details::operator_type& operation, - Sequence& arg_list) - { - if (1 == arg_list.size()) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate > >(arg_list[0]); \ - - case_stmt(details::e_sum , details::vec_add_op) - case_stmt(details::e_prod , details::vec_mul_op) - case_stmt(details::e_avg , details::vec_avg_op) - case_stmt(details::e_min , details::vec_min_op) - case_stmt(details::e_max , details::vec_max_op) - #undef case_stmt - default : return error_node(); - } - } - else - return error_node(); - } - - template class Sequence> - inline expression_node_ptr vararg_function(const details::operator_type& operation, - Sequence& arg_list) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - else if (is_constant_foldable(arg_list)) - return const_optimise_varargfunc(operation,arg_list); - else if ((1 == arg_list.size()) && details::is_ivector_node(arg_list[0])) - return vectorize_func(operation,arg_list); - else if ((1 == arg_list.size()) && special_one_parameter_vararg(operation)) - return arg_list[0]; - else if (all_nodes_variables(arg_list)) - return varnode_optimise_varargfunc(operation,arg_list); - - #ifndef exprtk_disable_string_capabilities - if (details::e_smulti == operation) - { - expression_node_ptr result = node_allocator_-> - allocate > >(arg_list); - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR257 - Failed to synthesize node: str_vararg_node", - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - } - else - #endif - { - expression_node_ptr result = error_node(); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - allocate > >(arg_list); \ - break; \ - - case_stmt(details::e_sum , details::vararg_add_op ) - case_stmt(details::e_prod , details::vararg_mul_op ) - case_stmt(details::e_avg , details::vararg_avg_op ) - case_stmt(details::e_min , details::vararg_min_op ) - case_stmt(details::e_max , details::vararg_max_op ) - case_stmt(details::e_mand , details::vararg_mand_op ) - case_stmt(details::e_mor , details::vararg_mor_op ) - case_stmt(details::e_multi , details::vararg_multi_op) - #undef case_stmt - default : return error_node(); - } - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR258 - Failed to synthesize node: vararg_node", - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - } - - return error_node(); - } - - template - inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N]) - { - typedef typename details::function_N_node function_N_node_t; - expression_node_ptr result = synthesize_expression(f,b); - - if (0 == result) - return error_node(); - else - { - // Can the function call be completely optimised? - if (details::is_constant_node(result)) - return result; - else if (!all_nodes_valid(b)) - { - details::free_node(*node_allocator_,result); - std::fill_n(b, N, reinterpret_cast(0)); - - return error_node(); - } - else if (N != f->param_count) - { - details::free_node(*node_allocator_,result); - std::fill_n(b, N, reinterpret_cast(0)); - - return error_node(); - } - - function_N_node_t* func_node_ptr = reinterpret_cast(result); - - if (!func_node_ptr->init_branches(b)) - { - details::free_node(*node_allocator_,result); - std::fill_n(b, N, reinterpret_cast(0)); - - return error_node(); - } - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR259 - Failed to synthesize node: function_N_node_t", - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - } - - inline expression_node_ptr function(ifunction_t* f) - { - typedef typename details::function_N_node function_N_node_t; - return node_allocator_->allocate(f); - } - - inline expression_node_ptr vararg_function_call(ivararg_function_t* vaf, - std::vector& arg_list) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - - typedef details::vararg_function_node alloc_type; - - expression_node_ptr result = node_allocator_->allocate(vaf,arg_list); - - if ( - !arg_list.empty() && - !vaf->has_side_effects() && - is_constant_foldable(arg_list) - ) - { - const Type v = result->value(); - details::free_node(*node_allocator_,result); - result = node_allocator_->allocate(v); - } - - parser_->state_.activate_side_effect("vararg_function_call()"); - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR260 - Failed to synthesize node: vararg_function_node", - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - - inline expression_node_ptr generic_function_call(igeneric_function_t* gf, - std::vector& arg_list, - const std::size_t& param_seq_index = std::numeric_limits::max()) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - return error_node(); - } - - typedef details::generic_function_node alloc_type1; - typedef details::multimode_genfunction_node alloc_type2; - - const std::size_t no_psi = std::numeric_limits::max(); - - expression_node_ptr result = error_node(); - std::string node_name = "Unknown"; - - if (no_psi == param_seq_index) - { - result = node_allocator_->allocate(arg_list,gf); - node_name = "generic_function_node"; - } - else - { - result = node_allocator_->allocate(gf, param_seq_index, arg_list); - node_name = "multimode_genfunction_node"; - } - - alloc_type1* genfunc_node_ptr = static_cast(result); - - assert(genfunc_node_ptr); - - if ( - !arg_list.empty() && - !gf->has_side_effects() && - parser_->state_.type_check_enabled && - is_constant_foldable(arg_list) - ) - { - genfunc_node_ptr->init_branches(); - - const Type v = result->value(); - - details::free_node(*node_allocator_,result); - - return node_allocator_->allocate(v); - } - else if (genfunc_node_ptr->init_branches()) - { - if (result && result->valid()) - { - parser_->state_.activate_side_effect("generic_function_call()"); - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR261 - Failed to synthesize node: " + node_name, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - else - { - details::free_node(*node_allocator_, result); - details::free_all_nodes(*node_allocator_, arg_list); - - return error_node(); - } - } - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr string_function_call(igeneric_function_t* gf, - std::vector& arg_list, - const std::size_t& param_seq_index = std::numeric_limits::max()) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - return error_node(); - } - - typedef details::string_function_node alloc_type1; - typedef details::multimode_strfunction_node alloc_type2; - - const std::size_t no_psi = std::numeric_limits::max(); - - expression_node_ptr result = error_node(); - std::string node_name = "Unknown"; - - if (no_psi == param_seq_index) - { - result = node_allocator_->allocate(gf,arg_list); - node_name = "string_function_node"; - } - else - { - result = node_allocator_->allocate(gf, param_seq_index, arg_list); - node_name = "multimode_strfunction_node"; - } - - alloc_type1* strfunc_node_ptr = static_cast(result); - - assert(strfunc_node_ptr); - - if ( - !arg_list.empty() && - !gf->has_side_effects() && - is_constant_foldable(arg_list) - ) - { - strfunc_node_ptr->init_branches(); - - const Type v = result->value(); - - details::free_node(*node_allocator_,result); - - return node_allocator_->allocate(v); - } - else if (strfunc_node_ptr->init_branches()) - { - if (result && result->valid()) - { - parser_->state_.activate_side_effect("string_function_call()"); - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR262 - Failed to synthesize node: " + node_name, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - else - { - details::free_node (*node_allocator_,result ); - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - } - #endif - - #ifndef exprtk_disable_return_statement - inline expression_node_ptr return_call(std::vector& arg_list) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - return error_node(); - } - - typedef details::return_node alloc_type; - - expression_node_ptr result = node_allocator_-> - allocate_rr(arg_list,parser_->results_ctx()); - - alloc_type* return_node_ptr = static_cast(result); - - assert(return_node_ptr); - - if (return_node_ptr->init_branches()) - { - if (result && result->valid()) - { - parser_->state_.activate_side_effect("return_call()"); - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR263 - Failed to synthesize node: return_node", - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - else - { - details::free_node (*node_allocator_, result ); - details::free_all_nodes(*node_allocator_, arg_list); - - return error_node(); - } - } - - inline expression_node_ptr return_envelope(expression_node_ptr body, - results_context_t* rc, - bool*& return_invoked) - { - typedef details::return_envelope_node alloc_type; - - expression_node_ptr result = node_allocator_-> - allocate_cr(body,(*rc)); - - return_invoked = static_cast(result)->retinvk_ptr(); - - return result; - } - #else - inline expression_node_ptr return_call(std::vector&) - { - return error_node(); - } - - inline expression_node_ptr return_envelope(expression_node_ptr, - results_context_t*, - bool*&) - { - return error_node(); - } - #endif - - inline expression_node_ptr vector_element(const std::string& symbol, - vector_holder_ptr vector_base, - expression_node_ptr vec_node, - expression_node_ptr index) - { - expression_node_ptr result = error_node(); - std::string node_name = "Unknown"; - - if (details::is_constant_node(index)) - { - const std::size_t vec_index = static_cast(details::numeric::to_int64(index->value())); - - details::free_node(*node_allocator_,index); - - if (vec_index >= vector_base->size()) - { - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - token_t(), - "ERR264 - Index of " + details::to_str(vec_index) + " out of range for " - "vector '" + symbol + "' of size " + details::to_str(vector_base->size()), - exprtk_error_location)); - - details::free_node(*node_allocator_,vec_node); - - return error_node(); - } - - if (vector_base->rebaseable()) - { - vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); - - result = (rtc) ? - node_allocator_->allocate(vec_node, vec_index, vector_base, rtc) : - node_allocator_->allocate(vec_node, vec_index, vector_base ) ; - - node_name = (rtc) ? - "rebasevector_elem_rtc_node_t" : - "rebasevector_elem_node_t" ; - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR265 - Failed to synthesize node: " + node_name + " for vector: " + symbol, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - else if (details::is_ivector_node(vec_node) && !details::is_vector_node(vec_node)) - { - vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); - - result = (rtc) ? - node_allocator_->allocate(vec_node, vec_index, vector_base, rtc) : - node_allocator_->allocate(vec_node, vec_index, vector_base ) ; - - node_name = (rtc) ? - "vector_elem_rtc_node_t" : - "vector_elem_node_t" ; - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR266 - Failed to synthesize node: " + node_name + " for vector: " + symbol, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - - const scope_element& se = parser_->sem_.get_element(symbol,vec_index); - - if (se.index == vec_index) - { - result = se.var_node; - details::free_node(*node_allocator_,vec_node); - } - else - { - scope_element nse; - nse.name = symbol; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_vecelem; - nse.index = vec_index; - nse.depth = parser_->state_.scope_depth; - nse.data = 0; - nse.var_node = node_allocator_->allocate((*(*vector_base)[vec_index])); - - if (!parser_->sem_.add_element(nse)) - { - parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); - - parser_->sem_.free_element(nse); - - result = error_node(); - } - - details::free_node(*node_allocator_,vec_node); - - exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n", nse.name.c_str())); - - parser_->state_.activate_side_effect("vector_element()"); - - result = nse.var_node; - node_name = "variable_node_t"; - } - } - else - { - vector_access_runtime_check_ptr rtc = get_vector_access_runtime_check(); - - if (vector_base->rebaseable()) - { - result = (rtc) ? - node_allocator_->allocate(vec_node, index, vector_base, rtc) : - node_allocator_->allocate(vec_node, index, vector_base ) ; - - node_name = (rtc) ? - "rebasevector_elem_rtc_node_t" : - "rebasevector_elem_node_t" ; - } - else - { - result = rtc ? - node_allocator_->allocate(vec_node, index, vector_base, rtc) : - node_allocator_->allocate(vec_node, index, vector_base ) ; - - node_name = (rtc) ? - "vector_elem_rtc_node_t" : - "vector_elem_node_t" ; - } - } - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR267 - Failed to synthesize node: " + node_name, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - - private: - - template - inline bool is_constant_foldable(NodePtr (&b)[N]) const - { - for (std::size_t i = 0; i < N; ++i) - { - if (0 == b[i]) - return false; - else if (!details::is_constant_node(b[i])) - return false; - } - - return true; - } - - template class Sequence> - inline bool is_constant_foldable(const Sequence& b) const - { - for (std::size_t i = 0; i < b.size(); ++i) - { - if (0 == b[i]) - return false; - else if (!details::is_constant_node(b[i])) - return false; - } - - return true; - } - - void lodge_assignment(symbol_type cst, expression_node_ptr node) - { - parser_->state_.activate_side_effect("lodge_assignment()"); - - if (!parser_->dec_.collect_assignments()) - return; - - std::string symbol_name; - - switch (cst) - { - case e_st_variable : symbol_name = parser_->symtab_store_ - .get_variable_name(node); - break; - - #ifndef exprtk_disable_string_capabilities - case e_st_string : symbol_name = parser_->symtab_store_ - .get_stringvar_name(node); - break; - #endif - - case e_st_vector : { - typedef details::vector_holder vector_holder_t; - - vector_holder_t& vh = static_cast(node)->vec_holder(); - - symbol_name = parser_->symtab_store_.get_vector_name(&vh); - } - break; - - case e_st_vecelem : { - typedef details::vector_holder vector_holder_t; - - vector_holder_t& vh = static_cast(node)->vec_holder(); - - symbol_name = parser_->symtab_store_.get_vector_name(&vh); - - cst = e_st_vector; - } - break; - - default : return; - } - - if (!symbol_name.empty()) - { - parser_->dec_.add_assignment(symbol_name,cst); - } - } - - const void* base_ptr(expression_node_ptr node) - { - if (node) - { - switch(node->type()) - { - case details::expression_node::e_variable: - return reinterpret_cast(&static_cast(node)->ref()); - - case details::expression_node::e_vecelem: - return reinterpret_cast(&static_cast(node)->ref()); - - case details::expression_node::e_veccelem: - return reinterpret_cast(&static_cast(node)->ref()); - - case details::expression_node::e_vecelemrtc: - return reinterpret_cast(&static_cast(node)->ref()); - - case details::expression_node::e_veccelemrtc: - return reinterpret_cast(&static_cast(node)->ref()); - - case details::expression_node::e_rbvecelem: - return reinterpret_cast(&static_cast(node)->ref()); - - case details::expression_node::e_rbvecelemrtc: - return reinterpret_cast(&static_cast(node)->ref()); - - case details::expression_node::e_rbveccelem: - return reinterpret_cast(&static_cast(node)->ref()); - - case details::expression_node::e_rbveccelemrtc: - return reinterpret_cast(&static_cast(node)->ref()); - - case details::expression_node::e_vector: - return reinterpret_cast(static_cast(node)->vec_holder().data()); - - #ifndef exprtk_disable_string_capabilities - case details::expression_node::e_stringvar: - return reinterpret_cast((static_cast(node)->base())); - - case details::expression_node::e_stringvarrng: - return reinterpret_cast((static_cast(node)->base())); - #endif - default : return reinterpret_cast(0); - } - } - - return reinterpret_cast(0); - } - - bool assign_immutable_symbol(expression_node_ptr node) - { - interval_t interval; - const void* baseptr_addr = base_ptr(node); - - exprtk_debug(("assign_immutable_symbol - base ptr addr: %p\n", baseptr_addr)); - - if (parser_->immutable_memory_map_.in_interval(baseptr_addr,interval)) - { - typename immutable_symtok_map_t::iterator itr = parser_->immutable_symtok_map_.find(interval); - - if (parser_->immutable_symtok_map_.end() != itr) - { - token_t& token = itr->second; - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - token, - "ERR268 - Symbol '" + token.value + "' cannot be assigned-to as it is immutable.", - exprtk_error_location)); - } - else - parser_->set_synthesis_error("Unable to assign symbol is immutable."); - - return true; - } - - return false; - } - - inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - if (assign_immutable_symbol(branch[0])) - { - return error_node(); - } - else if (details::is_variable_node(branch[0])) - { - lodge_assignment(e_st_variable,branch[0]); - return synthesize_expression(operation,branch); - } - else if (details::is_vector_elem_node(branch[0]) || details::is_vector_celem_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression(operation, branch); - } - else if (details::is_vector_elem_rtc_node(branch[0]) || details::is_vector_celem_rtc_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression(operation, branch); - } - else if (details::is_rebasevector_elem_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression(operation, branch); - } - else if (details::is_rebasevector_elem_rtc_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression(operation, branch); - } - else if (details::is_rebasevector_celem_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression(operation, branch); - } - #ifndef exprtk_disable_string_capabilities - else if (details::is_string_node(branch[0])) - { - lodge_assignment(e_st_string,branch[0]); - return synthesize_expression(operation, branch); - } - else if (details::is_string_range_node(branch[0])) - { - lodge_assignment(e_st_string,branch[0]); - return synthesize_expression(operation, branch); - } - #endif - else if (details::is_vector_node(branch[0])) - { - lodge_assignment(e_st_vector,branch[0]); - - if (details::is_ivector_node(branch[1])) - return synthesize_expression(operation, branch); - else - return synthesize_expression(operation, branch); - } - else if (details::is_literal_node(branch[0])) - { - parser_->set_error(parser_error::make_error( - parser_error::e_syntax, - parser_->current_state().token, - "ERR269 - Cannot assign value to const variable", - exprtk_error_location)); - - return error_node(); - } - else - { - parser_->set_error(parser_error::make_error( - parser_error::e_syntax, - parser_->current_state().token, - "ERR270 - Invalid branches for assignment operator '" + details::to_str(operation) + "'", - exprtk_error_location)); - - return error_node(); - } - } - - inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - if (assign_immutable_symbol(branch[0])) - { - return error_node(); - } - - expression_node_ptr result = error_node(); - std::string node_name = "Unknown"; - - if (details::is_variable_node(branch[0])) - { - lodge_assignment(e_st_variable,branch[0]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_op_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else if (details::is_vector_elem_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_vec_elem_op_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else if (details::is_vector_elem_rtc_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_vec_elem_op_rtc_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else if (details::is_vector_celem_rtc_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_vec_celem_op_rtc_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else if (details::is_rebasevector_elem_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_rebasevec_elem_op_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else if (details::is_rebasevector_celem_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_rebasevec_celem_op_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else if (details::is_rebasevector_elem_rtc_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_rebasevec_elem_op_rtc_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else if (details::is_rebasevector_celem_rtc_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_rebasevec_celem_op_rtc_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else if (details::is_vector_node(branch[0])) - { - lodge_assignment(e_st_vector,branch[0]); - - if (details::is_ivector_node(branch[1])) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_rebasevec_celem_op_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "assignment_vec_op_node"; \ - break; \ - - case_stmt(details::e_addass , details::add_op) - case_stmt(details::e_subass , details::sub_op) - case_stmt(details::e_mulass , details::mul_op) - case_stmt(details::e_divass , details::div_op) - case_stmt(details::e_modass , details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - } - #ifndef exprtk_disable_string_capabilities - else if ( - (details::e_addass == operation) && - details::is_string_node(branch[0]) - ) - { - typedef details::assignment_string_node addass_t; - - lodge_assignment(e_st_string,branch[0]); - - result = synthesize_expression(operation,branch); - node_name = "assignment_string_node"; - } - #endif - else - { - parser_->set_error(parser_error::make_error( - parser_error::e_syntax, - parser_->current_state().token, - "ERR271 - Invalid branches for assignment operator '" + details::to_str(operation) + "'", - exprtk_error_location)); - - return error_node(); - } - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR272 - Failed to synthesize node: " + node_name, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - - inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const bool is_b0_ivec = details::is_ivector_node(branch[0]); - const bool is_b1_ivec = details::is_ivector_node(branch[1]); - - #define batch_eqineq_logic_case \ - case_stmt(details::e_lt , details::lt_op ) \ - case_stmt(details::e_lte , details::lte_op ) \ - case_stmt(details::e_gt , details::gt_op ) \ - case_stmt(details::e_gte , details::gte_op ) \ - case_stmt(details::e_eq , details::eq_op ) \ - case_stmt(details::e_ne , details::ne_op ) \ - case_stmt(details::e_equal , details::equal_op) \ - case_stmt(details::e_and , details::and_op ) \ - case_stmt(details::e_nand , details::nand_op ) \ - case_stmt(details::e_or , details::or_op ) \ - case_stmt(details::e_nor , details::nor_op ) \ - case_stmt(details::e_xor , details::xor_op ) \ - case_stmt(details::e_xnor , details::xnor_op ) \ - - expression_node_ptr result = error_node(); - std::string node_name = "Unknown"; - - if (is_b0_ivec && is_b1_ivec) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "vec_binop_vecvec_node"; \ - break; \ - - batch_eqineq_logic_case - #undef case_stmt - default : return error_node(); - } - } - else if (is_b0_ivec && !is_b1_ivec) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "vec_binop_vecval_node"; \ - break; \ - - batch_eqineq_logic_case - #undef case_stmt - default : return error_node(); - } - } - else if (!is_b0_ivec && is_b1_ivec) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "vec_binop_valvec_node"; \ - break; \ - - batch_eqineq_logic_case - #undef case_stmt - default : return error_node(); - } - } - else - return error_node(); - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR273 - Failed to synthesize node: " + node_name, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - - #undef batch_eqineq_logic_case - } - - inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const bool is_b0_ivec = details::is_ivector_node(branch[0]); - const bool is_b1_ivec = details::is_ivector_node(branch[1]); - - #define vector_ops \ - case_stmt(details::e_add , details::add_op) \ - case_stmt(details::e_sub , details::sub_op) \ - case_stmt(details::e_mul , details::mul_op) \ - case_stmt(details::e_div , details::div_op) \ - case_stmt(details::e_mod , details::mod_op) \ - - expression_node_ptr result = error_node(); - std::string node_name = "Unknown"; - - if (is_b0_ivec && is_b1_ivec) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "vec_binop_vecvec_node"; \ - break; \ - - vector_ops - case_stmt(details::e_pow,details:: pow_op) - #undef case_stmt - default : return error_node(); - } - } - else if (is_b0_ivec && !is_b1_ivec) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "vec_binop_vecval_node(b0ivec,!b1ivec)"; \ - break; \ - - vector_ops - case_stmt(details::e_pow,details:: pow_op) - #undef case_stmt - default : return error_node(); - } - } - else if (!is_b0_ivec && is_b1_ivec) - { - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : result = node_allocator_-> \ - template allocate_rrr > > \ - (operation, branch[0], branch[1]); \ - node_name = "vec_binop_vecval_node(!b0ivec,b1ivec)"; \ - break; \ - - vector_ops - #undef case_stmt - default : return error_node(); - } - } - else - return error_node(); - - if (result && result->valid()) - { - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR274 - Failed to synthesize node: " + node_name, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - - #undef vector_ops - } - - inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2]) - { - const bool v0_is_ivar = details::is_ivariable_node(branch[0]); - const bool v1_is_ivar = details::is_ivariable_node(branch[1]); - - const bool v0_is_ivec = details::is_ivector_node (branch[0]); - const bool v1_is_ivec = details::is_ivector_node (branch[1]); - - #ifndef exprtk_disable_string_capabilities - const bool v0_is_str = details::is_generally_string_node(branch[0]); - const bool v1_is_str = details::is_generally_string_node(branch[1]); - #endif - - expression_node_ptr result = error_node(); - std::string node_name = "Unknown"; - - if (v0_is_ivar && v1_is_ivar) - { - typedef details::variable_node* variable_node_ptr; - - variable_node_ptr v0 = variable_node_ptr(0); - variable_node_ptr v1 = variable_node_ptr(0); - - if ( - (0 != (v0 = dynamic_cast(branch[0]))) && - (0 != (v1 = dynamic_cast(branch[1]))) - ) - { - result = node_allocator_->allocate >(v0,v1); - node_name = "swap_node"; - } - else - { - result = node_allocator_->allocate >(branch[0],branch[1]); - node_name = "swap_generic_node"; - } - } - else if (v0_is_ivec && v1_is_ivec) - { - result = node_allocator_->allocate >(branch[0],branch[1]); - node_name = "swap_vecvec_node"; - } - #ifndef exprtk_disable_string_capabilities - else if (v0_is_str && v1_is_str) - { - if (is_string_node(branch[0]) && is_string_node(branch[1])) - { - result = node_allocator_->allocate > - (branch[0], branch[1]); - node_name = "swap_string_node"; - } - else - { - result = node_allocator_->allocate > - (branch[0], branch[1]); - node_name = "swap_genstrings_node"; - } - } - #endif - else - { - parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); - return error_node(); - } - - if (result && result->valid()) - { - parser_->state_.activate_side_effect("synthesize_swap_expression()"); - return result; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_synthesis, - token_t(), - "ERR275 - Failed to synthesize node: " + node_name, - exprtk_error_location)); - - details::free_node(*node_allocator_, result); - return error_node(); - } - - #ifndef exprtk_disable_sc_andor - inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - expression_node_ptr result = error_node(); - - if (details::is_constant_node(branch[0])) - { - if ( - (details::e_scand == operation) && - std::equal_to()(T(0),branch[0]->value()) - ) - result = node_allocator_->allocate_c(T(0)); - else if ( - (details::e_scor == operation) && - std::not_equal_to()(T(0),branch[0]->value()) - ) - result = node_allocator_->allocate_c(T(1)); - } - - if (details::is_constant_node(branch[1]) && (0 == result)) - { - if ( - (details::e_scand == operation) && - std::equal_to()(T(0),branch[1]->value()) - ) - result = node_allocator_->allocate_c(T(0)); - else if ( - (details::e_scor == operation) && - std::not_equal_to()(T(0),branch[1]->value()) - ) - result = node_allocator_->allocate_c(T(1)); - } - - if (result) - { - details::free_node(*node_allocator_, branch[0]); - details::free_node(*node_allocator_, branch[1]); - - return result; - } - else if (details::e_scand == operation) - { - return synthesize_expression(operation, branch); - } - else if (details::e_scor == operation) - { - return synthesize_expression(operation, branch); - } - else - return error_node(); - } - #else - inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type&, expression_node_ptr (&)[2]) - { - return error_node(); - } - #endif - - #define basic_opr_switch_statements \ - case_stmt(details::e_add , details::add_op) \ - case_stmt(details::e_sub , details::sub_op) \ - case_stmt(details::e_mul , details::mul_op) \ - case_stmt(details::e_div , details::div_op) \ - case_stmt(details::e_mod , details::mod_op) \ - case_stmt(details::e_pow , details::pow_op) \ - - #define extended_opr_switch_statements \ - case_stmt(details::e_lt , details::lt_op ) \ - case_stmt(details::e_lte , details::lte_op ) \ - case_stmt(details::e_gt , details::gt_op ) \ - case_stmt(details::e_gte , details::gte_op ) \ - case_stmt(details::e_eq , details::eq_op ) \ - case_stmt(details::e_ne , details::ne_op ) \ - case_stmt(details::e_and , details::and_op ) \ - case_stmt(details::e_nand , details::nand_op) \ - case_stmt(details::e_or , details::or_op ) \ - case_stmt(details::e_nor , details::nor_op ) \ - case_stmt(details::e_xor , details::xor_op ) \ - case_stmt(details::e_xnor , details::xnor_op) \ - - #ifndef exprtk_disable_cardinal_pow_optimisation - template class IPowNode> - inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) - { - switch (p) - { - #define case_stmt(cp) \ - case cp : return node_allocator_-> \ - allocate > >(v); \ - - case_stmt( 1) case_stmt( 2) case_stmt( 3) case_stmt( 4) - case_stmt( 5) case_stmt( 6) case_stmt( 7) case_stmt( 8) - case_stmt( 9) case_stmt(10) case_stmt(11) case_stmt(12) - case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) - case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) - case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) - case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) - case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) - case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) - case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) - case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) - case_stmt(45) case_stmt(46) case_stmt(47) case_stmt(48) - case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) - case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) - case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) - #undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c) - { - const bool not_recipricol = (c >= T(0)); - const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); - - if (0 == p) - return node_allocator_->allocate_c(T(1)); - else if (std::equal_to()(T(2),c)) - { - return node_allocator_-> - template allocate_rr > >(v,v); - } - else - { - if (not_recipricol) - return cardinal_pow_optimisation_impl(v,p); - else - return cardinal_pow_optimisation_impl(v,p); - } - } - - inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) const - { - return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); - } - - inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr (&branch)[2]) - { - const Type c = static_cast*>(branch[1])->value(); - const bool not_recipricol = (c >= T(0)); - const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); - - node_allocator_->free(branch[1]); - - if (0 == p) - { - details::free_all_nodes(*node_allocator_, branch); - - return node_allocator_->allocate_c(T(1)); - } - else if (not_recipricol) - return cardinal_pow_optimisation_impl(branch[0],p); - else - return cardinal_pow_optimisation_impl(branch[0],p); - } - #else - inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) - { - return error_node(); - } - - inline bool cardinal_pow_optimisable(const details::operator_type&, const T&) - { - return false; - } - - inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr(&)[2]) - { - return error_node(); - } - #endif - - struct synthesize_binary_ext_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const bool left_neg = is_neg_unary_node(branch[0]); - const bool right_neg = is_neg_unary_node(branch[1]); - - if (left_neg && right_neg) - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if ( - !expr_gen.parser_->simplify_unary_negation_branch(branch[0]) || - !expr_gen.parser_->simplify_unary_negation_branch(branch[1]) - ) - { - details::free_all_nodes(*expr_gen.node_allocator_,branch); - - return error_node(); - } - } - - switch (operation) - { - // -f(x + 1) + -g(y + 1) --> -(f(x + 1) + g(y + 1)) - case details::e_add : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0],branch[1])); - - // -f(x + 1) - -g(y + 1) --> g(y + 1) - f(x + 1) - case details::e_sub : return expr_gen.node_allocator_-> - template allocate > > - (branch[1],branch[0]); - - default : break; - } - } - else if (left_neg && !right_neg) - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if (!expr_gen.parser_->simplify_unary_negation_branch(branch[0])) - { - details::free_all_nodes(*expr_gen.node_allocator_,branch); - - return error_node(); - } - - switch (operation) - { - // -f(x + 1) + g(y + 1) --> g(y + 1) - f(x + 1) - case details::e_add : return expr_gen.node_allocator_-> - template allocate > > - (branch[1], branch[0]); - - // -f(x + 1) - g(y + 1) --> -(f(x + 1) + g(y + 1)) - case details::e_sub : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0], branch[1])); - - // -f(x + 1) * g(y + 1) --> -(f(x + 1) * g(y + 1)) - case details::e_mul : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0], branch[1])); - - // -f(x + 1) / g(y + 1) --> -(f(x + 1) / g(y + 1)) - case details::e_div : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0], branch[1])); - - default : return error_node(); - } - } - } - else if (!left_neg && right_neg) - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if (!expr_gen.parser_->simplify_unary_negation_branch(branch[1])) - { - details::free_all_nodes(*expr_gen.node_allocator_,branch); - - return error_node(); - } - - switch (operation) - { - // f(x + 1) + -g(y + 1) --> f(x + 1) - g(y + 1) - case details::e_add : return expr_gen.node_allocator_-> - template allocate > > - (branch[0], branch[1]); - - // f(x + 1) - - g(y + 1) --> f(x + 1) + g(y + 1) - case details::e_sub : return expr_gen.node_allocator_-> - template allocate > > - (branch[0], branch[1]); - - // f(x + 1) * -g(y + 1) --> -(f(x + 1) * g(y + 1)) - case details::e_mul : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0], branch[1])); - - // f(x + 1) / -g(y + 1) --> -(f(x + 1) / g(y + 1)) - case details::e_div : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0], branch[1])); - - default : return error_node(); - } - } - } - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return expr_gen.node_allocator_-> \ - template allocate > > \ - (branch[0], branch[1]); \ - - basic_opr_switch_statements - extended_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_vob_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type& v = static_cast*>(branch[0])->ref(); - - #ifndef exprtk_disable_enhanced_features - if (details::is_sf3ext_node(branch[1])) - { - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile_right - (expr_gen, v, operation, branch[1], result); - - if (synthesis_result) - { - details::free_node(*expr_gen.node_allocator_,branch[1]); - return result; - } - } - #endif - - if ( - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if (details::is_uv_node(branch[1])) - { - typedef details::uv_base_node* uvbn_ptr_t; - - details::operator_type o = static_cast(branch[1])->operation(); - - if (details::e_neg == o) - { - const Type& v1 = static_cast(branch[1])->v(); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - - switch (operation) - { - case details::e_mul : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v,v1)); - - case details::e_div : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v,v1)); - - default : break; - } - } - } - } - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return expr_gen.node_allocator_-> \ - template allocate_rc > > \ - (v, branch[1]); \ - - basic_opr_switch_statements - extended_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_bov_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type& v = static_cast*>(branch[1])->ref(); - - #ifndef exprtk_disable_enhanced_features - if (details::is_sf3ext_node(branch[0])) - { - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile_left - (expr_gen, v, operation, branch[0], result); - - if (synthesis_result) - { - details::free_node(*expr_gen.node_allocator_, branch[0]); - - return result; - } - } - #endif - - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if (details::is_uv_node(branch[0])) - { - typedef details::uv_base_node* uvbn_ptr_t; - - details::operator_type o = static_cast(branch[0])->operation(); - - if (details::e_neg == o) - { - const Type& v0 = static_cast(branch[0])->v(); - - details::free_node(*expr_gen.node_allocator_,branch[0]); - - switch (operation) - { - case details::e_add : return expr_gen.node_allocator_-> - template allocate_rr > >(v,v0); - - case details::e_sub : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v0,v)); - - case details::e_mul : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v0,v)); - - case details::e_div : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v0,v)); - default : break; - } - } - } - } - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return expr_gen.node_allocator_-> \ - template allocate_cr > > \ - (branch[0], v); \ - - basic_opr_switch_statements - extended_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_cob_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type c = static_cast*>(branch[0])->value(); - - details::free_node(*expr_gen.node_allocator_,branch[0]); - - if (std::equal_to()(T(0),c) && (details::e_mul == operation)) - { - details::free_node(*expr_gen.node_allocator_,branch[1]); - - return expr_gen(T(0)); - } - else if (std::equal_to()(T(0),c) && (details::e_div == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[1]); - - return expr_gen(T(0)); - } - else if (std::equal_to()(T(0),c) && (details::e_add == operation)) - return branch[1]; - else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) - return branch[1]; - - if (details::is_cob_node(branch[1])) - { - // Simplify expressions of the form: - // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) - // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x - if ( - (details::e_mul == operation) || - (details::e_add == operation) - ) - { - details::cob_base_node* cobnode = static_cast*>(branch[1]); - - if (operation == cobnode->operation()) - { - switch (operation) - { - case details::e_add : cobnode->set_c(c + cobnode->c()); break; - case details::e_mul : cobnode->set_c(c * cobnode->c()); break; - default : return error_node(); - } - - return cobnode; - } - } - - if (operation == details::e_mul) - { - details::cob_base_node* cobnode = static_cast*>(branch[1]); - details::operator_type cob_opr = cobnode->operation(); - - if ( - (details::e_div == cob_opr) || - (details::e_mul == cob_opr) - ) - { - switch (cob_opr) - { - case details::e_div : cobnode->set_c(c * cobnode->c()); break; - case details::e_mul : cobnode->set_c(cobnode->c() / c); break; - default : return error_node(); - } - - return cobnode; - } - } - else if (operation == details::e_div) - { - details::cob_base_node* cobnode = static_cast*>(branch[1]); - details::operator_type cob_opr = cobnode->operation(); - - if ( - (details::e_div == cob_opr) || - (details::e_mul == cob_opr) - ) - { - details::expression_node* new_cobnode = error_node(); - - switch (cob_opr) - { - case details::e_div : new_cobnode = expr_gen.node_allocator_-> - template allocate_tt > > - (c / cobnode->c(), cobnode->move_branch(0)); - break; - - case details::e_mul : new_cobnode = expr_gen.node_allocator_-> - template allocate_tt > > - (c / cobnode->c(), cobnode->move_branch(0)); - break; - - default : return error_node(); - } - - details::free_node(*expr_gen.node_allocator_,branch[1]); - - return new_cobnode; - } - } - } - #ifndef exprtk_disable_enhanced_features - else if (details::is_sf3ext_node(branch[1])) - { - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile_right - (expr_gen, c, operation, branch[1], result); - - if (synthesis_result) - { - details::free_node(*expr_gen.node_allocator_,branch[1]); - - return result; - } - } - #endif - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return expr_gen.node_allocator_-> \ - template allocate_tt > > \ - (c, branch[1]); \ - - basic_opr_switch_statements - extended_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_boc_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type c = static_cast*>(branch[1])->value(); - - details::free_node(*(expr_gen.node_allocator_), branch[1]); - - if (std::equal_to()(T(0),c) && (details::e_mul == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[0]); - - return expr_gen(T(0)); - } - else if (std::equal_to()(T(0),c) && (details::e_div == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[0]); - - return expr_gen(std::numeric_limits::quiet_NaN()); - } - else if (std::equal_to()(T(0),c) && (details::e_add == operation)) - return branch[0]; - else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) - return branch[0]; - - if (details::is_boc_node(branch[0])) - { - // Simplify expressions of the form: - // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) --> (x + 9) * 40320 - // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) --> x + 45 - if ( - (details::e_mul == operation) || - (details::e_add == operation) - ) - { - details::boc_base_node* bocnode = static_cast*>(branch[0]); - - if (operation == bocnode->operation()) - { - switch (operation) - { - case details::e_add : bocnode->set_c(c + bocnode->c()); break; - case details::e_mul : bocnode->set_c(c * bocnode->c()); break; - default : return error_node(); - } - - return bocnode; - } - } - else if (operation == details::e_div) - { - details::boc_base_node* bocnode = static_cast*>(branch[0]); - details::operator_type boc_opr = bocnode->operation(); - - if ( - (details::e_div == boc_opr) || - (details::e_mul == boc_opr) - ) - { - switch (boc_opr) - { - case details::e_div : bocnode->set_c(c * bocnode->c()); break; - case details::e_mul : bocnode->set_c(bocnode->c() / c); break; - default : return error_node(); - } - - return bocnode; - } - } - else if (operation == details::e_pow) - { - // (v ^ c0) ^ c1 --> v ^(c0 * c1) - details::boc_base_node* bocnode = static_cast*>(branch[0]); - details::operator_type boc_opr = bocnode->operation(); - - if (details::e_pow == boc_opr) - { - bocnode->set_c(bocnode->c() * c); - - return bocnode; - } - } - } - - #ifndef exprtk_disable_enhanced_features - if (details::is_sf3ext_node(branch[0])) - { - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile_left - (expr_gen, c, operation, branch[0], result); - - if (synthesis_result) - { - free_node(*expr_gen.node_allocator_, branch[0]); - - return result; - } - } - #endif - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return expr_gen.node_allocator_-> \ - template allocate_cr > > \ - (branch[0], c); \ - - basic_opr_switch_statements - extended_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_cocob_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - expression_node_ptr result = error_node(); - - // (cob) o c --> cob - if (details::is_cob_node(branch[0])) - { - details::cob_base_node* cobnode = static_cast*>(branch[0]); - - const Type c = static_cast*>(branch[1])->value(); - - if (std::equal_to()(T(0),c) && (details::e_mul == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[0]); - details::free_node(*expr_gen.node_allocator_, branch[1]); - - return expr_gen(T(0)); - } - else if (std::equal_to()(T(0),c) && (details::e_div == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[0]); - details::free_node(*expr_gen.node_allocator_, branch[1]); - - return expr_gen(T(std::numeric_limits::quiet_NaN())); - } - else if (std::equal_to()(T(0),c) && (details::e_add == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[1]); - - return branch[0]; - } - else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[1]); - - return branch[0]; - } - else if (std::equal_to()(T(1),c) && (details::e_div == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[1]); - - return branch[0]; - } - - const bool op_addsub = (details::e_add == cobnode->operation()) || - (details::e_sub == cobnode->operation()) ; - - if (op_addsub) - { - switch (operation) - { - case details::e_add : cobnode->set_c(cobnode->c() + c); break; - case details::e_sub : cobnode->set_c(cobnode->c() - c); break; - default : return error_node(); - } - - result = cobnode; - } - else if (details::e_mul == cobnode->operation()) - { - switch (operation) - { - case details::e_mul : cobnode->set_c(cobnode->c() * c); break; - case details::e_div : cobnode->set_c(cobnode->c() / c); break; - default : return error_node(); - } - - result = cobnode; - } - else if (details::e_div == cobnode->operation()) - { - if (details::e_mul == operation) - { - cobnode->set_c(cobnode->c() * c); - result = cobnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (cobnode->c() / c, cobnode->move_branch(0)); - - details::free_node(*expr_gen.node_allocator_, branch[0]); - } - } - - if (result) - { - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - } - - // c o (cob) --> cob - else if (details::is_cob_node(branch[1])) - { - details::cob_base_node* cobnode = static_cast*>(branch[1]); - - const Type c = static_cast*>(branch[0])->value(); - - if (std::equal_to()(T(0),c) && (details::e_mul == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[0]); - details::free_node(*expr_gen.node_allocator_, branch[1]); - - return expr_gen(T(0)); - } - else if (std::equal_to()(T(0),c) && (details::e_div == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[0]); - details::free_node(*expr_gen.node_allocator_, branch[1]); - - return expr_gen(T(0)); - } - else if (std::equal_to()(T(0),c) && (details::e_add == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[0]); - - return branch[1]; - } - else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) - { - details::free_node(*expr_gen.node_allocator_, branch[0]); - - return branch[1]; - } - - if (details::e_add == cobnode->operation()) - { - if (details::e_add == operation) - { - cobnode->set_c(c + cobnode->c()); - result = cobnode; - } - else if (details::e_sub == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c - cobnode->c(), cobnode->move_branch(0)); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_sub == cobnode->operation()) - { - if (details::e_add == operation) - { - cobnode->set_c(c + cobnode->c()); - result = cobnode; - } - else if (details::e_sub == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c - cobnode->c(), cobnode->move_branch(0)); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_mul == cobnode->operation()) - { - if (details::e_mul == operation) - { - cobnode->set_c(c * cobnode->c()); - result = cobnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c / cobnode->c(), cobnode->move_branch(0)); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_div == cobnode->operation()) - { - if (details::e_mul == operation) - { - cobnode->set_c(c * cobnode->c()); - result = cobnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c / cobnode->c(), cobnode->move_branch(0)); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - } - - if (result) - { - details::free_node(*expr_gen.node_allocator_,branch[0]); - } - } - - return result; - } - }; - - struct synthesize_coboc_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - expression_node_ptr result = error_node(); - - // (boc) o c --> boc - if (details::is_boc_node(branch[0])) - { - details::boc_base_node* bocnode = static_cast*>(branch[0]); - - const Type c = static_cast*>(branch[1])->value(); - - if (details::e_add == bocnode->operation()) - { - switch (operation) - { - case details::e_add : bocnode->set_c(bocnode->c() + c); break; - case details::e_sub : bocnode->set_c(bocnode->c() - c); break; - default : return error_node(); - } - - result = bocnode; - } - else if (details::e_mul == bocnode->operation()) - { - switch (operation) - { - case details::e_mul : bocnode->set_c(bocnode->c() * c); break; - case details::e_div : bocnode->set_c(bocnode->c() / c); break; - default : return error_node(); - } - - result = bocnode; - } - else if (details::e_sub == bocnode->operation()) - { - if (details::e_add == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (bocnode->move_branch(0), c - bocnode->c()); - - details::free_node(*expr_gen.node_allocator_,branch[0]); - } - else if (details::e_sub == operation) - { - bocnode->set_c(bocnode->c() + c); - result = bocnode; - } - } - else if (details::e_div == bocnode->operation()) - { - switch (operation) - { - case details::e_div : bocnode->set_c(bocnode->c() * c); break; - case details::e_mul : bocnode->set_c(bocnode->c() / c); break; - default : return error_node(); - } - - result = bocnode; - } - - if (result) - { - details::free_node(*expr_gen.node_allocator_, branch[1]); - } - } - - // c o (boc) --> boc - else if (details::is_boc_node(branch[1])) - { - details::boc_base_node* bocnode = static_cast*>(branch[1]); - - const Type c = static_cast*>(branch[0])->value(); - - if (details::e_add == bocnode->operation()) - { - if (details::e_add == operation) - { - bocnode->set_c(c + bocnode->c()); - result = bocnode; - } - else if (details::e_sub == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c - bocnode->c(), bocnode->move_branch(0)); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_sub == bocnode->operation()) - { - if (details::e_add == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (bocnode->move_branch(0), c - bocnode->c()); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - else if (details::e_sub == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c + bocnode->c(), bocnode->move_branch(0)); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_mul == bocnode->operation()) - { - if (details::e_mul == operation) - { - bocnode->set_c(c * bocnode->c()); - result = bocnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c / bocnode->c(), bocnode->move_branch(0)); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_div == bocnode->operation()) - { - if (details::e_mul == operation) - { - bocnode->set_c(bocnode->c() / c); - result = bocnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c * bocnode->c(), bocnode->move_branch(0)); - - details::free_node(*expr_gen.node_allocator_,branch[1]); - } - } - - if (result) - { - details::free_node(*expr_gen.node_allocator_,branch[0]); - } - } - - return result; - } - }; - - #ifndef exprtk_disable_enhanced_features - inline bool synthesize_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2], - expression_node_ptr& result) - { - result = error_node(); - - if (!operation_optimisable(operation)) - return false; - - const std::string node_id = branch_to_id(branch); - - const typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id); - - if (synthesize_map_.end() != itr) - { - result = itr->second((*this), operation, branch); - - return true; - } - else - return false; - } - - struct synthesize_vov_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type& v1 = static_cast*>(branch[0])->ref(); - const Type& v2 = static_cast*>(branch[1])->ref(); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return expr_gen.node_allocator_-> \ - template allocate_rr > > \ - (v1, v2); \ - - basic_opr_switch_statements - extended_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_cov_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type c = static_cast*> (branch[0])->value(); - const Type& v = static_cast*>(branch[1])->ref (); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - if (std::equal_to()(T(0),c) && (details::e_mul == operation)) - return expr_gen(T(0)); - else if (std::equal_to()(T(0),c) && (details::e_div == operation)) - return expr_gen(T(0)); - else if (std::equal_to()(T(0),c) && (details::e_add == operation)) - return static_cast*>(branch[1]); - else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) - return static_cast*>(branch[1]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return expr_gen.node_allocator_-> \ - template allocate_cr > > \ - (c, v); \ - - basic_opr_switch_statements - extended_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_voc_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type& v = static_cast*>(branch[0])->ref (); - const Type c = static_cast*> (branch[1])->value(); - - details::free_node(*(expr_gen.node_allocator_), branch[1]); - - if (expr_gen.cardinal_pow_optimisable(operation,c)) - { - if (std::equal_to()(T(1),c)) - return branch[0]; - else - return expr_gen.cardinal_pow_optimisation(v,c); - } - else if (std::equal_to()(T(0),c) && (details::e_mul == operation)) - return expr_gen(T(0)); - else if (std::equal_to()(T(0),c) && (details::e_div == operation)) - return expr_gen(std::numeric_limits::quiet_NaN()); - else if (std::equal_to()(T(0),c) && (details::e_add == operation)) - return static_cast*>(branch[0]); - else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) - return static_cast*>(branch[0]); - else if (std::equal_to()(T(1),c) && (details::e_div == operation)) - return static_cast*>(branch[0]); - - switch (operation) - { - #define case_stmt(op0, op1) \ - case op0 : return expr_gen.node_allocator_-> \ - template allocate_rc > > \ - (v, c); \ - - basic_opr_switch_statements - extended_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_sf3ext_expression - { - template - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& sf3opr, - T0 t0, T1 t1, T2 t2) - { - switch (sf3opr) - { - #define case_stmt(op) \ - case details::e_sf##op : return details::T0oT1oT2_sf3ext >:: \ - allocate(*(expr_gen.node_allocator_), t0, t1, t2); \ - - case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) - case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) - case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) - case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) - case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) - case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) - case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) - case_stmt(28) case_stmt(29) case_stmt(30) - #undef case_stmt - default : return error_node(); - } - } - - template - static inline bool compile(expression_generator& expr_gen, const std::string& id, - T0 t0, T1 t1, T2 t2, - expression_node_ptr& result) - { - details::operator_type sf3opr; - - if (!expr_gen.sf3_optimisable(id,sf3opr)) - return false; - else - result = synthesize_sf3ext_expression::template process - (expr_gen, sf3opr, t0, t1, t2); - - return true; - } - }; - - struct synthesize_sf4ext_expression - { - template - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& sf4opr, - T0 t0, T1 t1, T2 t2, T3 t3) - { - switch (sf4opr) - { - #define case_stmt0(op) \ - case details::e_sf##op : return details::T0oT1oT2oT3_sf4ext >:: \ - allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ - - #define case_stmt1(op) \ - case details::e_sf4ext##op : return details::T0oT1oT2oT3_sf4ext >:: \ - allocate(*(expr_gen.node_allocator_), t0, t1, t2, t3); \ - - case_stmt0(48) case_stmt0(49) case_stmt0(50) case_stmt0(51) - case_stmt0(52) case_stmt0(53) case_stmt0(54) case_stmt0(55) - case_stmt0(56) case_stmt0(57) case_stmt0(58) case_stmt0(59) - case_stmt0(60) case_stmt0(61) case_stmt0(62) case_stmt0(63) - case_stmt0(64) case_stmt0(65) case_stmt0(66) case_stmt0(67) - case_stmt0(68) case_stmt0(69) case_stmt0(70) case_stmt0(71) - case_stmt0(72) case_stmt0(73) case_stmt0(74) case_stmt0(75) - case_stmt0(76) case_stmt0(77) case_stmt0(78) case_stmt0(79) - case_stmt0(80) case_stmt0(81) case_stmt0(82) case_stmt0(83) - - case_stmt1(00) case_stmt1(01) case_stmt1(02) case_stmt1(03) - case_stmt1(04) case_stmt1(05) case_stmt1(06) case_stmt1(07) - case_stmt1(08) case_stmt1(09) case_stmt1(10) case_stmt1(11) - case_stmt1(12) case_stmt1(13) case_stmt1(14) case_stmt1(15) - case_stmt1(16) case_stmt1(17) case_stmt1(18) case_stmt1(19) - case_stmt1(20) case_stmt1(21) case_stmt1(22) case_stmt1(23) - case_stmt1(24) case_stmt1(25) case_stmt1(26) case_stmt1(27) - case_stmt1(28) case_stmt1(29) case_stmt1(30) case_stmt1(31) - case_stmt1(32) case_stmt1(33) case_stmt1(34) case_stmt1(35) - case_stmt1(36) case_stmt1(37) case_stmt1(38) case_stmt1(39) - case_stmt1(40) case_stmt1(41) case_stmt1(42) case_stmt1(43) - case_stmt1(44) case_stmt1(45) case_stmt1(46) case_stmt1(47) - case_stmt1(48) case_stmt1(49) case_stmt1(50) case_stmt1(51) - case_stmt1(52) case_stmt1(53) case_stmt1(54) case_stmt1(55) - case_stmt1(56) case_stmt1(57) case_stmt1(58) case_stmt1(59) - case_stmt1(60) case_stmt1(61) - - #undef case_stmt0 - #undef case_stmt1 - default : return error_node(); - } - } - - template - static inline bool compile(expression_generator& expr_gen, const std::string& id, - T0 t0, T1 t1, T2 t2, T3 t3, - expression_node_ptr& result) - { - details::operator_type sf4opr; - - if (!expr_gen.sf4_optimisable(id,sf4opr)) - return false; - else - result = synthesize_sf4ext_expression::template process - (expr_gen, sf4opr, t0, t1, t2, t3); - - return true; - } - - // T o (sf3ext) - template - static inline bool compile_right(expression_generator& expr_gen, - ExternalType t, - const details::operator_type& operation, - expression_node_ptr& sf3node, - expression_node_ptr& result) - { - if (!details::is_sf3ext_node(sf3node)) - return false; - - typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; - - sf3ext_base_ptr n = static_cast(sf3node); - const std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; - - switch (n->type()) - { - case details::expression_node::e_covoc : return compile_right_impl - - (expr_gen, id, t, sf3node, result); - - case details::expression_node::e_covov : return compile_right_impl - - (expr_gen, id, t, sf3node, result); - - case details::expression_node::e_vocov : return compile_right_impl - - (expr_gen, id, t, sf3node, result); - - case details::expression_node::e_vovoc : return compile_right_impl - - (expr_gen, id, t, sf3node, result); - - case details::expression_node::e_vovov : return compile_right_impl - - (expr_gen, id, t, sf3node, result); - - default : return false; - } - } - - // (sf3ext) o T - template - static inline bool compile_left(expression_generator& expr_gen, - ExternalType t, - const details::operator_type& operation, - expression_node_ptr& sf3node, - expression_node_ptr& result) - { - if (!details::is_sf3ext_node(sf3node)) - return false; - - typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; - - sf3ext_base_ptr n = static_cast(sf3node); - - const std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; - - switch (n->type()) - { - case details::expression_node::e_covoc : return compile_left_impl - - (expr_gen, id, t, sf3node, result); - - case details::expression_node::e_covov : return compile_left_impl - - (expr_gen, id, t, sf3node, result); - - case details::expression_node::e_vocov : return compile_left_impl - - (expr_gen, id, t, sf3node, result); - - case details::expression_node::e_vovoc : return compile_left_impl - - (expr_gen, id, t, sf3node, result); - - case details::expression_node::e_vovov : return compile_left_impl - - (expr_gen, id, t, sf3node, result); - - default : return false; - } - } - - template - static inline bool compile_right_impl(expression_generator& expr_gen, - const std::string& id, - ExternalType t, - expression_node_ptr& node, - expression_node_ptr& result) - { - SF3TypeNode* n = dynamic_cast(node); - - if (n) - { - T0 t0 = n->t0(); - T1 t1 = n->t1(); - T2 t2 = n->t2(); - - return synthesize_sf4ext_expression::template compile - (expr_gen, id, t, t0, t1, t2, result); - } - else - return false; - } - - template - static inline bool compile_left_impl(expression_generator& expr_gen, - const std::string& id, - ExternalType t, - expression_node_ptr& node, - expression_node_ptr& result) - { - SF3TypeNode* n = dynamic_cast(node); - - if (n) - { - T0 t0 = n->t0(); - T1 t1 = n->t1(); - T2 t2 = n->t2(); - - return synthesize_sf4ext_expression::template compile - (expr_gen, id, t0, t1, t2, t, result); - } - else - return false; - } - }; - - struct synthesize_vovov_expression0 - { - typedef typename vovov_t::type0 node_type; - typedef typename vovov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (v2) - const details::vov_base_node* vov = static_cast*>(branch[0]); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = vov->operation(); - const details::operator_type o1 = operation; - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t/(t*t)", v0, v1, v2, result); - - exprtk_debug(("(v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; - } - }; - - struct synthesize_vovov_expression1 - { - typedef typename vovov_t::type1 node_type; - typedef typename vovov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0) o0 (v1 o1 v2) - const details::vov_base_node* vov = static_cast*>(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vov->v0(); - const Type& v2 = vov->v1(); - const details::operator_type o0 = operation; - const details::operator_type o1 = vov->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", v0, v2, v1, result); - - exprtk_debug(("v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), v0, v1, v2, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; - } - }; - - struct synthesize_vovoc_expression0 - { - typedef typename vovoc_t::type0 node_type; - typedef typename vovoc_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (c) - const details::vov_base_node* vov = static_cast*>(branch[0]); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const Type c = static_cast*>(branch[1])->value(); - const details::operator_type o0 = vov->operation(); - const details::operator_type o1 = operation; - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) / c --> (vovoc) v0 / (v1 * c) - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t/(t*t)", v0, v1, c, result); - - exprtk_debug(("(v0 / v1) / c --> (vovoc) v0 / (v1 * c)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; - } - }; - - struct synthesize_vovoc_expression1 - { - typedef typename vovoc_t::type1 node_type; - typedef typename vovoc_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0) o0 (v1 o1 c) - const details::voc_base_node* voc = static_cast*>(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = voc->v(); - const Type c = voc->c(); - const details::operator_type o0 = operation; - const details::operator_type o1 = voc->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // v0 / (v1 / c) --> (vocov) (v0 * c) / v1 - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", v0, c, v1, result); - - exprtk_debug(("v0 / (v1 / c) --> (vocov) (v0 * c) / v1\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), v0, v1, c, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; - } - }; - - struct synthesize_vocov_expression0 - { - typedef typename vocov_t::type0 node_type; - typedef typename vocov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 c) o1 (v1) - const details::voc_base_node* voc = static_cast*>(branch[0]); - const Type& v0 = voc->v(); - const Type c = voc->c(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = voc->operation(); - const details::operator_type o1 = operation; - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t/(t*t)", v0, v1, c, result); - - exprtk_debug(("(v0 / c) / v1 --> (vovoc) v0 / (v1 * c)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; - } - }; - - struct synthesize_vocov_expression1 - { - typedef typename vocov_t::type1 node_type; - typedef typename vocov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0) o0 (c o1 v1) - const details::cov_base_node* cov = static_cast*>(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c = cov->c(); - const Type& v1 = cov->v(); - const details::operator_type o0 = operation; - const details::operator_type o1 = cov->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // v0 / (c / v1) --> (vovoc) (v0 * v1) / c - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", v0, v1, c, result); - - exprtk_debug(("v0 / (c / v1) --> (vovoc) (v0 * v1) / c\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), v0, c, v1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; - } - }; - - struct synthesize_covov_expression0 - { - typedef typename covov_t::type0 node_type; - typedef typename covov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c o0 v0) o1 (v1) - const details::cov_base_node* cov = static_cast*>(branch[0]); - const Type c = cov->c(); - const Type& v0 = cov->v(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = cov->operation(); - const details::operator_type o1 = operation; - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c / v0) / v1 --> (covov) c / (v0 * v1) - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t/(t*t)", c, v0, v1, result); - - exprtk_debug(("(c / v0) / v1 --> (covov) c / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; - } - }; - - struct synthesize_covov_expression1 - { - typedef typename covov_t::type1 node_type; - typedef typename covov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c) o0 (v0 o1 v1) - const details::vov_base_node* vov = static_cast*>(branch[1]); - const Type c = static_cast*>(branch[0])->value(); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const details::operator_type o0 = operation; - const details::operator_type o1 = vov->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // c / (v0 / v1) --> (covov) (c * v1) / v0 - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", c, v1, v0, result); - - exprtk_debug(("c / (v0 / v1) --> (covov) (c * v1) / v0\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), c, v0, v1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; - } - }; - - struct synthesize_covoc_expression0 - { - typedef typename covoc_t::type0 node_type; - typedef typename covoc_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0 o0 v) o1 (c1) - const details::cov_base_node* cov = static_cast*>(branch[0]); - const Type c0 = cov->c(); - const Type& v = cov->v(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = cov->operation(); - const details::operator_type o1 = operation; - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0 + v) + c1 --> (cov) (c0 + c1) + v - if ((details::e_add == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0 + v) + c1 --> (cov) (c0 + c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1, v); - } - // (c0 + v) - c1 --> (cov) (c0 - c1) + v - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0 + v) - c1 --> (cov) (c0 - c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1, v); - } - // (c0 - v) + c1 --> (cov) (c0 + c1) - v - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0 - v) + c1 --> (cov) (c0 + c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1, v); - } - // (c0 - v) - c1 --> (cov) (c0 - c1) - v - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0 - v) - c1 --> (cov) (c0 - c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1, v); - } - // (c0 * v) * c1 --> (cov) (c0 * c1) * v - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0 * v) * c1 --> (cov) (c0 * c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1, v); - } - // (c0 * v) / c1 --> (cov) (c0 / c1) * v - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0 * v) / c1 --> (cov) (c0 / c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1, v); - } - // (c0 / v) * c1 --> (cov) (c0 * c1) / v - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0 / v) * c1 --> (cov) (c0 * c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1, v); - } - // (c0 / v) / c1 --> (cov) (c0 / c1) / v - else if ((details::e_div == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0 / v) / c1 --> (cov) (c0 / c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1, v); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; - } - }; - - struct synthesize_covoc_expression1 - { - typedef typename covoc_t::type1 node_type; - typedef typename covoc_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0) o0 (v o1 c1) - const details::voc_base_node* voc = static_cast*>(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v = voc->v(); - const Type c1 = voc->c(); - const details::operator_type o0 = operation; - const details::operator_type o1 = voc->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0) + (v + c1) --> (cov) (c0 + c1) + v - if ((details::e_add == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0) + (v + c1) --> (cov) (c0 + c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1, v); - } - // (c0) + (v - c1) --> (cov) (c0 - c1) + v - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0) + (v - c1) --> (cov) (c0 - c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1, v); - } - // (c0) - (v + c1) --> (cov) (c0 - c1) - v - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0) - (v + c1) --> (cov) (c0 - c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1, v); - } - // (c0) - (v - c1) --> (cov) (c0 + c1) - v - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0) - (v - c1) --> (cov) (c0 + c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1, v); - } - // (c0) * (v * c1) --> (voc) v * (c0 * c1) - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0) * (v * c1) --> (voc) v * (c0 * c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1, v); - } - // (c0) * (v / c1) --> (cov) (c0 / c1) * v - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0) * (v / c1) --> (cov) (c0 / c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1, v); - } - // (c0) / (v * c1) --> (cov) (c0 / c1) / v - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0) / (v * c1) --> (cov) (c0 / c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1, v); - } - // (c0) / (v / c1) --> (cov) (c0 * c1) / v - else if ((details::e_div == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0) / (v / c1) --> (cov) (c0 * c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1, v); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), c0, v, c1, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; - } - }; - - struct synthesize_cocov_expression0 - { - typedef typename cocov_t::type0 node_type; - static inline expression_node_ptr process(expression_generator&, - const details::operator_type&, - expression_node_ptr (&)[2]) - { - // (c0 o0 c1) o1 (v) - Not possible. - return error_node(); - } - }; - - struct synthesize_cocov_expression1 - { - typedef typename cocov_t::type1 node_type; - typedef typename cocov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0) o0 (c1 o1 v) - const details::cov_base_node* cov = static_cast*>(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type c1 = cov->c(); - const Type& v = cov->v(); - const details::operator_type o0 = operation; - const details::operator_type o1 = cov->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0) + (c1 + v) --> (cov) (c0 + c1) + v - if ((details::e_add == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0) + (c1 + v) --> (cov) (c0 + c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1, v); - } - // (c0) + (c1 - v) --> (cov) (c0 + c1) - v - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0) + (c1 - v) --> (cov) (c0 + c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1, v); - } - // (c0) - (c1 + v) --> (cov) (c0 - c1) - v - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0) - (c1 + v) --> (cov) (c0 - c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1, v); - } - // (c0) - (c1 - v) --> (cov) (c0 - c1) + v - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0) - (c1 - v) --> (cov) (c0 - c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1, v); - } - // (c0) * (c1 * v) --> (cov) (c0 * c1) * v - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0) * (c1 * v) --> (cov) (c0 * c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1, v); - } - // (c0) * (c1 / v) --> (cov) (c0 * c1) / v - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0) * (c1 / v) --> (cov) (c0 * c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1, v); - } - // (c0) / (c1 * v) --> (cov) (c0 / c1) / v - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0) / (c1 * v) --> (cov) (c0 / c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1, v); - } - // (c0) / (c1 / v) --> (cov) (c0 / c1) * v - else if ((details::e_div == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0) / (c1 / v) --> (cov) (c0 / c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1, v); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), c0, c1, v, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), c0, c1, v, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)"; - } - }; - - struct synthesize_vococ_expression0 - { - typedef typename vococ_t::type0 node_type; - typedef typename vococ_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v o0 c0) o1 (c1) - const details::voc_base_node* voc = static_cast*>(branch[0]); - const Type& v = voc->v(); - const Type& c0 = voc->c(); - const Type& c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = voc->operation(); - const details::operator_type o1 = operation; - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v + c0) + c1 --> (voc) v + (c0 + c1) - if ((details::e_add == o0) && (details::e_add == o1)) - { - exprtk_debug(("(v + c0) + c1 --> (voc) v + (c0 + c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v, c0 + c1); - } - // (v + c0) - c1 --> (voc) v + (c0 - c1) - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(v + c0) - c1 --> (voc) v + (c0 - c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v, c0 - c1); - } - // (v - c0) + c1 --> (voc) v - (c0 + c1) - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - exprtk_debug(("(v - c0) + c1 --> (voc) v - (c0 + c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v, c1 - c0); - } - // (v - c0) - c1 --> (voc) v - (c0 + c1) - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(v - c0) - c1 --> (voc) v - (c0 + c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v, c0 + c1); - } - // (v * c0) * c1 --> (voc) v * (c0 * c1) - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(v * c0) * c1 --> (voc) v * (c0 * c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v, c0 * c1); - } - // (v * c0) / c1 --> (voc) v * (c0 / c1) - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - exprtk_debug(("(v * c0) / c1 --> (voc) v * (c0 / c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v, c0 / c1); - } - // (v / c0) * c1 --> (voc) v * (c1 / c0) - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(v / c0) * c1 --> (voc) v * (c1 / c0)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v, c1 / c0); - } - // (v / c0) / c1 --> (voc) v / (c0 * c1) - else if ((details::e_div == o0) && (details::e_div == o1)) - { - exprtk_debug(("(v / c0) / c1 --> (voc) v / (c0 * c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v, c0 * c1); - } - // (v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1) - else if ((details::e_pow == o0) && (details::e_pow == o1)) - { - exprtk_debug(("(v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v, c0 * c1); - } - } - - const bool synthesis_result = - synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), v, c0, c1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v, c0, c1, f0, f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t"; - } - }; - - struct synthesize_vococ_expression1 - { - typedef typename vococ_t::type0 node_type; - - static inline expression_node_ptr process(expression_generator&, - const details::operator_type&, - expression_node_ptr (&)[2]) - { - // (v) o0 (c0 o1 c1) - Not possible. - exprtk_debug(("(v) o0 (c0 o1 c1) - Not possible.\n")); - return error_node(); - } - }; - - struct synthesize_vovovov_expression0 - { - typedef typename vovovov_t::type0 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (v2 o2 v3) - const details::vov_base_node* vov0 = static_cast*>(branch[0]); - const details::vov_base_node* vov1 = static_cast*>(branch[1]); - const Type& v0 = vov0->v0(); - const Type& v1 = vov0->v1(); - const Type& v2 = vov1->v0(); - const Type& v3 = vov1->v1(); - const details::operator_type o0 = vov0->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = vov1->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, v3, result); - - exprtk_debug(("(v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", v0, v3, v1, v2, result); - - exprtk_debug(("(v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) - else if ((details::e_add == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t+t)*(t/t)", v0, v1, v3, v2, result); - - exprtk_debug(("(v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 - v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) - else if ((details::e_sub == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t-t)*(t/t)", v0, v1, v3, v2, result); - - exprtk_debug(("(v0 - v1) / (v2 / v3) --> (vovovov) (v0 - v1) * (v3 / v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2 - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "((t*t)*t)/t", v0, v1, v3, v2, result); - - exprtk_debug(("(v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vovovoc_expression0 - { - typedef typename vovovoc_t::type0 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (v2 o2 c) - const details::vov_base_node* vov = static_cast*>(branch[0]); - const details::voc_base_node* voc = static_cast*>(branch[1]); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const Type& v2 = voc->v (); - const Type c = voc->c (); - const details::operator_type o0 = vov->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = voc->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); - - exprtk_debug(("(v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2) - if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); - - exprtk_debug(("(v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vovocov_expression0 - { - typedef typename vovocov_t::type0 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (c o2 v2) - const details::vov_base_node* vov = static_cast*>(branch[0]); - const details::cov_base_node* cov = static_cast*>(branch[1]); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const Type& v2 = cov->v (); - const Type c = cov->c (); - const details::operator_type o0 = vov->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = cov->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", v0, c, v1, v2, result); - - exprtk_debug(("(v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c) - if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", v0, v2, v1, c, result); - - exprtk_debug(("(v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vocovov_expression0 - { - typedef typename vocovov_t::type0 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 c) o1 (v1 o2 v2) - const details::voc_base_node* voc = static_cast*>(branch[0]); - const details::vov_base_node* vov = static_cast*>(branch[1]); - const Type c = voc->c (); - const Type& v0 = voc->v (); - const Type& v1 = vov->v0(); - const Type& v2 = vov->v1(); - const details::operator_type o0 = voc->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = vov->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", v0, v1, c, v2, result); - - exprtk_debug(("(v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1) - if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", v0, v2, c, v1, result); - - exprtk_debug(("(v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_covovov_expression0 - { - typedef typename covovov_t::type0 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c o0 v0) o1 (v1 o2 v2) - const details::cov_base_node* cov = static_cast*>(branch[0]); - const details::vov_base_node* vov = static_cast*>(branch[1]); - const Type c = cov->c (); - const Type& v0 = cov->v (); - const Type& v1 = vov->v0(); - const Type& v2 = vov->v1(); - const details::operator_type o0 = cov->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = vov->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", c, v1, v0, v2, result); - - exprtk_debug(("(c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1) - if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)/(t*t)", c, v2, v0, v1, result); - - exprtk_debug(("(c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_covocov_expression0 - { - typedef typename covocov_t::type0 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0 o0 v0) o1 (c1 o2 v1) - const details::cov_base_node* cov0 = static_cast*>(branch[0]); - const details::cov_base_node* cov1 = static_cast*>(branch[1]); - const Type c0 = cov0->c(); - const Type& v0 = cov0->v(); - const Type c1 = cov1->c(); - const Type& v1 = cov1->v(); - const details::operator_type o0 = cov0->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = cov1->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); - - exprtk_debug(("(c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); - - exprtk_debug(("(c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1 - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t-t)+t", (c0 - c1), v0, v1, result); - - exprtk_debug(("(c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); - - exprtk_debug(("(c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); - - exprtk_debug(("(c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); - - exprtk_debug(("(c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0 - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", (c0 / c1), v1, v0, result); - - exprtk_debug(("(c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t*(t*t)", (c0 / c1), v0, v1, result); - - exprtk_debug(("(c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); - - exprtk_debug(("(c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1) - else if ( - (std::equal_to()(c0,c1)) && - (details::e_mul == o0) && - (details::e_mul == o2) && - ( - (details::e_add == o1) || - (details::e_sub == o1) - ) - ) - { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "t*(t+t)"; break; - case details::e_sub : specfunc = "t*(t-t)"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, specfunc, c0, v0, v1, result); - - exprtk_debug(("(c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vocovoc_expression0 - { - typedef typename vocovoc_t::type0 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 c0) o1 (v1 o2 c1) - const details::voc_base_node* voc0 = static_cast*>(branch[0]); - const details::voc_base_node* voc1 = static_cast*>(branch[1]); - const Type c0 = voc0->c(); - const Type& v0 = voc0->v(); - const Type c1 = voc1->c(); - const Type& v1 = voc1->v(); - const details::operator_type o0 = voc0->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = voc1->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); - - exprtk_debug(("(v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); - - exprtk_debug(("(v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1 - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)-t", (c1 - c0), v0, v1, result); - - exprtk_debug(("(v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); - - exprtk_debug(("(v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); - - exprtk_debug(("(v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1 - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)*t", Type(1) / (c0 * c1), v0, v1, result); - - exprtk_debug(("(v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1 - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); - - exprtk_debug(("(v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t*(t/t)", (c0 * c1), v0, v1, result); - - exprtk_debug(("(v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1 - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t*(t/t)", Type(1) / (c0 * c1), v0, v1, result); - - exprtk_debug(("(v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)*(t+t)", v0, T(1) / c0, v1, c1, result); - - exprtk_debug(("(v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen, "(t*t)*(t-t)", v0, T(1) / c0, v1, c1, result); - - exprtk_debug(("(v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1) - else if ( - (std::equal_to()(c0,c1)) && - (details::e_mul == o0) && - (details::e_mul == o2) && - ( - (details::e_add == o1) || - (details::e_sub == o1) - ) - ) - { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "t*(t+t)"; break; - case details::e_sub : specfunc = "t*(t-t)"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, specfunc, c0, v0, v1, result); - - exprtk_debug(("(v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c - else if ( - (std::equal_to()(c0,c1)) && - (details::e_div == o0) && - (details::e_div == o2) && - ( - (details::e_add == o1) || - (details::e_sub == o1) - ) - ) - { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "(t+t)/t"; break; - case details::e_sub : specfunc = "(t-t)/t"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, specfunc, v0, v1, c0, result); - - exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_covovoc_expression0 - { - typedef typename covovoc_t::type0 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0 o0 v0) o1 (v1 o2 c1) - const details::cov_base_node* cov = static_cast*>(branch[0]); - const details::voc_base_node* voc = static_cast*>(branch[1]); - const Type c0 = cov->c(); - const Type& v0 = cov->v(); - const Type c1 = voc->c(); - const Type& v1 = voc->v(); - const details::operator_type o0 = cov->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = voc->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); - - exprtk_debug(("(c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); - - exprtk_debug(("(c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1 - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t-(t+t)", (c0 + c1), v0, v1, result); - - exprtk_debug(("(c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); - - exprtk_debug(("(c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); - - exprtk_debug(("(c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t*(t/t)", (c0 / c1), v1, v0, result); - - exprtk_debug(("(c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t/(t*t)", (c0 * c1), v0, v1, result); - - exprtk_debug(("(c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", (c0 * c1), v0, v1, result); - - exprtk_debug(("(c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "t/(t*t)", (c0 / c1), v0, v1, result); - - exprtk_debug(("(c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1) - else if ( - (std::equal_to()(c0,c1)) && - (details::e_mul == o0) && - (details::e_mul == o2) && - ( - (details::e_add == o1) || - (details::e_sub == o1) - ) - ) - { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "t*(t+t)"; break; - case details::e_sub : specfunc = "t*(t-t)"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, specfunc, c0, v0, v1, result); - - exprtk_debug(("(c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vococov_expression0 - { - typedef typename vococov_t::type0 node_type; - typedef typename vococov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 c0) o1 (c1 o2 v1) - const details::voc_base_node* voc = static_cast*>(branch[0]); - const details::cov_base_node* cov = static_cast*>(branch[1]); - const Type c0 = voc->c(); - const Type& v0 = voc->v(); - const Type c1 = cov->c(); - const Type& v1 = cov->v(); - const details::operator_type o0 = voc->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = cov->operation(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)+t", (c0 + c1), v0, v1, result); - - exprtk_debug(("(v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)-t", (c0 - c1), v0, v1, result); - - exprtk_debug(("(v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0) - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t+t)-t", v0, v1, (c1 + c0), result); - - exprtk_debug(("(v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)*t", (c0 * c1), v0, v1, result); - - exprtk_debug(("(v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", (c0 / c1), v0, v1, result); - - exprtk_debug(("(v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", (c1 / c0), v0, v1, result); - - exprtk_debug(("(v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)*t", (c0 / c1), v0, v1, result); - - exprtk_debug(("(v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)/t", Type(1) / (c0 * c1), v0, v1, result); - - exprtk_debug(("(v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1)) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, "(t*t)*t", v0, v1, Type(1) / (c0 * c1), result); - - exprtk_debug(("(v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1))\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1) - else if ( - (std::equal_to()(c0,c1)) && - (details::e_mul == o0) && - (details::e_mul == o2) && - ( - (details::e_add == o1) || (details::e_sub == o1) - ) - ) - { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "t*(t+t)"; break; - case details::e_sub : specfunc = "t*(t-t)"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen, specfunc, c0, v0, v1, result); - - exprtk_debug(("(v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); - - if (synthesis_result) - return result; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vovovov_expression1 - { - typedef typename vovovov_t::type1 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (v1 o1 (v2 o2 v3)) - typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vovov->t0(); - const Type& v2 = vovov->t1(); - const Type& v3 = vovov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovov->f0(); - binary_functor_t f2 = vovov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen,id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (v1 o1 (v2 o2 v3))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; - } - }; - - struct synthesize_vovovoc_expression1 - { - typedef typename vovovoc_t::type1 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (v1 o1 (v2 o2 c)) - typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vovoc->t0(); - const Type& v2 = vovoc->t1(); - const Type c = vovoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovoc->f0(); - binary_functor_t f2 = vovoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (v1 o1 (v2 o2 c))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; - } - }; - - struct synthesize_vovocov_expression1 - { - typedef typename vovocov_t::type1 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (v1 o1 (c o2 v2)) - typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vocov->t0(); - const Type c = vocov->t1(); - const Type& v2 = vocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vocov->f0(); - binary_functor_t f2 = vocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); - - if (synthesis_result) - return result; - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (v1 o1 (c o2 v2))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; - } - }; - - struct synthesize_vocovov_expression1 - { - typedef typename vocovov_t::type1 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (c o1 (v1 o2 v2)) - typedef typename synthesize_covov_expression1::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c = covov->t0(); - const Type& v1 = covov->t1(); - const Type& v2 = covov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(covov->f0()); - const details::operator_type o2 = expr_gen.get_operator(covov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = covov->f0(); - binary_functor_t f2 = covov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (c o1 (v1 o2 v2))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; - } - }; - - struct synthesize_covovov_expression1 - { - typedef typename covovov_t::type1 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c o0 (v0 o1 (v1 o2 v2)) - typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[1]); - const Type c = static_cast*>(branch[0])->value(); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovov->f0(); - binary_functor_t f2 = vovov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); - - if (synthesis_result) - return result; - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c o0 (v0 o1 (v1 o2 v2))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; - } - }; - - struct synthesize_covocov_expression1 - { - typedef typename covocov_t::type1 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c0 o0 (v0 o1 (c1 o2 v1)) - typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v0 = vocov->t0(); - const Type c1 = vocov->t1(); - const Type& v1 = vocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vocov->f0(); - binary_functor_t f2 = vocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c0 o0 (v0 o1 (c1 o2 v1))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; - } - }; - - struct synthesize_vocovoc_expression1 - { - typedef typename vocovoc_t::type1 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (c0 o1 (v1 o2 c2)) - typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; - - const lcl_covoc_t* covoc = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c0 = covoc->t0(); - const Type& v1 = covoc->t1(); - const Type c1 = covoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = covoc->f0(); - binary_functor_t f2 = covoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (c0 o1 (v1 o2 c2))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; - } - }; - - struct synthesize_covovoc_expression1 - { - typedef typename covovoc_t::type1 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c0 o0 (v0 o1 (v1 o2 c1)) - typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v0 = vovoc->t0(); - const Type& v1 = vovoc->t1(); - const Type c1 = vovoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovoc->f0(); - binary_functor_t f2 = vovoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c0 o0 (v0 o1 (v1 o2 c1))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; - } - }; - - struct synthesize_vococov_expression1 - { - typedef typename vococov_t::type1 node_type; - typedef typename vococov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (c0 o1 (c1 o2 v1)) - typedef typename synthesize_cocov_expression1::node_type lcl_cocov_t; - - const lcl_cocov_t* cocov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c0 = cocov->t0(); - const Type c1 = cocov->t1(); - const Type& v1 = cocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(cocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(cocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = cocov->f0(); - binary_functor_t f2 = cocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (c0 o1 (c1 o2 v1))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "(t" << expr_gen.to_str(o2) - << "t))"; - } - }; - - struct synthesize_vovovov_expression2 - { - typedef typename vovovov_t::type2 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((v1 o1 v2) o2 v3) - typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vovov->t0(); - const Type& v2 = vovov->t1(); - const Type& v3 = vovov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovov->f0(); - binary_functor_t f2 = vovov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((v1 o1 v2) o2 v3)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vovovoc_expression2 - { - typedef typename vovovoc_t::type2 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((v1 o1 v2) o2 c) - typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vovoc->t0(); - const Type& v2 = vovoc->t1(); - const Type c = vovoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovoc->f0(); - binary_functor_t f2 = vovoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((v1 o1 v2) o2 c)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vovocov_expression2 - { - typedef typename vovocov_t::type2 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((v1 o1 c) o2 v2) - typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vocov->t0(); - const Type c = vocov->t1(); - const Type& v2 = vocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vocov->f0(); - binary_functor_t f2 = vocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((v1 o1 c) o2 v2)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vocovov_expression2 - { - typedef typename vocovov_t::type2 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((c o1 v1) o2 v2) - typedef typename synthesize_covov_expression0::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c = covov->t0(); - const Type& v1 = covov->t1(); - const Type& v2 = covov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(covov->f0()); - const details::operator_type o2 = expr_gen.get_operator(covov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = covov->f0(); - binary_functor_t f2 = covov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((c o1 v1) o2 v2)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_covovov_expression2 - { - typedef typename covovov_t::type2 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c o0 ((v1 o1 v2) o2 v3) - typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[1]); - const Type c = static_cast*>(branch[0])->value(); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovov->f0(); - binary_functor_t f2 = vovov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c o0 ((v1 o1 v2) o2 v3)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_covocov_expression2 - { - typedef typename covocov_t::type2 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c0 o0 ((v0 o1 c1) o2 v1) - typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v0 = vocov->t0(); - const Type c1 = vocov->t1(); - const Type& v1 = vocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vocov->f0(); - binary_functor_t f2 = vocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c0 o0 ((v0 o1 c1) o2 v1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vocovoc_expression2 - { - typedef typename vocovoc_t::type2 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((c0 o1 v1) o2 c1) - typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; - - const lcl_covoc_t* covoc = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c0 = covoc->t0(); - const Type& v1 = covoc->t1(); - const Type c1 = covoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = covoc->f0(); - binary_functor_t f2 = covoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((c0 o1 v1) o2 c1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_covovoc_expression2 - { - typedef typename covovoc_t::type2 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c0 o0 ((v0 o1 v1) o2 c1) - typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v0 = vovoc->t0(); - const Type& v1 = vovoc->t1(); - const Type c1 = vovoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovoc->f0(); - binary_functor_t f2 = vovoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c0 o0 ((v0 o1 v1) o2 c1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "t" << expr_gen.to_str(o0) - << "((t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t)"; - } - }; - - struct synthesize_vococov_expression2 - { - typedef typename vococov_t::type2 node_type; - static inline expression_node_ptr process(expression_generator&, - const details::operator_type&, - expression_node_ptr (&)[2]) - { - // v0 o0 ((c0 o1 c1) o2 v1) - Not possible - exprtk_debug(("v0 o0 ((c0 o1 c1) o2 v1) - Not possible\n")); - return error_node(); - } - - static inline std::string id(expression_generator&, - const details::operator_type, - const details::operator_type, - const details::operator_type) - { - return "INVALID"; - } - }; - - struct synthesize_vovovov_expression3 - { - typedef typename vovovov_t::type3 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 v1) o1 v2) o2 v3 - typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[0]); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const Type& v3 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovov->f0(); - binary_functor_t f1 = vovov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 v1) o1 v2) o2 v3\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vovovoc_expression3 - { - typedef typename vovovoc_t::type3 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 v1) o1 v2) o2 c - typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[0]); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const Type c = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovov->f0(); - binary_functor_t f1 = vovov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 v1) o1 v2) o2 c\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vovocov_expression3 - { - typedef typename vovocov_t::type3 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 v1) o1 c) o2 v2 - typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[0]); - const Type& v0 = vovoc->t0(); - const Type& v1 = vovoc->t1(); - const Type c = vovoc->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovoc->f0(); - binary_functor_t f1 = vovoc->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 v1) o1 c) o2 v2\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vocovov_expression3 - { - typedef typename vocovov_t::type3 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 c) o1 v1) o2 v2 - typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[0]); - const Type& v0 = vocov->t0(); - const Type c = vocov->t1(); - const Type& v1 = vocov->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vocov->f0(); - binary_functor_t f1 = vocov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 c) o1 v1) o2 v2\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_covovov_expression3 - { - typedef typename covovov_t::type3 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c o0 v0) o1 v1) o2 v2 - typedef typename synthesize_covov_expression0::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[0]); - const Type c = covov->t0(); - const Type& v0 = covov->t1(); - const Type& v1 = covov->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(covov->f0()); - const details::operator_type o1 = expr_gen.get_operator(covov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covov->f0(); - binary_functor_t f1 = covov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c o0 v0) o1 v1) o2 v2\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_covocov_expression3 - { - typedef typename covocov_t::type3 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c0 o0 v0) o1 c1) o2 v1 - typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; - - const lcl_covoc_t* covoc = static_cast(branch[0]); - const Type c0 = covoc->t0(); - const Type& v0 = covoc->t1(); - const Type c1 = covoc->t2(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); - const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covoc->f0(); - binary_functor_t f1 = covoc->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c0 o0 v0) o1 c1) o2 v1\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vocovoc_expression3 - { - typedef typename vocovoc_t::type3 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 c0) o1 v1) o2 c1 - typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[0]); - const Type& v0 = vocov->t0(); - const Type c0 = vocov->t1(); - const Type& v1 = vocov->t2(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vocov->f0(); - binary_functor_t f1 = vocov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 c0) o1 v1) o2 c1\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_covovoc_expression3 - { - typedef typename covovoc_t::type3 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c0 o0 v0) o1 v1) o2 c1 - typedef typename synthesize_covov_expression0::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[0]); - const Type c0 = covov->t0(); - const Type& v0 = covov->t1(); - const Type& v1 = covov->t2(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(covov->f0()); - const details::operator_type o1 = expr_gen.get_operator(covov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covov->f0(); - binary_functor_t f1 = covov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c0 o0 v0) o1 v1) o2 c1\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vococov_expression3 - { - typedef typename vococov_t::type3 node_type; - typedef typename vococov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 c0) o1 c1) o2 v1 - typedef typename synthesize_vococ_expression0::node_type lcl_vococ_t; - - const lcl_vococ_t* vococ = static_cast(branch[0]); - const Type& v0 = vococ->t0(); - const Type c0 = vococ->t1(); - const Type c1 = vococ->t2(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vococ->f0()); - const details::operator_type o1 = expr_gen.get_operator(vococ->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vococ->f0(); - binary_functor_t f1 = vococ->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, c1, v1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 c0) o1 c1) o2 v1\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, c1, v1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "((t" << expr_gen.to_str(o0) - << "t)" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vovovov_expression4 - { - typedef typename vovovov_t::type4 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 (v1 o1 v2)) o2 v3 - typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[0]); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const Type& v3 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovov->f0(); - binary_functor_t f1 = vovov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("(v0 o0 (v1 o1 v2)) o2 v3\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, v3, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vovovoc_expression4 - { - typedef typename vovovoc_t::type4 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 (v1 o1 v2)) o2 c) - typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[0]); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const Type c = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovov->f0(); - binary_functor_t f1 = vovov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, c, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 (v1 o1 v2)) o2 c)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, v2, c, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vovocov_expression4 - { - typedef typename vovocov_t::type4 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 (v1 o1 c)) o2 v1) - typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[0]); - const Type& v0 = vovoc->t0(); - const Type& v1 = vovoc->t1(); - const Type c = vovoc->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovoc->f0(); - binary_functor_t f1 = vovoc->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, c, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 (v1 o1 c)) o2 v1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, v1, c, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vocovov_expression4 - { - typedef typename vocovov_t::type4 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 (c o1 v1)) o2 v2) - typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[0]); - const Type& v0 = vocov->t0(); - const Type c = vocov->t1(); - const Type& v1 = vocov->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vocov->f0(); - binary_functor_t f1 = vocov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c, v1, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 (c o1 v1)) o2 v2)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_covovov_expression4 - { - typedef typename covovov_t::type4 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c o0 (v0 o1 v1)) o2 v2) - typedef typename synthesize_covov_expression1::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[0]); - const Type c = covov->t0(); - const Type& v0 = covov->t1(); - const Type& v1 = covov->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(covov->f0()); - const details::operator_type o1 = expr_gen.get_operator(covov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covov->f0(); - binary_functor_t f1 = covov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c, v0, v1, v2, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c o0 (v0 o1 v1)) o2 v2)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c, v0, v1, v2, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_covocov_expression4 - { - typedef typename covocov_t::type4 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c0 o0 (v0 o1 c1)) o2 v1) - typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; - - const lcl_covoc_t* covoc = static_cast(branch[0]); - const Type c0 = covoc->t0(); - const Type& v0 = covoc->t1(); - const Type c1 = covoc->t2(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); - const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covoc->f0(); - binary_functor_t f1 = covoc->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, c1, v1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c0 o0 (v0 o1 c1)) o2 v1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, c1, v1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vocovoc_expression4 - { - typedef typename vocovoc_t::type4 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 (c0 o1 v1)) o2 c1) - typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[0]); - const Type& v0 = vocov->t0(); - const Type c0 = vocov->t1(); - const Type& v1 = vocov->t2(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vocov->f0(); - binary_functor_t f1 = vocov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, c0, v1, c1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 (c0 o1 v1)) o2 c1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), v0, c0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_covovoc_expression4 - { - typedef typename covovoc_t::type4 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c0 o0 (v0 o1 v1)) o2 c1) - typedef typename synthesize_covov_expression1::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[0]); - const Type c0 = covov->t0(); - const Type& v0 = covov->t1(); - const Type& v1 = covov->t2(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(covov->f0()); - const details::operator_type o1 = expr_gen.get_operator(covov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covov->f0(); - binary_functor_t f1 = covov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - const bool synthesis_result = - synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), c0, v0, v1, c1, result); - - if (synthesis_result) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c0 o0 (v0 o1 v1)) o2 c1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_), c0, v0, v1, c1, f0, f1, f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return details::build_string() - << "(t" << expr_gen.to_str(o0) - << "(t" << expr_gen.to_str(o1) - << "t)" << expr_gen.to_str(o2) - << "t"; - } - }; - - struct synthesize_vococov_expression4 - { - typedef typename vococov_t::type4 node_type; - static inline expression_node_ptr process(expression_generator&, - const details::operator_type&, - expression_node_ptr (&)[2]) - { - // ((v0 o0 (c0 o1 c1)) o2 v1) - Not possible - exprtk_debug(("((v0 o0 (c0 o1 c1)) o2 v1) - Not possible\n")); - return error_node(); - } - - static inline std::string id(expression_generator&, - const details::operator_type, - const details::operator_type, - const details::operator_type) - { - return "INVALID"; - } - }; - #endif - - inline expression_node_ptr synthesize_uvouv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - // Definition: uv o uv - details::operator_type o0 = static_cast*>(branch[0])->operation(); - details::operator_type o1 = static_cast*>(branch[1])->operation(); - const Type& v0 = static_cast*>(branch[0])->v(); - const Type& v1 = static_cast*>(branch[1])->v(); - unary_functor_t u0 = reinterpret_cast (0); - unary_functor_t u1 = reinterpret_cast (0); - binary_functor_t f = reinterpret_cast(0); - - if (!valid_operator(o0,u0)) - return error_node(); - else if (!valid_operator(o1,u1)) - return error_node(); - else if (!valid_operator(operation,f)) - return error_node(); - - expression_node_ptr result = error_node(); - - if ( - (details::e_neg == o0) && - (details::e_neg == o1) - ) - { - switch (operation) - { - // (-v0 + -v1) --> -(v0 + v1) - case details::e_add : result = (*this)(details::e_neg, - node_allocator_-> - allocate_rr > >(v0, v1)); - exprtk_debug(("(-v0 + -v1) --> -(v0 + v1)\n")); - break; - - // (-v0 - -v1) --> (v1 - v0) - case details::e_sub : result = node_allocator_-> - allocate_rr > >(v1, v0); - exprtk_debug(("(-v0 - -v1) --> (v1 - v0)\n")); - break; - - // (-v0 * -v1) --> (v0 * v1) - case details::e_mul : result = node_allocator_-> - allocate_rr > >(v0, v1); - exprtk_debug(("(-v0 * -v1) --> (v0 * v1)\n")); - break; - - // (-v0 / -v1) --> (v0 / v1) - case details::e_div : result = node_allocator_-> - allocate_rr > >(v0, v1); - exprtk_debug(("(-v0 / -v1) --> (v0 / v1)\n")); - break; - - default : break; - } - } - - if (0 == result) - { - result = node_allocator_-> - allocate_rrrrr >(v0, v1, u0, u1, f); - } - - details::free_all_nodes(*node_allocator_,branch); - return result; - } - - #undef basic_opr_switch_statements - #undef extended_opr_switch_statements - #undef unary_opr_switch_statements - - #ifndef exprtk_disable_string_capabilities - - #define string_opr_switch_statements \ - case_stmt(details::e_lt , details::lt_op ) \ - case_stmt(details::e_lte , details::lte_op ) \ - case_stmt(details::e_gt , details::gt_op ) \ - case_stmt(details::e_gte , details::gte_op ) \ - case_stmt(details::e_eq , details::eq_op ) \ - case_stmt(details::e_ne , details::ne_op ) \ - case_stmt(details::e_in , details::in_op ) \ - case_stmt(details::e_like , details::like_op ) \ - case_stmt(details::e_ilike , details::ilike_op) \ - - template - inline expression_node_ptr synthesize_str_xrox_expression_impl(const details::operator_type& opr, - T0 s0, T1 s1, - range_t rp0) - { - switch (opr) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate_ttt >,T0,T1> \ - (s0, s1, rp0); \ - - string_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - - template - inline expression_node_ptr synthesize_str_xoxr_expression_impl(const details::operator_type& opr, - T0 s0, T1 s1, - range_t rp1) - { - switch (opr) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate_ttt >,T0,T1> \ - (s0, s1, rp1); \ - - string_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - - template - inline expression_node_ptr synthesize_str_xroxr_expression_impl(const details::operator_type& opr, - T0 s0, T1 s1, - range_t rp0, range_t rp1) - { - switch (opr) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate_tttt >,T0,T1> \ - (s0, s1, rp0, rp1); \ - - string_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - - template - inline expression_node_ptr synthesize_sos_expression_impl(const details::operator_type& opr, T0 s0, T1 s1) - { - switch (opr) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate_tt >,T0,T1>(s0, s1); \ - - string_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr synthesize_sos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*>(branch[0])->ref(); - std::string& s1 = static_cast*>(branch[1])->ref(); - - return synthesize_sos_expression_impl(opr, s0, s1); - } - - inline expression_node_ptr synthesize_sros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*>(branch[0])->ref (); - std::string& s1 = static_cast*> (branch[1])->ref (); - range_t rp0 = static_cast*>(branch[0])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - - return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); - } - - inline expression_node_ptr synthesize_sosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*> (branch[0])->ref (); - std::string& s1 = static_cast*>(branch[1])->ref (); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); - } - - inline expression_node_ptr synthesize_socsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*> (branch[0])->ref (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); - } - - inline expression_node_ptr synthesize_srosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*>(branch[0])->ref (); - std::string& s1 = static_cast*>(branch[1])->ref (); - range_t rp0 = static_cast*>(branch[0])->range(); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - static_cast*>(branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); - } - - inline expression_node_ptr synthesize_socs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); - std::string s1 = static_cast*>(branch[1])->str(); - - details::free_node(*node_allocator_,branch[1]); - - return synthesize_sos_expression_impl(opr, s0, s1); - } - - inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string s0 = static_cast*>(branch[0])->str(); - std::string& s1 = static_cast* >(branch[1])->ref(); - - details::free_node(*node_allocator_,branch[0]); - - return synthesize_sos_expression_impl(opr, s0, s1); - } - - inline expression_node_ptr synthesize_csosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string s0 = static_cast*>(branch[0])->str (); - std::string& s1 = static_cast* >(branch[1])->ref (); - range_t rp1 = static_cast* >(branch[1])->range(); - - static_cast*>(branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); - } - - inline expression_node_ptr synthesize_srocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast* >(branch[0])->ref (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp0 = static_cast* >(branch[0])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); - } - - inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast* >(branch[0])->ref (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp0 = static_cast* >(branch[0])->range(); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*> (branch[0])->range_ref().clear(); - static_cast*>(branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); - } - - inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - const std::string s0 = static_cast*>(branch[0])->str(); - const std::string s1 = static_cast*>(branch[1])->str(); - - expression_node_ptr result = error_node(); - - if (details::e_add == opr) - result = node_allocator_->allocate_c >(s0 + s1); - else if (details::e_in == opr) - result = node_allocator_->allocate_c >(details::in_op ::process(s0,s1)); - else if (details::e_like == opr) - result = node_allocator_->allocate_c >(details::like_op ::process(s0,s1)); - else if (details::e_ilike == opr) - result = node_allocator_->allocate_c >(details::ilike_op::process(s0,s1)); - else - { - expression_node_ptr temp = synthesize_sos_expression_impl(opr, s0, s1); - - const Type v = temp->value(); - - details::free_node(*node_allocator_,temp); - - result = node_allocator_->allocate(v); - } - - details::free_all_nodes(*node_allocator_,branch); - - return result; - } - - inline expression_node_ptr synthesize_csocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - const std::string s0 = static_cast* >(branch[0])->str (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xoxr_expression_impl(opr, s0, s1, rp1); - } - - inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string s0 = static_cast*>(branch[0])->str (); - std::string& s1 = static_cast* >(branch[1])->ref (); - range_t rp0 = static_cast*>(branch[0])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - - return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); - } - - inline expression_node_ptr synthesize_csrosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - const std::string s0 = static_cast*>(branch[0])->str (); - std::string& s1 = static_cast* >(branch[1])->ref (); - const range_t rp0 = static_cast*>(branch[0])->range(); - const range_t rp1 = static_cast* >(branch[1])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - static_cast*> (branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); - } - - inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - const std::string s0 = static_cast*>(branch[0])->str (); - const std::string s1 = static_cast* >(branch[1])->str (); - const range_t rp0 = static_cast*>(branch[0])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - - details::free_all_nodes(*node_allocator_,branch); - - return synthesize_str_xrox_expression_impl(opr, s0, s1, rp0); - } - - inline expression_node_ptr synthesize_csrocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - const std::string s0 = static_cast*>(branch[0])->str (); - const std::string s1 = static_cast*>(branch[1])->str (); - const range_t rp0 = static_cast*>(branch[0])->range(); - const range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - static_cast*>(branch[1])->range_ref().clear(); - - details::free_all_nodes(*node_allocator_,branch); - - return synthesize_str_xroxr_expression_impl(opr, s0, s1, rp0, rp1); - } - - inline expression_node_ptr synthesize_strogen_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - switch (opr) - { - #define case_stmt(op0, op1) \ - case op0 : return node_allocator_-> \ - allocate_ttt > > \ - (opr, branch[0], branch[1]); \ - - string_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } - - #undef string_opr_switch_statements - #endif - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - if ((0 == branch[0]) || (0 == branch[1])) - { - details::free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - - const bool b0_is_s = details::is_string_node (branch[0]); - const bool b0_is_cs = details::is_const_string_node (branch[0]); - const bool b0_is_sr = details::is_string_range_node (branch[0]); - const bool b0_is_csr = details::is_const_string_range_node(branch[0]); - - const bool b1_is_s = details::is_string_node (branch[1]); - const bool b1_is_cs = details::is_const_string_node (branch[1]); - const bool b1_is_sr = details::is_string_range_node (branch[1]); - const bool b1_is_csr = details::is_const_string_range_node(branch[1]); - - const bool b0_is_gen = details::is_string_assignment_node (branch[0]) || - details::is_genricstring_range_node(branch[0]) || - details::is_string_concat_node (branch[0]) || - details::is_string_function_node (branch[0]) || - details::is_string_condition_node (branch[0]) || - details::is_string_ccondition_node (branch[0]) || - details::is_string_vararg_node (branch[0]) ; - - const bool b1_is_gen = details::is_string_assignment_node (branch[1]) || - details::is_genricstring_range_node(branch[1]) || - details::is_string_concat_node (branch[1]) || - details::is_string_function_node (branch[1]) || - details::is_string_condition_node (branch[1]) || - details::is_string_ccondition_node (branch[1]) || - details::is_string_vararg_node (branch[1]) ; - - if (details::e_add == opr) - { - if (!b0_is_cs || !b1_is_cs) - { - return synthesize_expression(opr,branch); - } - } - - if (b0_is_gen || b1_is_gen) - { - return synthesize_strogen_expression(opr,branch); - } - else if (b0_is_s) - { - if (b1_is_s ) return synthesize_sos_expression (opr,branch); - else if (b1_is_cs ) return synthesize_socs_expression (opr,branch); - else if (b1_is_sr ) return synthesize_sosr_expression (opr,branch); - else if (b1_is_csr) return synthesize_socsr_expression (opr,branch); - } - else if (b0_is_cs) - { - if (b1_is_s ) return synthesize_csos_expression (opr,branch); - else if (b1_is_cs ) return synthesize_csocs_expression (opr,branch); - else if (b1_is_sr ) return synthesize_csosr_expression (opr,branch); - else if (b1_is_csr) return synthesize_csocsr_expression(opr,branch); - } - else if (b0_is_sr) - { - if (b1_is_s ) return synthesize_sros_expression (opr,branch); - else if (b1_is_sr ) return synthesize_srosr_expression (opr,branch); - else if (b1_is_cs ) return synthesize_srocs_expression (opr,branch); - else if (b1_is_csr) return synthesize_srocsr_expression(opr,branch); - } - else if (b0_is_csr) - { - if (b1_is_s ) return synthesize_csros_expression (opr,branch); - else if (b1_is_sr ) return synthesize_csrosr_expression (opr,branch); - else if (b1_is_cs ) return synthesize_csrocs_expression (opr,branch); - else if (b1_is_csr) return synthesize_csrocsr_expression(opr,branch); - } - - return error_node(); - } - #else - inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[2]) - { - details::free_all_nodes(*node_allocator_,branch); - return error_node(); - } - #endif - - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[3]) - { - if (details::e_inrange != opr) - return error_node(); - else if ((0 == branch[0]) || (0 == branch[1]) || (0 == branch[2])) - { - details::free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - else if ( - details::is_const_string_node(branch[0]) && - details::is_const_string_node(branch[1]) && - details::is_const_string_node(branch[2]) - ) - { - const std::string s0 = static_cast*>(branch[0])->str(); - const std::string s1 = static_cast*>(branch[1])->str(); - const std::string s2 = static_cast*>(branch[2])->str(); - - const Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); - - details::free_all_nodes(*node_allocator_,branch); - - return node_allocator_->allocate_c >(v); - } - else if ( - details::is_string_node(branch[0]) && - details::is_string_node(branch[1]) && - details::is_string_node(branch[2]) - ) - { - std::string& s0 = static_cast*>(branch[0])->ref(); - std::string& s1 = static_cast*>(branch[1])->ref(); - std::string& s2 = static_cast*>(branch[2])->ref(); - - typedef typename details::sosos_node > inrange_t; - - return node_allocator_->allocate_type(s0, s1, s2); - } - else if ( - details::is_const_string_node(branch[0]) && - details::is_string_node(branch[1]) && - details::is_const_string_node(branch[2]) - ) - { - std::string s0 = static_cast*>(branch[0])->str(); - std::string& s1 = static_cast* >(branch[1])->ref(); - std::string s2 = static_cast*>(branch[2])->str(); - - typedef typename details::sosos_node > inrange_t; - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[2]); - - return node_allocator_->allocate_type(s0, s1, s2); - } - else if ( - details::is_string_node(branch[0]) && - details::is_const_string_node(branch[1]) && - details::is_string_node(branch[2]) - ) - { - std::string& s0 = static_cast* >(branch[0])->ref(); - std::string s1 = static_cast*>(branch[1])->str(); - std::string& s2 = static_cast* >(branch[2])->ref(); - - typedef typename details::sosos_node > inrange_t; - - details::free_node(*node_allocator_,branch[1]); - - return node_allocator_->allocate_type(s0, s1, s2); - } - else if ( - details::is_string_node(branch[0]) && - details::is_string_node(branch[1]) && - details::is_const_string_node(branch[2]) - ) - { - std::string& s0 = static_cast* >(branch[0])->ref(); - std::string& s1 = static_cast* >(branch[1])->ref(); - std::string s2 = static_cast*>(branch[2])->str(); - - typedef typename details::sosos_node > inrange_t; - - details::free_node(*node_allocator_,branch[2]); - - return node_allocator_->allocate_type(s0, s1, s2); - } - else if ( - details::is_const_string_node(branch[0]) && - details:: is_string_node(branch[1]) && - details:: is_string_node(branch[2]) - ) - { - std::string s0 = static_cast*>(branch[0])->str(); - std::string& s1 = static_cast* >(branch[1])->ref(); - std::string& s2 = static_cast* >(branch[2])->ref(); - - typedef typename details::sosos_node > inrange_t; - - details::free_node(*node_allocator_,branch[0]); - - return node_allocator_->allocate_type(s0, s1, s2); - } - else - return error_node(); - } - #else - inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[3]) - { - details::free_all_nodes(*node_allocator_,branch); - return error_node(); - } - #endif - - inline expression_node_ptr synthesize_null_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - /* - Note: The following are the type promotion rules - that relate to operations that include 'null': - 0. null ==/!= null --> true false - 1. null operation null --> null - 2. x ==/!= null --> true/false - 3. null ==/!= x --> true/false - 4. x operation null --> x - 5. null operation x --> x - */ - - typedef typename details::null_eq_node nulleq_node_t; - - const bool b0_null = details::is_null_node(branch[0]); - const bool b1_null = details::is_null_node(branch[1]); - - if (b0_null && b1_null) - { - expression_node_ptr result = error_node(); - - if (details::e_eq == operation) - result = node_allocator_->allocate_c(T(1)); - else if (details::e_ne == operation) - result = node_allocator_->allocate_c(T(0)); - - if (result) - { - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return result; - } - - details::free_node(*node_allocator_,branch[1]); - - return branch[0]; - } - else if (details::e_eq == operation) - { - expression_node_ptr result = node_allocator_-> - allocate_rc(branch[b0_null ? 0 : 1],true); - - details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); - - return result; - } - else if (details::e_ne == operation) - { - expression_node_ptr result = node_allocator_-> - allocate_rc(branch[b0_null ? 0 : 1],false); - - details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); - - return result; - } - else if (b0_null) - { - details::free_node(*node_allocator_,branch[0]); - branch[0] = branch[1]; - branch[1] = error_node(); - } - else if (b1_null) - { - details::free_node(*node_allocator_,branch[1]); - branch[1] = error_node(); - } - - if ( - (details::e_add == operation) || (details::e_sub == operation) || - (details::e_mul == operation) || (details::e_div == operation) || - (details::e_mod == operation) || (details::e_pow == operation) - ) - { - return branch[0]; - } - - details::free_node(*node_allocator_, branch[0]); - - if ( - (details::e_lt == operation) || (details::e_lte == operation) || - (details::e_gt == operation) || (details::e_gte == operation) || - (details::e_and == operation) || (details::e_nand == operation) || - (details::e_or == operation) || (details::e_nor == operation) || - (details::e_xor == operation) || (details::e_xnor == operation) || - (details::e_in == operation) || (details::e_like == operation) || - (details::e_ilike == operation) - ) - { - return node_allocator_->allocate_c(T(0)); - } - - return node_allocator_->allocate >(); - } - - template - inline expression_node_ptr synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[N]) - { - if ( - (details::e_in == operation) || - (details::e_like == operation) || - (details::e_ilike == operation) - ) - { - free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - else if (!details::all_nodes_valid(branch)) - { - free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - else if ((details::e_default != operation)) - { - // Attempt simple constant folding optimisation. - expression_node_ptr expression_point = node_allocator_->allocate(operation,branch); - - if (is_constant_foldable(branch)) - { - const Type v = expression_point->value(); - details::free_node(*node_allocator_,expression_point); - - return node_allocator_->allocate(v); - } - - if (expression_point && expression_point->valid()) - { - return expression_point; - } - - parser_->set_error(parser_error::make_error( - parser_error::e_parser, - token_t(), - "ERR276 - Failed to synthesize node: NodeType", - exprtk_error_location)); - - details::free_node(*node_allocator_, expression_point); - } - - return error_node(); - } - - template - inline expression_node_ptr synthesize_expression(F* f, expression_node_ptr (&branch)[N]) - { - if (!details::all_nodes_valid(branch)) - { - free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - - typedef typename details::function_N_node function_N_node_t; - - // Attempt simple constant folding optimisation. - - expression_node_ptr expression_point = node_allocator_->allocate(f); - function_N_node_t* func_node_ptr = dynamic_cast(expression_point); - - if (0 == func_node_ptr) - { - free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - else - func_node_ptr->init_branches(branch); - - if (is_constant_foldable(branch) && !f->has_side_effects()) - { - Type v = expression_point->value(); - details::free_node(*node_allocator_,expression_point); - - return node_allocator_->allocate(v); - } - - parser_->state_.activate_side_effect("synthesize_expression(function)"); - - return expression_point; - } - - bool strength_reduction_enabled_; - details::node_allocator* node_allocator_; - synthesize_map_t synthesize_map_; - unary_op_map_t* unary_op_map_; - binary_op_map_t* binary_op_map_; - inv_binary_op_map_t* inv_binary_op_map_; - sf3_map_t* sf3_map_; - sf4_map_t* sf4_map_; - parser_t* parser_; - }; // class expression_generator - - inline void set_error(const parser_error::type& error_type) - { - error_list_.push_back(error_type); - } - - inline void remove_last_error() - { - if (!error_list_.empty()) - { - error_list_.pop_back(); - } - } - - inline void set_synthesis_error(const std::string& synthesis_error_message) - { - if (synthesis_error_.empty()) - { - synthesis_error_ = synthesis_error_message; - } - } - - inline void register_local_vars(expression& e) - { - for (std::size_t i = 0; i < sem_.size(); ++i) - { - scope_element& se = sem_.get_element(i); - - exprtk_debug(("register_local_vars() - se[%s]\n", se.name.c_str())); - - if ( - (scope_element::e_variable == se.type) || - (scope_element::e_literal == se.type) || - (scope_element::e_vecelem == se.type) - ) - { - if (se.var_node) - { - e.register_local_var(se.var_node); - } - - if (se.data) - { - e.register_local_data(se.data, 1, 0); - } - } - else if (scope_element::e_vector == se.type) - { - if (se.vec_node) - { - e.register_local_var(se.vec_node); - } - - if (se.data) - { - e.register_local_data(se.data, se.size, 1); - } - } - #ifndef exprtk_disable_string_capabilities - else if (scope_element::e_string == se.type) - { - if (se.str_node) - { - e.register_local_var(se.str_node); - } - - if (se.data) - { - e.register_local_data(se.data, se.size, 2); - } - } - #endif - - se.var_node = 0; - se.vec_node = 0; - #ifndef exprtk_disable_string_capabilities - se.str_node = 0; - #endif - se.data = 0; - se.ref_count = 0; - se.active = false; - } - } - - inline void register_return_results(expression& e) - { - e.register_return_results(results_context_); - results_context_ = 0; - } - - inline void load_unary_operations_map(unary_op_map_t& m) - { - #define register_unary_op(Op, UnaryFunctor) \ - m.insert(std::make_pair(Op,UnaryFunctor::process)); \ - - register_unary_op(details::e_abs , details::abs_op ) - register_unary_op(details::e_acos , details::acos_op ) - register_unary_op(details::e_acosh , details::acosh_op) - register_unary_op(details::e_asin , details::asin_op ) - register_unary_op(details::e_asinh , details::asinh_op) - register_unary_op(details::e_atanh , details::atanh_op) - register_unary_op(details::e_ceil , details::ceil_op ) - register_unary_op(details::e_cos , details::cos_op ) - register_unary_op(details::e_cosh , details::cosh_op ) - register_unary_op(details::e_exp , details::exp_op ) - register_unary_op(details::e_expm1 , details::expm1_op) - register_unary_op(details::e_floor , details::floor_op) - register_unary_op(details::e_log , details::log_op ) - register_unary_op(details::e_log10 , details::log10_op) - register_unary_op(details::e_log2 , details::log2_op ) - register_unary_op(details::e_log1p , details::log1p_op) - register_unary_op(details::e_neg , details::neg_op ) - register_unary_op(details::e_pos , details::pos_op ) - register_unary_op(details::e_round , details::round_op) - register_unary_op(details::e_sin , details::sin_op ) - register_unary_op(details::e_sinc , details::sinc_op ) - register_unary_op(details::e_sinh , details::sinh_op ) - register_unary_op(details::e_sqrt , details::sqrt_op ) - register_unary_op(details::e_tan , details::tan_op ) - register_unary_op(details::e_tanh , details::tanh_op ) - register_unary_op(details::e_cot , details::cot_op ) - register_unary_op(details::e_sec , details::sec_op ) - register_unary_op(details::e_csc , details::csc_op ) - register_unary_op(details::e_r2d , details::r2d_op ) - register_unary_op(details::e_d2r , details::d2r_op ) - register_unary_op(details::e_d2g , details::d2g_op ) - register_unary_op(details::e_g2d , details::g2d_op ) - register_unary_op(details::e_notl , details::notl_op ) - register_unary_op(details::e_sgn , details::sgn_op ) - register_unary_op(details::e_erf , details::erf_op ) - register_unary_op(details::e_erfc , details::erfc_op ) - register_unary_op(details::e_ncdf , details::ncdf_op ) - register_unary_op(details::e_frac , details::frac_op ) - register_unary_op(details::e_trunc , details::trunc_op) - #undef register_unary_op - } - - inline void load_binary_operations_map(binary_op_map_t& m) - { - typedef typename binary_op_map_t::value_type value_type; - - #define register_binary_op(Op, BinaryFunctor) \ - m.insert(value_type(Op,BinaryFunctor::process)); \ - - register_binary_op(details::e_add , details::add_op ) - register_binary_op(details::e_sub , details::sub_op ) - register_binary_op(details::e_mul , details::mul_op ) - register_binary_op(details::e_div , details::div_op ) - register_binary_op(details::e_mod , details::mod_op ) - register_binary_op(details::e_pow , details::pow_op ) - register_binary_op(details::e_lt , details::lt_op ) - register_binary_op(details::e_lte , details::lte_op ) - register_binary_op(details::e_gt , details::gt_op ) - register_binary_op(details::e_gte , details::gte_op ) - register_binary_op(details::e_eq , details::eq_op ) - register_binary_op(details::e_ne , details::ne_op ) - register_binary_op(details::e_and , details::and_op ) - register_binary_op(details::e_nand , details::nand_op) - register_binary_op(details::e_or , details::or_op ) - register_binary_op(details::e_nor , details::nor_op ) - register_binary_op(details::e_xor , details::xor_op ) - register_binary_op(details::e_xnor , details::xnor_op) - #undef register_binary_op - } - - inline void load_inv_binary_operations_map(inv_binary_op_map_t& m) - { - typedef typename inv_binary_op_map_t::value_type value_type; - - #define register_binary_op(Op, BinaryFunctor) \ - m.insert(value_type(BinaryFunctor::process,Op)); \ - - register_binary_op(details::e_add , details::add_op ) - register_binary_op(details::e_sub , details::sub_op ) - register_binary_op(details::e_mul , details::mul_op ) - register_binary_op(details::e_div , details::div_op ) - register_binary_op(details::e_mod , details::mod_op ) - register_binary_op(details::e_pow , details::pow_op ) - register_binary_op(details::e_lt , details::lt_op ) - register_binary_op(details::e_lte , details::lte_op ) - register_binary_op(details::e_gt , details::gt_op ) - register_binary_op(details::e_gte , details::gte_op ) - register_binary_op(details::e_eq , details::eq_op ) - register_binary_op(details::e_ne , details::ne_op ) - register_binary_op(details::e_and , details::and_op ) - register_binary_op(details::e_nand , details::nand_op) - register_binary_op(details::e_or , details::or_op ) - register_binary_op(details::e_nor , details::nor_op ) - register_binary_op(details::e_xor , details::xor_op ) - register_binary_op(details::e_xnor , details::xnor_op) - #undef register_binary_op - } - - inline void load_sf3_map(sf3_map_t& sf3_map) - { - typedef std::pair pair_t; - - #define register_sf3(Op) \ - sf3_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ - - register_sf3(00) register_sf3(01) register_sf3(02) register_sf3(03) - register_sf3(04) register_sf3(05) register_sf3(06) register_sf3(07) - register_sf3(08) register_sf3(09) register_sf3(10) register_sf3(11) - register_sf3(12) register_sf3(13) register_sf3(14) register_sf3(15) - register_sf3(16) register_sf3(17) register_sf3(18) register_sf3(19) - register_sf3(20) register_sf3(21) register_sf3(22) register_sf3(23) - register_sf3(24) register_sf3(25) register_sf3(26) register_sf3(27) - register_sf3(28) register_sf3(29) register_sf3(30) - #undef register_sf3 - - #define register_sf3_extid(Id, Op) \ - sf3_map[Id] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ - - register_sf3_extid("(t-t)-t",23) // (t-t)-t --> t-(t+t) - #undef register_sf3_extid - } - - inline void load_sf4_map(sf4_map_t& sf4_map) - { - typedef std::pair pair_t; - - #define register_sf4(Op) \ - sf4_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ - - register_sf4(48) register_sf4(49) register_sf4(50) register_sf4(51) - register_sf4(52) register_sf4(53) register_sf4(54) register_sf4(55) - register_sf4(56) register_sf4(57) register_sf4(58) register_sf4(59) - register_sf4(60) register_sf4(61) register_sf4(62) register_sf4(63) - register_sf4(64) register_sf4(65) register_sf4(66) register_sf4(67) - register_sf4(68) register_sf4(69) register_sf4(70) register_sf4(71) - register_sf4(72) register_sf4(73) register_sf4(74) register_sf4(75) - register_sf4(76) register_sf4(77) register_sf4(78) register_sf4(79) - register_sf4(80) register_sf4(81) register_sf4(82) register_sf4(83) - #undef register_sf4 - - #define register_sf4ext(Op) \ - sf4_map[details::sfext##Op##_op::id()] = pair_t(details::sfext##Op##_op::process,details::e_sf4ext##Op); \ - - register_sf4ext(00) register_sf4ext(01) register_sf4ext(02) register_sf4ext(03) - register_sf4ext(04) register_sf4ext(05) register_sf4ext(06) register_sf4ext(07) - register_sf4ext(08) register_sf4ext(09) register_sf4ext(10) register_sf4ext(11) - register_sf4ext(12) register_sf4ext(13) register_sf4ext(14) register_sf4ext(15) - register_sf4ext(16) register_sf4ext(17) register_sf4ext(18) register_sf4ext(19) - register_sf4ext(20) register_sf4ext(21) register_sf4ext(22) register_sf4ext(23) - register_sf4ext(24) register_sf4ext(25) register_sf4ext(26) register_sf4ext(27) - register_sf4ext(28) register_sf4ext(29) register_sf4ext(30) register_sf4ext(31) - register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35) - register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39) - register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43) - register_sf4ext(44) register_sf4ext(45) register_sf4ext(46) register_sf4ext(47) - register_sf4ext(48) register_sf4ext(49) register_sf4ext(50) register_sf4ext(51) - register_sf4ext(52) register_sf4ext(53) register_sf4ext(54) register_sf4ext(55) - register_sf4ext(56) register_sf4ext(57) register_sf4ext(58) register_sf4ext(59) - register_sf4ext(60) register_sf4ext(61) - #undef register_sf4ext - } - - inline results_context_t& results_ctx() - { - if (0 == results_context_) - { - results_context_ = new results_context_t(); - } - - return (*results_context_); - } - - inline void return_cleanup() - { - #ifndef exprtk_disable_return_statement - if (results_context_) - { - delete results_context_; - results_context_ = 0; - } - - state_.return_stmt_present = false; - #endif - } - - private: - - parser(const parser&) exprtk_delete; - parser& operator=(const parser&) exprtk_delete; - - settings_store settings_; - expression_generator expression_generator_; - details::node_allocator node_allocator_; - symtab_store symtab_store_; - dependent_entity_collector dec_; - std::deque error_list_; - std::deque brkcnt_list_; - parser_state state_; - bool resolve_unknown_symbol_; - results_context_t* results_context_; - unknown_symbol_resolver* unknown_symbol_resolver_; - unknown_symbol_resolver default_usr_; - base_ops_map_t base_ops_map_; - unary_op_map_t unary_op_map_; - binary_op_map_t binary_op_map_; - inv_binary_op_map_t inv_binary_op_map_; - sf3_map_t sf3_map_; - sf4_map_t sf4_map_; - std::string synthesis_error_; - scope_element_manager sem_; - std::vector current_state_stack_; - - immutable_memory_map_t immutable_memory_map_; - immutable_symtok_map_t immutable_symtok_map_; - - lexer::helper::helper_assembly helper_assembly_; - - lexer::helper::commutative_inserter commutative_inserter_; - lexer::helper::operator_joiner operator_joiner_2_; - lexer::helper::operator_joiner operator_joiner_3_; - lexer::helper::symbol_replacer symbol_replacer_; - lexer::helper::bracket_checker bracket_checker_; - lexer::helper::numeric_checker numeric_checker_; - lexer::helper::sequence_validator sequence_validator_; - lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_; - - loop_runtime_check_ptr loop_runtime_check_; - vector_access_runtime_check_ptr vector_access_runtime_check_; - compilation_check_ptr compilation_check_ptr_; - assert_check_ptr assert_check_; - std::set assert_ids_; - - template - friend void details::disable_type_checking(ParserType& p); - }; // class parser - - namespace details - { - template - struct collector_helper - { - typedef exprtk::symbol_table symbol_table_t; - typedef exprtk::expression expression_t; - typedef exprtk::parser parser_t; - typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; - typedef typename parser_t::unknown_symbol_resolver usr_t; - - struct resolve_as_vector : public usr_t - { - typedef exprtk::parser parser_t; - - using usr_t::process; - - resolve_as_vector() - : usr_t(usr_t::e_usrmode_extended) - {} - - virtual bool process(const std::string& unknown_symbol, - symbol_table_t& symbol_table, - std::string&) exprtk_override - { - static T v[1]; - symbol_table.add_vector(unknown_symbol,v); - return true; - } - }; - - static inline bool collection_pass(const std::string& expression_string, - std::set& symbol_set, - const bool collect_variables, - const bool collect_functions, - const bool vector_pass, - symbol_table_t& ext_symbol_table) - { - symbol_table_t symbol_table; - expression_t expression; - parser_t parser; - - resolve_as_vector vect_resolver; - - expression.register_symbol_table(symbol_table ); - expression.register_symbol_table(ext_symbol_table); - - if (vector_pass) - parser.enable_unknown_symbol_resolver(&vect_resolver); - else - parser.enable_unknown_symbol_resolver(); - - if (collect_variables) - parser.dec().collect_variables() = true; - - if (collect_functions) - parser.dec().collect_functions() = true; - - bool pass_result = false; - - details::disable_type_checking(parser); - - if (parser.compile(expression_string, expression)) - { - pass_result = true; - - std::deque symb_list; - parser.dec().symbols(symb_list); - - for (std::size_t i = 0; i < symb_list.size(); ++i) - { - symbol_set.insert(symb_list[i].first); - } - } - - return pass_result; - } - }; - } - - template class Sequence> - inline bool collect_variables(const std::string& expression, - Sequence& symbol_list) - { - typedef double T; - typedef details::collector_helper collect_t; - - collect_t::symbol_table_t null_symbol_table; - - std::set symbol_set; - - const bool variable_pass = collect_t::collection_pass - (expression, symbol_set, true, false, false, null_symbol_table); - const bool vector_pass = collect_t::collection_pass - (expression, symbol_set, true, false, true, null_symbol_table); - - if (!variable_pass && !vector_pass) - return false; - - std::set::iterator itr = symbol_set.begin(); - - while (symbol_set.end() != itr) - { - symbol_list.push_back(*itr); - ++itr; - } - - return true; - } - - template class Sequence> - inline bool collect_variables(const std::string& expression, - exprtk::symbol_table& extrnl_symbol_table, - Sequence& symbol_list) - { - typedef details::collector_helper collect_t; - - std::set symbol_set; - - const bool variable_pass = collect_t::collection_pass - (expression, symbol_set, true, false, false, extrnl_symbol_table); - const bool vector_pass = collect_t::collection_pass - (expression, symbol_set, true, false, true, extrnl_symbol_table); - - if (!variable_pass && !vector_pass) - return false; - - std::set::iterator itr = symbol_set.begin(); - - while (symbol_set.end() != itr) - { - symbol_list.push_back(*itr); - ++itr; - } - - return true; - } - - template class Sequence> - inline bool collect_functions(const std::string& expression, - Sequence& symbol_list) - { - typedef double T; - typedef details::collector_helper collect_t; - - collect_t::symbol_table_t null_symbol_table; - - std::set symbol_set; - - const bool variable_pass = collect_t::collection_pass - (expression, symbol_set, false, true, false, null_symbol_table); - const bool vector_pass = collect_t::collection_pass - (expression, symbol_set, false, true, true, null_symbol_table); - - if (!variable_pass && !vector_pass) - return false; - - std::set::iterator itr = symbol_set.begin(); - - while (symbol_set.end() != itr) - { - symbol_list.push_back(*itr); - ++itr; - } - - return true; - } - - template class Sequence> - inline bool collect_functions(const std::string& expression, - exprtk::symbol_table& extrnl_symbol_table, - Sequence& symbol_list) - { - typedef details::collector_helper collect_t; - - std::set symbol_set; - - const bool variable_pass = collect_t::collection_pass - (expression, symbol_set, false, true, false, extrnl_symbol_table); - const bool vector_pass = collect_t::collection_pass - (expression, symbol_set, false, true, true, extrnl_symbol_table); - - if (!variable_pass && !vector_pass) - return false; - - std::set::iterator itr = symbol_set.begin(); - - while (symbol_set.end() != itr) - { - symbol_list.push_back(*itr); - ++itr; - } - - return true; - } - - template - inline T integrate(const expression& e, - T& x, - const T& r0, const T& r1, - const std::size_t number_of_intervals = 1000000) - { - if (r0 > r1) - return T(0); - - const T h = (r1 - r0) / (T(2) * number_of_intervals); - T total_area = T(0); - - for (std::size_t i = 0; i < number_of_intervals; ++i) - { - x = r0 + T(2) * i * h; - const T y0 = e.value(); x += h; - const T y1 = e.value(); x += h; - const T y2 = e.value(); x += h; - total_area += h * (y0 + T(4) * y1 + y2) / T(3); - } - - return total_area; - } - - template - inline T integrate(const expression& e, - const std::string& variable_name, - const T& r0, const T& r1, - const std::size_t number_of_intervals = 1000000) - { - const symbol_table& sym_table = e.get_symbol_table(); - - if (!sym_table.valid()) - { - return std::numeric_limits::quiet_NaN(); - } - - details::variable_node* var = sym_table.get_variable(variable_name); - - if (var) - { - T& x = var->ref(); - const T x_original = x; - const T result = integrate(e, x, r0, r1, number_of_intervals); - x = x_original; - - return result; - } - - return std::numeric_limits::quiet_NaN(); - } - - template - inline T derivative(const expression& e, - T& x, - const T& h = T(0.00000001)) - { - const T x_init = x; - const T _2h = T(2) * h; - - x = x_init + _2h; - const T y0 = e.value(); - x = x_init + h; - const T y1 = e.value(); - x = x_init - h; - const T y2 = e.value(); - x = x_init - _2h; - const T y3 = e.value(); - x = x_init; - - return (-y0 + T(8) * (y1 - y2) + y3) / (T(12) * h); - } - - template - inline T second_derivative(const expression& e, - T& x, - const T& h = T(0.00001)) - { - const T x_init = x; - const T _2h = T(2) * h; - - const T y = e.value(); - x = x_init + _2h; - const T y0 = e.value(); - x = x_init + h; - const T y1 = e.value(); - x = x_init - h; - const T y2 = e.value(); - x = x_init - _2h; - const T y3 = e.value(); - x = x_init; - - return (-y0 + T(16) * (y1 + y2) - T(30) * y - y3) / (T(12) * h * h); - } - - template - inline T third_derivative(const expression& e, - T& x, - const T& h = T(0.0001)) - { - const T x_init = x; - const T _2h = T(2) * h; - - x = x_init + _2h; - const T y0 = e.value(); - x = x_init + h; - const T y1 = e.value(); - x = x_init - h; - const T y2 = e.value(); - x = x_init - _2h; - const T y3 = e.value(); - x = x_init; - - return (y0 + T(2) * (y2 - y1) - y3) / (T(2) * h * h * h); - } - - template - inline T derivative(const expression& e, - const std::string& variable_name, - const T& h = T(0.00000001)) - { - const symbol_table& sym_table = e.get_symbol_table(); - - if (!sym_table.valid()) - { - return std::numeric_limits::quiet_NaN(); - } - - details::variable_node* var = sym_table.get_variable(variable_name); - - if (var) - { - T& x = var->ref(); - const T x_original = x; - const T result = derivative(e, x, h); - x = x_original; - - return result; - } - - return std::numeric_limits::quiet_NaN(); - } - - template - inline T second_derivative(const expression& e, - const std::string& variable_name, - const T& h = T(0.00001)) - { - const symbol_table& sym_table = e.get_symbol_table(); - - if (!sym_table.valid()) - { - return std::numeric_limits::quiet_NaN(); - } - - details::variable_node* var = sym_table.get_variable(variable_name); - - if (var) - { - T& x = var->ref(); - const T x_original = x; - const T result = second_derivative(e, x, h); - x = x_original; - - return result; - } - - return std::numeric_limits::quiet_NaN(); - } - - template - inline T third_derivative(const expression& e, - const std::string& variable_name, - const T& h = T(0.0001)) - { - const symbol_table& sym_table = e.get_symbol_table(); - - if (!sym_table.valid()) - { - return std::numeric_limits::quiet_NaN(); - } - - details::variable_node* var = sym_table.get_variable(variable_name); - - if (var) - { - T& x = var->ref(); - const T x_original = x; - const T result = third_derivative(e, x, h); - x = x_original; - - return result; - } - - return std::numeric_limits::quiet_NaN(); - } - - /* - Note: The following 'compute' routines are simple helpers, - for quickly setting up the required pieces of code in order - to evaluate an expression. By virtue of how they operate - there will be an overhead with regards to their setup and - teardown and hence should not be used in time critical - sections of code. - Furthermore they only assume a small sub set of variables, - no string variables or user defined functions. - */ - template - inline bool compute(const std::string& expression_string, T& result) - { - // No variables - symbol_table symbol_table; - symbol_table.add_constants(); - - expression expression; - expression.register_symbol_table(symbol_table); - - parser parser; - - if (parser.compile(expression_string,expression)) - { - result = expression.value(); - - return true; - } - else - return false; - } - - template - inline bool compute(const std::string& expression_string, - const T& x, - T& result) - { - // Only 'x' - static const std::string x_var("x"); - - symbol_table symbol_table; - symbol_table.add_constants(); - symbol_table.add_constant(x_var,x); - - expression expression; - expression.register_symbol_table(symbol_table); - - parser parser; - - if (parser.compile(expression_string,expression)) - { - result = expression.value(); - - return true; - } - else - return false; - } - - template - inline bool compute(const std::string& expression_string, - const T&x, const T& y, - T& result) - { - // Only 'x' and 'y' - static const std::string x_var("x"); - static const std::string y_var("y"); - - symbol_table symbol_table; - symbol_table.add_constants(); - symbol_table.add_constant(x_var,x); - symbol_table.add_constant(y_var,y); - - expression expression; - expression.register_symbol_table(symbol_table); - - parser parser; - - if (parser.compile(expression_string,expression)) - { - result = expression.value(); - - return true; - } - else - return false; - } - - template - inline bool compute(const std::string& expression_string, - const T& x, const T& y, const T& z, - T& result) - { - // Only 'x', 'y' or 'z' - static const std::string x_var("x"); - static const std::string y_var("y"); - static const std::string z_var("z"); - - symbol_table symbol_table; - symbol_table.add_constants(); - symbol_table.add_constant(x_var,x); - symbol_table.add_constant(y_var,y); - symbol_table.add_constant(z_var,z); - - expression expression; - expression.register_symbol_table(symbol_table); - - parser parser; - - if (parser.compile(expression_string,expression)) - { - result = expression.value(); - - return true; - } - else - return false; - } - - template - class polynomial : public ifunction - { - private: - - template - struct poly_impl { }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c12, const Type c11, const Type c10, const Type c9, const Type c8, - const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, - const Type c2, const Type c1, const Type c0) - { - // p(x) = c_12x^12 + c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((((((((((c12 * x + c11) * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c11, const Type c10, const Type c9, const Type c8, const Type c7, - const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, - const Type c1, const Type c0) - { - // p(x) = c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((((((((((c11 * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c10, const Type c9, const Type c8, const Type c7, const Type c6, - const Type c5, const Type c4, const Type c3, const Type c2, const Type c1, - const Type c0) - { - // p(x) = c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((((((((c10 * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c9, const Type c8, const Type c7, const Type c6, const Type c5, - const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((((((((c9 * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c8, const Type c7, const Type c6, const Type c5, const Type c4, - const Type c3, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((((((c8 * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, - const Type c2, const Type c1, const Type c0) - { - // p(x) = c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((((((c7 * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, - const Type c1, const Type c0) - { - // p(x) = c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((((c6 * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c5, const Type c4, const Type c3, const Type c2, - const Type c1, const Type c0) - { - // p(x) = c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((((c5 * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((c4 * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, const Type c3, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((c3 * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_2x^2 + c_1x^1 + c_0x^0 - return ((c2 * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, const Type c1, const Type c0) - { - // p(x) = c_1x^1 + c_0x^0 - return (c1 * x + c0); - } - }; - - public: - - using ifunction::operator(); - - polynomial() - : ifunction((N+2 <= 20) ? (N + 2) : std::numeric_limits::max()) - { - disable_has_side_effects(*this); - } - - virtual ~polynomial() - {} - - #define poly_rtrn(NN) \ - return (NN != N) ? std::numeric_limits::quiet_NaN() : - - inline virtual T operator() (const T& x, const T& c1, const T& c0) exprtk_override - { - poly_rtrn(1) (poly_impl::evaluate(x, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) exprtk_override - { - poly_rtrn(2) (poly_impl::evaluate(x, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override - { - poly_rtrn(3) (poly_impl::evaluate(x, c3, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1, - const T& c0) exprtk_override - { - poly_rtrn(4) (poly_impl::evaluate(x, c4, c3, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2, - const T& c1, const T& c0) exprtk_override - { - poly_rtrn(5) (poly_impl::evaluate(x, c5, c4, c3, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3, - const T& c2, const T& c1, const T& c0) exprtk_override - { - poly_rtrn(6) (poly_impl::evaluate(x, c6, c5, c4, c3, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4, - const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override - { - poly_rtrn(7) (poly_impl::evaluate(x, c7, c6, c5, c4, c3, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5, - const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override - { - poly_rtrn(8) (poly_impl::evaluate(x, c8, c7, c6, c5, c4, c3, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6, - const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, - const T& c0) exprtk_override - { - poly_rtrn(9) (poly_impl::evaluate(x, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7, - const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, - const T& c1, const T& c0) exprtk_override - { - poly_rtrn(10) (poly_impl::evaluate(x, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8, - const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, - const T& c2, const T& c1, const T& c0) exprtk_override - { - poly_rtrn(11) (poly_impl::evaluate(x, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); - } - - inline virtual T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9, - const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, - const T& c3, const T& c2, const T& c1, const T& c0) exprtk_override - { - poly_rtrn(12) (poly_impl::evaluate(x, c12, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); - } - - #undef poly_rtrn - - inline virtual T operator() () exprtk_override - { - return std::numeric_limits::quiet_NaN(); - } - - inline virtual T operator() (const T&) exprtk_override - { - return std::numeric_limits::quiet_NaN(); - } - - inline virtual T operator() (const T&, const T&) exprtk_override - { - return std::numeric_limits::quiet_NaN(); - } - }; - - template - class function_compositor - { - public: - - typedef exprtk::expression expression_t; - typedef exprtk::symbol_table symbol_table_t; - typedef exprtk::parser parser_t; - typedef typename parser_t::settings_store settings_t; - - struct function - { - function() - {} - - function(const std::string& n) - : name_(n) - {} - - function(const std::string& name, - const std::string& expression) - : name_(name) - , expression_(expression) - {} - - function(const std::string& name, - const std::string& expression, - const std::string& v0) - : name_(name) - , expression_(expression) - { - v_.push_back(v0); - } - - function(const std::string& name, - const std::string& expression, - const std::string& v0, const std::string& v1) - : name_(name) - , expression_(expression) - { - v_.push_back(v0); v_.push_back(v1); - } - - function(const std::string& name, - const std::string& expression, - const std::string& v0, const std::string& v1, - const std::string& v2) - : name_(name) - , expression_(expression) - { - v_.push_back(v0); v_.push_back(v1); - v_.push_back(v2); - } - - function(const std::string& name, - const std::string& expression, - const std::string& v0, const std::string& v1, - const std::string& v2, const std::string& v3) - : name_(name) - , expression_(expression) - { - v_.push_back(v0); v_.push_back(v1); - v_.push_back(v2); v_.push_back(v3); - } - - function(const std::string& name, - const std::string& expression, - const std::string& v0, const std::string& v1, - const std::string& v2, const std::string& v3, - const std::string& v4) - : name_(name) - , expression_(expression) - { - v_.push_back(v0); v_.push_back(v1); - v_.push_back(v2); v_.push_back(v3); - v_.push_back(v4); - } - - inline function& name(const std::string& n) - { - name_ = n; - return (*this); - } - - inline function& expression(const std::string& e) - { - expression_ = e; - return (*this); - } - - inline function& var(const std::string& v) - { - v_.push_back(v); - return (*this); - } - - inline function& vars(const std::string& v0, - const std::string& v1) - { - v_.push_back(v0); - v_.push_back(v1); - return (*this); - } - - inline function& vars(const std::string& v0, - const std::string& v1, - const std::string& v2) - { - v_.push_back(v0); - v_.push_back(v1); - v_.push_back(v2); - return (*this); - } - - inline function& vars(const std::string& v0, - const std::string& v1, - const std::string& v2, - const std::string& v3) - { - v_.push_back(v0); - v_.push_back(v1); - v_.push_back(v2); - v_.push_back(v3); - return (*this); - } - - inline function& vars(const std::string& v0, - const std::string& v1, - const std::string& v2, - const std::string& v3, - const std::string& v4) - { - v_.push_back(v0); - v_.push_back(v1); - v_.push_back(v2); - v_.push_back(v3); - v_.push_back(v4); - return (*this); - } - - std::string name_; - std::string expression_; - std::deque v_; - }; - - private: - - struct base_func : public exprtk::ifunction - { - typedef const T& type; - typedef exprtk::ifunction function_t; - typedef std::vector varref_t; - typedef std::vector var_t; - typedef std::vector str_t; - typedef std::pair lvarref_t; - typedef std::vector lvr_vec_t; - typedef std::vector lstr_vec_t; - - using exprtk::ifunction::operator(); - - base_func(const std::size_t& pc = 0) - : exprtk::ifunction(pc) - , local_var_stack_size(0) - , stack_depth(0) - { - v.resize(pc); - } - - virtual ~base_func() - {} - - #define exprtk_assign(Index) \ - (*v[Index]) = v##Index; \ - - inline void update(const T& v0) - { - exprtk_assign(0) - } - - inline void update(const T& v0, const T& v1) - { - exprtk_assign(0) exprtk_assign(1) - } - - inline void update(const T& v0, const T& v1, const T& v2) - { - exprtk_assign(0) exprtk_assign(1) - exprtk_assign(2) - } - - inline void update(const T& v0, const T& v1, const T& v2, const T& v3) - { - exprtk_assign(0) exprtk_assign(1) - exprtk_assign(2) exprtk_assign(3) - } - - inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) - { - exprtk_assign(0) exprtk_assign(1) - exprtk_assign(2) exprtk_assign(3) - exprtk_assign(4) - } - - inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) - { - exprtk_assign(0) exprtk_assign(1) - exprtk_assign(2) exprtk_assign(3) - exprtk_assign(4) exprtk_assign(5) - } - - #ifdef exprtk_assign - #undef exprtk_assign - #endif - - inline function_t& setup(expression_t& expr) - { - expression = expr; - - typedef typename expression_t::control_block ctrlblk_t; - typedef typename ctrlblk_t::local_data_list_t ldl_t; - typedef typename ctrlblk_t::data_type data_t; - typedef typename ldl_t::value_type ldl_value_type; - - const ldl_t ldl = expr.local_data_list(); - - std::vector > index_list; - - for (std::size_t i = 0; i < ldl.size(); ++i) - { - exprtk_debug(("base_func::setup() - element[%02d] type: %s size: %d\n", - static_cast(i), - expression_t::control_block::to_str(ldl[i].type).c_str(), - static_cast(ldl[i].size))); - - switch (ldl[i].type) - { - case ctrlblk_t::e_unknown : continue; - case ctrlblk_t::e_expr : continue; - case ctrlblk_t::e_vecholder : continue; - default : break; - } - - if (ldl[i].size) - { - index_list.push_back(std::make_pair(i,ldl[i].type)); - } - } - - std::size_t input_param_count = 0; - - for (std::size_t i = 0; i < index_list.size(); ++i) - { - const std::size_t index = index_list[i].first; - const ldl_value_type& local_var = ldl[index]; - - assert(local_var.pointer); - - if (i < (index_list.size() - v.size())) - { - if (local_var.type == ctrlblk_t::e_string) - { - local_str_vars.push_back( - reinterpret_cast(local_var.pointer)); - } - else if ( - (local_var.type == ctrlblk_t::e_data ) || - (local_var.type == ctrlblk_t::e_vecdata) - ) - { - local_vars.push_back(std::make_pair( - reinterpret_cast(local_var.pointer), - local_var.size)); - - local_var_stack_size += local_var.size; - } - } - else - { - v[input_param_count++] = reinterpret_cast(local_var.pointer); - } - } - - clear_stack(); - - return (*this); - } - - inline void pre() - { - if (stack_depth++) - { - if (!v.empty()) - { - var_t var_stack(v.size(),T(0)); - copy(v,var_stack); - input_params_stack.push_back(var_stack); - } - - if (!local_vars.empty()) - { - var_t local_vec_frame(local_var_stack_size,T(0)); - copy(local_vars,local_vec_frame); - local_var_stack.push_back(local_vec_frame); - } - - if (!local_str_vars.empty()) - { - str_t local_str_frame(local_str_vars.size()); - copy(local_str_vars,local_str_frame); - local_str_stack.push_back(local_str_frame); - } - } - } - - inline void post() - { - if (--stack_depth) - { - if (!v.empty()) - { - copy(input_params_stack.back(), v); - input_params_stack.pop_back(); - } - - if (!local_vars.empty()) - { - copy(local_var_stack.back(), local_vars); - local_var_stack.pop_back(); - } - - if (!local_str_vars.empty()) - { - copy(local_str_stack.back(), local_str_vars); - local_str_stack.pop_back(); - } - } - } - - void copy(const varref_t& src_v, var_t& dest_v) - { - for (std::size_t i = 0; i < src_v.size(); ++i) - { - dest_v[i] = (*src_v[i]); - } - } - - void copy(const lstr_vec_t& src_v, str_t& dest_v) - { - for (std::size_t i = 0; i < src_v.size(); ++i) - { - dest_v[i] = (*src_v[i]); - } - } - - void copy(const var_t& src_v, varref_t& dest_v) - { - for (std::size_t i = 0; i < src_v.size(); ++i) - { - (*dest_v[i]) = src_v[i]; - } - } - - void copy(const lvr_vec_t& src_v, var_t& dest_v) - { - typename var_t::iterator itr = dest_v.begin(); - typedef typename std::iterator_traits::difference_type diff_t; - - for (std::size_t i = 0; i < src_v.size(); ++i) - { - lvarref_t vr = src_v[i]; - - if (1 == vr.second) - *itr++ = (*vr.first); - else - { - std::copy(vr.first, vr.first + vr.second, itr); - itr += static_cast(vr.second); - } - } - } - - void copy(const var_t& src_v, lvr_vec_t& dest_v) - { - typename var_t::const_iterator itr = src_v.begin(); - typedef typename std::iterator_traits::difference_type diff_t; - - for (std::size_t i = 0; i < dest_v.size(); ++i) - { - lvarref_t& vr = dest_v[i]; - - assert(vr.first != 0); - assert(vr.second > 0); - - if (1 == vr.second) - (*vr.first) = *itr++; - else - { - std::copy(itr, itr + static_cast(vr.second), vr.first); - itr += static_cast(vr.second); - } - } - } - - void copy(const str_t& src_str, lstr_vec_t& dest_str) - { - assert(src_str.size() == dest_str.size()); - - for (std::size_t i = 0; i < dest_str.size(); ++i) - { - *dest_str[i] = src_str[i]; - } - } - - inline void clear_stack() - { - for (std::size_t i = 0; i < v.size(); ++i) - { - (*v[i]) = 0; - } - } - - inline virtual T value(expression_t& e) - { - return e.value(); - } - - expression_t expression; - varref_t v; - lvr_vec_t local_vars; - lstr_vec_t local_str_vars; - std::size_t local_var_stack_size; - std::size_t stack_depth; - std::deque input_params_stack; - std::deque local_var_stack; - std::deque local_str_stack; - }; - - typedef std::map funcparam_t; - - typedef const T& type; - - template - struct scoped_bft - { - explicit scoped_bft(BaseFuncType& bft) - : bft_(bft) - { - bft_.pre (); - } - - ~scoped_bft() - { - bft_.post(); - } - - BaseFuncType& bft_; - - private: - - scoped_bft(const scoped_bft&) exprtk_delete; - scoped_bft& operator=(const scoped_bft&) exprtk_delete; - }; - - struct func_0param : public base_func - { - using exprtk::ifunction::operator(); - - func_0param() : base_func(0) {} - - inline T operator() () exprtk_override - { - scoped_bft sb(*this); - return this->value(base_func::expression); - } - }; - - struct func_1param : public base_func - { - using exprtk::ifunction::operator(); - - func_1param() : base_func(1) {} - - inline T operator() (type v0) exprtk_override - { - scoped_bft sb(*this); - base_func::update(v0); - return this->value(base_func::expression); - } - }; - - struct func_2param : public base_func - { - using exprtk::ifunction::operator(); - - func_2param() : base_func(2) {} - - inline T operator() (type v0, type v1) exprtk_override - { - scoped_bft sb(*this); - base_func::update(v0, v1); - return this->value(base_func::expression); - } - }; - - struct func_3param : public base_func - { - using exprtk::ifunction::operator(); - - func_3param() : base_func(3) {} - - inline T operator() (type v0, type v1, type v2) exprtk_override - { - scoped_bft sb(*this); - base_func::update(v0, v1, v2); - return this->value(base_func::expression); - } - }; - - struct func_4param : public base_func - { - using exprtk::ifunction::operator(); - - func_4param() : base_func(4) {} - - inline T operator() (type v0, type v1, type v2, type v3) exprtk_override - { - scoped_bft sb(*this); - base_func::update(v0, v1, v2, v3); - return this->value(base_func::expression); - } - }; - - struct func_5param : public base_func - { - using exprtk::ifunction::operator(); - - func_5param() : base_func(5) {} - - inline T operator() (type v0, type v1, type v2, type v3, type v4) exprtk_override - { - scoped_bft sb(*this); - base_func::update(v0, v1, v2, v3, v4); - return this->value(base_func::expression); - } - }; - - struct func_6param : public base_func - { - using exprtk::ifunction::operator(); - - func_6param() : base_func(6) {} - - inline T operator() (type v0, type v1, type v2, type v3, type v4, type v5) exprtk_override - { - scoped_bft sb(*this); - base_func::update(v0, v1, v2, v3, v4, v5); - return this->value(base_func::expression); - } - }; - - static T return_value(expression_t& e) - { - typedef exprtk::results_context results_context_t; - typedef typename results_context_t::type_store_t type_t; - typedef typename type_t::scalar_view scalar_t; - - const T result = e.value(); - - if (e.return_invoked()) - { - // Due to the post compilation checks, it can be safely - // assumed that there will be at least one parameter - // and that the first parameter will always be scalar. - return scalar_t(e.results()[0])(); - } - - return result; - } - - #define def_fp_retval(N) \ - struct func_##N##param_retval exprtk_final : public func_##N##param \ - { \ - inline T value(expression_t& e) exprtk_override \ - { \ - return return_value(e); \ - } \ - }; \ - - def_fp_retval(0) - def_fp_retval(1) - def_fp_retval(2) - def_fp_retval(3) - def_fp_retval(4) - def_fp_retval(5) - def_fp_retval(6) - - #undef def_fp_retval - - template class Sequence> - inline bool add(const std::string& name, - const std::string& expression, - const Sequence& var_list, - const bool override = false) - { - const typename std::map::iterator itr = expr_map_.find(name); - - if (expr_map_.end() != itr) - { - if (!override) - { - exprtk_debug(("Compositor error(add): function '%s' already defined\n", - name.c_str())); - - return false; - } - - remove(name, var_list.size()); - } - - if (compile_expression(name, expression, var_list)) - { - const std::size_t n = var_list.size(); - - fp_map_[n][name]->setup(expr_map_[name]); - - return true; - } - else - { - exprtk_debug(("Compositor error(add): Failed to compile function '%s'\n", - name.c_str())); - - return false; - } - } - - public: - - function_compositor() - : parser_(settings_t::default_compile_all_opts + - settings_t::e_disable_zero_return) - , fp_map_(7) - , load_variables_(false) - , load_vectors_(false) - {} - - explicit function_compositor(const symbol_table_t& st) - : symbol_table_(st) - , parser_(settings_t::default_compile_all_opts + - settings_t::e_disable_zero_return) - , fp_map_(7) - , load_variables_(false) - , load_vectors_(false) - {} - - ~function_compositor() - { - clear(); - } - - inline symbol_table_t& symbol_table() - { - return symbol_table_; - } - - inline const symbol_table_t& symbol_table() const - { - return symbol_table_; - } - - inline void add_auxiliary_symtab(symbol_table_t& symtab) - { - auxiliary_symtab_list_.push_back(&symtab); - } - - void load_variables(const bool load = true) - { - load_variables_ = load; - } - - void load_vectors(const bool load = true) - { - load_vectors_ = load; - } - - inline void register_loop_runtime_check(loop_runtime_check& lrtchk) - { - parser_.register_loop_runtime_check(lrtchk); - } - - inline void register_vector_access_runtime_check(vector_access_runtime_check& vartchk) - { - parser_.register_vector_access_runtime_check(vartchk); - } - - inline void register_compilation_timeout_check(compilation_check& compchk) - { - parser_.register_compilation_timeout_check(compchk); - } - - inline void clear_loop_runtime_check() - { - parser_.clear_loop_runtime_check(); - } - - inline void clear_vector_access_runtime_check() - { - parser_.clear_vector_access_runtime_check(); - } - - inline void clear_compilation_timeout_check() - { - parser_.clear_compilation_timeout_check(); - } - - void clear() - { - symbol_table_.clear(); - expr_map_ .clear(); - - for (std::size_t i = 0; i < fp_map_.size(); ++i) - { - typename funcparam_t::iterator itr = fp_map_[i].begin(); - typename funcparam_t::iterator end = fp_map_[i].end (); - - while (itr != end) - { - delete itr->second; - ++itr; - } - - fp_map_[i].clear(); - } - - clear_loop_runtime_check (); - clear_vector_access_runtime_check(); - clear_compilation_timeout_check (); - } - - inline bool add(const function& f, const bool override = false) - { - return add(f.name_, f.expression_, f.v_,override); - } - - inline std::string error() const - { - if (!error_list_.empty()) - { - return error_list_[0].diagnostic; - } - else - return std::string("No Error"); - } - - inline std::size_t error_count() const - { - return error_list_.size(); - } - - inline parser_error::type get_error(const std::size_t& index) const - { - if (index < error_list_.size()) - { - return error_list_[index]; - } - - throw std::invalid_argument("compositor::get_error() - Invalid error index specified"); - } - - private: - - template class Sequence> - bool compile_expression(const std::string& name, - const std::string& expression, - const Sequence& input_var_list, - bool return_present = false) - { - expression_t compiled_expression; - symbol_table_t local_symbol_table; - - local_symbol_table.load_from(symbol_table_); - local_symbol_table.add_constants(); - - if (load_variables_) - { - local_symbol_table.load_variables_from(symbol_table_); - } - - if (load_vectors_) - { - local_symbol_table.load_vectors_from(symbol_table_); - } - - error_list_.clear(); - - if (!valid(name,input_var_list.size())) - { - parser_error::type error = - parser_error::make_error( - parser_error::e_parser, - lexer::token(), - "ERR277 - Function '" + name + "' is an invalid overload", - exprtk_error_location); - - error_list_.push_back(error); - return false; - } - - if (!forward(name, - input_var_list.size(), - local_symbol_table, - return_present)) - return false; - - compiled_expression.register_symbol_table(local_symbol_table); - - for (std::size_t i = 0; i < auxiliary_symtab_list_.size(); ++i) - { - compiled_expression.register_symbol_table((*auxiliary_symtab_list_[i])); - } - - std::string mod_expression; - - for (std::size_t i = 0; i < input_var_list.size(); ++i) - { - mod_expression += " var " + input_var_list[i] + "{};\n"; - } - - if ( - ('{' == details::front(expression)) && - ('}' == details::back (expression)) - ) - mod_expression += "~" + expression + ";"; - else - mod_expression += "~{" + expression + "};"; - - if (!parser_.compile(mod_expression,compiled_expression)) - { - exprtk_debug(("Compositor Error: %s\n", parser_.error().c_str())); - exprtk_debug(("Compositor modified expression: \n%s\n", mod_expression.c_str())); - - remove(name,input_var_list.size()); - - for (std::size_t err_index = 0; err_index < parser_.error_count(); ++err_index) - { - error_list_.push_back(parser_.get_error(err_index)); - } - - return false; - } - - if (!return_present && parser_.dec().return_present()) - { - remove(name,input_var_list.size()); - return compile_expression(name, expression, input_var_list, true); - } - - // Make sure every return point has a scalar as its first parameter - if (parser_.dec().return_present()) - { - typedef std::vector str_list_t; - - str_list_t ret_param_list = parser_.dec().return_param_type_list(); - - for (std::size_t i = 0; i < ret_param_list.size(); ++i) - { - const std::string& params = ret_param_list[i]; - - if (params.empty() || ('T' != params[0])) - { - exprtk_debug(("Compositor Error: Return statement in function '%s' is invalid\n", - name.c_str())); - - remove(name,input_var_list.size()); - - return false; - } - } - } - - expr_map_[name] = compiled_expression; - - exprtk::ifunction& ifunc = (*(fp_map_[input_var_list.size()])[name]); - - if (symbol_table_.add_function(name,ifunc)) - return true; - else - { - exprtk_debug(("Compositor Error: Failed to add function '%s' to symbol table\n", - name.c_str())); - return false; - } - } - - inline bool symbol_used(const std::string& symbol) const - { - return ( - symbol_table_.is_variable (symbol) || - symbol_table_.is_stringvar (symbol) || - symbol_table_.is_function (symbol) || - symbol_table_.is_vector (symbol) || - symbol_table_.is_vararg_function(symbol) - ); - } - - inline bool valid(const std::string& name, - const std::size_t& arg_count) const - { - if (arg_count > 6) - return false; - else if (symbol_used(name)) - return false; - else if (fp_map_[arg_count].end() != fp_map_[arg_count].find(name)) - return false; - else - return true; - } - - inline bool forward(const std::string& name, - const std::size_t& arg_count, - symbol_table_t& sym_table, - const bool ret_present = false) - { - switch (arg_count) - { - #define case_stmt(N) \ - case N : (fp_map_[arg_count])[name] = \ - (!ret_present) ? static_cast \ - (new func_##N##param) : \ - static_cast \ - (new func_##N##param_retval) ; \ - break; \ - - case_stmt(0) case_stmt(1) case_stmt(2) - case_stmt(3) case_stmt(4) case_stmt(5) - case_stmt(6) - #undef case_stmt - } - - exprtk::ifunction& ifunc = (*(fp_map_[arg_count])[name]); - - return sym_table.add_function(name,ifunc); - } - - inline void remove(const std::string& name, const std::size_t& arg_count) - { - if (arg_count > 6) - return; - - const typename std::map::iterator em_itr = expr_map_.find(name); - - if (expr_map_.end() != em_itr) - { - expr_map_.erase(em_itr); - } - - const typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); - - if (fp_map_[arg_count].end() != fp_itr) - { - delete fp_itr->second; - fp_map_[arg_count].erase(fp_itr); - } - - symbol_table_.remove_function(name); - } - - private: - - symbol_table_t symbol_table_; - parser_t parser_; - std::map expr_map_; - std::vector fp_map_; - std::vector auxiliary_symtab_list_; - std::deque error_list_; - bool load_variables_; - bool load_vectors_; - }; // class function_compositor - -} // namespace exprtk - -#if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) -# ifndef NOMINMAX -# define NOMINMAX -# endif -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# include -#else -# include -# include -# include -#endif - -namespace exprtk -{ - class timer - { - public: - - #if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) - timer() - : in_use_(false) - , start_time_{ {0, 0} } - , stop_time_ { {0, 0} } - { - QueryPerformanceFrequency(&clock_frequency_); - } - - inline void start() - { - in_use_ = true; - QueryPerformanceCounter(&start_time_); - } - - inline void stop() - { - QueryPerformanceCounter(&stop_time_); - in_use_ = false; - } - - inline double time() const - { - return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart); - } - - #else - - timer() - : in_use_(false) - { - start_time_.tv_sec = 0; - start_time_.tv_usec = 0; - - stop_time_.tv_sec = 0; - stop_time_.tv_usec = 0; - } - - inline void start() - { - in_use_ = true; - gettimeofday(&start_time_,0); - } - - inline void stop() - { - gettimeofday(&stop_time_, 0); - in_use_ = false; - } - - inline unsigned long long int usec_time() const - { - if (!in_use_) - { - if (stop_time_.tv_sec >= start_time_.tv_sec) - { - return 1000000LLU * static_cast(stop_time_.tv_sec - start_time_.tv_sec ) + - static_cast(stop_time_.tv_usec - start_time_.tv_usec) ; - } - else - return std::numeric_limits::max(); - } - else - return std::numeric_limits::max(); - } - - inline double time() const - { - return usec_time() * 0.000001; - } - - #endif - - inline bool in_use() const - { - return in_use_; - } - - private: - - bool in_use_; - - #if defined(_MSC_VER) || defined(_WIN32) || defined(__WIN32__) || defined(WIN32) - LARGE_INTEGER start_time_; - LARGE_INTEGER stop_time_; - LARGE_INTEGER clock_frequency_; - #else - struct timeval start_time_; - struct timeval stop_time_; - #endif - }; - - template - struct type_defs - { - typedef symbol_table symbol_table_t; - typedef expression expression_t; - typedef parser parser_t; - typedef parser_error::type error_t; - typedef function_compositor compositor_t; - typedef typename compositor_t::function function_t; - }; - -} // namespace exprtk - -#ifndef exprtk_disable_rtl_io -namespace exprtk -{ - namespace rtl { namespace io { namespace details - { - template - inline void print_type(const std::string& fmt, - const T v, - exprtk::details::numeric::details::real_type_tag) - { - #if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wformat-nonliteral" - #elif defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wformat-nonliteral" - #elif defined(_MSC_VER) - #endif - - printf(fmt.c_str(), v); - - #if defined(__clang__) - #pragma clang diagnostic pop - #elif defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic pop - #elif defined(_MSC_VER) - #endif - } - - template - struct print_impl - { - typedef typename igeneric_function::generic_type generic_type; - typedef typename igeneric_function::parameter_list_t parameter_list_t; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - typedef typename generic_type::string_view string_t; - typedef typename exprtk::details::numeric::details::number_type::type num_type; - - static void process(const std::string& scalar_format, parameter_list_t parameters) - { - for (std::size_t i = 0; i < parameters.size(); ++i) - { - generic_type& gt = parameters[i]; - - switch (gt.type) - { - case generic_type::e_scalar : print(scalar_format,scalar_t(gt)); - break; - - case generic_type::e_vector : print(scalar_format,vector_t(gt)); - break; - - case generic_type::e_string : print(string_t(gt)); - break; - - default : continue; - } - } - } - - static inline void print(const std::string& scalar_format, const scalar_t& s) - { - print_type(scalar_format,s(),num_type()); - } - - static inline void print(const std::string& scalar_format, const vector_t& v) - { - for (std::size_t i = 0; i < v.size(); ++i) - { - print_type(scalar_format,v[i],num_type()); - - if ((i + 1) < v.size()) - printf(" "); - } - } - - static inline void print(const string_t& s) - { - printf("%s",to_str(s).c_str()); - } - }; - - } // namespace exprtk::rtl::io::details - - template - struct print exprtk_final : public exprtk::igeneric_function - { - typedef typename igeneric_function::parameter_list_t parameter_list_t; - - using exprtk::igeneric_function::operator(); - - explicit print(const std::string& scalar_format = "%10.5f") - : scalar_format_(scalar_format) - { - exprtk::enable_zero_parameters(*this); - } - - inline T operator() (parameter_list_t parameters) exprtk_override - { - details::print_impl::process(scalar_format_,parameters); - return T(0); - } - - std::string scalar_format_; - }; - - template - struct println exprtk_final : public exprtk::igeneric_function - { - typedef typename igeneric_function::parameter_list_t parameter_list_t; - - using exprtk::igeneric_function::operator(); - - explicit println(const std::string& scalar_format = "%10.5f") - : scalar_format_(scalar_format) - { - exprtk::enable_zero_parameters(*this); - } - - inline T operator() (parameter_list_t parameters) exprtk_override - { - details::print_impl::process(scalar_format_,parameters); - printf("\n"); - return T(0); - } - - std::string scalar_format_; - }; - - template - struct package - { - print p; - println pl; - - bool register_package(exprtk::symbol_table& symtab) - { - #define exprtk_register_function(FunctionName, FunctionType) \ - if (!symtab.add_function(FunctionName,FunctionType)) \ - { \ - exprtk_debug(( \ - "exprtk::rtl::io::register_package - Failed to add function: %s\n", \ - FunctionName)); \ - return false; \ - } \ - - exprtk_register_function("print" , p ) - exprtk_register_function("println", pl) - #undef exprtk_register_function - - return true; - } - }; - - } // namespace exprtk::rtl::io - } // namespace exprtk::rtl -} // namespace exprtk -#endif - -#ifndef exprtk_disable_rtl_io_file -#include -namespace exprtk -{ - namespace rtl { namespace io { namespace file { namespace details - { - using ::exprtk::details::char_ptr; - using ::exprtk::details::char_cptr; - - enum file_mode - { - e_error = 0, - e_read = 1, - e_write = 2, - e_rdwrt = 4 - }; - - struct file_descriptor - { - file_descriptor(const std::string& fname, const std::string& access) - : stream_ptr(0) - , mode(get_file_mode(access)) - , file_name(fname) - {} - - void* stream_ptr; - file_mode mode; - std::string file_name; - - bool open() - { - if (e_read == mode) - { - std::ifstream* stream = new std::ifstream(file_name.c_str(),std::ios::binary); - - if (!(*stream)) - { - file_name.clear(); - delete stream; - - return false; - } - - stream_ptr = stream; - - return true; - } - else if (e_write == mode) - { - std::ofstream* stream = new std::ofstream(file_name.c_str(),std::ios::binary); - - if (!(*stream)) - { - file_name.clear(); - delete stream; - - return false; - } - - stream_ptr = stream; - - return true; - } - else if (e_rdwrt == mode) - { - std::fstream* stream = new std::fstream(file_name.c_str(),std::ios::binary); - - if (!(*stream)) - { - file_name.clear(); - delete stream; - - return false; - } - - stream_ptr = stream; - - return true; - } - - return false; - } - - template - void close(Ptr& p) - { - Stream* stream = reinterpret_cast(p); - stream->close(); - delete stream; - p = reinterpret_cast(0); - } - - bool close() - { - switch (mode) - { - case e_read : close(stream_ptr); - break; - - case e_write : close(stream_ptr); - break; - - case e_rdwrt : close (stream_ptr); - break; - - default : return false; - } - - return true; - } - - template - bool write(const View& view, const std::size_t amount, const std::size_t offset = 0) - { - switch (mode) - { - case e_write : reinterpret_cast(stream_ptr)-> - write(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); - break; - - case e_rdwrt : reinterpret_cast(stream_ptr)-> - write(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); - break; - - default : return false; - } - - return true; - } - - template - bool read(View& view, const std::size_t amount, const std::size_t offset = 0) - { - switch (mode) - { - case e_read : reinterpret_cast(stream_ptr)-> - read(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); - break; - - case e_rdwrt : reinterpret_cast(stream_ptr)-> - read(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); - break; - - default : return false; - } - - return true; - } - - bool getline(std::string& s) - { - switch (mode) - { - case e_read : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); - case e_rdwrt : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); - default : return false; - } - } - - bool eof() const - { - switch (mode) - { - case e_read : return reinterpret_cast(stream_ptr)->eof(); - case e_write : return reinterpret_cast(stream_ptr)->eof(); - case e_rdwrt : return reinterpret_cast(stream_ptr)->eof(); - default : return true; - } - } - - file_mode get_file_mode(const std::string& access) const - { - if (access.empty() || access.size() > 2) - return e_error; - - std::size_t w_cnt = 0; - std::size_t r_cnt = 0; - - for (std::size_t i = 0; i < access.size(); ++i) - { - switch (std::tolower(access[i])) - { - case 'r' : r_cnt++; break; - case 'w' : w_cnt++; break; - default : return e_error; - } - } - - if ((0 == r_cnt) && (0 == w_cnt)) - return e_error; - else if ((r_cnt > 1) || (w_cnt > 1)) - return e_error; - else if ((1 == r_cnt) && (1 == w_cnt)) - return e_rdwrt; - else if (1 == r_cnt) - return e_read; - else - return e_write; - } - }; - - template - file_descriptor* make_handle(T v) - { - const std::size_t fd_size = sizeof(details::file_descriptor*); - details::file_descriptor* fd = reinterpret_cast(0); - - std::memcpy(reinterpret_cast(&fd), - reinterpret_cast(&v ), - fd_size); - return fd; - } - - template - void perform_check() - { - #ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable: 4127) - #endif - if (sizeof(T) < sizeof(void*)) - { - throw std::runtime_error("exprtk::rtl::io::file - Error - pointer size larger than holder."); - } - #ifdef _MSC_VER - #pragma warning(pop) - #endif - assert(sizeof(T) <= sizeof(void*)); - } - - } // namespace exprtk::rtl::io::file::details - - template - class open exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - - using igfun_t::operator(); - - open() - : exprtk::igeneric_function("S|SS") - { details::perform_check(); } - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const std::string file_name = to_str(string_t(parameters[0])); - - if (file_name.empty()) - { - return T(0); - } - - if ((1 == ps_index) && (0 == string_t(parameters[1]).size())) - { - return T(0); - } - - const std::string access = - (0 == ps_index) ? "r" : to_str(string_t(parameters[1])); - - details::file_descriptor* fd = new details::file_descriptor(file_name,access); - - if (fd->open()) - { - T t = T(0); - - const std::size_t fd_size = sizeof(details::file_descriptor*); - - std::memcpy(reinterpret_cast(&t ), - reinterpret_cast(&fd), - fd_size); - return t; - } - else - { - delete fd; - return T(0); - } - } - }; - - template - struct close exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - close() - : exprtk::ifunction(1) - { details::perform_check(); } - - inline T operator() (const T& v) exprtk_override - { - details::file_descriptor* fd = details::make_handle(v); - - if (!fd->close()) - return T(0); - - delete fd; - - return T(1); - } - }; - - template - class write exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - write() - : igfun_t("TS|TST|TV|TVT") - { details::perform_check(); } - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); - - switch (ps_index) - { - case 0 : { - const string_t buffer(parameters[1]); - const std::size_t amount = buffer.size(); - return T(fd->write(buffer, amount) ? 1 : 0); - } - - case 1 : { - const string_t buffer(parameters[1]); - const std::size_t amount = - std::min(buffer.size(), - static_cast(scalar_t(parameters[2])())); - return T(fd->write(buffer, amount) ? 1 : 0); - } - - case 2 : { - const vector_t vec(parameters[1]); - const std::size_t amount = vec.size(); - return T(fd->write(vec, amount) ? 1 : 0); - } - - case 3 : { - const vector_t vec(parameters[1]); - const std::size_t amount = - std::min(vec.size(), - static_cast(scalar_t(parameters[2])())); - return T(fd->write(vec, amount) ? 1 : 0); - } - } - - return T(0); - } - }; - - template - class read exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - read() - : igfun_t("TS|TST|TV|TVT") - { details::perform_check(); } - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); - - switch (ps_index) - { - case 0 : { - string_t buffer(parameters[1]); - const std::size_t amount = buffer.size(); - return T(fd->read(buffer,amount) ? 1 : 0); - } - - case 1 : { - string_t buffer(parameters[1]); - const std::size_t amount = - std::min(buffer.size(), - static_cast(scalar_t(parameters[2])())); - return T(fd->read(buffer,amount) ? 1 : 0); - } - - case 2 : { - vector_t vec(parameters[1]); - const std::size_t amount = vec.size(); - return T(fd->read(vec,amount) ? 1 : 0); - } - - case 3 : { - vector_t vec(parameters[1]); - const std::size_t amount = - std::min(vec.size(), - static_cast(scalar_t(parameters[2])())); - return T(fd->read(vec,amount) ? 1 : 0); - } - } - - return T(0); - } - }; - - template - class getline exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - typedef typename generic_type::scalar_view scalar_t; - - using igfun_t::operator(); - - getline() - : igfun_t("T",igfun_t::e_rtrn_string) - { details::perform_check(); } - - inline T operator() (std::string& result, parameter_list_t parameters) exprtk_override - { - details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); - return T(fd->getline(result) ? 1 : 0); - } - }; - - template - struct eof exprtk_final : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - eof() - : exprtk::ifunction(1) - { details::perform_check(); } - - inline T operator() (const T& v) exprtk_override - { - details::file_descriptor* fd = details::make_handle(v); - return (fd->eof() ? T(1) : T(0)); - } - }; - - template - struct package - { - open o; - close c; - write w; - read r; - getline g; - eof e; - - bool register_package(exprtk::symbol_table& symtab) - { - #define exprtk_register_function(FunctionName, FunctionType) \ - if (!symtab.add_function(FunctionName,FunctionType)) \ - { \ - exprtk_debug(( \ - "exprtk::rtl::io::file::register_package - Failed to add function: %s\n", \ - FunctionName)); \ - return false; \ - } \ - - exprtk_register_function("open" , o) - exprtk_register_function("close" , c) - exprtk_register_function("write" , w) - exprtk_register_function("read" , r) - exprtk_register_function("getline" , g) - exprtk_register_function("eof" , e) - #undef exprtk_register_function - - return true; - } - }; - - } // namespace exprtk::rtl::io::file - } // namespace exprtk::rtl::io - } // namespace exprtk::rtl -} // namespace exprtk -#endif - -#ifndef exprtk_disable_rtl_vecops -namespace exprtk -{ - namespace rtl { namespace vecops { - - namespace helper - { - template - inline bool invalid_range(const Vector& v, const std::size_t r0, const std::size_t r1) - { - if (r0 > (v.size() - 1)) - return true; - else if (r1 > (v.size() - 1)) - return true; - else if (r1 < r0) - return true; - else - return false; - } - - template - struct load_vector_range - { - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - static inline bool process(parameter_list_t& parameters, - std::size_t& r0, std::size_t& r1, - const std::size_t& r0_prmidx, - const std::size_t& r1_prmidx, - const std::size_t vec_idx = 0) - { - if (r0_prmidx >= parameters.size()) - return false; - - if (r1_prmidx >= parameters.size()) - return false; - - if (!scalar_t(parameters[r0_prmidx]).to_uint(r0)) - return false; - - if (!scalar_t(parameters[r1_prmidx]).to_uint(r1)) - return false; - - return !invalid_range(vector_t(parameters[vec_idx]), r0, r1); - } - }; - } - - namespace details - { - template - inline void kahan_sum(T& sum, T& error, const T v) - { - const T x = v - error; - const T y = sum + x; - error = (y - sum) - x; - sum = y; - } - - } // namespace exprtk::rtl::details - - template - class all_true exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - all_true() - : exprtk::igeneric_function("V|VTT|T*") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - 2. T* - T....T - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - if (2 == ps_index) - { - for (std::size_t i = 0; i < parameters.size(); ++i) - { - if (scalar_t(parameters[i])() == T(0)) - { - return T(0); - } - } - } - else - { - const vector_t vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - { - return std::numeric_limits::quiet_NaN(); - } - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] == T(0)) - { - return T(0); - } - } - } - - return T(1); - } - }; - - template - class all_false exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - all_false() - : exprtk::igeneric_function("V|VTT|T*") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - 2. T* - T....T - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - if (2 == ps_index) - { - for (std::size_t i = 0; i < parameters.size(); ++i) - { - if (scalar_t(parameters[i])() != T(0)) - { - return T(0); - } - } - } - else - { - const vector_t vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - { - return std::numeric_limits::quiet_NaN(); - } - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) - { - return T(0); - } - } - } - - return T(1); - } - }; - - template - class any_true exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - any_true() - : exprtk::igeneric_function("V|VTT|T*") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - 2. T* - T....T - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - if (2 == ps_index) - { - for (std::size_t i = 0; i < parameters.size(); ++i) - { - if (scalar_t(parameters[i])() != T(0)) - { - return T(1); - } - } - } - else - { - const vector_t vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - { - return std::numeric_limits::quiet_NaN(); - } - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) - { - return T(1); - } - } - } - - return T(0); - } - }; - - template - class any_false exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - any_false() - : exprtk::igeneric_function("V|VTT|T*") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - 2. T* - T....T - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - if (2 == ps_index) - { - for (std::size_t i = 0; i < parameters.size(); ++i) - { - if (scalar_t(parameters[i])() == T(0)) - { - return T(1); - } - } - } - else - { - const vector_t vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - { - return std::numeric_limits::quiet_NaN(); - } - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] == T(0)) - { - return T(1); - } - } - } - - return T(0); - } - }; - - template - class count exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - count() - : exprtk::igeneric_function("V|VTT|T*") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - 2. T* - T....T - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - std::size_t cnt = 0; - - if (2 == ps_index) - { - for (std::size_t i = 0; i < parameters.size(); ++i) - { - if (scalar_t(parameters[i])() != T(0)) ++cnt; - } - } - else - { - const vector_t vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - { - return std::numeric_limits::quiet_NaN(); - } - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) ++cnt; - } - } - - return T(cnt); - } - }; - - template - class copy exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - copy() - : exprtk::igeneric_function("VV|VTTVTT") - /* - Overloads: - 0. VV - x(vector), y(vector) - 1. VTTVTT - x(vector), xr0, xr1, y(vector), yr0, yr1, - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[0]); - vector_t y(parameters[(0 == ps_index) ? 1 : 3]); - - std::size_t xr0 = 0; - std::size_t xr1 = x.size() - 1; - - std::size_t yr0 = 0; - std::size_t yr1 = y.size() - 1; - - if (1 == ps_index) - { - if ( - !helper::load_vector_range::process(parameters, xr0, xr1, 1, 2, 0) || - !helper::load_vector_range::process(parameters, yr0, yr1, 4, 5, 3) - ) - return T(0); - } - - const std::size_t n = std::min(xr1 - xr0 + 1, yr1 - yr0 + 1); - - std::copy( - x.begin() + xr0, - x.begin() + xr0 + n, - y.begin() + yr0); - - return T(n); - } - }; - - template - class rol exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - rol() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, N - 1. VTTT - vector, N, r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) - ) - return T(0); - - const std::size_t dist = r1 - r0 + 1; - const std::size_t shift = n % dist; - - std::rotate( - vec.begin() + r0, - vec.begin() + r0 + shift, - vec.begin() + r1 + 1); - - return T(1); - } - }; - - template - class ror exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - ror() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, N - 1. VTTT - vector, N, r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) - ) - return T(0); - - const std::size_t dist = r1 - r0 + 1; - const std::size_t shift = (dist - (n % dist)) % dist; - - std::rotate( - vec.begin() + r0, - vec.begin() + r0 + shift, - vec.begin() + r1 + 1); - - return T(1); - } - }; - - template - class reverse exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - reverse() - : exprtk::igeneric_function("V|VTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - return T(0); - - std::reverse(vec.begin() + r0, vec.begin() + r1 + 1); - - return T(1); - } - }; - - template - class shift_left exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - shift_left() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, N - 1. VTTT - vector, N, r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) - ) - return T(0); - - const std::size_t dist = r1 - r0 + 1; - - if (n > dist) - return T(0); - - std::rotate( - vec.begin() + r0, - vec.begin() + r0 + n, - vec.begin() + r1 + 1); - - for (std::size_t i = r1 - n + 1ULL; i <= r1; ++i) - { - vec[i] = T(0); - } - - return T(1); - } - }; - - template - class shift_right exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - shift_right() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, N - 1. VTTT - vector, N, r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) - ) - return T(0); - - const std::size_t dist = r1 - r0 + 1; - - if (n > dist) - return T(0); - - const std::size_t shift = (dist - (n % dist)) % dist; - - std::rotate( - vec.begin() + r0, - vec.begin() + r0 + shift, - vec.begin() + r1 + 1); - - for (std::size_t i = r0; i < r0 + n; ++i) - { - vec[i] = T(0); - } - - return T(1); - } - }; - - template - class sort exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - sort() - : exprtk::igeneric_function("V|VTT|VS|VSTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - 2. VS - vector, string - 3. VSTT - vector, string, r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0)) - return T(0); - if ((3 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) - return T(0); - - bool ascending = true; - - if ((2 == ps_index) || (3 == ps_index)) - { - if (exprtk::details::imatch(to_str(string_t(parameters[1])),"ascending")) - ascending = true; - else if (exprtk::details::imatch(to_str(string_t(parameters[1])),"descending")) - ascending = false; - else - return T(0); - } - - if (ascending) - std::sort( - vec.begin() + r0, - vec.begin() + r1 + 1, - std::less()); - else - std::sort( - vec.begin() + r0, - vec.begin() + r1 + 1, - std::greater()); - - return T(1); - } - }; - - template - class nthelement exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - nthelement() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, nth-element - 1. VTTT - vector, nth-element, r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) - { - return std::numeric_limits::quiet_NaN(); - } - - std::nth_element( - vec.begin() + r0, - vec.begin() + r0 + n , - vec.begin() + r1 + 1); - - return T(1); - } - }; - - template - class assign exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - assign() - : exprtk::igeneric_function("VT|VTTT|VTTTT") - /* - Overloads: - 0. VT - vector, V - 1. VTTT - vector, V, r0, r1 - 2. VTTTT - vector, V, r0, r1, SS - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - const T assign_value = scalar_t(parameters[1]); - - const std::size_t step_size = (2 != ps_index) ? 1 : - static_cast(scalar_t(parameters.back())()); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - ((ps_index == 1) || (ps_index == 2)) && - !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0) - ) - { - return T(0); - } - - for (std::size_t i = r0; i <= r1; i += step_size) - { - vec[i] = assign_value; - } - - return T(1); - } - }; - - template - class iota exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - iota() - : exprtk::igeneric_function("VTT|VT|VTTTT|VTTT") - /* - Overloads: - 0. VTT - vector, SV, SS - 1. VT - vector, SV, SS (+1) - 2. VTTT - vector, r0, r1, SV, SS - 3. VTT - vector, r0, r1, SV, SS (+1) - - Where: - 1. SV - Start value - 2. SS - Step size - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - const T start_value = (ps_index <= 1) ? - scalar_t(parameters[1]) : - scalar_t(parameters[3]) ; - - const T step_size = ((0 == ps_index) || (2 == ps_index)) ? - scalar_t(parameters.back())() : - T(1) ; - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - ((ps_index == 2) || (ps_index == 3)) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - { - return T(0); - } - - for (std::size_t i = r0; i <= r1; ++i) - { - vec[i] = start_value + ((i - r0) * step_size); - } - - return T(1); - } - }; - - template - class sumk exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - sumk() - : exprtk::igeneric_function("V|VTT|VTTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - 2. VTTT - vector, r0, r1, stride - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t vec(parameters[0]); - - const std::size_t stride = (2 != ps_index) ? 1 : - static_cast(scalar_t(parameters[3])()); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - ((1 == ps_index) || (2 == ps_index)) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - { - return std::numeric_limits::quiet_NaN(); - } - - T result = T(0); - T error = T(0); - - for (std::size_t i = r0; i <= r1; i += stride) - { - details::kahan_sum(result, error, vec[i]); - } - - return result; - } - }; - - template - class axpy exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - axpy() - : exprtk::igeneric_function("TVV|TVVTT") - /* - y <- ax + y - Overloads: - 0. TVV - a, x(vector), y(vector) - 1. TVVTT - a, x(vector), y(vector), r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[1]); - vector_t y(parameters[2]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y, r0, r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - y[i] = (a * x[i]) + y[i]; - } - - return T(1); - } - }; - - template - class axpby exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - axpby() - : exprtk::igeneric_function("TVTV|TVTVTT") - /* - y <- ax + by - Overloads: - 0. TVTV - a, x(vector), b, y(vector) - 1. TVTVTT - a, x(vector), b, y(vector), r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[1]); - vector_t y(parameters[3]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y, r0, r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - const T b = scalar_t(parameters[2])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - y[i] = (a * x[i]) + (b * y[i]); - } - - return T(1); - } - }; - - template - class axpyz exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - axpyz() - : exprtk::igeneric_function("TVVV|TVVVTT") - /* - z <- ax + y - Overloads: - 0. TVVV - a, x(vector), y(vector), z(vector) - 1. TVVVTT - a, x(vector), y(vector), z(vector), r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[1]); - const vector_t y(parameters[2]); - vector_t z(parameters[3]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y, r0, r1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z, r0, r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - z[i] = (a * x[i]) + y[i]; - } - - return T(1); - } - }; - - template - class axpbyz exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - axpbyz() - : exprtk::igeneric_function("TVTVV|TVTVVTT") - /* - z <- ax + by - Overloads: - 0. TVTVV - a, x(vector), b, y(vector), z(vector) - 1. TVTVVTT - a, x(vector), b, y(vector), z(vector), r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[1]); - const vector_t y(parameters[3]); - vector_t z(parameters[4]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 5, 6, 1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y, r0, r1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z, r0, r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - const T b = scalar_t(parameters[2])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - z[i] = (a * x[i]) + (b * y[i]); - } - - return T(1); - } - }; - - template - class axpbsy exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - axpbsy() - : exprtk::igeneric_function("TVTTV|TVTTVTT") - /* - y <- ax + by - Overloads: - 0. TVTVV - a, x(vector), b, shift, y(vector), z(vector) - 1. TVTVVTT - a, x(vector), b, shift, y(vector), z(vector), r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[1]); - vector_t y(parameters[4]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 5, 6, 1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y, r0, r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - const T b = scalar_t(parameters[2])(); - - const std::size_t s = static_cast(scalar_t(parameters[3])()); - - for (std::size_t i = r0; i <= r1; ++i) - { - y[i] = (a * x[i]) + (b * y[i + s]); - } - - return T(1); - } - }; - - template - class axpbsyz exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - axpbsyz() - : exprtk::igeneric_function("TVTTVV|TVTTVVTT") - /* - z <- ax + by - Overloads: - 0. TVTVV - a, x(vector), b, shift, y(vector), z(vector) - 1. TVTVVTT - a, x(vector), b, shift, y(vector), z(vector), r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[1]); - const vector_t y(parameters[4]); - vector_t z(parameters[5]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 6, 7, 1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y, r0, r1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z, r0, r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - const T b = scalar_t(parameters[2])(); - - const std::size_t s = static_cast(scalar_t(parameters[3])()); - - for (std::size_t i = r0; i <= r1; ++i) - { - z[i] = (a * x[i]) + (b * y[i + s]); - } - - return T(1); - } - }; - - template - class axpbz exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - axpbz() - : exprtk::igeneric_function("TVTV|TVTVTT") - /* - z <- ax + b - Overloads: - 0. TVTV - a, x(vector), b, z(vector) - 1. TVTVTT - a, x(vector), b, z(vector), r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[1]); - vector_t z(parameters[3]); - - std::size_t r0 = 0; - std::size_t r1 = x.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z, r0, r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - const T b = scalar_t(parameters[2])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - z[i] = (a * x[i]) + b; - } - - return T(1); - } - }; - - template - class diff exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - diff() - : exprtk::igeneric_function("VV|VVT") - /* - x_(i - stride) - x_i - Overloads: - 0. VV - x(vector), y(vector) - 1. VVT - x(vector), y(vector), stride - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[0]); - vector_t y(parameters[1]); - - const std::size_t r0 = 0; - const std::size_t r1 = std::min(x.size(),y.size()) - 1; - - const std::size_t stride = (1 != ps_index) ? 1 : - std::min(r1,static_cast(scalar_t(parameters[2])())); - - for (std::size_t i = 0; i < stride; ++i) - { - y[i] = std::numeric_limits::quiet_NaN(); - } - - for (std::size_t i = (r0 + stride); i <= r1; ++i) - { - y[i] = x[i] - x[i - stride]; - } - - return T(1); - } - }; - - template - class dot exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - dot() - : exprtk::igeneric_function("VV|VVTT") - /* - Overloads: - 0. VV - x(vector), y(vector) - 1. VVTT - x(vector), y(vector), r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[0]); - const vector_t y(parameters[1]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y, r0, r1)) - return std::numeric_limits::quiet_NaN(); - - T result = T(0); - - for (std::size_t i = r0; i <= r1; ++i) - { - result += (x[i] * y[i]); - } - - return result; - } - }; - - template - class dotk exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - dotk() - : exprtk::igeneric_function("VV|VVTT") - /* - Overloads: - 0. VV - x(vector), y(vector) - 1. VVTT - x(vector), y(vector), r0, r1 - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - const vector_t x(parameters[0]); - const vector_t y(parameters[1]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y, r0, r1)) - return std::numeric_limits::quiet_NaN(); - - T result = T(0); - T error = T(0); - - for (std::size_t i = r0; i <= r1; ++i) - { - details::kahan_sum(result, error, (x[i] * y[i])); - } - - return result; - } - }; - - template - class threshold_below exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - threshold_below() - : exprtk::igeneric_function("VTT|VTTTT") - /* - Overloads: - 0. VTT - vector, TV, SV - 1. VTTTT - vector, r0, r1, TV, SV - - Where: - TV - Threshold value - SV - Snap-to value - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - const T threshold_value = (0 == ps_index) ? - scalar_t(parameters[1]) : - scalar_t(parameters[3]) ; - - const T snap_value = scalar_t(parameters.back()); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - { - return T(0); - } - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] < threshold_value) - { - vec[i] = snap_value; - } - } - - return T(1); - } - }; - - template - class threshold_above exprtk_final : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using igfun_t::operator(); - - threshold_above() - : exprtk::igeneric_function("VTT|VTTTT") - /* - Overloads: - 0. VTT - vector, TV, SV - 1. VTTTT - vector, r0, r1, TV, SV - - Where: - TV - Threshold value - SV - Snap-to value - */ - {} - - inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) exprtk_override - { - vector_t vec(parameters[0]); - - const T threshold_value = (0 == ps_index) ? - scalar_t(parameters[1]) : - scalar_t(parameters[3]) ; - - const T snap_value = scalar_t(parameters.back()); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ( - (1 == ps_index) && - !helper::load_vector_range::process(parameters, r0, r1, 1, 2, 0) - ) - { - return T(0); - } - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] > threshold_value) - { - vec[i] = snap_value; - } - } - - return T(1); - } - }; - - template - struct package - { - all_true at; - all_false af; - any_true nt; - any_false nf; - count c; - copy cp; - rol rl; - ror rr; - reverse rev; - shift_left sl; - shift_right sr; - sort st; - nthelement ne; - assign an; - iota ia; - sumk sk; - axpy b1_axpy; - axpby b1_axpby; - axpyz b1_axpyz; - axpbyz b1_axpbyz; - axpbsy b1_axpbsy; - axpbsyz b1_axpbsyz; - axpbz b1_axpbz; - diff df; - dot dt; - dotk dtk; - threshold_above ta; - threshold_below tb; - - bool register_package(exprtk::symbol_table& symtab) - { - #define exprtk_register_function(FunctionName, FunctionType) \ - if (!symtab.add_function(FunctionName,FunctionType)) \ - { \ - exprtk_debug(( \ - "exprtk::rtl::vecops::register_package - Failed to add function: %s\n", \ - FunctionName)); \ - return false; \ - } \ - - exprtk_register_function("all_true" , at ) - exprtk_register_function("all_false" , af ) - exprtk_register_function("any_true" , nt ) - exprtk_register_function("any_false" , nf ) - exprtk_register_function("count" , c ) - exprtk_register_function("copy" , cp ) - exprtk_register_function("rotate_left" , rl ) - exprtk_register_function("rol" , rl ) - exprtk_register_function("rotate_right" , rr ) - exprtk_register_function("ror" , rr ) - exprtk_register_function("reverse" , rev ) - exprtk_register_function("shftl" , sl ) - exprtk_register_function("shftr" , sr ) - exprtk_register_function("sort" , st ) - exprtk_register_function("nth_element" , ne ) - exprtk_register_function("assign" , an ) - exprtk_register_function("iota" , ia ) - exprtk_register_function("sumk" , sk ) - exprtk_register_function("axpy" , b1_axpy ) - exprtk_register_function("axpby" , b1_axpby ) - exprtk_register_function("axpyz" , b1_axpyz ) - exprtk_register_function("axpbyz" , b1_axpbyz ) - exprtk_register_function("axpbsy" , b1_axpbsy ) - exprtk_register_function("axpbsyz" , b1_axpbsyz) - exprtk_register_function("axpbz" , b1_axpbz ) - exprtk_register_function("diff" , df ) - exprtk_register_function("dot" , dt ) - exprtk_register_function("dotk" , dtk ) - exprtk_register_function("threshold_above" , ta ) - exprtk_register_function("threshold_below" , tb ) - #undef exprtk_register_function - - return true; - } - }; - - } // namespace exprtk::rtl::vecops - } // namespace exprtk::rtl -} // namespace exprtk -#endif - -namespace exprtk -{ - namespace information - { - using ::exprtk::details::char_cptr; - - static char_cptr library = "Mathematical Expression Toolkit"; - static char_cptr version = "2.718281828459045235360287471352662497757" - "24709369995957496696762772407663035354759" - "45713821785251664274274663919320030599218" - "17413596629043572900334295260595630738132"; - static char_cptr date = "20240101"; - static char_cptr min_cpp = "199711L"; - - static inline std::string data() - { - static const std::string info_str = std::string(library) + - std::string(" v") + std::string(version) + - std::string(" (") + date + std::string(")") + - std::string(" (") + min_cpp + std::string(")"); - return info_str; - } - - } // namespace information - - #ifdef exprtk_debug - #undef exprtk_debug - #endif - - #ifdef exprtk_error_location - #undef exprtk_error_location - #endif - - #ifdef exprtk_fallthrough - #undef exprtk_fallthrough - #endif - - #ifdef exprtk_override - #undef exprtk_override - #endif - - #ifdef exprtk_final - #undef exprtk_final - #endif - - #ifdef exprtk_delete - #undef exprtk_delete - #endif - -} // namespace exprtk - -#endif diff --git a/server/src/json.c b/server/src/json.c deleted file mode 100644 index 3156797..0000000 --- a/server/src/json.c +++ /dev/null @@ -1,953 +0,0 @@ -/* vim: set et ts=3 sw=3 sts=3 ft=c: - * - * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. - * https://github.com/udp/json-parser - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "json.h" - -#ifdef _MSC_VER - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif -#endif - -#ifdef __cplusplus - const struct _json_value json_value_none; /* zero-d by ctor */ -#else - const struct _json_value json_value_none = { 0 }; -#endif - -#include -#include -#include -#include - -typedef unsigned short json_uchar; - -static unsigned char hex_value (json_char c) -{ - if (isdigit(c)) - return c - '0'; - - switch (c) { - case 'a': case 'A': return 0x0A; - case 'b': case 'B': return 0x0B; - case 'c': case 'C': return 0x0C; - case 'd': case 'D': return 0x0D; - case 'e': case 'E': return 0x0E; - case 'f': case 'F': return 0x0F; - default: return 0xFF; - } -} - -typedef struct -{ - unsigned long used_memory; - - unsigned int uint_max; - unsigned long ulong_max; - - json_settings settings; - int first_pass; - -} json_state; - -static void * default_alloc (size_t size, int zero, void * user_data) -{ - return zero ? calloc (1, size) : malloc (size); -} - -static void default_free (void * ptr, void * user_data) -{ - free (ptr); -} - -static void * json_alloc (json_state * state, unsigned long size, int zero) -{ - if ((state->ulong_max - state->used_memory) < size) - return 0; - - if (state->settings.max_memory - && (state->used_memory += size) > state->settings.max_memory) - { - return 0; - } - - return state->settings.mem_alloc (size, zero, state->settings.user_data); -} - -static int new_value - (json_state * state, json_value ** top, json_value ** root, json_value ** alloc, json_type type) -{ - json_value * value; - int values_size; - - if (!state->first_pass) - { - value = *top = *alloc; - *alloc = (*alloc)->_reserved.next_alloc; - - if (!*root) - *root = value; - - switch (value->type) - { - case json_array: - - if (! (value->u.array.values = (json_value **) json_alloc - (state, value->u.array.length * sizeof (json_value *), 0)) ) - { - return 0; - } - - value->u.array.length = 0; - break; - - case json_object: - - values_size = sizeof (*value->u.object.values) * value->u.object.length; - - void *tmp_alloc = json_alloc(state, values_size + ((unsigned long) value->u.object.values), 0); - if (!tmp_alloc) - { - return 0; - } - /* 避免违反严格别名:通过中间变量复制 */ - memcpy(&value->u.object.values, &tmp_alloc, sizeof(void*)); - char *obj_mem = (char*)value->u.object.values + values_size; - memcpy(&value->_reserved.object_mem, &obj_mem, sizeof(char*)); - - value->u.object.length = 0; - break; - - case json_string: - - if (! (value->u.string.ptr = (json_char *) json_alloc - (state, (value->u.string.length + 1) * sizeof (json_char), 0)) ) - { - return 0; - } - - value->u.string.length = 0; - break; - - default: - break; - }; - - return 1; - } - - value = (json_value *) json_alloc (state, sizeof (json_value), 1); - - if (!value) - return 0; - - if (!*root) - *root = value; - - value->type = type; - value->parent = *top; - - if (*alloc) - (*alloc)->_reserved.next_alloc = value; - - *alloc = *top = value; - - return 1; -} - -#define e_off \ - ((int) (i - cur_line_begin)) - -#define whitespace \ - case '\n': ++ cur_line; cur_line_begin = i; \ - case ' ': case '\t': case '\r' - -#define string_add(b) \ - do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); - -static const long - flag_next = 1 << 0, - flag_reproc = 1 << 1, - flag_need_comma = 1 << 2, - flag_seek_value = 1 << 3, - flag_escaped = 1 << 4, - flag_string = 1 << 5, - flag_need_colon = 1 << 6, - flag_done = 1 << 7, - flag_num_negative = 1 << 8, - flag_num_zero = 1 << 9, - flag_num_e = 1 << 10, - flag_num_e_got_sign = 1 << 11, - flag_num_e_negative = 1 << 12, - flag_line_comment = 1 << 13, - flag_block_comment = 1 << 14; - -json_value * json_parse_ex (json_settings * settings, - const json_char * json, - size_t length, - char * error_buf) -{ - json_char error [json_error_max]; - unsigned int cur_line; - const json_char * cur_line_begin, * i, * end; - json_value * top, * root, * alloc = 0; - json_state state = { 0 }; - long flags; - long num_digits = 0, num_e = 0; - json_int_t num_fraction = 0; - - /* Skip UTF-8 BOM - */ - if (length >= 3 && ((unsigned char) json [0]) == 0xEF - && ((unsigned char) json [1]) == 0xBB - && ((unsigned char) json [2]) == 0xBF) - { - json += 3; - length -= 3; - } - - error[0] = '\0'; - end = (json + length); - - memcpy (&state.settings, settings, sizeof (json_settings)); - - if (!state.settings.mem_alloc) - state.settings.mem_alloc = default_alloc; - - if (!state.settings.mem_free) - state.settings.mem_free = default_free; - - memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); - memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); - - state.uint_max -= 8; /* limit of how much can be added before next check */ - state.ulong_max -= 8; - - for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass) - { - json_uchar uchar; - unsigned char uc_b1, uc_b2, uc_b3, uc_b4; - json_char * string = 0; - unsigned int string_length = 0; - - top = root = 0; - flags = flag_seek_value; - - cur_line = 1; - cur_line_begin = json; - - for (i = json ;; ++ i) - { - json_char b = (i == end ? 0 : *i); - - if (flags & flag_string) - { - if (!b) - { sprintf (error, "Unexpected EOF in string (at %d:%d)", cur_line, e_off); - goto e_failed; - } - - if (string_length > state.uint_max) - goto e_overflow; - - if (flags & flag_escaped) - { - flags &= ~ flag_escaped; - - switch (b) - { - case 'b': string_add ('\b'); break; - case 'f': string_add ('\f'); break; - case 'n': string_add ('\n'); break; - case 'r': string_add ('\r'); break; - case 't': string_add ('\t'); break; - case 'u': - - if (end - i < 4 || - (uc_b1 = hex_value (*++ i)) == 0xFF || (uc_b2 = hex_value (*++ i)) == 0xFF - || (uc_b3 = hex_value (*++ i)) == 0xFF || (uc_b4 = hex_value (*++ i)) == 0xFF) - { - sprintf (error, "Invalid character value `%c` (at %d:%d)", b, cur_line, e_off); - goto e_failed; - } - - uc_b1 = uc_b1 * 16 + uc_b2; - uc_b2 = uc_b3 * 16 + uc_b4; - - uchar = ((json_char) uc_b1) * 256 + uc_b2; - - if (sizeof (json_char) >= sizeof (json_uchar) || (uc_b1 == 0 && uc_b2 <= 0x7F)) - { - string_add ((json_char) uchar); - break; - } - - if (uchar <= 0x7FF) - { - if (state.first_pass) - string_length += 2; - else - { string [string_length ++] = 0xC0 | ((uc_b2 & 0xC0) >> 6) | ((uc_b1 & 0x7) << 2); - string [string_length ++] = 0x80 | (uc_b2 & 0x3F); - } - - break; - } - - if (state.first_pass) - string_length += 3; - else - { string [string_length ++] = 0xE0 | ((uc_b1 & 0xF0) >> 4); - string [string_length ++] = 0x80 | ((uc_b1 & 0xF) << 2) | ((uc_b2 & 0xC0) >> 6); - string [string_length ++] = 0x80 | (uc_b2 & 0x3F); - } - - break; - - default: - string_add (b); - }; - - continue; - } - - if (b == '\\') - { - flags |= flag_escaped; - continue; - } - - if (b == '"') - { - if (!state.first_pass) - string [string_length] = 0; - - flags &= ~ flag_string; - string = 0; - - switch (top->type) - { - case json_string: - - top->u.string.length = string_length; - flags |= flag_next; - - break; - - case json_object: - - if (state.first_pass) - { - json_char *adv = (json_char*)top->u.object.values; - adv += string_length + 1; - memcpy(&top->u.object.values, &adv, sizeof(json_char*)); - } - else - { - top->u.object.values[top->u.object.length].name = (json_char *)top->_reserved.object_mem; - top->u.object.values[top->u.object.length].name_length = string_length; - json_char *adv2 = (json_char*)top->_reserved.object_mem; - adv2 += string_length + 1; - memcpy(&top->_reserved.object_mem, &adv2, sizeof(json_char*)); - } - - flags |= flag_seek_value | flag_need_colon; - continue; - - default: - break; - }; - } - else - { - string_add (b); - continue; - } - } - - if (state.settings.settings & json_enable_comments) - { - if (flags & (flag_line_comment | flag_block_comment)) - { - if (flags & flag_line_comment) - { - if (b == '\r' || b == '\n' || !b) - { - flags &= ~ flag_line_comment; - -- i; /* so null can be reproc'd */ - } - - continue; - } - - if (flags & flag_block_comment) - { - if (!b) - { sprintf (error, "%d:%d: Unexpected EOF in block comment", cur_line, e_off); - goto e_failed; - } - - if (b == '*' && i < (end - 1) && i [1] == '/') - { - flags &= ~ flag_block_comment; - ++ i; /* skip closing sequence */ - } - - continue; - } - } - else if (b == '/') - { - if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object) - { - sprintf (error, "%d:%d: Comment not allowed here", cur_line, e_off); - goto e_failed; - } - - if (++ i == end) - { sprintf (error, "%d:%d: EOF unexpected", cur_line, e_off); - goto e_failed; - } - - switch (b = *i) - { - case '/': - flags |= flag_line_comment; - continue; - - case '*': - flags |= flag_block_comment; - continue; - - default: - sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", cur_line, e_off, b); - goto e_failed; - }; - } - } - - if (flags & flag_done) - { - if (!b) - break; - - switch (b) - { - whitespace: - continue; - - default: - sprintf (error, "%d:%d: Trailing garbage: `%c`", cur_line, e_off, b); - goto e_failed; - }; - } - - if (flags & flag_seek_value) - { - switch (b) - { - whitespace: - continue; - - case ']': - - if (top->type == json_array) - flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; - else - { sprintf (error, "%d:%d: Unexpected ]", cur_line, e_off); - goto e_failed; - } - - break; - - default: - - if (flags & flag_need_comma) - { - if (b == ',') - { flags &= ~ flag_need_comma; - continue; - } - else - { sprintf (error, "%d:%d: Expected , before %c", cur_line, e_off, b); - goto e_failed; - } - } - - if (flags & flag_need_colon) - { - if (b == ':') - { flags &= ~ flag_need_colon; - continue; - } - else - { sprintf (error, "%d:%d: Expected : before %c", cur_line, e_off, b); - goto e_failed; - } - } - - flags &= ~ flag_seek_value; - - switch (b) - { - case '{': - - if (!new_value (&state, &top, &root, &alloc, json_object)) - goto e_alloc_failure; - - continue; - - case '[': - - if (!new_value (&state, &top, &root, &alloc, json_array)) - goto e_alloc_failure; - - flags |= flag_seek_value; - continue; - - case '"': - - if (!new_value (&state, &top, &root, &alloc, json_string)) - goto e_alloc_failure; - - flags |= flag_string; - - string = top->u.string.ptr; - string_length = 0; - - continue; - - case 't': - - if ((end - i) < 3 || *(++ i) != 'r' || *(++ i) != 'u' || *(++ i) != 'e') - goto e_unknown_value; - - if (!new_value (&state, &top, &root, &alloc, json_boolean)) - goto e_alloc_failure; - - top->u.boolean = 1; - - flags |= flag_next; - break; - - case 'f': - - if ((end - i) < 4 || *(++ i) != 'a' || *(++ i) != 'l' || *(++ i) != 's' || *(++ i) != 'e') - goto e_unknown_value; - - if (!new_value (&state, &top, &root, &alloc, json_boolean)) - goto e_alloc_failure; - - flags |= flag_next; - break; - - case 'n': - - if ((end - i) < 3 || *(++ i) != 'u' || *(++ i) != 'l' || *(++ i) != 'l') - goto e_unknown_value; - - if (!new_value (&state, &top, &root, &alloc, json_null)) - goto e_alloc_failure; - - flags |= flag_next; - break; - - default: - - if (isdigit (b) || b == '-') - { - if (!new_value (&state, &top, &root, &alloc, json_integer)) - goto e_alloc_failure; - - if (!state.first_pass) - { - while (isdigit (b) || b == '+' || b == '-' - || b == 'e' || b == 'E' || b == '.') - { - if ( (++ i) == end) - { - b = 0; - break; - } - - b = *i; - } - - flags |= flag_next | flag_reproc; - break; - } - - flags &= ~ (flag_num_negative | flag_num_e | - flag_num_e_got_sign | flag_num_e_negative | - flag_num_zero); - - num_digits = 0; - num_fraction = 0; - num_e = 0; - - if (b != '-') - { - flags |= flag_reproc; - break; - } - - flags |= flag_num_negative; - continue; - } - else - { sprintf (error, "%d:%d: Unexpected %c when seeking value", cur_line, e_off, b); - goto e_failed; - } - }; - }; - } - else - { - switch (top->type) - { - case json_object: - - switch (b) - { - whitespace: - continue; - - case '"': - - if (flags & flag_need_comma) - { - sprintf (error, "%d:%d: Expected , before \"", cur_line, e_off); - goto e_failed; - } - - flags |= flag_string; - - string = (json_char *) top->_reserved.object_mem; - string_length = 0; - - break; - - case '}': - - flags = (flags & ~ flag_need_comma) | flag_next; - break; - - case ',': - - if (flags & flag_need_comma) - { - flags &= ~ flag_need_comma; - break; - } - - default: - - sprintf (error, "%d:%d: Unexpected `%c` in object", cur_line, e_off, b); - goto e_failed; - }; - - break; - - case json_integer: - case json_double: - - if (isdigit (b)) - { - ++ num_digits; - - if (top->type == json_integer || flags & flag_num_e) - { - if (! (flags & flag_num_e)) - { - if (flags & flag_num_zero) - { sprintf (error, "%d:%d: Unexpected `0` before `%c`", cur_line, e_off, b); - goto e_failed; - } - - if (num_digits == 1 && b == '0') - flags |= flag_num_zero; - } - else - { - flags |= flag_num_e_got_sign; - num_e = (num_e * 10) + (b - '0'); - continue; - } - - top->u.integer = (top->u.integer * 10) + (b - '0'); - continue; - } - - num_fraction = (num_fraction * 10) + (b - '0'); - continue; - } - - if (b == '+' || b == '-') - { - if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign)) - { - flags |= flag_num_e_got_sign; - - if (b == '-') - flags |= flag_num_e_negative; - - continue; - } - } - else if (b == '.' && top->type == json_integer) - { - if (!num_digits) - { sprintf (error, "%d:%d: Expected digit before `.`", cur_line, e_off); - goto e_failed; - } - - top->type = json_double; - top->u.dbl = (double) top->u.integer; - - num_digits = 0; - continue; - } - - if (! (flags & flag_num_e)) - { - if (top->type == json_double) - { - if (!num_digits) - { sprintf (error, "%d:%d: Expected digit after `.`", cur_line, e_off); - goto e_failed; - } - - top->u.dbl += ((double) num_fraction) / (pow (10, (double) num_digits)); - } - - if (b == 'e' || b == 'E') - { - flags |= flag_num_e; - - if (top->type == json_integer) - { - top->type = json_double; - top->u.dbl = (double) top->u.integer; - } - - num_digits = 0; - flags &= ~ flag_num_zero; - - continue; - } - } - else - { - if (!num_digits) - { sprintf (error, "%d:%d: Expected digit after `e`", cur_line, e_off); - goto e_failed; - } - - top->u.dbl *= pow (10, (double) (flags & flag_num_e_negative ? - num_e : num_e)); - } - - if (flags & flag_num_negative) - { - if (top->type == json_integer) - top->u.integer = - top->u.integer; - else - top->u.dbl = - top->u.dbl; - } - - flags |= flag_next | flag_reproc; - break; - - default: - break; - }; - } - - if (flags & flag_reproc) - { - flags &= ~ flag_reproc; - -- i; - } - - if (flags & flag_next) - { - flags = (flags & ~ flag_next) | flag_need_comma; - - if (!top->parent) - { - /* root value done */ - - flags |= flag_done; - continue; - } - - if (top->parent->type == json_array) - flags |= flag_seek_value; - - if (!state.first_pass) - { - json_value * parent = top->parent; - - switch (parent->type) - { - case json_object: - - parent->u.object.values - [parent->u.object.length].value = top; - - break; - - case json_array: - - parent->u.array.values - [parent->u.array.length] = top; - - break; - - default: - break; - }; - } - - if ( (++ top->parent->u.array.length) > state.uint_max) - goto e_overflow; - - top = top->parent; - - continue; - } - } - - alloc = root; - } - - return root; - -e_unknown_value: - - sprintf (error, "%d:%d: Unknown value", cur_line, e_off); - goto e_failed; - -e_alloc_failure: - - strcpy (error, "Memory allocation failure"); - goto e_failed; - -e_overflow: - - sprintf (error, "%d:%d: Too long (caught overflow)", cur_line, e_off); - goto e_failed; - -e_failed: - - if (error_buf) - { - if (*error) - strcpy (error_buf, error); - else - strcpy (error_buf, "Unknown error"); - } - - if (state.first_pass) - alloc = root; - - while (alloc) - { - top = alloc->_reserved.next_alloc; - state.settings.mem_free (alloc, state.settings.user_data); - alloc = top; - } - - if (!state.first_pass) - json_value_free_ex (&state.settings, root); - - return 0; -} - -json_value * json_parse (const json_char * json, size_t length) -{ - json_settings settings = { 0 }; - return json_parse_ex (&settings, json, length, 0); -} - -void json_value_free_ex (json_settings * settings, json_value * value) -{ - json_value * cur_value; - - if (!value) - return; - - value->parent = 0; - - while (value) - { - switch (value->type) - { - case json_array: - - if (!value->u.array.length) - { - settings->mem_free (value->u.array.values, settings->user_data); - break; - } - - value = value->u.array.values [-- value->u.array.length]; - continue; - - case json_object: - - if (!value->u.object.length) - { - settings->mem_free (value->u.object.values, settings->user_data); - break; - } - - value = value->u.object.values [-- value->u.object.length].value; - continue; - - case json_string: - - settings->mem_free (value->u.string.ptr, settings->user_data); - break; - - default: - break; - }; - - cur_value = value; - value = value->parent; - settings->mem_free (cur_value, settings->user_data); - } -} - -void json_value_free (json_value * value) -{ - json_settings settings = { 0 }; - settings.mem_free = default_free; - json_value_free_ex (&settings, value); -} diff --git a/server/src/main.cpp b/server/src/main.cpp deleted file mode 100644 index 7dd1c97..0000000 --- a/server/src/main.cpp +++ /dev/null @@ -1,1176 +0,0 @@ -#define __STDC_FORMAT_MACROS -#include -#include -#include -#include -#include -#include -#include "server.h" -#include "main.h" -#include "exprtk.hpp" -#include "curl/curl.h" -#include -#include -#include - -// 全局运行标志(需在 SSLCheckThread 定义前初始化) -static volatile int gs_Running = 1; -static volatile int gs_ReloadConfig = 0; - -static void JsonEscape(const char *pSrc, char *pDst, int DstSize) -{ - if(!pDst || DstSize <= 0) - return; - int Out = 0; - if(!pSrc) - { - pDst[0] = 0; - return; - } - for(const unsigned char *p = (const unsigned char *)pSrc; *p && Out < DstSize - 1; ++p) - { - const char *pEsc = 0; - switch(*p) - { - case '"': pEsc = "\\\""; break; - case '\\': pEsc = "\\\\"; break; - case '\b': pEsc = "\\b"; break; - case '\f': pEsc = "\\f"; break; - case '\n': pEsc = "\\n"; break; - case '\r': pEsc = "\\r"; break; - case '\t': pEsc = "\\t"; break; - default: break; - } - if(pEsc) - { - for(const char *q = pEsc; *q && Out < DstSize - 1; ++q) - pDst[Out++] = *q; - } - else if(*p < 0x20) - { - if(Out < DstSize - 6) - Out += snprintf(pDst + Out, DstSize - Out, "\\u%04x", *p); - else - break; - } - else - pDst[Out++] = *p; - } - pDst[Out] = 0; -} - -static int64_t ParseOpenSSLEnddate(const char *line) -{ - // line format: notAfter=Aug 12 23:59:59 2025 GMT - const char *p = strstr(line, "notAfter="); - if(!p) return 0; - p += 9; - struct tm tmv; memset(&tmv,0,sizeof(tmv)); - char month[4]={0}; - int day, hour, min, sec, year; - if(sscanf(p, "%3s %d %d:%d:%d %d GMT", month, &day, &hour, &min, &sec, &year)!=6) return 0; - const char *months="JanFebMarAprMayJunJulAugSepOctNovDec"; - const char *mpos = strstr(months, month); - if(!mpos) return 0; - int mon = (int)((mpos - months)/3); - tmv.tm_year = year - 1900; - tmv.tm_mon = mon; - tmv.tm_mday = day; - tmv.tm_hour = hour; tmv.tm_min = min; tmv.tm_sec = sec; - time_t t = timegm(&tmv); - return (int64_t)t; -} - -struct SSLCheckThreadData { CMain *pMain; }; -static void SSLCheckThread(void *pUser) -{ - SSLCheckThreadData *pData = (SSLCheckThreadData*)pUser; - while(gs_Running){ - for(int i=0;ipMain->SSLCert(i) || !strcmp(pData->pMain->SSLCert(i)->m_aName, "NULL")) break; - CMain::CSSLCerts *cert = pData->pMain->SSLCert(i); - time_t nowt = time(0); - if(cert->m_aLastCheck !=0 && (nowt - cert->m_aLastCheck) < cert->m_aInterval) continue; - cert->m_aLastCheck = nowt; - char cmd[1024]; - // 说明: 通过 s_client 获取证书,再用 x509 解析到期时间;统一屏蔽 stderr 以防握手失败/非 TLS 端口时刷屏。 - // 若配置中写成 https://domain/path 则需要清洗。 - char cleanHost[256]; - str_copy(cleanHost, cert->m_aDomain, sizeof(cleanHost)); - // 去协议 - if(!strncasecmp(cleanHost, "https://", 8)) memmove(cleanHost, cleanHost+8, strlen(cleanHost+8)+1); - else if(!strncasecmp(cleanHost, "http://", 7)) memmove(cleanHost, cleanHost+7, strlen(cleanHost+7)+1); - // 去路径 - char *slash = strchr(cleanHost, '/'); if(slash) *slash='\0'; - // 若含 :port 再截取主机部分(端口由配置提供) - char *colon = strchr(cleanHost, ':'); if(colon) *colon='\0'; - int n = snprintf(cmd,sizeof(cmd),"echo | openssl s_client -servername %s -connect %s:%d /dev/null | openssl x509 -noout -enddate -text 2>/dev/null", cleanHost, cleanHost, cert->m_aPort); - if(n <= 0 || n >= (int)sizeof(cmd)) continue; // 避免截断执行 - FILE *fp = popen(cmd, "r"); - if(!fp) continue; - char line[1024]={0}; - int foundEnddate=0; - int mismatch = 1; // 默认视为不匹配,发现任一匹配域名再置0 - int haveNames = 0; - // 将目标域名转为小写 - char target[256]; str_copy(target, cleanHost, sizeof(target)); - for(char *p=target; *p; ++p) *p=tolower(*p); - while(fgets(line,sizeof(line),fp)){ - if(!foundEnddate){ - int64_t expire = ParseOpenSSLEnddate(line); - if(expire>0){ cert->m_aExpireTS = expire; foundEnddate=1; } - } - // 解析 subjectAltName - // 解析 Subject 中的 CN(备用) - char *subj = strstr(line, "Subject:"); - if(subj){ - char *cn = strstr(subj, " CN="); - if(cn){ - cn += 4; // 跳过 ' CN=' - char name[256]={0}; int ni=0; - while(*cn && *cn!='/' && *cn!=',' && *cn!='\n' && ni<(int)sizeof(name)-1){ name[ni++]=*cn++; } - name[ni]='\0'; - while(ni>0 && (name[ni-1]==' '||name[ni-1]=='\r'||name[ni-1]=='\t')){ name[--ni]='\0'; } - for(char *q=name; *q; ++q) *q=tolower(*q); - if(ni>0){ - haveNames=1; - int match=0; - if(name[0]=='*' && name[1]=='.'){ - const char *sub = strchr(target,'.'); - if(sub && !strcmp(sub+1, name+2)) match=1; - }else if(!strcmp(name,target)) match=1; - if(match){ mismatch=0; } - } - } - } - if(strstr(line, "DNS:")){ - char *p = line; - while((p = strstr(p, "DNS:"))){ - p += 4; while(*p==' '){p++;} - char name[256]={0}; int ni=0; - while(*p && *p!=',' && *p!='\n' && ni<(int)sizeof(name)-1){ name[ni++]=*p++; } - name[ni]='\0'; - // 去空白 - while(ni>0 && (name[ni-1]==' '||name[ni-1]=='\r'||name[ni-1]=='\t')){ name[--ni]='\0'; } - for(char *q=name; *q; ++q) *q=tolower(*q); - haveNames=1; - // 通配符匹配 *.example.com - int match=0; - if(name[0]=='*' && name[1]=='.'){ - const char *sub = strchr(target,'.'); - if(sub && !strcmp(sub+1, name+2)) match=1; - }else if(!strcmp(name,target)) match=1; - if(match){ mismatch=0; goto names_done; } - } - } - } -names_done: - pclose(fp); - if(haveNames){ cert->m_aHostnameMismatch = mismatch ? 1 : 0; } - else { /* 未能提取任何域名,保留原状态,不触发误报 */ } - // 告警: 仅在不匹配且 24h 冷却 - if(cert->m_aHostnameMismatch==1){ - if(cert->m_aLastAlarmMismatch==0 || nowt - cert->m_aLastAlarmMismatch > 24*3600){ - if(strlen(cert->m_aCallback)>0){ - CURL *curl = curl_easy_init(); - if(curl){ - char msg[1024]; - snprintf(msg,sizeof(msg),"【SSL证书域名不匹配】%s(%s) 证书域名与配置不一致", cert->m_aName, cert->m_aDomain); - char *enc = curl_easy_escape(curl,msg,0); - char url[1500]; snprintf(url,sizeof(url),"%s%s", cert->m_aCallback, enc?enc:""); - curl_easy_setopt(curl, CURLOPT_POST, 1L); - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "signature=ServerStatusSSL"); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L); - curl_easy_perform(curl); - if(enc) curl_free(enc); - curl_easy_cleanup(curl); - } - } - cert->m_aLastAlarmMismatch = nowt; - } - } - // alarm logic - if(cert->m_aExpireTS>0){ - // 剩余天数: 向下取整 (floor) —— 与 JSON expire_days 保持一致,用于阈值分桶和消息显示 - int64_t secsLeft = cert->m_aExpireTS - nowt; - int days = (int)(secsLeft/86400); - int64_t *lastAlarm = NULL; int need=0; - if(days <=7 && days >3){ lastAlarm=&cert->m_aLastAlarm7; } - else if(days <=3 && days >1){ lastAlarm=&cert->m_aLastAlarm3; } - else if(days <=1){ lastAlarm=&cert->m_aLastAlarm1; } - if(lastAlarm && (*lastAlarm==0 || nowt - *lastAlarm > 20*3600)) need=1; // avoid spam, 20h - if(need && strlen(cert->m_aCallback)>0){ - CURL *curl = curl_easy_init(); - if(curl){ - char msg[1024]; - char timebuf[32]; - time_t expt = (time_t)cert->m_aExpireTS; - strftime(timebuf,sizeof(timebuf),"%Y-%m-%d %H:%M:%S", gmtime(&expt)); - // 使用 floor(days) - snprintf(msg,sizeof(msg),"【SSL证书提醒】%s(%s) 将在 %d 天后(%s UTC) 到期", cert->m_aName, cert->m_aDomain, days, timebuf); - char *enc = curl_easy_escape(curl,msg,0); - char url[1500]; snprintf(url,sizeof(url),"%s%s", cert->m_aCallback, enc?enc:""); - curl_easy_setopt(curl, CURLOPT_POST, 1L); - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "signature=ServerStatusSSL"); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L); - curl_easy_perform(curl); - if(enc) curl_free(enc); - curl_easy_cleanup(curl); - } - *lastAlarm = nowt; - } - } - } - thread_sleep(5000); - } -} - -#if defined(CONF_FAMILY_UNIX) - #include -#endif - -#ifndef PRId64 - #define PRId64 "I64d" -#endif - -static void ExitFunc(int Signal) -{ - printf("[EXIT] Caught signal %d\n", Signal); - gs_Running = 0; -} - -static void ReloadFunc(int Signal) -{ - printf("[RELOAD] Caught signal %d\n", Signal); - gs_ReloadConfig = 1; -} - -CConfig::CConfig() -{ - // Initialize to default values - m_Verbose = false; // -v, --verbose - str_copy(m_aConfigFile, "config.json", sizeof(m_aConfigFile)); // -c, --config - str_copy(m_aWebDir, "../web/", sizeof(m_aJSONFile)); // -d, --web-dir - str_copy(m_aTemplateFile, "template.html", sizeof(m_aTemplateFile)); - str_copy(m_aJSONFile, "json/stats.json", sizeof(m_aJSONFile)); - str_copy(m_aBindAddr, "", sizeof(m_aBindAddr)); // -b, --bind - m_Port = 35601; // -p, --port -} - -CMain::CMain(CConfig Config) : m_Config(Config) -{ - mem_zero(m_aClients, sizeof(m_aClients)); - for(int i = 0; i < NET_MAX_CLIENTS; i++) - m_aClients[i].m_ClientNetID = -1; -} - -CMain::CClient *CMain::ClientNet(int ClientNetID) -{ - if(ClientNetID < 0 || ClientNetID >= NET_MAX_CLIENTS) - return 0; - - for(int i = 0; i < NET_MAX_CLIENTS; i++) - { - if(Client(i)->m_ClientNetID == ClientNetID) - return Client(i); - } - - return 0; -} - -int CMain::ClientNetToClient(int ClientNetID) -{ - if(ClientNetID < 0 || ClientNetID >= NET_MAX_CLIENTS) - return -1; - - for(int i = 0; i < NET_MAX_CLIENTS; i++) - { - if(Client(i)->m_ClientNetID == ClientNetID) - return i; - } - - return -1; -} - -void CMain::OnNewClient(int ClientNetID, int ClientID) -{ - dbg_msg("main", "OnNewClient(ncid=%d, cid=%d)", ClientNetID, ClientID); - Client(ClientID)->m_ClientNetID = ClientNetID; - Client(ClientID)->m_ClientNetType = m_Server.Network()->ClientAddr(ClientNetID)->type; - Client(ClientID)->m_TimeConnected = time_get(); - Client(ClientID)->m_Connected = true; - - if(Client(ClientID)->m_ClientNetType == NETTYPE_IPV4) - Client(ClientID)->m_Stats.m_Online4 = true; - else if(Client(ClientID)->m_ClientNetType == NETTYPE_IPV6) - Client(ClientID)->m_Stats.m_Online6 = true; - - // Send monitor to client - // support by cpp.la - int ID = 0; - char monitorBuffer[2048]; - while (strcmp(Monitors(ID)->m_aName, "NULL")) - { - memset(monitorBuffer, 0, sizeof(monitorBuffer)); - sprintf(monitorBuffer, "{\"name\":\"%s\",\"host\":\"%s\",\"interval\":%d,\"type\":\"%s\",\"monitor\":%d}", Monitors(ID)->m_aName, Monitors(ID)->m_aHost, Monitors(ID)->m_aInterval, Monitors(ID)->m_aType, ID); - m_Server.Network()->Send(ClientNetID, monitorBuffer); - ID++; - } -} - -void CMain::OnDelClient(int ClientNetID) -{ - int ClientID = ClientNetToClient(ClientNetID); - dbg_msg("main", "OnDelClient(ncid=%d, cid=%d)", ClientNetID, ClientID); - if(ClientID >= 0 && ClientID < NET_MAX_CLIENTS) - { - Client(ClientID)->m_Connected = false; - Client(ClientID)->m_ClientNetID = -1; - Client(ClientID)->m_ClientNetType = NETTYPE_INVALID; - mem_zero(&Client(ClientID)->m_Stats, sizeof(CClient::CStats)); - } - m_OfflineAlarmThreadData.pClients = m_aClients; - m_OfflineAlarmThreadData.pWatchDogs = m_aCWatchDogs; - m_OfflineAlarmThreadData.m_ReloadRequired = ClientID; - thread_create(offlineAlarmThread, &m_OfflineAlarmThreadData); -} - -int CMain::HandleMessage(int ClientNetID, char *pMessage) -{ - CClient *pClient = ClientNet(ClientNetID); - if(!pClient) - return true; - - if(str_comp_num(pMessage, "update", sizeof("update")-1) == 0) - { - char *pData = str_skip_whitespaces(&pMessage[sizeof("update")-1]); - - // parse json data - json_settings JsonSettings; - mem_zero(&JsonSettings, sizeof(JsonSettings)); - char aError[256]; - json_value *pJsonData = json_parse_ex(&JsonSettings, pData, strlen(pData), aError); - if(!pJsonData) - { - dbg_msg("main", "JSON Error: %s", aError); - if(pClient->m_Stats.m_Pong) - m_Server.Network()->Send(ClientNetID, "1"); - return 1; - } - - // extract data - const json_value &rStart = (*pJsonData); - if(rStart["uptime"].type) - pClient->m_Stats.m_Uptime = rStart["uptime"].u.integer; - if(rStart["load_1"].type) - pClient->m_Stats.m_Load_1 = rStart["load_1"].u.dbl; - if(rStart["load_5"].type) - pClient->m_Stats.m_Load_5 = rStart["load_5"].u.dbl; - if(rStart["load_15"].type) - pClient->m_Stats.m_Load_15 = rStart["load_15"].u.dbl; - if(rStart["ping_10010"].type) - pClient->m_Stats.m_ping_10010 = rStart["ping_10010"].u.dbl; - if(rStart["ping_189"].type) - pClient->m_Stats.m_ping_189 = rStart["ping_189"].u.dbl; - if(rStart["ping_10086"].type) - pClient->m_Stats.m_ping_10086 = rStart["ping_10086"].u.dbl; - if(rStart["time_10010"].type) - pClient->m_Stats.m_time_10010 = rStart["time_10010"].u.integer; - if(rStart["time_189"].type) - pClient->m_Stats.m_time_189 = rStart["time_189"].u.integer; - if(rStart["time_10086"].type) - pClient->m_Stats.m_time_10086 = rStart["time_10086"].u.integer; - if(rStart["tcp"].type) - pClient->m_Stats.m_tcpCount = rStart["tcp"].u.integer; - if(rStart["udp"].type) - pClient->m_Stats.m_udpCount = rStart["udp"].u.integer; - if(rStart["process"].type) - pClient->m_Stats.m_processCount = rStart["process"].u.integer; - if(rStart["thread"].type) - pClient->m_Stats.m_threadCount = rStart["thread"].u.integer; - if(rStart["network_rx"].type) - pClient->m_Stats.m_NetworkRx = rStart["network_rx"].u.integer; - if(rStart["network_tx"].type) - pClient->m_Stats.m_NetworkTx = rStart["network_tx"].u.integer; - if(rStart["network_in"].type) - pClient->m_Stats.m_NetworkIN = rStart["network_in"].u.integer; - if(rStart["network_out"].type) - pClient->m_Stats.m_NetworkOUT = rStart["network_out"].u.integer; - if(rStart["memory_total"].type) - pClient->m_Stats.m_MemTotal = rStart["memory_total"].u.integer; - if(rStart["memory_used"].type) - pClient->m_Stats.m_MemUsed = rStart["memory_used"].u.integer; - if(rStart["swap_total"].type) - pClient->m_Stats.m_SwapTotal = rStart["swap_total"].u.integer; - if(rStart["swap_used"].type) - pClient->m_Stats.m_SwapUsed = rStart["swap_used"].u.integer; - if(rStart["hdd_total"].type) - pClient->m_Stats.m_HDDTotal = rStart["hdd_total"].u.integer; - if(rStart["hdd_used"].type) - pClient->m_Stats.m_HDDUsed = rStart["hdd_used"].u.integer; - if(rStart["io_read"].type) - pClient->m_Stats.m_IORead = rStart["io_read"].u.integer; - if(rStart["io_write"].type) - pClient->m_Stats.m_IOWrite = rStart["io_write"].u.integer; - if(rStart["cpu"].type) - pClient->m_Stats.m_CPU = rStart["cpu"].u.dbl; - if(rStart["cpu_cores"].type) - pClient->m_Stats.m_CPUCores = rStart["cpu_cores"].u.integer; - if(rStart["cpu_model"].type == json_string) - str_copy(pClient->m_Stats.m_aCPUModel, rStart["cpu_model"].u.string.ptr, sizeof(pClient->m_Stats.m_aCPUModel)); - if(rStart["online4"].type && pClient->m_ClientNetType == NETTYPE_IPV6) - pClient->m_Stats.m_Online4 = rStart["online4"].u.boolean; - if(rStart["online6"].type && pClient->m_ClientNetType == NETTYPE_IPV4) - pClient->m_Stats.m_Online6 = rStart["online6"].u.boolean; - if(rStart["custom"].type == json_string) - str_copy(pClient->m_Stats.m_aCustom, rStart["custom"].u.string.ptr, sizeof(pClient->m_Stats.m_aCustom)); - // optional OS field from clients - if(rStart["os"].type == json_string) - str_copy(pClient->m_Stats.m_aOS, rStart["os"].u.string.ptr, sizeof(pClient->m_Stats.m_aOS)); - - //copy message for watchdog to analysis - WatchdogMessage(ClientNetID, - pClient->m_Stats.m_Load_1, pClient->m_Stats.m_Load_5, pClient->m_Stats.m_Load_15, - pClient->m_Stats.m_ping_10010, pClient->m_Stats.m_ping_189, pClient->m_Stats.m_ping_10086, - pClient->m_Stats.m_time_10010, pClient->m_Stats.m_time_189, pClient->m_Stats.m_time_10086, - pClient->m_Stats.m_tcpCount, pClient->m_Stats.m_udpCount, pClient->m_Stats.m_processCount, - pClient->m_Stats.m_threadCount, pClient->m_Stats.m_NetworkRx, pClient->m_Stats.m_NetworkTx, - pClient->m_Stats.m_NetworkIN, pClient->m_Stats.m_NetworkOUT, - pClient->m_LastNetworkIN, pClient->m_LastNetworkOUT, pClient->m_Stats.m_MemTotal, - pClient->m_Stats.m_MemUsed, pClient->m_Stats.m_SwapTotal, pClient->m_Stats.m_SwapUsed, - pClient->m_Stats.m_HDDTotal, pClient->m_Stats.m_HDDUsed, pClient->m_Stats.m_IORead, - pClient->m_Stats.m_IOWrite, pClient->m_Stats.m_CPU, pClient->m_Stats.m_Online4, - pClient->m_Stats.m_Online6); - - if(m_Config.m_Verbose) - { - if(rStart["online4"].type) - dbg_msg("main", "Online4: %s\nUptime: %" PRId64 "\nLoad_1: %f\nLoad_5: %f\nLoad_15: %f\nPing_10010: %f\nPing_189: %f\nPing_10086: %f\nTime_10010: %" PRId64 "\nTime_189: %" PRId64 "\nTime_10086: %" PRId64 "\nTcp_count: %" PRId64 "\nUdp_count: %" PRId64 "\nprocess_count: %" PRId64 "\nthread_count: %" PRId64 "\nNetworkRx: %" PRId64 "\nNetworkTx: %" PRId64 "\nNetworkIN: %" PRId64 "\nNetworkOUT: %" PRId64 "\nMemTotal: %" PRId64 "\nMemUsed: %" PRId64 "\nSwapTotal: %" PRId64 "\nSwapUsed: %" PRId64 "\nHDDTotal: %" PRId64 "\nHDDUsed: %" PRId64 "\nCPU: %f\nIORead: %" PRId64 "\nIOWrite: %" PRId64 "\n", - rStart["online4"].u.boolean ? "true" : "false", - pClient->m_Stats.m_Uptime, - pClient->m_Stats.m_Load_1, pClient->m_Stats.m_Load_5, pClient->m_Stats.m_Load_15, pClient->m_Stats.m_ping_10010, pClient->m_Stats.m_ping_189, pClient->m_Stats.m_ping_10086, pClient->m_Stats.m_time_10010, pClient->m_Stats.m_time_189, pClient->m_Stats.m_time_10086,pClient->m_Stats.m_tcpCount,pClient->m_Stats.m_udpCount,pClient->m_Stats.m_processCount,pClient->m_Stats.m_threadCount,pClient->m_Stats.m_NetworkRx, pClient->m_Stats.m_NetworkTx, pClient->m_Stats.m_NetworkIN, pClient->m_Stats.m_NetworkOUT, pClient->m_Stats.m_MemTotal, pClient->m_Stats.m_MemUsed, pClient->m_Stats.m_SwapTotal, pClient->m_Stats.m_SwapUsed, pClient->m_Stats.m_HDDTotal, pClient->m_Stats.m_HDDUsed, pClient->m_Stats.m_CPU, pClient->m_Stats.m_IORead, pClient->m_Stats.m_IOWrite); - else if(rStart["online6"].type) - dbg_msg("main", "Online6: %s\nUptime: %" PRId64 "\nLoad_1: %f\nLoad_5: %f\nLoad_15: %f\nPing_10010: %f\nPing_189: %f\nPing_10086: %f\nTime_10010: %" PRId64 "\nTime_189: %" PRId64 "\nTime_10086: %" PRId64 "\nTcp_count: %" PRId64 "\nUdp_count: %" PRId64 "\nprocess_count: %" PRId64 "\nthread_count: %" PRId64 "\nNetworkRx: %" PRId64 "\nNetworkTx: %" PRId64 "\nNetworkIN: %" PRId64 "\nNetworkOUT: %" PRId64 "\nMemTotal: %" PRId64 "\nMemUsed: %" PRId64 "\nSwapTotal: %" PRId64 "\nSwapUsed: %" PRId64 "\nHDDTotal: %" PRId64 "\nHDDUsed: %" PRId64 "\nCPU: %f\nIORead: %" PRId64 "\nIOWrite: %" PRId64 "\n", - rStart["online6"].u.boolean ? "true" : "false", - pClient->m_Stats.m_Uptime, - pClient->m_Stats.m_Load_1, pClient->m_Stats.m_Load_5, pClient->m_Stats.m_Load_15, pClient->m_Stats.m_ping_10010, pClient->m_Stats.m_ping_189, pClient->m_Stats.m_ping_10086, pClient->m_Stats.m_time_10010, pClient->m_Stats.m_time_189, pClient->m_Stats.m_time_10086,pClient->m_Stats.m_tcpCount,pClient->m_Stats.m_udpCount,pClient->m_Stats.m_processCount,pClient->m_Stats.m_threadCount,pClient->m_Stats.m_NetworkRx, pClient->m_Stats.m_NetworkTx, pClient->m_Stats.m_NetworkIN, pClient->m_Stats.m_NetworkOUT, pClient->m_Stats.m_MemTotal, pClient->m_Stats.m_MemUsed, pClient->m_Stats.m_SwapTotal, pClient->m_Stats.m_SwapUsed, pClient->m_Stats.m_HDDTotal, pClient->m_Stats.m_HDDUsed, pClient->m_Stats.m_CPU, pClient->m_Stats.m_IORead, pClient->m_Stats.m_IOWrite); - else - dbg_msg("main", "Uptime: %" PRId64 "\nLoad_1: %f\nLoad_5: %f\nLoad_15: %f\nPing_10010: %f\nPing_189: %f\nPing_10086: %f\nTime_10010: %" PRId64 "\nTime_189: %" PRId64 "\nTime_10086: %" PRId64 "\nTcp_count: %" PRId64 "\nUdp_count: %" PRId64 "\nprocess_count: %" PRId64 "\nthread_count: %" PRId64 "\nNetworkRx: %" PRId64 "\nNetworkTx: %" PRId64 "\nNetworkIN: %" PRId64 "\nNetworkOUT: %" PRId64 "\nMemTotal: %" PRId64 "\nMemUsed: %" PRId64 "\nSwapTotal: %" PRId64 "\nSwapUsed: %" PRId64 "\nHDDTotal: %" PRId64 "\nHDDUsed: %" PRId64 "\nCPU: %f\nIORead: %" PRId64 "\nIOWrite: %" PRId64 "\n", - pClient->m_Stats.m_Uptime, - pClient->m_Stats.m_Load_1, pClient->m_Stats.m_Load_5, pClient->m_Stats.m_Load_15, pClient->m_Stats.m_ping_10010, pClient->m_Stats.m_ping_189, pClient->m_Stats.m_ping_10086, pClient->m_Stats.m_time_10010, pClient->m_Stats.m_time_189, pClient->m_Stats.m_time_10086,pClient->m_Stats.m_tcpCount,pClient->m_Stats.m_udpCount,pClient->m_Stats.m_processCount,pClient->m_Stats.m_threadCount,pClient->m_Stats.m_NetworkRx, pClient->m_Stats.m_NetworkTx, pClient->m_Stats.m_NetworkIN, pClient->m_Stats.m_NetworkOUT, pClient->m_Stats.m_MemTotal, pClient->m_Stats.m_MemUsed, pClient->m_Stats.m_SwapTotal, pClient->m_Stats.m_SwapUsed, pClient->m_Stats.m_HDDTotal, pClient->m_Stats.m_HDDUsed, pClient->m_Stats.m_CPU, pClient->m_Stats.m_IORead, pClient->m_Stats.m_IOWrite); - } - - // clean up - json_value_free(pJsonData); - - if(pClient->m_Stats.m_Pong) - m_Server.Network()->Send(ClientNetID, "0"); - return 0; - } - else if(str_comp_num(pMessage, "pong", sizeof("pong")-1) == 0) - { - char *pData = str_skip_whitespaces(&pMessage[sizeof("pong")-1]); - - if(!str_comp(pData, "0") || !str_comp(pData, "off")) - pClient->m_Stats.m_Pong = false; - else if(!str_comp(pData, "1") || !str_comp(pData, "on")) - pClient->m_Stats.m_Pong = true; - - return 0; - } - - if(pClient->m_Stats.m_Pong) - m_Server.Network()->Send(ClientNetID, "1"); - - return 1; -} - - -void CMain::WatchdogMessage(int ClientNetID, double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, - double time_10010, double time_189, double time_10086, double tcp_count, double udp_count, double process_count, double thread_count, - double network_rx, double network_tx, double network_in, double network_out, double last_network_in, double last_network_out, double memory_total, double memory_used, - double swap_total, double swap_used, double hdd_total, double hdd_used, double io_read, double io_write, double cpu, - double online4, double online6) -{ - int ID = 0; - while (strcmp(Watchdog(ID)->m_aName, "NULL")) - { -// Exprtk库默认使用窄字符类型,但可能会出现中文等Unicode字符无法正确解析的问题。 -// todo: 为解决此问题,可以使用宽字符类型替换Exprtk库中默认的窄字符类型。 -// #include -// #include -// #include -// typedef exprtk::expression expression_type; -// typedef exprtk::parser parser_type; -// int main() -// { -// std::wstring expression_string = L"sin(x)"; -// expression_type expression; -// parser_type parser; -// parser.compile(expression_string, expression); -// double x = 3.14; -// double result = expression.value(); -// return 0; -// } - typedef exprtk::symbol_table symbol_table_t; - typedef exprtk::expression expression_t; - typedef exprtk::parser parser_t; - const std::string expression_string = Watchdog(ID)->m_aRule; - int ClientID = ClientNetToClient(ClientNetID); - if(ClientID < 0 || ClientID >= NET_MAX_CLIENTS) { - ID++; - continue; // 无效客户端,跳过当前 watchdog 规则 - } - std::string username = Client(ClientID)->m_aUsername; - std::string name = Client(ClientID)->m_aName; - std::string type = Client(ClientID)->m_aType; - std::string host = Client(ClientID)->m_aHost; - std::string location = Client(ClientID)->m_aLocation; - - symbol_table_t symbol_table; - symbol_table.add_stringvar("username", username); - symbol_table.add_stringvar("name", name); - symbol_table.add_stringvar("type", type); - symbol_table.add_stringvar("host", host); - symbol_table.add_stringvar("location", location); - symbol_table.add_variable("load_1",load_1); - symbol_table.add_variable("load_5",load_5); - symbol_table.add_variable("load_15",load_15); - symbol_table.add_variable("ping_10010",ping_10010); - symbol_table.add_variable("ping_189",ping_189); - symbol_table.add_variable("ping_10086",ping_10086); - symbol_table.add_variable("time_10010",time_10010); - symbol_table.add_variable("time_189",time_189); - symbol_table.add_variable("time_10086",time_10086); - symbol_table.add_variable("tcp_count",tcp_count); - symbol_table.add_variable("udp_count",udp_count); - symbol_table.add_variable("process_count",process_count); - symbol_table.add_variable("thread_count",thread_count); - symbol_table.add_variable("network_rx",network_rx); - symbol_table.add_variable("network_tx",network_tx); - symbol_table.add_variable("network_in",network_in); - symbol_table.add_variable("network_out",network_out); - symbol_table.add_variable("last_network_in",last_network_in); - symbol_table.add_variable("last_network_out",last_network_out); - symbol_table.add_variable("memory_total",memory_total); - symbol_table.add_variable("memory_used",memory_used); - symbol_table.add_variable("swap_total",swap_total); - symbol_table.add_variable("swap_used",swap_used); - symbol_table.add_variable("hdd_total",hdd_total); - symbol_table.add_variable("hdd_used",hdd_used); - symbol_table.add_variable("io_read",io_read); - symbol_table.add_variable("io_write",io_write); - symbol_table.add_variable("cpu",cpu); - symbol_table.add_variable("online4",online4); - symbol_table.add_variable("online6",online6); - symbol_table.add_constants(); - - expression_t expression; - expression.register_symbol_table(symbol_table); - - parser_t parser; - parser.compile(expression_string,expression); - - if (expression.value() > 0) - { - time_t currentStamp = (long long)time(/*ago*/0); - if ((currentStamp-Client(ClientID)->m_AlarmLastTime) > Watchdog(ID)->m_aInterval) - { - if (!Client(ClientID)->m_Stats.m_Online4 && !Client(ClientID)->m_Stats.m_Online6) - { - //休眠5分钟如果5分钟后状态发生了变更,消息不发出。 - printf("download\n"); - } - Client(ClientID)->m_AlarmLastTime = currentStamp; - CURL *curl; - CURLcode res; - curl_global_init(CURL_GLOBAL_ALL); - - curl = curl_easy_init(); - if(curl) { - //standard time - char standardTime[32]= { 0 }; - strftime(standardTime, sizeof(standardTime), "%Y-%m-%d %H:%M:%S",localtime(¤tStamp)); - - //url encode, Rules conflict with url special characters,eg:&, del rules, by https://cpp.la, 2023-10-09 - char encodeBuffer[2048] = { 0 }; - sprintf(encodeBuffer, "【告警名称】 %s \n\n【告警时间】 %s \n\n【用户名】 %s \n\n【节点名】 %s \n\n【虚拟化】 %s \n\n【主机名】 %s \n\n【位 置】 %s", - Watchdog(ID)->m_aName, - standardTime, - username.c_str(), - name.c_str(), - type.c_str(), - host.c_str(), - location.c_str()); - char *encodeUrl = curl_easy_escape(curl, encodeBuffer, strlen(encodeBuffer)); - - //standard url - char urlBuffer[2048] = { 0 }; - sprintf(urlBuffer, "%s%s",Watchdog(ID)->m_aCallback, encodeUrl); - - - curl_easy_setopt(curl, CURLOPT_POST, 1L); - curl_easy_setopt(curl, CURLOPT_URL, urlBuffer); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS,"signature=ServerStatus"); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L); - res = curl_easy_perform(curl); - if(res != CURLE_OK) - fprintf(stderr, "watchdog failed: %s\n", curl_easy_strerror(res)); - if(encodeUrl) - curl_free(encodeUrl); - curl_easy_cleanup(curl); - } - curl_global_cleanup(); - } - } - ID++; - } -} - -void CMain::JSONUpdateThread(void *pUser) -{ - CJSONUpdateThreadData *m_pJSONUpdateThreadData = (CJSONUpdateThreadData *)pUser; - CClient *pClients = m_pJSONUpdateThreadData->pClients; - CConfig *pConfig = m_pJSONUpdateThreadData->pConfig; - - while(gs_Running) - { - char aFileBuf[2048*NET_MAX_CLIENTS]; - char *pBuf = aFileBuf; - - str_format(pBuf, sizeof(aFileBuf), "{\n\"servers\": [\n"); - pBuf += strlen(pBuf); - - for(int i = 0; i < NET_MAX_CLIENTS; i++) - { - if(!pClients[i].m_Active || pClients[i].m_Disabled) - continue; - - if(pClients[i].m_Connected) - { - // Uptime - char aUptime[16]; - int Days = pClients[i].m_Stats.m_Uptime/60.0/60.0/24.0; - if(Days > 0) - { - if(Days > 1) - str_format(aUptime, sizeof(aUptime), "%d 天", Days); - else - str_format(aUptime, sizeof(aUptime), "%d 天", Days); - } - else - str_format(aUptime, sizeof(aUptime), "%02d:%02d:%02d", (int)(pClients[i].m_Stats.m_Uptime/60.0/60.0), (int)((pClients[i].m_Stats.m_Uptime/60)%60), (int)((pClients[i].m_Stats.m_Uptime)%60)); - - // track month network traffic, diff: 2021-10-01 00:05, 5minutes - // last_network_in/out is last record flag. - time_t currentStamp = (long long)time(/*ago*/0); - if(0 == pClients[i].m_LastNetworkIN || (0 != pClients[i].m_Stats.m_NetworkIN && pClients[i].m_LastNetworkIN > pClients[i].m_Stats.m_NetworkIN) || (localtime(¤tStamp)->tm_mday == pClients[i].m_aMonthStart && localtime(¤tStamp)->tm_hour == 0 && localtime(¤tStamp)->tm_min < 5)) - { - pClients[i].m_LastNetworkIN = pClients[i].m_Stats.m_NetworkIN; - pClients[i].m_LastNetworkOUT = pClients[i].m_Stats.m_NetworkOUT; - } - - char aCustomEsc[2048] = { 0 }; - char aOSEsc[128] = { 0 }; - char aCPUModelEsc[384] = { 0 }; - JsonEscape(pClients[i].m_Stats.m_aCustom, aCustomEsc, sizeof(aCustomEsc)); - JsonEscape(pClients[i].m_Stats.m_aOS[0] ? pClients[i].m_Stats.m_aOS : "", aOSEsc, sizeof(aOSEsc)); - JsonEscape(pClients[i].m_Stats.m_aCPUModel[0] ? pClients[i].m_Stats.m_aCPUModel : "", aCPUModelEsc, sizeof(aCPUModelEsc)); - str_format(pBuf, sizeof(aFileBuf) - (pBuf - aFileBuf), - "{ \"name\": \"%s\",\"type\": \"%s\",\"host\": \"%s\",\"location\": \"%s\",\"online4\": %s, \"online6\": %s, \"uptime\": \"%s\",\"load_1\": %.2f, \"load_5\": %.2f, \"load_15\": %.2f,\"ping_10010\": %.2f, \"ping_189\": %.2f, \"ping_10086\": %.2f,\"time_10010\": %" PRId64 ", \"time_189\": %" PRId64 ", \"time_10086\": %" PRId64 ", \"tcp_count\": %" PRId64 ", \"udp_count\": %" PRId64 ", \"process_count\": %" PRId64 ", \"thread_count\": %" PRId64 ", \"network_rx\": %" PRId64 ", \"network_tx\": %" PRId64 ", \"network_in\": %" PRId64 ", \"network_out\": %" PRId64 ", \"cpu\": %d, \"cpu_cores\": %" PRId64 ", \"cpu_model\": \"%s\", \"memory_total\": %" PRId64 ", \"memory_used\": %" PRId64 ", \"swap_total\": %" PRId64 ", \"swap_used\": %" PRId64 ", \"hdd_total\": %" PRId64 ", \"hdd_used\": %" PRId64 ", \"last_network_in\": %" PRId64 ", \"last_network_out\": %" PRId64 ",\"io_read\": %" PRId64 ", \"io_write\": %" PRId64 ",\"custom\": \"%s\", \"os\": \"%s\" },\n", - pClients[i].m_aName,pClients[i].m_aType,pClients[i].m_aHost,pClients[i].m_aLocation, - pClients[i].m_Stats.m_Online4 ? "true" : "false",pClients[i].m_Stats.m_Online6 ? "true" : "false", - aUptime, pClients[i].m_Stats.m_Load_1, pClients[i].m_Stats.m_Load_5, pClients[i].m_Stats.m_Load_15, pClients[i].m_Stats.m_ping_10010, pClients[i].m_Stats.m_ping_189, pClients[i].m_Stats.m_ping_10086, - pClients[i].m_Stats.m_time_10010, pClients[i].m_Stats.m_time_189, pClients[i].m_Stats.m_time_10086,pClients[i].m_Stats.m_tcpCount,pClients[i].m_Stats.m_udpCount,pClients[i].m_Stats.m_processCount,pClients[i].m_Stats.m_threadCount, - pClients[i].m_Stats.m_NetworkRx, pClients[i].m_Stats.m_NetworkTx, pClients[i].m_Stats.m_NetworkIN, pClients[i].m_Stats.m_NetworkOUT, (int)pClients[i].m_Stats.m_CPU, pClients[i].m_Stats.m_CPUCores, aCPUModelEsc, pClients[i].m_Stats.m_MemTotal, pClients[i].m_Stats.m_MemUsed, - pClients[i].m_Stats.m_SwapTotal, pClients[i].m_Stats.m_SwapUsed, pClients[i].m_Stats.m_HDDTotal, pClients[i].m_Stats.m_HDDUsed, - pClients[i].m_Stats.m_NetworkIN == 0 || pClients[i].m_LastNetworkIN == 0 ? pClients[i].m_Stats.m_NetworkIN : pClients[i].m_LastNetworkIN, - pClients[i].m_Stats.m_NetworkOUT == 0 || pClients[i].m_LastNetworkOUT == 0 ? pClients[i].m_Stats.m_NetworkOUT : pClients[i].m_LastNetworkOUT, - pClients[i].m_Stats.m_IORead, pClients[i].m_Stats.m_IOWrite, - aCustomEsc, - aOSEsc); - pBuf += strlen(pBuf); - } - else - { - // sava network traffic record to json when close client - // last_network_in == last network in record, last_network_out == last network out record - char aOSEsc[128] = { 0 }; - char aCPUModelEsc[384] = { 0 }; - JsonEscape(pClients[i].m_Stats.m_aOS[0] ? pClients[i].m_Stats.m_aOS : "", aOSEsc, sizeof(aOSEsc)); - JsonEscape(pClients[i].m_Stats.m_aCPUModel[0] ? pClients[i].m_Stats.m_aCPUModel : "", aCPUModelEsc, sizeof(aCPUModelEsc)); - str_format(pBuf, sizeof(aFileBuf) - (pBuf - aFileBuf), "{ \"name\": \"%s\", \"type\": \"%s\", \"host\": \"%s\", \"location\": \"%s\", \"online4\": false, \"online6\": false, \"last_network_in\": %" PRId64 ", \"last_network_out\": %" PRId64 ", \"os\": \"%s\", \"cpu_model\": \"%s\" },\n", - pClients[i].m_aName, pClients[i].m_aType, pClients[i].m_aHost, pClients[i].m_aLocation, pClients[i].m_LastNetworkIN, pClients[i].m_LastNetworkOUT, - aOSEsc, aCPUModelEsc); - pBuf += strlen(pBuf); - } - } - // append ssl certs data - str_format(pBuf - 2, sizeof(aFileBuf) - (pBuf - aFileBuf), "\n],\n\"sslcerts\": [\n"); - pBuf += strlen(pBuf); - for(int si = 0; si < NET_MAX_CLIENTS; si++) - { - if(!m_pJSONUpdateThreadData->pMain->SSLCert(si) || !strcmp(m_pJSONUpdateThreadData->pMain->SSLCert(si)->m_aName, "NULL")) break; - int64_t expire_ts = m_pJSONUpdateThreadData->pMain->SSLCert(si)->m_aExpireTS; - int expire_days = 0; - if(expire_ts>0){ - int64_t nowts = (long long)time(/*ago*/0); - expire_days = (int)((expire_ts - nowts)/86400); - } - str_format(pBuf, sizeof(aFileBuf) - (pBuf - aFileBuf), "{ \"name\": \"%s\", \"domain\": \"%s\", \"port\": %d, \"expire_ts\": %lld, \"expire_days\": %d, \"mismatch\": %s },\n", m_pJSONUpdateThreadData->pMain->SSLCert(si)->m_aName, m_pJSONUpdateThreadData->pMain->SSLCert(si)->m_aDomain, m_pJSONUpdateThreadData->pMain->SSLCert(si)->m_aPort, (long long)expire_ts, expire_days, m_pJSONUpdateThreadData->pMain->SSLCert(si)->m_aHostnameMismatch?"true":"false"); - pBuf += strlen(pBuf); - } - if(pBuf - aFileBuf >= 2) str_format(pBuf - 2, sizeof(aFileBuf) - (pBuf - aFileBuf), "\n],\n\"updated\": \"%lld\"%s\n}", (long long)time(/*ago*/0), m_pJSONUpdateThreadData->m_ReloadRequired?",\n\"reload\": true":""); - if(m_pJSONUpdateThreadData->m_ReloadRequired) m_pJSONUpdateThreadData->m_ReloadRequired--; - pBuf += strlen(pBuf); - - char aJSONFileTmp[1024]; - str_format(aJSONFileTmp, sizeof(aJSONFileTmp), "%s~", pConfig->m_aJSONFile); - IOHANDLE File = io_open(aJSONFileTmp, IOFLAG_WRITE); - if(!File) - { - dbg_msg("main", "Couldn't open %s", aJSONFileTmp); - exit(1); - } - io_write(File, aFileBuf, (pBuf - aFileBuf)); - io_flush(File); - io_close(File); - fs_rename(aJSONFileTmp, pConfig->m_aJSONFile); - thread_sleep(1000); - } - // support by: https://cpp.la. don't remove month traffic record, storage as "stats.json~", remark: 2021-10-18 - // fs_remove(pConfig->m_aJSONFile); - char aJSONFileTmp[1024]; - str_format(aJSONFileTmp, sizeof(aJSONFileTmp), "%s~", pConfig->m_aJSONFile); - fs_rename(pConfig->m_aJSONFile, aJSONFileTmp); -} - -void CMain::offlineAlarmThread(void *pUser) -{ - CJSONUpdateThreadData *m_OfflineAlarmThreadData = (CJSONUpdateThreadData *)pUser; - CClient *pClients = m_OfflineAlarmThreadData->pClients; - CWatchDog *pWatchDogs = m_OfflineAlarmThreadData->pWatchDogs; - volatile short ClientID = m_OfflineAlarmThreadData->m_ReloadRequired; - thread_sleep(25000); - if(!pClients[ClientID].m_Connected) - { - int ID = 0; - while (strcmp(pWatchDogs[ID].m_aName, "NULL")) - { - typedef exprtk::symbol_table symbol_table_t; - typedef exprtk::expression expression_t; - typedef exprtk::parser parser_t; - const std::string expression_string = pWatchDogs[ID].m_aRule; - std::string username = pClients[ClientID].m_aUsername; - std::string name = pClients[ClientID].m_aName; - std::string type = pClients[ClientID].m_aType; - std::string host = pClients[ClientID].m_aHost; - std::string location = pClients[ClientID].m_aLocation; - std::double_t online4 = pClients[ClientID].m_Stats.m_Online4; - std::double_t online6 = pClients[ClientID].m_Stats.m_Online6; - - symbol_table_t symbol_table; - symbol_table.add_stringvar("username", username); - symbol_table.add_stringvar("name", name); - symbol_table.add_stringvar("type", type); - symbol_table.add_stringvar("host", host); - symbol_table.add_stringvar("location", location); - symbol_table.add_variable("online4",online4); - symbol_table.add_variable("online6",online6); - symbol_table.add_constants(); - - expression_t expression; - expression.register_symbol_table(symbol_table); - - parser_t parser; - parser.compile(expression_string,expression); - - if (expression.value() > 0) - { - time_t currentStamp = (long long)time(/*ago*/0); - if ((currentStamp-pClients[ClientID].m_AlarmLastTime) > pWatchDogs[ID].m_aInterval) - { - printf("客户端下线且超过阈值, Client disconnects and sends alert information\n"); - pClients[ClientID].m_AlarmLastTime = currentStamp; - CURL *curl; - CURLcode res; - curl_global_init(CURL_GLOBAL_ALL); - - curl = curl_easy_init(); - if(curl) { - //standard time - char standardTime[32]= { 0 }; - strftime(standardTime, sizeof(standardTime), "%Y-%m-%d %H:%M:%S",localtime(¤tStamp)); - - //url encode, Rules conflict with url special characters,eg:&, del rules, by https://cpp.la, 2023-10-09 - char encodeBuffer[2048] = { 0 }; - sprintf(encodeBuffer, "【告警名称】 %s \n\n【告警时间】 %s \n\n【用户名】 %s \n\n【节点名】 %s \n\n【虚拟化】 %s \n\n【主机名】 %s \n\n【位 置】 %s", - pWatchDogs[ID].m_aName, - standardTime, - pClients[ClientID].m_aUsername, - pClients[ClientID].m_aName, - pClients[ClientID].m_aType, - pClients[ClientID].m_aHost, - pClients[ClientID].m_aLocation); - char *encodeUrl = curl_easy_escape(curl, encodeBuffer, strlen(encodeBuffer)); - - //standard url - char urlBuffer[2048] = { 0 }; - sprintf(urlBuffer, "%s%s",pWatchDogs[ID].m_aCallback, encodeUrl); - - - curl_easy_setopt(curl, CURLOPT_POST, 1L); - curl_easy_setopt(curl, CURLOPT_URL, urlBuffer); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS,"signature=ServerStatus"); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 6L); - res = curl_easy_perform(curl); - if(res != CURLE_OK) - fprintf(stderr, "watchdog failed: %s\n", curl_easy_strerror(res)); - if(encodeUrl) - curl_free(encodeUrl); - curl_easy_cleanup(curl); - } - curl_global_cleanup(); - } - else - printf("客户端下线但未超过阈值,No alarm if the threshold is not exceeded\n"); - } - ID++; - } - } - else - { - printf("网络波动,No alarm information is sent due to network fluctuations\n"); - } - fflush(stdout); -} - -int CMain::ReadConfig() -{ - // read and parse config - IOHANDLE File = io_open(m_Config.m_aConfigFile, IOFLAG_READ); - if(!File) - { - dbg_msg("main", "Couldn't open %s", m_Config.m_aConfigFile); - return 1; - } - int FileSize = (int)io_length(File); - char *pFileData = (char *)mem_alloc(FileSize + 1, 1); - - io_read(File, pFileData, FileSize); - pFileData[FileSize] = 0; - io_close(File); - - // parse json data - json_settings JsonSettings; - mem_zero(&JsonSettings, sizeof(JsonSettings)); - char aError[256]; - json_value *pJsonData = json_parse_ex(&JsonSettings, pFileData, strlen(pFileData), aError); - if(!pJsonData) - { - dbg_msg("main", "JSON Error in file %s: %s", m_Config.m_aConfigFile, aError); - mem_free(pFileData); - return 1; - } - - // reset clients - for(int i = 0; i < NET_MAX_CLIENTS; i++) - { - if(!Client(i)->m_Active || !Client(i)->m_Connected) - continue; - - m_Server.Network()->Drop(Client(i)->m_ClientNetID, "Server reloading..."); - } - mem_zero(m_aClients, sizeof(m_aClients)); - for(int i = 0; i < NET_MAX_CLIENTS; i++) - m_aClients[i].m_ClientNetID = -1; - - // extract data - int ID = 0; - const json_value &rStart = (*pJsonData)["servers"]; - if(rStart.type == json_array) - { - for(unsigned i = 0; i < rStart.u.array.length; i++) - { - if(ID < 0 || ID >= NET_MAX_CLIENTS) - continue; - - Client(ID)->m_Active = true; - Client(ID)->m_Disabled = rStart[i]["disabled"].u.boolean; - str_copy(Client(ID)->m_aName, rStart[i]["name"].u.string.ptr, sizeof(Client(ID)->m_aName)); - str_copy(Client(ID)->m_aUsername, rStart[i]["username"].u.string.ptr, sizeof(Client(ID)->m_aUsername)); - str_copy(Client(ID)->m_aType, rStart[i]["type"].u.string.ptr, sizeof(Client(ID)->m_aType)); - str_copy(Client(ID)->m_aHost, rStart[i]["host"].u.string.ptr, sizeof(Client(ID)->m_aHost)); - str_copy(Client(ID)->m_aLocation, rStart[i]["location"].u.string.ptr, sizeof(Client(ID)->m_aLocation)); - str_copy(Client(ID)->m_aPassword, rStart[i]["password"].u.string.ptr, sizeof(Client(ID)->m_aPassword)); - //if month start day > 28, diff: 3days(29,30,31) - Client(ID)->m_aMonthStart = rStart[i]["monthstart"].u.integer; - if(Client(ID)->m_aMonthStart > 28) - { - Client(ID)->m_aMonthStart = 28; - } - Client(ID)->m_LastNetworkIN = 0; - Client(ID)->m_LastNetworkOUT = 0; - - if(m_Config.m_Verbose) - { - if(Client(ID)->m_Disabled) - dbg_msg("main", "[#%d: Name: \"%s\", Username: \"%s\", Type: \"%s\", Host: \"%s\", Location: \"%s\", Password: \"%s\", MonthStart: %\" PRId64 \"]", - ID, Client(ID)->m_aName, Client(ID)->m_aUsername, Client(ID)->m_aType, Client(ID)->m_aHost, Client(ID)->m_aLocation, Client(ID)->m_aPassword, Client(ID)->m_aMonthStart); - else - dbg_msg("main", "#%d: Name: \"%s\", Username: \"%s\", Type: \"%s\", Host: \"%s\", Location: \"%s\", Password: \"%s\", MonthStart: %\" PRId64 \"", - ID, Client(ID)->m_aName, Client(ID)->m_aUsername, Client(ID)->m_aType, Client(ID)->m_aHost, Client(ID)->m_aLocation, Client(ID)->m_aPassword, Client(ID)->m_aMonthStart); - - } - ID++; - } - } - - // watch dog - // support by: https://cpp.la - ID = 0; - const json_value &jStart = (*pJsonData)["watchdog"]; - if(jStart.type == json_array) - { - for(unsigned i = 0; i < jStart.u.array.length; i++) - { - if(ID < 0 || ID >= NET_MAX_CLIENTS) - continue; - - str_copy(Watchdog(ID)->m_aName, jStart[i]["name"].u.string.ptr, sizeof(Watchdog(ID)->m_aName)); - str_copy(Watchdog(ID)->m_aRule, jStart[i]["rule"].u.string.ptr, sizeof(Watchdog(ID)->m_aRule)); - Watchdog(ID)->m_aInterval = jStart[i]["interval"].u.integer; - str_copy(Watchdog(ID)->m_aCallback, jStart[i]["callback"].u.string.ptr, sizeof(Watchdog(ID)->m_aCallback)); - - ID++; - } - str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName)); - } - else - { - str_copy(Watchdog(ID)->m_aName, "NULL", sizeof(Watchdog(ID)->m_aName)); - } - - // monitor - // support by: https://cpp.la - ID = 0; - const json_value &mStart = (*pJsonData)["monitors"]; - if(mStart.type == json_array) - { - for(unsigned i = 0; i < mStart.u.array.length; i++) - { - if(ID < 0 || ID >= NET_MAX_CLIENTS) - continue; - - str_copy(Monitors(ID)->m_aName, mStart[i]["name"].u.string.ptr, sizeof(Monitors(ID)->m_aName)); - str_copy(Monitors(ID)->m_aHost, mStart[i]["host"].u.string.ptr, sizeof(Monitors(ID)->m_aHost)); - Monitors(ID)->m_aInterval = mStart[i]["interval"].u.integer; - str_copy(Monitors(ID)->m_aType, mStart[i]["type"].u.string.ptr, sizeof(Monitors(ID)->m_aType)); - - ID++; - } - str_copy(Monitors(ID)->m_aName, "NULL", sizeof(Monitors(ID)->m_aName)); - } - else - { - str_copy(Monitors(ID)->m_aName, "NULL", sizeof(Monitors(ID)->m_aName)); - } - - // sslcerts - ID = 0; - const json_value &sStart = (*pJsonData)["sslcerts"]; - if(sStart.type == json_array) - { - for(unsigned i = 0; i < sStart.u.array.length; i++) - { - if(ID < 0 || ID >= NET_MAX_CLIENTS) - continue; - str_copy(SSLCert(ID)->m_aName, sStart[i]["name"].u.string.ptr, sizeof(SSLCert(ID)->m_aName)); - str_copy(SSLCert(ID)->m_aDomain, sStart[i]["domain"].u.string.ptr, sizeof(SSLCert(ID)->m_aDomain)); - SSLCert(ID)->m_aPort = sStart[i]["port"].u.integer; - SSLCert(ID)->m_aInterval = sStart[i]["interval"].u.integer; - str_copy(SSLCert(ID)->m_aCallback, sStart[i]["callback"].u.string.ptr, sizeof(SSLCert(ID)->m_aCallback)); - SSLCert(ID)->m_aExpireTS = 0; // reset - SSLCert(ID)->m_aLastCheck = 0; - SSLCert(ID)->m_aLastAlarm7 = 0; - SSLCert(ID)->m_aLastAlarm3 = 0; - SSLCert(ID)->m_aLastAlarm1 = 0; - ID++; - } - str_copy(SSLCert(ID)->m_aName, "NULL", sizeof(SSLCert(ID)->m_aName)); - }else - str_copy(SSLCert(ID)->m_aName, "NULL", sizeof(SSLCert(ID)->m_aName)); - - // if file exists, read last network traffic record,reset m_LastNetworkIN and m_LastNetworkOUT - // support by: https://cpp.la - IOHANDLE nFile = io_open(m_Config.m_aJSONFile, IOFLAG_READ); - if(!nFile) - { - char aJSONFileTmp[1024]; - str_format(aJSONFileTmp, sizeof(aJSONFileTmp), "%s~", m_Config.m_aJSONFile); - nFile = io_open(aJSONFileTmp, IOFLAG_READ); - } - if(nFile) - { - int nFileSize = (int)io_length(nFile); - char *pNFileData = (char *)mem_alloc(nFileSize + 1, 1); - - io_read(nFile, pNFileData, nFileSize); - pNFileData[nFileSize] = 0; - io_close(nFile); - - json_settings nJsonSettings; - mem_zero(&nJsonSettings, sizeof(nJsonSettings)); - json_value *pNJsonData = json_parse_ex(&nJsonSettings, pNFileData, strlen(pNFileData), aError); - if(pNJsonData) - { - const json_value &cStart = (*pNJsonData)["servers"]; - if(rStart.type == json_array) - { - int ID = 0; - for(unsigned i = 0; i < rStart.u.array.length; i++) - { - if(ID < 0 || ID >= NET_MAX_CLIENTS) - continue; - for(unsigned j = 0; j < cStart.u.array.length; j++) - { - if(strcmp(Client(ID)->m_aName, cStart[j]["name"].u.string.ptr)==0 && - strcmp(Client(ID)->m_aType, cStart[j]["type"].u.string.ptr)==0 && - strcmp(Client(ID)->m_aHost, cStart[j]["host"].u.string.ptr)==0 && - strcmp(Client(ID)->m_aLocation, cStart[j]["location"].u.string.ptr)==0) - { - Client(ID)->m_LastNetworkIN = cStart[j]["last_network_in"].u.integer; - Client(ID)->m_LastNetworkOUT = cStart[j]["last_network_out"].u.integer; - break; - } - } - ID++; - } - } - json_value_free(pNJsonData); - } - mem_free(pNFileData); - } - - // clean up - json_value_free(pJsonData); - mem_free(pFileData); - - // tell clients to reload the page - m_JSONUpdateThreadData.m_ReloadRequired = 2; - - return 0; -} - -int CMain::Run() -{ - if(m_Server.Init(this, m_Config.m_aBindAddr, m_Config.m_Port)) - return 1; - - if(ReadConfig()) - return 1; - - // Start JSON Update Thread - m_JSONUpdateThreadData.m_ReloadRequired = 2; - m_JSONUpdateThreadData.pClients = m_aClients; - m_JSONUpdateThreadData.pConfig = &m_Config; - m_JSONUpdateThreadData.pWatchDogs = m_aCWatchDogs; - m_JSONUpdateThreadData.pMain = this; - void *LoadThread = thread_create(JSONUpdateThread, &m_JSONUpdateThreadData); - // Start SSL check thread - static SSLCheckThreadData sslData; sslData.pMain = this; thread_create(SSLCheckThread, &sslData); - //thread_detach(LoadThread); - - while(gs_Running) - { - if(gs_ReloadConfig) - { - if(ReadConfig()) - return 1; - m_Server.NetBan()->UnbanAll(); - gs_ReloadConfig = 0; - } - - m_Server.Update(); - - // wait for incomming data - net_socket_read_wait(*m_Server.Network()->Socket(), 10); - } - - dbg_msg("server", "Closing."); - m_Server.Network()->Close(); - thread_wait(LoadThread); - - return 0; -} - -int main(int argc, const char *argv[]) -{ - int RetVal; - dbg_logger_stdout(); - - #if defined(CONF_FAMILY_UNIX) - signal(SIGINT, ExitFunc); - signal(SIGTERM, ExitFunc); - signal(SIGQUIT, ExitFunc); - signal(SIGHUP, ReloadFunc); - #endif - - char aUsage[128]; - CConfig Config; - str_format(aUsage, sizeof(aUsage), "%s [options]", argv[0]); - const char *pConfigFile = 0; - const char *pWebDir = 0; - const char *pBindAddr = 0; - - struct argparse_option aOptions[] = { - OPT_HELP(), - OPT_BOOLEAN('v', "verbose", &Config.m_Verbose, "Verbose output", 0), - OPT_STRING('c', "config", &pConfigFile, "Config file to use", 0), - OPT_STRING('d', "web-dir", &pWebDir, "Location of the web directory", 0), - OPT_STRING('b', "bind", &pBindAddr, "Bind to address", 0), - OPT_INTEGER('p', "port", &Config.m_Port, "Listen on port", 0), - OPT_END(), - }; - struct argparse Argparse; - argparse_init(&Argparse, aOptions, aUsage, 0); - argc = argparse_parse(&Argparse, argc, argv); - - if(pConfigFile) - str_copy(Config.m_aConfigFile, pConfigFile, sizeof(Config.m_aConfigFile)); - if(pWebDir) - str_copy(Config.m_aWebDir, pWebDir, sizeof(Config.m_aWebDir)); - if(pBindAddr) - str_copy(Config.m_aBindAddr, pBindAddr, sizeof(Config.m_aBindAddr)); - - if(Config.m_aWebDir[strlen(Config.m_aWebDir)-1] != '/') - str_append(Config.m_aWebDir, "/", sizeof(Config.m_aWebDir)); - if(!fs_is_dir(Config.m_aWebDir)) - { - dbg_msg("main", "ERROR: Can't find web directory: %s", Config.m_aWebDir); - return 1; - } - - char aTmp[1024]; - str_format(aTmp, sizeof(aTmp), "%s%s", Config.m_aWebDir, Config.m_aJSONFile); - str_copy(Config.m_aJSONFile, aTmp, sizeof(Config.m_aJSONFile)); - - CMain Main(Config); - RetVal = Main.Run(); - - return RetVal; -} diff --git a/server/src/main.h b/server/src/main.h deleted file mode 100644 index 9e0d7be..0000000 --- a/server/src/main.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef MAIN_H -#define MAIN_H - -#include -#include "server.h" - -class CConfig -{ -public: - bool m_Verbose; - char m_aConfigFile[1024]; - char m_aWebDir[1024]; - char m_aTemplateFile[1024]; - char m_aJSONFile[1024]; - char m_aBindAddr[256]; - int m_Port; - - CConfig(); -}; - -class CMain -{ - CConfig m_Config; - CServer m_Server; - - struct CClient - { - bool m_Active; - bool m_Disabled; - bool m_Connected; - int m_ClientNetID; - int m_ClientNetType; - char m_aUsername[128]; - char m_aName[128]; - char m_aType[128]; - char m_aHost[128]; - char m_aLocation[128]; - char m_aPassword[128]; - int m_aMonthStart; //track month network traffic. by: https://cpp.la - - int64_t m_LastNetworkIN; //restore month traffic info. - int64_t m_LastNetworkOUT; //restore month traffic info. - int64_t m_TimeConnected; - int64_t m_LastUpdate; - int64_t m_AlarmLastTime; //record last alarm time. - - struct CStats - { - bool m_Online4; - bool m_Online6; - // bool m_IpStatus, delete ip_status check, Duplicate packet loss rate detection - // mh361 or mh370, mourn mh370, 2014-03-08 01:20 lost from all over the world. by:https://cpp.la - int64_t m_Uptime; - double m_Load_1; - double m_Load_5; - double m_Load_15; - double m_ping_10010; - double m_ping_189; - double m_ping_10086; - int64_t m_time_10010; - int64_t m_time_189; - int64_t m_time_10086; - int64_t m_NetworkRx; - int64_t m_NetworkTx; - int64_t m_NetworkIN; - int64_t m_NetworkOUT; - int64_t m_MemTotal; - int64_t m_MemUsed; - int64_t m_SwapTotal; - int64_t m_SwapUsed; - int64_t m_HDDTotal; - int64_t m_HDDUsed; - int64_t m_tcpCount; - int64_t m_udpCount; - int64_t m_processCount; - int64_t m_threadCount; - int64_t m_IORead; - int64_t m_IOWrite; - int64_t m_CPUCores; - double m_CPU; - char m_aCustom[1024]; - char m_aCPUModel[192]; - // OS name reported by client (e.g. linux/windows/darwin/freebsd) - char m_aOS[64]; - // Options - bool m_Pong; - } m_Stats; - } m_aClients[NET_MAX_CLIENTS]; - - struct CWatchDog{ - char m_aName[128]; - char m_aRule[128]; - int m_aInterval; - char m_aCallback[1024]; - } m_aCWatchDogs[NET_MAX_CLIENTS]; - - struct CMonitors{ - char m_aName[128]; - char m_aHost[128]; - int m_aInterval; - char m_aType[128]; - } m_aCMonitors[NET_MAX_CLIENTS]; -public: - struct CSSLCerts{ - char m_aName[128]; - char m_aDomain[256]; - int m_aPort; - int m_aInterval; // seconds - char m_aCallback[1024]; - int64_t m_aExpireTS; // epoch seconds cache - int64_t m_aLastCheck; // last check time - int64_t m_aLastAlarm7; - int64_t m_aLastAlarm3; - int64_t m_aLastAlarm1; - int m_aHostnameMismatch; // 1: 域名与证书不匹配 - int64_t m_aLastAlarmMismatch; // 上次不匹配告警时间 - } m_aCSSLCerts[NET_MAX_CLIENTS]; - - struct CJSONUpdateThreadData - { - CClient *pClients; - CConfig *pConfig; - CWatchDog *pWatchDogs; - CMain *pMain; - volatile short m_ReloadRequired; - } m_JSONUpdateThreadData, m_OfflineAlarmThreadData; - - static void JSONUpdateThread(void *pUser); - static void offlineAlarmThread(void *pUser); -public: - CMain(CConfig Config); - - void OnNewClient(int ClienNettID, int ClientID); - void OnDelClient(int ClientNetID); - int HandleMessage(int ClientNetID, char *pMessage); - int ReadConfig(); - int Run(); - - CWatchDog *Watchdog(int ruleID) { return &m_aCWatchDogs[ruleID]; } - CMonitors *Monitors(int ruleID) { return &m_aCMonitors[ruleID]; } - CSSLCerts *SSLCert(int ruleID) { return &m_aCSSLCerts[ruleID]; } - - void WatchdogMessage(int ClientNetID, - double load_1, double load_5, double load_15, double ping_10010, double ping_189, double ping_10086, - double time_10010, double time_189, double time_10086, double tcp_count, double udp_count, double process_count, double thread_count, - double network_rx, double network_tx, double network_in, double network_out, double last_network_in, double last_network_out, - double memory_total, double memory_used,double swap_total, double swap_used, double hdd_total, - double hdd_used, double io_read, double io_write, double cpu,double online4, double online6); - - CClient *Client(int ClientID) { return &m_aClients[ClientID]; } - CClient *ClientNet(int ClientNetID); - const CConfig *Config() const { return &m_Config; } - int ClientNetToClient(int ClientNetID); -}; - - -#endif diff --git a/server/src/netban.cpp b/server/src/netban.cpp deleted file mode 100644 index 0ed2d65..0000000 --- a/server/src/netban.cpp +++ /dev/null @@ -1,463 +0,0 @@ -#include -#include "netban.h" - -bool CNetBan::StrAllnum(const char *pStr) -{ - while(*pStr) - { - if(!(*pStr >= '0' && *pStr <= '9')) - return false; - pStr++; - } - return true; -} - - -CNetBan::CNetHash::CNetHash(const NETADDR *pAddr) -{ - if(pAddr->type==NETTYPE_IPV4) - m_Hash = (pAddr->ip[0]+pAddr->ip[1]+pAddr->ip[2]+pAddr->ip[3])&0xFF; - else - m_Hash = (pAddr->ip[0]+pAddr->ip[1]+pAddr->ip[2]+pAddr->ip[3]+pAddr->ip[4]+pAddr->ip[5]+pAddr->ip[6]+pAddr->ip[7]+ - pAddr->ip[8]+pAddr->ip[9]+pAddr->ip[10]+pAddr->ip[11]+pAddr->ip[12]+pAddr->ip[13]+pAddr->ip[14]+pAddr->ip[15])&0xFF; - m_HashIndex = 0; -} - -CNetBan::CNetHash::CNetHash(const CNetRange *pRange) -{ - m_Hash = 0; - m_HashIndex = 0; - for(int i = 0; pRange->m_LB.ip[i] == pRange->m_UB.ip[i]; ++i) - { - m_Hash += pRange->m_LB.ip[i]; - ++m_HashIndex; - } - m_Hash &= 0xFF; -} - -int CNetBan::CNetHash::MakeHashArray(const NETADDR *pAddr, CNetHash aHash[17]) -{ - int Length = pAddr->type==NETTYPE_IPV4 ? 4 : 16; - aHash[0].m_Hash = 0; - aHash[0].m_HashIndex = 0; - for(int i = 1, Sum = 0; i <= Length; ++i) - { - Sum += pAddr->ip[i-1]; - aHash[i].m_Hash = Sum&0xFF; - aHash[i].m_HashIndex = i%Length; - } - return Length; -} - - -template -typename CNetBan::CBan *CNetBan::CBanPool::Add(const T *pData, const CBanInfo *pInfo, const CNetHash *pNetHash) -{ - if(!m_pFirstFree) - return 0; - - // create new ban - CBan *pBan = m_pFirstFree; - pBan->m_Data = *pData; - pBan->m_Info = *pInfo; - pBan->m_NetHash = *pNetHash; - if(pBan->m_pNext) - pBan->m_pNext->m_pPrev = pBan->m_pPrev; - if(pBan->m_pPrev) - pBan->m_pPrev->m_pNext = pBan->m_pNext; - else - m_pFirstFree = pBan->m_pNext; - - // add it to the hash list - if(m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]) - m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]->m_pHashPrev = pBan; - pBan->m_pHashPrev = 0; - pBan->m_pHashNext = m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]; - m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash] = pBan; - - // insert it into the used list - if(m_pFirstUsed) - { - for(CBan *p = m_pFirstUsed; ; p = p->m_pNext) - { - if(p->m_Info.m_Expires == CBanInfo::EXPIRES_NEVER || (pInfo->m_Expires != CBanInfo::EXPIRES_NEVER && pInfo->m_Expires <= p->m_Info.m_Expires)) - { - // insert before - pBan->m_pNext = p; - pBan->m_pPrev = p->m_pPrev; - if(p->m_pPrev) - p->m_pPrev->m_pNext = pBan; - else - m_pFirstUsed = pBan; - p->m_pPrev = pBan; - break; - } - - if(!p->m_pNext) - { - // last entry - p->m_pNext = pBan; - pBan->m_pPrev = p; - pBan->m_pNext = 0; - break; - } - } - } - else - { - m_pFirstUsed = pBan; - pBan->m_pNext = pBan->m_pPrev = 0; - } - - // update ban count - ++m_CountUsed; - - return pBan; -} - -template -int CNetBan::CBanPool::Remove(CBan *pBan) -{ - if(pBan == 0) - return -1; - - // remove from hash list - if(pBan->m_pHashNext) - pBan->m_pHashNext->m_pHashPrev = pBan->m_pHashPrev; - if(pBan->m_pHashPrev) - pBan->m_pHashPrev->m_pHashNext = pBan->m_pHashNext; - else - m_paaHashList[pBan->m_NetHash.m_HashIndex][pBan->m_NetHash.m_Hash] = pBan->m_pHashNext; - pBan->m_pHashNext = pBan->m_pHashPrev = 0; - - // remove from used list - if(pBan->m_pNext) - pBan->m_pNext->m_pPrev = pBan->m_pPrev; - if(pBan->m_pPrev) - pBan->m_pPrev->m_pNext = pBan->m_pNext; - else - m_pFirstUsed = pBan->m_pNext; - - // add to recycle list - if(m_pFirstFree) - m_pFirstFree->m_pPrev = pBan; - pBan->m_pPrev = 0; - pBan->m_pNext = m_pFirstFree; - m_pFirstFree = pBan; - - // update ban count - --m_CountUsed; - - return 0; -} - -template -void CNetBan::CBanPool::Update(CBan *pBan, const CBanInfo *pInfo) -{ - pBan->m_Info = *pInfo; - - // remove from used list - if(pBan->m_pNext) - pBan->m_pNext->m_pPrev = pBan->m_pPrev; - if(pBan->m_pPrev) - pBan->m_pPrev->m_pNext = pBan->m_pNext; - else - m_pFirstUsed = pBan->m_pNext; - - // insert it into the used list - if(m_pFirstUsed) - { - for(CBan *p = m_pFirstUsed; ; p = p->m_pNext) - { - if(p->m_Info.m_Expires == CBanInfo::EXPIRES_NEVER || (pInfo->m_Expires != CBanInfo::EXPIRES_NEVER && pInfo->m_Expires <= p->m_Info.m_Expires)) - { - // insert before - pBan->m_pNext = p; - pBan->m_pPrev = p->m_pPrev; - if(p->m_pPrev) - p->m_pPrev->m_pNext = pBan; - else - m_pFirstUsed = pBan; - p->m_pPrev = pBan; - break; - } - - if(!p->m_pNext) - { - // last entry - p->m_pNext = pBan; - pBan->m_pPrev = p; - pBan->m_pNext = 0; - break; - } - } - } - else - { - m_pFirstUsed = pBan; - pBan->m_pNext = pBan->m_pPrev = 0; - } -} - -template -void CNetBan::CBanPool::Reset() -{ - mem_zero(m_paaHashList, sizeof(m_paaHashList)); - mem_zero(m_aBans, sizeof(m_aBans)); - m_pFirstUsed = 0; - m_CountUsed = 0; - - for(int i = 1; i < MAX_BANS-1; ++i) - { - m_aBans[i].m_pNext = &m_aBans[i+1]; - m_aBans[i].m_pPrev = &m_aBans[i-1]; - } - - m_aBans[0].m_pNext = &m_aBans[1]; - m_aBans[MAX_BANS-1].m_pPrev = &m_aBans[MAX_BANS-2]; - m_pFirstFree = &m_aBans[0]; -} - -template -typename CNetBan::CBan *CNetBan::CBanPool::Get(int Index) const -{ - if(Index < 0 || Index >= Num()) - return 0; - - for(CNetBan::CBan *pBan = m_pFirstUsed; pBan; pBan = pBan->m_pNext, --Index) - { - if(Index == 0) - return pBan; - } - - return 0; -} - - -template -void CNetBan::MakeBanInfo(const CBan *pBan, char *pBuf, unsigned BuffSize, int Type) const -{ - if(pBan == 0 || pBuf == 0) - { - if(BuffSize > 0) - pBuf[0] = 0; - return; - } - - // build type based part - char aBuf[256]; - if(Type == MSGTYPE_PLAYER) - str_copy(aBuf, "You have been banned", sizeof(aBuf)); - else - { - char aTemp[256]; - switch(Type) - { - case MSGTYPE_LIST: - str_format(aBuf, sizeof(aBuf), "%s banned", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break; - case MSGTYPE_BANADD: - str_format(aBuf, sizeof(aBuf), "banned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break; - case MSGTYPE_BANREM: - str_format(aBuf, sizeof(aBuf), "unbanned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break; - default: - aBuf[0] = 0; - } - } - - // add info part - if(pBan->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER) - { - int Mins = ((pBan->m_Info.m_Expires-time_timestamp()) + 59) / 60; - if(Mins <= 1) - str_format(pBuf, BuffSize, "%s for 1 minute (%s)", aBuf, pBan->m_Info.m_aReason); - else - str_format(pBuf, BuffSize, "%s for %d minutes (%s)", aBuf, Mins, pBan->m_Info.m_aReason); - } - else - str_format(pBuf, BuffSize, "%s for life (%s)", aBuf, pBan->m_Info.m_aReason); -} - -template -int CNetBan::Ban(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason) -{ - // do not ban localhost - if(NetMatch(pData, &m_LocalhostIPV4) || NetMatch(pData, &m_LocalhostIPV6)) - { - dbg_msg("net_ban", "ban failed (localhost)"); - return -1; - } - - int Stamp = Seconds > 0 ? time_timestamp()+Seconds : CBanInfo::EXPIRES_NEVER; - - // set up info - CBanInfo Info = {0}; - Info.m_Expires = Stamp; - str_copy(Info.m_aReason, pReason, sizeof(Info.m_aReason)); - - // check if it already exists - CNetHash NetHash(pData); - CBan *pBan = pBanPool->Find(pData, &NetHash); - if(pBan) - { - // adjust the ban - pBanPool->Update(pBan, &Info); - char aBuf[128]; - MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_LIST); - dbg_msg("net_ban", aBuf); - return 1; - } - - // add ban and print result - pBan = pBanPool->Add(pData, &Info, &NetHash); - if(pBan) - { - char aBuf[128]; - MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_BANADD); - dbg_msg("net_ban", aBuf); - return 0; - } - else - dbg_msg("net_ban", "ban failed (full banlist)"); - return -1; -} - -template -int CNetBan::Unban(T *pBanPool, const typename T::CDataType *pData) -{ - CNetHash NetHash(pData); - CBan *pBan = pBanPool->Find(pData, &NetHash); - if(pBan) - { - char aBuf[256]; - MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_BANREM); - pBanPool->Remove(pBan); - dbg_msg("net_ban", aBuf); - return 0; - } - else - dbg_msg("net_ban", "unban failed (invalid entry)"); - return -1; -} - -void CNetBan::Init() -{ - m_BanAddrPool.Reset(); - m_BanRangePool.Reset(); - - net_host_lookup("localhost", &m_LocalhostIPV4, NETTYPE_IPV4); - net_host_lookup("localhost", &m_LocalhostIPV6, NETTYPE_IPV6); -} - -void CNetBan::Update() -{ - int Now = time_timestamp(); - - // remove expired bans - char aBuf[256], aNetStr[256]; - while(m_BanAddrPool.First() && m_BanAddrPool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanAddrPool.First()->m_Info.m_Expires < Now) - { - str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanAddrPool.First()->m_Data, aNetStr, sizeof(aNetStr))); - dbg_msg("net_ban", aBuf); - m_BanAddrPool.Remove(m_BanAddrPool.First()); - } - while(m_BanRangePool.First() && m_BanRangePool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanRangePool.First()->m_Info.m_Expires < Now) - { - str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanRangePool.First()->m_Data, aNetStr, sizeof(aNetStr))); - dbg_msg("net_ban", aBuf); - m_BanRangePool.Remove(m_BanRangePool.First()); - } -} - -int CNetBan::BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason) -{ - return Ban(&m_BanAddrPool, pAddr, Seconds, pReason); -} - -int CNetBan::BanRange(const CNetRange *pRange, int Seconds, const char *pReason) -{ - if(pRange->IsValid()) - return Ban(&m_BanRangePool, pRange, Seconds, pReason); - - dbg_msg("net_ban", "ban failed (invalid range)"); - return -1; -} - -int CNetBan::UnbanByAddr(const NETADDR *pAddr) -{ - return Unban(&m_BanAddrPool, pAddr); -} - -int CNetBan::UnbanByRange(const CNetRange *pRange) -{ - if(pRange->IsValid()) - return Unban(&m_BanRangePool, pRange); - - dbg_msg("net_ban", "ban failed (invalid range)"); - return -1; -} - -int CNetBan::UnbanByIndex(int Index) -{ - int Result; - char aBuf[256]; - CBanAddr *pBan = m_BanAddrPool.Get(Index); - if(pBan) - { - NetToString(&pBan->m_Data, aBuf, sizeof(aBuf)); - Result = m_BanAddrPool.Remove(pBan); - } - else - { - CBanRange *pBan = m_BanRangePool.Get(Index-m_BanAddrPool.Num()); - if(pBan) - { - NetToString(&pBan->m_Data, aBuf, sizeof(aBuf)); - Result = m_BanRangePool.Remove(pBan); - } - else - { - dbg_msg("net_ban", "unban failed (invalid index)"); - return -1; - } - } - - char aMsg[256]; - str_format(aMsg, sizeof(aMsg), "unbanned index %i (%s)", Index, aBuf); - dbg_msg("net_ban", aMsg); - return Result; -} - -void CNetBan::UnbanAll() -{ - m_BanAddrPool.Reset(); - m_BanRangePool.Reset(); -} - -bool CNetBan::IsBanned(const NETADDR *pAddr, char *pBuf, unsigned BufferSize) const -{ - CNetHash aHash[17]; - int Length = CNetHash::MakeHashArray(pAddr, aHash); - - // check ban adresses - CBanAddr *pBan = m_BanAddrPool.Find(pAddr, &aHash[Length]); - if(pBan) - { - MakeBanInfo(pBan, pBuf, BufferSize, MSGTYPE_PLAYER); - return true; - } - - // check ban ranges - for(int i = Length-1; i >= 0; --i) - { - for(CBanRange *pBan = m_BanRangePool.First(&aHash[i]); pBan; pBan = pBan->m_pHashNext) - { - if(NetMatch(&pBan->m_Data, pAddr, i, Length)) - { - MakeBanInfo(pBan, pBuf, BufferSize, MSGTYPE_PLAYER); - return true; - } - } - } - - return false; -} diff --git a/server/src/netban.h b/server/src/netban.h deleted file mode 100644 index 544a4b1..0000000 --- a/server/src/netban.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef NETBAN_H -#define NETBAN_H - -#include - -inline int NetComp(const NETADDR *pAddr1, const NETADDR *pAddr2) -{ - return mem_comp(pAddr1, pAddr2, pAddr1->type==NETTYPE_IPV4 ? 8 : 20); -} - -class CNetRange -{ -public: - NETADDR m_LB; - NETADDR m_UB; - - bool IsValid() const { return m_LB.type == m_UB.type && NetComp(&m_LB, &m_UB) < 0; } -}; - -inline int NetComp(const CNetRange *pRange1, const CNetRange *pRange2) -{ - return NetComp(&pRange1->m_LB, &pRange2->m_LB) || NetComp(&pRange1->m_UB, &pRange2->m_UB); -} - - -class CNetBan -{ -protected: - bool NetMatch(const NETADDR *pAddr1, const NETADDR *pAddr2) const - { - return NetComp(pAddr1, pAddr2) == 0; - } - - bool NetMatch(const CNetRange *pRange, const NETADDR *pAddr, int Start, int Length) const - { - return pRange->m_LB.type == pAddr->type && (Start == 0 || mem_comp(&pRange->m_LB.ip[0], &pAddr->ip[0], Start) == 0) && - mem_comp(&pRange->m_LB.ip[Start], &pAddr->ip[Start], Length-Start) <= 0 && mem_comp(&pRange->m_UB.ip[Start], &pAddr->ip[Start], Length-Start) >= 0; - } - - bool NetMatch(const CNetRange *pRange, const NETADDR *pAddr) const - { - return NetMatch(pRange, pAddr, 0, pRange->m_LB.type==NETTYPE_IPV4 ? 4 : 16); - } - - const char *NetToString(const NETADDR *pData, char *pBuffer, unsigned BufferSize) const - { - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(pData, aAddrStr, sizeof(aAddrStr), false); - str_format(pBuffer, BufferSize, "'%s'", aAddrStr); - return pBuffer; - } - - const char *NetToString(const CNetRange *pData, char *pBuffer, unsigned BufferSize) const - { - char aAddrStr1[NETADDR_MAXSTRSIZE], aAddrStr2[NETADDR_MAXSTRSIZE]; - net_addr_str(&pData->m_LB, aAddrStr1, sizeof(aAddrStr1), false); - net_addr_str(&pData->m_UB, aAddrStr2, sizeof(aAddrStr2), false); - str_format(pBuffer, BufferSize, "'%s' - '%s'", aAddrStr1, aAddrStr2); - return pBuffer; - } - - // todo: move? - static bool StrAllnum(const char *pStr); - - class CNetHash - { - public: - int m_Hash; - int m_HashIndex; // matching parts for ranges, 0 for addr - - CNetHash() {} - CNetHash(const NETADDR *pAddr); - CNetHash(const CNetRange *pRange); - - static int MakeHashArray(const NETADDR *pAddr, CNetHash aHash[17]); - }; - - struct CBanInfo - { - enum - { - EXPIRES_NEVER=-1, - REASON_LENGTH=64, - }; - int m_Expires; - char m_aReason[REASON_LENGTH]; - }; - - template struct CBan - { - T m_Data; - CBanInfo m_Info; - CNetHash m_NetHash; - - // hash list - CBan *m_pHashNext; - CBan *m_pHashPrev; - - // used or free list - CBan *m_pNext; - CBan *m_pPrev; - }; - - template class CBanPool - { - public: - typedef T CDataType; - - CBan *Add(const CDataType *pData, const CBanInfo *pInfo, const CNetHash *pNetHash); - int Remove(CBan *pBan); - void Update(CBan *pBan, const CBanInfo *pInfo); - void Reset(); - - int Num() const { return m_CountUsed; } - bool IsFull() const { return m_CountUsed == MAX_BANS; } - - CBan *First() const { return m_pFirstUsed; } - CBan *First(const CNetHash *pNetHash) const { return m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]; } - CBan *Find(const CDataType *pData, const CNetHash *pNetHash) const - { - for(CBan *pBan = m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]; pBan; pBan = pBan->m_pHashNext) - { - if(NetComp(&pBan->m_Data, pData) == 0) - return pBan; - } - - return 0; - } - CBan *Get(int Index) const; - - private: - enum - { - MAX_BANS=1024, - }; - - CBan *m_paaHashList[HashCount][256]; - CBan m_aBans[MAX_BANS]; - CBan *m_pFirstFree; - CBan *m_pFirstUsed; - int m_CountUsed; - }; - - typedef CBanPool CBanAddrPool; - typedef CBanPool CBanRangePool; - typedef CBan CBanAddr; - typedef CBan CBanRange; - - template void MakeBanInfo(const CBan *pBan, char *pBuf, unsigned BuffSize, int Type) const; - template int Ban(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason); - template int Unban(T *pBanPool, const typename T::CDataType *pData); - - CBanAddrPool m_BanAddrPool; - CBanRangePool m_BanRangePool; - NETADDR m_LocalhostIPV4, m_LocalhostIPV6; - -public: - enum - { - MSGTYPE_PLAYER=0, - MSGTYPE_LIST, - MSGTYPE_BANADD, - MSGTYPE_BANREM, - }; - - virtual ~CNetBan() {} - void Init(); - void Update(); - - virtual int BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason); - virtual int BanRange(const CNetRange *pRange, int Seconds, const char *pReason); - int UnbanByAddr(const NETADDR *pAddr); - int UnbanByRange(const CNetRange *pRange); - int UnbanByIndex(int Index); - void UnbanAll(); - bool IsBanned(const NETADDR *pAddr, char *pBuf, unsigned BufferSize) const; -}; - -#endif diff --git a/server/src/network.cpp b/server/src/network.cpp deleted file mode 100644 index a1cb1ae..0000000 --- a/server/src/network.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include -#include "netban.h" -#include "network.h" - -bool CNetwork::Open(NETADDR BindAddr, CNetBan *pNetBan) -{ - // zero out the whole structure - mem_zero(this, sizeof(*this)); - m_Socket.type = NETTYPE_INVALID; - m_Socket.ipv4sock = -1; - m_Socket.ipv6sock = -1; - m_pNetBan = pNetBan; - - // open socket - m_Socket = net_tcp_create(BindAddr); - if(!m_Socket.type) - return false; - if(net_tcp_listen(m_Socket, NET_MAX_CLIENTS)) - return false; - net_set_non_blocking(m_Socket); - - for(int i = 0; i < NET_MAX_CLIENTS; i++) - m_aSlots[i].m_Connection.Reset(); - - return true; -} - -void CNetwork::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser) -{ - m_pfnNewClient = pfnNewClient; - m_pfnDelClient = pfnDelClient; - m_UserPtr = pUser; -} - -int CNetwork::Close() -{ - for(int i = 0; i < NET_MAX_CLIENTS; i++) - m_aSlots[i].m_Connection.Disconnect("Closing connection."); - - net_tcp_close(m_Socket); - - return 0; -} - -int CNetwork::Drop(int ClientID, const char *pReason) -{ - if(m_pfnDelClient) - m_pfnDelClient(ClientID, pReason, m_UserPtr); - - m_aSlots[ClientID].m_Connection.Disconnect(pReason); - - return 0; -} - -int CNetwork::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr) -{ - char aError[256] = { 0 }; - int FreeSlot = -1; - - // look for free slot or multiple client - for(int i = 0; i < NET_MAX_CLIENTS; i++) - { - if(FreeSlot == -1 && m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE) - FreeSlot = i; - if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE) - { - if(net_addr_comp(pAddr, m_aSlots[i].m_Connection.PeerAddress()) == 0) - { - str_copy(aError, "Only one client per IP allowed.", sizeof(aError)); - break; - } - } - } - - // accept client - if(!aError[0] && FreeSlot != -1) - { - m_aSlots[FreeSlot].m_Connection.Init(Socket, pAddr); - if(m_pfnNewClient) - m_pfnNewClient(FreeSlot, m_UserPtr); - return 0; - } - - // reject client - if(!aError[0]) - str_copy(aError, "No free slot available.", sizeof(aError)); - - net_tcp_send(Socket, aError, str_length(aError)); - net_tcp_close(Socket); - - return -1; -} - -int CNetwork::Update() -{ - NETSOCKET Socket; - NETADDR Addr; - - if(net_tcp_accept(m_Socket, &Socket, &Addr) > 0) - { - // check if we should just drop the packet - char aBuf[128]; - if(NetBan() && NetBan()->IsBanned(&Addr, aBuf, sizeof(aBuf))) - { - // banned, reply with a message and drop - net_tcp_send(Socket, aBuf, str_length(aBuf)); - net_tcp_close(Socket); - } - else - AcceptClient(Socket, &Addr); - } - - for(int i = 0; i < NET_MAX_CLIENTS; i++) - { - if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE) - m_aSlots[i].m_Connection.Update(); - if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR) - Drop(i, m_aSlots[i].m_Connection.ErrorString()); - } - - return 0; -} - -int CNetwork::Recv(char *pLine, int MaxLength, int *pClientID) -{ - for(int i = 0; i < NET_MAX_CLIENTS; i++) - { - if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE && m_aSlots[i].m_Connection.Recv(pLine, MaxLength)) - { - if(pClientID) - *pClientID = i; - return 1; - } - } - return 0; -} - -int CNetwork::Send(int ClientID, const char *pLine) -{ - if(m_aSlots[ClientID].m_Connection.State() == NET_CONNSTATE_ONLINE) - return m_aSlots[ClientID].m_Connection.Send(pLine); - else - return -1; -} diff --git a/server/src/network.h b/server/src/network.h deleted file mode 100644 index 49187f8..0000000 --- a/server/src/network.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef NETWORK_H -#define NETWORK_H - -enum -{ - NET_CONNSTATE_OFFLINE=0, - NET_CONNSTATE_CONNECT=1, - NET_CONNSTATE_PENDING=2, - NET_CONNSTATE_ONLINE=3, - NET_CONNSTATE_ERROR=4, - - NET_MAX_PACKETSIZE = 1400, - NET_MAX_CLIENTS = 512 -}; - -typedef int (*NETFUNC_DELCLIENT)(int ClientID, const char* pReason, void *pUser); -typedef int (*NETFUNC_NEWCLIENT)(int ClientID, void *pUser); - -class CNetworkClient -{ -private: - int m_State; - - NETADDR m_PeerAddr; - NETSOCKET m_Socket; - - char m_aBuffer[NET_MAX_PACKETSIZE]; - int m_BufferOffset; - - char m_aErrorString[256]; - - bool m_LineEndingDetected; - char m_aLineEnding[3]; - -public: - void Init(NETSOCKET Socket, const NETADDR *pAddr); - void Disconnect(const char *pReason); - - int State() const { return m_State; } - const NETADDR *PeerAddress() const { return &m_PeerAddr; } - const char *ErrorString() const { return m_aErrorString; } - - void Reset(); - int Update(); - int Send(const char *pLine); - int Recv(char *pLine, int MaxLength); -}; - -class CNetwork -{ -private: - struct CSlot - { - CNetworkClient m_Connection; - }; - - NETSOCKET m_Socket; - class CNetBan *m_pNetBan; - CSlot m_aSlots[NET_MAX_CLIENTS]; - - NETFUNC_NEWCLIENT m_pfnNewClient; - NETFUNC_DELCLIENT m_pfnDelClient; - void *m_UserPtr; - -public: - void SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser); - - // - bool Open(NETADDR BindAddr, CNetBan *pNetBan); - int Close(); - - // - int Recv(char *pLine, int MaxLength, int *pClientID = 0); - int Send(int ClientID, const char *pLine); - int Update(); - - // - int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr); - int Drop(int ClientID, const char *pReason); - - // status requests - const NETADDR *ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } - const NETSOCKET *Socket() const { return &m_Socket; } - class CNetBan *NetBan() const { return m_pNetBan; } -}; - -#endif diff --git a/server/src/network_client.cpp b/server/src/network_client.cpp deleted file mode 100644 index 0a4bce5..0000000 --- a/server/src/network_client.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include -#include "network.h" - -void CNetworkClient::Reset() -{ - m_State = NET_CONNSTATE_OFFLINE; - mem_zero(&m_PeerAddr, sizeof(m_PeerAddr)); - m_aErrorString[0] = 0; - - m_Socket.type = NETTYPE_INVALID; - m_Socket.ipv4sock = -1; - m_Socket.ipv6sock = -1; - m_aBuffer[0] = 0; - m_BufferOffset = 0; - - m_LineEndingDetected = false; - #if defined(CONF_FAMILY_WINDOWS) - m_aLineEnding[0] = '\r'; - m_aLineEnding[1] = '\n'; - m_aLineEnding[2] = 0; - #else - m_aLineEnding[0] = '\n'; - m_aLineEnding[1] = 0; - m_aLineEnding[2] = 0; - #endif -} - -void CNetworkClient::Init(NETSOCKET Socket, const NETADDR *pAddr) -{ - Reset(); - - m_Socket = Socket; - net_set_non_blocking(m_Socket); - - m_PeerAddr = *pAddr; - m_State = NET_CONNSTATE_ONLINE; -} - -void CNetworkClient::Disconnect(const char *pReason) -{ - if(State() == NET_CONNSTATE_OFFLINE) - return; - - if(pReason && pReason[0]) - Send(pReason); - - net_tcp_close(m_Socket); - - Reset(); -} - -int CNetworkClient::Update() -{ - if(State() == NET_CONNSTATE_ONLINE) - { - if((int)(sizeof(m_aBuffer)) <= m_BufferOffset) - { - m_State = NET_CONNSTATE_ERROR; - str_copy(m_aErrorString, "too weak connection (out of buffer)", sizeof(m_aErrorString)); - return -1; - } - - int Bytes = net_tcp_recv(m_Socket, m_aBuffer+m_BufferOffset, (int)(sizeof(m_aBuffer))-m_BufferOffset); - - if(Bytes > 0) - { - m_BufferOffset += Bytes; - } - else if(Bytes < 0) - { - if(net_would_block()) // no data received - return 0; - - m_State = NET_CONNSTATE_ERROR; // error - str_copy(m_aErrorString, "connection failure", sizeof(m_aErrorString)); - return -1; - } - else - { - m_State = NET_CONNSTATE_ERROR; - str_copy(m_aErrorString, "remote end closed the connection", sizeof(m_aErrorString)); - return -1; - } - } - - return 0; -} - -int CNetworkClient::Recv(char *pLine, int MaxLength) -{ - if(State() == NET_CONNSTATE_ONLINE) - { - if(m_BufferOffset) - { - // find message start - int StartOffset = 0; - while(m_aBuffer[StartOffset] == '\r' || m_aBuffer[StartOffset] == '\n') - { - // detect clients line ending format - if(!m_LineEndingDetected) - { - m_aLineEnding[0] = m_aBuffer[StartOffset]; - if(StartOffset+1 < m_BufferOffset && (m_aBuffer[StartOffset+1] == '\r' || m_aBuffer[StartOffset+1] == '\n') && - m_aBuffer[StartOffset] != m_aBuffer[StartOffset+1]) - m_aLineEnding[1] = m_aBuffer[StartOffset+1]; - m_LineEndingDetected = true; - } - - if(++StartOffset >= m_BufferOffset) - { - m_BufferOffset = 0; - return 0; - } - } - - // find message end - int EndOffset = StartOffset; - while(m_aBuffer[EndOffset] != '\r' && m_aBuffer[EndOffset] != '\n') - { - if(++EndOffset >= m_BufferOffset) - { - if(StartOffset > 0) - { - mem_move(m_aBuffer, m_aBuffer+StartOffset, m_BufferOffset-StartOffset); - m_BufferOffset -= StartOffset; - } - return 0; - } - } - - // extract message and update buffer - if(MaxLength-1 < EndOffset-StartOffset) - { - if(StartOffset > 0) - { - mem_move(m_aBuffer, m_aBuffer+StartOffset, m_BufferOffset-StartOffset); - m_BufferOffset -= StartOffset; - } - return 0; - } - mem_copy(pLine, m_aBuffer+StartOffset, EndOffset-StartOffset); - pLine[EndOffset-StartOffset] = 0; - str_sanitize_cc(pLine); - mem_move(m_aBuffer, m_aBuffer+EndOffset, m_BufferOffset-EndOffset); - m_BufferOffset -= EndOffset; - return 1; - } - } - return 0; -} - -int CNetworkClient::Send(const char *pLine) -{ - if(State() != NET_CONNSTATE_ONLINE) - return -1; - - char aBuf[1024]; - str_copy(aBuf, pLine, (int)(sizeof(aBuf))-2); - int Length = str_length(aBuf); - aBuf[Length] = m_aLineEnding[0]; - aBuf[Length+1] = m_aLineEnding[1]; - aBuf[Length+2] = m_aLineEnding[2]; - Length += 3; - const char *pData = aBuf; - - while(1) - { - int Send = net_tcp_send(m_Socket, pData, Length); - if(Send < 0) - { - m_State = NET_CONNSTATE_ERROR; - str_copy(m_aErrorString, "failed to send packet", sizeof(m_aErrorString)); - return -1; - } - - if(Send >= Length) - break; - - pData += Send; - Length -= Send; - } - - return 0; -} diff --git a/server/src/server.cpp b/server/src/server.cpp deleted file mode 100644 index 6996ac3..0000000 --- a/server/src/server.cpp +++ /dev/null @@ -1,204 +0,0 @@ -#include -#include "netban.h" -#include "network.h" -#include "main.h" -#include "server.h" - -int CServer::NewClientCallback(int ClientID, void *pUser) -{ - CServer *pThis = (CServer *)pUser; - - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(pThis->m_Network.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true); - if(pThis->Main()->Config()->m_Verbose) - dbg_msg("server", "Connection accepted. ncid=%d addr=%s'", ClientID, aAddrStr); - - pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED; - pThis->m_aClients[ClientID].m_TimeConnected = time_get(); - pThis->m_Network.Send(ClientID, "Authentication required:"); - - return 0; -} - -int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) -{ - CServer *pThis = (CServer *)pUser; - - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(pThis->m_Network.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true); - if(pThis->Main()->Config()->m_Verbose) - dbg_msg("server", "Client dropped. ncid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason); - - if(pThis->m_aClients[ClientID].m_State == CClient::STATE_AUTHED) - pThis->Main()->OnDelClient(ClientID); - pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY; - - return 0; -} - -int CServer::Init(CMain *pMain, const char *Bind, int Port) -{ - m_pMain = pMain; - m_NetBan.Init(); - - for(int i = 0; i < NET_MAX_CLIENTS; i++) - m_aClients[i].m_State = CClient::STATE_EMPTY; - - m_Ready = false; - - if(Port == 0) - { - dbg_msg("server", "Will not bind to port 0."); - return 1; - } - - NETADDR BindAddr; - if(Bind[0] && net_host_lookup(Bind, &BindAddr, NETTYPE_ALL) == 0) - { - // got bindaddr - BindAddr.type = NETTYPE_ALL; - BindAddr.port = Port; - } - else - { - mem_zero(&BindAddr, sizeof(BindAddr)); - BindAddr.type = NETTYPE_ALL; - BindAddr.port = Port; - } - - if(m_Network.Open(BindAddr, &m_NetBan)) - { - m_Network.SetCallbacks(NewClientCallback, DelClientCallback, this); - m_Ready = true; - dbg_msg("server", "Bound to %s:%d", Bind, Port); - return 0; - } - else - dbg_msg("server", "Couldn't open socket. Port (%d) might already be in use.", Port); - - return 1; -} - -void CServer::Update() -{ - if(!m_Ready) - return; - - m_NetBan.Update(); - m_Network.Update(); - - char aBuf[NET_MAX_PACKETSIZE]; - int ClientID; - - while(m_Network.Recv(aBuf, (int)(sizeof(aBuf))-1, &ClientID)) - { - dbg_assert(m_aClients[ClientID].m_State != CClient::STATE_EMPTY, "Got message from empty slot."); - if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTED) - { - int ID = -1; - char aUsername[128] = {0}; - char aPassword[128] = {0}; - const char *pTmp; - - if(!(pTmp = str_find(aBuf, ":")) - || (unsigned)(pTmp - aBuf) > sizeof(aUsername) || (unsigned)(str_length(pTmp) - 1) > sizeof(aPassword)) - { - m_Network.NetBan()->BanAddr(m_Network.ClientAddr(ClientID), 60, "You're an idiot, go away."); - m_Network.Drop(ClientID, "Fuck off."); - return; - } - - str_copy(aUsername, aBuf, pTmp - aBuf + 1); - str_copy(aPassword, pTmp + 1, sizeof(aPassword)); - if(!*aUsername || !*aPassword) - { - m_Network.NetBan()->BanAddr(m_Network.ClientAddr(ClientID), 60, "You're an idiot, go away."); - m_Network.Drop(ClientID, "Username and password must not be blank."); - return; - } - - for(int i = 0; i < NET_MAX_CLIENTS; i++) - { - if(!Main()->Client(i)->m_Active) - continue; - - if(str_comp(Main()->Client(i)->m_aUsername, aUsername) == 0 && str_comp(Main()->Client(i)->m_aPassword, aPassword) == 0) - ID = i; - } - - if(ID == -1) - { - m_Network.NetBan()->BanAddr(m_Network.ClientAddr(ClientID), 60, "Wrong username and/or password."); - m_Network.Drop(ClientID, "Wrong username and/or password."); - } - else if(Main()->Client(ID)->m_ClientNetID != -1) - { - m_Network.Drop(ClientID, "Only one connection per user allowed."); - } - else - { - m_aClients[ClientID].m_State = CClient::STATE_AUTHED; - m_aClients[ClientID].m_LastReceived = time_get(); - m_Network.Send(ClientID, "Authentication successful. Access granted."); - - if(m_Network.ClientAddr(ClientID)->type == NETTYPE_IPV4) - m_Network.Send(ClientID, "You are connecting via: IPv4"); - else if(m_Network.ClientAddr(ClientID)->type == NETTYPE_IPV6) - m_Network.Send(ClientID, "You are connecting via: IPv6"); - - if(Main()->Config()->m_Verbose) - dbg_msg("server", "ncid=%d authed", ClientID); - Main()->OnNewClient(ClientID, ID); - } - } - else if(m_aClients[ClientID].m_State == CClient::STATE_AUTHED) - { - m_aClients[ClientID].m_LastReceived = time_get(); - if(Main()->Config()->m_Verbose) - dbg_msg("server", "ncid=%d cmd='%s'", ClientID, aBuf); - - if(str_comp(aBuf, "logout") == 0) - m_Network.Drop(ClientID, "Logout. Bye Bye ~"); - else - Main()->HandleMessage(ClientID, aBuf); - } - } - - for(int i = 0; i < NET_MAX_CLIENTS; ++i) - { - if(m_aClients[i].m_State == CClient::STATE_CONNECTED && - time_get() > m_aClients[i].m_TimeConnected + 5 * time_freq()) - { - m_Network.NetBan()->BanAddr(m_Network.ClientAddr(i), 30, "Authentication timeout."); - m_Network.Drop(i, "Authentication timeout."); - } - else if(m_aClients[i].m_State == CClient::STATE_AUTHED && - time_get() > m_aClients[i].m_LastReceived + 15 * time_freq()) - m_Network.Drop(i, "Timeout."); - } -} - -void CServer::Send(int ClientID, const char *pLine) -{ - if(!m_Ready) - return; - - if(ClientID == -1) - { - for(int i = 0; i < NET_MAX_CLIENTS; i++) - { - if(m_aClients[i].m_State == CClient::STATE_AUTHED) - m_Network.Send(i, pLine); - } - } - else if(ClientID >= 0 && ClientID < NET_MAX_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_AUTHED) - m_Network.Send(ClientID, pLine); -} - -void CServer::Shutdown() -{ - if(!m_Ready) - return; - - m_Network.Close(); -} diff --git a/server/src/server.h b/server/src/server.h deleted file mode 100644 index f5bf162..0000000 --- a/server/src/server.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef SERVER_H -#define SERVER_H - -#include "netban.h" -#include "network.h" - -class CServer -{ - class CClient - { - public: - enum - { - STATE_EMPTY=0, - STATE_CONNECTED, - STATE_AUTHED, - }; - - int m_State; - int64 m_TimeConnected; - int64 m_LastReceived; - }; - CClient m_aClients[NET_MAX_CLIENTS]; - - CNetwork m_Network; - CNetBan m_NetBan; - - class CMain *m_pMain; - - bool m_Ready; - - static int NewClientCallback(int ClientID, void *pUser); - static int DelClientCallback(int ClientID, const char *pReason, void *pUser); - -public: - int Init(CMain *pMain, const char *Bind, int Port); - void Update(); - void Send(int ClientID, const char *pLine); - void Shutdown(); - - CNetwork *Network() { return &m_Network; } - CNetBan *NetBan() { return &m_NetBan; } - CMain *Main() { return m_pMain; } -}; - -#endif diff --git a/server/src/system.c b/server/src/system.c deleted file mode 100644 index aac93f9..0000000 --- a/server/src/system.c +++ /dev/null @@ -1,2001 +0,0 @@ -/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ -/* If you are missing that file, acquire a complete release at teeworlds.com. */ -#include -#include -#include -#include -#include -#include - -#include "system.h" - -#if defined(CONF_FAMILY_UNIX) - #include - #include - - /* unix net includes */ - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - - #include - - #if defined(CONF_PLATFORM_MACOSX) - #include - #endif - -#elif defined(CONF_FAMILY_WINDOWS) - #define WIN32_LEAN_AND_MEAN - #define _WIN32_WINNT 0x0501 /* required for mingw to get getaddrinfo to work */ - #include - #include - #include - #include - #include - #include -#else - #error NOT IMPLEMENTED -#endif - -#if defined(CONF_PLATFORM_SOLARIS) - #include -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -IOHANDLE io_stdin() { return (IOHANDLE)stdin; } -IOHANDLE io_stdout() { return (IOHANDLE)stdout; } -IOHANDLE io_stderr() { return (IOHANDLE)stderr; } - -static DBG_LOGGER loggers[16]; -static int num_loggers = 0; - -static NETSTATS network_stats = {0}; -static MEMSTATS memory_stats = {0}; - -static NETSOCKET invalid_socket = {NETTYPE_INVALID, -1, -1}; - -void dbg_logger(DBG_LOGGER logger) -{ - loggers[num_loggers++] = logger; -} - -void dbg_assert_imp(const char *filename, int line, int test, const char *msg) -{ - if(!test) - { - dbg_msg("assert", "%s(%d): %s", filename, line, msg); - dbg_break(); - } -} - -void dbg_break() -{ - *((volatile unsigned*)0) = 0x0; -} - -void dbg_msg(const char *sys, const char *fmt, ...) -{ - va_list args; - char str[1024*8]; - char *msg; - int i, len; - - str_format(str, sizeof(str), "[%s]: ", sys); - len = strlen(str); - msg = (char *)str + len; - - va_start(args, fmt); -#if defined(CONF_FAMILY_WINDOWS) - _vsnprintf(msg, sizeof(str)-len, fmt, args); -#else - vsnprintf(msg, sizeof(str)-len, fmt, args); -#endif - va_end(args); - - for(i = 0; i < num_loggers; i++) - loggers[i](str); -} - -static void logger_stdout(const char *line) -{ - printf("%s\n", line); - fflush(stdout); -} - -static void logger_debugger(const char *line) -{ -#if defined(CONF_FAMILY_WINDOWS) - OutputDebugString(line); - OutputDebugString("\n"); -#endif -} - - -static IOHANDLE logfile = 0; -static void logger_file(const char *line) -{ - io_write(logfile, line, strlen(line)); - io_write_newline(logfile); - io_flush(logfile); -} - -void dbg_logger_stdout() { dbg_logger(logger_stdout); } -void dbg_logger_debugger() { dbg_logger(logger_debugger); } -void dbg_logger_file(const char *filename) -{ - logfile = io_open(filename, IOFLAG_WRITE); - if(logfile) - dbg_logger(logger_file); - else - dbg_msg("dbg/logger", "failed to open '%s' for logging", filename); - -} -/* */ - -typedef struct MEMHEADER -{ - const char *filename; - int line; - int size; - struct MEMHEADER *prev; - struct MEMHEADER *next; -} MEMHEADER; - -typedef struct MEMTAIL -{ - int guard; -} MEMTAIL; - -static struct MEMHEADER *first = 0; -static const int MEM_GUARD_VAL = 0xbaadc0de; - -void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned alignment) -{ - /* TODO: fix alignment */ - /* TODO: add debugging */ - MEMTAIL *tail; - MEMHEADER *header = (struct MEMHEADER *)malloc(size+sizeof(MEMHEADER)+sizeof(MEMTAIL)); - dbg_assert(header != 0, "mem_alloc failure"); - if(!header) - return NULL; - tail = (struct MEMTAIL *)(((char*)(header+1))+size); - header->size = size; - header->filename = filename; - header->line = line; - - memory_stats.allocated += header->size; - memory_stats.total_allocations++; - memory_stats.active_allocations++; - - tail->guard = MEM_GUARD_VAL; - - header->prev = (MEMHEADER *)0; - header->next = first; - if(first) - first->prev = header; - first = header; - - /*dbg_msg("mem", "++ %p", header+1); */ - return header+1; -} - -void mem_free(void *p) -{ - if(p) - { - MEMHEADER *header = (MEMHEADER *)p - 1; - MEMTAIL *tail = (MEMTAIL *)(((char*)(header+1))+header->size); - - if(tail->guard != MEM_GUARD_VAL) - dbg_msg("mem", "!! %p", p); - /* dbg_msg("mem", "-- %p", p); */ - memory_stats.allocated -= header->size; - memory_stats.active_allocations--; - - if(header->prev) - header->prev->next = header->next; - else - first = header->next; - if(header->next) - header->next->prev = header->prev; - - free(header); - } -} - -void mem_debug_dump(IOHANDLE file) -{ - char buf[1024]; - MEMHEADER *header = first; - if(!file) - file = io_open("memory.txt", IOFLAG_WRITE); - - if(file) - { - while(header) - { - str_format(buf, sizeof(buf), "%s(%d): %d", header->filename, header->line, header->size); - io_write(file, buf, strlen(buf)); - io_write_newline(file); - header = header->next; - } - - io_close(file); - } -} - - -void mem_copy(void *dest, const void *source, unsigned size) -{ - memcpy(dest, source, size); -} - -void mem_move(void *dest, const void *source, unsigned size) -{ - memmove(dest, source, size); -} - -void mem_zero(void *block, unsigned size) -{ - memset(block, 0, size); -} - -int mem_check_imp() -{ - MEMHEADER *header = first; - while(header) - { - MEMTAIL *tail = (MEMTAIL *)(((char*)(header+1))+header->size); - if(tail->guard != MEM_GUARD_VAL) - { - dbg_msg("mem", "Memory check failed at %s(%d): %d", header->filename, header->line, header->size); - return 0; - } - header = header->next; - } - - return 1; -} - -IOHANDLE io_open(const char *filename, int flags) -{ - if(flags == IOFLAG_READ) - { - #if defined(CONF_FAMILY_WINDOWS) - // check for filename case sensitive - WIN32_FIND_DATA finddata; - HANDLE handle; - int length; - - length = str_length(filename); - if(!filename || !length || filename[length-1] == '\\') - return 0x0; - handle = FindFirstFile(filename, &finddata); - if(handle == INVALID_HANDLE_VALUE) - return 0x0; - else if(str_comp(filename+length-str_length(finddata.cFileName), finddata.cFileName) != 0) - { - FindClose(handle); - return 0x0; - } - FindClose(handle); - #endif - return (IOHANDLE)fopen(filename, "rb"); - } - if(flags == IOFLAG_WRITE) - return (IOHANDLE)fopen(filename, "wb"); - return 0x0; -} - -unsigned io_read(IOHANDLE io, void *buffer, unsigned size) -{ - return fread(buffer, 1, size, (FILE*)io); -} - -unsigned io_skip(IOHANDLE io, int size) -{ - fseek((FILE*)io, size, SEEK_CUR); - return size; -} - -int io_seek(IOHANDLE io, int offset, int origin) -{ - int real_origin; - - switch(origin) - { - case IOSEEK_START: - real_origin = SEEK_SET; - break; - case IOSEEK_CUR: - real_origin = SEEK_CUR; - break; - case IOSEEK_END: - real_origin = SEEK_END; - break; - default: - return -1; - } - - return fseek((FILE*)io, offset, real_origin); -} - -long int io_tell(IOHANDLE io) -{ - return ftell((FILE*)io); -} - -long int io_length(IOHANDLE io) -{ - long int length; - io_seek(io, 0, IOSEEK_END); - length = io_tell(io); - io_seek(io, 0, IOSEEK_START); - return length; -} - -unsigned io_write(IOHANDLE io, const void *buffer, unsigned size) -{ - return fwrite(buffer, 1, size, (FILE*)io); -} - -unsigned io_write_newline(IOHANDLE io) -{ -#if defined(CONF_FAMILY_WINDOWS) - return fwrite("\r\n", 1, 2, (FILE*)io); -#else - return fwrite("\n", 1, 1, (FILE*)io); -#endif -} - -int io_close(IOHANDLE io) -{ - fclose((FILE*)io); - return 1; -} - -int io_flush(IOHANDLE io) -{ - fflush((FILE*)io); - return 0; -} - -void *thread_create(void (*threadfunc)(void *), void *u) -{ -#if defined(CONF_FAMILY_UNIX) - pthread_t id; - pthread_create(&id, NULL, (void *(*)(void*))threadfunc, u); - return (void*)id; -#elif defined(CONF_FAMILY_WINDOWS) - return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadfunc, u, 0, NULL); -#else - #error not implemented -#endif -} - -void thread_wait(void *thread) -{ -#if defined(CONF_FAMILY_UNIX) - pthread_join((pthread_t)thread, NULL); -#elif defined(CONF_FAMILY_WINDOWS) - WaitForSingleObject((HANDLE)thread, INFINITE); -#else - #error not implemented -#endif -} - -void thread_destroy(void *thread) -{ -#if defined(CONF_FAMILY_UNIX) - void *r = 0; - pthread_join((pthread_t)thread, &r); -#else - /*#error not implemented*/ -#endif -} - -void thread_yield() -{ -#if defined(CONF_FAMILY_UNIX) - sched_yield(); -#elif defined(CONF_FAMILY_WINDOWS) - Sleep(0); -#else - #error not implemented -#endif -} - -void thread_sleep(int milliseconds) -{ -#if defined(CONF_FAMILY_UNIX) - usleep(milliseconds*1000); -#elif defined(CONF_FAMILY_WINDOWS) - Sleep(milliseconds); -#else - #error not implemented -#endif -} - -void thread_detach(void *thread) -{ -#if defined(CONF_FAMILY_UNIX) - pthread_detach((pthread_t)(thread)); -#elif defined(CONF_FAMILY_WINDOWS) - CloseHandle(thread); -#else - #error not implemented -#endif -} - - - - -#if defined(CONF_FAMILY_UNIX) -typedef pthread_mutex_t LOCKINTERNAL; -#elif defined(CONF_FAMILY_WINDOWS) -typedef CRITICAL_SECTION LOCKINTERNAL; -#else - #error not implemented on this platform -#endif - -LOCK lock_create() -{ - LOCKINTERNAL *lock = (LOCKINTERNAL*)mem_alloc(sizeof(LOCKINTERNAL), 4); - -#if defined(CONF_FAMILY_UNIX) - pthread_mutex_init(lock, 0x0); -#elif defined(CONF_FAMILY_WINDOWS) - InitializeCriticalSection((LPCRITICAL_SECTION)lock); -#else - #error not implemented on this platform -#endif - return (LOCK)lock; -} - -void lock_destroy(LOCK lock) -{ -#if defined(CONF_FAMILY_UNIX) - pthread_mutex_destroy((LOCKINTERNAL *)lock); -#elif defined(CONF_FAMILY_WINDOWS) - DeleteCriticalSection((LPCRITICAL_SECTION)lock); -#else - #error not implemented on this platform -#endif - mem_free(lock); -} - -int lock_try(LOCK lock) -{ -#if defined(CONF_FAMILY_UNIX) - return pthread_mutex_trylock((LOCKINTERNAL *)lock); -#elif defined(CONF_FAMILY_WINDOWS) - return !TryEnterCriticalSection((LPCRITICAL_SECTION)lock); -#else - #error not implemented on this platform -#endif -} - -void lock_wait(LOCK lock) -{ -#if defined(CONF_FAMILY_UNIX) - pthread_mutex_lock((LOCKINTERNAL *)lock); -#elif defined(CONF_FAMILY_WINDOWS) - EnterCriticalSection((LPCRITICAL_SECTION)lock); -#else - #error not implemented on this platform -#endif -} - -void lock_release(LOCK lock) -{ -#if defined(CONF_FAMILY_UNIX) - pthread_mutex_unlock((LOCKINTERNAL *)lock); -#elif defined(CONF_FAMILY_WINDOWS) - LeaveCriticalSection((LPCRITICAL_SECTION)lock); -#else - #error not implemented on this platform -#endif -} - -#if !defined(CONF_PLATFORM_MACOSX) - #if defined(CONF_FAMILY_UNIX) - void semaphore_init(SEMAPHORE *sem) { sem_init(sem, 0, 0); } - void semaphore_wait(SEMAPHORE *sem) { sem_wait(sem); } - void semaphore_signal(SEMAPHORE *sem) { sem_post(sem); } - void semaphore_destroy(SEMAPHORE *sem) { sem_destroy(sem); } - #elif defined(CONF_FAMILY_WINDOWS) - void semaphore_init(SEMAPHORE *sem) { *sem = CreateSemaphore(0, 0, 10000, 0); } - void semaphore_wait(SEMAPHORE *sem) { WaitForSingleObject((HANDLE)*sem, INFINITE); } - void semaphore_signal(SEMAPHORE *sem) { ReleaseSemaphore((HANDLE)*sem, 1, NULL); } - void semaphore_destroy(SEMAPHORE *sem) { CloseHandle((HANDLE)*sem); } - #else - #error not implemented on this platform - #endif -#endif - - -/* ----- time ----- */ -int64 time_get() -{ -#if defined(CONF_FAMILY_UNIX) - struct timeval val; - gettimeofday(&val, NULL); - return (int64)val.tv_sec*(int64)1000000+(int64)val.tv_usec; -#elif defined(CONF_FAMILY_WINDOWS) - static int64 last = 0; - int64 t; - QueryPerformanceCounter((PLARGE_INTEGER)&t); - if(ttype != NETTYPE_IPV4) - { - dbg_msg("system", "couldn't convert NETADDR of type %d to ipv4", src->type); - return; - } - - dest->sin_family = AF_INET; - dest->sin_port = htons(src->port); - mem_copy(&dest->sin_addr.s_addr, src->ip, 4); -} - -static void netaddr_to_sockaddr_in6(const NETADDR *src, struct sockaddr_in6 *dest) -{ - mem_zero(dest, sizeof(struct sockaddr_in6)); - if(src->type != NETTYPE_IPV6) - { - dbg_msg("system", "couldn't not convert NETADDR of type %d to ipv6", src->type); - return; - } - - dest->sin6_family = AF_INET6; - dest->sin6_port = htons(src->port); - mem_copy(&dest->sin6_addr.s6_addr, src->ip, 16); -} - -static void sockaddr_to_netaddr(const struct sockaddr *src, NETADDR *dst) -{ - if(src->sa_family == AF_INET) - { - mem_zero(dst, sizeof(NETADDR)); - dst->type = NETTYPE_IPV4; - dst->port = htons(((struct sockaddr_in*)src)->sin_port); - mem_copy(dst->ip, &((struct sockaddr_in*)src)->sin_addr.s_addr, 4); - } - else if(src->sa_family == AF_INET6) - { - mem_zero(dst, sizeof(NETADDR)); - dst->type = NETTYPE_IPV6; - dst->port = htons(((struct sockaddr_in6*)src)->sin6_port); - mem_copy(dst->ip, &((struct sockaddr_in6*)src)->sin6_addr.s6_addr, 16); - } - else - { - mem_zero(dst, sizeof(struct sockaddr)); - dbg_msg("system", "couldn't convert sockaddr of family %d", src->sa_family); - } -} - -int net_addr_comp(const NETADDR *a, const NETADDR *b) -{ - return mem_comp(a, b, sizeof(NETADDR)); -} - -void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_port) -{ - if(addr->type == NETTYPE_IPV4) - { - if(add_port != 0) - str_format(string, max_length, "%d.%d.%d.%d:%d", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3], addr->port); - else - str_format(string, max_length, "%d.%d.%d.%d", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3]); - } - else if(addr->type == NETTYPE_IPV6) - { - if(add_port != 0) - str_format(string, max_length, "[%x:%x:%x:%x:%x:%x:%x:%x]:%d", - (addr->ip[0]<<8)|addr->ip[1], (addr->ip[2]<<8)|addr->ip[3], (addr->ip[4]<<8)|addr->ip[5], (addr->ip[6]<<8)|addr->ip[7], - (addr->ip[8]<<8)|addr->ip[9], (addr->ip[10]<<8)|addr->ip[11], (addr->ip[12]<<8)|addr->ip[13], (addr->ip[14]<<8)|addr->ip[15], - addr->port); - else - str_format(string, max_length, "[%x:%x:%x:%x:%x:%x:%x:%x]", - (addr->ip[0]<<8)|addr->ip[1], (addr->ip[2]<<8)|addr->ip[3], (addr->ip[4]<<8)|addr->ip[5], (addr->ip[6]<<8)|addr->ip[7], - (addr->ip[8]<<8)|addr->ip[9], (addr->ip[10]<<8)|addr->ip[11], (addr->ip[12]<<8)|addr->ip[13], (addr->ip[14]<<8)|addr->ip[15]); - } - else - str_format(string, max_length, "unknown type %d", addr->type); -} - -static int priv_net_extract(const char *hostname, char *host, int max_host, int *port) -{ - int i; - - *port = 0; - host[0] = 0; - - if(hostname[0] == '[') - { - // ipv6 mode - for(i = 1; i < max_host && hostname[i] && hostname[i] != ']'; i++) - host[i-1] = hostname[i]; - host[i-1] = 0; - if(hostname[i] != ']') // malformatted - return -1; - - i++; - if(hostname[i] == ':') - *port = atol(hostname+i+1); - } - else - { - // generic mode (ipv4, hostname etc) - for(i = 0; i < max_host-1 && hostname[i] && hostname[i] != ':'; i++) - host[i] = hostname[i]; - host[i] = 0; - - if(hostname[i] == ':') - *port = atol(hostname+i+1); - } - - return 0; -} - -int net_host_lookup(const char *hostname, NETADDR *addr, int types) -{ - struct addrinfo hints; - struct addrinfo *result; - int e; - char host[256]; - int port = 0; - - if(priv_net_extract(hostname, host, sizeof(host), &port)) - return -1; - /* - dbg_msg("host lookup", "host='%s' port=%d %d", host, port, types); - */ - - mem_zero(&hints, sizeof(hints)); - - hints.ai_family = AF_UNSPEC; - - if(types == NETTYPE_IPV4) - hints.ai_family = AF_INET; - else if(types == NETTYPE_IPV6) - hints.ai_family = AF_INET6; - - e = getaddrinfo(host, NULL, &hints, &result); - if(e != 0 || !result) - return -1; - - sockaddr_to_netaddr(result->ai_addr, addr); - freeaddrinfo(result); - addr->port = port; - return 0; -} - -static int parse_int(int *out, const char **str) -{ - int i = 0; - *out = 0; - if(**str < '0' || **str > '9') - return -1; - - i = **str - '0'; - (*str)++; - - while(1) - { - if(**str < '0' || **str > '9') - { - *out = i; - return 0; - } - - i = (i*10) + (**str - '0'); - (*str)++; - } - - return 0; -} - -static int parse_char(char c, const char **str) -{ - if(**str != c) return -1; - (*str)++; - return 0; -} - -static int parse_uint8(unsigned char *out, const char **str) -{ - int i; - if(parse_int(&i, str) != 0) return -1; - if(i < 0 || i > 0xff) return -1; - *out = i; - return 0; -} - -static int parse_uint16(unsigned short *out, const char **str) -{ - int i; - if(parse_int(&i, str) != 0) return -1; - if(i < 0 || i > 0xffff) return -1; - *out = i; - return 0; -} - -int net_addr_from_str(NETADDR *addr, const char *string) -{ - const char *str = string; - mem_zero(addr, sizeof(NETADDR)); - - if(str[0] == '[') - { - /* ipv6 */ - struct sockaddr_in6 sa6; - char buf[128]; - int i; - str++; - for(i = 0; i < 127 && str[i] && str[i] != ']'; i++) - buf[i] = str[i]; - buf[i] = 0; - str += i; -#if defined(CONF_FAMILY_WINDOWS) - { - int size; - sa6.sin6_family = AF_INET6; - size = (int)sizeof(sa6); - if(WSAStringToAddress(buf, AF_INET6, NULL, (struct sockaddr *)&sa6, &size) != 0) - return -1; - } -#else - if(inet_pton(AF_INET6, buf, &sa6) != 1) - return -1; -#endif - sockaddr_to_netaddr((struct sockaddr *)&sa6, addr); - - if(*str == ']') - { - str++; - if(*str == ':') - { - str++; - if(parse_uint16(&addr->port, &str)) - return -1; - } - } - else - return -1; - - return 0; - } - else - { - /* ipv4 */ - if(parse_uint8(&addr->ip[0], &str)) return -1; - if(parse_char('.', &str)) return -1; - if(parse_uint8(&addr->ip[1], &str)) return -1; - if(parse_char('.', &str)) return -1; - if(parse_uint8(&addr->ip[2], &str)) return -1; - if(parse_char('.', &str)) return -1; - if(parse_uint8(&addr->ip[3], &str)) return -1; - if(*str == ':') - { - str++; - if(parse_uint16(&addr->port, &str)) return -1; - } - - addr->type = NETTYPE_IPV4; - } - - return 0; -} - -static void priv_net_close_socket(int sock) -{ -#if defined(CONF_FAMILY_WINDOWS) - closesocket(sock); -#else - close(sock); -#endif -} - -static int priv_net_close_all_sockets(NETSOCKET sock) -{ - /* close down ipv4 */ - if(sock.ipv4sock >= 0) - { - priv_net_close_socket(sock.ipv4sock); - sock.ipv4sock = -1; - sock.type &= ~NETTYPE_IPV4; - } - - /* close down ipv6 */ - if(sock.ipv6sock >= 0) - { - priv_net_close_socket(sock.ipv6sock); - sock.ipv6sock = -1; - sock.type &= ~NETTYPE_IPV6; - } - return 0; -} - -static int priv_net_create_socket(int domain, int type, struct sockaddr *addr, int sockaddrlen) -{ - int sock, e; - - /* create socket */ - sock = socket(domain, type, 0); - if(sock < 0) - { -#if defined(CONF_FAMILY_WINDOWS) - char buf[128]; - int error = WSAGetLastError(); - if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, 0, buf, sizeof(buf), 0) == 0) - buf[0] = 0; - dbg_msg("net", "failed to create socket with domain %d and type %d (%d '%s')", domain, type, error, buf); -#else - dbg_msg("net", "failed to create socket with domain %d and type %d (%d '%s')", domain, type, errno, strerror(errno)); -#endif - return -1; - } - - /* set to IPv6 only if thats what we are creating */ -#if defined(IPV6_V6ONLY) /* windows sdk 6.1 and higher */ - if(domain == AF_INET6) - { - int ipv6only = 1; - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&ipv6only, sizeof(ipv6only)); - } -#endif - - if(type == SOCK_STREAM) - { - int tmp = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)); - } - - /* bind the socket */ - e = bind(sock, addr, sockaddrlen); - if(e != 0) - { -#if defined(CONF_FAMILY_WINDOWS) - char buf[128]; - int error = WSAGetLastError(); - if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, 0, buf, sizeof(buf), 0) == 0) - buf[0] = 0; - dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, error, buf); -#else - dbg_msg("net", "failed to bind socket with domain %d and type %d (%d '%s')", domain, type, errno, strerror(errno)); -#endif - priv_net_close_socket(sock); - return -1; - } - - /* return the newly created socket */ - return sock; -} - -NETSOCKET net_udp_create(NETADDR bindaddr) -{ - NETSOCKET sock = invalid_socket; - NETADDR tmpbindaddr = bindaddr; - int broadcast = 1; - int recvsize = 65536; - - if(bindaddr.type&NETTYPE_IPV4) - { - struct sockaddr_in addr; - int socket = -1; - - /* bind, we should check for error */ - tmpbindaddr.type = NETTYPE_IPV4; - netaddr_to_sockaddr_in(&tmpbindaddr, &addr); - socket = priv_net_create_socket(AF_INET, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr)); - if(socket >= 0) - { - sock.type |= NETTYPE_IPV4; - sock.ipv4sock = socket; - - /* set broadcast */ - setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)); - - /* set receive buffer size */ - setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvsize, sizeof(recvsize)); - } - } - - if(bindaddr.type&NETTYPE_IPV6) - { - struct sockaddr_in6 addr; - int socket = -1; - - /* bind, we should check for error */ - tmpbindaddr.type = NETTYPE_IPV6; - netaddr_to_sockaddr_in6(&tmpbindaddr, &addr); - socket = priv_net_create_socket(AF_INET6, SOCK_DGRAM, (struct sockaddr *)&addr, sizeof(addr)); - if(socket >= 0) - { - sock.type |= NETTYPE_IPV6; - sock.ipv6sock = socket; - - /* set broadcast */ - setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast)); - - /* set receive buffer size */ - setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char*)&recvsize, sizeof(recvsize)); - } - } - - /* set non-blocking */ - net_set_non_blocking(sock); - - /* return */ - return sock; -} - -int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size) -{ - int d = -1; - - if(addr->type&NETTYPE_IPV4) - { - if(sock.ipv4sock >= 0) - { - struct sockaddr_in sa; - if(addr->type&NETTYPE_LINK_BROADCAST) - { - mem_zero(&sa, sizeof(sa)); - sa.sin_port = htons(addr->port); - sa.sin_family = AF_INET; - sa.sin_addr.s_addr = INADDR_BROADCAST; - } - else - netaddr_to_sockaddr_in(addr, &sa); - - d = sendto((int)sock.ipv4sock, (const char*)data, size, 0, (struct sockaddr *)&sa, sizeof(sa)); - } - else - dbg_msg("net", "can't sent ipv4 traffic to this socket"); - } - - if(addr->type&NETTYPE_IPV6) - { - if(sock.ipv6sock >= 0) - { - struct sockaddr_in6 sa; - if(addr->type&NETTYPE_LINK_BROADCAST) - { - mem_zero(&sa, sizeof(sa)); - sa.sin6_port = htons(addr->port); - sa.sin6_family = AF_INET6; - sa.sin6_addr.s6_addr[0] = 0xff; /* multicast */ - sa.sin6_addr.s6_addr[1] = 0x02; /* link local scope */ - sa.sin6_addr.s6_addr[15] = 1; /* all nodes */ - } - else - netaddr_to_sockaddr_in6(addr, &sa); - - d = sendto((int)sock.ipv6sock, (const char*)data, size, 0, (struct sockaddr *)&sa, sizeof(sa)); - } - else - dbg_msg("net", "can't sent ipv6 traffic to this socket"); - } - /* - else - dbg_msg("net", "can't sent to network of type %d", addr->type); - */ - - /*if(d < 0) - { - char addrstr[256]; - net_addr_str(addr, addrstr, sizeof(addrstr)); - - dbg_msg("net", "sendto error (%d '%s')", errno, strerror(errno)); - dbg_msg("net", "\tsock = %d %x", sock, sock); - dbg_msg("net", "\tsize = %d %x", size, size); - dbg_msg("net", "\taddr = %s", addrstr); - - }*/ - network_stats.sent_bytes += size; - network_stats.sent_packets++; - return d; -} - -int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize) -{ - char sockaddrbuf[128]; - socklen_t fromlen;// = sizeof(sockaddrbuf); - int bytes = 0; - - if(bytes == 0 && sock.ipv4sock >= 0) - { - fromlen = sizeof(struct sockaddr_in); - bytes = recvfrom(sock.ipv4sock, (char*)data, maxsize, 0, (struct sockaddr *)&sockaddrbuf, &fromlen); - } - - if(bytes <= 0 && sock.ipv6sock >= 0) - { - fromlen = sizeof(struct sockaddr_in6); - bytes = recvfrom(sock.ipv6sock, (char*)data, maxsize, 0, (struct sockaddr *)&sockaddrbuf, &fromlen); - } - - if(bytes > 0) - { - sockaddr_to_netaddr((struct sockaddr *)&sockaddrbuf, addr); - network_stats.recv_bytes += bytes; - network_stats.recv_packets++; - return bytes; - } - else if(bytes == 0) - return 0; - return -1; /* error */ -} - -int net_udp_close(NETSOCKET sock) -{ - return priv_net_close_all_sockets(sock); -} - -NETSOCKET net_tcp_create(NETADDR bindaddr) -{ - NETSOCKET sock = invalid_socket; - NETADDR tmpbindaddr = bindaddr; - - if(bindaddr.type&NETTYPE_IPV4) - { - struct sockaddr_in addr; - int socket = -1; - - /* bind, we should check for error */ - tmpbindaddr.type = NETTYPE_IPV4; - netaddr_to_sockaddr_in(&tmpbindaddr, &addr); - socket = priv_net_create_socket(AF_INET, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr)); - if(socket >= 0) - { - sock.type |= NETTYPE_IPV4; - sock.ipv4sock = socket; - } - } - - if(bindaddr.type&NETTYPE_IPV6) - { - struct sockaddr_in6 addr; - int socket = -1; - - /* bind, we should check for error */ - tmpbindaddr.type = NETTYPE_IPV6; - netaddr_to_sockaddr_in6(&tmpbindaddr, &addr); - socket = priv_net_create_socket(AF_INET6, SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr)); - if(socket >= 0) - { - sock.type |= NETTYPE_IPV6; - sock.ipv6sock = socket; - } - } - - /* return */ - return sock; -} - -int net_set_non_blocking(NETSOCKET sock) -{ - unsigned long mode = 1; - if(sock.ipv4sock >= 0) - { -#if defined(CONF_FAMILY_WINDOWS) - ioctlsocket(sock.ipv4sock, FIONBIO, (unsigned long *)&mode); -#else - ioctl(sock.ipv4sock, FIONBIO, (unsigned long *)&mode); -#endif - } - - if(sock.ipv6sock >= 0) - { -#if defined(CONF_FAMILY_WINDOWS) - ioctlsocket(sock.ipv6sock, FIONBIO, (unsigned long *)&mode); -#else - ioctl(sock.ipv6sock, FIONBIO, (unsigned long *)&mode); -#endif - } - - return 0; -} - -int net_set_blocking(NETSOCKET sock) -{ - unsigned long mode = 0; - if(sock.ipv4sock >= 0) - { -#if defined(CONF_FAMILY_WINDOWS) - ioctlsocket(sock.ipv4sock, FIONBIO, (unsigned long *)&mode); -#else - ioctl(sock.ipv4sock, FIONBIO, (unsigned long *)&mode); -#endif - } - - if(sock.ipv6sock >= 0) - { -#if defined(CONF_FAMILY_WINDOWS) - ioctlsocket(sock.ipv6sock, FIONBIO, (unsigned long *)&mode); -#else - ioctl(sock.ipv6sock, FIONBIO, (unsigned long *)&mode); -#endif - } - - return 0; -} - -int net_tcp_listen(NETSOCKET sock, int backlog) -{ - int err = -1; - if(sock.ipv4sock >= 0) - err = listen(sock.ipv4sock, backlog); - if(sock.ipv6sock >= 0) - err = listen(sock.ipv6sock, backlog); - return err; -} - -int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a) -{ - int s; - socklen_t sockaddr_len; - - *new_sock = invalid_socket; - - if(sock.ipv4sock >= 0) - { - struct sockaddr_in addr; - sockaddr_len = sizeof(addr); - - s = accept(sock.ipv4sock, (struct sockaddr *)&addr, &sockaddr_len); - - if (s != -1) - { - sockaddr_to_netaddr((const struct sockaddr *)&addr, a); - new_sock->type = NETTYPE_IPV4; - new_sock->ipv4sock = s; - return s; - } - } - - if(sock.ipv6sock >= 0) - { - struct sockaddr_in6 addr; - sockaddr_len = sizeof(addr); - - s = accept(sock.ipv6sock, (struct sockaddr *)&addr, &sockaddr_len); - - if (s != -1) - { - sockaddr_to_netaddr((const struct sockaddr *)&addr, a); - new_sock->type = NETTYPE_IPV6; - new_sock->ipv6sock = s; - return s; - } - } - - return -1; -} - -int net_tcp_connect(NETSOCKET sock, const NETADDR *a) -{ - if(a->type&NETTYPE_IPV4) - { - struct sockaddr_in addr; - netaddr_to_sockaddr_in(a, &addr); - return connect(sock.ipv4sock, (struct sockaddr *)&addr, sizeof(addr)); - } - - if(a->type&NETTYPE_IPV6) - { - struct sockaddr_in6 addr; - netaddr_to_sockaddr_in6(a, &addr); - return connect(sock.ipv6sock, (struct sockaddr *)&addr, sizeof(addr)); - } - - return -1; -} - -int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr) -{ - int res = 0; - - net_set_non_blocking(sock); - res = net_tcp_connect(sock, &bindaddr); - net_set_blocking(sock); - - return res; -} - -int net_tcp_send(NETSOCKET sock, const void *data, int size) -{ - int bytes = -1; - - if(sock.ipv4sock >= 0) - bytes = send((int)sock.ipv4sock, (const char*)data, size, 0); - if(sock.ipv6sock >= 0) - bytes = send((int)sock.ipv6sock, (const char*)data, size, 0); - - return bytes; -} - -int net_tcp_recv(NETSOCKET sock, void *data, int maxsize) -{ - int bytes = -1; - - if(sock.ipv4sock >= 0) - bytes = recv((int)sock.ipv4sock, (char*)data, maxsize, 0); - if(sock.ipv6sock >= 0) - bytes = recv((int)sock.ipv6sock, (char*)data, maxsize, 0); - - return bytes; -} - -int net_tcp_close(NETSOCKET sock) -{ - return priv_net_close_all_sockets(sock); -} - -int net_errno() -{ -#if defined(CONF_FAMILY_WINDOWS) - return WSAGetLastError(); -#else - return errno; -#endif -} - -int net_would_block() -{ -#if defined(CONF_FAMILY_WINDOWS) - return net_errno() == WSAEWOULDBLOCK; -#else - return net_errno() == EWOULDBLOCK; -#endif -} - -int net_init() -{ -#if defined(CONF_FAMILY_WINDOWS) - WSADATA wsaData; - int err = WSAStartup(MAKEWORD(1, 1), &wsaData); - dbg_assert(err == 0, "network initialization failed."); - return err==0?0:1; -#endif - - return 0; -} - -int fs_listdir(const char *dir, FS_LISTDIR_CALLBACK cb, int type, void *user) -{ -#if defined(CONF_FAMILY_WINDOWS) - WIN32_FIND_DATA finddata; - HANDLE handle; - char buffer[1024*2]; - int length; - str_format(buffer, sizeof(buffer), "%s/*", dir); - - handle = FindFirstFileA(buffer, &finddata); - - if (handle == INVALID_HANDLE_VALUE) - return 0; - - str_format(buffer, sizeof(buffer), "%s/", dir); - length = str_length(buffer); - - /* add all the entries */ - do - { - str_copy(buffer+length, finddata.cFileName, (int)sizeof(buffer)-length); - if(cb(finddata.cFileName, fs_is_dir(buffer), type, user)) - break; - } - while (FindNextFileA(handle, &finddata)); - - FindClose(handle); - return 0; -#else - struct dirent *entry; - char buffer[1024*2]; - int length; - DIR *d = opendir(dir); - - if(!d) - return 0; - - str_format(buffer, sizeof(buffer), "%s/", dir); - length = str_length(buffer); - - while((entry = readdir(d)) != NULL) - { - str_copy(buffer+length, entry->d_name, (int)sizeof(buffer)-length); - if(cb(entry->d_name, fs_is_dir(buffer), type, user)) - break; - } - - /* close the directory and return */ - closedir(d); - return 0; -#endif -} - -int fs_storage_path(const char *appname, char *path, int max) -{ -#if defined(CONF_FAMILY_WINDOWS) - char *home = getenv("APPDATA"); - if(!home) - return -1; - _snprintf(path, max, "%s/%s", home, appname); - return 0; -#else - char *home = getenv("HOME"); -#if !defined(CONF_PLATFORM_MACOSX) - int i; -#endif - if(!home) - return -1; - -#if defined(CONF_PLATFORM_MACOSX) - snprintf(path, max, "%s/Library/Application Support/%s", home, appname); -#else - snprintf(path, max, "%s/.%s", home, appname); - for(i = strlen(home)+2; path[i]; i++) - path[i] = tolower(path[i]); -#endif - - return 0; -#endif -} - -int fs_makedir(const char *path) -{ -#if defined(CONF_FAMILY_WINDOWS) - if(_mkdir(path) == 0) - return 0; - if(errno == EEXIST) - return 0; - return -1; -#else - if(mkdir(path, 0755) == 0) - return 0; - if(errno == EEXIST) - return 0; - return -1; -#endif -} - -int fs_is_dir(const char *path) -{ -#if defined(CONF_FAMILY_WINDOWS) - /* TODO: do this smarter */ - WIN32_FIND_DATA finddata; - HANDLE handle; - char buffer[1024*2]; - str_format(buffer, sizeof(buffer), "%s/*", path); - - if ((handle = FindFirstFileA(buffer, &finddata)) == INVALID_HANDLE_VALUE) - return 0; - - FindClose(handle); - return 1; -#else - struct stat sb; - if (stat(path, &sb) == -1) - return 0; - - if (S_ISDIR(sb.st_mode)) - return 1; - else - return 0; -#endif -} - -int fs_chdir(const char *path) -{ - if(fs_is_dir(path)) - { - if(chdir(path)) - return 1; - else - return 0; - } - else - return 1; -} - -char *fs_getcwd(char *buffer, int buffer_size) -{ - if(buffer == 0) - return 0; -#if defined(CONF_FAMILY_WINDOWS) - return _getcwd(buffer, buffer_size); -#else - return getcwd(buffer, buffer_size); -#endif -} - -int fs_parent_dir(char *path) -{ - char *parent = 0; - for(; *path; ++path) - { - if(*path == '/' || *path == '\\') - parent = path; - } - - if(parent) - { - *parent = 0; - return 0; - } - return 1; -} - -int fs_remove(const char *filename) -{ - if(remove(filename) != 0) - return 1; - return 0; -} - -int fs_rename(const char *oldname, const char *newname) -{ - if(rename(oldname, newname) != 0) - return 1; - return 0; -} - -void swap_endian(void *data, unsigned elem_size, unsigned num) -{ - char *src = (char*) data; - char *dst = src + (elem_size - 1); - - while(num) - { - unsigned n = elem_size>>1; - char tmp; - while(n) - { - tmp = *src; - *src = *dst; - *dst = tmp; - - src++; - dst--; - n--; - } - - src = src + (elem_size>>1); - dst = src + (elem_size - 1); - num--; - } -} - -int net_socket_read_wait(NETSOCKET sock, int time) -{ - struct timeval tv; - fd_set readfds; - int sockid; - - tv.tv_sec = 0; - tv.tv_usec = 1000*time; - sockid = 0; - - FD_ZERO(&readfds); - if(sock.ipv4sock >= 0) - { - FD_SET(sock.ipv4sock, &readfds); - sockid = sock.ipv4sock; - } - if(sock.ipv6sock >= 0) - { - FD_SET(sock.ipv6sock, &readfds); - if(sock.ipv6sock > sockid) - sockid = sock.ipv6sock; - } - - /* don't care about writefds and exceptfds */ - select(sockid+1, &readfds, NULL, NULL, &tv); - - if(sock.ipv4sock >= 0 && FD_ISSET(sock.ipv4sock, &readfds)) - return 1; - - if(sock.ipv6sock >= 0 && FD_ISSET(sock.ipv6sock, &readfds)) - return 1; - - return 0; -} - -int time_timestamp() -{ - return time(0); -} - -void str_append(char *dst, const char *src, int dst_size) -{ - int s = strlen(dst); - int i = 0; - while(s < dst_size) - { - dst[s] = src[i]; - if(!src[i]) /* check for null termination */ - break; - s++; - i++; - } - - dst[dst_size-1] = 0; /* assure null termination */ -} - -void str_copy(char *dst, const char *src, int dst_size) -{ - strncpy(dst, src, dst_size); - dst[dst_size-1] = 0; /* assure null termination */ -} - -int str_length(const char *str) -{ - return (int)strlen(str); -} - -void str_format(char *buffer, int buffer_size, const char *format, ...) -{ -#if defined(CONF_FAMILY_WINDOWS) - va_list ap; - va_start(ap, format); - _vsnprintf(buffer, buffer_size, format, ap); - va_end(ap); -#else - va_list ap; - va_start(ap, format); - vsnprintf(buffer, buffer_size, format, ap); - va_end(ap); -#endif - - buffer[buffer_size-1] = 0; /* assure null termination */ -} - - - -/* makes sure that the string only contains the characters between 32 and 127 */ -void str_sanitize_strong(char *str_in) -{ - unsigned char *str = (unsigned char *)str_in; - while(*str) - { - *str &= 0x7f; - if(*str < 32) - *str = 32; - str++; - } -} - -/* makes sure that the string only contains the characters between 32 and 255 */ -void str_sanitize_cc(char *str_in) -{ - unsigned char *str = (unsigned char *)str_in; - while(*str) - { - if(*str < 32) - *str = ' '; - str++; - } -} - -/* makes sure that the string only contains the characters between 32 and 255 + \r\n\t */ -void str_sanitize(char *str_in) -{ - unsigned char *str = (unsigned char *)str_in; - while(*str) - { - if(*str < 32 && !(*str == '\r') && !(*str == '\n') && !(*str == '\t')) - *str = ' '; - str++; - } -} - -char *str_skip_to_whitespace(char *str) -{ - while(*str && (*str != ' ' && *str != '\t' && *str != '\n')) - str++; - return str; -} - -char *str_skip_whitespaces(char *str) -{ - while(*str && (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r')) - str++; - return str; -} - -/* case */ -int str_comp_nocase(const char *a, const char *b) -{ -#if defined(CONF_FAMILY_WINDOWS) - return _stricmp(a,b); -#else - return strcasecmp(a,b); -#endif -} - -int str_comp_nocase_num(const char *a, const char *b, const int num) -{ -#if defined(CONF_FAMILY_WINDOWS) - return _strnicmp(a, b, num); -#else - return strncasecmp(a, b, num); -#endif -} - -int str_comp(const char *a, const char *b) -{ - return strcmp(a, b); -} - -int str_comp_num(const char *a, const char *b, const int num) -{ - return strncmp(a, b, num); -} - -int str_comp_filenames(const char *a, const char *b) -{ - int result; - - for(; *a && *b; ++a, ++b) - { - if(*a >= '0' && *a <= '9' && *b >= '0' && *b <= '9') - { - result = 0; - do - { - if(!result) - result = *a - *b; - ++a; ++b; - } - while(*a >= '0' && *a <= '9' && *b >= '0' && *b <= '9'); - - if(*a >= '0' && *a <= '9') - return 1; - else if(*b >= '0' && *b <= '9') - return -1; - else if(result) - return result; - } - - if(tolower(*a) != tolower(*b)) - break; - } - return tolower(*a) - tolower(*b); -} - -const char *str_find_nocase(const char *haystack, const char *needle) -{ - while(*haystack) /* native implementation */ - { - const char *a = haystack; - const char *b = needle; - while(*a && *b && tolower(*a) == tolower(*b)) - { - a++; - b++; - } - if(!(*b)) - return haystack; - haystack++; - } - - return 0; -} - - -const char *str_find(const char *haystack, const char *needle) -{ - while(*haystack) /* native implementation */ - { - const char *a = haystack; - const char *b = needle; - while(*a && *b && *a == *b) - { - a++; - b++; - } - if(!(*b)) - return haystack; - haystack++; - } - - return 0; -} - -void str_hex(char *dst, int dst_size, const void *data, int data_size) -{ - static const char hex[] = "0123456789ABCDEF"; - int b; - - for(b = 0; b < data_size && b < dst_size/4-4; b++) - { - dst[b*3] = hex[((const unsigned char *)data)[b]>>4]; - dst[b*3+1] = hex[((const unsigned char *)data)[b]&0xf]; - dst[b*3+2] = ' '; - dst[b*3+3] = 0; - } -} - -void str_timestamp(char *buffer, int buffer_size) -{ - time_t time_data; - struct tm *time_info; - - time(&time_data); - time_info = localtime(&time_data); - strftime(buffer, buffer_size, "%Y-%m-%d_%H-%M-%S", time_info); - buffer[buffer_size-1] = 0; /* assure null termination */ -} - -int mem_comp(const void *a, const void *b, int size) -{ - return memcmp(a,b,size); -} - -const MEMSTATS *mem_stats() -{ - return &memory_stats; -} - -void net_stats(NETSTATS *stats_inout) -{ - *stats_inout = network_stats; -} - -void gui_messagebox(const char *title, const char *message) -{ -#if defined(CONF_PLATFORM_MACOSX) - DialogRef theItem; - DialogItemIndex itemIndex; - - /* FIXME: really needed? can we rely on glfw? */ - /* HACK - get events without a bundle */ - ProcessSerialNumber psn; - GetCurrentProcess(&psn); - TransformProcessType(&psn,kProcessTransformToForegroundApplication); - SetFrontProcess(&psn); - /* END HACK */ - - CreateStandardAlert(kAlertStopAlert, - CFStringCreateWithCString(NULL, title, kCFStringEncodingASCII), - CFStringCreateWithCString(NULL, message, kCFStringEncodingASCII), - NULL, - &theItem); - - RunStandardAlert(theItem, NULL, &itemIndex); -#elif defined(CONF_FAMILY_UNIX) - static char cmd[1024]; - int err; - /* use xmessage which is available on nearly every X11 system */ - snprintf(cmd, sizeof(cmd), "xmessage -center -title '%s' '%s'", - title, - message); - - err = system(cmd); - dbg_msg("gui/msgbox", "result = %i", err); -#elif defined(CONF_FAMILY_WINDOWS) - MessageBox(NULL, - message, - title, - MB_ICONEXCLAMATION | MB_OK); -#else - /* this is not critical */ - #warning not implemented -#endif -} - -int str_isspace(char c) { return c == ' ' || c == '\n' || c == '\t'; } - -char str_uppercase(char c) -{ - if(c >= 'a' && c <= 'z') - return 'A' + (c-'a'); - return c; -} - -int str_toint(const char *str) { return atoi(str); } -float str_tofloat(const char *str) { return atof(str); } - - - -static int str_utf8_isstart(char c) -{ - if((c&0xC0) == 0x80) /* 10xxxxxx */ - return 0; - return 1; -} - -int str_utf8_rewind(const char *str, int cursor) -{ - while(cursor) - { - cursor--; - if(str_utf8_isstart(*(str + cursor))) - break; - } - return cursor; -} - -int str_utf8_forward(const char *str, int cursor) -{ - const char *buf = str + cursor; - if(!buf[0]) - return cursor; - - if((*buf&0x80) == 0x0) /* 0xxxxxxx */ - return cursor+1; - else if((*buf&0xE0) == 0xC0) /* 110xxxxx */ - { - if(!buf[1]) return cursor+1; - return cursor+2; - } - else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */ - { - if(!buf[1]) return cursor+1; - if(!buf[2]) return cursor+2; - return cursor+3; - } - else if((*buf & 0xF8) == 0xF0) /* 11110xxx */ - { - if(!buf[1]) return cursor+1; - if(!buf[2]) return cursor+2; - if(!buf[3]) return cursor+3; - return cursor+4; - } - - /* invalid */ - return cursor+1; -} - -int str_utf8_encode(char *ptr, int chr) -{ - /* encode */ - if(chr <= 0x7F) - { - ptr[0] = (char)chr; - return 1; - } - else if(chr <= 0x7FF) - { - ptr[0] = 0xC0|((chr>>6)&0x1F); - ptr[1] = 0x80|(chr&0x3F); - return 2; - } - else if(chr <= 0xFFFF) - { - ptr[0] = 0xE0|((chr>>12)&0x0F); - ptr[1] = 0x80|((chr>>6)&0x3F); - ptr[2] = 0x80|(chr&0x3F); - return 3; - } - else if(chr <= 0x10FFFF) - { - ptr[0] = 0xF0|((chr>>18)&0x07); - ptr[1] = 0x80|((chr>>12)&0x3F); - ptr[2] = 0x80|((chr>>6)&0x3F); - ptr[3] = 0x80|(chr&0x3F); - return 4; - } - - return 0; -} - -int str_utf8_decode(const char **ptr) -{ - const char *buf = *ptr; - int ch = 0; - - do - { - if((*buf&0x80) == 0x0) /* 0xxxxxxx */ - { - ch = *buf; - buf++; - } - else if((*buf&0xE0) == 0xC0) /* 110xxxxx */ - { - ch = (*buf++ & 0x3F) << 6; if(!(*buf)) break; - ch += (*buf++ & 0x3F); - if(ch == 0) ch = -1; - } - else if((*buf & 0xF0) == 0xE0) /* 1110xxxx */ - { - ch = (*buf++ & 0x1F) << 12; if(!(*buf)) break; - ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break; - ch += (*buf++ & 0x3F); - if(ch == 0) ch = -1; - } - else if((*buf & 0xF8) == 0xF0) /* 11110xxx */ - { - ch = (*buf++ & 0x0F) << 18; if(!(*buf)) break; - ch += (*buf++ & 0x3F) << 12; if(!(*buf)) break; - ch += (*buf++ & 0x3F) << 6; if(!(*buf)) break; - ch += (*buf++ & 0x3F); - if(ch == 0) ch = -1; - } - else - { - /* invalid */ - buf++; - break; - } - - *ptr = buf; - return ch; - } while(0); - - /* out of bounds */ - *ptr = buf; - return -1; - -} - -int str_utf8_check(const char *str) -{ - while(*str) - { - if((*str&0x80) == 0x0) - str++; - else if((*str&0xE0) == 0xC0 && (*(str+1)&0xC0) == 0x80) - str += 2; - else if((*str&0xF0) == 0xE0 && (*(str+1)&0xC0) == 0x80 && (*(str+2)&0xC0) == 0x80) - str += 3; - else if((*str&0xF8) == 0xF0 && (*(str+1)&0xC0) == 0x80 && (*(str+2)&0xC0) == 0x80 && (*(str+3)&0xC0) == 0x80) - str += 4; - else - return 0; - } - return 1; -} - - -unsigned str_quickhash(const char *str) -{ - unsigned hash = 5381; - for(; *str; str++) - hash = ((hash << 5) + hash) + (*str); /* hash * 33 + c */ - return hash; -} - - -#if defined(__cplusplus) -} -#endif diff --git a/server/ssl.go b/server/ssl.go new file mode 100644 index 0000000..90e925a --- /dev/null +++ b/server/ssl.go @@ -0,0 +1,204 @@ +package main + +import ( + "crypto/tls" + "fmt" + "net" + "net/url" + "strconv" + "strings" + "time" +) + +type CertState struct { + Config SSLCertConfig + ExpireTS int64 + Mismatch bool + LastError string + LastCheck time.Time + Checking bool + LastAlarm7 time.Time + LastAlarm3 time.Time + LastAlarm1 time.Time + LastAlarmMismatch time.Time +} + +func certKey(config SSLCertConfig) string { + return fmt.Sprintf("%s\x00%s\x00%d", config.Name, config.Domain, config.Port) +} + +func (a *App) reconcileCerts(configs []SSLCertConfig) { + a.certMu.Lock() + defer a.certMu.Unlock() + next := make(map[string]*CertState, len(configs)) + for _, config := range configs { + key := certKey(config) + if existing := a.certs[key]; existing != nil { + existing.Config = config + next[key] = existing + } else { + next[key] = &CertState{Config: config} + } + } + a.certs = next +} + +func (a *App) sslLoop() { + a.runDueSSLChecks() + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + for { + select { + case <-a.ctx.Done(): + return + case <-ticker.C: + a.runDueSSLChecks() + } + } +} + +func (a *App) runDueSSLChecks() { + now := time.Now() + type dueCheck struct { + key string + config SSLCertConfig + } + due := make([]dueCheck, 0) + a.certMu.Lock() + for key, state := range a.certs { + interval := secondsDuration(state.Config.Interval) + if !state.Checking && (state.LastCheck.IsZero() || now.Sub(state.LastCheck) >= interval) { + state.Checking = true + due = append(due, dueCheck{key: key, config: state.Config}) + } + } + a.certMu.Unlock() + for _, check := range due { + check := check + go a.executeSSLCheck(check.key, check.config) + } +} + +func (a *App) executeSSLCheck(key string, config SSLCertConfig) { + expireTS, mismatch, err := checkCertificate(config) + now := time.Now() + type notification struct { + message string + } + alerts := make([]notification, 0, 2) + + a.certMu.Lock() + state := a.certs[key] + if state == nil { + a.certMu.Unlock() + return + } + state.Checking = false + state.LastCheck = now + if err != nil { + state.LastError = err.Error() + a.certMu.Unlock() + a.wakeStatsWriter() + return + } + state.ExpireTS = expireTS + state.Mismatch = mismatch + state.LastError = "" + if config.Callback != "" && mismatch && (state.LastAlarmMismatch.IsZero() || now.Sub(state.LastAlarmMismatch) >= 24*time.Hour) { + state.LastAlarmMismatch = now + alerts = append(alerts, notification{message: fmt.Sprintf("【SSL证书域名不匹配】%s(%s) 证书域名与配置不一致", config.Name, config.Domain)}) + } + days := int((expireTS - now.Unix()) / 86400) + if config.Callback != "" { + var lastAlarm *time.Time + switch { + case days <= 7 && days > 3: + lastAlarm = &state.LastAlarm7 + case days <= 3 && days > 1: + lastAlarm = &state.LastAlarm3 + case days <= 1: + lastAlarm = &state.LastAlarm1 + } + if lastAlarm != nil && (lastAlarm.IsZero() || now.Sub(*lastAlarm) >= 20*time.Hour) { + *lastAlarm = now + expire := time.Unix(expireTS, 0).UTC().Format("2006-01-02 15:04:05") + alerts = append(alerts, notification{message: fmt.Sprintf("【SSL证书提醒】%s(%s) 将在 %d 天后(%s UTC) 到期", config.Name, config.Domain, days, expire)}) + } + } + a.certMu.Unlock() + a.wakeStatsWriter() + + for _, alert := range alerts { + if err := a.sendCallback(config.Callback, alert.message, "ServerStatusSSL"); err != nil { + a.logger.Printf("SSL certificate %q callback: %v", config.Name, err) + } + } +} + +func checkCertificate(config SSLCertConfig) (int64, bool, error) { + host, err := certificateHost(config.Domain) + if err != nil { + return 0, false, err + } + address := net.JoinHostPort(host, strconv.Itoa(config.Port)) + dialer := &net.Dialer{Timeout: 6 * time.Second} + connection, err := tls.DialWithDialer(dialer, "tcp", address, &tls.Config{ + ServerName: host, + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: true, // VerifyHostname below preserves the legacy chain-independent check. + }) + if err != nil { + return 0, false, err + } + defer connection.Close() + certificates := connection.ConnectionState().PeerCertificates + if len(certificates) == 0 { + return 0, false, fmt.Errorf("server returned no certificate") + } + leaf := certificates[0] + mismatch := leaf.VerifyHostname(host) != nil + return leaf.NotAfter.Unix(), mismatch, nil +} + +func certificateHost(raw string) (string, error) { + raw = strings.TrimSpace(raw) + if raw == "" { + return "", fmt.Errorf("domain is empty") + } + if parsed, err := url.Parse(raw); err == nil && parsed.Hostname() != "" { + return parsed.Hostname(), nil + } + withoutPath := strings.SplitN(raw, "/", 2)[0] + if host, _, err := net.SplitHostPort(withoutPath); err == nil { + return strings.Trim(host, "[]"), nil + } + host := strings.Trim(withoutPath, "[]") + if host == "" { + return "", fmt.Errorf("domain is invalid") + } + return host, nil +} + +func (a *App) sslSnapshot(configs []SSLCertConfig, now time.Time) []any { + a.certMu.RLock() + defer a.certMu.RUnlock() + result := make([]any, 0, len(configs)) + for _, config := range configs { + entry := map[string]any{ + "name": config.Name, "domain": config.Domain, "port": config.Port, + "expire_ts": int64(0), "expire_days": 0, "mismatch": false, + } + if state := a.certs[certKey(config)]; state != nil { + entry["expire_ts"] = state.ExpireTS + if state.ExpireTS != 0 { + entry["expire_days"] = int((state.ExpireTS - now.Unix()) / 86400) + } + entry["mismatch"] = state.Mismatch + if state.LastError != "" { + entry["error"] = state.LastError + } + } + result = append(result, entry) + } + return result +} diff --git a/server/ssl_test.go b/server/ssl_test.go new file mode 100644 index 0000000..fc65fc3 --- /dev/null +++ b/server/ssl_test.go @@ -0,0 +1,74 @@ +package main + +import ( + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "sync/atomic" + "testing" + "time" +) + +func TestCertificateCheckAndSnapshot(t *testing.T) { + server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(204) })) + defer server.Close() + parsed, err := url.Parse(server.URL) + if err != nil { + t.Fatal(err) + } + port, _ := strconv.Atoi(parsed.Port()) + config := SSLCertConfig{Name: "local", Domain: server.URL, Port: port, Interval: 1} + expireTS, _, err := checkCertificate(config) + if err != nil { + t.Fatal(err) + } + if expireTS <= time.Now().Unix() { + t.Fatalf("unexpected expiration %d", expireTS) + } + + doc := minimalTestConfig() + doc["sslcerts"] = []any{map[string]any{"name": config.Name, "domain": config.Domain, "port": config.Port, "interval": 1}} + app := newTestApp(t, doc) + app.runDueSSLChecks() + eventually(t, 2*time.Second, func() bool { + app.certMu.RLock() + defer app.certMu.RUnlock() + state := app.certs[certKey(config)] + return state != nil && !state.LastCheck.IsZero() && state.ExpireTS > 0 + }) + certs := app.SnapshotStats()["sslcerts"].([]any) + if certs[0].(map[string]any)["expire_ts"].(int64) <= time.Now().Unix() { + t.Fatalf("certificate snapshot: %#v", certs[0]) + } +} + +func TestCallbackDelivery(t *testing.T) { + var calls atomic.Int32 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { + calls.Add(1) + if request.Method != http.MethodPost || request.URL.Query().Get("message") == "" { + t.Errorf("unexpected callback request: %s %s", request.Method, request.URL.String()) + } + w.WriteHeader(204) + })) + defer server.Close() + doc := minimalTestConfig() + doc["watchdog"] = []any{map[string]any{ + "name": "cpu", "rule": "cpu>90", "interval": 60, "callback": server.URL + "?message=", + }} + app := newTestApp(t, doc) + app.nodeMu.Lock() + node := app.nodes["s01"] + node.Connected = true + node.Stats = AgentStats{CPU: 99} + node.HasUpdate = true + app.nodeMu.Unlock() + app.evaluateWatchdogs("s01", false) + eventually(t, time.Second, func() bool { return calls.Load() == 1 }) + app.evaluateWatchdogs("s01", false) + time.Sleep(30 * time.Millisecond) + if calls.Load() != 1 { + t.Fatalf("watchdog cooldown failed: calls=%d", calls.Load()) + } +} diff --git a/server/tcp_server.go b/server/tcp_server.go new file mode 100644 index 0000000..9aef664 --- /dev/null +++ b/server/tcp_server.go @@ -0,0 +1,247 @@ +package main + +import ( + "bufio" + "encoding/json" + "errors" + "fmt" + "io" + "net" + "strings" + "time" +) + +type AgentServer struct { + app *App +} + +func NewAgentServer(app *App) *AgentServer { + return &AgentServer{app: app} +} + +func (s *AgentServer) ListenAndServe() error { + listener, err := net.Listen("tcp", s.app.opts.AgentAddr) + if err != nil { + return err + } + s.app.logger.Printf("agent TCP listening on %s", listener.Addr()) + return s.Serve(listener) +} + +func (s *AgentServer) Serve(listener net.Listener) error { + defer listener.Close() + s.app.agentRunning.Store(true) + defer s.app.agentRunning.Store(false) + go func() { + <-s.app.ctx.Done() + _ = listener.Close() + }() + for { + conn, err := listener.Accept() + if err != nil { + if s.app.ctx.Err() != nil || errors.Is(err, net.ErrClosed) { + return nil + } + return err + } + go s.handleConnection(conn) + } +} + +func (s *AgentServer) handleConnection(conn net.Conn) { + defer conn.Close() + if tcpConn, ok := conn.(*net.TCPConn); ok { + _ = tcpConn.SetNoDelay(true) + _ = tcpConn.SetKeepAlive(true) + _ = tcpConn.SetKeepAlivePeriod(10 * time.Second) + } + _ = conn.SetDeadline(time.Now().Add(5 * time.Second)) + if _, err := io.WriteString(conn, "Authentication required:\n"); err != nil { + return + } + + reader := bufio.NewReaderSize(conn, 64*1024) + credentials, err := reader.ReadString('\n') + if err != nil { + return + } + credentials = strings.TrimSpace(credentials) + parts := strings.SplitN(credentials, ":", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + _, _ = io.WriteString(conn, "Wrong username and/or password.\n") + return + } + family := remoteFamily(conn.RemoteAddr()) + connectionID, monitors, apiErr := s.app.connectAgent(parts[0], parts[1], conn, family) + if apiErr != nil { + _, _ = io.WriteString(conn, apiErr.Message+"\n") + return + } + username := parts[0] + defer s.app.disconnectAgent(username, conn, connectionID) + + if _, err := io.WriteString(conn, "Authentication successful. Access granted.\n"); err != nil { + return + } + // Existing Python agents use recv() instead of a line reader during the + // handshake. Keep the auth and metadata packets separate for compatibility. + time.Sleep(20 * time.Millisecond) + var metadata strings.Builder + fmt.Fprintf(&metadata, "You are connecting via: IPv%d\n", family) + for index, monitor := range monitors { + payload := map[string]any{"name": monitor.Name, "host": monitor.Host, "interval": monitor.Interval, "type": monitor.Type, "monitor": index} + data, _ := json.Marshal(payload) + metadata.Write(data) + metadata.WriteByte('\n') + } + if _, err := io.WriteString(conn, metadata.String()); err != nil { + return + } + + _ = conn.SetDeadline(time.Now().Add(20 * time.Second)) + scanner := bufio.NewScanner(reader) + scanner.Buffer(make([]byte, 4096), maxRequestBody) + for scanner.Scan() { + _ = conn.SetDeadline(time.Now().Add(20 * time.Second)) + line := strings.TrimSpace(scanner.Text()) + switch { + case strings.HasPrefix(line, "update"): + body := strings.TrimSpace(strings.TrimPrefix(line, "update")) + var update AgentStats + if err := json.Unmarshal([]byte(body), &update); err != nil { + if s.app.agentPong(username, connectionID) { + _, _ = io.WriteString(conn, "1\n") + } + continue + } + if !s.app.updateAgent(username, connectionID, update) { + return + } + if s.app.agentPong(username, connectionID) { + _, _ = io.WriteString(conn, "0\n") + } + case strings.HasPrefix(line, "pong"): + value := strings.TrimSpace(strings.TrimPrefix(line, "pong")) + s.app.setAgentPong(username, connectionID, value == "1" || strings.EqualFold(value, "on")) + default: + if s.app.agentPong(username, connectionID) { + _, _ = io.WriteString(conn, "1\n") + } + } + } +} + +func remoteFamily(address net.Addr) int { + host, _, err := net.SplitHostPort(address.String()) + if err == nil { + if ip := net.ParseIP(host); ip != nil && ip.To4() == nil { + return 6 + } + } + return 4 +} + +func (a *App) connectAgent(username, password string, conn net.Conn, family int) (uint64, []MonitorConfig, *APIError) { + a.configMu.RLock() + defer a.configMu.RUnlock() + var config *ServerConfig + for index := range a.runtime.Servers { + if a.runtime.Servers[index].Username == username { + server := a.runtime.Servers[index] + config = &server + break + } + } + if config == nil || config.Password != password { + return 0, nil, &APIError{Status: 401, Message: "Wrong username and/or password."} + } + if config.Disabled { + return 0, nil, &APIError{Status: 403, Message: "Server is disabled."} + } + a.nodeMu.Lock() + defer a.nodeMu.Unlock() + node := a.nodes[username] + if node == nil { + return 0, nil, &APIError{Status: 404, Message: "Server is not configured."} + } + if node.Connected { + return 0, nil, &APIError{Status: 409, Message: "Only one connection per user allowed."} + } + id := a.connectionID.Add(1) + node.Connected = true + node.Connection = conn + node.ConnectionID = id + node.Family = family + node.HasUpdate = false + node.Pong = false + node.Online4 = family == 4 + node.Online6 = family == 6 + a.wakeStatsWriter() + return id, append([]MonitorConfig(nil), a.runtime.Monitors...), nil +} + +func (a *App) disconnectAgent(username string, conn net.Conn, connectionID uint64) { + a.nodeMu.Lock() + node := a.nodes[username] + if node == nil || node.ConnectionID != connectionID || node.Connection != conn { + a.nodeMu.Unlock() + return + } + node.Connected = false + node.Connection = nil + node.Online4 = false + node.Online6 = false + node.HasUpdate = false + node.Pong = false + a.nodeMu.Unlock() + a.wakeStatsWriter() + time.AfterFunc(25*time.Second, func() { + if a.ctx.Err() != nil { + return + } + a.nodeMu.RLock() + current := a.nodes[username] + stillOffline := current != nil && !current.Connected && current.ConnectionID == connectionID + a.nodeMu.RUnlock() + if stillOffline { + a.evaluateWatchdogs(username, true) + } + }) +} + +func (a *App) updateAgent(username string, connectionID uint64, update AgentStats) bool { + a.nodeMu.Lock() + node := a.nodes[username] + if node == nil || !node.Connected || node.ConnectionID != connectionID { + a.nodeMu.Unlock() + return false + } + if update.Online4 != nil { + node.Online4 = *update.Online4 + } + if update.Online6 != nil { + node.Online6 = *update.Online6 + } + node.Stats = update + node.HasUpdate = true + node.LastUpdate = time.Now() + a.nodeMu.Unlock() + a.wakeStatsWriter() + a.evaluateWatchdogs(username, false) + return true +} + +func (a *App) setAgentPong(username string, connectionID uint64, enabled bool) { + a.nodeMu.Lock() + defer a.nodeMu.Unlock() + if node := a.nodes[username]; node != nil && node.ConnectionID == connectionID { + node.Pong = enabled + } +} + +func (a *App) agentPong(username string, connectionID uint64) bool { + a.nodeMu.RLock() + defer a.nodeMu.RUnlock() + node := a.nodes[username] + return node != nil && node.ConnectionID == connectionID && node.Pong +} diff --git a/server/tcp_server_test.go b/server/tcp_server_test.go new file mode 100644 index 0000000..ff08f89 --- /dev/null +++ b/server/tcp_server_test.go @@ -0,0 +1,120 @@ +package main + +import ( + "bufio" + "encoding/json" + "fmt" + "net" + "strings" + "testing" + "time" +) + +func TestAgentProtocolAndTrafficState(t *testing.T) { + app := newTestApp(t, minimalTestConfig()) + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + serveDone := make(chan error, 1) + go func() { serveDone <- NewAgentServer(app).Serve(listener) }() + + connection, err := net.DialTimeout("tcp", listener.Addr().String(), time.Second) + if err != nil { + t.Fatal(err) + } + defer connection.Close() + reader := bufio.NewReader(connection) + readContains(t, reader, "Authentication required") + if _, err := fmt.Fprintln(connection, "s01:secret"); err != nil { + t.Fatal(err) + } + readContains(t, reader, "Authentication successful") + readContains(t, reader, "You are connecting via: IPv4") + readContains(t, reader, `"monitor":0`) + + if _, err := fmt.Fprintln(connection, "pong on"); err != nil { + t.Fatal(err) + } + online6 := true + update := AgentStats{ + Uptime: 90061, Load1: 1.25, Load5: 1, Load15: 0.75, CPU: 33.5, CPUCores: 4, CPUModel: "Test CPU", + MemoryTotal: 1024, MemoryUsed: 512, SwapTotal: 128, SwapUsed: 2, HDDTotal: 10000, HDDUsed: 4000, + NetworkRX: 123, NetworkTX: 456, NetworkIn: 1_000_000, NetworkOut: 2_000_000, + Ping10010: 1, Ping189: 2, Ping10086: 3, Time10010: 10, Time189: 20, Time10086: 30, + TCPCount: 10, UDPCount: 2, ProcessCount: 30, ThreadCount: 60, IORead: 1, IOWrite: 2, + OS: "linux", Custom: "example=12", Online6: &online6, + } + payload, _ := json.Marshal(update) + if _, err := fmt.Fprintf(connection, "update %s\n", payload); err != nil { + t.Fatal(err) + } + readContains(t, reader, "0") + + eventually(t, time.Second, func() bool { + servers := app.SnapshotStats()["servers"].([]any) + server := servers[0].(map[string]any) + return server["online4"] == true && server["online6"] == true && server["cpu_model"] == "Test CPU" && server["uptime"] == "1 天" + }) + + result, apiErr := app.ResetTraffic("s01") + if apiErr != nil { + t.Fatal(apiErr) + } + stats := result["stats"].(map[string]any) + if stats["last_network_in"] != int64(1_000_000) { + t.Fatalf("traffic reset result: %#v", stats) + } + + duplicate, err := net.DialTimeout("tcp", listener.Addr().String(), time.Second) + if err != nil { + t.Fatal(err) + } + duplicateReader := bufio.NewReader(duplicate) + readContains(t, duplicateReader, "Authentication required") + _, _ = fmt.Fprintln(duplicate, "s01:secret") + readContains(t, duplicateReader, "Only one connection per user") + _ = duplicate.Close() + + wrong, err := net.DialTimeout("tcp", listener.Addr().String(), time.Second) + if err != nil { + t.Fatal(err) + } + wrongReader := bufio.NewReader(wrong) + readContains(t, wrongReader, "Authentication required") + _, _ = fmt.Fprintln(wrong, "s01:wrong") + readContains(t, wrongReader, "Wrong username") + _ = wrong.Close() + + if apiErr := app.ReloadConfig(); apiErr != nil { + t.Fatal(apiErr) + } + readContains(t, reader, "Server reloading") + eventually(t, time.Second, func() bool { + server := app.SnapshotStats()["servers"].([]any)[0].(map[string]any) + return server["online4"] == false && server["online6"] == false + }) + + app.cancel() + _ = listener.Close() + select { + case err := <-serveDone: + if err != nil { + t.Fatal(err) + } + case <-time.After(time.Second): + t.Fatal("agent server did not stop") + } +} + +func readContains(t *testing.T, reader *bufio.Reader, expected string) string { + t.Helper() + line, err := reader.ReadString('\n') + if err != nil { + t.Fatalf("read %q: %v", expected, err) + } + if !strings.Contains(line, expected) { + t.Fatalf("expected %q in %q", expected, line) + } + return line +} diff --git a/server/test_helpers_test.go b/server/test_helpers_test.go new file mode 100644 index 0000000..64d91f0 --- /dev/null +++ b/server/test_helpers_test.go @@ -0,0 +1,87 @@ +package main + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" + "time" +) + +func minimalTestConfig() ConfigDocument { + return ConfigDocument{ + "servers": []any{ + map[string]any{ + "username": "s01", "name": "node1", "type": "kvm", "host": "host1", + "location": "CN", "password": "secret", "monthstart": 1, + }, + }, + "monitors": []any{ + map[string]any{"name": "example", "host": "https://example.com", "interval": 60, "type": "https"}, + }, + "sslcerts": []any{}, + "watchdog": []any{}, + } +} + +func newTestApp(t *testing.T, doc ConfigDocument) *App { + t.Helper() + directory := t.TempDir() + configPath := filepath.Join(directory, "config.json") + statsPath := filepath.Join(directory, "data", "stats.json") + webDir := filepath.Join(directory, "web") + if err := os.MkdirAll(webDir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(webDir, "index.html"), []byte("test-ui"), 0o644); err != nil { + t.Fatal(err) + } + data, err := json.MarshalIndent(doc, "", " ") + if err != nil { + t.Fatal(err) + } + if err := os.WriteFile(configPath, data, 0o644); err != nil { + t.Fatal(err) + } + app, err := NewApp(Options{ + ConfigPath: configPath, + StatsPath: statsPath, + WebDir: webDir, + HTTPAddr: "127.0.0.1:0", + AgentAddr: "127.0.0.1:0", + AdminToken: "test-token", + }) + if err != nil { + t.Fatal(err) + } + t.Cleanup(app.Close) + return app +} + +func performRequest(handler http.Handler, method, path, body, token string) *httptest.ResponseRecorder { + request := httptest.NewRequest(method, path, strings.NewReader(body)) + if body != "" { + request.Header.Set("Content-Type", "application/json") + } + if token != "" { + request.Header.Set("Authorization", "Bearer "+token) + } + response := httptest.NewRecorder() + handler.ServeHTTP(response, request) + return response +} + +func eventually(t *testing.T, timeout time.Duration, condition func() bool) { + t.Helper() + deadline := time.Now().Add(timeout) + for time.Now().Before(deadline) { + if condition() { + return + } + time.Sleep(10 * time.Millisecond) + } + t.Fatal("condition was not met before timeout") +} diff --git a/server/watchdog.go b/server/watchdog.go new file mode 100644 index 0000000..f20a413 --- /dev/null +++ b/server/watchdog.go @@ -0,0 +1,217 @@ +package main + +import ( + "crypto/tls" + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/expr-lang/expr" +) + +func compileWatchdog(rule WatchdogConfig, index int) (CompiledWatchdog, error) { + normalized := normalizeLegacyExpression(rule.Rule) + program, err := expr.Compile(normalized, expr.Env(WatchdogEnvironment{})) + if err != nil { + return CompiledWatchdog{}, err + } + return CompiledWatchdog{ + WatchdogConfig: rule, + Key: fmt.Sprintf("%d:%s", index, rule.Name), + Normalized: normalized, + Program: program, + }, nil +} + +func normalizeLegacyExpression(input string) string { + var output strings.Builder + var quote rune + runes := []rune(input) + for index := 0; index < len(runes); index++ { + current := runes[index] + if quote != 0 { + output.WriteRune(current) + if current == quote && (index == 0 || runes[index-1] != '\\') { + quote = 0 + } + continue + } + if current == '\'' || current == '"' { + quote = current + output.WriteRune(current) + continue + } + switch current { + case '&': + output.WriteString("&&") + if index+1 < len(runes) && runes[index+1] == '&' { + index++ + } + case '|': + output.WriteString("||") + if index+1 < len(runes) && runes[index+1] == '|' { + index++ + } + case '=': + previousOperator := index > 0 && strings.ContainsRune("!<>=", runes[index-1]) + nextEqual := index+1 < len(runes) && runes[index+1] == '=' + if previousOperator || nextEqual { + output.WriteRune(current) + } else { + output.WriteString("==") + } + default: + output.WriteRune(current) + } + } + return output.String() +} + +func (a *App) evaluateWatchdogs(username string, offline bool) { + runtime := a.RuntimeSnapshot() + now := time.Now() + type pendingAlert struct { + rule WatchdogConfig + node ServerConfig + } + pending := make([]pendingAlert, 0) + + a.nodeMu.Lock() + node := a.nodes[username] + if node == nil || (!offline && !node.Connected) || (offline && node.Connected) { + a.nodeMu.Unlock() + return + } + stats := node.Stats + if offline { + stats = AgentStats{} + } + environment := watchdogEnvironment(node.Config, stats, node.Online4, node.Online6, node.LastNetworkIn, node.LastNetworkOut) + for _, rule := range runtime.Watchdogs { + result, err := expr.Run(rule.Program, environment) + if err != nil || !expressionTruthy(result) { + continue + } + if last := node.AlarmLast[rule.Key]; !last.IsZero() && now.Sub(last) < secondsDuration(rule.Interval) { + continue + } + node.AlarmLast[rule.Key] = now + if rule.Callback != "" { + pending = append(pending, pendingAlert{rule: rule.WatchdogConfig, node: node.Config}) + } + } + a.nodeMu.Unlock() + + for _, alert := range pending { + alert := alert + go func() { + message := fmt.Sprintf("【告警名称】 %s \n\n【告警时间】 %s \n\n【用户名】 %s \n\n【节点名】 %s \n\n【虚拟化】 %s \n\n【主机名】 %s \n\n【位 置】 %s", + alert.rule.Name, now.Format("2006-01-02 15:04:05"), alert.node.Username, alert.node.Name, alert.node.Type, alert.node.Host, alert.node.Location) + if err := a.sendCallback(alert.rule.Callback, message, "ServerStatus"); err != nil { + a.logger.Printf("watchdog %q callback: %v", alert.rule.Name, err) + } + }() + } +} + +type WatchdogEnvironment struct { + Username string `expr:"username"` + Name string `expr:"name"` + NodeType string `expr:"type"` + Host string `expr:"host"` + Location string `expr:"location"` + Load1 float64 `expr:"load_1"` + Load5 float64 `expr:"load_5"` + Load15 float64 `expr:"load_15"` + Ping10010 float64 `expr:"ping_10010"` + Ping189 float64 `expr:"ping_189"` + Ping10086 float64 `expr:"ping_10086"` + Time10010 float64 `expr:"time_10010"` + Time189 float64 `expr:"time_189"` + Time10086 float64 `expr:"time_10086"` + TCPCount float64 `expr:"tcp_count"` + UDPCount float64 `expr:"udp_count"` + ProcessCount float64 `expr:"process_count"` + ThreadCount float64 `expr:"thread_count"` + NetworkRX float64 `expr:"network_rx"` + NetworkTX float64 `expr:"network_tx"` + NetworkIn float64 `expr:"network_in"` + NetworkOut float64 `expr:"network_out"` + LastNetworkIn float64 `expr:"last_network_in"` + LastNetworkOut float64 `expr:"last_network_out"` + MemoryTotal float64 `expr:"memory_total"` + MemoryUsed float64 `expr:"memory_used"` + SwapTotal float64 `expr:"swap_total"` + SwapUsed float64 `expr:"swap_used"` + HDDTotal float64 `expr:"hdd_total"` + HDDUsed float64 `expr:"hdd_used"` + IORead float64 `expr:"io_read"` + IOWrite float64 `expr:"io_write"` + CPU float64 `expr:"cpu"` + Online4 float64 `expr:"online4"` + Online6 float64 `expr:"online6"` +} + +func watchdogEnvironment(config ServerConfig, stats AgentStats, online4, online6 bool, lastNetworkIn, lastNetworkOut int64) WatchdogEnvironment { + boolNumber := func(value bool) float64 { + if value { + return 1 + } + return 0 + } + return WatchdogEnvironment{ + Username: config.Username, Name: config.Name, NodeType: config.Type, Host: config.Host, Location: config.Location, + Load1: stats.Load1, Load5: stats.Load5, Load15: stats.Load15, + Ping10010: stats.Ping10010, Ping189: stats.Ping189, Ping10086: stats.Ping10086, + Time10010: float64(stats.Time10010), Time189: float64(stats.Time189), Time10086: float64(stats.Time10086), + TCPCount: float64(stats.TCPCount), UDPCount: float64(stats.UDPCount), + ProcessCount: float64(stats.ProcessCount), ThreadCount: float64(stats.ThreadCount), + NetworkRX: float64(stats.NetworkRX), NetworkTX: float64(stats.NetworkTX), + NetworkIn: float64(stats.NetworkIn), NetworkOut: float64(stats.NetworkOut), + LastNetworkIn: float64(lastNetworkIn), LastNetworkOut: float64(lastNetworkOut), + MemoryTotal: float64(stats.MemoryTotal), MemoryUsed: float64(stats.MemoryUsed), + SwapTotal: float64(stats.SwapTotal), SwapUsed: float64(stats.SwapUsed), + HDDTotal: float64(stats.HDDTotal), HDDUsed: float64(stats.HDDUsed), + IORead: float64(stats.IORead), IOWrite: float64(stats.IOWrite), CPU: stats.CPU, + Online4: boolNumber(online4), Online6: boolNumber(online6), + } +} + +func expressionTruthy(result any) bool { + switch value := result.(type) { + case bool: + return value + case int: + return value != 0 + case int64: + return value != 0 + case float64: + return value != 0 + case string: + parsed, _ := strconv.ParseBool(value) + return parsed + default: + return false + } +} + +func (a *App) sendCallback(baseURL, message, signature string) error { + requestURL := baseURL + url.QueryEscape(message) + transport := http.DefaultTransport.(*http.Transport).Clone() + if a.opts.InsecureCallbackTLS { + transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint:gosec -- explicit compatibility option + } + client := &http.Client{Timeout: 6 * time.Second, Transport: transport} + response, err := client.Post(requestURL, "application/x-www-form-urlencoded", strings.NewReader("signature="+url.QueryEscape(signature))) + if err != nil { + return err + } + defer response.Body.Close() + if response.StatusCode < 200 || response.StatusCode >= 300 { + return fmt.Errorf("HTTP %s", response.Status) + } + return nil +} diff --git a/service/status-server.service b/service/status-server.service index 64d48ae..a2ec2ed 100644 --- a/service/status-server.service +++ b/service/status-server.service @@ -1,9 +1,20 @@ -[Unit] -Description=ServerStatus-Server -After=network.target -[Service] -ExecStart=/usr/local/ServerStatus/server/sergate --config=/usr/local/ServerStatus/server/config.json --web-dir=/usr/local/ServerStatus/web -ExecReload=/bin/kill -HUP $MAINPID -Restart=on-failure -[Install] -WantedBy=multi-user.target +[Unit] +Description=ServerStatus Go Server +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +WorkingDirectory=/usr/local/ServerStatus/server +EnvironmentFile=-/usr/local/ServerStatus/server/config.conf +ExecStart=/usr/local/ServerStatus/server/serverstatus --config=/usr/local/ServerStatus/server/config.json --web-dir=/usr/local/ServerStatus/web +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=2 +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=full +ReadWritePaths=/usr/local/ServerStatus/server /usr/local/ServerStatus/web/json + +[Install] +WantedBy=multi-user.target diff --git a/status.sh b/status.sh index ba64046..55c3ebf 100644 --- a/status.sh +++ b/status.sh @@ -2,7 +2,7 @@ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH -sh_ver="1.0.0" +sh_ver="2.0.0" filepath=$( cd "$(dirname "$0")" || exit @@ -49,7 +49,7 @@ check_sys() { } check_installed_server_status() { - [[ ! -e "${server_file}/sergate" ]] && echo -e "${Error} $NAME 服务端没有安装,请检查 !" && exit 1 + [[ ! -x "${server_file}/serverstatus" ]] && echo -e "${Error} $NAME Go 服务端没有安装,请检查 !" && exit 1 } check_installed_client_status() { @@ -58,27 +58,24 @@ check_installed_client_status() { Download_Server_Status_server() { cd "/tmp" || exit 1 + rm -rf "/tmp/ServerStatus-master" "/tmp/master.zip" wget -N --no-check-certificate https://github.com/cppla/ServerStatus/archive/refs/heads/master.zip - [[ ! -e "master.zip" ]] && echo -e "${Error} ServerStatus 服务端下载失败 !" && exit 1 + [[ ! -e "master.zip" ]] && echo -e "${Error} ServerStatus 服务端下载失败 !" && exit 1 unzip master.zip rm -rf master.zip [[ ! -d "/tmp/ServerStatus-master" ]] && echo -e "${Error} ServerStatus 服务端解压失败 !" && exit 1 cd "/tmp/ServerStatus-master/server" || exit 1 - make - [[ ! -e "sergate" ]] && echo -e "${Error} ServerStatus 服务端编译失败 !" && cd "${file_1}" && rm -rf "/tmp//ServerStatus-master" && exit 1 + go build -trimpath -ldflags="-s -w -X main.version=${sh_ver}" -o /tmp/serverstatus . + [[ ! -x "/tmp/serverstatus" ]] && echo -e "${Error} ServerStatus Go 服务端编译失败,请确认 Go 版本满足 go.mod !" && cd "${file_1}" && rm -rf "/tmp/ServerStatus-master" && exit 1 cd "${file_1}" || exit 1 - mkdir -p "${server_file}" - mv "/tmp/ServerStatus-master/server" "${file}" - mv "/tmp/ServerStatus-master/web" "${file}" - mv "/tmp/ServerStatus-master/plugin" "${file}" + mkdir -p "${server_file}" "${web_file}/json" "${plugin_file}" + install -m 0755 /tmp/serverstatus "${server_file}/serverstatus" + [[ ! -e "${server_conf}" ]] && install -m 0644 "/tmp/ServerStatus-master/server/config.json" "${server_conf}" + cp -a "/tmp/ServerStatus-master/web/." "${web_file}/" + cp -a "/tmp/ServerStatus-master/plugin/." "${plugin_file}/" + rm -f /tmp/serverstatus rm -rf "/tmp/ServerStatus-master" - if [[ ! -e "${server_file}/sergate" ]]; then - echo -e "${Error} ServerStatus 服务端移动重命名失败 !" - [[ -e "${server_file}/sergate1" ]] && mv "${server_file}/sergate1" "${server_file}/sergate" - exit 1 - else - [[ -e "${server_file}/sergate1" ]] && rm -rf "${server_file}/sergate1" - fi + [[ ! -x "${server_file}/serverstatus" ]] && echo -e "${Error} ServerStatus Go 服务端安装失败 !" && exit 1 } Download_Server_Status_client() { @@ -113,18 +110,27 @@ Installation_dependency() { if [[ ${release} == "centos" ]]; then yum makecache yum -y install unzip - yum -y install python3 >/dev/null 2>&1 || yum -y install python - [[ ${mode} == "server" ]] && yum -y groupinstall "Development Tools" + if [[ ${mode} == "server" ]]; then + yum -y install golang + else + yum -y install python3 >/dev/null 2>&1 || yum -y install python + fi elif [[ ${release} == "debian" ]]; then apt -y update apt -y install unzip - apt -y install python3 >/dev/null 2>&1 || apt -y install python - [[ ${mode} == "server" ]] && apt -y install build-essential + if [[ ${mode} == "server" ]]; then + apt -y install golang-go + else + apt -y install python3 >/dev/null 2>&1 || apt -y install python + fi elif [[ ${release} == "archlinux" ]]; then - pacman -Sy python python-pip unzip --noconfirm - [[ ${mode} == "server" ]] && pacman -Sy base-devel --noconfirm + if [[ ${mode} == "server" ]]; then + pacman -Sy go unzip --noconfirm + else + pacman -Sy python python-pip unzip --noconfirm + fi fi - [[ ! -e /usr/bin/python ]] && ln -s /usr/bin/python3 /usr/bin/python + [[ ${mode} == "client" && ! -e /usr/bin/python ]] && ln -s /usr/bin/python3 /usr/bin/python } Write_server_config() { @@ -147,7 +153,9 @@ EOF Write_server_config_conf() { cat >${server_conf_1} <<-EOF -PORT = ${server_port_s} +AGENT_ADDR=:${server_port_s} +HTTP_ADDR=:${server_http_port_s} +ADMIN_TOKEN=${admin_token_s} EOF } @@ -162,10 +170,19 @@ Read_config_client() { Read_config_server() { if [[ ! -e "${server_conf_1}" ]]; then server_port_s="35601" + server_http_port_s="8080" + admin_token_s="" Write_server_config_conf server_port="35601" + server_http_port="8080" else - server_port="$(grep "PORT = " ${server_conf_1} | awk '{print $3}')" + agent_addr="$(grep '^AGENT_ADDR=' "${server_conf_1}" | head -1 | cut -d= -f2-)" + http_addr="$(grep '^HTTP_ADDR=' "${server_conf_1}" | head -1 | cut -d= -f2-)" + admin_token_s="$(grep '^ADMIN_TOKEN=' "${server_conf_1}" | head -1 | cut -d= -f2-)" + server_port="${agent_addr##*:}" + server_http_port="${http_addr##*:}" + server_port_s="${server_port:-35601}" + server_http_port_s="${server_http_port:-8080}" fi } @@ -191,8 +208,8 @@ Set_server() { Set_server_http_port() { while true; do echo -e "请输入 $NAME 服务端中网站要设置的 域名/IP的端口[1-65535](如果是域名的话,一般用 80 端口)" - read -erp "(默认: 8888):" server_http_port_s - [[ -z "$server_http_port_s" ]] && server_http_port_s="8888" + read -erp "(默认: 8080):" server_http_port_s + [[ -z "$server_http_port_s" ]] && server_http_port_s="8080" if [[ "$server_http_port_s" =~ ^[0-9]*$ ]]; then if [[ ${server_http_port_s} -ge 1 ]] && [[ ${server_http_port_s} -le 65535 ]]; then echo && echo " ================================================" @@ -623,54 +640,16 @@ Install_jq() { fi } -Install_caddy() { - echo - echo -e "${Info} 是否由脚本自动配置HTTP服务(服务端的在线监控网站),如果选择 N,则请在其他HTTP服务中配置网站根目录为:${Green_font_prefix}${web_file}${Font_color_suffix} [Y/n]" - read -erp "(默认: Y 自动部署):" caddy_yn - [[ -z "$caddy_yn" ]] && caddy_yn="y" - if [[ "${caddy_yn}" == [Yy] ]]; then - caddy_file="/etc/caddy/Caddyfile" # Where is the default Caddyfile specified in Archlinux? - [[ ! -e /usr/bin/caddy ]] && { - if [[ ${release} == "debian" ]]; then - apt install -y debian-keyring debian-archive-keyring apt-transport-https curl - curl -1sLf "https://dl.cloudsmith.io/public/caddy/stable/gpg.key" | tee /etc/apt/trusted.gpg.d/caddy-stable.asc - curl -1sLf "https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt" | tee /etc/apt/sources.list.d/caddy-stable.list - apt update && apt install caddy - elif [[ ${release} == "centos" ]]; then - yum install yum-plugin-copr -y - yum copr enable @caddy/caddy -y - yum install caddy -y - elif [[ ${release} == "archlinux" ]]; then - pacman -Sy caddy --noconfirm - fi - [[ ! -e "/usr/bin/caddy" ]] && echo -e "${Error} Caddy安装失败,请手动部署,Web网页文件位置:${web_file}" && exit 1 - systemctl enable caddy - echo "" >${caddy_file} - } - Set_server "server" - Set_server_http_port - cat >>${caddy_file} <<-EOF -http://${server_s}:${server_http_port_s} { - root * ${web_file} - encode gzip - file_server -} -EOF - systemctl restart caddy - else - echo -e "${Info} 跳过 HTTP服务部署,请手动部署,Web网页文件位置:${web_file} ,如果位置改变,请注意修改服务脚本文件 /etc/init.d/status-server 中的 WEB_BIN 变量 !" - fi -} - Install_ServerStatus_server() { - [[ -e "${server_file}/sergate" ]] && echo -e "${Error} 检测到 $NAME 服务端已安装 !" && exit 1 + [[ -x "${server_file}/serverstatus" ]] && echo -e "${Error} 检测到 $NAME 服务端已安装 !" && exit 1 Set_server_port + Set_server_http_port + admin_token_s="$(LC_ALL=C tr -dc 'A-Za-z0-9' /dev/null || true Download_Server_Status_server - rm -rf /etc/init.d/status-server + rm -f "${service}/status-server.service" Service_Server_Status_server Start_ServerStatus_server } @@ -723,12 +705,12 @@ Update_ServerStatus_client() { } Start_ServerStatus_server() { - port="$(grep "m_Port = " ${server_file}/src/main.cpp | awk '{print $3}' | sed '{s/;$//}')" check_installed_server_status + Read_config_server systemctl -q is-active status-server && echo -e "${Error} $NAME 正在运行,请检查 !" && exit 1 systemctl start status-server if (systemctl -q is-active status-server) then - echo -e "${Info} $NAME 服务端启动成功[监听端口:${port}] !" + echo -e "${Info} $NAME Go 服务端启动成功[Agent:${server_port},Web:${server_http_port}] !" else echo -e "${Error} $NAME 服务端启动失败 !" fi @@ -777,13 +759,6 @@ Uninstall_ServerStatus_server() { else rm -rf "${file}" fi - if [[ -e "/usr/bin/caddy" ]]; then - systemctl stop caddy - systemctl disable caddy - [[ ${release} == "debian" ]] && apt purge -y caddy - [[ ${release} == "centos" ]] && yum -y remove caddy - [[ ${release} == "archlinux" ]] && pacman -R caddy --noconfirm - fi systemctl daemon-reload systemctl reset-failed echo && echo "ServerStatus 卸载完成 !" && echo @@ -977,7 +952,7 @@ menu_server() { ${Green_font_prefix} 9.${Font_color_suffix} 查看 服务端日志 ———————————— ${Green_font_prefix}10.${Font_color_suffix} 切换为 客户端菜单" && echo - if [[ -e "${server_file}/sergate" ]]; then + if [[ -x "${server_file}/serverstatus" ]]; then if (systemctl -q is-active status-server) then echo -e " 当前状态: 服务端 ${Green_font_prefix}已安装${Font_color_suffix} 并 ${Green_font_prefix}已启动${Font_color_suffix}" else diff --git a/web/index.html b/web/index.html index 7950bbe..f51e2bd 100644 --- a/web/index.html +++ b/web/index.html @@ -6,7 +6,7 @@ 云监控 - +
@@ -170,7 +170,7 @@

新增节点

-

保存后会写入 config.json,并向 sergate 发送 SIGHUP 重载。

+

保存后会写入 config.json,并由 Go 服务热重载。

@@ -200,6 +200,6 @@ ServerStatus中文版 - + diff --git a/web/js/app.js b/web/js/app.js index 5251169..2f58658 100644 --- a/web/js/app.js +++ b/web/js/app.js @@ -328,8 +328,8 @@ function renderOverview(){ $('overviewCards').innerHTML = [ card('在线主机', `${online}/${total}`, '当前在线节点', online === total ? 'ok' : 'warn'), card('证书风险', sslWarn, sslWarn ? '过期或域名不匹配' : '证书正常', sslWarn ? 'warn' : 'ok'), - card('本月下行', humanMinMBFromB(monthDown), '下载累计', 'traffic-down'), card('本月上行', humanMinMBFromB(monthUp), '上传累计', 'traffic-up'), + card('本月下行', humanMinMBFromB(monthDown), '下载累计', 'traffic-down'), card('活跃告警', alerts.total, `离线 ${alerts.offline} / 异常 ${alerts.abnormal} / 被墙 ${alerts.blocked}`, alerts.total ? (alerts.offline || alerts.blocked ? 'err' : 'warn') : 'ok') ].join(''); } @@ -812,7 +812,7 @@ const CONFIG_TYPES = { label: '节点', addLabel: '新增节点', empty: '暂无节点配置', - hint: '客户端登录使用 username/password,保存后自动重载 sergate。', + hint: '客户端登录使用 username/password,保存后 Go 服务会热重载并让客户端自动重连。', fields: [ { name:'username', label:'用户名', required:true, max:120 }, { name:'name', label:'节点名', required:true, max:120 }, @@ -1041,8 +1041,8 @@ function bindAdmin(){ catch(err){ setAdminStatus('重载失败:' + err.message, 'err'); } }); $('adminRestart').addEventListener('click', async () => { - if(!confirm('重启 sergate 采集服务?客户端会短暂断开后自动重连。')) return; - try{ await api('/api/restart', { method:'POST' }); setAdminStatus('服务重启已触发,等待容器入口脚本拉起 sergate。', 'ok'); } + if(!confirm('重启采集运行时?客户端会短暂断开后自动重连。')) return; + try{ await api('/api/restart', { method:'POST' }); setAdminStatus('采集运行时已在进程内重启,客户端正在自动重连。', 'ok'); } catch(err){ setAdminStatus('重启失败:' + err.message, 'err'); } }); $('configForm').addEventListener('submit', async e => {