add files

This commit is contained in:
烨玮
2025-02-20 12:17:03 +08:00
parent a21dd4555c
commit edd008441b
667 changed files with 473123 additions and 0 deletions

View File

View File

@@ -0,0 +1,85 @@
# Copyright 2018 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# cmake build file for C++ paraformer example.
# Assumes protobuf and gRPC have been installed using cmake.
# See cmake_externalproject/CMakeLists.txt for all-in-one cmake build
# that automatically builds all the dependencies before building paraformer.
cmake_minimum_required(VERSION 3.10)
project(ASR C CXX)
include(common.cmake)
# Proto file
get_filename_component(rg_proto "../python/grpc/proto/paraformer.proto" ABSOLUTE)
get_filename_component(rg_proto_path "${rg_proto}" PATH)
# Generated sources
set(rg_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/paraformer.pb.cc")
set(rg_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/paraformer.pb.h")
set(rg_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/paraformer.grpc.pb.cc")
set(rg_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/paraformer.grpc.pb.h")
add_custom_command(
OUTPUT "${rg_proto_srcs}" "${rg_proto_hdrs}" "${rg_grpc_srcs}" "${rg_grpc_hdrs}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}"
--cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
-I "${rg_proto_path}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
"${rg_proto}"
DEPENDS "${rg_proto}")
# Include generated *.pb.h files
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
link_directories(${ONNXRUNTIME_DIR}/lib)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/include/)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/yaml-cpp/include/)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/kaldi-native-fbank)
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/yaml-cpp yaml-cpp)
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/kaldi-native-fbank/kaldi-native-fbank/csrc csrc)
add_subdirectory("../onnxruntime/src" onnx_src)
include_directories(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/glog)
set(BUILD_TESTING OFF)
add_subdirectory(${PROJECT_SOURCE_DIR}/../onnxruntime/third_party/glog glog)
# rg_grpc_proto
add_library(rg_grpc_proto
${rg_grpc_srcs}
${rg_grpc_hdrs}
${rg_proto_srcs}
${rg_proto_hdrs})
target_link_libraries(rg_grpc_proto
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF})
foreach(_target
paraformer-server)
add_executable(${_target}
"${_target}.cc")
target_link_libraries(${_target}
rg_grpc_proto
funasr
${EXTRA_LIBS}
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF})
endforeach()

View File

@@ -0,0 +1,210 @@
# Service with grpc-cpp
## For the Server
### Build [onnxruntime](./onnxruntime_cpp.md) as it's document
### Compile and install grpc v1.52.0 in case of grpc bugs
```
export GRPC_INSTALL_DIR=/data/soft/grpc
export PKG_CONFIG_PATH=$GRPC_INSTALL_DIR/lib/pkgconfig
git clone -b v1.52.0 --depth=1 https://github.com/grpc/grpc.git
cd grpc
git submodule update --init --recursive
mkdir -p cmake/build
pushd cmake/build
cmake -DgRPC_INSTALL=ON \
-DgRPC_BUILD_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=$GRPC_INSTALL_DIR \
../..
make
make install
popd
echo "export GRPC_INSTALL_DIR=/data/soft/grpc" >> ~/.bashrc
echo "export PKG_CONFIG_PATH=\$GRPC_INSTALL_DIR/lib/pkgconfig" >> ~/.bashrc
echo "export PATH=\$GRPC_INSTALL_DIR/bin/:\$PKG_CONFIG_PATH:\$PATH" >> ~/.bashrc
source ~/.bashrc
```
### Compile and start grpc onnx paraformer server
```
# set -DONNXRUNTIME_DIR=/path/to/asrmodel/onnxruntime-linux-x64-1.14.0
./rebuild.sh
```
### Start grpc paraformer server
```
./cmake/build/paraformer-server --port-id <string> [--punc-config
<string>] [--punc-model <string>]
--am-config <string> --am-cmvn <string>
--am-model <string> [--vad-config
<string>] [--vad-cmvn <string>]
[--vad-model <string>] [--] [--version]
[-h]
Where:
--port-id <string>
(required) port id
--am-config <string>
(required) am config path
--am-cmvn <string>
(required) am cmvn path
--am-model <string>
(required) am model path
--punc-config <string>
punc config path
--punc-model <string>
punc model path
--vad-config <string>
vad config path
--vad-cmvn <string>
vad cmvn path
--vad-model <string>
vad model path
Required: --port-id <string> --am-config <string> --am-cmvn <string> --am-model <string>
If use vad, please add: [--vad-config <string>] [--vad-cmvn <string>] [--vad-model <string>]
If use punc, please add: [--punc-config <string>] [--punc-model <string>]
```
## For the client
### Install the requirements as in [grpc-python](./docs/grpc_python.md)
```shell
git clone https://github.com/alibaba/FunASR.git && cd FunASR
cd funasr/runtime/python/grpc
pip install -r requirements_client.txt
```
### Generate protobuf file
Run on server, the two generated pb files are both used for server and client
```shell
# paraformer_pb2.py and paraformer_pb2_grpc.py are already generated,
# regenerate it only when you make changes to ./proto/paraformer.proto file.
python -m grpc_tools.protoc --proto_path=./proto -I ./proto --python_out=. --grpc_python_out=./ ./proto/paraformer.proto
```
### Start grpc client
```
# Start client.
python grpc_main_client_mic.py --host 127.0.0.1 --port 10095
```
[//]: # (```)
[//]: # (# go to ../python/grpc to find this package)
[//]: # (import paraformer_pb2)
[//]: # ()
[//]: # ()
[//]: # (class RecognizeStub:)
[//]: # ( def __init__&#40;self, channel&#41;:)
[//]: # ( self.Recognize = channel.stream_stream&#40;)
[//]: # ( '/paraformer.ASR/Recognize',)
[//]: # ( request_serializer=paraformer_pb2.Request.SerializeToString,)
[//]: # ( response_deserializer=paraformer_pb2.Response.FromString,)
[//]: # ( &#41;)
[//]: # ()
[//]: # ()
[//]: # (async def send&#40;channel, data, speaking, isEnd&#41;:)
[//]: # ( stub = RecognizeStub&#40;channel&#41;)
[//]: # ( req = paraformer_pb2.Request&#40;&#41;)
[//]: # ( if data:)
[//]: # ( req.audio_data = data)
[//]: # ( req.user = 'zz')
[//]: # ( req.language = 'zh-CN')
[//]: # ( req.speaking = speaking)
[//]: # ( req.isEnd = isEnd)
[//]: # ( q = queue.SimpleQueue&#40;&#41;)
[//]: # ( q.put&#40;req&#41;)
[//]: # ( return stub.Recognize&#40;iter&#40;q.get, None&#41;&#41;)
[//]: # ()
[//]: # (# send the audio data once)
[//]: # (async def grpc_rec&#40;data, grpc_uri&#41;:)
[//]: # ( with grpc.insecure_channel&#40;grpc_uri&#41; as channel:)
[//]: # ( b = time.time&#40;&#41;)
[//]: # ( response = await send&#40;channel, data, False, False&#41;)
[//]: # ( resp = response.next&#40;&#41;)
[//]: # ( text = '')
[//]: # ( if 'decoding' == resp.action:)
[//]: # ( resp = response.next&#40;&#41;)
[//]: # ( if 'finish' == resp.action:)
[//]: # ( text = json.loads&#40;resp.sentence&#41;['text'])
[//]: # ( response = await send&#40;channel, None, False, True&#41;)
[//]: # ( return {)
[//]: # ( 'text': text,)
[//]: # ( 'time': time.time&#40;&#41; - b,)
[//]: # ( })
[//]: # ()
[//]: # (async def test&#40;&#41;:)
[//]: # ( # fc = FunAsrGrpcClient&#40;'127.0.0.1', 9900&#41;)
[//]: # ( # t = await fc.rec&#40;wav.tobytes&#40;&#41;&#41;)
[//]: # ( # print&#40;t&#41;)
[//]: # ( wav, _ = sf.read&#40;'z-10s.wav', dtype='int16'&#41;)
[//]: # ( uri = '127.0.0.1:9900')
[//]: # ( res = await grpc_rec&#40;wav.tobytes&#40;&#41;, uri&#41;)
[//]: # ( print&#40;res&#41;)
[//]: # ()
[//]: # ()
[//]: # (if __name__ == '__main__':)
[//]: # ( asyncio.run&#40;test&#40;&#41;&#41;)
[//]: # ()
[//]: # (```)
## Acknowledge
1. This project is maintained by [FunASR community](https://github.com/alibaba-damo-academy/FunASR).
2. We acknowledge [DeepScience](https://www.deepscience.cn) for contributing the grpc service.

View File

@@ -0,0 +1,125 @@
# Copyright 2018 gRPC authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# cmake build file for C++ route_guide example.
# Assumes protobuf and gRPC have been installed using cmake.
# See cmake_externalproject/CMakeLists.txt for all-in-one cmake build
# that automatically builds all the dependencies before building route_guide.
cmake_minimum_required(VERSION 3.5.1)
if (NOT DEFINED CMAKE_CXX_STANDARD)
set (CMAKE_CXX_STANDARD 14)
endif()
if(MSVC)
add_definitions(-D_WIN32_WINNT=0x600)
endif()
find_package(Threads REQUIRED)
if(GRPC_AS_SUBMODULE)
# One way to build a projects that uses gRPC is to just include the
# entire gRPC project tree via "add_subdirectory".
# This approach is very simple to use, but the are some potential
# disadvantages:
# * it includes gRPC's CMakeLists.txt directly into your build script
# without and that can make gRPC's internal setting interfere with your
# own build.
# * depending on what's installed on your system, the contents of submodules
# in gRPC's third_party/* might need to be available (and there might be
# additional prerequisites required to build them). Consider using
# the gRPC_*_PROVIDER options to fine-tune the expected behavior.
#
# A more robust approach to add dependency on gRPC is using
# cmake's ExternalProject_Add (see cmake_externalproject/CMakeLists.txt).
# Include the gRPC's cmake build (normally grpc source code would live
# in a git submodule called "third_party/grpc", but this example lives in
# the same repository as gRPC sources, so we just look a few directories up)
add_subdirectory(../../.. ${CMAKE_CURRENT_BINARY_DIR}/grpc EXCLUDE_FROM_ALL)
message(STATUS "Using gRPC via add_subdirectory.")
# After using add_subdirectory, we can now use the grpc targets directly from
# this build.
set(_PROTOBUF_LIBPROTOBUF libprotobuf)
set(_REFLECTION grpc++_reflection)
if(CMAKE_CROSSCOMPILING)
find_program(_PROTOBUF_PROTOC protoc)
else()
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
endif()
set(_GRPC_GRPCPP grpc++)
if(CMAKE_CROSSCOMPILING)
find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
else()
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:grpc_cpp_plugin>)
endif()
elseif(GRPC_FETCHCONTENT)
# Another way is to use CMake's FetchContent module to clone gRPC at
# configure time. This makes gRPC's source code available to your project,
# similar to a git submodule.
message(STATUS "Using gRPC via add_subdirectory (FetchContent).")
include(FetchContent)
FetchContent_Declare(
grpc
GIT_REPOSITORY https://github.com/grpc/grpc.git
# when using gRPC, you will actually set this to an existing tag, such as
# v1.25.0, v1.26.0 etc..
# For the purpose of testing, we override the tag used to the commit
# that's currently under test.
GIT_TAG vGRPC_TAG_VERSION_OF_YOUR_CHOICE)
FetchContent_MakeAvailable(grpc)
# Since FetchContent uses add_subdirectory under the hood, we can use
# the grpc targets directly from this build.
set(_PROTOBUF_LIBPROTOBUF libprotobuf)
set(_REFLECTION grpc++_reflection)
set(_PROTOBUF_PROTOC $<TARGET_FILE:protoc>)
set(_GRPC_GRPCPP grpc++)
if(CMAKE_CROSSCOMPILING)
find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
else()
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:grpc_cpp_plugin>)
endif()
else()
# This branch assumes that gRPC and all its dependencies are already installed
# on this system, so they can be located by find_package().
# Find Protobuf installation
# Looks for protobuf-config.cmake file installed by Protobuf's cmake installation.
set(protobuf_MODULE_COMPATIBLE TRUE)
find_package(Protobuf CONFIG REQUIRED)
message(STATUS "Using protobuf ${Protobuf_VERSION}")
set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
set(_REFLECTION gRPC::grpc++_reflection)
if(CMAKE_CROSSCOMPILING)
find_program(_PROTOBUF_PROTOC protoc)
else()
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
endif()
# Find gRPC installation
# Looks for gRPCConfig.cmake file installed by gRPC's cmake installation.
find_package(gRPC CONFIG REQUIRED)
message(STATUS "Using gRPC ${gRPC_VERSION}")
set(_GRPC_GRPCPP gRPC::grpc++)
if(CMAKE_CROSSCOMPILING)
find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
else()
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
endif()
endif()

View File

@@ -0,0 +1,243 @@
#include <algorithm>
#include <chrono>
#include <cmath>
#include <iostream>
#include <sstream>
#include <memory>
#include <string>
#include <grpc/grpc.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include <grpcpp/server_context.h>
#include <grpcpp/security/server_credentials.h>
#include "paraformer.grpc.pb.h"
#include "paraformer-server.h"
#include "tclap/CmdLine.h"
#include "com-define.h"
#include "glog/logging.h"
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::ServerReader;
using grpc::ServerReaderWriter;
using grpc::ServerWriter;
using grpc::Status;
using paraformer::Request;
using paraformer::Response;
using paraformer::ASR;
ASRServicer::ASRServicer(std::map<std::string, std::string>& model_path) {
AsrHanlde=FunASRInit(model_path, 1);
std::cout << "ASRServicer init" << std::endl;
init_flag = 0;
}
void ASRServicer::clear_states(const std::string& user) {
clear_buffers(user);
clear_transcriptions(user);
}
void ASRServicer::clear_buffers(const std::string& user) {
if (client_buffers.count(user)) {
client_buffers.erase(user);
}
}
void ASRServicer::clear_transcriptions(const std::string& user) {
if (client_transcription.count(user)) {
client_transcription.erase(user);
}
}
void ASRServicer::disconnect(const std::string& user) {
clear_states(user);
std::cout << "Disconnecting user: " << user << std::endl;
}
grpc::Status ASRServicer::Recognize(
grpc::ServerContext* context,
grpc::ServerReaderWriter<Response, Request>* stream) {
Request req;
while (stream->Read(&req)) {
if (req.isend()) {
std::cout << "asr end" << std::endl;
disconnect(req.user());
Response res;
res.set_sentence(
R"({"success": true, "detail": "asr end"})"
);
res.set_user(req.user());
res.set_action("terminate");
res.set_language(req.language());
stream->Write(res);
} else if (req.speaking()) {
if (req.audio_data().size() > 0) {
auto& buf = client_buffers[req.user()];
buf.insert(buf.end(), req.audio_data().begin(), req.audio_data().end());
}
Response res;
res.set_sentence(
R"({"success": true, "detail": "speaking"})"
);
res.set_user(req.user());
res.set_action("speaking");
res.set_language(req.language());
stream->Write(res);
} else if (!req.speaking()) {
if (client_buffers.count(req.user()) == 0 && req.audio_data().size() == 0) {
Response res;
res.set_sentence(
R"({"success": true, "detail": "waiting_for_voice"})"
);
res.set_user(req.user());
res.set_action("waiting");
res.set_language(req.language());
stream->Write(res);
}else {
auto begin_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
if (req.audio_data().size() > 0) {
auto& buf = client_buffers[req.user()];
buf.insert(buf.end(), req.audio_data().begin(), req.audio_data().end());
}
std::string tmp_data = this->client_buffers[req.user()];
this->clear_states(req.user());
Response res;
res.set_sentence(
R"({"success": true, "detail": "decoding data: " + std::to_string(tmp_data.length()) + " bytes"})"
);
int data_len_int = tmp_data.length();
std::string data_len = std::to_string(data_len_int);
std::stringstream ss;
ss << R"({"success": true, "detail": "decoding data: )" << data_len << R"( bytes")" << R"("})";
std::string result = ss.str();
res.set_sentence(result);
res.set_user(req.user());
res.set_action("decoding");
res.set_language(req.language());
stream->Write(res);
if (tmp_data.length() < 800) { //min input_len for asr model
auto end_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
std::string delay_str = std::to_string(end_time - begin_time);
std::cout << "user: " << req.user() << " , delay(ms): " << delay_str << ", error: data_is_not_long_enough" << std::endl;
Response res;
std::stringstream ss;
std::string asr_result = "";
ss << R"({"success": true, "detail": "finish_sentence","server_delay_ms":)" << delay_str << R"(,"text":")" << asr_result << R"("})";
std::string result = ss.str();
res.set_sentence(result);
res.set_user(req.user());
res.set_action("finish");
res.set_language(req.language());
stream->Write(res);
}
else {
FUNASR_RESULT Result= FunASRRecogPCMBuffer(AsrHanlde, tmp_data.c_str(), data_len_int, 16000, RASR_NONE, NULL);
std::string asr_result = ((FUNASR_RECOG_RESULT*)Result)->msg;
auto end_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
std::string delay_str = std::to_string(end_time - begin_time);
std::cout << "user: " << req.user() << " , delay(ms): " << delay_str << ", text: " << asr_result << std::endl;
Response res;
std::stringstream ss;
ss << R"({"success": true, "detail": "finish_sentence","server_delay_ms":)" << delay_str << R"(,"text":")" << asr_result << R"("})";
std::string result = ss.str();
res.set_sentence(result);
res.set_user(req.user());
res.set_action("finish");
res.set_language(req.language());
stream->Write(res);
}
}
}else {
Response res;
res.set_sentence(
R"({"success": false, "detail": "error, no condition matched! Unknown reason."})"
);
res.set_user(req.user());
res.set_action("terminate");
res.set_language(req.language());
stream->Write(res);
}
}
return Status::OK;
}
void RunServer(std::map<std::string, std::string>& model_path) {
std::string port;
try{
port = model_path.at(PORT_ID);
}catch(std::exception const &e){
printf("Error when read port.\n");
exit(0);
}
std::string server_address;
server_address = "0.0.0.0:" + port;
ASRServicer service(model_path);
ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
}
void GetValue(TCLAP::ValueArg<std::string>& value_arg, std::string key, std::map<std::string, std::string>& model_path)
{
if (value_arg.isSet()){
model_path.insert({key, value_arg.getValue()});
LOG(INFO)<< key << " : " << value_arg.getValue();
}
}
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
FLAGS_logtostderr = true;
TCLAP::CmdLine cmd("paraformer-server", ' ', "1.0");
TCLAP::ValueArg<std::string> vad_model("", VAD_MODEL_PATH, "vad model path", false, "", "string");
TCLAP::ValueArg<std::string> vad_cmvn("", VAD_CMVN_PATH, "vad cmvn path", false, "", "string");
TCLAP::ValueArg<std::string> vad_config("", VAD_CONFIG_PATH, "vad config path", false, "", "string");
TCLAP::ValueArg<std::string> am_model("", AM_MODEL_PATH, "am model path", true, "", "string");
TCLAP::ValueArg<std::string> am_cmvn("", AM_CMVN_PATH, "am cmvn path", true, "", "string");
TCLAP::ValueArg<std::string> am_config("", AM_CONFIG_PATH, "am config path", true, "", "string");
TCLAP::ValueArg<std::string> punc_model("", PUNC_MODEL_PATH, "punc model path", false, "", "string");
TCLAP::ValueArg<std::string> punc_config("", PUNC_CONFIG_PATH, "punc config path", false, "", "string");
TCLAP::ValueArg<std::string> port_id("", PORT_ID, "port id", true, "", "string");
cmd.add(vad_model);
cmd.add(vad_cmvn);
cmd.add(vad_config);
cmd.add(am_model);
cmd.add(am_cmvn);
cmd.add(am_config);
cmd.add(punc_model);
cmd.add(punc_config);
cmd.add(port_id);
cmd.parse(argc, argv);
std::map<std::string, std::string> model_path;
GetValue(vad_model, VAD_MODEL_PATH, model_path);
GetValue(vad_cmvn, VAD_CMVN_PATH, model_path);
GetValue(vad_config, VAD_CONFIG_PATH, model_path);
GetValue(am_model, AM_MODEL_PATH, model_path);
GetValue(am_cmvn, AM_CMVN_PATH, model_path);
GetValue(am_config, AM_CONFIG_PATH, model_path);
GetValue(punc_model, PUNC_MODEL_PATH, model_path);
GetValue(punc_config, PUNC_CONFIG_PATH, model_path);
GetValue(port_id, PORT_ID, model_path);
RunServer(model_path);
return 0;
}

View File

@@ -0,0 +1,55 @@
#include <algorithm>
#include <chrono>
#include <cmath>
#include <iostream>
#include <memory>
#include <string>
#include <grpc/grpc.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include <grpcpp/server_context.h>
#include <grpcpp/security/server_credentials.h>
#include <unordered_map>
#include <chrono>
#include "paraformer.grpc.pb.h"
#include "libfunasrapi.h"
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::ServerReader;
using grpc::ServerReaderWriter;
using grpc::ServerWriter;
using grpc::Status;
using paraformer::Request;
using paraformer::Response;
using paraformer::ASR;
typedef struct
{
std::string msg;
float snippet_time;
}FUNASR_RECOG_RESULT;
class ASRServicer final : public ASR::Service {
private:
int init_flag;
std::unordered_map<std::string, std::string> client_buffers;
std::unordered_map<std::string, std::string> client_transcription;
public:
ASRServicer(std::map<std::string, std::string>& model_path);
void clear_states(const std::string& user);
void clear_buffers(const std::string& user);
void clear_transcriptions(const std::string& user);
void disconnect(const std::string& user);
grpc::Status Recognize(grpc::ServerContext* context, grpc::ServerReaderWriter<Response, Request>* stream);
FUNASR_HANDLE AsrHanlde;
};

View File

@@ -0,0 +1,12 @@
#!/bin/bash
rm cmake -rf
mkdir -p cmake/build
cd cmake/build
cmake -DCMAKE_BUILD_TYPE=release ../.. -DONNXRUNTIME_DIR=/data/asrmodel/onnxruntime-linux-x64-1.14.0
make
echo "Build cmake/build/paraformer_server successfully!"

View File

@@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.16)
project(FunASROnnx)
option(ENABLE_GLOG "Whether to build glog" ON)
# set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 14 CACHE STRING "The C++ version to be used.")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
include(TestBigEndian)
test_big_endian(BIG_ENDIAN)
if(BIG_ENDIAN)
message("Big endian system")
else()
message("Little endian system")
endif()
# for onnxruntime
IF(WIN32)
if(CMAKE_CL_64)
link_directories(${ONNXRUNTIME_DIR}\\lib)
else()
add_definitions(-D_WIN_X86)
endif()
ELSE()
link_directories(${ONNXRUNTIME_DIR}/lib)
endif()
include_directories(${PROJECT_SOURCE_DIR}/third_party/kaldi-native-fbank)
include_directories(${PROJECT_SOURCE_DIR}/third_party/yaml-cpp/include)
add_subdirectory(third_party/yaml-cpp)
add_subdirectory(third_party/kaldi-native-fbank/kaldi-native-fbank/csrc)
add_subdirectory(src)
if(ENABLE_GLOG)
include_directories(${PROJECT_SOURCE_DIR}/third_party/glog)
set(BUILD_TESTING OFF)
add_subdirectory(third_party/glog)
endif()

View File

@@ -0,0 +1,44 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"buildCommandArgs": "",
"ctestCommandArgs": ""
},
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ]
},
{
"name": "Linux-GCC-Debug",
"generator": "Unix Makefiles",
"configurationType": "Debug",
"cmakeExecutable": "cmake",
"remoteCopySourcesExclusionList": [ ".vs", ".git", "out" ],
"cmakeCommandArgs": "-DONNXRUNTIME_DIR=/data/linux/thirdpart/onnxruntime-linux-x64-1.14.1",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "linux_x64" ],
"remoteMachineName": "${defaultRemoteMachineName}",
"remoteCMakeListsRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/src",
"remoteBuildRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/out/build/${name}",
"remoteInstallRoot": "$HOME/.vs/${projectDirName}/${workspaceHash}/out/install/${name}",
"remoteCopySources": true,
"rsyncCommandArgs": "-t --delete",
"remoteCopyBuildOutput": false,
"remoteCopySourcesMethod": "rsync"
}
]
}

View File

@@ -0,0 +1,62 @@
#ifndef AUDIO_H
#define AUDIO_H
#include <queue>
#include <stdint.h>
#include "model.h"
#ifndef WAV_HEADER_SIZE
#define WAV_HEADER_SIZE 44
#endif
using namespace std;
class AudioFrame {
private:
int start;
int end;
int len;
public:
AudioFrame();
AudioFrame(int len);
~AudioFrame();
int SetStart(int val);
int SetEnd(int val);
int GetStart();
int GetLen();
int Disp();
};
class Audio {
private:
float *speech_data;
int16_t *speech_buff;
int speech_len;
int speech_align_len;
int offset;
float align_size;
int data_type;
queue<AudioFrame *> frame_queue;
public:
Audio(int data_type);
Audio(int data_type, int size);
~Audio();
void Disp();
bool LoadWav(const char* filename, int32_t* sampling_rate);
void WavResample(int32_t sampling_rate, const float *waveform, int32_t n);
bool LoadWav(const char* buf, int n_len, int32_t* sampling_rate);
bool LoadPcmwav(const char* buf, int n_file_len, int32_t* sampling_rate);
bool LoadPcmwav(const char* filename, int32_t* sampling_rate);
int FetchChunck(float *&dout, int len);
int Fetch(float *&dout, int &len, int &flag);
void Padding();
void Split(Model* recog_obj);
float GetTimeLen();
int GetQueueSize() { return (int)frame_queue.size(); }
};
#endif

View File

@@ -0,0 +1,63 @@
#ifndef COMDEFINE_H
#define COMDEFINE_H
#define S_BEGIN 0
#define S_MIDDLE 1
#define S_END 2
#define S_ALL 3
#define S_ERR 4
#ifndef MODEL_SAMPLE_RATE
#define MODEL_SAMPLE_RATE 16000
#endif
// model path
#define VAD_MODEL_PATH "vad-model"
#define VAD_CMVN_PATH "vad-cmvn"
#define VAD_CONFIG_PATH "vad-config"
#define AM_MODEL_PATH "am-model"
#define AM_CMVN_PATH "am-cmvn"
#define AM_CONFIG_PATH "am-config"
#define PUNC_MODEL_PATH "punc-model"
#define PUNC_CONFIG_PATH "punc-config"
#define WAV_PATH "wav-path"
#define WAV_SCP "wav-scp"
#define THREAD_NUM "thread-num"
#define PORT_ID "port-id"
// vad
#ifndef VAD_SILENCE_DURATION
#define VAD_SILENCE_DURATION 800
#endif
#ifndef VAD_MAX_LEN
#define VAD_MAX_LEN 15000
#endif
#ifndef VAD_SPEECH_NOISE_THRES
#define VAD_SPEECH_NOISE_THRES 0.9
#endif
#ifndef VAD_LFR_M
#define VAD_LFR_M 5
#endif
#ifndef VAD_LFR_N
#define VAD_LFR_N 1
#endif
// punc
#define UNK_CHAR "<unk>"
#define TOKEN_LEN 20
#define CANDIDATE_NUM 6
#define UNKNOW_INDEX 0
#define NOTPUNC_INDEX 1
#define COMMA_INDEX 2
#define PERIOD_INDEX 3
#define QUESTION_INDEX 4
#define DUN_INDEX 5
#define CACHE_POP_TRIGGER_LIMIT 200
#endif

View File

@@ -0,0 +1,75 @@
#pragma once
#include <map>
#ifdef WIN32
#ifdef _FUNASR_API_EXPORT
#define _FUNASRAPI __declspec(dllexport)
#else
#define _FUNASRAPI __declspec(dllimport)
#endif
#else
#define _FUNASRAPI
#endif
#ifndef _WIN32
#define FUNASR_CALLBCK_PREFIX __attribute__((__stdcall__))
#else
#define FUNASR_CALLBCK_PREFIX __stdcall
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef void* FUNASR_HANDLE;
typedef void* FUNASR_RESULT;
typedef unsigned char FUNASR_BOOL;
#define FUNASR_TRUE 1
#define FUNASR_FALSE 0
#define QM_DEFAULT_THREAD_NUM 4
typedef enum
{
RASR_NONE=-1,
RASRM_CTC_GREEDY_SEARCH=0,
RASRM_CTC_RPEFIX_BEAM_SEARCH = 1,
RASRM_ATTENSION_RESCORING = 2,
}FUNASR_MODE;
typedef enum {
FUNASR_MODEL_PADDLE = 0,
FUNASR_MODEL_PADDLE_2 = 1,
FUNASR_MODEL_K2 = 2,
FUNASR_MODEL_PARAFORMER = 3,
}FUNASR_MODEL_TYPE;
typedef void (* QM_CALLBACK)(int cur_step, int n_total); // n_total: total steps; cur_step: Current Step.
// // ASR
_FUNASRAPI FUNASR_HANDLE FunASRInit(std::map<std::string, std::string>& model_path, int thread_num);
_FUNASRAPI FUNASR_RESULT FunASRRecogBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback);
_FUNASRAPI FUNASR_RESULT FunASRRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback);
_FUNASRAPI FUNASR_RESULT FunASRRecogPCMFile(FUNASR_HANDLE handle, const char* sz_filename, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback);
_FUNASRAPI FUNASR_RESULT FunASRRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback);
_FUNASRAPI const char* FunASRGetResult(FUNASR_RESULT result,int n_index);
_FUNASRAPI const int FunASRGetRetNumber(FUNASR_RESULT result);
_FUNASRAPI void FunASRFreeResult(FUNASR_RESULT result);
_FUNASRAPI void FunASRUninit(FUNASR_HANDLE handle);
_FUNASRAPI const float FunASRGetRetSnippetTime(FUNASR_RESULT result);
// VAD
_FUNASRAPI FUNASR_HANDLE FunVadInit(std::map<std::string, std::string>& model_path, int thread_num);
_FUNASRAPI FUNASR_RESULT FunASRVadBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback);
_FUNASRAPI FUNASR_RESULT FunASRVadPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback);
_FUNASRAPI FUNASR_RESULT FunASRVadPCMFile(FUNASR_HANDLE handle, const char* sz_filename, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback);
_FUNASRAPI FUNASR_RESULT FunASRVadFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,22 @@
#ifndef MODEL_H
#define MODEL_H
#include <string>
#include <map>
class Model {
public:
virtual ~Model(){};
virtual void Reset() = 0;
virtual std::string ForwardChunk(float *din, int len, int flag) = 0;
virtual std::string Forward(float *din, int len, int flag) = 0;
virtual std::string Rescoring() = 0;
virtual std::vector<std::vector<int>> VadSeg(std::vector<float>& pcm_data)=0;
virtual std::string AddPunc(const char* sz_input)=0;
virtual bool UseVad() =0;
virtual bool UsePunc() =0;
};
Model *CreateModel(std::map<std::string, std::string>& model_path,int thread_num=1);
#endif

View File

@@ -0,0 +1,683 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: Arg.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno .
* Copyright (c) 2017 Google Inc.
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_ARGUMENT_H
#define TCLAP_ARGUMENT_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <tclap/sstream.h>
#include <tclap/ArgException.h>
#include <tclap/Visitor.h>
#include <tclap/CmdLineInterface.h>
#include <tclap/ArgTraits.h>
#include <tclap/StandardTraits.h>
namespace TCLAP {
/**
* A virtual base class that defines the essential data for all arguments.
* This class, or one of its existing children, must be subclassed to do
* anything.
*/
class Arg
{
private:
/**
* Prevent accidental copying.
*/
Arg(const Arg& rhs);
/**
* Prevent accidental copying.
*/
Arg& operator=(const Arg& rhs);
/**
* Indicates whether the rest of the arguments should be ignored.
*/
static bool& ignoreRestRef() { static bool ign = false; return ign; }
/**
* The delimiter that separates an argument flag/name from the
* value.
*/
static char& delimiterRef() { static char delim = ' '; return delim; }
protected:
/**
* The single char flag used to identify the argument.
* This value (preceded by a dash {-}), can be used to identify
* an argument on the command line. The _flag can be blank,
* in fact this is how unlabeled args work. Unlabeled args must
* override appropriate functions to get correct handling. Note
* that the _flag does NOT include the dash as part of the flag.
*/
std::string _flag;
/**
* A single word namd identifying the argument.
* This value (preceded by two dashed {--}) can also be used
* to identify an argument on the command line. Note that the
* _name does NOT include the two dashes as part of the _name. The
* _name cannot be blank.
*/
std::string _name;
/**
* Description of the argument.
*/
std::string _description;
/**
* Indicating whether the argument is required.
*/
bool _required;
/**
* Label to be used in usage description. Normally set to
* "required", but can be changed when necessary.
*/
std::string _requireLabel;
/**
* Indicates whether a value is required for the argument.
* Note that the value may be required but the argument/value
* combination may not be, as specified by _required.
*/
bool _valueRequired;
/**
* Indicates whether the argument has been set.
* Indicates that a value on the command line has matched the
* name/flag of this argument and the values have been set accordingly.
*/
bool _alreadySet;
/**
* A pointer to a visitor object.
* The visitor allows special handling to occur as soon as the
* argument is matched. This defaults to NULL and should not
* be used unless absolutely necessary.
*/
Visitor* _visitor;
/**
* Whether this argument can be ignored, if desired.
*/
bool _ignoreable;
/**
* Indicates that the arg was set as part of an XOR and not on the
* command line.
*/
bool _xorSet;
bool _acceptsMultipleValues;
/**
* Performs the special handling described by the Visitor.
*/
void _checkWithVisitor() const;
/**
* Primary constructor. YOU (yes you) should NEVER construct an Arg
* directly, this is a base class that is extended by various children
* that are meant to be used. Use SwitchArg, ValueArg, MultiArg,
* UnlabeledValueArg, or UnlabeledMultiArg instead.
*
* \param flag - The flag identifying the argument.
* \param name - The name identifying the argument.
* \param desc - The description of the argument, used in the usage.
* \param req - Whether the argument is required.
* \param valreq - Whether the a value is required for the argument.
* \param v - The visitor checked by the argument. Defaults to NULL.
*/
Arg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
bool valreq,
Visitor* v = NULL );
public:
/**
* Destructor.
*/
virtual ~Arg();
/**
* Adds this to the specified list of Args.
* \param argList - The list to add this to.
*/
virtual void addToList( std::list<Arg*>& argList ) const;
/**
* Begin ignoring arguments since the "--" argument was specified.
*/
static void beginIgnoring() { ignoreRestRef() = true; }
/**
* Whether to ignore the rest.
*/
static bool ignoreRest() { return ignoreRestRef(); }
/**
* The delimiter that separates an argument flag/name from the
* value.
*/
static char delimiter() { return delimiterRef(); }
/**
* The char used as a place holder when SwitchArgs are combined.
* Currently set to the bell char (ASCII 7).
*/
static char blankChar() { return (char)7; }
/**
* The char that indicates the beginning of a flag. Defaults to '-', but
* clients can define TCLAP_FLAGSTARTCHAR to override.
*/
#ifndef TCLAP_FLAGSTARTCHAR
#define TCLAP_FLAGSTARTCHAR '-'
#endif
static char flagStartChar() { return TCLAP_FLAGSTARTCHAR; }
/**
* The sting that indicates the beginning of a flag. Defaults to "-", but
* clients can define TCLAP_FLAGSTARTSTRING to override. Should be the same
* as TCLAP_FLAGSTARTCHAR.
*/
#ifndef TCLAP_FLAGSTARTSTRING
#define TCLAP_FLAGSTARTSTRING "-"
#endif
static const std::string flagStartString() { return TCLAP_FLAGSTARTSTRING; }
/**
* The sting that indicates the beginning of a name. Defaults to "--", but
* clients can define TCLAP_NAMESTARTSTRING to override.
*/
#ifndef TCLAP_NAMESTARTSTRING
#define TCLAP_NAMESTARTSTRING "--"
#endif
static const std::string nameStartString() { return TCLAP_NAMESTARTSTRING; }
/**
* The name used to identify the ignore rest argument.
*/
static const std::string ignoreNameString() { return "ignore_rest"; }
/**
* Sets the delimiter for all arguments.
* \param c - The character that delimits flags/names from values.
*/
static void setDelimiter( char c ) { delimiterRef() = c; }
/**
* Pure virtual method meant to handle the parsing and value assignment
* of the string on the command line.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. What is
* passed in from main.
*/
virtual bool processArg(int *i, std::vector<std::string>& args) = 0;
/**
* Operator ==.
* Equality operator. Must be virtual to handle unlabeled args.
* \param a - The Arg to be compared to this.
*/
virtual bool operator==(const Arg& a) const;
/**
* Returns the argument flag.
*/
const std::string& getFlag() const;
/**
* Returns the argument name.
*/
const std::string& getName() const;
/**
* Returns the argument description.
*/
std::string getDescription() const;
/**
* Indicates whether the argument is required.
*/
virtual bool isRequired() const;
/**
* Sets _required to true. This is used by the XorHandler.
* You really have no reason to ever use it.
*/
void forceRequired();
/**
* Sets the _alreadySet value to true. This is used by the XorHandler.
* You really have no reason to ever use it.
*/
void xorSet();
/**
* Indicates whether a value must be specified for argument.
*/
bool isValueRequired() const;
/**
* Indicates whether the argument has already been set. Only true
* if the arg has been matched on the command line.
*/
bool isSet() const;
/**
* Indicates whether the argument can be ignored, if desired.
*/
bool isIgnoreable() const;
/**
* A method that tests whether a string matches this argument.
* This is generally called by the processArg() method. This
* method could be re-implemented by a child to change how
* arguments are specified on the command line.
* \param s - The string to be compared to the flag/name to determine
* whether the arg matches.
*/
virtual bool argMatches( const std::string& s ) const;
/**
* Returns a simple string representation of the argument.
* Primarily for debugging.
*/
virtual std::string toString() const;
/**
* Returns a short ID for the usage.
* \param valueId - The value used in the id.
*/
virtual std::string shortID( const std::string& valueId = "val" ) const;
/**
* Returns a long ID for the usage.
* \param valueId - The value used in the id.
*/
virtual std::string longID( const std::string& valueId = "val" ) const;
/**
* Trims a value off of the flag.
* \param flag - The string from which the flag and value will be
* trimmed. Contains the flag once the value has been trimmed.
* \param value - Where the value trimmed from the string will
* be stored.
*/
virtual void trimFlag( std::string& flag, std::string& value ) const;
/**
* Checks whether a given string has blank chars, indicating that
* it is a combined SwitchArg. If so, return true, otherwise return
* false.
* \param s - string to be checked.
*/
bool _hasBlanks( const std::string& s ) const;
/**
* Sets the requireLabel. Used by XorHandler. You shouldn't ever
* use this.
* \param s - Set the requireLabel to this value.
*/
void setRequireLabel( const std::string& s );
/**
* Used for MultiArgs and XorHandler to determine whether args
* can still be set.
*/
virtual bool allowMore();
/**
* Use by output classes to determine whether an Arg accepts
* multiple values.
*/
virtual bool acceptsMultipleValues();
/**
* Clears the Arg object and allows it to be reused by new
* command lines.
*/
virtual void reset();
};
/**
* Typedef of an Arg list iterator.
*/
typedef std::list<Arg*>::const_iterator ArgListIterator;
/**
* Typedef of an Arg vector iterator.
*/
typedef std::vector<Arg*>::const_iterator ArgVectorIterator;
/**
* Typedef of a Visitor list iterator.
*/
typedef std::list<Visitor*>::const_iterator VisitorListIterator;
/*
* Extract a value of type T from it's string representation contained
* in strVal. The ValueLike parameter used to select the correct
* specialization of ExtractValue depending on the value traits of T.
* ValueLike traits use operator>> to assign the value from strVal.
*/
template<typename T> void
ExtractValue(T &destVal, const std::string& strVal, ValueLike vl)
{
static_cast<void>(vl); // Avoid warning about unused vl
istringstream is(strVal.c_str());
int valuesRead = 0;
while ( is.good() ) {
if ( is.peek() != EOF )
#ifdef TCLAP_SETBASE_ZERO
is >> std::setbase(0) >> destVal;
#else
is >> destVal;
#endif
else
break;
valuesRead++;
}
if ( is.fail() )
throw( ArgParseException("Couldn't read argument value "
"from string '" + strVal + "'"));
if ( valuesRead > 1 )
throw( ArgParseException("More than one valid value parsed from "
"string '" + strVal + "'"));
}
/*
* Extract a value of type T from it's string representation contained
* in strVal. The ValueLike parameter used to select the correct
* specialization of ExtractValue depending on the value traits of T.
* StringLike uses assignment (operator=) to assign from strVal.
*/
template<typename T> void
ExtractValue(T &destVal, const std::string& strVal, StringLike sl)
{
static_cast<void>(sl); // Avoid warning about unused sl
SetString(destVal, strVal);
}
//////////////////////////////////////////////////////////////////////
//BEGIN Arg.cpp
//////////////////////////////////////////////////////////////////////
inline Arg::Arg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
bool valreq,
Visitor* v) :
_flag(flag),
_name(name),
_description(desc),
_required(req),
_requireLabel("required"),
_valueRequired(valreq),
_alreadySet(false),
_visitor( v ),
_ignoreable(true),
_xorSet(false),
_acceptsMultipleValues(false)
{
if ( _flag.length() > 1 )
throw(SpecificationException(
"Argument flag can only be one character long", toString() ) );
if ( _name != ignoreNameString() &&
( _flag == Arg::flagStartString() ||
_flag == Arg::nameStartString() ||
_flag == " " ) )
throw(SpecificationException("Argument flag cannot be either '" +
Arg::flagStartString() + "' or '" +
Arg::nameStartString() + "' or a space.",
toString() ) );
if ( ( _name.substr( 0, Arg::flagStartString().length() ) == Arg::flagStartString() ) ||
( _name.substr( 0, Arg::nameStartString().length() ) == Arg::nameStartString() ) ||
( _name.find( " ", 0 ) != std::string::npos ) )
throw(SpecificationException("Argument name begin with either '" +
Arg::flagStartString() + "' or '" +
Arg::nameStartString() + "' or space.",
toString() ) );
}
inline Arg::~Arg() { }
inline std::string Arg::shortID( const std::string& valueId ) const
{
std::string id = "";
if ( _flag != "" )
id = Arg::flagStartString() + _flag;
else
id = Arg::nameStartString() + _name;
if ( _valueRequired )
id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
if ( !_required )
id = "[" + id + "]";
return id;
}
inline std::string Arg::longID( const std::string& valueId ) const
{
std::string id = "";
if ( _flag != "" )
{
id += Arg::flagStartString() + _flag;
if ( _valueRequired )
id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
id += ", ";
}
id += Arg::nameStartString() + _name;
if ( _valueRequired )
id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
return id;
}
inline bool Arg::operator==(const Arg& a) const
{
if ( ( _flag != "" && _flag == a._flag ) || _name == a._name)
return true;
else
return false;
}
inline std::string Arg::getDescription() const
{
std::string desc = "";
if ( _required )
desc = "(" + _requireLabel + ") ";
// if ( _valueRequired )
// desc += "(value required) ";
desc += _description;
return desc;
}
inline const std::string& Arg::getFlag() const { return _flag; }
inline const std::string& Arg::getName() const { return _name; }
inline bool Arg::isRequired() const { return _required; }
inline bool Arg::isValueRequired() const { return _valueRequired; }
inline bool Arg::isSet() const
{
if ( _alreadySet && !_xorSet )
return true;
else
return false;
}
inline bool Arg::isIgnoreable() const { return _ignoreable; }
inline void Arg::setRequireLabel( const std::string& s)
{
_requireLabel = s;
}
inline bool Arg::argMatches( const std::string& argFlag ) const
{
if ( ( argFlag == Arg::flagStartString() + _flag && _flag != "" ) ||
argFlag == Arg::nameStartString() + _name )
return true;
else
return false;
}
inline std::string Arg::toString() const
{
std::string s = "";
if ( _flag != "" )
s += Arg::flagStartString() + _flag + " ";
s += "(" + Arg::nameStartString() + _name + ")";
return s;
}
inline void Arg::_checkWithVisitor() const
{
if ( _visitor != NULL )
_visitor->visit();
}
/**
* Implementation of trimFlag.
*/
inline void Arg::trimFlag(std::string& flag, std::string& value) const
{
int stop = 0;
for ( int i = 0; static_cast<unsigned int>(i) < flag.length(); i++ )
if ( flag[i] == Arg::delimiter() )
{
stop = i;
break;
}
if ( stop > 1 )
{
value = flag.substr(stop+1);
flag = flag.substr(0,stop);
}
}
/**
* Implementation of _hasBlanks.
*/
inline bool Arg::_hasBlanks( const std::string& s ) const
{
for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
if ( s[i] == Arg::blankChar() )
return true;
return false;
}
inline void Arg::forceRequired()
{
_required = true;
}
inline void Arg::xorSet()
{
_alreadySet = true;
_xorSet = true;
}
/**
* Overridden by Args that need to added to the end of the list.
*/
inline void Arg::addToList( std::list<Arg*>& argList ) const
{
argList.push_front( const_cast<Arg*>(this) );
}
inline bool Arg::allowMore()
{
return false;
}
inline bool Arg::acceptsMultipleValues()
{
return _acceptsMultipleValues;
}
inline void Arg::reset()
{
_xorSet = false;
_alreadySet = false;
}
//////////////////////////////////////////////////////////////////////
//END Arg.cpp
//////////////////////////////////////////////////////////////////////
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,213 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: ArgException.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2017 Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_ARG_EXCEPTION_H
#define TCLAP_ARG_EXCEPTION_H
#include <string>
#include <exception>
namespace TCLAP {
/**
* A simple class that defines and argument exception. Should be caught
* whenever a CmdLine is created and parsed.
*/
class ArgException : public std::exception
{
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source.
* \param td - Text describing the type of ArgException it is.
* of the exception.
*/
ArgException( const std::string& text = "undefined exception",
const std::string& id = "undefined",
const std::string& td = "Generic ArgException")
: std::exception(),
_errorText(text),
_argId( id ),
_typeDescription(td)
{ }
/**
* Destructor.
*/
virtual ~ArgException() throw() { }
/**
* Returns the error text.
*/
std::string error() const { return ( _errorText ); }
/**
* Returns the argument id.
*/
std::string argId() const
{
if ( _argId == "undefined" )
return " ";
else
return ( "Argument: " + _argId );
}
/**
* Returns the arg id and error text.
*/
const char* what() const throw()
{
static std::string ex;
ex = _argId + " -- " + _errorText;
return ex.c_str();
}
/**
* Returns the type of the exception. Used to explain and distinguish
* between different child exceptions.
*/
std::string typeDescription() const
{
return _typeDescription;
}
private:
/**
* The text of the exception message.
*/
std::string _errorText;
/**
* The argument related to this exception.
*/
std::string _argId;
/**
* Describes the type of the exception. Used to distinguish
* between different child exceptions.
*/
std::string _typeDescription;
};
/**
* Thrown from within the child Arg classes when it fails to properly
* parse the argument it has been passed.
*/
class ArgParseException : public ArgException
{
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source
* of the exception.
*/
ArgParseException( const std::string& text = "undefined exception",
const std::string& id = "undefined" )
: ArgException( text,
id,
std::string( "Exception found while parsing " ) +
std::string( "the value the Arg has been passed." ))
{ }
};
/**
* Thrown from CmdLine when the arguments on the command line are not
* properly specified, e.g. too many arguments, required argument missing, etc.
*/
class CmdLineParseException : public ArgException
{
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source
* of the exception.
*/
CmdLineParseException( const std::string& text = "undefined exception",
const std::string& id = "undefined" )
: ArgException( text,
id,
std::string( "Exception found when the values ") +
std::string( "on the command line do not meet ") +
std::string( "the requirements of the defined ") +
std::string( "Args." ))
{ }
};
/**
* Thrown from Arg and CmdLine when an Arg is improperly specified, e.g.
* same flag as another Arg, same name, etc.
*/
class SpecificationException : public ArgException
{
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source
* of the exception.
*/
SpecificationException( const std::string& text = "undefined exception",
const std::string& id = "undefined" )
: ArgException( text,
id,
std::string("Exception found when an Arg object ")+
std::string("is improperly defined by the ") +
std::string("developer." ))
{ }
};
/**
* Thrown when TCLAP thinks the program should exit.
*
* For example after parse error this exception will be thrown (and
* normally caught). This allows any resource to be clened properly
* before exit.
*
* If exception handling is disabled (CmdLine::setExceptionHandling),
* this exception will propagate to the call site, allowing the
* program to catch it and avoid program termination, or do it's own
* cleanup. See for example, https://sourceforge.net/p/tclap/bugs/29.
*/
class ExitException {
public:
ExitException(int estat) : _estat(estat) {}
int getExitStatus() const { return _estat; }
private:
int _estat;
};
} // namespace TCLAP
#endif

View File

@@ -0,0 +1,122 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: ArgTraits.h
*
* Copyright (c) 2007, Daniel Aarno, Michael E. Smoot .
* Copyright (c) 2017 Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
// This is an internal tclap file, you should probably not have to
// include this directly
#ifndef TCLAP_ARGTRAITS_H
#define TCLAP_ARGTRAITS_H
namespace TCLAP {
// We use two empty structs to get compile type specialization
// function to work
/**
* A value like argument value type is a value that can be set using
* operator>>. This is the default value type.
*/
struct ValueLike {
typedef ValueLike ValueCategory;
virtual ~ValueLike() {}
};
/**
* A string like argument value type is a value that can be set using
* operator=(string). Useful if the value type contains spaces which
* will be broken up into individual tokens by operator>>.
*/
struct StringLike {
virtual ~StringLike() {}
};
/**
* A class can inherit from this object to make it have string like
* traits. This is a compile time thing and does not add any overhead
* to the inherenting class.
*/
struct StringLikeTrait {
typedef StringLike ValueCategory;
virtual ~StringLikeTrait() {}
};
/**
* A class can inherit from this object to make it have value like
* traits. This is a compile time thing and does not add any overhead
* to the inherenting class.
*/
struct ValueLikeTrait {
typedef ValueLike ValueCategory;
virtual ~ValueLikeTrait() {}
};
/**
* Arg traits are used to get compile type specialization when parsing
* argument values. Using an ArgTraits you can specify the way that
* values gets assigned to any particular type during parsing. The two
* supported types are StringLike and ValueLike. ValueLike is the
* default and means that operator>> will be used to assign values to
* the type.
*/
template<typename T>
class ArgTraits {
// This is a bit silly, but what we want to do is:
// 1) If there exists a specialization of ArgTraits for type X,
// use it.
//
// 2) If no specialization exists but X has the typename
// X::ValueCategory, use the specialization for X::ValueCategory.
//
// 3) If neither (1) nor (2) defines the trait, use the default
// which is ValueLike.
// This is the "how":
//
// test<T>(0) (where 0 is the NULL ptr) will match
// test(typename C::ValueCategory*) iff type T has the
// corresponding typedef. If it does not test(...) will be
// matched. This allows us to determine if T::ValueCategory
// exists by checking the sizeof for the test function (return
// value must have different sizeof).
template<typename C> static short test(typename C::ValueCategory*);
template<typename C> static long test(...);
static const bool hasTrait = sizeof(test<T>(0)) == sizeof(short);
template <typename C, bool>
struct DefaultArgTrait {
typedef ValueLike ValueCategory;
};
template <typename C>
struct DefaultArgTrait<C, true> {
typedef typename C::ValueCategory ValueCategory;
};
public:
typedef typename DefaultArgTrait<T, hasTrait>::ValueCategory ValueCategory;
};
} // namespace
#endif

View File

@@ -0,0 +1,657 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: CmdLine.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_CMDLINE_H
#define TCLAP_CMDLINE_H
#include <tclap/SwitchArg.h>
#include <tclap/MultiSwitchArg.h>
#include <tclap/UnlabeledValueArg.h>
#include <tclap/UnlabeledMultiArg.h>
#include <tclap/XorHandler.h>
#include <tclap/HelpVisitor.h>
#include <tclap/VersionVisitor.h>
#include <tclap/IgnoreRestVisitor.h>
#include <tclap/CmdLineOutput.h>
#include <tclap/StdOutput.h>
#include <tclap/Constraint.h>
#include <tclap/ValuesConstraint.h>
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <stdlib.h> // Needed for exit(), which isn't defined in some envs.
namespace TCLAP {
template<typename T> void DelPtr(T ptr)
{
delete ptr;
}
template<typename C> void ClearContainer(C &c)
{
typedef typename C::value_type value_type;
std::for_each(c.begin(), c.end(), DelPtr<value_type>);
c.clear();
}
/**
* The base class that manages the command line definition and passes
* along the parsing to the appropriate Arg classes.
*/
class CmdLine : public CmdLineInterface
{
protected:
/**
* The list of arguments that will be tested against the
* command line.
*/
std::list<Arg*> _argList;
/**
* The name of the program. Set to argv[0].
*/
std::string _progName;
/**
* A message used to describe the program. Used in the usage output.
*/
std::string _message;
/**
* The version to be displayed with the --version switch.
*/
std::string _version;
/**
* The number of arguments that are required to be present on
* the command line. This is set dynamically, based on the
* Args added to the CmdLine object.
*/
int _numRequired;
/**
* The character that is used to separate the argument flag/name
* from the value. Defaults to ' ' (space).
*/
char _delimiter;
/**
* The handler that manages xoring lists of args.
*/
XorHandler _xorHandler;
/**
* A list of Args to be explicitly deleted when the destructor
* is called. At the moment, this only includes the three default
* Args.
*/
std::list<Arg*> _argDeleteOnExitList;
/**
* A list of Visitors to be explicitly deleted when the destructor
* is called. At the moment, these are the Visitors created for the
* default Args.
*/
std::list<Visitor*> _visitorDeleteOnExitList;
/**
* Object that handles all output for the CmdLine.
*/
CmdLineOutput* _output;
/**
* Should CmdLine handle parsing exceptions internally?
*/
bool _handleExceptions;
/**
* Throws an exception listing the missing args.
*/
void missingArgsException();
/**
* Checks whether a name/flag string matches entirely matches
* the Arg::blankChar. Used when multiple switches are combined
* into a single argument.
* \param s - The message to be used in the usage.
*/
bool _emptyCombined(const std::string& s);
/**
* Perform a delete ptr; operation on ptr when this object is deleted.
*/
void deleteOnExit(Arg* ptr);
/**
* Perform a delete ptr; operation on ptr when this object is deleted.
*/
void deleteOnExit(Visitor* ptr);
private:
/**
* Prevent accidental copying.
*/
CmdLine(const CmdLine& rhs);
CmdLine& operator=(const CmdLine& rhs);
/**
* Encapsulates the code common to the constructors
* (which is all of it).
*/
void _constructor();
/**
* Is set to true when a user sets the output object. We use this so
* that we don't delete objects that are created outside of this lib.
*/
bool _userSetOutput;
/**
* Whether or not to automatically create help and version switches.
*/
bool _helpAndVersion;
/**
* Whether or not to ignore unmatched args.
*/
bool _ignoreUnmatched;
public:
/**
* Command line constructor. Defines how the arguments will be
* parsed.
* \param message - The message to be used in the usage
* output.
* \param delimiter - The character that is used to separate
* the argument flag/name from the value. Defaults to ' ' (space).
* \param version - The version number to be used in the
* --version switch.
* \param helpAndVersion - Whether or not to create the Help and
* Version switches. Defaults to true.
*/
CmdLine(const std::string& message,
const char delimiter = ' ',
const std::string& version = "none",
bool helpAndVersion = true);
/**
* Deletes any resources allocated by a CmdLine object.
*/
virtual ~CmdLine();
/**
* Adds an argument to the list of arguments to be parsed.
* \param a - Argument to be added.
*/
void add( Arg& a );
/**
* An alternative add. Functionally identical.
* \param a - Argument to be added.
*/
void add( Arg* a );
/**
* Add two Args that will be xor'd. If this method is used, add does
* not need to be called.
* \param a - Argument to be added and xor'd.
* \param b - Argument to be added and xor'd.
*/
void xorAdd( Arg& a, Arg& b );
/**
* Add a list of Args that will be xor'd. If this method is used,
* add does not need to be called.
* \param xors - List of Args to be added and xor'd.
*/
void xorAdd( const std::vector<Arg*>& xors );
/**
* Parses the command line.
* \param argc - Number of arguments.
* \param argv - Array of arguments.
*/
void parse(int argc, const char * const * argv);
/**
* Parses the command line.
* \param args - A vector of strings representing the args.
* args[0] is still the program name.
*/
void parse(std::vector<std::string>& args);
/**
*
*/
CmdLineOutput* getOutput();
/**
*
*/
void setOutput(CmdLineOutput* co);
/**
*
*/
std::string& getVersion();
/**
*
*/
std::string& getProgramName();
/**
*
*/
std::list<Arg*>& getArgList();
/**
*
*/
XorHandler& getXorHandler();
/**
*
*/
char getDelimiter();
/**
*
*/
std::string& getMessage();
/**
*
*/
bool hasHelpAndVersion();
/**
* Disables or enables CmdLine's internal parsing exception handling.
*
* @param state Should CmdLine handle parsing exceptions internally?
*/
void setExceptionHandling(const bool state);
/**
* Returns the current state of the internal exception handling.
*
* @retval true Parsing exceptions are handled internally.
* @retval false Parsing exceptions are propagated to the caller.
*/
bool getExceptionHandling() const;
/**
* Allows the CmdLine object to be reused.
*/
void reset();
/**
* Allows unmatched args to be ignored. By default false.
*
* @param ignore If true the cmdline will ignore any unmatched args
* and if false it will behave as normal.
*/
void ignoreUnmatched(const bool ignore);
};
///////////////////////////////////////////////////////////////////////////////
//Begin CmdLine.cpp
///////////////////////////////////////////////////////////////////////////////
inline CmdLine::CmdLine(const std::string& m,
char delim,
const std::string& v,
bool help )
:
_argList(std::list<Arg*>()),
_progName("not_set_yet"),
_message(m),
_version(v),
_numRequired(0),
_delimiter(delim),
_xorHandler(XorHandler()),
_argDeleteOnExitList(std::list<Arg*>()),
_visitorDeleteOnExitList(std::list<Visitor*>()),
_output(0),
_handleExceptions(true),
_userSetOutput(false),
_helpAndVersion(help),
_ignoreUnmatched(false)
{
_constructor();
}
inline CmdLine::~CmdLine()
{
ClearContainer(_argDeleteOnExitList);
ClearContainer(_visitorDeleteOnExitList);
if ( !_userSetOutput ) {
delete _output;
_output = 0;
}
}
inline void CmdLine::_constructor()
{
_output = new StdOutput;
Arg::setDelimiter( _delimiter );
Visitor* v;
if ( _helpAndVersion )
{
v = new HelpVisitor( this, &_output );
SwitchArg* help = new SwitchArg("h","help",
"Displays usage information and exits.",
false, v);
add( help );
deleteOnExit(help);
deleteOnExit(v);
v = new VersionVisitor( this, &_output );
SwitchArg* vers = new SwitchArg("","version",
"Displays version information and exits.",
false, v);
add( vers );
deleteOnExit(vers);
deleteOnExit(v);
}
v = new IgnoreRestVisitor();
SwitchArg* ignore = new SwitchArg(Arg::flagStartString(),
Arg::ignoreNameString(),
"Ignores the rest of the labeled arguments following this flag.",
false, v);
add( ignore );
deleteOnExit(ignore);
deleteOnExit(v);
}
inline void CmdLine::xorAdd( const std::vector<Arg*>& ors )
{
_xorHandler.add( ors );
for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
{
(*it)->forceRequired();
(*it)->setRequireLabel( "OR required" );
add( *it );
}
}
inline void CmdLine::xorAdd( Arg& a, Arg& b )
{
std::vector<Arg*> ors;
ors.push_back( &a );
ors.push_back( &b );
xorAdd( ors );
}
inline void CmdLine::add( Arg& a )
{
add( &a );
}
inline void CmdLine::add( Arg* a )
{
for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
if ( *a == *(*it) )
throw( SpecificationException(
"Argument with same flag/name already exists!",
a->longID() ) );
a->addToList( _argList );
if ( a->isRequired() )
_numRequired++;
}
inline void CmdLine::parse(int argc, const char * const * argv)
{
// this step is necessary so that we have easy access to
// mutable strings.
std::vector<std::string> args;
for (int i = 0; i < argc; i++)
args.push_back(argv[i]);
parse(args);
}
inline void CmdLine::parse(std::vector<std::string>& args)
{
bool shouldExit = false;
int estat = 0;
try {
if (args.empty()) {
// https://sourceforge.net/p/tclap/bugs/30/
throw CmdLineParseException("The args vector must not be empty, "
"the first entry should contain the "
"program's name.");
}
_progName = args.front();
args.erase(args.begin());
int requiredCount = 0;
for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++)
{
bool matched = false;
for (ArgListIterator it = _argList.begin();
it != _argList.end(); it++) {
if ( (*it)->processArg( &i, args ) )
{
requiredCount += _xorHandler.check( *it );
matched = true;
break;
}
}
// checks to see if the argument is an empty combined
// switch and if so, then we've actually matched it
if ( !matched && _emptyCombined( args[i] ) )
matched = true;
if ( !matched && !Arg::ignoreRest() && !_ignoreUnmatched)
throw(CmdLineParseException("Couldn't find match "
"for argument",
args[i]));
}
if ( requiredCount < _numRequired )
missingArgsException();
if ( requiredCount > _numRequired )
throw(CmdLineParseException("Too many arguments!"));
} catch ( ArgException& e ) {
// If we're not handling the exceptions, rethrow.
if ( !_handleExceptions) {
throw;
}
try {
_output->failure(*this,e);
} catch ( ExitException &ee ) {
estat = ee.getExitStatus();
shouldExit = true;
}
} catch (ExitException &ee) {
// If we're not handling the exceptions, rethrow.
if ( !_handleExceptions) {
throw;
}
estat = ee.getExitStatus();
shouldExit = true;
}
if (shouldExit)
exit(estat);
}
inline bool CmdLine::_emptyCombined(const std::string& s)
{
if ( s.length() > 0 && s[0] != Arg::flagStartChar() )
return false;
for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
if ( s[i] != Arg::blankChar() )
return false;
return true;
}
inline void CmdLine::missingArgsException()
{
int count = 0;
std::string missingArgList;
for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
{
if ( (*it)->isRequired() && !(*it)->isSet() )
{
missingArgList += (*it)->getName();
missingArgList += ", ";
count++;
}
}
missingArgList = missingArgList.substr(0,missingArgList.length()-2);
std::string msg;
if ( count > 1 )
msg = "Required arguments missing: ";
else
msg = "Required argument missing: ";
msg += missingArgList;
throw(CmdLineParseException(msg));
}
inline void CmdLine::deleteOnExit(Arg* ptr)
{
_argDeleteOnExitList.push_back(ptr);
}
inline void CmdLine::deleteOnExit(Visitor* ptr)
{
_visitorDeleteOnExitList.push_back(ptr);
}
inline CmdLineOutput* CmdLine::getOutput()
{
return _output;
}
inline void CmdLine::setOutput(CmdLineOutput* co)
{
if ( !_userSetOutput )
delete _output;
_userSetOutput = true;
_output = co;
}
inline std::string& CmdLine::getVersion()
{
return _version;
}
inline std::string& CmdLine::getProgramName()
{
return _progName;
}
inline std::list<Arg*>& CmdLine::getArgList()
{
return _argList;
}
inline XorHandler& CmdLine::getXorHandler()
{
return _xorHandler;
}
inline char CmdLine::getDelimiter()
{
return _delimiter;
}
inline std::string& CmdLine::getMessage()
{
return _message;
}
inline bool CmdLine::hasHelpAndVersion()
{
return _helpAndVersion;
}
inline void CmdLine::setExceptionHandling(const bool state)
{
_handleExceptions = state;
}
inline bool CmdLine::getExceptionHandling() const
{
return _handleExceptions;
}
inline void CmdLine::reset()
{
for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
(*it)->reset();
_progName.clear();
}
inline void CmdLine::ignoreUnmatched(const bool ignore)
{
_ignoreUnmatched = ignore;
}
///////////////////////////////////////////////////////////////////////////////
//End CmdLine.cpp
///////////////////////////////////////////////////////////////////////////////
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,153 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: CmdLineInterface.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_COMMANDLINE_INTERFACE_H
#define TCLAP_COMMANDLINE_INTERFACE_H
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <algorithm>
namespace TCLAP {
class Arg;
class CmdLineOutput;
class XorHandler;
/**
* The base class that manages the command line definition and passes
* along the parsing to the appropriate Arg classes.
*/
class CmdLineInterface
{
public:
/**
* Destructor
*/
virtual ~CmdLineInterface() {}
/**
* Adds an argument to the list of arguments to be parsed.
* \param a - Argument to be added.
*/
virtual void add( Arg& a )=0;
/**
* An alternative add. Functionally identical.
* \param a - Argument to be added.
*/
virtual void add( Arg* a )=0;
/**
* Add two Args that will be xor'd.
* If this method is used, add does
* not need to be called.
* \param a - Argument to be added and xor'd.
* \param b - Argument to be added and xor'd.
*/
virtual void xorAdd( Arg& a, Arg& b )=0;
/**
* Add a list of Args that will be xor'd. If this method is used,
* add does not need to be called.
* \param xors - List of Args to be added and xor'd.
*/
virtual void xorAdd( const std::vector<Arg*>& xors )=0;
/**
* Parses the command line.
* \param argc - Number of arguments.
* \param argv - Array of arguments.
*/
virtual void parse(int argc, const char * const * argv)=0;
/**
* Parses the command line.
* \param args - A vector of strings representing the args.
* args[0] is still the program name.
*/
void parse(std::vector<std::string>& args);
/**
* Returns the CmdLineOutput object.
*/
virtual CmdLineOutput* getOutput()=0;
/**
* \param co - CmdLineOutput object that we want to use instead.
*/
virtual void setOutput(CmdLineOutput* co)=0;
/**
* Returns the version string.
*/
virtual std::string& getVersion()=0;
/**
* Returns the program name string.
*/
virtual std::string& getProgramName()=0;
/**
* Returns the argList.
*/
virtual std::list<Arg*>& getArgList()=0;
/**
* Returns the XorHandler.
*/
virtual XorHandler& getXorHandler()=0;
/**
* Returns the delimiter string.
*/
virtual char getDelimiter()=0;
/**
* Returns the message string.
*/
virtual std::string& getMessage()=0;
/**
* Indicates whether or not the help and version switches were created
* automatically.
*/
virtual bool hasHelpAndVersion()=0;
/**
* Resets the instance as if it had just been constructed so that the
* instance can be reused.
*/
virtual void reset()=0;
};
} //namespace
#endif

View File

@@ -0,0 +1,77 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: CmdLineOutput.h
*
* Copyright (c) 2004, Michael E. Smoot
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_CMDLINEOUTPUT_H
#define TCLAP_CMDLINEOUTPUT_H
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <iomanip>
#include <algorithm>
namespace TCLAP {
class CmdLineInterface;
class ArgException;
/**
* The interface that any output object must implement.
*/
class CmdLineOutput
{
public:
/**
* Virtual destructor.
*/
virtual ~CmdLineOutput() {}
/**
* Generates some sort of output for the USAGE.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c)=0;
/**
* Generates some sort of output for the version.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c)=0;
/**
* Generates some sort of output for a failure.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure( CmdLineInterface& c,
ArgException& e )=0;
};
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,78 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: Constraint.h
*
* Copyright (c) 2005, Michael E. Smoot
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_CONSTRAINT_H
#define TCLAP_CONSTRAINT_H
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <stdexcept>
namespace TCLAP {
/**
* The interface that defines the interaction between the Arg and Constraint.
*/
template<class T>
class Constraint
{
public:
/**
* Returns a description of the Constraint.
*/
virtual std::string description() const =0;
/**
* Returns the short ID for the Constraint.
*/
virtual std::string shortID() const =0;
/**
* The method used to verify that the value parsed from the command
* line meets the constraint.
* \param value - The value that will be checked.
*/
virtual bool check(const T& value) const =0;
/**
* Destructor.
* Silences warnings about Constraint being a base class with virtual
* functions but without a virtual destructor.
*/
virtual ~Constraint() { ; }
static std::string shortID(Constraint<T> *constraint) {
if (!constraint)
throw std::logic_error("Cannot create a ValueArg with a NULL constraint");
return constraint->shortID();
}
};
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,303 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: DocBookOutput.h
*
* Copyright (c) 2004, Michael E. Smoot
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_DOCBOOKOUTPUT_H
#define TCLAP_DOCBOOKOUTPUT_H
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLineInterface.h>
#include <tclap/CmdLineOutput.h>
#include <tclap/XorHandler.h>
#include <tclap/Arg.h>
namespace TCLAP {
/**
* A class that generates DocBook output for usage() method for the
* given CmdLine and its Args.
*/
class DocBookOutput : public CmdLineOutput
{
public:
/**
* Prints the usage to stdout. Can be overridden to
* produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c);
/**
* Prints the version to stdout. Can be overridden
* to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c);
/**
* Prints (to stderr) an error message, short usage
* Can be overridden to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure(CmdLineInterface& c,
ArgException& e );
DocBookOutput() : theDelimiter('=') {}
protected:
/**
* Substitutes the char r for string x in string s.
* \param s - The string to operate on.
* \param r - The char to replace.
* \param x - What to replace r with.
*/
void substituteSpecialChars( std::string& s, char r, std::string& x );
void removeChar( std::string& s, char r);
void basename( std::string& s );
void printShortArg(Arg* it);
void printLongArg(Arg* it);
char theDelimiter;
};
inline void DocBookOutput::version(CmdLineInterface& _cmd)
{
std::cout << _cmd.getVersion() << std::endl;
}
inline void DocBookOutput::usage(CmdLineInterface& _cmd )
{
std::list<Arg*> argList = _cmd.getArgList();
std::string progName = _cmd.getProgramName();
std::string xversion = _cmd.getVersion();
theDelimiter = _cmd.getDelimiter();
XorHandler xorHandler = _cmd.getXorHandler();
const std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
basename(progName);
std::cout << "<?xml version='1.0'?>" << std::endl;
std::cout << "<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\"" << std::endl;
std::cout << "\t\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\">" << std::endl << std::endl;
std::cout << "<refentry>" << std::endl;
std::cout << "<refmeta>" << std::endl;
std::cout << "<refentrytitle>" << progName << "</refentrytitle>" << std::endl;
std::cout << "<manvolnum>1</manvolnum>" << std::endl;
std::cout << "</refmeta>" << std::endl;
std::cout << "<refnamediv>" << std::endl;
std::cout << "<refname>" << progName << "</refname>" << std::endl;
std::cout << "<refpurpose>" << _cmd.getMessage() << "</refpurpose>" << std::endl;
std::cout << "</refnamediv>" << std::endl;
std::cout << "<refsynopsisdiv>" << std::endl;
std::cout << "<cmdsynopsis>" << std::endl;
std::cout << "<command>" << progName << "</command>" << std::endl;
// xor
for ( int i = 0; (unsigned int)i < xorList.size(); i++ )
{
std::cout << "<group choice='req'>" << std::endl;
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end(); it++ )
printShortArg((*it));
std::cout << "</group>" << std::endl;
}
// rest of args
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
if ( !xorHandler.contains( (*it) ) )
printShortArg((*it));
std::cout << "</cmdsynopsis>" << std::endl;
std::cout << "</refsynopsisdiv>" << std::endl;
std::cout << "<refsect1>" << std::endl;
std::cout << "<title>Description</title>" << std::endl;
std::cout << "<para>" << std::endl;
std::cout << _cmd.getMessage() << std::endl;
std::cout << "</para>" << std::endl;
std::cout << "</refsect1>" << std::endl;
std::cout << "<refsect1>" << std::endl;
std::cout << "<title>Options</title>" << std::endl;
std::cout << "<variablelist>" << std::endl;
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
printLongArg((*it));
std::cout << "</variablelist>" << std::endl;
std::cout << "</refsect1>" << std::endl;
std::cout << "<refsect1>" << std::endl;
std::cout << "<title>Version</title>" << std::endl;
std::cout << "<para>" << std::endl;
std::cout << xversion << std::endl;
std::cout << "</para>" << std::endl;
std::cout << "</refsect1>" << std::endl;
std::cout << "</refentry>" << std::endl;
}
inline void DocBookOutput::failure( CmdLineInterface& _cmd,
ArgException& e )
{
static_cast<void>(_cmd); // unused
std::cout << e.what() << std::endl;
throw ExitException(1);
}
inline void DocBookOutput::substituteSpecialChars( std::string& s,
char r,
std::string& x )
{
size_t p;
while ( (p = s.find_first_of(r)) != std::string::npos )
{
s.erase(p,1);
s.insert(p,x);
}
}
inline void DocBookOutput::removeChar( std::string& s, char r)
{
size_t p;
while ( (p = s.find_first_of(r)) != std::string::npos )
{
s.erase(p,1);
}
}
inline void DocBookOutput::basename( std::string& s )
{
size_t p = s.find_last_of('/');
if ( p != std::string::npos )
{
s.erase(0, p + 1);
}
}
inline void DocBookOutput::printShortArg(Arg* a)
{
std::string lt = "&lt;";
std::string gt = "&gt;";
std::string id = a->shortID();
substituteSpecialChars(id,'<',lt);
substituteSpecialChars(id,'>',gt);
removeChar(id,'[');
removeChar(id,']');
std::string choice = "opt";
if ( a->isRequired() )
choice = "plain";
std::cout << "<arg choice='" << choice << '\'';
if ( a->acceptsMultipleValues() )
std::cout << " rep='repeat'";
std::cout << '>';
if ( !a->getFlag().empty() )
std::cout << a->flagStartChar() << a->getFlag();
else
std::cout << a->nameStartString() << a->getName();
if ( a->isValueRequired() )
{
std::string arg = a->shortID();
removeChar(arg,'[');
removeChar(arg,']');
removeChar(arg,'<');
removeChar(arg,'>');
removeChar(arg,'.');
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
std::cout << theDelimiter;
std::cout << "<replaceable>" << arg << "</replaceable>";
}
std::cout << "</arg>" << std::endl;
}
inline void DocBookOutput::printLongArg(Arg* a)
{
std::string lt = "&lt;";
std::string gt = "&gt;";
std::string desc = a->getDescription();
substituteSpecialChars(desc,'<',lt);
substituteSpecialChars(desc,'>',gt);
std::cout << "<varlistentry>" << std::endl;
if ( !a->getFlag().empty() )
{
std::cout << "<term>" << std::endl;
std::cout << "<option>";
std::cout << a->flagStartChar() << a->getFlag();
std::cout << "</option>" << std::endl;
std::cout << "</term>" << std::endl;
}
std::cout << "<term>" << std::endl;
std::cout << "<option>";
std::cout << a->nameStartString() << a->getName();
if ( a->isValueRequired() )
{
std::string arg = a->shortID();
removeChar(arg,'[');
removeChar(arg,']');
removeChar(arg,'<');
removeChar(arg,'>');
removeChar(arg,'.');
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
std::cout << theDelimiter;
std::cout << "<replaceable>" << arg << "</replaceable>";
}
std::cout << "</option>" << std::endl;
std::cout << "</term>" << std::endl;
std::cout << "<listitem>" << std::endl;
std::cout << "<para>" << std::endl;
std::cout << desc << std::endl;
std::cout << "</para>" << std::endl;
std::cout << "</listitem>" << std::endl;
std::cout << "</varlistentry>" << std::endl;
}
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,78 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: HelpVisitor.h
*
* Copyright (c) 2003, Michael E. Smoot .
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_HELP_VISITOR_H
#define TCLAP_HELP_VISITOR_H
#include <tclap/CmdLineInterface.h>
#include <tclap/CmdLineOutput.h>
#include <tclap/Visitor.h>
namespace TCLAP {
/**
* A Visitor object that calls the usage method of the given CmdLineOutput
* object for the specified CmdLine object.
*/
class HelpVisitor: public Visitor
{
private:
/**
* Prevent accidental copying.
*/
HelpVisitor(const HelpVisitor& rhs);
HelpVisitor& operator=(const HelpVisitor& rhs);
protected:
/**
* The CmdLine the output will be generated for.
*/
CmdLineInterface* _cmd;
/**
* The output object.
*/
CmdLineOutput** _out;
public:
/**
* Constructor.
* \param cmd - The CmdLine the output will be generated for.
* \param out - The type of output.
*/
HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out)
: Visitor(), _cmd( cmd ), _out( out ) { }
/**
* Calls the usage method of the CmdLineOutput for the
* specified CmdLine.
*/
void visit() { (*_out)->usage(*_cmd); throw ExitException(0); }
};
}
#endif

View File

@@ -0,0 +1,54 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: IgnoreRestVisitor.h
*
* Copyright (c) 2003, Michael E. Smoot .
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_IGNORE_REST_VISITOR_H
#define TCLAP_IGNORE_REST_VISITOR_H
#include <tclap/Visitor.h>
#include <tclap/Arg.h>
namespace TCLAP {
/**
* A Visitor that tells the CmdLine to begin ignoring arguments after
* this one is parsed.
*/
class IgnoreRestVisitor: public Visitor
{
public:
/**
* Constructor.
*/
IgnoreRestVisitor() : Visitor() {}
/**
* Sets Arg::_ignoreRest.
*/
void visit() { Arg::beginIgnoring(); }
};
}
#endif

View File

@@ -0,0 +1,433 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: MultiArg.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_MULTIPLE_ARGUMENT_H
#define TCLAP_MULTIPLE_ARGUMENT_H
#include <string>
#include <vector>
#include <tclap/Arg.h>
#include <tclap/Constraint.h>
namespace TCLAP {
/**
* An argument that allows multiple values of type T to be specified. Very
* similar to a ValueArg, except a vector of values will be returned
* instead of just one.
*/
template<class T>
class MultiArg : public Arg
{
public:
typedef std::vector<T> container_type;
typedef typename container_type::iterator iterator;
typedef typename container_type::const_iterator const_iterator;
protected:
/**
* The list of values parsed from the CmdLine.
*/
std::vector<T> _values;
/**
* The description of type T to be used in the usage.
*/
std::string _typeDesc;
/**
* A list of constraint on this Arg.
*/
Constraint<T>* _constraint;
/**
* Extracts the value from the string.
* Attempts to parse string as type T, if this fails an exception
* is thrown.
* \param val - The string to be read.
*/
void _extractValue( const std::string& val );
/**
* Used by XorHandler to decide whether to keep parsing for this arg.
*/
bool _allowMore;
public:
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
Visitor* v = NULL);
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
Visitor* v = NULL );
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Returns a vector of type T containing the values parsed from
* the command line.
*/
const std::vector<T>& getValue() const { return _values; }
/**
* Returns an iterator over the values parsed from the command
* line.
*/
const_iterator begin() const { return _values.begin(); }
/**
* Returns the end of the values parsed from the command
* line.
*/
const_iterator end() const { return _values.end(); }
/**
* Returns the a short id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Returns the a long id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Once we've matched the first value, then the arg is no longer
* required.
*/
virtual bool isRequired() const;
virtual bool allowMore();
virtual void reset();
private:
/**
* Prevent accidental copying
*/
MultiArg(const MultiArg<T>& rhs);
MultiArg& operator=(const MultiArg<T>& rhs);
};
template<class T>
MultiArg<T>::MultiArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
Visitor* v) :
Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( typeDesc ),
_constraint( NULL ),
_allowMore(false)
{
_acceptsMultipleValues = true;
}
template<class T>
MultiArg<T>::MultiArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v)
: Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( typeDesc ),
_constraint( NULL ),
_allowMore(false)
{
parser.add( this );
_acceptsMultipleValues = true;
}
/**
*
*/
template<class T>
MultiArg<T>::MultiArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
Visitor* v)
: Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( Constraint<T>::shortID(constraint) ),
_constraint( constraint ),
_allowMore(false)
{
_acceptsMultipleValues = true;
}
template<class T>
MultiArg<T>::MultiArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v)
: Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( Constraint<T>::shortID(constraint) ),
_constraint( constraint ),
_allowMore(false)
{
parser.add( this );
_acceptsMultipleValues = true;
}
template<class T>
bool MultiArg<T>::processArg(int *i, std::vector<std::string>& args)
{
if ( _ignoreable && Arg::ignoreRest() )
return false;
if ( _hasBlanks( args[*i] ) )
return false;
std::string flag = args[*i];
std::string value = "";
trimFlag( flag, value );
if ( argMatches( flag ) )
{
if ( Arg::delimiter() != ' ' && value == "" )
throw( ArgParseException(
"Couldn't find delimiter for this argument!",
toString() ) );
// always take the first one, regardless of start string
if ( value == "" )
{
(*i)++;
if ( static_cast<unsigned int>(*i) < args.size() )
_extractValue( args[*i] );
else
throw( ArgParseException("Missing a value for this argument!",
toString() ) );
}
else
_extractValue( value );
/*
// continuing taking the args until we hit one with a start string
while ( (unsigned int)(*i)+1 < args.size() &&
args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 )
_extractValue( args[++(*i)] );
*/
_alreadySet = true;
_checkWithVisitor();
return true;
}
else
return false;
}
/**
*
*/
template<class T>
std::string MultiArg<T>::shortID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return Arg::shortID(_typeDesc) + " ...";
}
/**
*
*/
template<class T>
std::string MultiArg<T>::longID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return Arg::longID(_typeDesc) + " (accepted multiple times)";
}
/**
* Once we've matched the first value, then the arg is no longer
* required.
*/
template<class T>
bool MultiArg<T>::isRequired() const
{
if ( _required )
{
if ( _values.size() > 1 )
return false;
else
return true;
}
else
return false;
}
template<class T>
void MultiArg<T>::_extractValue( const std::string& val )
{
try {
T tmp;
ExtractValue(tmp, val, typename ArgTraits<T>::ValueCategory());
_values.push_back(tmp);
} catch( ArgParseException &e) {
throw ArgParseException(e.error(), toString());
}
if ( _constraint != NULL )
if ( ! _constraint->check( _values.back() ) )
throw( CmdLineParseException( "Value '" + val +
"' does not meet constraint: " +
_constraint->description(),
toString() ) );
}
template<class T>
bool MultiArg<T>::allowMore()
{
bool am = _allowMore;
_allowMore = true;
return am;
}
template<class T>
void MultiArg<T>::reset()
{
Arg::reset();
_values.clear();
}
} // namespace TCLAP
#endif

View File

@@ -0,0 +1,217 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: MultiSwitchArg.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
* Copyright (c) 2005, Michael E. Smoot, Daniel Aarno, Erik Zeek.
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_MULTI_SWITCH_ARG_H
#define TCLAP_MULTI_SWITCH_ARG_H
#include <string>
#include <vector>
#include <tclap/SwitchArg.h>
namespace TCLAP {
/**
* A multiple switch argument. If the switch is set on the command line, then
* the getValue method will return the number of times the switch appears.
*/
class MultiSwitchArg : public SwitchArg
{
protected:
/**
* The value of the switch.
*/
int _value;
/**
* Used to support the reset() method so that ValueArg can be
* reset to their constructed value.
*/
int _default;
public:
/**
* MultiSwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param init - Optional. The initial/default value of this Arg.
* Defaults to 0.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
int init = 0,
Visitor* v = NULL);
/**
* MultiSwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param parser - A CmdLine parser object to add this Arg to
* \param init - Optional. The initial/default value of this Arg.
* Defaults to 0.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
int init = 0,
Visitor* v = NULL);
/**
* Handles the processing of the argument.
* This re-implements the SwitchArg version of this method to set the
* _value of the argument appropriately.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed
* in from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Returns int, the number of times the switch has been set.
*/
int getValue() const { return _value; }
/**
* Returns the shortID for this Arg.
*/
std::string shortID(const std::string& val) const;
/**
* Returns the longID for this Arg.
*/
std::string longID(const std::string& val) const;
void reset();
};
//////////////////////////////////////////////////////////////////////
//BEGIN MultiSwitchArg.cpp
//////////////////////////////////////////////////////////////////////
inline MultiSwitchArg::MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
int init,
Visitor* v )
: SwitchArg(flag, name, desc, false, v),
_value( init ),
_default( init )
{ }
inline MultiSwitchArg::MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
int init,
Visitor* v )
: SwitchArg(flag, name, desc, false, v),
_value( init ),
_default( init )
{
parser.add( this );
}
inline bool MultiSwitchArg::processArg(int *i, std::vector<std::string>& args)
{
if ( _ignoreable && Arg::ignoreRest() )
return false;
if ( argMatches( args[*i] ))
{
// so the isSet() method will work
_alreadySet = true;
// Matched argument: increment value.
++_value;
_checkWithVisitor();
return true;
}
else if ( combinedSwitchesMatch( args[*i] ) )
{
// so the isSet() method will work
_alreadySet = true;
// Matched argument: increment value.
++_value;
// Check for more in argument and increment value.
while ( combinedSwitchesMatch( args[*i] ) )
++_value;
_checkWithVisitor();
return false;
}
else
return false;
}
inline std::string
MultiSwitchArg::shortID(const std::string& val) const
{
return Arg::shortID(val) + " ...";
}
inline std::string
MultiSwitchArg::longID(const std::string& val) const
{
return Arg::longID(val) + " (accepted multiple times)";
}
inline void
MultiSwitchArg::reset()
{
MultiSwitchArg::_value = MultiSwitchArg::_default;
}
//////////////////////////////////////////////////////////////////////
//END MultiSwitchArg.cpp
//////////////////////////////////////////////////////////////////////
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,64 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: OptionalUnlabeledTracker.h
*
* Copyright (c) 2005, Michael E. Smoot .
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_OPTIONAL_UNLABELED_TRACKER_H
#define TCLAP_OPTIONAL_UNLABELED_TRACKER_H
#include <string>
namespace TCLAP {
class OptionalUnlabeledTracker
{
public:
static void check( bool req, const std::string& argName );
static void gotOptional() { alreadyOptionalRef() = true; }
static bool& alreadyOptional() { return alreadyOptionalRef(); }
private:
static bool& alreadyOptionalRef() { static bool ct = false; return ct; }
};
inline void OptionalUnlabeledTracker::check( bool req, const std::string& argName )
{
if ( OptionalUnlabeledTracker::alreadyOptional() )
throw( SpecificationException(
"You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg",
argName ) );
if ( !req )
OptionalUnlabeledTracker::gotOptional();
}
} // namespace TCLAP
#endif

View File

@@ -0,0 +1,63 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: StandardTraits.h
*
* Copyright (c) 2007, Daniel Aarno, Michael E. Smoot .
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
// This is an internal tclap file, you should probably not have to
// include this directly
#ifndef TCLAP_STANDARD_TRAITS_H
#define TCLAP_STANDARD_TRAITS_H
#ifdef HAVE_CONFIG_H
#include <config.h> // To check for long long
#endif
// If Microsoft has already typedef'd wchar_t as an unsigned
// short, then compiles will break because it's as if we're
// creating ArgTraits twice for unsigned short. Thus...
#ifdef _MSC_VER
#ifndef _NATIVE_WCHAR_T_DEFINED
#define TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS
#endif
#endif
namespace TCLAP {
// Integer types (signed, unsigned and bool) and floating point types all
// have value-like semantics.
// Strings have string like argument traits.
template<>
struct ArgTraits<std::string> {
typedef StringLike ValueCategory;
};
template<typename T>
void SetString(T &dst, const std::string &src)
{
dst = src;
}
} // namespace
#endif

View File

@@ -0,0 +1,300 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: StdOutput.h
*
* Copyright (c) 2004, Michael E. Smoot
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_STDCMDLINEOUTPUT_H
#define TCLAP_STDCMDLINEOUTPUT_H
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLineInterface.h>
#include <tclap/CmdLineOutput.h>
#include <tclap/XorHandler.h>
#include <tclap/Arg.h>
namespace TCLAP {
/**
* A class that isolates any output from the CmdLine object so that it
* may be easily modified.
*/
class StdOutput : public CmdLineOutput
{
public:
/**
* Prints the usage to stdout. Can be overridden to
* produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c);
/**
* Prints the version to stdout. Can be overridden
* to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c);
/**
* Prints (to stderr) an error message, short usage
* Can be overridden to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure(CmdLineInterface& c,
ArgException& e );
protected:
/**
* Writes a brief usage message with short args.
* \param c - The CmdLine object the output is generated for.
* \param os - The stream to write the message to.
*/
void _shortUsage( CmdLineInterface& c, std::ostream& os ) const;
/**
* Writes a longer usage message with long and short args,
* provides descriptions and prints message.
* \param c - The CmdLine object the output is generated for.
* \param os - The stream to write the message to.
*/
void _longUsage( CmdLineInterface& c, std::ostream& os ) const;
/**
* This function inserts line breaks and indents long strings
* according the params input. It will only break lines at spaces,
* commas and pipes.
* \param os - The stream to be printed to.
* \param s - The string to be printed.
* \param maxWidth - The maxWidth allowed for the output line.
* \param indentSpaces - The number of spaces to indent the first line.
* \param secondLineOffset - The number of spaces to indent the second
* and all subsequent lines in addition to indentSpaces.
*/
void spacePrint( std::ostream& os,
const std::string& s,
int maxWidth,
int indentSpaces,
int secondLineOffset ) const;
};
inline void StdOutput::version(CmdLineInterface& _cmd)
{
std::string progName = _cmd.getProgramName();
std::string xversion = _cmd.getVersion();
std::cout << std::endl << progName << " version: "
<< xversion << std::endl << std::endl;
}
inline void StdOutput::usage(CmdLineInterface& _cmd )
{
std::cout << std::endl << "USAGE: " << std::endl << std::endl;
_shortUsage( _cmd, std::cout );
std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl;
_longUsage( _cmd, std::cout );
std::cout << std::endl;
}
inline void StdOutput::failure( CmdLineInterface& _cmd,
ArgException& e )
{
std::string progName = _cmd.getProgramName();
std::cerr << "PARSE ERROR: " << e.argId() << std::endl
<< " " << e.error() << std::endl << std::endl;
if ( _cmd.hasHelpAndVersion() )
{
std::cerr << "Brief USAGE: " << std::endl;
_shortUsage( _cmd, std::cerr );
std::cerr << std::endl << "For complete USAGE and HELP type: "
<< std::endl << " " << progName << " "
<< Arg::nameStartString() << "help"
<< std::endl << std::endl;
}
else
usage(_cmd);
throw ExitException(1);
}
inline void
StdOutput::_shortUsage( CmdLineInterface& _cmd,
std::ostream& os ) const
{
std::list<Arg*> argList = _cmd.getArgList();
std::string progName = _cmd.getProgramName();
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
std::string s = progName + " ";
// first the xor
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
{
s += " {";
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end(); it++ )
s += (*it)->shortID() + "|";
s[s.length()-1] = '}';
}
// then the rest
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
if ( !xorHandler.contains( (*it) ) )
s += " " + (*it)->shortID();
// if the program name is too long, then adjust the second line offset
int secondLineOffset = static_cast<int>(progName.length()) + 2;
if ( secondLineOffset > 75/2 )
secondLineOffset = static_cast<int>(75/2);
spacePrint( os, s, 75, 3, secondLineOffset );
}
inline void
StdOutput::_longUsage( CmdLineInterface& _cmd,
std::ostream& os ) const
{
std::list<Arg*> argList = _cmd.getArgList();
std::string message = _cmd.getMessage();
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
// first the xor
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
{
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end();
it++ )
{
spacePrint( os, (*it)->longID(), 75, 3, 3 );
spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
if ( it+1 != xorList[i].end() )
spacePrint(os, "-- OR --", 75, 9, 0);
}
os << std::endl << std::endl;
}
// then the rest
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
if ( !xorHandler.contains( (*it) ) )
{
spacePrint( os, (*it)->longID(), 75, 3, 3 );
spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
os << std::endl;
}
os << std::endl;
spacePrint( os, message, 75, 3, 0 );
}
inline void StdOutput::spacePrint( std::ostream& os,
const std::string& s,
int maxWidth,
int indentSpaces,
int secondLineOffset ) const
{
int len = static_cast<int>(s.length());
if ( (len + indentSpaces > maxWidth) && maxWidth > 0 )
{
int allowedLen = maxWidth - indentSpaces;
int start = 0;
while ( start < len )
{
// find the substring length
// int stringLen = std::min<int>( len - start, allowedLen );
// doing it this way to support a VisualC++ 2005 bug
using namespace std;
int stringLen = min<int>( len - start, allowedLen );
// trim the length so it doesn't end in middle of a word
if ( stringLen == allowedLen )
while ( stringLen >= 0 &&
s[stringLen+start] != ' ' &&
s[stringLen+start] != ',' &&
s[stringLen+start] != '|' )
stringLen--;
// ok, the word is longer than the line, so just split
// wherever the line ends
if ( stringLen <= 0 )
stringLen = allowedLen;
// check for newlines
for ( int i = 0; i < stringLen; i++ )
if ( s[start+i] == '\n' )
stringLen = i+1;
// print the indent
for ( int i = 0; i < indentSpaces; i++ )
os << " ";
if ( start == 0 )
{
// handle second line offsets
indentSpaces += secondLineOffset;
// adjust allowed len
allowedLen -= secondLineOffset;
}
os << s.substr(start,stringLen) << std::endl;
// so we don't start a line with a space
while ( s[stringLen+start] == ' ' && start < len )
start++;
start += stringLen;
}
}
else
{
for ( int i = 0; i < indentSpaces; i++ )
os << " ";
os << s << std::endl;
}
}
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,273 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: SwitchArg.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_SWITCH_ARG_H
#define TCLAP_SWITCH_ARG_H
#include <string>
#include <vector>
#include <tclap/Arg.h>
namespace TCLAP {
/**
* A simple switch argument. If the switch is set on the command line, then
* the getValue method will return the opposite of the default value for the
* switch.
*/
class SwitchArg : public Arg
{
protected:
/**
* The value of the switch.
*/
bool _value;
/**
* Used to support the reset() method so that ValueArg can be
* reset to their constructed value.
*/
bool _default;
public:
/**
* SwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param def - The default value for this Switch.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
SwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool def = false,
Visitor* v = NULL);
/**
* SwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param parser - A CmdLine parser object to add this Arg to
* \param def - The default value for this Switch.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
SwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
bool def = false,
Visitor* v = NULL);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed
* in from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Checks a string to see if any of the chars in the string
* match the flag for this Switch.
*/
bool combinedSwitchesMatch(std::string& combined);
/**
* Returns bool, whether or not the switch has been set.
*/
bool getValue() const { return _value; }
/**
* A SwitchArg can be used as a boolean, indicating
* whether or not the switch has been set. This is the
* same as calling getValue()
*/
operator bool() const { return _value; }
virtual void reset();
private:
/**
* Checks to see if we've found the last match in
* a combined string.
*/
bool lastCombined(std::string& combined);
/**
* Does the common processing of processArg.
*/
void commonProcessing();
};
//////////////////////////////////////////////////////////////////////
//BEGIN SwitchArg.cpp
//////////////////////////////////////////////////////////////////////
inline SwitchArg::SwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool default_val,
Visitor* v )
: Arg(flag, name, desc, false, false, v),
_value( default_val ),
_default( default_val )
{ }
inline SwitchArg::SwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
bool default_val,
Visitor* v )
: Arg(flag, name, desc, false, false, v),
_value( default_val ),
_default(default_val)
{
parser.add( this );
}
inline bool SwitchArg::lastCombined(std::string& combinedSwitches )
{
for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
if ( combinedSwitches[i] != Arg::blankChar() )
return false;
return true;
}
inline bool SwitchArg::combinedSwitchesMatch(std::string& combinedSwitches )
{
// make sure this is actually a combined switch
if ( combinedSwitches.length() > 0 &&
combinedSwitches[0] != Arg::flagStartString()[0] )
return false;
// make sure it isn't a long name
if ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) ==
Arg::nameStartString() )
return false;
// make sure the delimiter isn't in the string
if ( combinedSwitches.find_first_of(Arg::delimiter()) != std::string::npos)
return false;
// ok, we're not specifying a ValueArg, so we know that we have
// a combined switch list.
for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
if ( _flag.length() > 0 &&
combinedSwitches[i] == _flag[0] &&
_flag[0] != Arg::flagStartString()[0] )
{
// update the combined switches so this one is no longer present
// this is necessary so that no unlabeled args are matched
// later in the processing.
//combinedSwitches.erase(i,1);
combinedSwitches[i] = Arg::blankChar();
return true;
}
// none of the switches passed in the list match.
return false;
}
inline void SwitchArg::commonProcessing()
{
if ( _xorSet )
throw(CmdLineParseException(
"Mutually exclusive argument already set!", toString()));
if ( _alreadySet )
throw(CmdLineParseException("Argument already set!", toString()));
_alreadySet = true;
if ( _value == true )
_value = false;
else
_value = true;
_checkWithVisitor();
}
inline bool SwitchArg::processArg(int *i, std::vector<std::string>& args)
{
if ( _ignoreable && Arg::ignoreRest() )
return false;
// if the whole string matches the flag or name string
if ( argMatches( args[*i] ) )
{
commonProcessing();
return true;
}
// if a substring matches the flag as part of a combination
else if ( combinedSwitchesMatch( args[*i] ) )
{
// check again to ensure we don't misinterpret
// this as a MultiSwitchArg
if ( combinedSwitchesMatch( args[*i] ) )
throw(CmdLineParseException("Argument already set!",
toString()));
commonProcessing();
// We only want to return true if we've found the last combined
// match in the string, otherwise we return true so that other
// switches in the combination will have a chance to match.
return lastCombined( args[*i] );
}
else
return false;
}
inline void SwitchArg::reset()
{
Arg::reset();
_value = _default;
}
//////////////////////////////////////////////////////////////////////
//End SwitchArg.cpp
//////////////////////////////////////////////////////////////////////
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,304 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: UnlabeledMultiArg.h
*
* Copyright (c) 2003, Michael E. Smoot.
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H
#define TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H
#include <string>
#include <vector>
#include <tclap/MultiArg.h>
#include <tclap/OptionalUnlabeledTracker.h>
namespace TCLAP {
/**
* Just like a MultiArg, except that the arguments are unlabeled. Basically,
* this Arg will slurp up everything that hasn't been matched to another
* Arg.
*/
template<class T>
class UnlabeledMultiArg : public MultiArg<T>
{
// If compiler has two stage name lookup (as gcc >= 3.4 does)
// this is required to prevent undef. symbols
using MultiArg<T>::_ignoreable;
using MultiArg<T>::_hasBlanks;
using MultiArg<T>::_extractValue;
using MultiArg<T>::_typeDesc;
using MultiArg<T>::_name;
using MultiArg<T>::_description;
using MultiArg<T>::_alreadySet;
using MultiArg<T>::toString;
public:
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Returns the a short id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Returns the a long id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Operator ==.
* \param a - The Arg to be compared to this.
*/
virtual bool operator==(const Arg& a) const;
/**
* Pushes this to back of list rather than front.
* \param argList - The list this should be added to.
*/
virtual void addToList( std::list<Arg*>& argList ) const;
};
template<class T>
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, typeDesc, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
}
template<class T>
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, typeDesc, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
parser.add( this );
}
template<class T>
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, constraint, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
}
template<class T>
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, constraint, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
parser.add( this );
}
template<class T>
bool UnlabeledMultiArg<T>::processArg(int *i, std::vector<std::string>& args)
{
if ( _hasBlanks( args[*i] ) )
return false;
// never ignore an unlabeled multi arg
// always take the first value, regardless of the start string
_extractValue( args[(*i)] );
/*
// continue taking args until we hit the end or a start string
while ( (unsigned int)(*i)+1 < args.size() &&
args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 )
_extractValue( args[++(*i)] );
*/
_alreadySet = true;
return true;
}
template<class T>
std::string UnlabeledMultiArg<T>::shortID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return std::string("<") + _typeDesc + "> ...";
}
template<class T>
std::string UnlabeledMultiArg<T>::longID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return std::string("<") + _typeDesc + "> (accepted multiple times)";
}
template<class T>
bool UnlabeledMultiArg<T>::operator==(const Arg& a) const
{
if ( _name == a.getName() || _description == a.getDescription() )
return true;
else
return false;
}
template<class T>
void UnlabeledMultiArg<T>::addToList( std::list<Arg*>& argList ) const
{
argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
}
}
#endif

View File

@@ -0,0 +1,343 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: UnlabeledValueArg.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_UNLABELED_VALUE_ARGUMENT_H
#define TCLAP_UNLABELED_VALUE_ARGUMENT_H
#include <string>
#include <vector>
#include <tclap/ValueArg.h>
#include <tclap/OptionalUnlabeledTracker.h>
namespace TCLAP {
/**
* The basic unlabeled argument that parses a value.
* This is a template class, which means the type T defines the type
* that a given object will attempt to parse when an UnlabeledValueArg
* is reached in the list of args that the CmdLine iterates over.
*/
template<class T>
class UnlabeledValueArg : public ValueArg<T>
{
// If compiler has two stage name lookup (as gcc >= 3.4 does)
// this is required to prevent undef. symbols
using ValueArg<T>::_ignoreable;
using ValueArg<T>::_hasBlanks;
using ValueArg<T>::_extractValue;
using ValueArg<T>::_typeDesc;
using ValueArg<T>::_name;
using ValueArg<T>::_description;
using ValueArg<T>::_alreadySet;
using ValueArg<T>::toString;
public:
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Visitor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
bool ignoreable = false,
Visitor* v = NULL);
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Visitor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL );
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Visitor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
bool ignoreable = false,
Visitor* v = NULL );
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Visitor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. Handling specific to
* unlabeled arguments.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings.
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Overrides shortID for specific behavior.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Overrides longID for specific behavior.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Overrides operator== for specific behavior.
*/
virtual bool operator==(const Arg& a ) const;
/**
* Instead of pushing to the front of list, push to the back.
* \param argList - The list to add this to.
*/
virtual void addToList( std::list<Arg*>& argList ) const;
};
/**
* Constructor implementation.
*/
template<class T>
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
const std::string& desc,
bool req,
T val,
const std::string& typeDesc,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, typeDesc, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
}
template<class T>
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
const std::string& desc,
bool req,
T val,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, typeDesc, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
parser.add( this );
}
/**
* Constructor implementation.
*/
template<class T>
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
const std::string& desc,
bool req,
T val,
Constraint<T>* constraint,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, constraint, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
}
template<class T>
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
const std::string& desc,
bool req,
T val,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, constraint, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
parser.add( this );
}
/**
* Implementation of processArg().
*/
template<class T>
bool UnlabeledValueArg<T>::processArg(int *i, std::vector<std::string>& args)
{
if ( _alreadySet )
return false;
if ( _hasBlanks( args[*i] ) )
return false;
// never ignore an unlabeled arg
_extractValue( args[*i] );
_alreadySet = true;
return true;
}
/**
* Overriding shortID for specific output.
*/
template<class T>
std::string UnlabeledValueArg<T>::shortID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return std::string("<") + _typeDesc + ">";
}
/**
* Overriding longID for specific output.
*/
template<class T>
std::string UnlabeledValueArg<T>::longID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
// Ideally we would like to be able to use RTTI to return the name
// of the type required for this argument. However, g++ at least,
// doesn't appear to return terribly useful "names" of the types.
return std::string("<") + _typeDesc + ">";
}
/**
* Overriding operator== for specific behavior.
*/
template<class T>
bool UnlabeledValueArg<T>::operator==(const Arg& a ) const
{
if ( _name == a.getName() || _description == a.getDescription() )
return true;
else
return false;
}
template<class T>
void UnlabeledValueArg<T>::addToList( std::list<Arg*>& argList ) const
{
argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
}
}
#endif

View File

@@ -0,0 +1,430 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: ValueArg.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_VALUE_ARGUMENT_H
#define TCLAP_VALUE_ARGUMENT_H
#include <string>
#include <vector>
#include <tclap/Arg.h>
#include <tclap/Constraint.h>
namespace TCLAP {
/**
* The basic labeled argument that parses a value.
* This is a template class, which means the type T defines the type
* that a given object will attempt to parse when the flag/name is matched
* on the command line. While there is nothing stopping you from creating
* an unflagged ValueArg, it is unwise and would cause significant problems.
* Instead use an UnlabeledValueArg.
*/
template<class T>
class ValueArg : public Arg
{
protected:
/**
* The value parsed from the command line.
* Can be of any type, as long as the >> operator for the type
* is defined.
*/
T _value;
/**
* Used to support the reset() method so that ValueArg can be
* reset to their constructed value.
*/
T _default;
/**
* A human readable description of the type to be parsed.
* This is a hack, plain and simple. Ideally we would use RTTI to
* return the name of type T, but until there is some sort of
* consistent support for human readable names, we are left to our
* own devices.
*/
std::string _typeDesc;
/**
* A Constraint this Arg must conform to.
*/
Constraint<T>* _constraint;
/**
* Extracts the value from the string.
* Attempts to parse string as type T, if this fails an exception
* is thrown.
* \param val - value to be parsed.
*/
void _extractValue( const std::string& val );
public:
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
Visitor* v = NULL);
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
Visitor* v = NULL );
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed
* in from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Returns the value of the argument.
*/
const T& getValue() const { return _value; }
// TODO(macbishop): Non-const variant is deprecated, don't
// use. Remove in next major.
T& getValue() { return _value; }
/**
* A ValueArg can be used as as its value type (T) This is the
* same as calling getValue()
*/
operator const T&() const { return getValue(); }
/**
* Specialization of shortID.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val = "val") const;
/**
* Specialization of longID.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val = "val") const;
virtual void reset() ;
private:
/**
* Prevent accidental copying
*/
ValueArg(const ValueArg<T>& rhs);
ValueArg& operator=(const ValueArg<T>& rhs);
};
/**
* Constructor implementation.
*/
template<class T>
ValueArg<T>::ValueArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T val,
const std::string& typeDesc,
Visitor* v)
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( typeDesc ),
_constraint( NULL )
{ }
template<class T>
ValueArg<T>::ValueArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T val,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v)
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( typeDesc ),
_constraint( NULL )
{
parser.add( this );
}
template<class T>
ValueArg<T>::ValueArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T val,
Constraint<T>* constraint,
Visitor* v)
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( Constraint<T>::shortID(constraint) ),
_constraint( constraint )
{ }
template<class T>
ValueArg<T>::ValueArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T val,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v)
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( Constraint<T>::shortID(constraint) ), // TODO(macbishop): Will crash
// if constraint is NULL
_constraint( constraint )
{
parser.add( this );
}
/**
* Implementation of processArg().
*/
template<class T>
bool ValueArg<T>::processArg(int *i, std::vector<std::string>& args)
{
if ( _ignoreable && Arg::ignoreRest() )
return false;
if ( _hasBlanks( args[*i] ) )
return false;
std::string flag = args[*i];
std::string value = "";
trimFlag( flag, value );
if ( argMatches( flag ) )
{
if ( _alreadySet )
{
if ( _xorSet )
throw( CmdLineParseException("Mutually exclusive argument"
" already set!", toString()));
else
throw( CmdLineParseException("Argument already set!",
toString()) );
}
if ( Arg::delimiter() != ' ' && value == "" )
throw( ArgParseException("Couldn't find delimiter for this argument!",
toString() ) );
if ( value == "" )
{
(*i)++;
if ( static_cast<unsigned int>(*i) < args.size() )
_extractValue( args[*i] );
else
throw( ArgParseException("Missing a value for this argument!",
toString() ) );
}
else
_extractValue( value );
_alreadySet = true;
_checkWithVisitor();
return true;
}
else
return false;
}
/**
* Implementation of shortID.
*/
template<class T>
std::string ValueArg<T>::shortID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return Arg::shortID( _typeDesc );
}
/**
* Implementation of longID.
*/
template<class T>
std::string ValueArg<T>::longID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return Arg::longID( _typeDesc );
}
template<class T>
void ValueArg<T>::_extractValue( const std::string& val )
{
try {
ExtractValue(_value, val, typename ArgTraits<T>::ValueCategory());
} catch( ArgParseException &e) {
throw ArgParseException(e.error(), toString());
}
if ( _constraint != NULL )
if ( ! _constraint->check( _value ) )
throw( CmdLineParseException( "Value '" + val +
+ "' does not meet constraint: "
+ _constraint->description(),
toString() ) );
}
template<class T>
void ValueArg<T>::reset()
{
Arg::reset();
_value = _default;
}
} // namespace TCLAP
#endif

View File

@@ -0,0 +1,134 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: ValuesConstraint.h
*
* Copyright (c) 2005, Michael E. Smoot
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_VALUESCONSTRAINT_H
#define TCLAP_VALUESCONSTRAINT_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string>
#include <vector>
#include <tclap/Constraint.h>
#include <tclap/sstream.h>
namespace TCLAP {
/**
* A Constraint that constrains the Arg to only those values specified
* in the constraint.
*/
template<class T>
class ValuesConstraint : public Constraint<T>
{
public:
/**
* Constructor.
* \param allowed - vector of allowed values.
*/
ValuesConstraint(std::vector<T>const& allowed);
/**
* Virtual destructor.
*/
virtual ~ValuesConstraint() {}
/**
* Returns a description of the Constraint.
*/
virtual std::string description() const;
/**
* Returns the short ID for the Constraint.
*/
virtual std::string shortID() const;
/**
* The method used to verify that the value parsed from the command
* line meets the constraint.
* \param value - The value that will be checked.
*/
virtual bool check(const T& value) const;
protected:
/**
* The list of valid values.
*/
std::vector<T> _allowed;
/**
* The string used to describe the allowed values of this constraint.
*/
std::string _typeDesc;
};
template<class T>
ValuesConstraint<T>::ValuesConstraint(std::vector<T> const& allowed)
: _allowed(allowed),
_typeDesc("")
{
for ( unsigned int i = 0; i < _allowed.size(); i++ )
{
std::ostringstream os;
os << _allowed[i];
std::string temp( os.str() );
if ( i > 0 )
_typeDesc += "|";
_typeDesc += temp;
}
}
template<class T>
bool ValuesConstraint<T>::check( const T& val ) const
{
if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() )
return false;
else
return true;
}
template<class T>
std::string ValuesConstraint<T>::shortID() const
{
return _typeDesc;
}
template<class T>
std::string ValuesConstraint<T>::description() const
{
return _typeDesc;
}
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,81 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: VersionVisitor.h
*
* Copyright (c) 2003, Michael E. Smoot .
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_VERSION_VISITOR_H
#define TCLAP_VERSION_VISITOR_H
#include <tclap/CmdLineInterface.h>
#include <tclap/CmdLineOutput.h>
#include <tclap/Visitor.h>
namespace TCLAP {
/**
* A Visitor that will call the version method of the given CmdLineOutput
* for the specified CmdLine object and then exit.
*/
class VersionVisitor: public Visitor
{
private:
/**
* Prevent accidental copying
*/
VersionVisitor(const VersionVisitor& rhs);
VersionVisitor& operator=(const VersionVisitor& rhs);
protected:
/**
* The CmdLine of interest.
*/
CmdLineInterface* _cmd;
/**
* The output object.
*/
CmdLineOutput** _out;
public:
/**
* Constructor.
* \param cmd - The CmdLine the output is generated for.
* \param out - The type of output.
*/
VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out )
: Visitor(), _cmd( cmd ), _out( out ) { }
/**
* Calls the version method of the output object using the
* specified CmdLine.
*/
void visit() {
(*_out)->version(*_cmd);
throw ExitException(0);
}
};
}
#endif

View File

@@ -0,0 +1,57 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: Visitor.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2017, Google LLC
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_VISITOR_H
#define TCLAP_VISITOR_H
namespace TCLAP {
/**
* A base class that defines the interface for visitors.
*/
class Visitor
{
public:
/**
* Constructor. Does nothing.
*/
Visitor() { }
/**
* Destructor. Does nothing.
*/
virtual ~Visitor() { }
/**
* This method (to implemented by children) will be
* called when the visitor is visited.
*/
virtual void visit() = 0;
};
}
#endif

View File

@@ -0,0 +1,168 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: XorHandler.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_XORHANDLER_H
#define TCLAP_XORHANDLER_H
#include <tclap/Arg.h>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
namespace TCLAP {
/**
* This class handles lists of Arg's that are to be XOR'd on the command
* line. This is used by CmdLine and you shouldn't ever use it.
*/
class XorHandler
{
protected:
/**
* The list of of lists of Arg's to be or'd together.
*/
std::vector< std::vector<Arg*> > _orList;
public:
/**
* Constructor. Does nothing.
*/
XorHandler( ) : _orList(std::vector< std::vector<Arg*> >()) {}
/**
* Add a list of Arg*'s that will be xor'd together.
* \param ors - list of Arg* that will be xor'd.
*/
void add( const std::vector<Arg*>& ors );
/**
* Checks whether the specified Arg is in one of the xor lists and
* if it does match one, returns the size of the xor list that the
* Arg matched. If the Arg matches, then it also sets the rest of
* the Arg's in the list. You shouldn't use this.
* \param a - The Arg to be checked.
*/
int check( const Arg* a );
/**
* Returns the XOR specific short usage.
*/
std::string shortUsage();
/**
* Prints the XOR specific long usage.
* \param os - Stream to print to.
*/
void printLongUsage(std::ostream& os);
/**
* Simply checks whether the Arg is contained in one of the arg
* lists.
* \param a - The Arg to be checked.
*/
bool contains( const Arg* a );
const std::vector< std::vector<Arg*> >& getXorList() const;
};
//////////////////////////////////////////////////////////////////////
//BEGIN XOR.cpp
//////////////////////////////////////////////////////////////////////
inline void XorHandler::add( const std::vector<Arg*>& ors )
{
_orList.push_back( ors );
}
inline int XorHandler::check( const Arg* a )
{
// iterate over each XOR list
for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
{
// if the XOR list contains the arg..
ArgVectorIterator ait = std::find( _orList[i].begin(),
_orList[i].end(), a );
if ( ait != _orList[i].end() )
{
// first check to see if a mutually exclusive switch
// has not already been set
for ( ArgVectorIterator it = _orList[i].begin();
it != _orList[i].end();
it++ )
if ( a != (*it) && (*it)->isSet() )
throw(CmdLineParseException(
"Mutually exclusive argument already set!",
(*it)->toString()));
// go through and set each arg that is not a
for ( ArgVectorIterator it = _orList[i].begin();
it != _orList[i].end();
it++ )
if ( a != (*it) )
(*it)->xorSet();
// return the number of required args that have now been set
if ( (*ait)->allowMore() )
return 0;
else
return static_cast<int>(_orList[i].size());
}
}
if ( a->isRequired() )
return 1;
else
return 0;
}
inline bool XorHandler::contains( const Arg* a )
{
for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
for ( ArgVectorIterator it = _orList[i].begin();
it != _orList[i].end();
it++ )
if ( a == (*it) )
return true;
return false;
}
inline const std::vector< std::vector<Arg*> >& XorHandler::getXorList() const
{
return _orList;
}
//////////////////////////////////////////////////////////////////////
//END XOR.cpp
//////////////////////////////////////////////////////////////////////
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,336 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: ZshCompletionOutput.h
*
* Copyright (c) 2006, Oliver Kiddle
* Copyright (c) 2017 Google Inc.
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H
#define TCLAP_ZSHCOMPLETIONOUTPUT_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <map>
#include <tclap/CmdLineInterface.h>
#include <tclap/CmdLineOutput.h>
#include <tclap/XorHandler.h>
#include <tclap/Arg.h>
#include <tclap/sstream.h>
namespace TCLAP {
/**
* A class that generates a Zsh completion function as output from the usage()
* method for the given CmdLine and its Args.
*/
class ZshCompletionOutput : public CmdLineOutput
{
public:
ZshCompletionOutput();
/**
* Prints the usage to stdout. Can be overridden to
* produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c);
/**
* Prints the version to stdout. Can be overridden
* to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c);
/**
* Prints (to stderr) an error message, short usage
* Can be overridden to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure(CmdLineInterface& c,
ArgException& e );
protected:
void basename( std::string& s );
void quoteSpecialChars( std::string& s );
std::string getMutexList( CmdLineInterface& _cmd, Arg* a );
void printOption( Arg* it, std::string mutex );
void printArg( Arg* it );
std::map<std::string, std::string> common;
char theDelimiter;
};
ZshCompletionOutput::ZshCompletionOutput()
: common(std::map<std::string, std::string>()),
theDelimiter('=')
{
common["host"] = "_hosts";
common["hostname"] = "_hosts";
common["file"] = "_files";
common["filename"] = "_files";
common["user"] = "_users";
common["username"] = "_users";
common["directory"] = "_directories";
common["path"] = "_directories";
common["url"] = "_urls";
}
inline void ZshCompletionOutput::version(CmdLineInterface& _cmd)
{
std::cout << _cmd.getVersion() << std::endl;
}
inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd )
{
std::list<Arg*> argList = _cmd.getArgList();
std::string progName = _cmd.getProgramName();
std::string xversion = _cmd.getVersion();
theDelimiter = _cmd.getDelimiter();
basename(progName);
std::cout << "#compdef " << progName << std::endl << std::endl <<
"# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl <<
"_arguments -s -S";
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
{
if ( (*it)->shortID().at(0) == '<' )
printArg((*it));
else if ( (*it)->getFlag() != "-" )
printOption((*it), getMutexList(_cmd, *it));
}
std::cout << std::endl;
}
inline void ZshCompletionOutput::failure( CmdLineInterface& _cmd,
ArgException& e )
{
static_cast<void>(_cmd); // unused
std::cout << e.what() << std::endl;
}
inline void ZshCompletionOutput::quoteSpecialChars( std::string& s )
{
size_t idx = s.find_last_of(':');
while ( idx != std::string::npos )
{
s.insert(idx, 1, '\\');
idx = s.find_last_of(':', idx);
}
idx = s.find_last_of('\'');
while ( idx != std::string::npos )
{
s.insert(idx, "'\\'");
if (idx == 0)
idx = std::string::npos;
else
idx = s.find_last_of('\'', --idx);
}
}
inline void ZshCompletionOutput::basename( std::string& s )
{
size_t p = s.find_last_of('/');
if ( p != std::string::npos )
{
s.erase(0, p + 1);
}
}
inline void ZshCompletionOutput::printArg(Arg* a)
{
static int count = 1;
std::cout << " \\" << std::endl << " '";
if ( a->acceptsMultipleValues() )
std::cout << '*';
else
std::cout << count++;
std::cout << ':';
if ( !a->isRequired() )
std::cout << ':';
std::cout << a->getName() << ':';
std::map<std::string, std::string>::iterator compArg = common.find(a->getName());
if ( compArg != common.end() )
{
std::cout << compArg->second;
}
else
{
std::cout << "_guard \"^-*\" " << a->getName();
}
std::cout << '\'';
}
inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex)
{
std::string flag = a->flagStartChar() + a->getFlag();
std::string name = a->nameStartString() + a->getName();
std::string desc = a->getDescription();
// remove full stop and capitalization from description as
// this is the convention for zsh function
if (!desc.compare(0, 12, "(required) "))
{
desc.erase(0, 12);
}
if (!desc.compare(0, 15, "(OR required) "))
{
desc.erase(0, 15);
}
size_t len = desc.length();
if (len && desc.at(--len) == '.')
{
desc.erase(len);
}
if (len)
{
desc.replace(0, 1, 1, tolower(desc.at(0)));
}
std::cout << " \\" << std::endl << " '" << mutex;
if ( a->getFlag().empty() )
{
std::cout << name;
}
else
{
std::cout << "'{" << flag << ',' << name << "}'";
}
if ( theDelimiter == '=' && a->isValueRequired() )
std::cout << "=-";
quoteSpecialChars(desc);
std::cout << '[' << desc << ']';
if ( a->isValueRequired() )
{
std::string arg = a->shortID();
// Example arg: "[-A <integer>] ..."
size_t pos = arg.rfind(" ...");
if (pos != std::string::npos) {
arg.erase(pos);
}
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
if ( arg.at(arg.length()-1) == ']' )
arg.erase(arg.length()-1);
if ( arg.at(arg.length()-1) == ']' )
{
arg.erase(arg.length()-1);
}
if ( arg.at(0) == '<' )
{
arg.erase(arg.length()-1);
arg.erase(0, 1);
}
size_t p = arg.find('|');
if ( p != std::string::npos )
{
do
{
arg.replace(p, 1, 1, ' ');
}
while ( (p = arg.find_first_of('|', p)) != std::string::npos );
quoteSpecialChars(arg);
std::cout << ": :(" << arg << ')';
}
else
{
std::cout << ':' << arg;
std::map<std::string, std::string>::iterator compArg = common.find(arg);
if ( compArg != common.end() )
{
std::cout << ':' << compArg->second;
}
}
}
std::cout << '\'';
}
inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a)
{
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
if (a->getName() == "help" || a->getName() == "version")
{
return "(-)";
}
ostringstream list;
if ( a->acceptsMultipleValues() )
{
list << '*';
}
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
{
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end();
it++)
if ( a == (*it) )
{
list << '(';
for ( ArgVectorIterator iu = xorList[i].begin();
iu != xorList[i].end();
iu++ )
{
bool notCur = (*iu) != a;
bool hasFlag = !(*iu)->getFlag().empty();
if ( iu != xorList[i].begin() && (notCur || hasFlag) )
list << ' ';
if (hasFlag)
list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' ';
if ( notCur || hasFlag )
list << (*iu)->nameStartString() << (*iu)->getName();
}
list << ')';
return list.str();
}
}
// wasn't found in xor list
if (!a->getFlag().empty()) {
list << "(" << a->flagStartChar() << a->getFlag() << ' ' <<
a->nameStartString() << a->getName() << ')';
}
return list.str();
}
} //namespace TCLAP
#endif

View File

@@ -0,0 +1,50 @@
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
/******************************************************************************
*
* file: sstream.h
*
* Copyright (c) 2003, Michael E. Smoot .
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno .
* Copyright (c) 2017 Google Inc.
* All rights reserved.
*
* See the file COPYING in the top directory of this distribution for
* more information.
*
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
#ifndef TCLAP_SSTREAM_H
#define TCLAP_SSTREAM_H
#if !defined(HAVE_STRSTREAM)
// Assume sstream is available if strstream is not specified
// (https://sourceforge.net/p/tclap/bugs/23/)
#define HAVE_SSTREAM
#endif
#if defined(HAVE_SSTREAM)
#include <sstream>
namespace TCLAP {
typedef std::istringstream istringstream;
typedef std::ostringstream ostringstream;
}
#elif defined(HAVE_STRSTREAM)
#include <strstream>
namespace TCLAP {
typedef std::istrstream istringstream;
typedef std::ostrstream ostringstream;
}
#else
#error "Need a stringstream (sstream or strstream) to compile!"
#endif
#endif // TCLAP_SSTREAM_H

View File

@@ -0,0 +1,85 @@
# ONNXRuntime-cpp
## Export the model
### Install [modelscope and funasr](https://github.com/alibaba-damo-academy/FunASR#installation)
```shell
# pip3 install torch torchaudio
pip install -U modelscope funasr
# For the users in China, you could install with the command:
# pip install -U modelscope funasr -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html -i https://mirror.sjtu.edu.cn/pypi/web/simple
```
### Export [onnx model](https://github.com/alibaba-damo-academy/FunASR/tree/main/funasr/export)
```shell
python -m funasr.export.export_model --model-name damo/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch --export-dir ./export --type onnx --quantize True
```
## Building for Linux/Unix
### Download onnxruntime
```shell
# download an appropriate onnxruntime from https://github.com/microsoft/onnxruntime/releases/tag/v1.14.0
# here we get a copy of onnxruntime for linux 64
wget https://github.com/microsoft/onnxruntime/releases/download/v1.14.0/onnxruntime-linux-x64-1.14.0.tgz
tar -zxvf onnxruntime-linux-x64-1.14.0.tgz
```
### Install openblas
```shell
sudo apt-get install libopenblas-dev #ubuntu
# sudo yum -y install openblas-devel #centos
```
### Build runtime
```shell
git clone https://github.com/alibaba-damo-academy/FunASR.git && cd funasr/runtime/onnxruntime
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=release .. -DONNXRUNTIME_DIR=/path/to/onnxruntime-linux-x64-1.14.0
make
```
## Run the demo
```shell
./funasr-onnx-offline [--wav-scp <string>] [--wav-path <string>]
[--punc-config <string>] [--punc-model <string>]
--am-config <string> --am-cmvn <string>
--am-model <string> [--vad-config <string>]
[--vad-cmvn <string>] [--vad-model <string>] [--]
[--version] [-h]
Where:
--wav-scp <string>
wave scp path
--wav-path <string>
wave file path
--punc-config <string>
punc config path
--punc-model <string>
punc model path
--am-config <string>
(required) am config path
--am-cmvn <string>
(required) am cmvn path
--am-model <string>
(required) am model path
--vad-config <string>
vad config path
--vad-cmvn <string>
vad cmvn path
--vad-model <string>
vad model path
Required: --am-config <string> --am-cmvn <string> --am-model <string>
If use vad, please add: [--vad-config <string>] [--vad-cmvn <string>] [--vad-model <string>]
If use punc, please add: [--punc-config <string>] [--punc-model <string>]
```
## Acknowledge
1. This project is maintained by [FunASR community](https://github.com/alibaba-damo-academy/FunASR).
2. We acknowledge mayong for contributing the onnxruntime of Paraformer and CT_Transformer, [repo-asr](https://github.com/RapidAI/RapidASR/tree/main/cpp_onnx), [repo-punc](https://github.com/RapidAI/RapidPunc).
3. We acknowledge [ChinaTelecom](https://github.com/zhuzizyf/damo-fsmn-vad-infer-httpserver) for contributing the VAD runtime.
4. We borrowed a lot of code from [FastASR](https://github.com/chenkui164/FastASR) for audio frontend and text-postprocess.

View File

@@ -0,0 +1,31 @@
file(GLOB files1 "*.cpp")
file(GLOB files2 "*.cc")
set(files ${files1} ${files2})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_library(funasr ${files})
if(WIN32)
set(EXTRA_LIBS pthread yaml-cpp csrc glog)
if(CMAKE_CL_64)
target_link_directories(funasr PUBLIC ${CMAKE_SOURCE_DIR}/win/lib/x64)
else()
target_link_directories(funasr PUBLIC ${CMAKE_SOURCE_DIR}/win/lib/x86)
endif()
target_include_directories(funasr PUBLIC ${CMAKE_SOURCE_DIR}/win/include )
target_compile_definitions(funasr PUBLIC -D_FUNASR_API_EXPORT)
else()
set(EXTRA_LIBS pthread yaml-cpp csrc glog )
include_directories(${ONNXRUNTIME_DIR}/include)
endif()
include_directories(${CMAKE_SOURCE_DIR}/include)
target_link_libraries(funasr PUBLIC onnxruntime ${EXTRA_LIBS})
add_executable(funasr-onnx-offline "funasr-onnx-offline.cpp")
add_executable(funasr-onnx-offline-rtf "funasr-onnx-offline-rtf.cpp")
target_link_libraries(funasr-onnx-offline PUBLIC funasr)
target_link_libraries(funasr-onnx-offline-rtf PUBLIC funasr)

View File

@@ -0,0 +1,18 @@
#include "precomp.h"
void *AlignedMalloc(size_t alignment, size_t required_bytes)
{
void *p1; // original block
void **p2; // aligned block
int offset = alignment - 1 + sizeof(void *);
if ((p1 = (void *)malloc(required_bytes + offset)) == NULL) {
return NULL;
}
p2 = (void **)(((size_t)(p1) + offset) & ~(alignment - 1));
p2[-1] = p1;
return p2;
}
void AlignedFree(void *p)
{
free(((void **)p)[-1]);
}

View File

@@ -0,0 +1,8 @@
#ifndef ALIGNEDMEM_H
#define ALIGNEDMEM_H
extern void *AlignedMalloc(size_t alignment, size_t required_bytes);
extern void AlignedFree(void *p);
#endif

View File

@@ -0,0 +1,522 @@
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <assert.h>
#include "audio.h"
#include "precomp.h"
using namespace std;
// see http://soundfile.sapp.org/doc/WaveFormat/
// Note: We assume little endian here
struct WaveHeader {
bool Validate() const {
// F F I R
if (chunk_id != 0x46464952) {
printf("Expected chunk_id RIFF. Given: 0x%08x\n", chunk_id);
return false;
}
// E V A W
if (format != 0x45564157) {
printf("Expected format WAVE. Given: 0x%08x\n", format);
return false;
}
if (subchunk1_id != 0x20746d66) {
printf("Expected subchunk1_id 0x20746d66. Given: 0x%08x\n",
subchunk1_id);
return false;
}
if (subchunk1_size != 16) { // 16 for PCM
printf("Expected subchunk1_size 16. Given: %d\n",
subchunk1_size);
return false;
}
if (audio_format != 1) { // 1 for PCM
printf("Expected audio_format 1. Given: %d\n", audio_format);
return false;
}
if (num_channels != 1) { // we support only single channel for now
printf("Expected single channel. Given: %d\n", num_channels);
return false;
}
if (byte_rate != (sample_rate * num_channels * bits_per_sample / 8)) {
return false;
}
if (block_align != (num_channels * bits_per_sample / 8)) {
return false;
}
if (bits_per_sample != 16) { // we support only 16 bits per sample
printf("Expected bits_per_sample 16. Given: %d\n",
bits_per_sample);
return false;
}
return true;
}
// See https://en.wikipedia.org/wiki/WAV#Metadata and
// https://www.robotplanet.dk/audio/wav_meta_data/riff_mci.pdf
void SeekToDataChunk(std::istream &is) {
// a t a d
while (is && subchunk2_id != 0x61746164) {
// const char *p = reinterpret_cast<const char *>(&subchunk2_id);
// printf("Skip chunk (%x): %c%c%c%c of size: %d\n", subchunk2_id, p[0],
// p[1], p[2], p[3], subchunk2_size);
is.seekg(subchunk2_size, std::istream::cur);
is.read(reinterpret_cast<char *>(&subchunk2_id), sizeof(int32_t));
is.read(reinterpret_cast<char *>(&subchunk2_size), sizeof(int32_t));
}
}
int32_t chunk_id;
int32_t chunk_size;
int32_t format;
int32_t subchunk1_id;
int32_t subchunk1_size;
int16_t audio_format;
int16_t num_channels;
int32_t sample_rate;
int32_t byte_rate;
int16_t block_align;
int16_t bits_per_sample;
int32_t subchunk2_id; // a tag of this chunk
int32_t subchunk2_size; // size of subchunk2
};
static_assert(sizeof(WaveHeader) == WAV_HEADER_SIZE, "");
class AudioWindow {
private:
int *window;
int in_idx;
int out_idx;
int sum;
int window_size = 0;
public:
AudioWindow(int window_size) : window_size(window_size)
{
window = (int *)calloc(sizeof(int), window_size + 1);
in_idx = 0;
out_idx = 1;
sum = 0;
};
~AudioWindow(){
free(window);
};
int put(int val)
{
sum = sum + val - window[out_idx];
window[in_idx] = val;
in_idx = in_idx == window_size ? 0 : in_idx + 1;
out_idx = out_idx == window_size ? 0 : out_idx + 1;
return sum;
};
};
AudioFrame::AudioFrame(){};
AudioFrame::AudioFrame(int len) : len(len)
{
start = 0;
};
AudioFrame::~AudioFrame(){};
int AudioFrame::SetStart(int val)
{
start = val < 0 ? 0 : val;
return start;
};
int AudioFrame::SetEnd(int val)
{
end = val;
len = end - start;
return end;
};
int AudioFrame::GetStart()
{
return start;
};
int AudioFrame::GetLen()
{
return len;
};
int AudioFrame::Disp()
{
LOG(ERROR) << "Not imp!!!!";
return 0;
};
Audio::Audio(int data_type) : data_type(data_type)
{
speech_buff = NULL;
speech_data = NULL;
align_size = 1360;
}
Audio::Audio(int data_type, int size) : data_type(data_type)
{
speech_buff = NULL;
speech_data = NULL;
align_size = (float)size;
}
Audio::~Audio()
{
if (speech_buff != NULL) {
free(speech_buff);
}
if (speech_data != NULL) {
free(speech_data);
}
}
void Audio::Disp()
{
LOG(INFO) << "Audio time is " << (float)speech_len / MODEL_SAMPLE_RATE << " s. len is " << speech_len;
}
float Audio::GetTimeLen()
{
return (float)speech_len / MODEL_SAMPLE_RATE;
}
void Audio::WavResample(int32_t sampling_rate, const float *waveform,
int32_t n)
{
LOG(INFO) << "Creating a resampler:\n"
<< " in_sample_rate: "<< sampling_rate << "\n"
<< " output_sample_rate: " << static_cast<int32_t>(MODEL_SAMPLE_RATE);
float min_freq =
std::min<int32_t>(sampling_rate, MODEL_SAMPLE_RATE);
float lowpass_cutoff = 0.99 * 0.5 * min_freq;
int32_t lowpass_filter_width = 6;
auto resampler = std::make_unique<LinearResample>(
sampling_rate, MODEL_SAMPLE_RATE, lowpass_cutoff, lowpass_filter_width);
std::vector<float> samples;
resampler->Resample(waveform, n, true, &samples);
//reset speech_data
speech_len = samples.size();
if (speech_data != NULL) {
free(speech_data);
}
speech_data = (float*)malloc(sizeof(float) * speech_len);
memset(speech_data, 0, sizeof(float) * speech_len);
copy(samples.begin(), samples.end(), speech_data);
}
bool Audio::LoadWav(const char *filename, int32_t* sampling_rate)
{
WaveHeader header;
if (speech_data != NULL) {
free(speech_data);
}
if (speech_buff != NULL) {
free(speech_buff);
}
offset = 0;
std::ifstream is(filename, std::ifstream::binary);
is.read(reinterpret_cast<char *>(&header), sizeof(header));
if(!is){
LOG(ERROR) << "Failed to read " << filename;
return false;
}
*sampling_rate = header.sample_rate;
// header.subchunk2_size contains the number of bytes in the data.
// As we assume each sample contains two bytes, so it is divided by 2 here
speech_len = header.subchunk2_size / 2;
speech_buff = (int16_t *)malloc(sizeof(int16_t) * speech_len);
if (speech_buff)
{
memset(speech_buff, 0, sizeof(int16_t) * speech_len);
is.read(reinterpret_cast<char *>(speech_buff), header.subchunk2_size);
if (!is) {
LOG(ERROR) << "Failed to read " << filename;
return false;
}
speech_data = (float*)malloc(sizeof(float) * speech_len);
memset(speech_data, 0, sizeof(float) * speech_len);
float scale = 1;
if (data_type == 1) {
scale = 32768;
}
for (int32_t i = 0; i != speech_len; ++i) {
speech_data[i] = (float)speech_buff[i] / scale;
}
//resample
if(*sampling_rate != MODEL_SAMPLE_RATE){
WavResample(*sampling_rate, speech_data, speech_len);
}
AudioFrame* frame = new AudioFrame(speech_len);
frame_queue.push(frame);
return true;
}
else
return false;
}
bool Audio::LoadWav(const char* buf, int n_file_len, int32_t* sampling_rate)
{
WaveHeader header;
if (speech_data != NULL) {
free(speech_data);
}
if (speech_buff != NULL) {
free(speech_buff);
}
offset = 0;
std::memcpy(&header, buf, sizeof(header));
*sampling_rate = header.sample_rate;
speech_len = header.subchunk2_size / 2;
speech_buff = (int16_t *)malloc(sizeof(int16_t) * speech_len);
if (speech_buff)
{
memset(speech_buff, 0, sizeof(int16_t) * speech_len);
memcpy((void*)speech_buff, (const void*)(buf + WAV_HEADER_SIZE), speech_len * sizeof(int16_t));
speech_data = (float*)malloc(sizeof(float) * speech_len);
memset(speech_data, 0, sizeof(float) * speech_len);
float scale = 1;
if (data_type == 1) {
scale = 32768;
}
for (int32_t i = 0; i != speech_len; ++i) {
speech_data[i] = (float)speech_buff[i] / scale;
}
//resample
if(*sampling_rate != MODEL_SAMPLE_RATE){
WavResample(*sampling_rate, speech_data, speech_len);
}
AudioFrame* frame = new AudioFrame(speech_len);
frame_queue.push(frame);
return true;
}
else
return false;
}
bool Audio::LoadPcmwav(const char* buf, int n_buf_len, int32_t* sampling_rate)
{
if (speech_data != NULL) {
free(speech_data);
}
if (speech_buff != NULL) {
free(speech_buff);
}
offset = 0;
speech_len = n_buf_len / 2;
speech_buff = (int16_t*)malloc(sizeof(int16_t) * speech_len);
if (speech_buff)
{
memset(speech_buff, 0, sizeof(int16_t) * speech_len);
memcpy((void*)speech_buff, (const void*)buf, speech_len * sizeof(int16_t));
speech_data = (float*)malloc(sizeof(float) * speech_len);
memset(speech_data, 0, sizeof(float) * speech_len);
float scale = 1;
if (data_type == 1) {
scale = 32768;
}
for (int32_t i = 0; i != speech_len; ++i) {
speech_data[i] = (float)speech_buff[i] / scale;
}
//resample
if(*sampling_rate != MODEL_SAMPLE_RATE){
WavResample(*sampling_rate, speech_data, speech_len);
}
AudioFrame* frame = new AudioFrame(speech_len);
frame_queue.push(frame);
return true;
}
else
return false;
}
bool Audio::LoadPcmwav(const char* filename, int32_t* sampling_rate)
{
if (speech_data != NULL) {
free(speech_data);
}
if (speech_buff != NULL) {
free(speech_buff);
}
offset = 0;
FILE* fp;
fp = fopen(filename, "rb");
if (fp == nullptr)
{
LOG(ERROR) << "Failed to read " << filename;
return false;
}
fseek(fp, 0, SEEK_END);
uint32_t n_file_len = ftell(fp);
fseek(fp, 0, SEEK_SET);
speech_len = (n_file_len) / 2;
speech_buff = (int16_t*)malloc(sizeof(int16_t) * speech_len);
if (speech_buff)
{
memset(speech_buff, 0, sizeof(int16_t) * speech_len);
int ret = fread(speech_buff, sizeof(int16_t), speech_len, fp);
fclose(fp);
speech_data = (float*)malloc(sizeof(float) * speech_len);
memset(speech_data, 0, sizeof(float) * speech_len);
float scale = 1;
if (data_type == 1) {
scale = 32768;
}
for (int32_t i = 0; i != speech_len; ++i) {
speech_data[i] = (float)speech_buff[i] / scale;
}
//resample
if(*sampling_rate != MODEL_SAMPLE_RATE){
WavResample(*sampling_rate, speech_data, speech_len);
}
AudioFrame* frame = new AudioFrame(speech_len);
frame_queue.push(frame);
return true;
}
else
return false;
}
int Audio::FetchChunck(float *&dout, int len)
{
if (offset >= speech_align_len) {
dout = NULL;
return S_ERR;
} else if (offset == speech_align_len - len) {
dout = speech_data + offset;
offset = speech_align_len;
// 临时解决
AudioFrame *frame = frame_queue.front();
frame_queue.pop();
delete frame;
return S_END;
} else {
dout = speech_data + offset;
offset += len;
return S_MIDDLE;
}
}
int Audio::Fetch(float *&dout, int &len, int &flag)
{
if (frame_queue.size() > 0) {
AudioFrame *frame = frame_queue.front();
frame_queue.pop();
dout = speech_data + frame->GetStart();
len = frame->GetLen();
delete frame;
flag = S_END;
return 1;
} else {
return 0;
}
}
void Audio::Padding()
{
float num_samples = speech_len;
float frame_length = 400;
float frame_shift = 160;
float num_frames = floor((num_samples + (frame_shift / 2)) / frame_shift);
float num_new_samples = (num_frames - 1) * frame_shift + frame_length;
float num_padding = num_new_samples - num_samples;
float num_left_padding = (frame_length - frame_shift) / 2;
float num_right_padding = num_padding - num_left_padding;
float *new_data = (float *)malloc(num_new_samples * sizeof(float));
int i;
int tmp_off = 0;
for (i = 0; i < num_left_padding; i++) {
int ii = num_left_padding - i - 1;
new_data[i] = speech_data[ii];
}
tmp_off = num_left_padding;
memcpy(new_data + tmp_off, speech_data, speech_len * sizeof(float));
tmp_off += speech_len;
for (i = 0; i < num_right_padding; i++) {
int ii = speech_len - i - 1;
new_data[tmp_off + i] = speech_data[ii];
}
free(speech_data);
speech_data = new_data;
speech_len = num_new_samples;
AudioFrame *frame = new AudioFrame(num_new_samples);
frame_queue.push(frame);
frame = frame_queue.front();
frame_queue.pop();
delete frame;
}
void Audio::Split(Model* recog_obj)
{
AudioFrame *frame;
frame = frame_queue.front();
frame_queue.pop();
int sp_len = frame->GetLen();
delete frame;
frame = NULL;
std::vector<float> pcm_data(speech_data, speech_data+sp_len);
vector<std::vector<int>> vad_segments = recog_obj->VadSeg(pcm_data);
int seg_sample = MODEL_SAMPLE_RATE/1000;
for(vector<int> segment:vad_segments)
{
frame = new AudioFrame();
int start = segment[0]*seg_sample;
int end = segment[1]*seg_sample;
frame->SetStart(start);
frame->SetEnd(end);
frame_queue.push(frame);
frame = NULL;
}
}

View File

@@ -0,0 +1,6 @@
#ifndef COMMONSTRUCT_H
#define COMMONSTRUCT_H
#endif

View File

@@ -0,0 +1,54 @@
#pragma once
#include <algorithm>
typedef struct
{
std::string msg;
float snippet_time;
}FUNASR_RECOG_RESULT;
#ifdef _WIN32
#include <codecvt>
inline std::wstring String2wstring(const std::string& str, const std::string& locale)
{
typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> F;
std::wstring_convert<F> strCnv(new F(locale));
return strCnv.from_bytes(str);
}
inline std::wstring StrToWstr(std::string str) {
if (str.length() == 0)
return L"";
return String2wstring(str, "zh-CN");
}
#endif
inline void GetInputName(Ort::Session* session, string& inputName,int nIndex=0) {
size_t numInputNodes = session->GetInputCount();
if (numInputNodes > 0) {
Ort::AllocatorWithDefaultOptions allocator;
{
auto t = session->GetInputNameAllocated(nIndex, allocator);
inputName = t.get();
}
}
}
inline void GetOutputName(Ort::Session* session, string& outputName, int nIndex = 0) {
size_t numOutputNodes = session->GetOutputCount();
if (numOutputNodes > 0) {
Ort::AllocatorWithDefaultOptions allocator;
{
auto t = session->GetOutputNameAllocated(nIndex, allocator);
outputName = t.get();
}
}
}
template <class ForwardIterator>
inline static size_t Argmax(ForwardIterator first, ForwardIterator last) {
return std::distance(first, std::max_element(first, last));
}

View File

@@ -0,0 +1,187 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#include "precomp.h"
CTTransformer::CTTransformer()
:env_(ORT_LOGGING_LEVEL_ERROR, ""),session_options{}
{
}
void CTTransformer::InitPunc(const std::string &punc_model, const std::string &punc_config, int thread_num){
session_options.SetIntraOpNumThreads(thread_num);
session_options.SetGraphOptimizationLevel(ORT_ENABLE_ALL);
session_options.DisableCpuMemArena();
try{
m_session = std::make_unique<Ort::Session>(env_, punc_model.c_str(), session_options);
}
catch (std::exception const &e) {
LOG(ERROR) << "Error when load punc onnx model: " << e.what();
exit(0);
}
// read inputnames outputnames
string strName;
GetInputName(m_session.get(), strName);
m_strInputNames.push_back(strName.c_str());
GetInputName(m_session.get(), strName, 1);
m_strInputNames.push_back(strName);
GetOutputName(m_session.get(), strName);
m_strOutputNames.push_back(strName);
for (auto& item : m_strInputNames)
m_szInputNames.push_back(item.c_str());
for (auto& item : m_strOutputNames)
m_szOutputNames.push_back(item.c_str());
m_tokenizer.OpenYaml(punc_config.c_str());
}
CTTransformer::~CTTransformer()
{
}
string CTTransformer::AddPunc(const char* sz_input)
{
string strResult;
vector<string> strOut;
vector<int> InputData;
m_tokenizer.Tokenize(sz_input, strOut, InputData);
int nTotalBatch = ceil((float)InputData.size() / TOKEN_LEN);
int nCurBatch = -1;
int nSentEnd = -1, nLastCommaIndex = -1;
vector<int64_t> RemainIDs; //
vector<string> RemainStr; //
vector<int> NewPunctuation; //
vector<string> NewString; //
vector<string> NewSentenceOut;
vector<int> NewPuncOut;
int nDiff = 0;
for (size_t i = 0; i < InputData.size(); i += TOKEN_LEN)
{
nDiff = (i + TOKEN_LEN) < InputData.size() ? (0) : (i + TOKEN_LEN - InputData.size());
vector<int64_t> InputIDs(InputData.begin() + i, InputData.begin() + i + TOKEN_LEN - nDiff);
vector<string> InputStr(strOut.begin() + i, strOut.begin() + i + TOKEN_LEN - nDiff);
InputIDs.insert(InputIDs.begin(), RemainIDs.begin(), RemainIDs.end()); // RemainIDs+InputIDs;
InputStr.insert(InputStr.begin(), RemainStr.begin(), RemainStr.end()); // RemainStr+InputStr;
auto Punction = Infer(InputIDs);
nCurBatch = i / TOKEN_LEN;
if (nCurBatch < nTotalBatch - 1) // not the last minisetence
{
nSentEnd = -1;
nLastCommaIndex = -1;
for (int nIndex = Punction.size() - 2; nIndex > 0; nIndex--)
{
if (m_tokenizer.Id2Punc(Punction[nIndex]) == m_tokenizer.Id2Punc(PERIOD_INDEX) || m_tokenizer.Id2Punc(Punction[nIndex]) == m_tokenizer.Id2Punc(QUESTION_INDEX))
{
nSentEnd = nIndex;
break;
}
if (nLastCommaIndex < 0 && m_tokenizer.Id2Punc(Punction[nIndex]) == m_tokenizer.Id2Punc(COMMA_INDEX))
{
nLastCommaIndex = nIndex;
}
}
if (nSentEnd < 0 && InputStr.size() > CACHE_POP_TRIGGER_LIMIT && nLastCommaIndex > 0)
{
nSentEnd = nLastCommaIndex;
Punction[nSentEnd] = PERIOD_INDEX;
}
RemainStr.assign(InputStr.begin() + nSentEnd + 1, InputStr.end());
RemainIDs.assign(InputIDs.begin() + nSentEnd + 1, InputIDs.end());
InputStr.assign(InputStr.begin(), InputStr.begin() + nSentEnd + 1); // minit_sentence
Punction.assign(Punction.begin(), Punction.begin() + nSentEnd + 1);
}
NewPunctuation.insert(NewPunctuation.end(), Punction.begin(), Punction.end());
vector<string> WordWithPunc;
for (int i = 0; i < InputStr.size(); i++)
{
if (i > 0 && !(InputStr[i][0] & 0x80) && (i + 1) <InputStr.size() && !(InputStr[i+1][0] & 0x80))// <20>м<EFBFBD><D0BC>Ӣ<EFBFBD>ģ<EFBFBD>
{
InputStr[i] = InputStr[i]+ " ";
}
WordWithPunc.push_back(InputStr[i]);
if (Punction[i] != NOTPUNC_INDEX) // <20>»<EFBFBD><C2BB><EFBFBD>
{
WordWithPunc.push_back(m_tokenizer.Id2Punc(Punction[i]));
}
}
NewString.insert(NewString.end(), WordWithPunc.begin(), WordWithPunc.end()); // new_mini_sentence += "".join(words_with_punc)
NewSentenceOut = NewString;
NewPuncOut = NewPunctuation;
// last mini sentence
if(nCurBatch == nTotalBatch - 1)
{
if (NewString[NewString.size() - 1] == m_tokenizer.Id2Punc(COMMA_INDEX) || NewString[NewString.size() - 1] == m_tokenizer.Id2Punc(DUN_INDEX))
{
NewSentenceOut.assign(NewString.begin(), NewString.end() - 1);
NewSentenceOut.push_back(m_tokenizer.Id2Punc(PERIOD_INDEX));
NewPuncOut.assign(NewPunctuation.begin(), NewPunctuation.end() - 1);
NewPuncOut.push_back(PERIOD_INDEX);
}
else if (NewString[NewString.size() - 1] == m_tokenizer.Id2Punc(PERIOD_INDEX) && NewString[NewString.size() - 1] == m_tokenizer.Id2Punc(QUESTION_INDEX))
{
NewSentenceOut = NewString;
NewSentenceOut.push_back(m_tokenizer.Id2Punc(PERIOD_INDEX));
NewPuncOut = NewPunctuation;
NewPuncOut.push_back(PERIOD_INDEX);
}
}
}
for (auto& item : NewSentenceOut)
strResult += item;
return strResult;
}
vector<int> CTTransformer::Infer(vector<int64_t> input_data)
{
Ort::MemoryInfo m_memoryInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
vector<int> punction;
std::array<int64_t, 2> input_shape_{ 1, (int64_t)input_data.size()};
Ort::Value onnx_input = Ort::Value::CreateTensor<int64_t>(m_memoryInfo,
input_data.data(),
input_data.size(),
input_shape_.data(),
input_shape_.size());
std::array<int32_t,1> text_lengths{ (int32_t)input_data.size() };
std::array<int64_t,1> text_lengths_dim{ 1 };
Ort::Value onnx_text_lengths = Ort::Value::CreateTensor(
m_memoryInfo,
text_lengths.data(),
text_lengths.size() * sizeof(int32_t),
text_lengths_dim.data(),
text_lengths_dim.size(), ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32);
std::vector<Ort::Value> input_onnx;
input_onnx.emplace_back(std::move(onnx_input));
input_onnx.emplace_back(std::move(onnx_text_lengths));
try {
auto outputTensor = m_session->Run(Ort::RunOptions{nullptr}, m_szInputNames.data(), input_onnx.data(), m_szInputNames.size(), m_szOutputNames.data(), m_szOutputNames.size());
std::vector<int64_t> outputShape = outputTensor[0].GetTensorTypeAndShapeInfo().GetShape();
int64_t outputCount = std::accumulate(outputShape.begin(), outputShape.end(), 1, std::multiplies<int64_t>());
float * floatData = outputTensor[0].GetTensorMutableData<float>();
for (int i = 0; i < outputCount; i += CANDIDATE_NUM)
{
int index = Argmax(floatData + i, floatData + i + CANDIDATE_NUM-1);
punction.push_back(index);
}
}
catch (std::exception const &e)
{
LOG(ERROR) << "Error when run punc onnx forword: " << (e.what());
exit(0);
}
return punction;
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#pragma once
class CTTransformer {
/**
* Author: Speech Lab of DAMO Academy, Alibaba Group
* CT-Transformer: Controllable time-delay transformer for real-time punctuation prediction and disfluency detection
* https://arxiv.org/pdf/2003.01309.pdf
*/
private:
CTokenizer m_tokenizer;
vector<string> m_strInputNames, m_strOutputNames;
vector<const char*> m_szInputNames;
vector<const char*> m_szOutputNames;
std::shared_ptr<Ort::Session> m_session;
Ort::Env env_;
Ort::SessionOptions session_options;
public:
CTTransformer();
void InitPunc(const std::string &punc_model, const std::string &punc_config, int thread_num);
~CTTransformer();
vector<int> Infer(vector<int64_t> input_data);
string AddPunc(const char* sz_input);
};

View File

@@ -0,0 +1,791 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
* Collaborators: zhuzizyf(China Telecom Shanghai)
*/
#include <utility>
#include <vector>
#include <string>
#include <map>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <cassert>
enum class VadStateMachine {
kVadInStateStartPointNotDetected = 1,
kVadInStateInSpeechSegment = 2,
kVadInStateEndPointDetected = 3
};
enum class FrameState {
kFrameStateInvalid = -1,
kFrameStateSpeech = 1,
kFrameStateSil = 0
};
// final voice/unvoice state per frame
enum class AudioChangeState {
kChangeStateSpeech2Speech = 0,
kChangeStateSpeech2Sil = 1,
kChangeStateSil2Sil = 2,
kChangeStateSil2Speech = 3,
kChangeStateNoBegin = 4,
kChangeStateInvalid = 5
};
enum class VadDetectMode {
kVadSingleUtteranceDetectMode = 0,
kVadMutipleUtteranceDetectMode = 1
};
class VADXOptions {
public:
int sample_rate;
int detect_mode;
int snr_mode;
int max_end_silence_time;
int max_start_silence_time;
bool do_start_point_detection;
bool do_end_point_detection;
int window_size_ms;
int sil_to_speech_time_thres;
int speech_to_sil_time_thres;
float speech_2_noise_ratio;
int do_extend;
int lookback_time_start_point;
int lookahead_time_end_point;
int max_single_segment_time;
int nn_eval_block_size;
int dcd_block_size;
float snr_thres;
int noise_frame_num_used_for_snr;
float decibel_thres;
float speech_noise_thres;
float fe_prior_thres;
int silence_pdf_num;
std::vector<int> sil_pdf_ids;
float speech_noise_thresh_low;
float speech_noise_thresh_high;
bool output_frame_probs;
int frame_in_ms;
int frame_length_ms;
explicit VADXOptions(
int sr = 16000,
int dm = static_cast<int>(VadDetectMode::kVadMutipleUtteranceDetectMode),
int sm = 0,
int mset = 800,
int msst = 3000,
bool dspd = true,
bool depd = true,
int wsm = 200,
int ststh = 150,
int sttsh = 150,
float s2nr = 1.0,
int de = 1,
int lbtps = 200,
int latsp = 100,
int mss = 15000,
int nebs = 8,
int dbs = 4,
float st = -100.0,
int nfnus = 100,
float dt = -100.0,
float snt = 0.9,
float fept = 1e-4,
int spn = 1,
std::vector<int> spids = {0},
float sntl = -0.1,
float snth = 0.3,
bool ofp = false,
int fim = 10,
int flm = 25
) :
sample_rate(sr),
detect_mode(dm),
snr_mode(sm),
max_end_silence_time(mset),
max_start_silence_time(msst),
do_start_point_detection(dspd),
do_end_point_detection(depd),
window_size_ms(wsm),
sil_to_speech_time_thres(ststh),
speech_to_sil_time_thres(sttsh),
speech_2_noise_ratio(s2nr),
do_extend(de),
lookback_time_start_point(lbtps),
lookahead_time_end_point(latsp),
max_single_segment_time(mss),
nn_eval_block_size(nebs),
dcd_block_size(dbs),
snr_thres(st),
noise_frame_num_used_for_snr(nfnus),
decibel_thres(dt),
speech_noise_thres(snt),
fe_prior_thres(fept),
silence_pdf_num(spn),
sil_pdf_ids(std::move(spids)),
speech_noise_thresh_low(sntl),
speech_noise_thresh_high(snth),
output_frame_probs(ofp),
frame_in_ms(fim),
frame_length_ms(flm) {}
};
class E2EVadSpeechBufWithDoa {
public:
int start_ms;
int end_ms;
std::vector<float> buffer;
bool contain_seg_start_point;
bool contain_seg_end_point;
int doa;
E2EVadSpeechBufWithDoa() :
start_ms(0),
end_ms(0),
buffer(),
contain_seg_start_point(false),
contain_seg_end_point(false),
doa(0) {}
void Reset() {
start_ms = 0;
end_ms = 0;
buffer.clear();
contain_seg_start_point = false;
contain_seg_end_point = false;
doa = 0;
}
};
class E2EVadFrameProb {
public:
double noise_prob;
double speech_prob;
double score;
int frame_id;
int frm_state;
E2EVadFrameProb() :
noise_prob(0.0),
speech_prob(0.0),
score(0.0),
frame_id(0),
frm_state(0) {}
};
class WindowDetector {
public:
int window_size_ms;
int sil_to_speech_time;
int speech_to_sil_time;
int frame_size_ms;
int win_size_frame;
int win_sum;
std::vector<int> win_state;
int cur_win_pos;
FrameState pre_frame_state;
FrameState cur_frame_state;
int sil_to_speech_frmcnt_thres;
int speech_to_sil_frmcnt_thres;
int voice_last_frame_count;
int noise_last_frame_count;
int hydre_frame_count;
WindowDetector(int window_size_ms, int sil_to_speech_time, int speech_to_sil_time, int frame_size_ms) :
window_size_ms(window_size_ms),
sil_to_speech_time(sil_to_speech_time),
speech_to_sil_time(speech_to_sil_time),
frame_size_ms(frame_size_ms),
win_size_frame(window_size_ms / frame_size_ms),
win_sum(0),
win_state(std::vector<int>(win_size_frame, 0)),
cur_win_pos(0),
pre_frame_state(FrameState::kFrameStateSil),
cur_frame_state(FrameState::kFrameStateSil),
sil_to_speech_frmcnt_thres(sil_to_speech_time / frame_size_ms),
speech_to_sil_frmcnt_thres(speech_to_sil_time / frame_size_ms),
voice_last_frame_count(0),
noise_last_frame_count(0),
hydre_frame_count(0) {}
void Reset() {
cur_win_pos = 0;
win_sum = 0;
win_state = std::vector<int>(win_size_frame, 0);
pre_frame_state = FrameState::kFrameStateSil;
cur_frame_state = FrameState::kFrameStateSil;
voice_last_frame_count = 0;
noise_last_frame_count = 0;
hydre_frame_count = 0;
}
int GetWinSize() {
return win_size_frame;
}
AudioChangeState DetectOneFrame(FrameState frameState, int frame_count) {
int cur_frame_state = 0;
if (frameState == FrameState::kFrameStateSpeech) {
cur_frame_state = 1;
} else if (frameState == FrameState::kFrameStateSil) {
cur_frame_state = 0;
} else {
return AudioChangeState::kChangeStateInvalid;
}
win_sum -= win_state[cur_win_pos];
win_sum += cur_frame_state;
win_state[cur_win_pos] = cur_frame_state;
cur_win_pos = (cur_win_pos + 1) % win_size_frame;
if (pre_frame_state == FrameState::kFrameStateSil && win_sum >= sil_to_speech_frmcnt_thres) {
pre_frame_state = FrameState::kFrameStateSpeech;
return AudioChangeState::kChangeStateSil2Speech;
}
if (pre_frame_state == FrameState::kFrameStateSpeech && win_sum <= speech_to_sil_frmcnt_thres) {
pre_frame_state = FrameState::kFrameStateSil;
return AudioChangeState::kChangeStateSpeech2Sil;
}
if (pre_frame_state == FrameState::kFrameStateSil) {
return AudioChangeState::kChangeStateSil2Sil;
}
if (pre_frame_state == FrameState::kFrameStateSpeech) {
return AudioChangeState::kChangeStateSpeech2Speech;
}
return AudioChangeState::kChangeStateInvalid;
}
int FrameSizeMs() {
return frame_size_ms;
}
};
class E2EVadModel {
public:
E2EVadModel() {
this->vad_opts = VADXOptions();
// this->windows_detector = WindowDetector(200,150,150,10);
// this->encoder = encoder;
// init variables
this->is_final = false;
this->data_buf_start_frame = 0;
this->frm_cnt = 0;
this->latest_confirmed_speech_frame = 0;
this->lastest_confirmed_silence_frame = -1;
this->continous_silence_frame_count = 0;
this->vad_state_machine = VadStateMachine::kVadInStateStartPointNotDetected;
this->confirmed_start_frame = -1;
this->confirmed_end_frame = -1;
this->number_end_time_detected = 0;
this->sil_frame = 0;
this->sil_pdf_ids = this->vad_opts.sil_pdf_ids;
this->noise_average_decibel = -100.0;
this->pre_end_silence_detected = false;
this->next_seg = true;
// this->output_data_buf = [];
this->output_data_buf_offset = 0;
// this->frame_probs = [];
this->max_end_sil_frame_cnt_thresh =
this->vad_opts.max_end_silence_time - this->vad_opts.speech_to_sil_time_thres;
this->speech_noise_thres = this->vad_opts.speech_noise_thres;
this->max_time_out = false;
// this->decibel = [];
this->ResetDetection();
}
std::vector<std::vector<int>>
operator()(const std::vector<std::vector<float>> &score, const std::vector<float> &waveform, bool is_final = false,
bool online = false, int max_end_sil = 800, int max_single_segment_time = 15000,
float speech_noise_thres = 0.8, int sample_rate = 16000) {
max_end_sil_frame_cnt_thresh = max_end_sil - vad_opts.speech_to_sil_time_thres;
this->waveform = waveform;
this->vad_opts.max_single_segment_time = max_single_segment_time;
this->vad_opts.speech_noise_thres = speech_noise_thres;
this->vad_opts.sample_rate = sample_rate;
ComputeDecibel();
ComputeScores(score);
if (!is_final) {
DetectCommonFrames();
} else {
DetectLastFrames();
}
std::vector<std::vector<int>> segment_batch;
if (output_data_buf.size() > 0) {
for (size_t i = output_data_buf_offset; i < output_data_buf.size(); i++) {
int start_ms;
int end_ms;
if (online) {
if (!output_data_buf[i].contain_seg_start_point) {
continue;
}
if (!next_seg && !output_data_buf[i].contain_seg_end_point) {
continue;
}
start_ms = next_seg ? output_data_buf[i].start_ms : -1;
if (output_data_buf[i].contain_seg_end_point) {
end_ms = output_data_buf[i].end_ms;
next_seg = true;
output_data_buf_offset += 1;
} else {
end_ms = -1;
next_seg = false;
}
} else {
if (!is_final &&
(!output_data_buf[i].contain_seg_start_point || !output_data_buf[i].contain_seg_end_point)) {
continue;
}
start_ms = output_data_buf[i].start_ms;
end_ms = output_data_buf[i].end_ms;
output_data_buf_offset += 1;
}
std::vector<int> segment = {start_ms, end_ms};
segment_batch.push_back(segment);
}
}
if (is_final) {
AllResetDetection();
}
return segment_batch;
}
private:
VADXOptions vad_opts;
WindowDetector windows_detector = WindowDetector(200, 150, 150, 10);
bool is_final;
int data_buf_start_frame;
int frm_cnt;
int latest_confirmed_speech_frame;
int lastest_confirmed_silence_frame;
int continous_silence_frame_count;
VadStateMachine vad_state_machine;
int confirmed_start_frame;
int confirmed_end_frame;
int number_end_time_detected;
int sil_frame;
std::vector<int> sil_pdf_ids;
float noise_average_decibel;
bool pre_end_silence_detected;
bool next_seg;
std::vector<E2EVadSpeechBufWithDoa> output_data_buf;
int output_data_buf_offset;
std::vector<E2EVadFrameProb> frame_probs;
int max_end_sil_frame_cnt_thresh;
float speech_noise_thres;
std::vector<std::vector<float>> scores;
int idx_pre_chunk = 0;
bool max_time_out;
std::vector<float> decibel;
int data_buf_size = 0;
int data_buf_all_size = 0;
std::vector<float> waveform;
void AllResetDetection() {
is_final = false;
data_buf_start_frame = 0;
frm_cnt = 0;
latest_confirmed_speech_frame = 0;
lastest_confirmed_silence_frame = -1;
continous_silence_frame_count = 0;
vad_state_machine = VadStateMachine::kVadInStateStartPointNotDetected;
confirmed_start_frame = -1;
confirmed_end_frame = -1;
number_end_time_detected = 0;
sil_frame = 0;
sil_pdf_ids = vad_opts.sil_pdf_ids;
noise_average_decibel = -100.0;
pre_end_silence_detected = false;
next_seg = true;
output_data_buf.clear();
output_data_buf_offset = 0;
frame_probs.clear();
max_end_sil_frame_cnt_thresh = vad_opts.max_end_silence_time - vad_opts.speech_to_sil_time_thres;
speech_noise_thres = vad_opts.speech_noise_thres;
scores.clear();
idx_pre_chunk = 0;
max_time_out = false;
decibel.clear();
int data_buf_size = 0;
int data_buf_all_size = 0;
waveform.clear();
ResetDetection();
}
void ResetDetection() {
continous_silence_frame_count = 0;
latest_confirmed_speech_frame = 0;
lastest_confirmed_silence_frame = -1;
confirmed_start_frame = -1;
confirmed_end_frame = -1;
vad_state_machine = VadStateMachine::kVadInStateStartPointNotDetected;
windows_detector.Reset();
sil_frame = 0;
frame_probs.clear();
}
void ComputeDecibel() {
int frame_sample_length = int(vad_opts.frame_length_ms * vad_opts.sample_rate / 1000);
int frame_shift_length = int(vad_opts.frame_in_ms * vad_opts.sample_rate / 1000);
if (data_buf_all_size == 0) {
data_buf_all_size = waveform.size();
data_buf_size = data_buf_all_size;
} else {
data_buf_all_size += waveform.size();
}
for (int offset = 0; offset < waveform.size() - frame_sample_length + 1; offset += frame_shift_length) {
float sum = 0.0;
for (int i = 0; i < frame_sample_length; i++) {
sum += waveform[offset + i] * waveform[offset + i];
}
this->decibel.push_back(10 * log10(sum + 0.000001));
}
}
void ComputeScores(const std::vector<std::vector<float>> &scores) {
vad_opts.nn_eval_block_size = scores.size();
frm_cnt += scores.size();
this->scores = scores;
}
void PopDataBufTillFrame(int frame_idx) {
int frame_sample_length = int(vad_opts.frame_in_ms * vad_opts.sample_rate / 1000);
while (data_buf_start_frame < frame_idx) {
if (data_buf_size >= frame_sample_length) {
data_buf_start_frame += 1;
data_buf_size = data_buf_all_size - data_buf_start_frame * frame_sample_length;
}
}
}
void PopDataToOutputBuf(int start_frm, int frm_cnt, bool first_frm_is_start_point, bool last_frm_is_end_point,
bool end_point_is_sent_end) {
PopDataBufTillFrame(start_frm);
int expected_sample_number = int(frm_cnt * vad_opts.sample_rate * vad_opts.frame_in_ms / 1000);
if (last_frm_is_end_point) {
int extra_sample = std::max(0, int(vad_opts.frame_length_ms * vad_opts.sample_rate / 1000 -
vad_opts.sample_rate * vad_opts.frame_in_ms / 1000));
expected_sample_number += int(extra_sample);
}
if (end_point_is_sent_end) {
expected_sample_number = std::max(expected_sample_number, data_buf_size);
}
if (data_buf_size < expected_sample_number) {
std::cout << "error in calling pop data_buf\n";
}
if (output_data_buf.size() == 0 || first_frm_is_start_point) {
output_data_buf.push_back(E2EVadSpeechBufWithDoa());
output_data_buf[output_data_buf.size() - 1].Reset();
output_data_buf[output_data_buf.size() - 1].start_ms = start_frm * vad_opts.frame_in_ms;
output_data_buf[output_data_buf.size() - 1].end_ms = output_data_buf[output_data_buf.size() - 1].start_ms;
output_data_buf[output_data_buf.size() - 1].doa = 0;
}
E2EVadSpeechBufWithDoa &cur_seg = output_data_buf.back();
if (cur_seg.end_ms != start_frm * vad_opts.frame_in_ms) {
std::cout << "warning\n";
}
int out_pos = (int) cur_seg.buffer.size();
int data_to_pop;
if (end_point_is_sent_end) {
data_to_pop = expected_sample_number;
} else {
data_to_pop = int(frm_cnt * vad_opts.frame_in_ms * vad_opts.sample_rate / 1000);
}
if (data_to_pop > data_buf_size) {
std::cout << "VAD data_to_pop is bigger than data_buf.size()!!!\n";
data_to_pop = data_buf_size;
expected_sample_number = data_buf_size;
}
cur_seg.doa = 0;
for (int sample_cpy_out = 0; sample_cpy_out < data_to_pop; sample_cpy_out++) {
cur_seg.buffer.push_back(data_buf.back());
out_pos++;
}
for (int sample_cpy_out = data_to_pop; sample_cpy_out < expected_sample_number; sample_cpy_out++) {
cur_seg.buffer.push_back(data_buf.back());
out_pos++;
}
if (cur_seg.end_ms != start_frm * vad_opts.frame_in_ms) {
std::cout << "Something wrong with the VAD algorithm\n";
}
data_buf_start_frame += frm_cnt;
cur_seg.end_ms = (start_frm + frm_cnt) * vad_opts.frame_in_ms;
if (first_frm_is_start_point) {
cur_seg.contain_seg_start_point = true;
}
if (last_frm_is_end_point) {
cur_seg.contain_seg_end_point = true;
}
}
void OnSilenceDetected(int valid_frame) {
lastest_confirmed_silence_frame = valid_frame;
if (vad_state_machine == VadStateMachine::kVadInStateStartPointNotDetected) {
PopDataBufTillFrame(valid_frame);
}
// silence_detected_callback_
// pass
}
void OnVoiceDetected(int valid_frame) {
latest_confirmed_speech_frame = valid_frame;
PopDataToOutputBuf(valid_frame, 1, false, false, false);
}
void OnVoiceStart(int start_frame, bool fake_result = false) {
if (vad_opts.do_start_point_detection) {
// pass
}
if (confirmed_start_frame != -1) {
std::cout << "not reset vad properly\n";
} else {
confirmed_start_frame = start_frame;
}
if (!fake_result && vad_state_machine == VadStateMachine::kVadInStateStartPointNotDetected) {
PopDataToOutputBuf(confirmed_start_frame, 1, true, false, false);
}
}
void OnVoiceEnd(int end_frame, bool fake_result, bool is_last_frame) {
for (int t = latest_confirmed_speech_frame + 1; t < end_frame; t++) {
OnVoiceDetected(t);
}
if (vad_opts.do_end_point_detection) {
// pass
}
if (confirmed_end_frame != -1) {
std::cout << "not reset vad properly\n";
} else {
confirmed_end_frame = end_frame;
}
if (!fake_result) {
sil_frame = 0;
PopDataToOutputBuf(confirmed_end_frame, 1, false, true, is_last_frame);
}
number_end_time_detected++;
}
void MaybeOnVoiceEndIfLastFrame(bool is_final_frame, int cur_frm_idx) {
if (is_final_frame) {
OnVoiceEnd(cur_frm_idx, false, true);
vad_state_machine = VadStateMachine::kVadInStateEndPointDetected;
}
}
int GetLatency() {
return int(LatencyFrmNumAtStartPoint() * vad_opts.frame_in_ms);
}
int LatencyFrmNumAtStartPoint() {
int vad_latency = windows_detector.GetWinSize();
if (vad_opts.do_extend) {
vad_latency += int(vad_opts.lookback_time_start_point / vad_opts.frame_in_ms);
}
return vad_latency;
}
FrameState GetFrameState(int t) {
FrameState frame_state = FrameState::kFrameStateInvalid;
float cur_decibel = decibel[t];
float cur_snr = cur_decibel - noise_average_decibel;
if (cur_decibel < vad_opts.decibel_thres) {
frame_state = FrameState::kFrameStateSil;
DetectOneFrame(frame_state, t, false);
return frame_state;
}
float sum_score = 0.0;
float noise_prob = 0.0;
assert(sil_pdf_ids.size() == vad_opts.silence_pdf_num);
if (sil_pdf_ids.size() > 0) {
std::vector<float> sil_pdf_scores;
for (auto sil_pdf_id: sil_pdf_ids) {
sil_pdf_scores.push_back(scores[t - idx_pre_chunk][sil_pdf_id]);
}
sum_score = accumulate(sil_pdf_scores.begin(), sil_pdf_scores.end(), 0.0);
noise_prob = log(sum_score) * vad_opts.speech_2_noise_ratio;
float total_score = 1.0;
sum_score = total_score - sum_score;
}
float speech_prob = log(sum_score);
if (vad_opts.output_frame_probs) {
E2EVadFrameProb frame_prob;
frame_prob.noise_prob = noise_prob;
frame_prob.speech_prob = speech_prob;
frame_prob.score = sum_score;
frame_prob.frame_id = t;
frame_probs.push_back(frame_prob);
}
if (exp(speech_prob) >= exp(noise_prob) + speech_noise_thres) {
if (cur_snr >= vad_opts.snr_thres && cur_decibel >= vad_opts.decibel_thres) {
frame_state = FrameState::kFrameStateSpeech;
} else {
frame_state = FrameState::kFrameStateSil;
}
} else {
frame_state = FrameState::kFrameStateSil;
if (noise_average_decibel < -99.9) {
noise_average_decibel = cur_decibel;
} else {
noise_average_decibel =
(cur_decibel + noise_average_decibel * (vad_opts.noise_frame_num_used_for_snr - 1)) /
vad_opts.noise_frame_num_used_for_snr;
}
}
return frame_state;
}
int DetectCommonFrames() {
if (vad_state_machine == VadStateMachine::kVadInStateEndPointDetected) {
return 0;
}
for (int i = vad_opts.nn_eval_block_size - 1; i >= 0; i--) {
FrameState frame_state = FrameState::kFrameStateInvalid;
frame_state = GetFrameState(frm_cnt - 1 - i);
DetectOneFrame(frame_state, frm_cnt - 1 - i, false);
}
idx_pre_chunk += scores.size();
return 0;
}
int DetectLastFrames() {
if (vad_state_machine == VadStateMachine::kVadInStateEndPointDetected) {
return 0;
}
for (int i = vad_opts.nn_eval_block_size - 1; i >= 0; i--) {
FrameState frame_state = FrameState::kFrameStateInvalid;
frame_state = GetFrameState(frm_cnt - 1 - i);
if (i != 0) {
DetectOneFrame(frame_state, frm_cnt - 1 - i, false);
} else {
DetectOneFrame(frame_state, frm_cnt - 1, true);
}
}
return 0;
}
void DetectOneFrame(FrameState cur_frm_state, int cur_frm_idx, bool is_final_frame) {
FrameState tmp_cur_frm_state = FrameState::kFrameStateInvalid;
if (cur_frm_state == FrameState::kFrameStateSpeech) {
if (std::fabs(1.0) > vad_opts.fe_prior_thres) {
tmp_cur_frm_state = FrameState::kFrameStateSpeech;
} else {
tmp_cur_frm_state = FrameState::kFrameStateSil;
}
} else if (cur_frm_state == FrameState::kFrameStateSil) {
tmp_cur_frm_state = FrameState::kFrameStateSil;
}
AudioChangeState state_change = windows_detector.DetectOneFrame(tmp_cur_frm_state, cur_frm_idx);
int frm_shift_in_ms = vad_opts.frame_in_ms;
if (AudioChangeState::kChangeStateSil2Speech == state_change) {
int silence_frame_count = continous_silence_frame_count;
continous_silence_frame_count = 0;
pre_end_silence_detected = false;
int start_frame = 0;
if (vad_state_machine == VadStateMachine::kVadInStateStartPointNotDetected) {
start_frame = std::max(data_buf_start_frame, cur_frm_idx - LatencyFrmNumAtStartPoint());
OnVoiceStart(start_frame);
vad_state_machine = VadStateMachine::kVadInStateInSpeechSegment;
for (int t = start_frame + 1; t <= cur_frm_idx; t++) {
OnVoiceDetected(t);
}
} else if (vad_state_machine == VadStateMachine::kVadInStateInSpeechSegment) {
for (int t = latest_confirmed_speech_frame + 1; t < cur_frm_idx; t++) {
OnVoiceDetected(t);
}
if (cur_frm_idx - confirmed_start_frame + 1 > vad_opts.max_single_segment_time / frm_shift_in_ms) {
OnVoiceEnd(cur_frm_idx, false, false);
vad_state_machine = VadStateMachine::kVadInStateEndPointDetected;
} else if (!is_final_frame) {
OnVoiceDetected(cur_frm_idx);
} else {
MaybeOnVoiceEndIfLastFrame(is_final_frame, cur_frm_idx);
}
}
} else if (AudioChangeState::kChangeStateSpeech2Sil == state_change) {
continous_silence_frame_count = 0;
if (vad_state_machine == VadStateMachine::kVadInStateStartPointNotDetected) {
// do nothing
} else if (vad_state_machine == VadStateMachine::kVadInStateInSpeechSegment) {
if (cur_frm_idx - confirmed_start_frame + 1 >
vad_opts.max_single_segment_time / frm_shift_in_ms) {
OnVoiceEnd(cur_frm_idx, false, false);
vad_state_machine = VadStateMachine::kVadInStateEndPointDetected;
} else if (!is_final_frame) {
OnVoiceDetected(cur_frm_idx);
} else {
MaybeOnVoiceEndIfLastFrame(is_final_frame, cur_frm_idx);
}
}
} else if (AudioChangeState::kChangeStateSpeech2Speech == state_change) {
continous_silence_frame_count = 0;
if (vad_state_machine == VadStateMachine::kVadInStateInSpeechSegment) {
if (cur_frm_idx - confirmed_start_frame + 1 >
vad_opts.max_single_segment_time / frm_shift_in_ms) {
max_time_out = true;
OnVoiceEnd(cur_frm_idx, false, false);
vad_state_machine = VadStateMachine::kVadInStateEndPointDetected;
} else if (!is_final_frame) {
OnVoiceDetected(cur_frm_idx);
} else {
MaybeOnVoiceEndIfLastFrame(is_final_frame, cur_frm_idx);
}
}
} else if (AudioChangeState::kChangeStateSil2Sil == state_change) {
continous_silence_frame_count += 1;
if (vad_state_machine == VadStateMachine::kVadInStateStartPointNotDetected) {
if ((vad_opts.detect_mode == static_cast<int>(VadDetectMode::kVadSingleUtteranceDetectMode) &&
(continous_silence_frame_count * frm_shift_in_ms > vad_opts.max_start_silence_time)) ||
(is_final_frame && number_end_time_detected == 0)) {
for (int t = lastest_confirmed_silence_frame + 1; t < cur_frm_idx; t++) {
OnSilenceDetected(t);
}
OnVoiceStart(0, true);
OnVoiceEnd(0, true, false);
vad_state_machine = VadStateMachine::kVadInStateEndPointDetected;
} else {
if (cur_frm_idx >= LatencyFrmNumAtStartPoint()) {
OnSilenceDetected(cur_frm_idx - LatencyFrmNumAtStartPoint());
}
}
} else if (vad_state_machine == VadStateMachine::kVadInStateInSpeechSegment) {
if (continous_silence_frame_count * frm_shift_in_ms >= max_end_sil_frame_cnt_thresh) {
int lookback_frame = max_end_sil_frame_cnt_thresh / frm_shift_in_ms;
if (vad_opts.do_extend) {
lookback_frame -= vad_opts.lookahead_time_end_point / frm_shift_in_ms;
lookback_frame -= 1;
lookback_frame = std::max(0, lookback_frame);
}
OnVoiceEnd(cur_frm_idx - lookback_frame, false, false);
vad_state_machine = VadStateMachine::kVadInStateEndPointDetected;
} else if (cur_frm_idx - confirmed_start_frame + 1 >
vad_opts.max_single_segment_time / frm_shift_in_ms) {
OnVoiceEnd(cur_frm_idx, false, false);
vad_state_machine = VadStateMachine::kVadInStateEndPointDetected;
} else if (vad_opts.do_extend && !is_final_frame) {
if (continous_silence_frame_count <= vad_opts.lookahead_time_end_point / frm_shift_in_ms) {
OnVoiceDetected(cur_frm_idx);
}
} else {
MaybeOnVoiceEndIfLastFrame(is_final_frame, cur_frm_idx);
}
}
}
if (vad_state_machine == VadStateMachine::kVadInStateEndPointDetected &&
vad_opts.detect_mode == static_cast<int>(VadDetectMode::kVadMutipleUtteranceDetectMode)) {
ResetDetection();
}
}
};

View File

@@ -0,0 +1,300 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#include <fstream>
#include "precomp.h"
void FsmnVad::InitVad(const std::string &vad_model, const std::string &vad_cmvn, const std::string &vad_config) {
session_options_.SetIntraOpNumThreads(1);
session_options_.SetGraphOptimizationLevel(ORT_ENABLE_ALL);
session_options_.DisableCpuMemArena();
ReadModel(vad_model.c_str());
LoadCmvn(vad_cmvn.c_str());
LoadConfigFromYaml(vad_config.c_str());
InitCache();
}
void FsmnVad::LoadConfigFromYaml(const char* filename){
YAML::Node config;
try{
config = YAML::LoadFile(filename);
}catch(exception const &e){
LOG(ERROR) << "Error loading file, yaml file error or not exist.";
exit(-1);
}
try{
YAML::Node frontend_conf = config["frontend_conf"];
YAML::Node post_conf = config["vad_post_conf"];
this->vad_sample_rate_ = frontend_conf["fs"].as<int>();
this->vad_silence_duration_ = post_conf["max_end_silence_time"].as<int>();
this->vad_max_len_ = post_conf["max_single_segment_time"].as<int>();
this->vad_speech_noise_thres_ = post_conf["speech_noise_thres"].as<double>();
fbank_opts.frame_opts.dither = frontend_conf["dither"].as<float>();
fbank_opts.mel_opts.num_bins = frontend_conf["n_mels"].as<int>();
fbank_opts.frame_opts.samp_freq = (float)vad_sample_rate_;
fbank_opts.frame_opts.window_type = frontend_conf["window"].as<string>();
fbank_opts.frame_opts.frame_shift_ms = frontend_conf["frame_shift"].as<float>();
fbank_opts.frame_opts.frame_length_ms = frontend_conf["frame_length"].as<float>();
fbank_opts.energy_floor = 0;
fbank_opts.mel_opts.debug_mel = false;
}catch(exception const &e){
LOG(ERROR) << "Error when load argument from vad config YAML.";
exit(-1);
}
}
void FsmnVad::ReadModel(const char* vad_model) {
try {
vad_session_ = std::make_shared<Ort::Session>(
env_, vad_model, session_options_);
} catch (std::exception const &e) {
LOG(ERROR) << "Error when load vad onnx model: " << e.what();
exit(0);
}
GetInputOutputInfo(vad_session_, &vad_in_names_, &vad_out_names_);
}
void FsmnVad::GetInputOutputInfo(
const std::shared_ptr<Ort::Session> &session,
std::vector<const char *> *in_names, std::vector<const char *> *out_names) {
Ort::AllocatorWithDefaultOptions allocator;
// Input info
int num_nodes = session->GetInputCount();
in_names->resize(num_nodes);
for (int i = 0; i < num_nodes; ++i) {
std::unique_ptr<char, Ort::detail::AllocatedFree> name = session->GetInputNameAllocated(i, allocator);
Ort::TypeInfo type_info = session->GetInputTypeInfo(i);
auto tensor_info = type_info.GetTensorTypeAndShapeInfo();
ONNXTensorElementDataType type = tensor_info.GetElementType();
std::vector<int64_t> node_dims = tensor_info.GetShape();
std::stringstream shape;
for (auto j: node_dims) {
shape << j;
shape << " ";
}
// LOG(INFO) << "\tInput " << i << " : name=" << name.get() << " type=" << type
// << " dims=" << shape.str();
(*in_names)[i] = name.get();
name.release();
}
// Output info
num_nodes = session->GetOutputCount();
out_names->resize(num_nodes);
for (int i = 0; i < num_nodes; ++i) {
std::unique_ptr<char, Ort::detail::AllocatedFree> name = session->GetOutputNameAllocated(i, allocator);
Ort::TypeInfo type_info = session->GetOutputTypeInfo(i);
auto tensor_info = type_info.GetTensorTypeAndShapeInfo();
ONNXTensorElementDataType type = tensor_info.GetElementType();
std::vector<int64_t> node_dims = tensor_info.GetShape();
std::stringstream shape;
for (auto j: node_dims) {
shape << j;
shape << " ";
}
// LOG(INFO) << "\tOutput " << i << " : name=" << name.get() << " type=" << type
// << " dims=" << shape.str();
(*out_names)[i] = name.get();
name.release();
}
}
void FsmnVad::Forward(
const std::vector<std::vector<float>> &chunk_feats,
std::vector<std::vector<float>> *out_prob) {
Ort::MemoryInfo memory_info =
Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
int num_frames = chunk_feats.size();
const int feature_dim = chunk_feats[0].size();
// 2. Generate input nodes tensor
// vad node { batch,frame number,feature dim }
const int64_t vad_feats_shape[3] = {1, num_frames, feature_dim};
std::vector<float> vad_feats;
for (const auto &chunk_feat: chunk_feats) {
vad_feats.insert(vad_feats.end(), chunk_feat.begin(), chunk_feat.end());
}
Ort::Value vad_feats_ort = Ort::Value::CreateTensor<float>(
memory_info, vad_feats.data(), vad_feats.size(), vad_feats_shape, 3);
// 3. Put nodes into onnx input vector
std::vector<Ort::Value> vad_inputs;
vad_inputs.emplace_back(std::move(vad_feats_ort));
// 4 caches
// cache node {batch,128,19,1}
const int64_t cache_feats_shape[4] = {1, 128, 19, 1};
for (int i = 0; i < in_cache_.size(); i++) {
vad_inputs.emplace_back(std::move(Ort::Value::CreateTensor<float>(
memory_info, in_cache_[i].data(), in_cache_[i].size(), cache_feats_shape, 4)));
}
// 4. Onnx infer
std::vector<Ort::Value> vad_ort_outputs;
try {
vad_ort_outputs = vad_session_->Run(
Ort::RunOptions{nullptr}, vad_in_names_.data(), vad_inputs.data(),
vad_inputs.size(), vad_out_names_.data(), vad_out_names_.size());
} catch (std::exception const &e) {
LOG(ERROR) << "Error when run vad onnx forword: " << (e.what());
exit(0);
}
// 5. Change infer result to output shapes
float *logp_data = vad_ort_outputs[0].GetTensorMutableData<float>();
auto type_info = vad_ort_outputs[0].GetTensorTypeAndShapeInfo();
int num_outputs = type_info.GetShape()[1];
int output_dim = type_info.GetShape()[2];
out_prob->resize(num_outputs);
for (int i = 0; i < num_outputs; i++) {
(*out_prob)[i].resize(output_dim);
memcpy((*out_prob)[i].data(), logp_data + i * output_dim,
sizeof(float) * output_dim);
}
// get 4 caches outputs,each size is 128*19
for (int i = 1; i < 5; i++) {
float* data = vad_ort_outputs[i].GetTensorMutableData<float>();
memcpy(in_cache_[i-1].data(), data, sizeof(float) * 128*19);
}
}
void FsmnVad::FbankKaldi(float sample_rate, std::vector<std::vector<float>> &vad_feats,
const std::vector<float> &waves) {
knf::OnlineFbank fbank(fbank_opts);
fbank.AcceptWaveform(sample_rate, &waves[0], waves.size());
int32_t frames = fbank.NumFramesReady();
for (int32_t i = 0; i != frames; ++i) {
const float *frame = fbank.GetFrame(i);
std::vector<float> frame_vector(frame, frame + fbank_opts.mel_opts.num_bins);
vad_feats.emplace_back(frame_vector);
}
}
void FsmnVad::LoadCmvn(const char *filename)
{
try{
using namespace std;
ifstream cmvn_stream(filename);
if (!cmvn_stream.is_open()) {
LOG(ERROR) << "Failed to open file: " << filename;
exit(0);
}
string line;
while (getline(cmvn_stream, line)) {
istringstream iss(line);
vector<string> line_item{istream_iterator<string>{iss}, istream_iterator<string>{}};
if (line_item[0] == "<AddShift>") {
getline(cmvn_stream, line);
istringstream means_lines_stream(line);
vector<string> means_lines{istream_iterator<string>{means_lines_stream}, istream_iterator<string>{}};
if (means_lines[0] == "<LearnRateCoef>") {
for (int j = 3; j < means_lines.size() - 1; j++) {
means_list.push_back(stof(means_lines[j]));
}
continue;
}
}
else if (line_item[0] == "<Rescale>") {
getline(cmvn_stream, line);
istringstream vars_lines_stream(line);
vector<string> vars_lines{istream_iterator<string>{vars_lines_stream}, istream_iterator<string>{}};
if (vars_lines[0] == "<LearnRateCoef>") {
for (int j = 3; j < vars_lines.size() - 1; j++) {
// vars_list.push_back(stof(vars_lines[j])*scale);
vars_list.push_back(stof(vars_lines[j]));
}
continue;
}
}
}
}catch(std::exception const &e) {
LOG(ERROR) << "Error when load vad cmvn : " << e.what();
exit(0);
}
}
std::vector<std::vector<float>> &FsmnVad::LfrCmvn(std::vector<std::vector<float>> &vad_feats) {
std::vector<std::vector<float>> out_feats;
int T = vad_feats.size();
int T_lrf = ceil(1.0 * T / lfr_n);
// Pad frames at start(copy first frame)
for (int i = 0; i < (lfr_m - 1) / 2; i++) {
vad_feats.insert(vad_feats.begin(), vad_feats[0]);
}
// Merge lfr_m frames as one,lfr_n frames per window
T = T + (lfr_m - 1) / 2;
std::vector<float> p;
for (int i = 0; i < T_lrf; i++) {
if (lfr_m <= T - i * lfr_n) {
for (int j = 0; j < lfr_m; j++) {
p.insert(p.end(), vad_feats[i * lfr_n + j].begin(), vad_feats[i * lfr_n + j].end());
}
out_feats.emplace_back(p);
p.clear();
} else {
// Fill to lfr_m frames at last window if less than lfr_m frames (copy last frame)
int num_padding = lfr_m - (T - i * lfr_n);
for (int j = 0; j < (vad_feats.size() - i * lfr_n); j++) {
p.insert(p.end(), vad_feats[i * lfr_n + j].begin(), vad_feats[i * lfr_n + j].end());
}
for (int j = 0; j < num_padding; j++) {
p.insert(p.end(), vad_feats[vad_feats.size() - 1].begin(), vad_feats[vad_feats.size() - 1].end());
}
out_feats.emplace_back(p);
}
}
// Apply cmvn
for (auto &out_feat: out_feats) {
for (int j = 0; j < means_list.size(); j++) {
out_feat[j] = (out_feat[j] + means_list[j]) * vars_list[j];
}
}
vad_feats = out_feats;
return vad_feats;
}
std::vector<std::vector<int>>
FsmnVad::Infer(const std::vector<float> &waves) {
std::vector<std::vector<float>> vad_feats;
std::vector<std::vector<float>> vad_probs;
FbankKaldi(vad_sample_rate_, vad_feats, waves);
vad_feats = LfrCmvn(vad_feats);
Forward(vad_feats, &vad_probs);
E2EVadModel vad_scorer = E2EVadModel();
std::vector<std::vector<int>> vad_segments;
vad_segments = vad_scorer(vad_probs, waves, true, false, vad_silence_duration_, vad_max_len_,
vad_speech_noise_thres_, vad_sample_rate_);
return vad_segments;
}
void FsmnVad::InitCache(){
std::vector<float> cache_feats(128 * 19 * 1, 0);
for (int i=0;i<4;i++){
in_cache_.emplace_back(cache_feats);
}
};
void FsmnVad::Reset(){
in_cache_.clear();
InitCache();
};
void FsmnVad::Test() {
}
FsmnVad::FsmnVad():env_(ORT_LOGGING_LEVEL_ERROR, ""),session_options_{} {
}

View File

@@ -0,0 +1,67 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#ifndef VAD_SERVER_FSMNVAD_H
#define VAD_SERVER_FSMNVAD_H
#include "precomp.h"
class FsmnVad {
/**
* Author: Speech Lab of DAMO Academy, Alibaba Group
* Deep-FSMN for Large Vocabulary Continuous Speech Recognition
* https://arxiv.org/abs/1803.05030
*/
public:
FsmnVad();
void Test();
void InitVad(const std::string &vad_model, const std::string &vad_cmvn, const std::string &vad_config);
std::vector<std::vector<int>> Infer(const std::vector<float> &waves);
void Reset();
private:
void ReadModel(const char* vad_model);
void LoadConfigFromYaml(const char* filename);
static void GetInputOutputInfo(
const std::shared_ptr<Ort::Session> &session,
std::vector<const char *> *in_names, std::vector<const char *> *out_names);
void FbankKaldi(float sample_rate, std::vector<std::vector<float>> &vad_feats,
const std::vector<float> &waves);
std::vector<std::vector<float>> &LfrCmvn(std::vector<std::vector<float>> &vad_feats);
void Forward(
const std::vector<std::vector<float>> &chunk_feats,
std::vector<std::vector<float>> *out_prob);
void LoadCmvn(const char *filename);
void InitCache();
std::shared_ptr<Ort::Session> vad_session_ = nullptr;
Ort::Env env_;
Ort::SessionOptions session_options_;
std::vector<const char *> vad_in_names_;
std::vector<const char *> vad_out_names_;
std::vector<std::vector<float>> in_cache_;
knf::FbankOptions fbank_opts;
std::vector<float> means_list;
std::vector<float> vars_list;
int vad_sample_rate_ = MODEL_SAMPLE_RATE;
int vad_silence_duration_ = VAD_SILENCE_DURATION;
int vad_max_len_ = VAD_MAX_LEN;
double vad_speech_noise_thres_ = VAD_SPEECH_NOISE_THRES;
int lfr_m = VAD_LFR_M;
int lfr_n = VAD_LFR_N;
};
#endif //VAD_SERVER_FSMNVAD_H

View File

@@ -0,0 +1,188 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#ifndef _WIN32
#include <sys/time.h>
#else
#include <win_func.h>
#endif
#include <glog/logging.h>
#include "libfunasrapi.h"
#include "tclap/CmdLine.h"
#include "com-define.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <atomic>
#include <mutex>
#include <thread>
#include <map>
using namespace std;
std::atomic<int> wav_index(0);
std::mutex mtx;
void runReg(FUNASR_HANDLE asr_handle, vector<string> wav_list,
float* total_length, long* total_time, int core_id) {
struct timeval start, end;
long seconds = 0;
float n_total_length = 0.0f;
long n_total_time = 0;
// warm up
for (size_t i = 0; i < 1; i++)
{
FUNASR_RESULT result=FunASRRecogFile(asr_handle, wav_list[0].c_str(), RASR_NONE, NULL);
}
while (true) {
// 使用原子变量获取索引并递增
int i = wav_index.fetch_add(1);
if (i >= wav_list.size()) {
break;
}
gettimeofday(&start, NULL);
FUNASR_RESULT result=FunASRRecogFile(asr_handle, wav_list[i].c_str(), RASR_NONE, NULL);
gettimeofday(&end, NULL);
seconds = (end.tv_sec - start.tv_sec);
long taking_micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec);
n_total_time += taking_micros;
if(result){
string msg = FunASRGetResult(result, 0);
LOG(INFO) << "Thread: " << this_thread::get_id() <<" Result: " << msg.c_str();
float snippet_time = FunASRGetRetSnippetTime(result);
n_total_length += snippet_time;
FunASRFreeResult(result);
}else{
LOG(ERROR) << ("No return data!\n");
}
}
{
lock_guard<mutex> guard(mtx);
*total_length += n_total_length;
if(*total_time < n_total_time){
*total_time = n_total_time;
}
}
}
void GetValue(TCLAP::ValueArg<std::string>& value_arg, string key, std::map<std::string, std::string>& model_path)
{
if (value_arg.isSet()){
model_path.insert({key, value_arg.getValue()});
LOG(INFO)<< key << " : " << value_arg.getValue();
}
}
int main(int argc, char *argv[])
{
google::InitGoogleLogging(argv[0]);
FLAGS_logtostderr = true;
TCLAP::CmdLine cmd("funasr-onnx-offline-rtf", ' ', "1.0");
TCLAP::ValueArg<std::string> vad_model("", VAD_MODEL_PATH, "vad model path", false, "", "string");
TCLAP::ValueArg<std::string> vad_cmvn("", VAD_CMVN_PATH, "vad cmvn path", false, "", "string");
TCLAP::ValueArg<std::string> vad_config("", VAD_CONFIG_PATH, "vad config path", false, "", "string");
TCLAP::ValueArg<std::string> am_model("", AM_MODEL_PATH, "am model path", false, "", "string");
TCLAP::ValueArg<std::string> am_cmvn("", AM_CMVN_PATH, "am cmvn path", false, "", "string");
TCLAP::ValueArg<std::string> am_config("", AM_CONFIG_PATH, "am config path", false, "", "string");
TCLAP::ValueArg<std::string> punc_model("", PUNC_MODEL_PATH, "punc model path", false, "", "string");
TCLAP::ValueArg<std::string> punc_config("", PUNC_CONFIG_PATH, "punc config path", false, "", "string");
TCLAP::ValueArg<std::string> wav_scp("", WAV_SCP, "wave scp path", true, "", "string");
TCLAP::ValueArg<std::int32_t> thread_num("", THREAD_NUM, "multi-thread num for rtf", true, 0, "int32_t");
cmd.add(vad_model);
cmd.add(vad_cmvn);
cmd.add(vad_config);
cmd.add(am_model);
cmd.add(am_cmvn);
cmd.add(am_config);
cmd.add(punc_model);
cmd.add(punc_config);
cmd.add(wav_scp);
cmd.add(thread_num);
cmd.parse(argc, argv);
std::map<std::string, std::string> model_path;
GetValue(vad_model, VAD_MODEL_PATH, model_path);
GetValue(vad_cmvn, VAD_CMVN_PATH, model_path);
GetValue(vad_config, VAD_CONFIG_PATH, model_path);
GetValue(am_model, AM_MODEL_PATH, model_path);
GetValue(am_cmvn, AM_CMVN_PATH, model_path);
GetValue(am_config, AM_CONFIG_PATH, model_path);
GetValue(punc_model, PUNC_MODEL_PATH, model_path);
GetValue(punc_config, PUNC_CONFIG_PATH, model_path);
GetValue(wav_scp, WAV_SCP, model_path);
struct timeval start, end;
gettimeofday(&start, NULL);
FUNASR_HANDLE asr_handle=FunASRInit(model_path, 1);
if (!asr_handle)
{
LOG(ERROR) << "FunASR init failed";
exit(-1);
}
gettimeofday(&end, NULL);
long seconds = (end.tv_sec - start.tv_sec);
long modle_init_micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec);
LOG(INFO) << "Model initialization takes " << (double)modle_init_micros / 1000000 << " s";
// read wav_scp
vector<string> wav_list;
if(model_path.find(WAV_SCP)!=model_path.end()){
ifstream in(model_path.at(WAV_SCP));
if (!in.is_open()) {
LOG(ERROR) << "Failed to open file: " << model_path.at(WAV_SCP);
return 0;
}
string line;
while(getline(in, line))
{
istringstream iss(line);
string column1, column2;
iss >> column1 >> column2;
wav_list.emplace_back(column2);
}
in.close();
}
// 多线程测试
float total_length = 0.0f;
long total_time = 0;
std::vector<std::thread> threads;
int rtf_threds = thread_num.getValue();
for (int i = 0; i < rtf_threds; i++)
{
threads.emplace_back(thread(runReg, asr_handle, wav_list, &total_length, &total_time, i));
}
for (auto& thread : threads)
{
thread.join();
}
LOG(INFO) << "total_time_wav " << (long)(total_length * 1000) << " ms";
LOG(INFO) << "total_time_comput " << total_time / 1000 << " ms";
LOG(INFO) << "total_rtf " << (double)total_time/ (total_length*1000000);
LOG(INFO) << "speedup " << 1.0/((double)total_time/ (total_length*1000000));
FunASRUninit(asr_handle);
return 0;
}

View File

@@ -0,0 +1,144 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#ifndef _WIN32
#include <sys/time.h>
#else
#include <win_func.h>
#endif
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <glog/logging.h>
#include "libfunasrapi.h"
#include "tclap/CmdLine.h"
#include "com-define.h"
using namespace std;
void GetValue(TCLAP::ValueArg<std::string>& value_arg, string key, std::map<std::string, std::string>& model_path)
{
if (value_arg.isSet()){
model_path.insert({key, value_arg.getValue()});
LOG(INFO)<< key << " : " << value_arg.getValue();
}
}
int main(int argc, char *argv[])
{
google::InitGoogleLogging(argv[0]);
FLAGS_logtostderr = true;
TCLAP::CmdLine cmd("funasr-onnx-offline", ' ', "1.0");
TCLAP::ValueArg<std::string> vad_model("", VAD_MODEL_PATH, "vad model path", false, "", "string");
TCLAP::ValueArg<std::string> vad_cmvn("", VAD_CMVN_PATH, "vad cmvn path", false, "", "string");
TCLAP::ValueArg<std::string> vad_config("", VAD_CONFIG_PATH, "vad config path", false, "", "string");
TCLAP::ValueArg<std::string> am_model("", AM_MODEL_PATH, "am model path", true, "", "string");
TCLAP::ValueArg<std::string> am_cmvn("", AM_CMVN_PATH, "am cmvn path", true, "", "string");
TCLAP::ValueArg<std::string> am_config("", AM_CONFIG_PATH, "am config path", true, "", "string");
TCLAP::ValueArg<std::string> punc_model("", PUNC_MODEL_PATH, "punc model path", false, "", "string");
TCLAP::ValueArg<std::string> punc_config("", PUNC_CONFIG_PATH, "punc config path", false, "", "string");
TCLAP::ValueArg<std::string> wav_path("", WAV_PATH, "wave file path", false, "", "string");
TCLAP::ValueArg<std::string> wav_scp("", WAV_SCP, "wave scp path", false, "", "string");
cmd.add(vad_model);
cmd.add(vad_cmvn);
cmd.add(vad_config);
cmd.add(am_model);
cmd.add(am_cmvn);
cmd.add(am_config);
cmd.add(punc_model);
cmd.add(punc_config);
cmd.add(wav_path);
cmd.add(wav_scp);
cmd.parse(argc, argv);
std::map<std::string, std::string> model_path;
GetValue(vad_model, VAD_MODEL_PATH, model_path);
GetValue(vad_cmvn, VAD_CMVN_PATH, model_path);
GetValue(vad_config, VAD_CONFIG_PATH, model_path);
GetValue(am_model, AM_MODEL_PATH, model_path);
GetValue(am_cmvn, AM_CMVN_PATH, model_path);
GetValue(am_config, AM_CONFIG_PATH, model_path);
GetValue(punc_model, PUNC_MODEL_PATH, model_path);
GetValue(punc_config, PUNC_CONFIG_PATH, model_path);
GetValue(wav_path, WAV_PATH, model_path);
GetValue(wav_scp, WAV_SCP, model_path);
struct timeval start, end;
gettimeofday(&start, NULL);
int thread_num = 1;
FUNASR_HANDLE asr_hanlde=FunASRInit(model_path, thread_num);
if (!asr_hanlde)
{
LOG(ERROR) << "FunASR init failed";
exit(-1);
}
gettimeofday(&end, NULL);
long seconds = (end.tv_sec - start.tv_sec);
long modle_init_micros = ((seconds * 1000000) + end.tv_usec) - (start.tv_usec);
LOG(INFO) << "Model initialization takes " << (double)modle_init_micros / 1000000 << " s";
// read wav_path and wav_scp
vector<string> wav_list;
if(model_path.find(WAV_PATH)!=model_path.end()){
wav_list.emplace_back(model_path.at(WAV_PATH));
}
if(model_path.find(WAV_SCP)!=model_path.end()){
ifstream in(model_path.at(WAV_SCP));
if (!in.is_open()) {
LOG(ERROR) << "Failed to open file: " << model_path.at(WAV_SCP) ;
return 0;
}
string line;
while(getline(in, line))
{
istringstream iss(line);
string column1, column2;
iss >> column1 >> column2;
wav_list.emplace_back(column2);
}
in.close();
}
float snippet_time = 0.0f;
long taking_micros = 0;
for(auto& wav_file : wav_list){
gettimeofday(&start, NULL);
FUNASR_RESULT result=FunASRRecogFile(asr_hanlde, wav_file.c_str(), RASR_NONE, NULL);
gettimeofday(&end, NULL);
seconds = (end.tv_sec - start.tv_sec);
taking_micros += ((seconds * 1000000) + end.tv_usec) - (start.tv_usec);
if (result)
{
string msg = FunASRGetResult(result, 0);
setbuf(stdout, NULL);
printf("Result: %s \n", msg.c_str());
snippet_time += FunASRGetRetSnippetTime(result);
FunASRFreeResult(result);
}
else
{
LOG(ERROR) << ("No return data!\n");
}
}
LOG(INFO) << "Audio length: " << (double)snippet_time << " s";
LOG(INFO) << "Model inference takes: " << (double)taking_micros / 1000000 <<" s";
LOG(INFO) << "Model inference RTF: " << (double)taking_micros/ (snippet_time*1000000);
FunASRUninit(asr_hanlde);
return 0;
}

View File

@@ -0,0 +1,210 @@
#include "precomp.h"
#ifdef __cplusplus
extern "C" {
#endif
// APIs for funasr
_FUNASRAPI FUNASR_HANDLE FunASRInit(std::map<std::string, std::string>& model_path, int thread_num)
{
Model* mm = CreateModel(model_path, thread_num);
return mm;
}
_FUNASRAPI FUNASR_HANDLE FunVadInit(std::map<std::string, std::string>& model_path, int thread_num)
{
Model* mm = CreateModel(model_path, thread_num);
return mm;
}
_FUNASRAPI FUNASR_RESULT FunASRRecogBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, FUNASR_MODE mode, QM_CALLBACK fn_callback)
{
Model* recog_obj = (Model*)handle;
if (!recog_obj)
return nullptr;
int32_t sampling_rate = -1;
Audio audio(1);
if (!audio.LoadWav(sz_buf, n_len, &sampling_rate))
return nullptr;
if(recog_obj->UseVad()){
audio.Split(recog_obj);
}
float* buff;
int len;
int flag=0;
FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT;
p_result->snippet_time = audio.GetTimeLen();
int n_step = 0;
int n_total = audio.GetQueueSize();
while (audio.Fetch(buff, len, flag) > 0) {
string msg = recog_obj->Forward(buff, len, flag);
p_result->msg += msg;
n_step++;
if (fn_callback)
fn_callback(n_step, n_total);
}
if(recog_obj->UsePunc()){
string punc_res = recog_obj->AddPunc((p_result->msg).c_str());
p_result->msg = punc_res;
}
return p_result;
}
_FUNASRAPI FUNASR_RESULT FunASRRecogPCMBuffer(FUNASR_HANDLE handle, const char* sz_buf, int n_len, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback)
{
Model* recog_obj = (Model*)handle;
if (!recog_obj)
return nullptr;
Audio audio(1);
if (!audio.LoadPcmwav(sz_buf, n_len, &sampling_rate))
return nullptr;
if(recog_obj->UseVad()){
audio.Split(recog_obj);
}
float* buff;
int len;
int flag = 0;
FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT;
p_result->snippet_time = audio.GetTimeLen();
int n_step = 0;
int n_total = audio.GetQueueSize();
while (audio.Fetch(buff, len, flag) > 0) {
string msg = recog_obj->Forward(buff, len, flag);
p_result->msg += msg;
n_step++;
if (fn_callback)
fn_callback(n_step, n_total);
}
if(recog_obj->UsePunc()){
string punc_res = recog_obj->AddPunc((p_result->msg).c_str());
p_result->msg = punc_res;
}
return p_result;
}
_FUNASRAPI FUNASR_RESULT FunASRRecogPCMFile(FUNASR_HANDLE handle, const char* sz_filename, int sampling_rate, FUNASR_MODE mode, QM_CALLBACK fn_callback)
{
Model* recog_obj = (Model*)handle;
if (!recog_obj)
return nullptr;
Audio audio(1);
if (!audio.LoadPcmwav(sz_filename, &sampling_rate))
return nullptr;
if(recog_obj->UseVad()){
audio.Split(recog_obj);
}
float* buff;
int len;
int flag = 0;
FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT;
p_result->snippet_time = audio.GetTimeLen();
int n_step = 0;
int n_total = audio.GetQueueSize();
while (audio.Fetch(buff, len, flag) > 0) {
string msg = recog_obj->Forward(buff, len, flag);
p_result->msg += msg;
n_step++;
if (fn_callback)
fn_callback(n_step, n_total);
}
if(recog_obj->UsePunc()){
string punc_res = recog_obj->AddPunc((p_result->msg).c_str());
p_result->msg = punc_res;
}
return p_result;
}
_FUNASRAPI FUNASR_RESULT FunASRRecogFile(FUNASR_HANDLE handle, const char* sz_wavfile, FUNASR_MODE mode, QM_CALLBACK fn_callback)
{
Model* recog_obj = (Model*)handle;
if (!recog_obj)
return nullptr;
int32_t sampling_rate = -1;
Audio audio(1);
if(!audio.LoadWav(sz_wavfile, &sampling_rate))
return nullptr;
if(recog_obj->UseVad()){
audio.Split(recog_obj);
}
float* buff;
int len;
int flag = 0;
int n_step = 0;
int n_total = audio.GetQueueSize();
FUNASR_RECOG_RESULT* p_result = new FUNASR_RECOG_RESULT;
p_result->snippet_time = audio.GetTimeLen();
while (audio.Fetch(buff, len, flag) > 0) {
string msg = recog_obj->Forward(buff, len, flag);
p_result->msg+= msg;
n_step++;
if (fn_callback)
fn_callback(n_step, n_total);
}
if(recog_obj->UsePunc()){
string punc_res = recog_obj->AddPunc((p_result->msg).c_str());
p_result->msg = punc_res;
}
return p_result;
}
_FUNASRAPI const int FunASRGetRetNumber(FUNASR_RESULT result)
{
if (!result)
return 0;
return 1;
}
_FUNASRAPI const float FunASRGetRetSnippetTime(FUNASR_RESULT result)
{
if (!result)
return 0.0f;
return ((FUNASR_RECOG_RESULT*)result)->snippet_time;
}
_FUNASRAPI const char* FunASRGetResult(FUNASR_RESULT result,int n_index)
{
FUNASR_RECOG_RESULT * p_result = (FUNASR_RECOG_RESULT*)result;
if(!p_result)
return nullptr;
return p_result->msg.c_str();
}
_FUNASRAPI void FunASRFreeResult(FUNASR_RESULT result)
{
if (result)
{
delete (FUNASR_RECOG_RESULT*)result;
}
}
_FUNASRAPI void FunASRUninit(FUNASR_HANDLE handle)
{
Model* recog_obj = (Model*)handle;
if (!recog_obj)
return;
delete recog_obj;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,8 @@
#include "precomp.h"
Model *CreateModel(std::map<std::string, std::string>& model_path, int thread_num)
{
Model *mm;
mm = new paraformer::Paraformer(model_path, thread_num);
return mm;
}

View File

@@ -0,0 +1,133 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#include "online-feature.h"
#include <utility>
OnlineFeature::OnlineFeature(int sample_rate, knf::FbankOptions fbank_opts, int lfr_m, int lfr_n,
std::vector<std::vector<float>> cmvns)
: sample_rate_(sample_rate),
fbank_opts_(std::move(fbank_opts)),
lfr_m_(lfr_m),
lfr_n_(lfr_n),
cmvns_(std::move(cmvns)) {
frame_sample_length_ = sample_rate_ / 1000 * 25;;
frame_shift_sample_length_ = sample_rate_ / 1000 * 10;
}
void OnlineFeature::ExtractFeats(vector<std::vector<float>> &vad_feats,
vector<float> waves, bool input_finished) {
input_finished_ = input_finished;
OnlineFbank(vad_feats, waves);
// cache deal & online lfr,cmvn
if (vad_feats.size() > 0) {
if (!reserve_waveforms_.empty()) {
waves.insert(waves.begin(), reserve_waveforms_.begin(), reserve_waveforms_.end());
}
if (lfr_splice_cache_.empty()) {
for (int i = 0; i < (lfr_m_ - 1) / 2; i++) {
lfr_splice_cache_.emplace_back(vad_feats[0]);
}
}
if (vad_feats.size() + lfr_splice_cache_.size() >= lfr_m_) {
vad_feats.insert(vad_feats.begin(), lfr_splice_cache_.begin(), lfr_splice_cache_.end());
int frame_from_waves = (waves.size() - frame_sample_length_) / frame_shift_sample_length_ + 1;
int minus_frame = reserve_waveforms_.empty() ? (lfr_m_ - 1) / 2 : 0;
int lfr_splice_frame_idxs = OnlineLfrCmvn(vad_feats);
int reserve_frame_idx = lfr_splice_frame_idxs - minus_frame;
reserve_waveforms_.clear();
reserve_waveforms_.insert(reserve_waveforms_.begin(),
waves.begin() + reserve_frame_idx * frame_shift_sample_length_,
waves.begin() + frame_from_waves * frame_shift_sample_length_);
int sample_length = (frame_from_waves - 1) * frame_shift_sample_length_ + frame_sample_length_;
waves.erase(waves.begin() + sample_length, waves.end());
} else {
reserve_waveforms_.clear();
reserve_waveforms_.insert(reserve_waveforms_.begin(),
waves.begin() + frame_sample_length_ - frame_shift_sample_length_, waves.end());
lfr_splice_cache_.insert(lfr_splice_cache_.end(), vad_feats.begin(), vad_feats.end());
}
} else {
if (input_finished_) {
if (!reserve_waveforms_.empty()) {
waves = reserve_waveforms_;
}
vad_feats = lfr_splice_cache_;
OnlineLfrCmvn(vad_feats);
ResetCache();
}
}
}
int OnlineFeature::OnlineLfrCmvn(vector<vector<float>> &vad_feats) {
vector<vector<float>> out_feats;
int T = vad_feats.size();
int T_lrf = ceil((T - (lfr_m_ - 1) / 2) / lfr_n_);
int lfr_splice_frame_idxs = T_lrf;
vector<float> p;
for (int i = 0; i < T_lrf; i++) {
if (lfr_m_ <= T - i * lfr_n_) {
for (int j = 0; j < lfr_m_; j++) {
p.insert(p.end(), vad_feats[i * lfr_n_ + j].begin(), vad_feats[i * lfr_n_ + j].end());
}
out_feats.emplace_back(p);
p.clear();
} else {
if (input_finished_) {
int num_padding = lfr_m_ - (T - i * lfr_n_);
for (int j = 0; j < (vad_feats.size() - i * lfr_n_); j++) {
p.insert(p.end(), vad_feats[i * lfr_n_ + j].begin(), vad_feats[i * lfr_n_ + j].end());
}
for (int j = 0; j < num_padding; j++) {
p.insert(p.end(), vad_feats[vad_feats.size() - 1].begin(), vad_feats[vad_feats.size() - 1].end());
}
out_feats.emplace_back(p);
} else {
lfr_splice_frame_idxs = i;
break;
}
}
}
lfr_splice_frame_idxs = std::min(T - 1, lfr_splice_frame_idxs * lfr_n_);
lfr_splice_cache_.clear();
lfr_splice_cache_.insert(lfr_splice_cache_.begin(), vad_feats.begin() + lfr_splice_frame_idxs, vad_feats.end());
// Apply cmvn
for (auto &out_feat: out_feats) {
for (int j = 0; j < cmvns_[0].size(); j++) {
out_feat[j] = (out_feat[j] + cmvns_[0][j]) * cmvns_[1][j];
}
}
vad_feats = out_feats;
return lfr_splice_frame_idxs;
}
void OnlineFeature::OnlineFbank(vector<std::vector<float>> &vad_feats,
vector<float> &waves) {
knf::OnlineFbank fbank(fbank_opts_);
// cache merge
waves.insert(waves.begin(), input_cache_.begin(), input_cache_.end());
int frame_number = ComputeFrameNum(waves.size(), frame_sample_length_, frame_shift_sample_length_);
// Send the audio after the last frame shift position to the cache
input_cache_.clear();
input_cache_.insert(input_cache_.begin(), waves.begin() + frame_number * frame_shift_sample_length_, waves.end());
if (frame_number == 0) {
return;
}
// Delete audio that haven't undergone fbank processing
waves.erase(waves.begin() + (frame_number - 1) * frame_shift_sample_length_ + frame_sample_length_, waves.end());
fbank.AcceptWaveform(sample_rate_, &waves[0], waves.size());
int32_t frames = fbank.NumFramesReady();
for (int32_t i = 0; i != frames; ++i) {
const float *frame = fbank.GetFrame(i);
vector<float> frame_vector(frame, frame + fbank_opts_.mel_opts.num_bins);
vad_feats.emplace_back(frame_vector);
}
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#include <vector>
#include "precomp.h"
using namespace std;
class OnlineFeature {
public:
OnlineFeature(int sample_rate, knf::FbankOptions fbank_opts, int lfr_m_, int lfr_n_,
std::vector<std::vector<float>> cmvns_);
void ExtractFeats(vector<vector<float>> &vad_feats, vector<float> waves, bool input_finished);
private:
void OnlineFbank(vector<vector<float>> &vad_feats, vector<float> &waves);
int OnlineLfrCmvn(vector<vector<float>> &vad_feats);
static int ComputeFrameNum(int sample_length, int frame_sample_length, int frame_shift_sample_length) {
int frame_num = static_cast<int>((sample_length - frame_sample_length) / frame_shift_sample_length + 1);
if (frame_num >= 1 && sample_length >= frame_sample_length)
return frame_num;
else
return 0;
}
void ResetCache() {
reserve_waveforms_.clear();
input_cache_.clear();
lfr_splice_cache_.clear();
input_finished_ = false;
}
knf::FbankOptions fbank_opts_;
// The reserved waveforms by fbank
std::vector<float> reserve_waveforms_;
// waveforms reserved after last shift position
std::vector<float> input_cache_;
// lfr reserved cache
std::vector<std::vector<float>> lfr_splice_cache_;
std::vector<std::vector<float>> cmvns_;
int sample_rate_ = 16000;
int frame_sample_length_ = sample_rate_ / 1000 * 25;;
int frame_shift_sample_length_ = sample_rate_ / 1000 * 10;
int lfr_m_;
int lfr_n_;
bool input_finished_ = false;
};

View File

@@ -0,0 +1,302 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#include "precomp.h"
using namespace std;
using namespace paraformer;
Paraformer::Paraformer(std::map<std::string, std::string>& model_path,int thread_num)
:env_(ORT_LOGGING_LEVEL_ERROR, "paraformer"),session_options{}{
// VAD model
if(model_path.find(VAD_MODEL_PATH) != model_path.end()){
use_vad = true;
string vad_model_path;
string vad_cmvn_path;
string vad_config_path;
try{
vad_model_path = model_path.at(VAD_MODEL_PATH);
vad_cmvn_path = model_path.at(VAD_CMVN_PATH);
vad_config_path = model_path.at(VAD_CONFIG_PATH);
}catch(const out_of_range& e){
LOG(ERROR) << "Error when read "<< VAD_CMVN_PATH << " or " << VAD_CONFIG_PATH <<" :" << e.what();
exit(0);
}
vad_handle = make_unique<FsmnVad>();
vad_handle->InitVad(vad_model_path, vad_cmvn_path, vad_config_path);
}
// AM model
if(model_path.find(AM_MODEL_PATH) != model_path.end()){
string am_model_path;
string am_cmvn_path;
string am_config_path;
try{
am_model_path = model_path.at(AM_MODEL_PATH);
am_cmvn_path = model_path.at(AM_CMVN_PATH);
am_config_path = model_path.at(AM_CONFIG_PATH);
}catch(const out_of_range& e){
LOG(ERROR) << "Error when read "<< AM_CONFIG_PATH << " or " << AM_CMVN_PATH <<" :" << e.what();
exit(0);
}
InitAM(am_model_path, am_cmvn_path, am_config_path, thread_num);
}
// PUNC model
if(model_path.find(PUNC_MODEL_PATH) != model_path.end()){
use_punc = true;
string punc_model_path;
string punc_config_path;
try{
punc_model_path = model_path.at(PUNC_MODEL_PATH);
punc_config_path = model_path.at(PUNC_CONFIG_PATH);
}catch(const out_of_range& e){
LOG(ERROR) << "Error when read "<< PUNC_CONFIG_PATH <<" :" << e.what();
exit(0);
}
punc_handle = make_unique<CTTransformer>();
punc_handle->InitPunc(punc_model_path, punc_config_path, thread_num);
}
}
void Paraformer::InitAM(const std::string &am_model, const std::string &am_cmvn, const std::string &am_config, int thread_num){
// knf options
fbank_opts.frame_opts.dither = 0;
fbank_opts.mel_opts.num_bins = 80;
fbank_opts.frame_opts.samp_freq = MODEL_SAMPLE_RATE;
fbank_opts.frame_opts.window_type = "hamming";
fbank_opts.frame_opts.frame_shift_ms = 10;
fbank_opts.frame_opts.frame_length_ms = 25;
fbank_opts.energy_floor = 0;
fbank_opts.mel_opts.debug_mel = false;
// fbank_ = std::make_unique<knf::OnlineFbank>(fbank_opts);
// session_options.SetInterOpNumThreads(1);
session_options.SetIntraOpNumThreads(thread_num);
session_options.SetGraphOptimizationLevel(ORT_ENABLE_ALL);
// DisableCpuMemArena can improve performance
session_options.DisableCpuMemArena();
try {
m_session = std::make_unique<Ort::Session>(env_, am_model.c_str(), session_options);
} catch (std::exception const &e) {
LOG(ERROR) << "Error when load am onnx model: " << e.what();
exit(0);
}
string strName;
GetInputName(m_session.get(), strName);
m_strInputNames.push_back(strName.c_str());
GetInputName(m_session.get(), strName,1);
m_strInputNames.push_back(strName);
GetOutputName(m_session.get(), strName);
m_strOutputNames.push_back(strName);
GetOutputName(m_session.get(), strName,1);
m_strOutputNames.push_back(strName);
for (auto& item : m_strInputNames)
m_szInputNames.push_back(item.c_str());
for (auto& item : m_strOutputNames)
m_szOutputNames.push_back(item.c_str());
vocab = new Vocab(am_config.c_str());
LoadCmvn(am_cmvn.c_str());
}
Paraformer::~Paraformer()
{
if(vocab)
delete vocab;
}
void Paraformer::Reset()
{
}
vector<std::vector<int>> Paraformer::VadSeg(std::vector<float>& pcm_data){
return vad_handle->Infer(pcm_data);
}
string Paraformer::AddPunc(const char* sz_input){
return punc_handle->AddPunc(sz_input);
}
vector<float> Paraformer::FbankKaldi(float sample_rate, const float* waves, int len) {
knf::OnlineFbank fbank_(fbank_opts);
fbank_.AcceptWaveform(sample_rate, waves, len);
//fbank_->InputFinished();
int32_t frames = fbank_.NumFramesReady();
int32_t feature_dim = fbank_opts.mel_opts.num_bins;
vector<float> features(frames * feature_dim);
float *p = features.data();
for (int32_t i = 0; i != frames; ++i) {
const float *f = fbank_.GetFrame(i);
std::copy(f, f + feature_dim, p);
p += feature_dim;
}
return features;
}
void Paraformer::LoadCmvn(const char *filename)
{
ifstream cmvn_stream(filename);
if (!cmvn_stream.is_open()) {
LOG(ERROR) << "Failed to open file: " << filename;
exit(0);
}
string line;
while (getline(cmvn_stream, line)) {
istringstream iss(line);
vector<string> line_item{istream_iterator<string>{iss}, istream_iterator<string>{}};
if (line_item[0] == "<AddShift>") {
getline(cmvn_stream, line);
istringstream means_lines_stream(line);
vector<string> means_lines{istream_iterator<string>{means_lines_stream}, istream_iterator<string>{}};
if (means_lines[0] == "<LearnRateCoef>") {
for (int j = 3; j < means_lines.size() - 1; j++) {
means_list.push_back(stof(means_lines[j]));
}
continue;
}
}
else if (line_item[0] == "<Rescale>") {
getline(cmvn_stream, line);
istringstream vars_lines_stream(line);
vector<string> vars_lines{istream_iterator<string>{vars_lines_stream}, istream_iterator<string>{}};
if (vars_lines[0] == "<LearnRateCoef>") {
for (int j = 3; j < vars_lines.size() - 1; j++) {
vars_list.push_back(stof(vars_lines[j])*scale);
}
continue;
}
}
}
}
string Paraformer::GreedySearch(float * in, int n_len, int64_t token_nums)
{
vector<int> hyps;
int Tmax = n_len;
for (int i = 0; i < Tmax; i++) {
int max_idx;
float max_val;
FindMax(in + i * token_nums, token_nums, max_val, max_idx);
hyps.push_back(max_idx);
}
return vocab->Vector2StringV2(hyps);
}
vector<float> Paraformer::ApplyLfr(const std::vector<float> &in)
{
int32_t in_feat_dim = fbank_opts.mel_opts.num_bins;
int32_t in_num_frames = in.size() / in_feat_dim;
int32_t out_num_frames =
(in_num_frames - lfr_window_size) / lfr_window_shift + 1;
int32_t out_feat_dim = in_feat_dim * lfr_window_size;
std::vector<float> out(out_num_frames * out_feat_dim);
const float *p_in = in.data();
float *p_out = out.data();
for (int32_t i = 0; i != out_num_frames; ++i) {
std::copy(p_in, p_in + out_feat_dim, p_out);
p_out += out_feat_dim;
p_in += lfr_window_shift * in_feat_dim;
}
return out;
}
void Paraformer::ApplyCmvn(std::vector<float> *v)
{
int32_t dim = means_list.size();
int32_t num_frames = v->size() / dim;
float *p = v->data();
for (int32_t i = 0; i != num_frames; ++i) {
for (int32_t k = 0; k != dim; ++k) {
p[k] = (p[k] + means_list[k]) * vars_list[k];
}
p += dim;
}
}
string Paraformer::Forward(float* din, int len, int flag)
{
int32_t in_feat_dim = fbank_opts.mel_opts.num_bins;
std::vector<float> wav_feats = FbankKaldi(MODEL_SAMPLE_RATE, din, len);
wav_feats = ApplyLfr(wav_feats);
ApplyCmvn(&wav_feats);
int32_t feat_dim = lfr_window_size*in_feat_dim;
int32_t num_frames = wav_feats.size() / feat_dim;
#ifdef _WIN_X86
Ort::MemoryInfo m_memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
#else
Ort::MemoryInfo m_memoryInfo = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
#endif
const int64_t input_shape_[3] = {1, num_frames, feat_dim};
Ort::Value onnx_feats = Ort::Value::CreateTensor<float>(m_memoryInfo,
wav_feats.data(),
wav_feats.size(),
input_shape_,
3);
const int64_t paraformer_length_shape[1] = {1};
std::vector<int32_t> paraformer_length;
paraformer_length.emplace_back(num_frames);
Ort::Value onnx_feats_len = Ort::Value::CreateTensor<int32_t>(
m_memoryInfo, paraformer_length.data(), paraformer_length.size(), paraformer_length_shape, 1);
std::vector<Ort::Value> input_onnx;
input_onnx.emplace_back(std::move(onnx_feats));
input_onnx.emplace_back(std::move(onnx_feats_len));
string result;
try {
auto outputTensor = m_session->Run(Ort::RunOptions{nullptr}, m_szInputNames.data(), input_onnx.data(), input_onnx.size(), m_szOutputNames.data(), m_szOutputNames.size());
std::vector<int64_t> outputShape = outputTensor[0].GetTensorTypeAndShapeInfo().GetShape();
int64_t outputCount = std::accumulate(outputShape.begin(), outputShape.end(), 1, std::multiplies<int64_t>());
float* floatData = outputTensor[0].GetTensorMutableData<float>();
auto encoder_out_lens = outputTensor[1].GetTensorMutableData<int64_t>();
result = GreedySearch(floatData, *encoder_out_lens, outputShape[2]);
}
catch (std::exception const &e)
{
printf(e.what());
}
return result;
}
string Paraformer::ForwardChunk(float* din, int len, int flag)
{
printf("Not Imp!!!!!!\n");
return "Hello";
}
string Paraformer::Rescoring()
{
printf("Not Imp!!!!!!\n");
return "Hello";
}

View File

@@ -0,0 +1,68 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#pragma once
#ifndef PARAFORMER_MODELIMP_H
#define PARAFORMER_MODELIMP_H
#include "precomp.h"
namespace paraformer {
class Paraformer : public Model {
/**
* Author: Speech Lab of DAMO Academy, Alibaba Group
* Paraformer: Fast and Accurate Parallel Transformer for Non-autoregressive End-to-End Speech Recognition
* https://arxiv.org/pdf/2206.08317.pdf
*/
private:
//std::unique_ptr<knf::OnlineFbank> fbank_;
knf::FbankOptions fbank_opts;
std::unique_ptr<FsmnVad> vad_handle;
std::unique_ptr<CTTransformer> punc_handle;
Vocab* vocab;
vector<float> means_list;
vector<float> vars_list;
const float scale = 22.6274169979695;
int32_t lfr_window_size = 7;
int32_t lfr_window_shift = 6;
void LoadCmvn(const char *filename);
vector<float> ApplyLfr(const vector<float> &in);
void ApplyCmvn(vector<float> *v);
string GreedySearch( float* in, int n_len, int64_t token_nums);
std::shared_ptr<Ort::Session> m_session;
Ort::Env env_;
Ort::SessionOptions session_options;
vector<string> m_strInputNames, m_strOutputNames;
vector<const char*> m_szInputNames;
vector<const char*> m_szOutputNames;
bool use_vad=false;
bool use_punc=false;
public:
Paraformer(std::map<std::string, std::string>& model_path, int thread_num=0);
~Paraformer();
void InitAM(const std::string &am_model, const std::string &am_cmvn, const std::string &am_config, int thread_num);
void Reset();
vector<float> FbankKaldi(float sample_rate, const float* waves, int len);
string ForwardChunk(float* din, int len, int flag);
string Forward(float* din, int len, int flag);
string Rescoring();
std::vector<std::vector<int>> VadSeg(std::vector<float>& pcm_data);
string AddPunc(const char* sz_input);
bool UseVad(){return use_vad;};
bool UsePunc(){return use_punc;};
};
} // namespace paraformer
#endif

View File

@@ -0,0 +1,47 @@
#pragma once
// system
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <deque>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iterator>
#include <list>
#include <locale.h>
#include <vector>
#include <string>
#include <math.h>
#include <numeric>
#include <cstring>
using namespace std;
// third part
#include "onnxruntime_run_options_config_keys.h"
#include "onnxruntime_cxx_api.h"
#include "kaldi-native-fbank/csrc/feature-fbank.h"
#include "kaldi-native-fbank/csrc/online-feature.h"
// mine
#include <glog/logging.h>
#include "common-struct.h"
#include "com-define.h"
#include "commonfunc.h"
#include "predefine-coe.h"
#include "tokenizer.h"
#include "ct-transformer.h"
#include "fsmn-vad.h"
#include "e2e-vad.h"
#include "vocab.h"
#include "audio.h"
#include "tensor.h"
#include "util.h"
#include "resample.h"
#include "model.h"
//#include "vad-model.h"
#include "paraformer.h"
#include "libfunasrapi.h"
using namespace paraformer;

View File

@@ -0,0 +1,592 @@
#ifndef PREDEFINE_COE_H
#define PREDEFINE_COE_H
#include <stdint.h>
const int32_t melcoe_hex[] = {
0x3f01050c, 0x3e0afb11, 0x3f5d413c, 0x3f547fd0, 0x3e2e00c1, 0x3f132970,
0x3ed9ad21, 0x3ebb8bb9, 0x3f223a24, 0x3e4de6f8, 0x3f4c8642, 0x3d9c0424,
0x3f6c7f7c, 0x3f7d295a, 0x3c35a961, 0x3f6fd497, 0x3d815b45, 0x3f6af197,
0x3da87344, 0x3f6dfce9, 0x3d9018b9, 0x3f787ebc, 0x3d2098fe, 0x3cf02873,
0x3f75f670, 0x3e08e423, 0x3f5dc6f7, 0x3e8161eb, 0x3f3f4f0b, 0x3eca38e2,
0x3f1ae38f, 0x3f0f2d23, 0x3ee1a5ba, 0x3f3e9a98, 0x3e82cad1, 0x3f7321ac,
0x3e321028, 0x3d4de548, 0x3f537bf6, 0x3ed50f76, 0x3f157845, 0x3f2cf6bc,
0x3ea61288, 0x3f739ea7, 0x3e794186, 0x3d461590, 0x3f41af9f, 0x3f0cdfd4,
0x3ee64058, 0x3f5f23aa, 0x3e53d467, 0x3e037156, 0x3f4b0ae6, 0x3f0e2fac,
0x3ee3a0a8, 0x3f6ab111, 0x3e94b1ed, 0x3daa7774, 0x3f35a70a, 0x3f2d08dc,
0x3d951fb4, 0x3ea5ee48, 0x3f6d5c09, 0x3ef61e1a, 0x3f04f0f3, 0x3f66305c,
0x3ea7def9, 0x3dce7d20, 0x3f2c1083, 0x3f44354b, 0x3e5baf49, 0x3e6f2ad2,
0x3f49142e, 0x3f2bfe35, 0x3e0d627b, 0x3ea80396, 0x3f5ca761, 0x3f1ce830,
0x3dc4d786, 0x3ec62fa0, 0x3f67650f, 0x3f165fc0, 0x3db1323f, 0x3ed34080,
0x3f69d9b8, 0x3f17def1, 0x3ddbd6b6, 0x3ed0421e, 0x3f648529, 0x3f20ebbd,
0x3e20901a, 0x3ebe2886, 0x3f57dbf9, 0x3f3116ac, 0x3e6edcc6, 0x3e9dd2a9,
0x3f4448ce, 0x3f47f9a3, 0x3eaba511, 0x3e601974, 0x3f2a2d77, 0x3f6536e2,
0x3eec3842, 0x3d0781f6, 0x3dd648ed, 0x3f09e3df, 0x3f7787e1, 0x3f1c411f,
0x3e45b702, 0x3ec77dc2, 0x3f4e9240, 0x3f47f500, 0x3ebf9c61, 0x3e602c00,
0x3f2031d0, 0x3f78f0f7, 0x3f135547, 0x3e3bcd78, 0x3ce1e12a, 0x3ed95573,
0x3f510ca2, 0x3f4bc3c2, 0x3ed37e77, 0x3d0ded37, 0x3e50f0f8, 0x3f1640c5,
0x3f77212d, 0x3f291bd1, 0x3e94df6c, 0x3eadc85e, 0x3f35904a, 0x3f6cd43b,
0x3f104351, 0x3e52dc63, 0x3d995e26, 0x3edf795f, 0x3f4b48e7, 0x3f5a29e7,
0x3f00963d, 0x3e1fdb2f, 0x3e175865, 0x3efed385, 0x3f580934, 0x3f50466d,
0x3ef30046, 0x3e0e7c6b, 0x3e3ee64e, 0x3f067fdd, 0x3f5c60e5, 0x3f4e9ea4,
0x3ef4f46a, 0x3e1cb596, 0x3e45856f, 0x3f0585cb, 0x3f58d29b, 0x3f54b3ef,
0x3f0309ad, 0x3e48aa5b, 0x3e2d3042, 0x3ef9eca6, 0x3f4dd569, 0x3f6212c4,
0x3f12be68, 0x3e8853a3, 0x3def69e0, 0x3eda8330, 0x3f3bd62e, 0x3f76516a,
0x3f2931b5, 0x3eb98e9b, 0x3d88773c, 0x3d1ae95c, 0x3ead9c96, 0x3f2338b2,
0x3f6ef119, 0x3f46054d, 0x3ef74eba, 0x3e47c83a, 0x3e67eace, 0x3f0458a3,
0x3f4e0df1, 0x3f68e26b, 0x3f207590, 0x3eb1515d, 0x3d8bc852, 0x3db8eca9,
0x3ebf14e0, 0x3f275751, 0x3f6e86f6, 0x3f4ae3f8, 0x3f04e6de, 0x3e7dfcce,
0x3e547020, 0x3ef63244, 0x3f4080cd, 0x3f7aaa80, 0x3f366659, 0x3ee560cb,
0x3e3e1967, 0x3caab00e, 0x3e93334e, 0x3f0d4f9a, 0x3f5079a6, 0x3f6ce5f8,
0x3f2acd10, 0x3ed272ff, 0x3e20a4c5, 0x3d98d042, 0x3eaa65e0, 0x3f16c680,
0x3f57d6cf, 0x3f679a1b, 0x3f278a40, 0x3ecfef5c, 0x3e2381fd, 0x3dc32f28,
0x3eb0eb80, 0x3f180852, 0x3f571f81, 0x3f6a42d8, 0x3f2c1ce8, 0x3edcd9d1,
0x3e44c475, 0x3dade93f, 0x3ea7c630, 0x3f119318, 0x3f4ecee3, 0x3f7467d4,
0x3f380f62, 0x3ef84c54, 0x3e815525, 0x3cb361d7, 0x3d3982c8, 0x3e8fe13b,
0x3f03d9d6, 0x3f3f556d, 0x3f7a64f1, 0x3f4af618, 0x3f10ba30, 0x3eadcbc5,
0x3debbe02, 0x3e5427a0, 0x3ede8b9f, 0x3f291a1d, 0x3f628840, 0x3f646e63,
0x3f2bc86b, 0x3ee70902, 0x3e6e854e, 0x3c83b300, 0x3ddc8cea, 0x3ea86f2a,
0x3f0c7b7f, 0x3f445eac, 0x3f7be268, 0x3f4cf80b, 0x3f162f6e, 0x3ebf8516,
0x3e26c0c2, 0x3e4c1fd5, 0x3ed3a124, 0x3f203d75, 0x3f564fd0, 0x3f73f733,
0x3f3e966d, 0x3f098cbf, 0x3ea9b21c, 0x3e01e917, 0x3d408cd1, 0x3e82d326,
0x3eece682, 0x3f2b26f2, 0x3f5f85ba, 0x3f6c6f56, 0x3f38b733, 0x3f0550d9,
0x3ea47689, 0x3dfbabd7, 0x3d9c8552, 0x3e8e919a, 0x3ef55e4f, 0x3f2dc4bb,
0x3f608a85, 0x3f6cfe84, 0x3f3ad56c, 0x3f08f945, 0x3eaed247, 0x3e189086,
0x3d980be2, 0x3e8a5528, 0x3eee0d76, 0x3f2896dc, 0x3f59dbde, 0x3f75295d,
0x3f4477f6, 0x3f140f14, 0x3ec7dbbd, 0x3e504e0f, 0x3c8fe67e, 0x3d2d6a38,
0x3e6e2028, 0x3ed7e1d9, 0x3f1c1221, 0x3f4bec7c, 0x3f7b80cc, 0x3f553023,
0x3f262589, 0x3eeebd40, 0x3e91b54d, 0x3dd4c6f8, 0x3e2b3f74, 0x3eb3b4ef,
0x3f08a160, 0x3f372559, 0x3f656721, 0x3f6c988d, 0x3f3ed8f9, 0x3f11596d,
0x3ec83270, 0x3e5c5ea4, 0x3d254149, 0x3d9b3b97, 0x3e824e0e, 0x3edd4d25,
0x3f1be6c8, 0x3f48e857, 0x3f75abeb, 0x3f5dcdd1, 0x3f318436, 0x3f0576a0,
0x3eb348db, 0x3e3833fb, 0x3c2bedc9, 0x3e08c8be, 0x3e9cf794, 0x3ef512c0,
0x3f265b92, 0x3f51f301, 0x3f7d5049, 0x3f578bfc, 0x3f2ca136, 0x3f01eecf,
0x3eaee867, 0x3e34c34c, 0x3c490794, 0x3e21d00f, 0x3ea6bd94, 0x3efc2262,
0x3f288bcc, 0x3f52cf2d, 0x3f7cdbe2, 0x3f594d89, 0x3f2fac87, 0x3f064092,
0x3eba1245, 0x3e5016cd, 0x3d335c27, 0x3e1ac9dd, 0x3ea0a6f1, 0x3ef37edc,
0x3f22f6de, 0x3f4bfa4d, 0x3f74ca3e, 0x3f6298cf, 0x3f3a2e5b, 0x3f11f5e8,
0x3ed3ddf9, 0x3e84323c, 0x3dd39eaa, 0x3deb3986, 0x3e8ba34a, 0x3edc142f,
0x3f161103, 0x3f3de6e2, 0x3f658c2b, 0x3f72feac, 0x3f4bb92e, 0x3f24a2e9,
0x3efb76d9, 0x3eae048f, 0x3e41dc34, 0x3d219509, 0x3d50153e, 0x3e511b46,
0x3eb6ba2d, 0x3f024494, 0x3f28fdb9, 0x3f4f88f3, 0x3f75e6af, 0x3f63e8a7,
0x3f3de4a8, 0x3f180cea, 0x3ee4c20e, 0x3e99c134, 0x3e1e2cfc, 0x3c1824f4,
0x3de0bac6, 0x3e8436b1, 0x3ecfe62d, 0x3f0d9ef9, 0x3f331f66, 0x3f5874c1,
0x3f7d9f6c, 0x3f5d6037, 0x3f3889c9, 0x3f13dcea, 0x3edeb27d, 0x3e95fcd3,
0x3e1b303e, 0x3c3075cb, 0x3e0a7f24, 0x3e8eec6e, 0x3ed8462b, 0x3f10a6c1,
0x3f350197, 0x3f5933f1, 0x3f7d3e29, 0x3f5edf68, 0x3f3b246a, 0x3f179088,
0x3ee846d8, 0x3ea1b983, 0x3e36f0d8, 0x3d2c1773, 0x3e048260, 0x3e89b72b,
0x3ed0def0, 0x3f0bdc94, 0x3f2f233e, 0x3f5243ca, 0x3f753e89, 0x3f67ec34,
0x3f453c1d, 0x3f22b0e2, 0x3f004a36, 0x3ebc0f98, 0x3e6fa55d, 0x3dcf7467,
0x3dc09e5f, 0x3e6b0f8d, 0x3eba9e3c, 0x3eff6b94, 0x3f21f834, 0x3f4416a9,
0x3f661173, 0x3f781723, 0x3f5662cf, 0x3f34d14a, 0x3f13624c, 0x3ee42b1a,
0x3ea1d591, 0x3e3f86e3, 0x3d6fa1a1, 0x3cfd1ba9, 0x3e2674c3, 0x3e965d6c,
0x3ed93b69, 0x3f0dea73, 0x3f2f1538, 0x3f501e47, 0x3f7105e6, 0x3f6e33a9,
0x3f4d8e22, 0x3f2d0944, 0x3f0ca4cd, 0x3ed8c0fd, 0x3e98782f, 0x3e30dd66,
0x3d452061, 0x3d8e62bc, 0x3e49c779, 0x3ea5ed78, 0x3ee6b665, 0x3f139f81,
0x3f33c3e8, 0x3f53c8a7, 0x3f73adfa, 0x3f6c8be0, 0x3f4ce4ab, 0x3f2d5c2a,
0x3f0df223, 0x3edd4cb5, 0x3e9ef12d, 0x3e41a276, 0x3d8bb1ba, 0x3d9ba0ff,
0x3e4c6d54, 0x3ea547ab, 0x3ee41bba, 0x3f1159a6, 0x3f30876a, 0x3f4f9762,
0x3f6e89c9, 0x3f72a12b, 0x3f53e942, 0x3f354e46, 0x3f16cffe, 0x3ef0dc6f,
0x3eb45177, 0x3e6ffd59, 0x3def8e9c
};
const int32_t window_hex[] = {
0x00000000, 0x398b03f6, 0x3a61d1c5, 0x3ae0ee32, 0x3b37623a, 0x3b85f871,
0x3bb69d19, 0x3bed453b, 0x3c14d40b, 0x3c35c45b, 0x3c59595d, 0x3c7f7c1d,
0x3c940c13, 0x3ca98d81, 0x3cc039eb, 0x3cd8098d, 0x3cf0f52e, 0x3d057b06,
0x3d1302e6, 0x3d210f33, 0x3d2f9d0e, 0x3d3ea9ba, 0x3d4e3293, 0x3d5e3510,
0x3d6eaebd, 0x3d7f9d38, 0x3d887f19, 0x3d9167b5, 0x3d9a8756, 0x3da3dce9,
0x3dad675d, 0x3db725ab, 0x3dc116cc, 0x3dcb39bf, 0x3dd58d86, 0x3de01126,
0x3deac3a7, 0x3df5a413, 0x3e0058bb, 0x3e05f571, 0x3e0ba7b2, 0x3e116f08,
0x3e174afe, 0x3e1d3b1c, 0x3e233ef0, 0x3e295605, 0x3e2f7fe7, 0x3e35bc23,
0x3e3c0a46, 0x3e4269de, 0x3e48da79, 0x3e4f5ba5, 0x3e55ecf2, 0x3e5c8ded,
0x3e633e26, 0x3e69fd2c, 0x3e70ca8f, 0x3e77a5de, 0x3e7e8eaa, 0x3e82c241,
0x3e86437c, 0x3e89cacd, 0x3e8d57fc, 0x3e90ead3, 0x3e948319, 0x3e982097,
0x3e9bc316, 0x3e9f6a5d, 0x3ea31636, 0x3ea6c66a, 0x3eaa7ac0, 0x3eae3303,
0x3eb1eefa, 0x3eb5ae6f, 0x3eb9712a, 0x3ebd36f6, 0x3ec0ff9b, 0x3ec4cae2,
0x3ec89895, 0x3ecc687d, 0x3ed03a64, 0x3ed40e13, 0x3ed7e354, 0x3edbb9f2,
0x3edf91b5, 0x3ee36a69, 0x3ee743d7, 0x3eeb1dca, 0x3eeef80c, 0x3ef2d267,
0x3ef6aca8, 0x3efa8698, 0x3efe6002, 0x3f011c59, 0x3f03083a, 0x3f04f389,
0x3f06de2d, 0x3f08c80b, 0x3f0ab10a, 0x3f0c990f, 0x3f0e8001, 0x3f1065c6,
0x3f124a45, 0x3f142d65, 0x3f160f0c, 0x3f17ef21, 0x3f19cd8b, 0x3f1baa32,
0x3f1d84fb, 0x3f1f5dd0, 0x3f213498, 0x3f230939, 0x3f24db9d, 0x3f26abaa,
0x3f28794a, 0x3f2a4464, 0x3f2c0ce1, 0x3f2dd2a9, 0x3f2f95a6, 0x3f3155bf,
0x3f3312e0, 0x3f34ccef, 0x3f3683d8, 0x3f383784, 0x3f39e7dd, 0x3f3b94cc,
0x3f3d3e3c, 0x3f3ee418, 0x3f40864a, 0x3f4224bd, 0x3f43bf5c, 0x3f455613,
0x3f46e8cc, 0x3f487774, 0x3f4a01f6, 0x3f4b883f, 0x3f4d0a3b, 0x3f4e87d6,
0x3f5000fe, 0x3f5175a0, 0x3f52e5a9, 0x3f545106, 0x3f55b7a5, 0x3f571975,
0x3f587664, 0x3f59ce60, 0x3f5b2158, 0x3f5c6f3b, 0x3f5db7f9, 0x3f5efb80,
0x3f6039c2, 0x3f6172af, 0x3f62a636, 0x3f63d448, 0x3f64fcd6, 0x3f661fd3,
0x3f673d2e, 0x3f6854db, 0x3f6966ca, 0x3f6a72ef, 0x3f6b793d, 0x3f6c79a5,
0x3f6d741d, 0x3f6e6896, 0x3f6f5706, 0x3f703f5f, 0x3f712198, 0x3f71fda4,
0x3f72d379, 0x3f73a30c, 0x3f746c52, 0x3f752f43, 0x3f75ebd4, 0x3f76a1fc,
0x3f7751b2, 0x3f77faee, 0x3f789da6, 0x3f7939d4, 0x3f79cf6e, 0x3f7a5e6f,
0x3f7ae6cf, 0x3f7b6886, 0x3f7be38f, 0x3f7c57e4, 0x3f7cc57f, 0x3f7d2c5b,
0x3f7d8c72, 0x3f7de5bf, 0x3f7e3840, 0x3f7e83ee, 0x3f7ec8c7, 0x3f7f06c7,
0x3f7f3deb, 0x3f7f6e31, 0x3f7f9795, 0x3f7fba17, 0x3f7fd5b4, 0x3f7fea6b,
0x3f7ff83b, 0x3f7fff23, 0x3f7fff23, 0x3f7ff83b, 0x3f7fea6b, 0x3f7fd5b4,
0x3f7fba17, 0x3f7f9795, 0x3f7f6e31, 0x3f7f3deb, 0x3f7f06c7, 0x3f7ec8c7,
0x3f7e83ee, 0x3f7e3840, 0x3f7de5bf, 0x3f7d8c72, 0x3f7d2c5b, 0x3f7cc57f,
0x3f7c57e4, 0x3f7be38f, 0x3f7b6886, 0x3f7ae6cf, 0x3f7a5e6f, 0x3f79cf6e,
0x3f7939d4, 0x3f789da6, 0x3f77faee, 0x3f7751b2, 0x3f76a1fc, 0x3f75ebd4,
0x3f752f43, 0x3f746c52, 0x3f73a30c, 0x3f72d379, 0x3f71fda4, 0x3f712198,
0x3f703f5f, 0x3f6f5706, 0x3f6e6896, 0x3f6d741d, 0x3f6c79a5, 0x3f6b793d,
0x3f6a72ef, 0x3f6966ca, 0x3f6854db, 0x3f673d2e, 0x3f661fd3, 0x3f64fcd6,
0x3f63d448, 0x3f62a636, 0x3f6172af, 0x3f6039c2, 0x3f5efb80, 0x3f5db7f9,
0x3f5c6f3b, 0x3f5b2158, 0x3f59ce60, 0x3f587664, 0x3f571975, 0x3f55b7a5,
0x3f545106, 0x3f52e5a9, 0x3f5175a0, 0x3f5000fe, 0x3f4e87d6, 0x3f4d0a3b,
0x3f4b883f, 0x3f4a01f6, 0x3f487774, 0x3f46e8cc, 0x3f455613, 0x3f43bf5c,
0x3f4224bd, 0x3f40864a, 0x3f3ee418, 0x3f3d3e3c, 0x3f3b94cc, 0x3f39e7dd,
0x3f383784, 0x3f3683d8, 0x3f34ccef, 0x3f3312e0, 0x3f3155bf, 0x3f2f95a6,
0x3f2dd2a9, 0x3f2c0ce1, 0x3f2a4464, 0x3f28794a, 0x3f26abaa, 0x3f24db9d,
0x3f230939, 0x3f213498, 0x3f1f5dd0, 0x3f1d84fb, 0x3f1baa32, 0x3f19cd8b,
0x3f17ef21, 0x3f160f0c, 0x3f142d65, 0x3f124a45, 0x3f1065c6, 0x3f0e8001,
0x3f0c990f, 0x3f0ab10a, 0x3f08c80b, 0x3f06de2d, 0x3f04f389, 0x3f03083a,
0x3f011c59, 0x3efe6002, 0x3efa8698, 0x3ef6aca8, 0x3ef2d267, 0x3eeef80c,
0x3eeb1dca, 0x3ee743d7, 0x3ee36a69, 0x3edf91b5, 0x3edbb9f2, 0x3ed7e354,
0x3ed40e13, 0x3ed03a64, 0x3ecc687d, 0x3ec89895, 0x3ec4cae2, 0x3ec0ff9b,
0x3ebd36f6, 0x3eb9712a, 0x3eb5ae6f, 0x3eb1eefa, 0x3eae3303, 0x3eaa7ac0,
0x3ea6c66a, 0x3ea31636, 0x3e9f6a5d, 0x3e9bc316, 0x3e982097, 0x3e948319,
0x3e90ead3, 0x3e8d57fc, 0x3e89cacd, 0x3e86437c, 0x3e82c241, 0x3e7e8eaa,
0x3e77a5de, 0x3e70ca8f, 0x3e69fd2c, 0x3e633e26, 0x3e5c8ded, 0x3e55ecf2,
0x3e4f5ba5, 0x3e48da79, 0x3e4269de, 0x3e3c0a46, 0x3e35bc23, 0x3e2f7fe7,
0x3e295605, 0x3e233ef0, 0x3e1d3b1c, 0x3e174afe, 0x3e116f08, 0x3e0ba7b2,
0x3e05f571, 0x3e0058bb, 0x3df5a413, 0x3deac3a7, 0x3de01126, 0x3dd58d86,
0x3dcb39bf, 0x3dc116cc, 0x3db725ab, 0x3dad675d, 0x3da3dce9, 0x3d9a8756,
0x3d9167b5, 0x3d887f19, 0x3d7f9d38, 0x3d6eaebd, 0x3d5e3510, 0x3d4e3293,
0x3d3ea9ba, 0x3d2f9d0e, 0x3d210f33, 0x3d1302e6, 0x3d057b06, 0x3cf0f52e,
0x3cd8098d, 0x3cc039eb, 0x3ca98d81, 0x3c940c13, 0x3c7f7c1d, 0x3c59595d,
0x3c35c45b, 0x3c14d40b, 0x3bed453b, 0x3bb69d19, 0x3b85f871, 0x3b37623a,
0x3ae0ee32, 0x3a61d1c5, 0x398b03f6, 0x00000000
};
const int32_t window_hamm_hex[] = {
0x3da3d70a, 0x3da3f4f1, 0x3da44ea4, 0x3da4e41d, 0x3da5b554, 0x3da6c239,
0x3da80abd, 0x3da98ecb, 0x3dab4e4a, 0x3dad491d, 0x3daf7f25, 0x3db1f03d,
0x3db49c3e, 0x3db782fd, 0x3dbaa449, 0x3dbdfff1, 0x3dc195be, 0x3dc56575,
0x3dc96ed9, 0x3dcdb1a8, 0x3dd22d9d, 0x3dd6e26e, 0x3ddbcfd0, 0x3de0f572,
0x3de65301, 0x3debe825, 0x3df1b484, 0x3df7b7c0, 0x3dfdf176, 0x3e0230a1,
0x3e05835d, 0x3e08f0ba, 0x3e0c7880, 0x3e101a75, 0x3e13d65f, 0x3e17ac00,
0x3e1b9b1b, 0x3e1fa36f, 0x3e23c4bc, 0x3e27febd, 0x3e2c512e, 0x3e30bbc9,
0x3e353e46, 0x3e39d85c, 0x3e3e89c0, 0x3e435226, 0x3e483140, 0x3e4d26be,
0x3e523251, 0x3e5753a7, 0x3e5c8a6b, 0x3e61d64a, 0x3e6736ec, 0x3e6cabfc,
0x3e72351f, 0x3e77d1fd, 0x3e7d8239, 0x3e81a2bc, 0x3e848dae, 0x3e8781c3,
0x3e8a7eca, 0x3e8d8495, 0x3e9092f0, 0x3e93a9ab, 0x3e96c894, 0x3e99ef77,
0x3e9d1e22, 0x3ea05460, 0x3ea391ff, 0x3ea6d6c8, 0x3eaa2286, 0x3ead7505,
0x3eb0ce0f, 0x3eb42d6c, 0x3eb792e6, 0x3ebafe46, 0x3ebe6f54, 0x3ec1e5d9,
0x3ec5619c, 0x3ec8e264, 0x3ecc67f8, 0x3ecff220, 0x3ed380a2, 0x3ed71344,
0x3edaa9cb, 0x3ede43fe, 0x3ee1e1a3, 0x3ee5827d, 0x3ee92653, 0x3eeccce9,
0x3ef07604, 0x3ef42168, 0x3ef7ceda, 0x3efb7e1d, 0x3eff2ef7, 0x3f017096,
0x3f034a3f, 0x3f052459, 0x3f06fec5, 0x3f08d967, 0x3f0ab41f, 0x3f0c8ed0,
0x3f0e695b, 0x3f1043a2, 0x3f121d87, 0x3f13f6ec, 0x3f15cfb4, 0x3f17a7bf,
0x3f197ef0, 0x3f1b5529, 0x3f1d2a4d, 0x3f1efe3d, 0x3f20d0db, 0x3f22a20b,
0x3f2471ae, 0x3f263fa8, 0x3f280bda, 0x3f29d628, 0x3f2b9e74, 0x3f2d64a2,
0x3f2f2895, 0x3f30ea30, 0x3f32a956, 0x3f3465ec, 0x3f361fd4, 0x3f37d6f3,
0x3f398b2d, 0x3f3b3c66, 0x3f3cea83, 0x3f3e9569, 0x3f403cfb, 0x3f41e121,
0x3f4381be, 0x3f451eb8, 0x3f46b7f6, 0x3f484d5d, 0x3f49ded3, 0x3f4b6c3f,
0x3f4cf588, 0x3f4e7a94, 0x3f4ffb4c, 0x3f517796, 0x3f52ef5a, 0x3f546282,
0x3f55d0f4, 0x3f573a9a, 0x3f589f5d, 0x3f59ff26, 0x3f5b59df, 0x3f5caf72,
0x3f5dffc9, 0x3f5f4acf, 0x3f60906f, 0x3f61d093, 0x3f630b29, 0x3f64401b,
0x3f656f57, 0x3f6698c9, 0x3f67bc5d, 0x3f68da03, 0x3f69f1a6, 0x3f6b0337,
0x3f6c0ea3, 0x3f6d13d9, 0x3f6e12c9, 0x3f6f0b62, 0x3f6ffd95, 0x3f70e953,
0x3f71ce8c, 0x3f72ad32, 0x3f738537, 0x3f74568d, 0x3f752127, 0x3f75e4f8,
0x3f76a1f3, 0x3f77580d, 0x3f780739, 0x3f78af6e, 0x3f79509f, 0x3f79eac3,
0x3f7a7dd1, 0x3f7b09be, 0x3f7b8e83, 0x3f7c0c15, 0x3f7c826e, 0x3f7cf187,
0x3f7d5957, 0x3f7db9d8, 0x3f7e1305, 0x3f7e64d7, 0x3f7eaf4a, 0x3f7ef258,
0x3f7f2dfe, 0x3f7f6237, 0x3f7f8f00, 0x3f7fb457, 0x3f7fd239, 0x3f7fe8a4,
0x3f7ff797, 0x3f7fff11, 0x3f7fff11, 0x3f7ff797, 0x3f7fe8a4, 0x3f7fd239,
0x3f7fb457, 0x3f7f8f00, 0x3f7f6237, 0x3f7f2dfe, 0x3f7ef258, 0x3f7eaf4a,
0x3f7e64d7, 0x3f7e1305, 0x3f7db9d8, 0x3f7d5957, 0x3f7cf187, 0x3f7c826e,
0x3f7c0c15, 0x3f7b8e83, 0x3f7b09be, 0x3f7a7dd1, 0x3f79eac3, 0x3f79509f,
0x3f78af6e, 0x3f780739, 0x3f77580d, 0x3f76a1f3, 0x3f75e4f8, 0x3f752127,
0x3f74568d, 0x3f738537, 0x3f72ad32, 0x3f71ce8c, 0x3f70e953, 0x3f6ffd95,
0x3f6f0b62, 0x3f6e12c9, 0x3f6d13d9, 0x3f6c0ea3, 0x3f6b0337, 0x3f69f1a6,
0x3f68da03, 0x3f67bc5d, 0x3f6698c9, 0x3f656f57, 0x3f64401b, 0x3f630b29,
0x3f61d093, 0x3f60906f, 0x3f5f4acf, 0x3f5dffc9, 0x3f5caf72, 0x3f5b59df,
0x3f59ff26, 0x3f589f5d, 0x3f573a9a, 0x3f55d0f4, 0x3f546282, 0x3f52ef5a,
0x3f517796, 0x3f4ffb4c, 0x3f4e7a94, 0x3f4cf588, 0x3f4b6c3f, 0x3f49ded3,
0x3f484d5d, 0x3f46b7f6, 0x3f451eb8, 0x3f4381be, 0x3f41e121, 0x3f403cfb,
0x3f3e9569, 0x3f3cea83, 0x3f3b3c66, 0x3f398b2d, 0x3f37d6f3, 0x3f361fd4,
0x3f3465ec, 0x3f32a956, 0x3f30ea30, 0x3f2f2895, 0x3f2d64a2, 0x3f2b9e74,
0x3f29d628, 0x3f280bda, 0x3f263fa8, 0x3f2471ae, 0x3f22a20b, 0x3f20d0db,
0x3f1efe3d, 0x3f1d2a4d, 0x3f1b5529, 0x3f197ef0, 0x3f17a7bf, 0x3f15cfb4,
0x3f13f6ec, 0x3f121d87, 0x3f1043a2, 0x3f0e695b, 0x3f0c8ed0, 0x3f0ab41f,
0x3f08d967, 0x3f06fec5, 0x3f052459, 0x3f034a3f, 0x3f017096, 0x3eff2ef7,
0x3efb7e1d, 0x3ef7ceda, 0x3ef42168, 0x3ef07604, 0x3eeccce9, 0x3ee92653,
0x3ee5827d, 0x3ee1e1a3, 0x3ede43fe, 0x3edaa9cb, 0x3ed71344, 0x3ed380a2,
0x3ecff220, 0x3ecc67f8, 0x3ec8e264, 0x3ec5619c, 0x3ec1e5d9, 0x3ebe6f54,
0x3ebafe46, 0x3eb792e6, 0x3eb42d6c, 0x3eb0ce0f, 0x3ead7505, 0x3eaa2286,
0x3ea6d6c8, 0x3ea391ff, 0x3ea05460, 0x3e9d1e22, 0x3e99ef77, 0x3e96c894,
0x3e93a9ab, 0x3e9092f0, 0x3e8d8495, 0x3e8a7eca, 0x3e8781c3, 0x3e848dae,
0x3e81a2bc, 0x3e7d8239, 0x3e77d1fd, 0x3e72351f, 0x3e6cabfc, 0x3e6736ec,
0x3e61d64a, 0x3e5c8a6b, 0x3e5753a7, 0x3e523251, 0x3e4d26be, 0x3e483140,
0x3e435226, 0x3e3e89c0, 0x3e39d85c, 0x3e353e46, 0x3e30bbc9, 0x3e2c512e,
0x3e27febd, 0x3e23c4bc, 0x3e1fa36f, 0x3e1b9b1b, 0x3e17ac00, 0x3e13d65f,
0x3e101a75, 0x3e0c7880, 0x3e08f0ba, 0x3e05835d, 0x3e0230a1, 0x3dfdf176,
0x3df7b7c0, 0x3df1b484, 0x3debe825, 0x3de65301, 0x3de0f572, 0x3ddbcfd0,
0x3dd6e26e, 0x3dd22d9d, 0x3dcdb1a8, 0x3dc96ed9, 0x3dc56575, 0x3dc195be,
0x3dbdfff1, 0x3dbaa449, 0x3db782fd, 0x3db49c3e, 0x3db1f03d, 0x3daf7f25,
0x3dad491d, 0x3dab4e4a, 0x3da98ecb, 0x3da80abd, 0x3da6c239, 0x3da5b554,
0x3da4e41d, 0x3da44ea4, 0x3da3f4f1, 0x3da3d70a
};
const int global_cmvn_mean_hex[] = {
0x413d6566, 0x4147923f, 0x4156ab15, 0x41613d12, 0x416b155b, 0x41722783,
0x4176cd05, 0x4178532a, 0x417aa3c3, 0x417aed19, 0x417d4d2c, 0x417e6abb,
0x41805848, 0x418122ab, 0x41812b23, 0x418161a8, 0x41810ef9, 0x4180863a,
0x41815d8f, 0x417ff8b2, 0x417de2aa, 0x4180a5f2, 0x417e8bd1, 0x418041ac,
0x417f2d60, 0x4180487f, 0x417eb835, 0x418018d8, 0x417ef8c1, 0x417ea302,
0x417f30cf, 0x417ea0bb, 0x417ebac2, 0x417faab6, 0x417fca4d, 0x41805e45,
0x4180e308, 0x4180ef3e, 0x418109fc, 0x4180afa3, 0x418113e2, 0x4180c915,
0x41819f86, 0x418190bf, 0x418220bd, 0x4182f2e5, 0x4183e1c7, 0x41843eec,
0x4184b066, 0x418574db, 0x41852611, 0x4184fc81, 0x41851b2a, 0x4185a1c7,
0x41861152, 0x41868c28, 0x41871930, 0x41871f83, 0x41868893, 0x4185d919,
0x4185664b, 0x418480a6, 0x41840e3a, 0x41836ace, 0x4182b217, 0x4181cb79,
0x4180fb13, 0x418098b9, 0x41805ded, 0x417ff69a, 0x417f49bd, 0x417ecef8,
0x417e286c, 0x417d9135, 0x417cfff4, 0x417ca8f7, 0x417b2e8f, 0x41773788,
0x4170b095, 0x4167417f};
const int global_cmvn_std_hex[] = {
0x4040335e, 0x405235d3, 0x40589be4, 0x4054261f, 0x40544ba2, 0x40575418,
0x405b6528, 0x40617999, 0x40605fcf, 0x405c9c6d, 0x40590796, 0x405899fc,
0x405810b8, 0x40587c40, 0x40592b5e, 0x4057fb12, 0x4057028b, 0x405515d7,
0x4053d714, 0x405418c7, 0x405536bc, 0x4052f54e, 0x4052d382, 0x4051201d,
0x4050a8d2, 0x4050857f, 0x404ffe85, 0x4050a0da, 0x40517a8a, 0x40508862,
0x40504f68, 0x404f3159, 0x404f0930, 0x404e8a2e, 0x404e7383, 0x404eb185,
0x404edaa9, 0x404efed2, 0x404ea8f4, 0x404f6d0d, 0x404ee9d9, 0x404f4cca,
0x404fb13f, 0x405051c5, 0x40503f5e, 0x4050df6e, 0x4052974e, 0x4053d421,
0x40544d48, 0x40544ec8, 0x40550e57, 0x40558287, 0x4055d122, 0x4056b22a,
0x4058ea5c, 0x405acbc3, 0x405a89e7, 0x405a88ed, 0x405afadb, 0x405a1c60,
0x405a6f46, 0x405b0a24, 0x405b5f44, 0x405cc0a9, 0x405d984b, 0x405ef9b8,
0x4061178a, 0x406262bf, 0x40644904, 0x40660b20, 0x4067f7f1, 0x406a35e5,
0x406c1e97, 0x406e16a9, 0x406eadb1, 0x406d0cba, 0x406d9ca0, 0x406f5a14,
0x406e84a7, 0x406cd985};
const int global_cmvn_mean_online_hex[] = {
0x413d5d27, 0x414785ae, 0x4156986a, 0x41612a4e, 0x416b063e, 0x41721c9b,
0x4176c505, 0x41784b5b, 0x417a9575, 0x417adfb2, 0x417d4153, 0x417e611e,
0x41805288, 0x41811c27, 0x4181250c, 0x41815cd4, 0x41810b77, 0x4180817c,
0x41815881, 0x417feaf2, 0x417dd2bf, 0x41809f37, 0x417e7b47, 0x41803a6a,
0x417f1ff4, 0x41804382, 0x417ead10, 0x41801220, 0x417eeb28, 0x417e9801,
0x417f26b9, 0x417e95f9, 0x417eac06, 0x417f9aa5, 0x417fbb16, 0x41805651,
0x4180daaa, 0x4180e84c, 0x41810566, 0x4180ab2c, 0x418111b0, 0x4180c6cc,
0x41819e27, 0x418190cc, 0x4182205c, 0x4182f265, 0x4183e1a2, 0x41844012,
0x4184b0cd, 0x41857447, 0x418527f7, 0x4184fdc6, 0x41851ad2, 0x4185a148,
0x41860f8b, 0x41868888, 0x418712e4, 0x41871702, 0x41867ec3, 0x4185cc48,
0x418559b4, 0x41847855, 0x418408f4, 0x418368f4, 0x4182b718, 0x4181d76d,
0x41810e52, 0x4180b204, 0x418078a4, 0x41801179, 0x417f5579, 0x417e93b7,
0x417d6f2c, 0x417c1a0b, 0x417a6c7a, 0x41787d18, 0x4174eceb, 0x416e3ed3,
0x41644af8, 0x41566dd4
};
const int global_cmvn_std_online_hex[] = {
0x40408fdd, 0x405293b6, 0x4058f2d2, 0x40546ddb, 0x4054984c, 0x4057971b,
0x405ba086, 0x4061afa7, 0x4060a24c, 0x405cbb7e, 0x405923f7, 0x4058c91f,
0x40585cf3, 0x4058c22a, 0x40594960, 0x405824a6, 0x405703f3, 0x40556377,
0x4053e02d, 0x40540a7e, 0x405553c7, 0x4052ead5, 0x4052d23d, 0x40510308,
0x4050a2f3, 0x40505b81, 0x404fed20, 0x4050a372, 0x40515196, 0x40504810,
0x40501fdd, 0x404f2225, 0x404f0931, 0x404e8a2b, 0x404e773b, 0x404ea782,
0x404ee17d, 0x404ef49c, 0x404e884d, 0x404f696b, 0x404edd0e, 0x404f23cc,
0x404f74d4, 0x40501e89, 0x405009f3, 0x4050c422, 0x4052902b, 0x4053987c,
0x40542997, 0x40543695, 0x4054cbef, 0x40553947, 0x4055ab7c, 0x4056887c,
0x4058b710, 0x405a8d28, 0x405a6a27, 0x405a6b3b, 0x405ac8d3, 0x405a031d,
0x405a2158, 0x405abb1b, 0x405b1350, 0x405c98c0, 0x405d5cf9, 0x405ead5b,
0x40609748, 0x4061dfb9, 0x4063aa9f, 0x40655831, 0x40671a35, 0x40694bf5,
0x406b1f59, 0x406cb49b, 0x406cf19e, 0x406b592b, 0x406b757c, 0x406c866d,
0x406ac24f, 0x406678d9
};
const unsigned int paraformer_cmvn_mean_hex[] = {
0xc104fd75, 0xc1099d56, 0xc119dad7, 0xc126f9a7, 0xc133681f, 0xc13e221f,
0xc145cc83, 0xc14a3166, 0xc14e1bda, 0xc14d4a62, 0xc14e41a9, 0xc14f4e7b,
0xc153297e, 0xc1567ee5, 0xc157dbab, 0xc158dfa4, 0xc158e6f9, 0xc1584e70,
0xc15aecea, 0xc15886b8, 0xc156bcb4, 0xc15a7ba9, 0xc1581d34, 0xc15c0a48,
0xc15c463f, 0xc15dfc3b, 0xc15bb28b, 0xc15b4413, 0xc158f8c0, 0xc1588ede,
0xc158c880, 0xc158ff19, 0xc159815a, 0xc159ed72, 0xc15a458d, 0xc15a93d3,
0xc15a06ec, 0xc15953d8, 0xc1592e92, 0xc1579518, 0xc1587d76, 0xc157bc56,
0xc159c47c, 0xc15a5ac4, 0xc15b7286, 0xc15cab60, 0xc15e7f8d, 0xc1607ee5,
0xc162e9ad, 0xc165bdb0, 0xc167bf3e, 0xc169a0a5, 0xc16b4b68, 0xc16d5682,
0xc16ebd51, 0xc170197a, 0xc170d1cc, 0xc1707fc1, 0xc16fd830, 0xc16ec4b1,
0xc16de888, 0xc16d3b06, 0xc16cc155, 0xc16c4e31, 0xc16b6abe, 0xc169cde8,
0xc1684578, 0xc166c2a4, 0xc165d326, 0xc164df46, 0xc163b4ad, 0xc1632d19,
0xc162a94a, 0xc16280fc, 0xc161ae3e, 0xc15fec42, 0xc15cbadc, 0xc15664c3,
0xc14c6d5d, 0xc13b64ae, 0xc104fd75, 0xc1099d56, 0xc119dad7, 0xc126f9a7,
0xc133681f, 0xc13e221f, 0xc145cc83, 0xc14a3166, 0xc14e1bda, 0xc14d4a62,
0xc14e41a9, 0xc14f4e7b, 0xc153297e, 0xc1567ee5, 0xc157dbab, 0xc158dfa4,
0xc158e6f9, 0xc1584e70, 0xc15aecea, 0xc15886b8, 0xc156bcb4, 0xc15a7ba9,
0xc1581d34, 0xc15c0a48, 0xc15c463f, 0xc15dfc3b, 0xc15bb28b, 0xc15b4413,
0xc158f8c0, 0xc1588ede, 0xc158c880, 0xc158ff19, 0xc159815a, 0xc159ed72,
0xc15a458d, 0xc15a93d3, 0xc15a06ec, 0xc15953d8, 0xc1592e92, 0xc1579518,
0xc1587d76, 0xc157bc56, 0xc159c47c, 0xc15a5ac4, 0xc15b7286, 0xc15cab60,
0xc15e7f8d, 0xc1607ee5, 0xc162e9ad, 0xc165bdb0, 0xc167bf3e, 0xc169a0a5,
0xc16b4b68, 0xc16d5682, 0xc16ebd51, 0xc170197a, 0xc170d1cc, 0xc1707fc1,
0xc16fd830, 0xc16ec4b1, 0xc16de888, 0xc16d3b06, 0xc16cc155, 0xc16c4e31,
0xc16b6abe, 0xc169cde8, 0xc1684578, 0xc166c2a4, 0xc165d326, 0xc164df46,
0xc163b4ad, 0xc1632d19, 0xc162a94a, 0xc16280fc, 0xc161ae3e, 0xc15fec42,
0xc15cbadc, 0xc15664c3, 0xc14c6d5d, 0xc13b64ae, 0xc104fd75, 0xc1099d56,
0xc119dad7, 0xc126f9a7, 0xc133681f, 0xc13e221f, 0xc145cc83, 0xc14a3166,
0xc14e1bda, 0xc14d4a62, 0xc14e41a9, 0xc14f4e7b, 0xc153297e, 0xc1567ee5,
0xc157dbab, 0xc158dfa4, 0xc158e6f9, 0xc1584e70, 0xc15aecea, 0xc15886b8,
0xc156bcb4, 0xc15a7ba9, 0xc1581d34, 0xc15c0a48, 0xc15c463f, 0xc15dfc3b,
0xc15bb28b, 0xc15b4413, 0xc158f8c0, 0xc1588ede, 0xc158c880, 0xc158ff19,
0xc159815a, 0xc159ed72, 0xc15a458d, 0xc15a93d3, 0xc15a06ec, 0xc15953d8,
0xc1592e92, 0xc1579518, 0xc1587d76, 0xc157bc56, 0xc159c47c, 0xc15a5ac4,
0xc15b7286, 0xc15cab60, 0xc15e7f8d, 0xc1607ee5, 0xc162e9ad, 0xc165bdb0,
0xc167bf3e, 0xc169a0a5, 0xc16b4b68, 0xc16d5682, 0xc16ebd51, 0xc170197a,
0xc170d1cc, 0xc1707fc1, 0xc16fd830, 0xc16ec4b1, 0xc16de888, 0xc16d3b06,
0xc16cc155, 0xc16c4e31, 0xc16b6abe, 0xc169cde8, 0xc1684578, 0xc166c2a4,
0xc165d326, 0xc164df46, 0xc163b4ad, 0xc1632d19, 0xc162a94a, 0xc16280fc,
0xc161ae3e, 0xc15fec42, 0xc15cbadc, 0xc15664c3, 0xc14c6d5d, 0xc13b64ae,
0xc104fd75, 0xc1099d56, 0xc119dad7, 0xc126f9a7, 0xc133681f, 0xc13e221f,
0xc145cc83, 0xc14a3166, 0xc14e1bda, 0xc14d4a62, 0xc14e41a9, 0xc14f4e7b,
0xc153297e, 0xc1567ee5, 0xc157dbab, 0xc158dfa4, 0xc158e6f9, 0xc1584e70,
0xc15aecea, 0xc15886b8, 0xc156bcb4, 0xc15a7ba9, 0xc1581d34, 0xc15c0a48,
0xc15c463f, 0xc15dfc3b, 0xc15bb28b, 0xc15b4413, 0xc158f8c0, 0xc1588ede,
0xc158c880, 0xc158ff19, 0xc159815a, 0xc159ed72, 0xc15a458d, 0xc15a93d3,
0xc15a06ec, 0xc15953d8, 0xc1592e92, 0xc1579518, 0xc1587d76, 0xc157bc56,
0xc159c47c, 0xc15a5ac4, 0xc15b7286, 0xc15cab60, 0xc15e7f8d, 0xc1607ee5,
0xc162e9ad, 0xc165bdb0, 0xc167bf3e, 0xc169a0a5, 0xc16b4b68, 0xc16d5682,
0xc16ebd51, 0xc170197a, 0xc170d1cc, 0xc1707fc1, 0xc16fd830, 0xc16ec4b1,
0xc16de888, 0xc16d3b06, 0xc16cc155, 0xc16c4e31, 0xc16b6abe, 0xc169cde8,
0xc1684578, 0xc166c2a4, 0xc165d326, 0xc164df46, 0xc163b4ad, 0xc1632d19,
0xc162a94a, 0xc16280fc, 0xc161ae3e, 0xc15fec42, 0xc15cbadc, 0xc15664c3,
0xc14c6d5d, 0xc13b64ae, 0xc104fd75, 0xc1099d56, 0xc119dad7, 0xc126f9a7,
0xc133681f, 0xc13e221f, 0xc145cc83, 0xc14a3166, 0xc14e1bda, 0xc14d4a62,
0xc14e41a9, 0xc14f4e7b, 0xc153297e, 0xc1567ee5, 0xc157dbab, 0xc158dfa4,
0xc158e6f9, 0xc1584e70, 0xc15aecea, 0xc15886b8, 0xc156bcb4, 0xc15a7ba9,
0xc1581d34, 0xc15c0a48, 0xc15c463f, 0xc15dfc3b, 0xc15bb28b, 0xc15b4413,
0xc158f8c0, 0xc1588ede, 0xc158c880, 0xc158ff19, 0xc159815a, 0xc159ed72,
0xc15a458d, 0xc15a93d3, 0xc15a06ec, 0xc15953d8, 0xc1592e92, 0xc1579518,
0xc1587d76, 0xc157bc56, 0xc159c47c, 0xc15a5ac4, 0xc15b7286, 0xc15cab60,
0xc15e7f8d, 0xc1607ee5, 0xc162e9ad, 0xc165bdb0, 0xc167bf3e, 0xc169a0a5,
0xc16b4b68, 0xc16d5682, 0xc16ebd51, 0xc170197a, 0xc170d1cc, 0xc1707fc1,
0xc16fd830, 0xc16ec4b1, 0xc16de888, 0xc16d3b06, 0xc16cc155, 0xc16c4e31,
0xc16b6abe, 0xc169cde8, 0xc1684578, 0xc166c2a4, 0xc165d326, 0xc164df46,
0xc163b4ad, 0xc1632d19, 0xc162a94a, 0xc16280fc, 0xc161ae3e, 0xc15fec42,
0xc15cbadc, 0xc15664c3, 0xc14c6d5d, 0xc13b64ae, 0xc104fd75, 0xc1099d56,
0xc119dad7, 0xc126f9a7, 0xc133681f, 0xc13e221f, 0xc145cc83, 0xc14a3166,
0xc14e1bda, 0xc14d4a62, 0xc14e41a9, 0xc14f4e7b, 0xc153297e, 0xc1567ee5,
0xc157dbab, 0xc158dfa4, 0xc158e6f9, 0xc1584e70, 0xc15aecea, 0xc15886b8,
0xc156bcb4, 0xc15a7ba9, 0xc1581d34, 0xc15c0a48, 0xc15c463f, 0xc15dfc3b,
0xc15bb28b, 0xc15b4413, 0xc158f8c0, 0xc1588ede, 0xc158c880, 0xc158ff19,
0xc159815a, 0xc159ed72, 0xc15a458d, 0xc15a93d3, 0xc15a06ec, 0xc15953d8,
0xc1592e92, 0xc1579518, 0xc1587d76, 0xc157bc56, 0xc159c47c, 0xc15a5ac4,
0xc15b7286, 0xc15cab60, 0xc15e7f8d, 0xc1607ee5, 0xc162e9ad, 0xc165bdb0,
0xc167bf3e, 0xc169a0a5, 0xc16b4b68, 0xc16d5682, 0xc16ebd51, 0xc170197a,
0xc170d1cc, 0xc1707fc1, 0xc16fd830, 0xc16ec4b1, 0xc16de888, 0xc16d3b06,
0xc16cc155, 0xc16c4e31, 0xc16b6abe, 0xc169cde8, 0xc1684578, 0xc166c2a4,
0xc165d326, 0xc164df46, 0xc163b4ad, 0xc1632d19, 0xc162a94a, 0xc16280fc,
0xc161ae3e, 0xc15fec42, 0xc15cbadc, 0xc15664c3, 0xc14c6d5d, 0xc13b64ae,
0xc104fd75, 0xc1099d56, 0xc119dad7, 0xc126f9a7, 0xc133681f, 0xc13e221f,
0xc145cc83, 0xc14a3166, 0xc14e1bda, 0xc14d4a62, 0xc14e41a9, 0xc14f4e7b,
0xc153297e, 0xc1567ee5, 0xc157dbab, 0xc158dfa4, 0xc158e6f9, 0xc1584e70,
0xc15aecea, 0xc15886b8, 0xc156bcb4, 0xc15a7ba9, 0xc1581d34, 0xc15c0a48,
0xc15c463f, 0xc15dfc3b, 0xc15bb28b, 0xc15b4413, 0xc158f8c0, 0xc1588ede,
0xc158c880, 0xc158ff19, 0xc159815a, 0xc159ed72, 0xc15a458d, 0xc15a93d3,
0xc15a06ec, 0xc15953d8, 0xc1592e92, 0xc1579518, 0xc1587d76, 0xc157bc56,
0xc159c47c, 0xc15a5ac4, 0xc15b7286, 0xc15cab60, 0xc15e7f8d, 0xc1607ee5,
0xc162e9ad, 0xc165bdb0, 0xc167bf3e, 0xc169a0a5, 0xc16b4b68, 0xc16d5682,
0xc16ebd51, 0xc170197a, 0xc170d1cc, 0xc1707fc1, 0xc16fd830, 0xc16ec4b1,
0xc16de888, 0xc16d3b06, 0xc16cc155, 0xc16c4e31, 0xc16b6abe, 0xc169cde8,
0xc1684578, 0xc166c2a4, 0xc165d326, 0xc164df46, 0xc163b4ad, 0xc1632d19,
0xc162a94a, 0xc16280fc, 0xc161ae3e, 0xc15fec42, 0xc15cbadc, 0xc15664c3,
0xc14c6d5d, 0xc13b64ae};
const unsigned int paraformer_cmvn_var_hex[] = {
0x40619618, 0x405fb77c, 0x405d3028, 0x405bef11, 0x405a189d, 0x4057aad5,
0x4054f9cc, 0x40518e8c, 0x404fffdd, 0x40510d0d, 0x4052400d, 0x4052bab0,
0x40526416, 0x40515cb8, 0x40506aee, 0x404fef8d, 0x404ff527, 0x40505b95,
0x4050d61c, 0x4051d0a5, 0x4052abd2, 0x4052f14b, 0x4053d196, 0x4054800d,
0x405545f2, 0x4055d71f, 0x40567588, 0x4056de4d, 0x40579b72, 0x40584d35,
0x4058cd2f, 0x40594731, 0x4059a53f, 0x405a00ed, 0x405a34c1, 0x405a406e,
0x405a1748, 0x405a0300, 0x405a1547, 0x405a66a7, 0x405a9be4, 0x405b04b2,
0x405b5754, 0x405b9189, 0x405b9016, 0x405b7a07, 0x405b63f9, 0x405b3f45,
0x405b0cb4, 0x405ac80b, 0x405ac1f7, 0x405abbd9, 0x405ac86a, 0x405ad72b,
0x405af2f0, 0x405ab465, 0x405a6364, 0x405a1350, 0x4059baa3, 0x4059911d,
0x40597921, 0x40595564, 0x40593b8d, 0x4059310f, 0x40594e46, 0x40599bae,
0x4059e703, 0x4059feec, 0x405a053a, 0x4059feaa, 0x4059d7a0, 0x40599386,
0x40592d0e, 0x4058ce4c, 0x40587335, 0x4058396a, 0x40584ee1, 0x4058925a,
0x40592f6d, 0x405a9f0a, 0x40619618, 0x405fb77c, 0x405d3028, 0x405bef11,
0x405a189d, 0x4057aad5, 0x4054f9cc, 0x40518e8c, 0x404fffdd, 0x40510d0d,
0x4052400d, 0x4052bab0, 0x40526416, 0x40515cb8, 0x40506aee, 0x404fef8d,
0x404ff527, 0x40505b95, 0x4050d61c, 0x4051d0a5, 0x4052abd2, 0x4052f14b,
0x4053d196, 0x4054800d, 0x405545f2, 0x4055d71f, 0x40567588, 0x4056de4d,
0x40579b72, 0x40584d35, 0x4058cd2f, 0x40594731, 0x4059a53f, 0x405a00ed,
0x405a34c1, 0x405a406e, 0x405a1748, 0x405a0300, 0x405a1547, 0x405a66a7,
0x405a9be4, 0x405b04b2, 0x405b5754, 0x405b9189, 0x405b9016, 0x405b7a07,
0x405b63f9, 0x405b3f45, 0x405b0cb4, 0x405ac80b, 0x405ac1f7, 0x405abbd9,
0x405ac86a, 0x405ad72b, 0x405af2f0, 0x405ab465, 0x405a6364, 0x405a1350,
0x4059baa3, 0x4059911d, 0x40597921, 0x40595564, 0x40593b8d, 0x4059310f,
0x40594e46, 0x40599bae, 0x4059e703, 0x4059feec, 0x405a053a, 0x4059feaa,
0x4059d7a0, 0x40599386, 0x40592d0e, 0x4058ce4c, 0x40587335, 0x4058396a,
0x40584ee1, 0x4058925a, 0x40592f6d, 0x405a9f0a, 0x40619618, 0x405fb77c,
0x405d3028, 0x405bef11, 0x405a189d, 0x4057aad5, 0x4054f9cc, 0x40518e8c,
0x404fffdd, 0x40510d0d, 0x4052400d, 0x4052bab0, 0x40526416, 0x40515cb8,
0x40506aee, 0x404fef8d, 0x404ff527, 0x40505b95, 0x4050d61c, 0x4051d0a5,
0x4052abd2, 0x4052f14b, 0x4053d196, 0x4054800d, 0x405545f2, 0x4055d71f,
0x40567588, 0x4056de4d, 0x40579b72, 0x40584d35, 0x4058cd2f, 0x40594731,
0x4059a53f, 0x405a00ed, 0x405a34c1, 0x405a406e, 0x405a1748, 0x405a0300,
0x405a1547, 0x405a66a7, 0x405a9be4, 0x405b04b2, 0x405b5754, 0x405b9189,
0x405b9016, 0x405b7a07, 0x405b63f9, 0x405b3f45, 0x405b0cb4, 0x405ac80b,
0x405ac1f7, 0x405abbd9, 0x405ac86a, 0x405ad72b, 0x405af2f0, 0x405ab465,
0x405a6364, 0x405a1350, 0x4059baa3, 0x4059911d, 0x40597921, 0x40595564,
0x40593b8d, 0x4059310f, 0x40594e46, 0x40599bae, 0x4059e703, 0x4059feec,
0x405a053a, 0x4059feaa, 0x4059d7a0, 0x40599386, 0x40592d0e, 0x4058ce4c,
0x40587335, 0x4058396a, 0x40584ee1, 0x4058925a, 0x40592f6d, 0x405a9f0a,
0x40619618, 0x405fb77c, 0x405d3028, 0x405bef11, 0x405a189d, 0x4057aad5,
0x4054f9cc, 0x40518e8c, 0x404fffdd, 0x40510d0d, 0x4052400d, 0x4052bab0,
0x40526416, 0x40515cb8, 0x40506aee, 0x404fef8d, 0x404ff527, 0x40505b95,
0x4050d61c, 0x4051d0a5, 0x4052abd2, 0x4052f14b, 0x4053d196, 0x4054800d,
0x405545f2, 0x4055d71f, 0x40567588, 0x4056de4d, 0x40579b72, 0x40584d35,
0x4058cd2f, 0x40594731, 0x4059a53f, 0x405a00ed, 0x405a34c1, 0x405a406e,
0x405a1748, 0x405a0300, 0x405a1547, 0x405a66a7, 0x405a9be4, 0x405b04b2,
0x405b5754, 0x405b9189, 0x405b9016, 0x405b7a07, 0x405b63f9, 0x405b3f45,
0x405b0cb4, 0x405ac80b, 0x405ac1f7, 0x405abbd9, 0x405ac86a, 0x405ad72b,
0x405af2f0, 0x405ab465, 0x405a6364, 0x405a1350, 0x4059baa3, 0x4059911d,
0x40597921, 0x40595564, 0x40593b8d, 0x4059310f, 0x40594e46, 0x40599bae,
0x4059e703, 0x4059feec, 0x405a053a, 0x4059feaa, 0x4059d7a0, 0x40599386,
0x40592d0e, 0x4058ce4c, 0x40587335, 0x4058396a, 0x40584ee1, 0x4058925a,
0x40592f6d, 0x405a9f0a, 0x40619618, 0x405fb77c, 0x405d3028, 0x405bef11,
0x405a189d, 0x4057aad5, 0x4054f9cc, 0x40518e8c, 0x404fffdd, 0x40510d0d,
0x4052400d, 0x4052bab0, 0x40526416, 0x40515cb8, 0x40506aee, 0x404fef8d,
0x404ff527, 0x40505b95, 0x4050d61c, 0x4051d0a5, 0x4052abd2, 0x4052f14b,
0x4053d196, 0x4054800d, 0x405545f2, 0x4055d71f, 0x40567588, 0x4056de4d,
0x40579b72, 0x40584d35, 0x4058cd2f, 0x40594731, 0x4059a53f, 0x405a00ed,
0x405a34c1, 0x405a406e, 0x405a1748, 0x405a0300, 0x405a1547, 0x405a66a7,
0x405a9be4, 0x405b04b2, 0x405b5754, 0x405b9189, 0x405b9016, 0x405b7a07,
0x405b63f9, 0x405b3f45, 0x405b0cb4, 0x405ac80b, 0x405ac1f7, 0x405abbd9,
0x405ac86a, 0x405ad72b, 0x405af2f0, 0x405ab465, 0x405a6364, 0x405a1350,
0x4059baa3, 0x4059911d, 0x40597921, 0x40595564, 0x40593b8d, 0x4059310f,
0x40594e46, 0x40599bae, 0x4059e703, 0x4059feec, 0x405a053a, 0x4059feaa,
0x4059d7a0, 0x40599386, 0x40592d0e, 0x4058ce4c, 0x40587335, 0x4058396a,
0x40584ee1, 0x4058925a, 0x40592f6d, 0x405a9f0a, 0x40619618, 0x405fb77c,
0x405d3028, 0x405bef11, 0x405a189d, 0x4057aad5, 0x4054f9cc, 0x40518e8c,
0x404fffdd, 0x40510d0d, 0x4052400d, 0x4052bab0, 0x40526416, 0x40515cb8,
0x40506aee, 0x404fef8d, 0x404ff527, 0x40505b95, 0x4050d61c, 0x4051d0a5,
0x4052abd2, 0x4052f14b, 0x4053d196, 0x4054800d, 0x405545f2, 0x4055d71f,
0x40567588, 0x4056de4d, 0x40579b72, 0x40584d35, 0x4058cd2f, 0x40594731,
0x4059a53f, 0x405a00ed, 0x405a34c1, 0x405a406e, 0x405a1748, 0x405a0300,
0x405a1547, 0x405a66a7, 0x405a9be4, 0x405b04b2, 0x405b5754, 0x405b9189,
0x405b9016, 0x405b7a07, 0x405b63f9, 0x405b3f45, 0x405b0cb4, 0x405ac80b,
0x405ac1f7, 0x405abbd9, 0x405ac86a, 0x405ad72b, 0x405af2f0, 0x405ab465,
0x405a6364, 0x405a1350, 0x4059baa3, 0x4059911d, 0x40597921, 0x40595564,
0x40593b8d, 0x4059310f, 0x40594e46, 0x40599bae, 0x4059e703, 0x4059feec,
0x405a053a, 0x4059feaa, 0x4059d7a0, 0x40599386, 0x40592d0e, 0x4058ce4c,
0x40587335, 0x4058396a, 0x40584ee1, 0x4058925a, 0x40592f6d, 0x405a9f0a,
0x40619618, 0x405fb77c, 0x405d3028, 0x405bef11, 0x405a189d, 0x4057aad5,
0x4054f9cc, 0x40518e8c, 0x404fffdd, 0x40510d0d, 0x4052400d, 0x4052bab0,
0x40526416, 0x40515cb8, 0x40506aee, 0x404fef8d, 0x404ff527, 0x40505b95,
0x4050d61c, 0x4051d0a5, 0x4052abd2, 0x4052f14b, 0x4053d196, 0x4054800d,
0x405545f2, 0x4055d71f, 0x40567588, 0x4056de4d, 0x40579b72, 0x40584d35,
0x4058cd2f, 0x40594731, 0x4059a53f, 0x405a00ed, 0x405a34c1, 0x405a406e,
0x405a1748, 0x405a0300, 0x405a1547, 0x405a66a7, 0x405a9be4, 0x405b04b2,
0x405b5754, 0x405b9189, 0x405b9016, 0x405b7a07, 0x405b63f9, 0x405b3f45,
0x405b0cb4, 0x405ac80b, 0x405ac1f7, 0x405abbd9, 0x405ac86a, 0x405ad72b,
0x405af2f0, 0x405ab465, 0x405a6364, 0x405a1350, 0x4059baa3, 0x4059911d,
0x40597921, 0x40595564, 0x40593b8d, 0x4059310f, 0x40594e46, 0x40599bae,
0x4059e703, 0x4059feec, 0x405a053a, 0x4059feaa, 0x4059d7a0, 0x40599386,
0x40592d0e, 0x4058ce4c, 0x40587335, 0x4058396a, 0x40584ee1, 0x4058925a,
0x40592f6d, 0x405a9f0a
};
const int pos_enc_coe_hex[] = {
0x3f800000, 0x3f84b063, 0x3f898cc0, 0x3f8e96b2, 0x3f93cfe5, 0x3f993a15,
0x3f9ed70c, 0x3fa4a8a8, 0x3faab0d5, 0x3fb0f193, 0x3fb76cf5, 0x3fbe2520,
0x3fc51c50, 0x3fcc54d2, 0x3fd3d10c, 0x3fdb9378, 0x3fe39ea9, 0x3febf549,
0x3ff49a1b, 0x3ffd8ffe, 0x40036cf4, 0x40083d78, 0x400d3b22, 0x40126799,
0x4017c496, 0x401d53df, 0x4023174b, 0x402910c4, 0x402f4244, 0x4035adda,
0x403c55a4, 0x40433bd9, 0x404a62c2, 0x4051ccbd, 0x40597c3f, 0x406173d4,
0x4069b621, 0x407245e2, 0x407b25ed, 0x40822c9a, 0x4086f161, 0x408be2e0,
0x409102bc, 0x409652a6, 0x409bd461, 0x40a189c1, 0x40a774aa, 0x40ad9711,
0x40b3f300, 0x40ba8a92, 0x40c15ff6, 0x40c8756f, 0x40cfcd58, 0x40d76a1e,
0x40df4e48, 0x40e77c73, 0x40eff755, 0x40f8c1be, 0x4100ef4c, 0x4105a873,
0x410a8de6, 0x410fa144, 0x4114e43b, 0x411a588a, 0x41200000, 0x4125dc7c,
0x412beff0, 0x41323c5f, 0x4138c3df, 0x413f889a, 0x41468cd0, 0x414dd2d2,
0x41555d0a, 0x415d2df7, 0x41654832, 0x416dae69, 0x41766364, 0x417f6a07,
0x418462a7, 0x41893c2b, 0x418e432a, 0x4193794e, 0x4198e051, 0x419e79ff,
0x41a44831, 0x41aa4cd6, 0x41b089ea, 0x41b70180, 0x41bdb5bc, 0x41c4a8d7,
0x41cbdd1e, 0x41d354f5, 0x41db12d6, 0x41e31950, 0x41eb6b0d, 0x41f40ad0,
0x41fcfb72, 0x42031ff6, 0x4207eda7, 0x420ce865, 0x421211d5, 0x42176bad,
0x421cf7b4, 0x4222b7c0, 0x4228adb9, 0x422edb98, 0x4235436b, 0x423be74f,
0x4242c979, 0x4249ec31, 0x425151d4, 0x4258fcd6, 0x4260efc0, 0x42692d37,
0x4271b7f3, 0x427a92cb, 0x4281e057, 0x4286a253, 0x428b90ed, 0x4290adc8,
0x4295fa95, 0x429b7917, 0x42a12b1f, 0x42a71290, 0x42ad3160, 0x42b38995,
0x42ba1d4a, 0x42c0eead, 0x42c80000, 0x42cf539b, 0x42d6ebec, 0x42decb76,
0x42e6f4d6, 0x42ef6ac1, 0x42f83003, 0x4300a3c3, 0x43055a26, 0x430a3cbb,
0x430f4d1f, 0x43148d01, 0x4319fe1e, 0x431fa244, 0x43257b51, 0x432b8b36,
0x4331d3f4, 0x433857a1, 0x433f1865, 0x4346187e, 0x434d5a3e, 0x4354e00b,
0x435cac64, 0x4364c1e0, 0x436d232b, 0x4375d30c, 0x437ed466, 0x43841519,
0x4388ebc5, 0x438defd2, 0x439322e8, 0x439886c2, 0x439e1d27, 0x43a3e7f3,
0x43a9e911, 0x43b0227e, 0x43b6964a, 0x43bd4698, 0x43c435a1, 0x43cb65b0,
0x43d2d927, 0x43da927e, 0x43e29445, 0x43eae123, 0x43f37bd8, 0x43fc673e,
0x4402d325, 0x44079e06, 0x440c95d8, 0x4411bc42, 0x441712f8, 0x441c9bbf,
0x4422586d, 0x44284ae8, 0x442e7528, 0x4434d93a, 0x443b793b, 0x4442575d,
0x444975e6, 0x4450d734, 0x44587db7, 0x44606bfa, 0x4468a49c, 0x44712a58,
0x447a0000, 0x44819441, 0x44865373, 0x448b3f2a, 0x44905906, 0x4495a2b9,
0x449b1e02, 0x44a0ccb4, 0x44a6b0b0, 0x44accbe9, 0x44b32067, 0x44b9b042,
0x44c07da6, 0x44c78ad5, 0x44ceda26, 0x44d66e03, 0x44de48f1, 0x44e66d89,
0x44eede7f, 0x44f79e9e, 0x45005867, 0x45050c07, 0x4509ebbf, 0x450ef92c,
0x451435fb, 0x4519a3e8, 0x451f44bf, 0x45251a60, 0x452b26b7, 0x45316bc7,
0x4537eba3, 0x453ea872, 0x4545a471, 0x454ce1f0, 0x45546355, 0x455c2b1d,
0x45643bdc, 0x456c983e, 0x45754309, 0x457e3f1c, 0x4583c7b8, 0x45889b8f,
0x458d9cab, 0x4592ccb6, 0x45982d67, 0x459dc087, 0x45a387ee, 0x45a98587,
0x45afbb4e, 0x45b62b53, 0x45bcd7b6, 0x45c3c2af, 0x45caee88, 0x45d25da1,
0x45da1272, 0x45e20f88, 0x45ea5789, 0x45f2ed34, 0x45fbd360, 0x46028680,
0x46074e93, 0x460c437c, 0x461166e2, 0x4616ba77};
const int pos_enc_div_term_hex[] = {
0x3f800000, 0x3f76f410, 0x3f6e39f8, 0x3f65ced3, 0x3f5dafd7, 0x3f55da52,
0x3f4e4bac, 0x3f470165, 0x3f3ff911, 0x3f39305c, 0x3f32a506, 0x3f2c54e5,
0x3f263de0, 0x3f205df3, 0x3f1ab32b, 0x3f153ba8, 0x3f0ff59a, 0x3f0adf41,
0x3f05f6ee, 0x3f013b01, 0x3ef953cf, 0x3ef0843c, 0x3ee80460, 0x3edfd167,
0x3ed7e89b, 0x3ed0475c, 0x3ec8eb24, 0x3ec1d181, 0x3ebaf81a, 0x3eb45caa,
0x3eadfcff, 0x3ea7d6fd, 0x3ea1e89b, 0x3e9c2fe1, 0x3e96aaea, 0x3e9157e1,
0x3e8c3504, 0x3e87409d, 0x3e827909, 0x3e7bb965, 0x3e72d424, 0x3e6a3f5c,
0x3e61f836, 0x3e59fbf3, 0x3e5247ed, 0x3e4ad998, 0x3e43ae7c, 0x3e3cc43a,
0x3e361887, 0x3e2fa92d, 0x3e29740a, 0x3e23770f, 0x3e1db040, 0x3e181db4,
0x3e12bd91, 0x3e0d8e0f, 0x3e088d77, 0x3e03ba20, 0x3dfe24e1, 0x3df529bb,
0x3dec7fd5, 0x3de42450, 0x3ddc1466, 0x3dd44d6c, 0x3dcccccd, 0x3dc5900d,
0x3dbe94c7, 0x3db7d8a9, 0x3db15978, 0x3dab150e, 0x3da50957, 0x3d9f3451,
0x3d99940e, 0x3d9426b0, 0x3d8eea6c, 0x3d89dd84, 0x3d84fe4d, 0x3d804b29,
0x3d778512, 0x3d6ec5da, 0x3d6655c3, 0x3d5e3202, 0x3d5657e4, 0x3d4ec4ce,
0x3d47763f, 0x3d4069ca, 0x3d399d19, 0x3d330dec, 0x3d2cba15, 0x3d269f7d,
0x3d20bc1d, 0x3d1b0e01, 0x3d159348, 0x3d104a21, 0x3d0b30cc, 0x3d064597,
0x3d0186e2, 0x3cf9e635, 0x3cf11176, 0x3ce88c9c, 0x3ce054d2, 0x3cd86761,
0x3cd0c1a8, 0x3cc9611d, 0x3cc24350, 0x3cbb65e3, 0x3cb4c691, 0x3cae6328,
0x3ca8398b, 0x3ca247ad, 0x3c9c8b97, 0x3c970362, 0x3c91ad39, 0x3c8c8757,
0x3c879008, 0x3c82c5a5, 0x3c7c4d33, 0x3c7362b9, 0x3c6ac8e7, 0x3c627ce5,
0x3c5a7bf1, 0x3c52c366, 0x3c4b50b4, 0x3c442163, 0x3c3d3311, 0x3c368373,
0x3c301052, 0x3c29d789, 0x3c23d70a, 0x3c1e0cd7, 0x3c187705, 0x3c1313ba,
0x3c0de12d, 0x3c08dda5, 0x3c040779, 0x3bfeba1b, 0x3bf5b9b0, 0x3bed0ab3,
0x3be4aa46, 0x3bdc95a0, 0x3bd4ca14, 0x3bcd450e, 0x3bc6040e, 0x3bbf04ae,
0x3bb8449c, 0x3bb1c19b, 0x3bab7983, 0x3ba56a3f, 0x3b9f91cc, 0x3b99ee3b,
0x3b947dae, 0x3b8f3e56, 0x3b8a2e77, 0x3b854c64, 0x3b80967d, 0x3b781668,
0x3b6f520d, 0x3b66dd02, 0x3b5eb47a, 0x3b56d5bf, 0x3b4f3e37, 0x3b47eb5e,
0x3b40dac5, 0x3b3a0a16, 0x3b33770f, 0x3b2d1f81, 0x3b270153, 0x3b211a7e,
0x3b1b690d, 0x3b15eb1c, 0x3b109edb, 0x3b0b8287, 0x3b06946f, 0x3b01d2f1,
0x3afa78f1, 0x3af19f03, 0x3ae91528, 0x3ae0d88b, 0x3ad8e673, 0x3ad13c3c,
0x3ac9d75c, 0x3ac2b561, 0x3abbd3ec, 0x3ab530b7, 0x3aaec98e, 0x3aa89c52,
0x3aa2a6f6, 0x3a9ce782, 0x3a975c0e, 0x3a9202c3, 0x3a8cd9db, 0x3a87dfa1,
0x3a83126f, 0x3a7ce158, 0x3a73f1a2, 0x3a6b52c4, 0x3a6301e2, 0x3a5afc3b,
0x3a533f27, 0x3a4bc816, 0x3a44948c, 0x3a3da229, 0x3a36ee9e, 0x3a3077b3,
0x3a2a3b43, 0x3a24373e, 0x3a1e69a5, 0x3a18d08b, 0x3a136a16, 0x3a0e347c,
0x3a092e02, 0x3a0454ff, 0x39ff4fad, 0x39f649f8, 0x39ed95e3, 0x39e5308a,
0x39dd1726, 0x39d54706, 0x39cdbd95, 0x39c67853, 0x39bf74d7, 0x39b8b0cf,
0x39b229fb, 0x39abde33, 0x39a5cb5f, 0x399fef7e, 0x399a489e, 0x3994d4df,
0x398f9272, 0x398a7f9b, 0x39859aa9, 0x3980e1fe, 0x3978a814, 0x396fde93,
0x39676491, 0x395f373e, 0x395753e5, 0x394fb7e7, 0x394860c1, 0x39414c02,
0x393a7753, 0x3933e06f, 0x392d8529, 0x39276363, 0x39217917, 0x391bc44d,
0x39164323, 0x3910f3c6, 0x390bd472, 0x3906e374, 0x39021f2b, 0x38fb0c03,
0x38f22ce3, 0x38e99e04, 0x38e15c92, 0x38d965ce};
#endif

View File

@@ -0,0 +1,305 @@
/**
* Copyright 2013 Pegah Ghahremani
* 2014 IMSL, PKU-HKUST (author: Wei Shi)
* 2014 Yanqing Sun, Junjie Wang
* 2014 Johns Hopkins University (author: Daniel Povey)
* Copyright 2023 Xiaomi Corporation (authors: Fangjun Kuang)
*
* See LICENSE for clarification regarding multiple authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// this file is copied and modified from
// kaldi/src/feat/resample.cc
#include "resample.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <cstdlib>
#include <type_traits>
#ifndef M_2PI
#define M_2PI 6.283185307179586476925286766559005
#endif
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
template <class I>
I Gcd(I m, I n) {
// this function is copied from kaldi/src/base/kaldi-math.h
if (m == 0 || n == 0) {
if (m == 0 && n == 0) { // gcd not defined, as all integers are divisors.
fprintf(stderr, "Undefined GCD since m = 0, n = 0.\n");
exit(-1);
}
return (m == 0 ? (n > 0 ? n : -n) : (m > 0 ? m : -m));
// return absolute value of whichever is nonzero
}
// could use compile-time assertion
// but involves messing with complex template stuff.
static_assert(std::is_integral<I>::value, "");
while (1) {
m %= n;
if (m == 0) return (n > 0 ? n : -n);
n %= m;
if (n == 0) return (m > 0 ? m : -m);
}
}
/// Returns the least common multiple of two integers. Will
/// crash unless the inputs are positive.
template <class I>
I Lcm(I m, I n) {
// This function is copied from kaldi/src/base/kaldi-math.h
assert(m > 0 && n > 0);
I gcd = Gcd(m, n);
return gcd * (m / gcd) * (n / gcd);
}
static float DotProduct(const float *a, const float *b, int32_t n) {
float sum = 0;
for (int32_t i = 0; i != n; ++i) {
sum += a[i] * b[i];
}
return sum;
}
LinearResample::LinearResample(int32_t samp_rate_in_hz,
int32_t samp_rate_out_hz, float filter_cutoff_hz,
int32_t num_zeros)
: samp_rate_in_(samp_rate_in_hz),
samp_rate_out_(samp_rate_out_hz),
filter_cutoff_(filter_cutoff_hz),
num_zeros_(num_zeros) {
assert(samp_rate_in_hz > 0.0 && samp_rate_out_hz > 0.0 &&
filter_cutoff_hz > 0.0 && filter_cutoff_hz * 2 <= samp_rate_in_hz &&
filter_cutoff_hz * 2 <= samp_rate_out_hz && num_zeros > 0);
// base_freq is the frequency of the repeating unit, which is the gcd
// of the input frequencies.
int32_t base_freq = Gcd(samp_rate_in_, samp_rate_out_);
input_samples_in_unit_ = samp_rate_in_ / base_freq;
output_samples_in_unit_ = samp_rate_out_ / base_freq;
SetIndexesAndWeights();
Reset();
}
void LinearResample::SetIndexesAndWeights() {
first_index_.resize(output_samples_in_unit_);
weights_.resize(output_samples_in_unit_);
double window_width = num_zeros_ / (2.0 * filter_cutoff_);
for (int32_t i = 0; i < output_samples_in_unit_; i++) {
double output_t = i / static_cast<double>(samp_rate_out_);
double min_t = output_t - window_width, max_t = output_t + window_width;
// we do ceil on the min and floor on the max, because if we did it
// the other way around we would unnecessarily include indexes just
// outside the window, with zero coefficients. It's possible
// if the arguments to the ceil and floor expressions are integers
// (e.g. if filter_cutoff_ has an exact ratio with the sample rates),
// that we unnecessarily include something with a zero coefficient,
// but this is only a slight efficiency issue.
int32_t min_input_index = ceil(min_t * samp_rate_in_),
max_input_index = floor(max_t * samp_rate_in_),
num_indices = max_input_index - min_input_index + 1;
first_index_[i] = min_input_index;
weights_[i].resize(num_indices);
for (int32_t j = 0; j < num_indices; j++) {
int32_t input_index = min_input_index + j;
double input_t = input_index / static_cast<double>(samp_rate_in_),
delta_t = input_t - output_t;
// sign of delta_t doesn't matter.
weights_[i][j] = FilterFunc(delta_t) / samp_rate_in_;
}
}
}
/** Here, t is a time in seconds representing an offset from
the center of the windowed filter function, and FilterFunction(t)
returns the windowed filter function, described
in the header as h(t) = f(t)g(t), evaluated at t.
*/
float LinearResample::FilterFunc(float t) const {
float window, // raised-cosine (Hanning) window of width
// num_zeros_/2*filter_cutoff_
filter; // sinc filter function
if (fabs(t) < num_zeros_ / (2.0 * filter_cutoff_))
window = 0.5 * (1 + cos(M_2PI * filter_cutoff_ / num_zeros_ * t));
else
window = 0.0; // outside support of window function
if (t != 0)
filter = sin(M_2PI * filter_cutoff_ * t) / (M_PI * t);
else
filter = 2 * filter_cutoff_; // limit of the function at t = 0
return filter * window;
}
void LinearResample::Reset() {
input_sample_offset_ = 0;
output_sample_offset_ = 0;
input_remainder_.resize(0);
}
void LinearResample::Resample(const float *input, int32_t input_dim, bool flush,
std::vector<float> *output) {
int64_t tot_input_samp = input_sample_offset_ + input_dim,
tot_output_samp = GetNumOutputSamples(tot_input_samp, flush);
assert(tot_output_samp >= output_sample_offset_);
output->resize(tot_output_samp - output_sample_offset_);
// samp_out is the index into the total output signal, not just the part
// of it we are producing here.
for (int64_t samp_out = output_sample_offset_; samp_out < tot_output_samp;
samp_out++) {
int64_t first_samp_in;
int32_t samp_out_wrapped;
GetIndexes(samp_out, &first_samp_in, &samp_out_wrapped);
const std::vector<float> &weights = weights_[samp_out_wrapped];
// first_input_index is the first index into "input" that we have a weight
// for.
int32_t first_input_index =
static_cast<int32_t>(first_samp_in - input_sample_offset_);
float this_output;
if (first_input_index >= 0 &&
first_input_index + static_cast<int32_t>(weights.size()) <= input_dim) {
this_output =
DotProduct(input + first_input_index, weights.data(), weights.size());
} else { // Handle edge cases.
this_output = 0.0;
for (int32_t i = 0; i < static_cast<int32_t>(weights.size()); i++) {
float weight = weights[i];
int32_t input_index = first_input_index + i;
if (input_index < 0 &&
static_cast<int32_t>(input_remainder_.size()) + input_index >= 0) {
this_output +=
weight * input_remainder_[input_remainder_.size() + input_index];
} else if (input_index >= 0 && input_index < input_dim) {
this_output += weight * input[input_index];
} else if (input_index >= input_dim) {
// We're past the end of the input and are adding zero; should only
// happen if the user specified flush == true, or else we would not
// be trying to output this sample.
assert(flush);
}
}
}
int32_t output_index =
static_cast<int32_t>(samp_out - output_sample_offset_);
(*output)[output_index] = this_output;
}
if (flush) {
Reset(); // Reset the internal state.
} else {
SetRemainder(input, input_dim);
input_sample_offset_ = tot_input_samp;
output_sample_offset_ = tot_output_samp;
}
}
int64_t LinearResample::GetNumOutputSamples(int64_t input_num_samp,
bool flush) const {
// For exact computation, we measure time in "ticks" of 1.0 / tick_freq,
// where tick_freq is the least common multiple of samp_rate_in_ and
// samp_rate_out_.
int32_t tick_freq = Lcm(samp_rate_in_, samp_rate_out_);
int32_t ticks_per_input_period = tick_freq / samp_rate_in_;
// work out the number of ticks in the time interval
// [ 0, input_num_samp/samp_rate_in_ ).
int64_t interval_length_in_ticks = input_num_samp * ticks_per_input_period;
if (!flush) {
float window_width = num_zeros_ / (2.0 * filter_cutoff_);
// To count the window-width in ticks we take the floor. This
// is because since we're looking for the largest integer num-out-samp
// that fits in the interval, which is open on the right, a reduction
// in interval length of less than a tick will never make a difference.
// For example, the largest integer in the interval [ 0, 2 ) and the
// largest integer in the interval [ 0, 2 - 0.9 ) are the same (both one).
// So when we're subtracting the window-width we can ignore the fractional
// part.
int32_t window_width_ticks = floor(window_width * tick_freq);
// The time-period of the output that we can sample gets reduced
// by the window-width (which is actually the distance from the
// center to the edge of the windowing function) if we're not
// "flushing the output".
interval_length_in_ticks -= window_width_ticks;
}
if (interval_length_in_ticks <= 0) return 0;
int32_t ticks_per_output_period = tick_freq / samp_rate_out_;
// Get the last output-sample in the closed interval, i.e. replacing [ ) with
// [ ]. Note: integer division rounds down. See
// http://en.wikipedia.org/wiki/Interval_(mathematics) for an explanation of
// the notation.
int64_t last_output_samp = interval_length_in_ticks / ticks_per_output_period;
// We need the last output-sample in the open interval, so if it takes us to
// the end of the interval exactly, subtract one.
if (last_output_samp * ticks_per_output_period == interval_length_in_ticks)
last_output_samp--;
// First output-sample index is zero, so the number of output samples
// is the last output-sample plus one.
int64_t num_output_samp = last_output_samp + 1;
return num_output_samp;
}
// inline
void LinearResample::GetIndexes(int64_t samp_out, int64_t *first_samp_in,
int32_t *samp_out_wrapped) const {
// A unit is the smallest nonzero amount of time that is an exact
// multiple of the input and output sample periods. The unit index
// is the answer to "which numbered unit we are in".
int64_t unit_index = samp_out / output_samples_in_unit_;
// samp_out_wrapped is equal to samp_out % output_samples_in_unit_
*samp_out_wrapped =
static_cast<int32_t>(samp_out - unit_index * output_samples_in_unit_);
*first_samp_in =
first_index_[*samp_out_wrapped] + unit_index * input_samples_in_unit_;
}
void LinearResample::SetRemainder(const float *input, int32_t input_dim) {
std::vector<float> old_remainder(input_remainder_);
// max_remainder_needed is the width of the filter from side to side,
// measured in input samples. you might think it should be half that,
// but you have to consider that you might be wanting to output samples
// that are "in the past" relative to the beginning of the latest
// input... anyway, storing more remainder than needed is not harmful.
int32_t max_remainder_needed =
ceil(samp_rate_in_ * num_zeros_ / filter_cutoff_);
input_remainder_.resize(max_remainder_needed);
for (int32_t index = -static_cast<int32_t>(input_remainder_.size());
index < 0; index++) {
// we interpret "index" as an offset from the end of "input" and
// from the end of input_remainder_.
int32_t input_index = index + input_dim;
if (input_index >= 0) {
input_remainder_[index + static_cast<int32_t>(input_remainder_.size())] =
input[input_index];
} else if (input_index + static_cast<int32_t>(old_remainder.size()) >= 0) {
input_remainder_[index + static_cast<int32_t>(input_remainder_.size())] =
old_remainder[input_index +
static_cast<int32_t>(old_remainder.size())];
// else leave it at zero.
}
}
}

View File

@@ -0,0 +1,137 @@
/**
* Copyright 2013 Pegah Ghahremani
* 2014 IMSL, PKU-HKUST (author: Wei Shi)
* 2014 Yanqing Sun, Junjie Wang
* 2014 Johns Hopkins University (author: Daniel Povey)
* Copyright 2023 Xiaomi Corporation (authors: Fangjun Kuang)
*
* See LICENSE for clarification regarding multiple authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// this file is copied and modified from
// kaldi/src/feat/resample.h
#include <cstdint>
#include <vector>
/*
We require that the input and output sampling rate be specified as
integers, as this is an easy way to specify that their ratio be rational.
*/
class LinearResample {
public:
/// Constructor. We make the input and output sample rates integers, because
/// we are going to need to find a common divisor. This should just remind
/// you that they need to be integers. The filter cutoff needs to be less
/// than samp_rate_in_hz/2 and less than samp_rate_out_hz/2. num_zeros
/// controls the sharpness of the filter, more == sharper but less efficient.
/// We suggest around 4 to 10 for normal use.
LinearResample(int32_t samp_rate_in_hz, int32_t samp_rate_out_hz,
float filter_cutoff_hz, int32_t num_zeros);
/// Calling the function Reset() resets the state of the object prior to
/// processing a new signal; it is only necessary if you have called
/// Resample(x, x_size, false, y) for some signal, leading to a remainder of
/// the signal being called, but then abandon processing the signal before
/// calling Resample(x, x_size, true, y) for the last piece. Call it
/// unnecessarily between signals will not do any harm.
void Reset();
/// This function does the resampling. If you call it with flush == true and
/// you have never called it with flush == false, it just resamples the input
/// signal (it resizes the output to a suitable number of samples).
///
/// You can also use this function to process a signal a piece at a time.
/// suppose you break it into piece1, piece2, ... pieceN. You can call
/// \code{.cc}
/// Resample(piece1, piece1_size, false, &output1);
/// Resample(piece2, piece2_size, false, &output2);
/// Resample(piece3, piece3_size, true, &output3);
/// \endcode
/// If you call it with flush == false, it won't output the last few samples
/// but will remember them, so that if you later give it a second piece of
/// the input signal it can process it correctly.
/// If your most recent call to the object was with flush == false, it will
/// have internal state; you can remove this by calling Reset().
/// Empty input is acceptable.
void Resample(const float *input, int32_t input_dim, bool flush,
std::vector<float> *output);
//// Return the input and output sampling rates (for checks, for example)
int32_t GetInputSamplingRate() const { return samp_rate_in_; }
int32_t GetOutputSamplingRate() const { return samp_rate_out_; }
private:
void SetIndexesAndWeights();
float FilterFunc(float) const;
/// This function outputs the number of output samples we will output
/// for a signal with "input_num_samp" input samples. If flush == true,
/// we return the largest n such that
/// (n/samp_rate_out_) is in the interval [ 0, input_num_samp/samp_rate_in_ ),
/// and note that the interval is half-open. If flush == false,
/// define window_width as num_zeros / (2.0 * filter_cutoff_);
/// we return the largest n such that (n/samp_rate_out_) is in the interval
/// [ 0, input_num_samp/samp_rate_in_ - window_width ).
int64_t GetNumOutputSamples(int64_t input_num_samp, bool flush) const;
/// Given an output-sample index, this function outputs to *first_samp_in the
/// first input-sample index that we have a weight on (may be negative),
/// and to *samp_out_wrapped the index into weights_ where we can get the
/// corresponding weights on the input.
inline void GetIndexes(int64_t samp_out, int64_t *first_samp_in,
int32_t *samp_out_wrapped) const;
void SetRemainder(const float *input, int32_t input_dim);
private:
// The following variables are provided by the user.
int32_t samp_rate_in_;
int32_t samp_rate_out_;
float filter_cutoff_;
int32_t num_zeros_;
int32_t input_samples_in_unit_; ///< The number of input samples in the
///< smallest repeating unit: num_samp_in_ =
///< samp_rate_in_hz / Gcd(samp_rate_in_hz,
///< samp_rate_out_hz)
int32_t output_samples_in_unit_; ///< The number of output samples in the
///< smallest repeating unit: num_samp_out_
///< = samp_rate_out_hz /
///< Gcd(samp_rate_in_hz, samp_rate_out_hz)
/// The first input-sample index that we sum over, for this output-sample
/// index. May be negative; any truncation at the beginning is handled
/// separately. This is just for the first few output samples, but we can
/// extrapolate the correct input-sample index for arbitrary output samples.
std::vector<int32_t> first_index_;
/// Weights on the input samples, for this output-sample index.
std::vector<std::vector<float>> weights_;
// the following variables keep track of where we are in a particular signal,
// if it is being provided over multiple calls to Resample().
int64_t input_sample_offset_; ///< The number of input samples we have
///< already received for this signal
///< (including anything in remainder_)
int64_t output_sample_offset_; ///< The number of samples we have already
///< output for this signal.
std::vector<float> input_remainder_; ///< A small trailing part of the
///< previously seen input signal.
};

View File

@@ -0,0 +1,155 @@
#ifndef TENSOR_H
#define TENSOR_H
#include "alignedmem.h"
using namespace std;
template <typename T> class Tensor {
private:
void alloc_buff();
void free_buff();
int mem_size;
public:
T *buff;
int size[4];
int buff_size;
Tensor(Tensor<T> *in);
Tensor(int a);
Tensor(int a, int b);
Tensor(int a, int b, int c);
Tensor(int a, int b, int c, int d);
~Tensor();
void zeros();
void shape();
void disp();
void dump(const char *mode);
void concat(Tensor<T> *din, int dim);
void resize(int a, int b, int c, int d);
void add(float coe, Tensor<T> *in);
void add(Tensor<T> *in);
void add(Tensor<T> *in1, Tensor<T> *in2);
void reload(Tensor<T> *in);
};
template <typename T> Tensor<T>::Tensor(int a) : size{1, 1, 1, a}
{
alloc_buff();
}
template <typename T> Tensor<T>::Tensor(int a, int b) : size{1, 1, a, b}
{
alloc_buff();
}
template <typename T> Tensor<T>::Tensor(int a, int b, int c) : size{1, a, b, c}
{
alloc_buff();
}
template <typename T>
Tensor<T>::Tensor(int a, int b, int c, int d) : size{a, b, c, d}
{
alloc_buff();
}
template <typename T> Tensor<T>::Tensor(Tensor<T> *in)
{
memcpy(size, in->size, 4 * sizeof(int));
alloc_buff();
memcpy(buff, in->buff, in->buff_size * sizeof(T));
}
template <typename T> Tensor<T>::~Tensor()
{
free_buff();
}
template <typename T> void Tensor<T>::alloc_buff()
{
buff_size = size[0] * size[1] * size[2] * size[3];
mem_size = buff_size;
buff = (T *)AlignedMalloc(32, buff_size * sizeof(T));
}
template <typename T> void Tensor<T>::free_buff()
{
aligned_free(buff);
}
template <typename T> void Tensor<T>::zeros()
{
memset(buff, 0, buff_size * sizeof(T));
}
template <typename T> void Tensor<T>::shape()
{
printf("(%d,%d,%d,%d)\n", size[0], size[1], size[2], size[3]);
}
// TODO:: fix it!!!!
template <typename T> void Tensor<T>::concat(Tensor<T> *din, int dim)
{
memcpy(buff + buff_size, din->buff, din->buff_size * sizeof(T));
buff_size += din->buff_size;
size[dim] += din->size[dim];
}
// TODO:: fix it!!!!
template <typename T> void Tensor<T>::resize(int a, int b, int c, int d)
{
size[0] = a;
size[1] = b;
size[2] = c;
size[3] = d;
buff_size = size[0] * size[1] * size[2] * size[3];
}
template <typename T> void Tensor<T>::add(float coe, Tensor<T> *in)
{
int i;
for (i = 0; i < buff_size; i++) {
buff[i] = buff[i] + coe * in->buff[i];
}
}
template <typename T> void Tensor<T>::add(Tensor<T> *in)
{
int i;
for (i = 0; i < buff_size; i++) {
buff[i] = buff[i] + in->buff[i];
}
}
template <typename T> void Tensor<T>::add(Tensor<T> *in1, Tensor<T> *in2)
{
int i;
for (i = 0; i < buff_size; i++) {
buff[i] = buff[i] + in1->buff[i] + in2->buff[i];
}
}
template <typename T> void Tensor<T>::reload(Tensor<T> *in)
{
memcpy(buff, in->buff, in->buff_size * sizeof(T));
}
template <typename T> void Tensor<T>::disp()
{
int i;
for (i = 0; i < buff_size; i++) {
cout << buff[i] << " ";
}
cout << endl;
}
template <typename T> void Tensor<T>::dump(const char *mode)
{
FILE *fp;
fp = fopen("tmp.bin", mode);
fwrite(buff, 1, buff_size * sizeof(T), fp);
fclose(fp);
}
#endif

View File

@@ -0,0 +1,218 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#include "precomp.h"
CTokenizer::CTokenizer(const char* sz_yamlfile):m_ready(false)
{
OpenYaml(sz_yamlfile);
}
CTokenizer::CTokenizer():m_ready(false)
{
}
void CTokenizer::ReadYaml(const YAML::Node& node)
{
if (node.IsMap())
{//<2F><>map<61><70>
for (auto it = node.begin(); it != node.end(); ++it)
{
ReadYaml(it->second);
}
}
if (node.IsSequence()) {//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
for (size_t i = 0; i < node.size(); ++i) {
ReadYaml(node[i]);
}
}
if (node.IsScalar()) {//<2F>DZ<EFBFBD><C7B1><EFBFBD><EFBFBD><EFBFBD>
LOG(INFO) << node.as<string>();
}
}
bool CTokenizer::OpenYaml(const char* sz_yamlfile)
{
YAML::Node m_Config;
try{
m_Config = YAML::LoadFile(sz_yamlfile);
}catch(exception const &e){
LOG(INFO) << "Error loading file, yaml file error or not exist.";
exit(-1);
}
try
{
auto Tokens = m_Config["token_list"];
if (Tokens.IsSequence())
{
for (size_t i = 0; i < Tokens.size(); ++i)
{
if (Tokens[i].IsScalar())
{
m_id2token.push_back(Tokens[i].as<string>());
m_token2id.insert(make_pair<string, int>(Tokens[i].as<string>(), i));
}
}
}
auto Puncs = m_Config["punc_list"];
if (Puncs.IsSequence())
{
for (size_t i = 0; i < Puncs.size(); ++i)
{
if (Puncs[i].IsScalar())
{
m_id2punc.push_back(Puncs[i].as<string>());
m_punc2id.insert(make_pair<string, int>(Puncs[i].as<string>(), i));
}
}
}
}
catch (YAML::BadFile& e) {
LOG(ERROR) << "Read error!";
return false;
}
m_ready = true;
return m_ready;
}
vector<string> CTokenizer::Id2String(vector<int> input)
{
vector<string> result;
for (auto& item : input)
{
result.push_back(m_id2token[item]);
}
return result;
}
int CTokenizer::String2Id(string input)
{
int nID = 0; // <blank>
if (m_token2id.find(input) != m_token2id.end())
nID=(m_token2id[input]);
else
nID=(m_token2id[UNK_CHAR]);
return nID;
}
vector<int> CTokenizer::String2Ids(vector<string> input)
{
vector<int> result;
for (auto& item : input)
{
transform(item.begin(), item.end(), item.begin(), ::tolower);
if (m_token2id.find(item) != m_token2id.end())
result.push_back(m_token2id[item]);
else
result.push_back(m_token2id[UNK_CHAR]);
}
return result;
}
vector<string> CTokenizer::Id2Punc(vector<int> input)
{
vector<string> result;
for (auto& item : input)
{
result.push_back(m_id2punc[item]);
}
return result;
}
string CTokenizer::Id2Punc(int n_punc_id)
{
return m_id2punc[n_punc_id];
}
vector<int> CTokenizer::Punc2Ids(vector<string> input)
{
vector<int> result;
for (auto& item : input)
{
result.push_back(m_punc2id[item]);
}
return result;
}
vector<string> CTokenizer::SplitChineseString(const string & str_info)
{
vector<string> list;
int strSize = str_info.size();
int i = 0;
while (i < strSize) {
int len = 1;
for (int j = 0; j < 6 && (str_info[i] & (0x80 >> j)); j++) {
len = j + 1;
}
list.push_back(str_info.substr(i, len));
i += len;
}
return list;
}
void CTokenizer::StrSplit(const string& str, const char split, vector<string>& res)
{
if (str == "")
{
return;
}
string&& strs = str + split;
size_t pos = strs.find(split);
while (pos != string::npos)
{
res.emplace_back(strs.substr(0, pos));
strs = move(strs.substr(pos + 1, strs.size()));
pos = strs.find(split);
}
}
void CTokenizer::Tokenize(const char* str_info, vector<string> & str_out, vector<int> & id_out)
{
vector<string> strList;
StrSplit(str_info,' ', strList);
string current_eng,current_chinese;
for (auto& item : strList)
{
current_eng = "";
current_chinese = "";
for (auto& ch : item)
{
if (!(ch& 0x80))
{ // Ӣ<><D3A2>
if (current_chinese.size() > 0)
{
// for utf-8 chinese
auto chineseList = SplitChineseString(current_chinese);
str_out.insert(str_out.end(), chineseList.begin(),chineseList.end());
current_chinese = "";
}
current_eng += ch;
}
else
{
if (current_eng.size() > 0)
{
str_out.push_back(current_eng);
current_eng = "";
}
current_chinese += ch;
}
}
if (current_chinese.size() > 0)
{
auto chineseList = SplitChineseString(current_chinese);
str_out.insert(str_out.end(), chineseList.begin(), chineseList.end());
current_chinese = "";
}
if (current_eng.size() > 0)
{
str_out.push_back(current_eng);
}
}
id_out= String2Ids(str_out);
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights Reserved.
* MIT License (https://opensource.org/licenses/MIT)
*/
#pragma once
#include <yaml-cpp/yaml.h>
class CTokenizer {
private:
bool m_ready = false;
vector<string> m_id2token,m_id2punc;
map<string, int> m_token2id,m_punc2id;
public:
CTokenizer(const char* sz_yamlfile);
CTokenizer();
bool OpenYaml(const char* sz_yamlfile);
void ReadYaml(const YAML::Node& node);
vector<string> Id2String(vector<int> input);
vector<int> String2Ids(vector<string> input);
int String2Id(string input);
vector<string> Id2Punc(vector<int> input);
string Id2Punc(int n_punc_id);
vector<int> Punc2Ids(vector<string> input);
vector<string> SplitChineseString(const string& str_info);
void StrSplit(const string& str, const char split, vector<string>& res);
void Tokenize(const char* str_info, vector<string>& str_out, vector<int>& id_out);
};

View File

@@ -0,0 +1,180 @@
#include "precomp.h"
float *LoadParams(const char *filename)
{
FILE *fp;
fp = fopen(filename, "rb");
fseek(fp, 0, SEEK_END);
uint32_t nFileLen = ftell(fp);
fseek(fp, 0, SEEK_SET);
float *params_addr = (float *)AlignedMalloc(32, nFileLen);
int n = fread(params_addr, 1, nFileLen, fp);
fclose(fp);
return params_addr;
}
int ValAlign(int val, int align)
{
float tmp = ceil((float)val / (float)align) * (float)align;
return (int)tmp;
}
void DispParams(float *din, int size)
{
int i;
for (i = 0; i < size; i++) {
printf("%f ", din[i]);
}
printf("\n");
}
void SaveDataFile(const char *filename, void *data, uint32_t len)
{
FILE *fp;
fp = fopen(filename, "wb+");
fwrite(data, 1, len, fp);
fclose(fp);
}
void BasicNorm(Tensor<float> *&din, float norm)
{
int Tmax = din->size[2];
int i, j;
for (i = 0; i < Tmax; i++) {
float sum = 0;
for (j = 0; j < 512; j++) {
int ii = i * 512 + j;
sum += din->buff[ii] * din->buff[ii];
}
float mean = sqrt(sum / 512 + norm);
for (j = 0; j < 512; j++) {
int ii = i * 512 + j;
din->buff[ii] = din->buff[ii] / mean;
}
}
}
void FindMax(float *din, int len, float &max_val, int &max_idx)
{
int i;
max_val = -INFINITY;
max_idx = -1;
for (i = 0; i < len; i++) {
if (din[i] > max_val) {
max_val = din[i];
max_idx = i;
}
}
}
string PathAppend(const string &p1, const string &p2)
{
char sep = '/';
string tmp = p1;
#ifdef _WIN32
sep = '\\';
#endif
if (p1[p1.length()-1] != sep) { // Need to add a
tmp += sep; // path separator
return (tmp + p2);
} else
return (p1 + p2);
}
void Relu(Tensor<float> *din)
{
int i;
for (i = 0; i < din->buff_size; i++) {
float val = din->buff[i];
din->buff[i] = val < 0 ? 0 : val;
}
}
void Swish(Tensor<float> *din)
{
int i;
for (i = 0; i < din->buff_size; i++) {
float val = din->buff[i];
din->buff[i] = val / (1 + exp(-val));
}
}
void Sigmoid(Tensor<float> *din)
{
int i;
for (i = 0; i < din->buff_size; i++) {
float val = din->buff[i];
din->buff[i] = 1 / (1 + exp(-val));
}
}
void DoubleSwish(Tensor<float> *din)
{
int i;
for (i = 0; i < din->buff_size; i++) {
float val = din->buff[i];
din->buff[i] = val / (1 + exp(-val + 1));
}
}
void Softmax(float *din, int mask, int len)
{
float *tmp = (float *)malloc(mask * sizeof(float));
int i;
float sum = 0;
float max = -INFINITY;
for (i = 0; i < mask; i++) {
max = max < din[i] ? din[i] : max;
}
for (i = 0; i < mask; i++) {
tmp[i] = exp(din[i] - max);
sum += tmp[i];
}
for (i = 0; i < mask; i++) {
din[i] = tmp[i] / sum;
}
free(tmp);
for (i = mask; i < len; i++) {
din[i] = 0;
}
}
void LogSoftmax(float *din, int len)
{
float *tmp = (float *)malloc(len * sizeof(float));
int i;
float sum = 0;
for (i = 0; i < len; i++) {
tmp[i] = exp(din[i]);
sum += tmp[i];
}
for (i = 0; i < len; i++) {
din[i] = log(tmp[i] / sum);
}
free(tmp);
}
void Glu(Tensor<float> *din, Tensor<float> *dout)
{
int mm = din->buff_size / 1024;
int i, j;
for (i = 0; i < mm; i++) {
for (j = 0; j < 512; j++) {
int in_off = i * 1024 + j;
int out_off = i * 512 + j;
float a = din->buff[in_off];
float b = din->buff[in_off + 512];
dout->buff[out_off] = a / (1 + exp(-b));
}
}
}

View File

@@ -0,0 +1,30 @@
#ifndef UTIL_H
#define UTIL_H
using namespace std;
extern float *LoadParams(const char *filename);
extern void SaveDataFile(const char *filename, void *data, uint32_t len);
extern void Relu(Tensor<float> *din);
extern void Swish(Tensor<float> *din);
extern void Sigmoid(Tensor<float> *din);
extern void DoubleSwish(Tensor<float> *din);
extern void Softmax(float *din, int mask, int len);
extern void LogSoftmax(float *din, int len);
extern int ValAlign(int val, int align);
extern void DispParams(float *din, int size);
extern void BasicNorm(Tensor<float> *&din, float norm);
extern void FindMax(float *din, int len, float &max_val, int &max_idx);
extern void Glu(Tensor<float> *din, Tensor<float> *dout);
string PathAppend(const string &p1, const string &p2);
#endif

View File

@@ -0,0 +1,153 @@
#include "vocab.h"
#include <yaml-cpp/yaml.h>
#include <glog/logging.h>
#include <fstream>
#include <iostream>
#include <list>
#include <sstream>
#include <string>
using namespace std;
Vocab::Vocab(const char *filename)
{
ifstream in(filename);
LoadVocabFromYaml(filename);
}
Vocab::~Vocab()
{
}
void Vocab::LoadVocabFromYaml(const char* filename){
YAML::Node config;
try{
config = YAML::LoadFile(filename);
}catch(exception const &e){
LOG(INFO) << "Error loading file, yaml file error or not exist.";
exit(-1);
}
YAML::Node myList = config["token_list"];
for (YAML::const_iterator it = myList.begin(); it != myList.end(); ++it) {
vocab.push_back(it->as<string>());
}
}
string Vocab::Vector2String(vector<int> in)
{
int i;
stringstream ss;
for (auto it = in.begin(); it != in.end(); it++) {
ss << vocab[*it];
}
return ss.str();
}
int Str2Int(string str)
{
const char *ch_array = str.c_str();
if (((ch_array[0] & 0xf0) != 0xe0) || ((ch_array[1] & 0xc0) != 0x80) ||
((ch_array[2] & 0xc0) != 0x80))
return 0;
int val = ((ch_array[0] & 0x0f) << 12) | ((ch_array[1] & 0x3f) << 6) |
(ch_array[2] & 0x3f);
return val;
}
bool Vocab::IsChinese(string ch)
{
if (ch.size() != 3) {
return false;
}
int unicode = Str2Int(ch);
if (unicode >= 19968 && unicode <= 40959) {
return true;
}
return false;
}
string Vocab::Vector2StringV2(vector<int> in)
{
int i;
list<string> words;
int is_pre_english = false;
int pre_english_len = 0;
int is_combining = false;
string combine = "";
for (auto it = in.begin(); it != in.end(); it++) {
string word = vocab[*it];
// step1 space character skips
if (word == "<s>" || word == "</s>" || word == "<unk>")
continue;
// step2 combie phoneme to full word
{
int sub_word = !(word.find("@@") == string::npos);
// process word start and middle part
if (sub_word) {
combine += word.erase(word.length() - 2);
is_combining = true;
continue;
}
// process word end part
else if (is_combining) {
combine += word;
is_combining = false;
word = combine;
combine = "";
}
}
// step3 process english word deal with space , turn abbreviation to upper case
{
// input word is chinese, not need process
if (IsChinese(word)) {
words.push_back(word);
is_pre_english = false;
}
// input word is english word
else {
// pre word is chinese
if (!is_pre_english) {
word[0] = word[0] - 32;
words.push_back(word);
pre_english_len = word.size();
}
// pre word is english word
else {
// single letter turn to upper case
if (word.size() == 1) {
word[0] = word[0] - 32;
}
if (pre_english_len > 1) {
words.push_back(" ");
words.push_back(word);
pre_english_len = word.size();
}
else {
if (word.size() > 1) {
words.push_back(" ");
}
words.push_back(word);
pre_english_len = word.size();
}
}
is_pre_english = true;
}
}
}
stringstream ss;
for (auto it = words.begin(); it != words.end(); it++) {
ss << *it;
}
return ss.str();
}
int Vocab::Size()
{
return vocab.size();
}

View File

@@ -0,0 +1,25 @@
#ifndef VOCAB_H
#define VOCAB_H
#include <stdint.h>
#include <string>
#include <vector>
using namespace std;
class Vocab {
private:
vector<string> vocab;
bool IsChinese(string ch);
bool IsEnglish(string ch);
void LoadVocabFromYaml(const char* filename);
public:
Vocab(const char *filename);
~Vocab();
int Size();
string Vector2String(vector<int> in);
string Vector2StringV2(vector<int> in);
};
#endif

View File

@@ -0,0 +1,941 @@
cmake_minimum_required (VERSION 3.16)
project (glog
VERSION 0.7.0
DESCRIPTION "C++ implementation of the Google logging module"
HOMEPAGE_URL https://github.com/google/glog
LANGUAGES CXX
)
set (CPACK_PACKAGE_NAME glog)
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Google logging library")
set (CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set (CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set (CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set (CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include (CheckCXXCompilerFlag)
include (CheckCXXSourceCompiles)
include (CheckCXXSourceRuns)
include (CheckCXXSymbolExists)
include (CheckFunctionExists)
include (CheckIncludeFileCXX)
include (CheckLibraryExists)
include (CheckStructHasMember)
include (CheckTypeSize)
include (CMakeDependentOption)
include (CMakePackageConfigHelpers)
include (CMakePushCheckState)
include (CPack)
include (CTest)
include (DetermineGflagsNamespace)
include (GenerateExportHeader)
include (GetCacheVariables)
include (GNUInstallDirs)
option (BUILD_SHARED_LIBS "Build shared libraries" ON)
option (PRINT_UNSYMBOLIZED_STACK_TRACES
"Print file offsets in traces instead of symbolizing" OFF)
option (WITH_GFLAGS "Use gflags" ON)
option (WITH_GTEST "Use Google Test" ON)
option (WITH_PKGCONFIG "Enable pkg-config support" ON)
option (WITH_SYMBOLIZE "Enable symbolize module" ON)
option (WITH_THREADS "Enable multithreading support" ON)
option (WITH_TLS "Enable Thread Local Storage (TLS) support" ON)
option (WITH_UNWIND "Enable libunwind support" ON)
cmake_dependent_option (WITH_GMOCK "Use Google Mock" ON WITH_GTEST OFF)
set (WITH_FUZZING none CACHE STRING "Fuzzing engine")
set_property (CACHE WITH_FUZZING PROPERTY STRINGS none libfuzzer ossfuzz)
if (NOT WITH_UNWIND)
set (CMAKE_DISABLE_FIND_PACKAGE_Unwind ON)
endif (NOT WITH_UNWIND)
if (NOT WITH_GTEST)
set (CMAKE_DISABLE_FIND_PACKAGE_GTest ON)
endif (NOT WITH_GTEST)
if (NOT WITH_THREADS)
set (CMAKE_DISABLE_FIND_PACKAGE_Threads ON)
endif (NOT WITH_THREADS)
set (CMAKE_C_VISIBILITY_PRESET hidden)
set (CMAKE_CXX_VISIBILITY_PRESET hidden)
set (CMAKE_POSITION_INDEPENDENT_CODE ON)
set (CMAKE_VISIBILITY_INLINES_HIDDEN ON)
set (CMAKE_DEBUG_POSTFIX d)
set (CMAKE_THREAD_PREFER_PTHREAD 1)
find_package (GTest NO_MODULE)
if (GTest_FOUND)
set (HAVE_LIB_GTEST 1)
endif (GTest_FOUND)
if (WITH_GMOCK AND TARGET GTest::gmock)
set (HAVE_LIB_GMOCK 1)
endif (WITH_GMOCK AND TARGET GTest::gmock)
if (WITH_GFLAGS)
find_package (gflags 2.2.2)
if (gflags_FOUND)
set (HAVE_LIB_GFLAGS 1)
determine_gflags_namespace (gflags_NAMESPACE)
endif (gflags_FOUND)
endif (WITH_GFLAGS)
find_package (Threads)
find_package (Unwind)
if (Unwind_FOUND)
set (HAVE_LIB_UNWIND 1)
else (Unwind_FOUND)
# Check whether linking actually succeeds. ARM toolchains of LLVM unwind
# implementation do not necessarily provide the _Unwind_Backtrace function
# which causes the previous check to succeed but the linking to fail.
check_cxx_symbol_exists (_Unwind_Backtrace unwind.h HAVE__UNWIND_BACKTRACE)
check_cxx_symbol_exists (_Unwind_GetIP unwind.h HAVE__UNWIND_GETIP)
endif (Unwind_FOUND)
check_include_file_cxx (dlfcn.h HAVE_DLFCN_H)
check_include_file_cxx (glob.h HAVE_GLOB_H)
check_include_file_cxx (memory.h HAVE_MEMORY_H)
check_include_file_cxx (pwd.h HAVE_PWD_H)
check_include_file_cxx (strings.h HAVE_STRINGS_H)
check_include_file_cxx (sys/stat.h HAVE_SYS_STAT_H)
check_include_file_cxx (sys/syscall.h HAVE_SYS_SYSCALL_H)
check_include_file_cxx (sys/time.h HAVE_SYS_TIME_H)
check_include_file_cxx (sys/types.h HAVE_SYS_TYPES_H)
check_include_file_cxx (sys/utsname.h HAVE_SYS_UTSNAME_H)
check_include_file_cxx (sys/wait.h HAVE_SYS_WAIT_H)
check_include_file_cxx (syscall.h HAVE_SYSCALL_H)
check_include_file_cxx (syslog.h HAVE_SYSLOG_H)
check_include_file_cxx (ucontext.h HAVE_UCONTEXT_H)
check_include_file_cxx (unistd.h HAVE_UNISTD_H)
check_type_size (mode_t HAVE_MODE_T LANGUAGE CXX)
check_type_size (ssize_t HAVE_SSIZE_T LANGUAGE CXX)
check_function_exists (dladdr HAVE_DLADDR)
check_function_exists (fcntl HAVE_FCNTL)
check_function_exists (pread HAVE_PREAD)
check_function_exists (pwrite HAVE_PWRITE)
check_function_exists (sigaction HAVE_SIGACTION)
check_function_exists (sigaltstack HAVE_SIGALTSTACK)
check_cxx_symbol_exists (backtrace execinfo.h HAVE_EXECINFO_BACKTRACE)
check_cxx_symbol_exists (backtrace_symbols execinfo.h
HAVE_EXECINFO_BACKTRACE_SYMBOLS)
# NOTE gcc does not fail if you pass a non-existent -Wno-* option as an
# argument. However, it will happily fail if you pass the corresponding -W*
# option. So, we check whether options that disable warnings exist by testing
# the availability of the corresponding option that enables the warning. This
# eliminates the need to check for compiler for several (mainly Clang) options.
check_cxx_compiler_flag (-Wdeprecated HAVE_NO_DEPRECATED)
check_cxx_compiler_flag (-Wunnamed-type-template-args
HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS)
cmake_push_check_state (RESET)
if (Threads_FOUND)
set (CMAKE_REQUIRED_LIBRARIES Threads::Threads)
endif (Threads_FOUND)
check_cxx_symbol_exists (pthread_threadid_np "pthread.h" HAVE_PTHREAD_THREADID_NP)
cmake_pop_check_state ()
# NOTE: Cannot use check_function_exists here since >=vc-14.0 can define
# snprintf as an inline function
check_cxx_symbol_exists (snprintf cstdio HAVE_SNPRINTF)
check_library_exists (dbghelp UnDecorateSymbolName "" HAVE_DBGHELP)
check_cxx_source_compiles ("
#include <cstdlib>
static void foo(void) __attribute__ ((unused));
int main(void) { return 0; }
" HAVE___ATTRIBUTE__)
check_cxx_source_compiles ("
#include <cstdlib>
static void foo(void) __attribute__ ((visibility(\"default\")));
int main(void) { return 0; }
" HAVE___ATTRIBUTE__VISIBILITY_DEFAULT)
check_cxx_source_compiles ("
#include <cstdlib>
static void foo(void) __attribute__ ((visibility(\"hidden\")));
int main(void) { return 0; }
" HAVE___ATTRIBUTE__VISIBILITY_HIDDEN)
check_cxx_source_compiles ("
int main(void) { if (__builtin_expect(0, 0)) return 1; return 0; }
" HAVE___BUILTIN_EXPECT)
check_cxx_source_compiles ("
int main(void)
{
int a; if (__sync_val_compare_and_swap(&a, 0, 1)) return 1; return 0;
}
" HAVE___SYNC_VAL_COMPARE_AND_SWAP)
if (Threads_FOUND)
cmake_push_check_state (RESET)
set (CMAKE_REQUIRED_LIBRARIES Threads::Threads)
check_cxx_source_compiles ("
#define _XOPEN_SOURCE 500
#include <pthread.h>
int main(void)
{
pthread_rwlock_t l;
pthread_rwlock_init(&l, NULL);
pthread_rwlock_rdlock(&l);
return 0;
}
" HAVE_RWLOCK)
cmake_pop_check_state ()
endif (Threads_FOUND)
check_cxx_source_compiles ("
__declspec(selectany) int a;
int main(void) { return 0; }
" HAVE___DECLSPEC)
if (WITH_TLS)
set (GLOG_THREAD_LOCAL_STORAGE 1)
endif (WITH_TLS)
set (_PC_FIELDS
"gregs[REG_PC]"
"gregs[REG_EIP]"
"gregs[REG_RIP]"
"sc_ip"
"uc_regs->gregs[PT_NIP]"
"gregs[R15]"
"arm_pc"
"mc_eip"
"mc_rip"
"__gregs[REG_EIP]"
"__gregs[REG_RIP]"
"ss.eip"
"__ss.__eip"
"ss.rip"
"__ss.__rip"
"ss.srr0"
"__ss.__srr0"
)
set (_PC_HEADERS ucontext.h signal.h)
if (HAVE_UCONTEXT_H AND NOT PC_FROM_UCONTEXT)
foreach (_PC_FIELD ${_PC_FIELDS})
foreach (_PC_HEADER ${_PC_HEADERS})
set (_TMP
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/uctfield.cpp)
file (WRITE ${_TMP} "
#define _GNU_SOURCE 1
#include <${_PC_HEADER}>
int main(void)
{
ucontext_t u;
return u.${_PC_FIELD} == 0;
}
")
try_compile (HAVE_PC_FROM_UCONTEXT ${CMAKE_CURRENT_BINARY_DIR} ${_TMP}
COMPILE_DEFINITIONS _GNU_SOURCE=1)
if (HAVE_PC_FROM_UCONTEXT)
set (PC_FROM_UCONTEXT ${_PC_FIELD} CACHE)
endif (HAVE_PC_FROM_UCONTEXT)
endforeach (_PC_HEADER)
endforeach (_PC_FIELD)
endif (HAVE_UCONTEXT_H AND NOT PC_FROM_UCONTEXT)
set (GOOGLE_NAMESPACE google)
set (_START_GOOGLE_NAMESPACE_ "namespace ${GOOGLE_NAMESPACE} {")
set (_END_GOOGLE_NAMESPACE_ "}")
set (ac_cv_have_glog_export 1)
if (HAVE_LIB_GFLAGS)
set (ac_cv_have_libgflags 1)
else (HAVE_LIB_GFLAGS)
set (ac_cv_have_libgflags 0)
endif (HAVE_LIB_GFLAGS)
if (HAVE_SYS_TYPES_H)
set (ac_cv_have_systypes_h 1)
else (HAVE_SYS_TYPES_H)
set (ac_cv_have_systypes_h 0)
endif (HAVE_SYS_TYPES_H)
if (HAVE_SSIZE_T)
set (ac_cv_have_ssize_t 1)
else (HAVE_SSIZE_T)
set (ac_cv_have_ssize_t 0)
endif (HAVE_SSIZE_T)
if (HAVE_MODE_T)
set (ac_cv_have_mode_t 1)
else (HAVE_MODE_T)
set (ac_cv_have_mode_t 0)
endif (HAVE_MODE_T)
if (HAVE_UNISTD_H)
set (ac_cv_have_unistd_h 1)
else (HAVE_UNISTD_H)
set (ac_cv_have_unistd_h 0)
endif (HAVE_UNISTD_H)
set (ac_google_namespace ${GOOGLE_NAMESPACE})
set (ac_google_end_namespace ${_END_GOOGLE_NAMESPACE_})
set (ac_google_start_namespace ${_START_GOOGLE_NAMESPACE_})
if (HAVE___ATTRIBUTE__)
set (ac_cv___attribute___noinline "__attribute__((noinline))")
set (ac_cv___attribute___printf_4_5 "__attribute__((__format__(__printf__, 4, 5)))")
elseif (HAVE___DECLSPEC)
#set (ac_cv___attribute___noinline "__declspec(noinline)")
endif (HAVE___ATTRIBUTE__)
if (HAVE___BUILTIN_EXPECT)
set (ac_cv_have___builtin_expect 1)
else (HAVE___BUILTIN_EXPECT)
set (ac_cv_have___builtin_expect 0)
endif (HAVE___BUILTIN_EXPECT)
if (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)
set (HAVE_STACKTRACE 1)
endif (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)
if (WITH_SYMBOLIZE)
if (WIN32 OR CYGWIN)
cmake_push_check_state (RESET)
set (CMAKE_REQUIRED_LIBRARIES DbgHelp)
check_cxx_source_runs ([=[
#include <windows.h>
#include <dbghelp.h>
#include <cstdlib>
void foobar() { }
int main()
{
HANDLE process = GetCurrentProcess();
if (!SymInitialize(process, NULL, TRUE))
return EXIT_FAILURE;
char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(buf);
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
void* const pc = reinterpret_cast<void*>(&foobar);
BOOL ret = SymFromAddr(process, reinterpret_cast<DWORD64>(pc), 0, symbol);
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
}
]=] HAVE_SYMBOLIZE)
cmake_pop_check_state ()
if (HAVE_SYMBOLIZE)
set (HAVE_STACKTRACE 1)
endif (HAVE_SYMBOLIZE)
elseif (UNIX)
cmake_push_check_state (RESET)
check_cxx_source_compiles ([=[
int main()
{
#ifndef __ELF__
#error __ELF__ not defined
#endif
}
]=] HAVE_SYMBOLIZE)
cmake_pop_check_state ()
elseif (APPLE AND HAVE_DLADDR)
set (HAVE_SYMBOLIZE 1)
endif (WIN32 OR CYGWIN)
endif (WITH_SYMBOLIZE)
# CMake manages symbolize availability. The definition is necessary only when
# building the library.
add_compile_definitions (GLOG_NO_SYMBOLIZE_DETECTION)
check_cxx_source_compiles ("
#include <cstdlib>
#include <ctime>
int main()
{
time_t timep;
struct tm result;
localtime_r(&timep, &result);
return EXIT_SUCCESS;
}
" HAVE_LOCALTIME_R)
set (SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
if (WITH_THREADS AND Threads_FOUND)
if (CMAKE_USE_PTHREADS_INIT)
set (HAVE_PTHREAD 1)
endif (CMAKE_USE_PTHREADS_INIT)
else (WITH_THREADS AND Threads_FOUND)
set (NO_THREADS 1)
endif (WITH_THREADS AND Threads_FOUND)
# fopen/open on Cygwin can not handle unix-type paths like /home/....
# therefore we translate TEST_SRC_DIR to windows-path.
if (CYGWIN)
execute_process (COMMAND cygpath.exe -m ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE TEST_SRC_DIR)
set (TEST_SRC_DIR \"${TEST_SRC_DIR}\")
else (CYGWIN)
set (TEST_SRC_DIR \"${CMAKE_CURRENT_SOURCE_DIR}\")
endif (CYGWIN)
configure_file (src/config.h.cmake.in config.h)
configure_file (src/glog/logging.h.in glog/logging.h @ONLY)
configure_file (src/glog/raw_logging.h.in glog/raw_logging.h @ONLY)
configure_file (src/glog/stl_logging.h.in glog/stl_logging.h @ONLY)
configure_file (src/glog/vlog_is_on.h.in glog/vlog_is_on.h @ONLY)
add_compile_options ($<$<AND:$<BOOL:${HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS}>,$<NOT:$<CXX_COMPILER_ID:GNU>>>:-Wno-unnamed-type-template-args>)
set (_glog_CMake_BINDIR ${CMAKE_INSTALL_BINDIR})
set (_glog_CMake_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})
set (_glog_CMake_LIBDIR ${CMAKE_INSTALL_LIBDIR})
set (_glog_CMake_INSTALLDIR ${_glog_CMake_LIBDIR}/cmake/glog)
set (_glog_CMake_DIR glog/cmake)
set (_glog_CMake_DATADIR ${CMAKE_INSTALL_DATAROOTDIR}/${_glog_CMake_DIR})
set (_glog_BINARY_CMake_DATADIR
${CMAKE_CURRENT_BINARY_DIR}/${_glog_CMake_DATADIR})
# Add additional CMake find modules here.
set (_glog_CMake_MODULES)
if (Unwind_FOUND)
# Copy the module only if libunwind is actually used.
list (APPEND _glog_CMake_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindUnwind.cmake)
endif (Unwind_FOUND)
# Generate file name for each module in the binary directory
foreach (_file ${_glog_CMake_MODULES})
get_filename_component (_module "${_file}" NAME)
list (APPEND _glog_BINARY_CMake_MODULES
${_glog_BINARY_CMake_DATADIR}/${_module})
endforeach (_file)
if (_glog_CMake_MODULES)
# Copy modules to binary directory during the build
add_custom_command (OUTPUT ${_glog_BINARY_CMake_MODULES}
COMMAND ${CMAKE_COMMAND} -E make_directory
${_glog_BINARY_CMake_DATADIR}
COMMAND ${CMAKE_COMMAND} -E copy ${_glog_CMake_MODULES}
${_glog_BINARY_CMake_DATADIR}
DEPENDS ${_glog_CMake_MODULES}
COMMENT "Copying find modules..."
)
endif (_glog_CMake_MODULES)
set (GLOG_PUBLIC_H
${CMAKE_CURRENT_BINARY_DIR}/glog/export.h
${CMAKE_CURRENT_BINARY_DIR}/glog/logging.h
${CMAKE_CURRENT_BINARY_DIR}/glog/raw_logging.h
${CMAKE_CURRENT_BINARY_DIR}/glog/stl_logging.h
${CMAKE_CURRENT_BINARY_DIR}/glog/vlog_is_on.h
src/glog/log_severity.h
src/glog/platform.h
)
set (GLOG_SRCS
${GLOG_PUBLIC_H}
src/base/commandlineflags.h
src/base/googleinit.h
src/base/mutex.h
src/demangle.cc
src/demangle.h
src/logging.cc
src/raw_logging.cc
src/symbolize.cc
src/symbolize.h
src/utilities.cc
src/utilities.h
src/vlog_is_on.cc
)
if (HAVE_PTHREAD OR WIN32 OR CYGWIN)
list (APPEND GLOG_SRCS src/signalhandler.cc)
endif (HAVE_PTHREAD OR WIN32 OR CYGWIN)
if (CYGWIN OR WIN32)
list (APPEND GLOG_SRCS
src/windows/port.cc
src/windows/port.h
)
endif (CYGWIN OR WIN32)
add_library (glog_internal OBJECT
${_glog_BINARY_CMake_MODULES}
${GLOG_SRCS}
)
target_compile_features (glog_internal PUBLIC $<TARGET_PROPERTY:glog,COMPILE_FEATURES>)
add_library (glog
$<TARGET_OBJECTS:glog_internal>
)
target_compile_features (glog PUBLIC cxx_std_14)
add_library (glog::glog ALIAS glog)
set (glog_libraries_options_for_static_linking)
if (Unwind_FOUND)
target_link_libraries (glog PRIVATE unwind::unwind)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -lunwind")
set (Unwind_DEPENDENCY "find_dependency (Unwind ${Unwind_VERSION})")
endif (Unwind_FOUND)
if (HAVE_DBGHELP)
target_link_libraries (glog PRIVATE dbghelp)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -ldbghelp")
endif (HAVE_DBGHELP)
if (HAVE_PTHREAD)
target_link_libraries (glog PRIVATE ${CMAKE_THREAD_LIBS_INIT})
if (CMAKE_THREAD_LIBS_INIT)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} ${CMAKE_THREAD_LIBS_INIT}")
endif (CMAKE_THREAD_LIBS_INIT)
endif (HAVE_PTHREAD)
if (gflags_FOUND)
# Prefer the gflags target that uses double colon convention
if (TARGET gflags::gflags)
target_link_libraries (glog PUBLIC gflags::gflags)
else (TARGET gflags::gflags)
target_link_libraries (glog PUBLIC gflags)
endif (TARGET gflags::gflags)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -lgflags")
endif (gflags_FOUND)
if (ANDROID)
target_link_libraries (glog PRIVATE log)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -llog")
endif (ANDROID)
set_target_properties (glog PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties (glog PROPERTIES SOVERSION 1)
if (CYGWIN OR WIN32)
target_compile_definitions (glog PUBLIC GLOG_NO_ABBREVIATED_SEVERITIES)
endif (CYGWIN OR WIN32)
set_target_properties (glog PROPERTIES PUBLIC_HEADER "${GLOG_PUBLIC_H}")
target_include_directories (glog BEFORE PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
"$<INSTALL_INTERFACE:${_glog_CMake_INCLUDE_DIR}>"
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
if (CYGWIN OR WIN32)
target_include_directories (glog_internal PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/windows>"
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/windows)
target_include_directories (glog PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/windows>"
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/windows)
endif (CYGWIN OR WIN32)
set_target_properties (glog PROPERTIES DEFINE_SYMBOL GOOGLE_GLOG_IS_A_DLL)
target_include_directories (glog_internal PUBLIC
$<TARGET_PROPERTY:glog,INCLUDE_DIRECTORIES>)
target_compile_definitions (glog_internal PUBLIC
$<TARGET_PROPERTY:glog,COMPILE_DEFINITIONS>
PRIVATE GOOGLE_GLOG_IS_A_DLL)
generate_export_header (glog
EXPORT_MACRO_NAME GLOG_EXPORT
EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/glog/export.h)
string (STRIP "${glog_libraries_options_for_static_linking}" glog_libraries_options_for_static_linking)
if (WITH_PKGCONFIG)
set (VERSION ${PROJECT_VERSION})
set (prefix ${CMAKE_INSTALL_PREFIX})
set (exec_prefix ${CMAKE_INSTALL_FULL_BINDIR})
set (libdir ${CMAKE_INSTALL_FULL_LIBDIR})
set (includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
configure_file (
"${PROJECT_SOURCE_DIR}/libglog.pc.in"
"${PROJECT_BINARY_DIR}/libglog.pc"
@ONLY
)
unset (VERSION)
unset (prefix)
unset (exec_prefix)
unset (libdir)
unset (includedir)
endif (WITH_PKGCONFIG)
# Unit testing
if (NOT WITH_FUZZING STREQUAL "none")
add_executable (fuzz_demangle
src/fuzz_demangle.cc
)
if (WITH_FUZZING STREQUAL "ossfuzz")
set (LIB_FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE})
target_link_libraries (fuzz_demangle PRIVATE glog ${LIB_FUZZING_ENGINE})
elseif (WITH_FUZZING STREQUAL "libfuzzer")
target_compile_options (fuzz_demangle PRIVATE -fsanitize=fuzzer)
target_link_libraries (fuzz_demangle PRIVATE glog)
else (WITH_FUZZING STREQUAL "libfuzzer")
message (FATAL_ERROR "Unsupported fuzzing engine ${WITH_FUZZING}")
endif (WITH_FUZZING STREQUAL "ossfuzz")
endif (NOT WITH_FUZZING STREQUAL "none")
if (BUILD_TESTING)
add_library (glogtest STATIC
$<TARGET_OBJECTS:glog_internal>
)
target_include_directories (glogtest PUBLIC
$<TARGET_PROPERTY:glog,INCLUDE_DIRECTORIES>)
target_compile_definitions (glogtest PUBLIC
$<TARGET_PROPERTY:glog,COMPILE_DEFINITIONS> GLOG_STATIC_DEFINE)
target_link_libraries (glogtest PUBLIC
$<TARGET_PROPERTY:glog,LINK_LIBRARIES>)
set (_GLOG_TEST_LIBS glogtest)
if (HAVE_LIB_GTEST)
list (APPEND _GLOG_TEST_LIBS GTest::gtest)
endif (HAVE_LIB_GTEST)
if (HAVE_LIB_GMOCK)
list (APPEND _GLOG_TEST_LIBS GTest::gmock)
endif (HAVE_LIB_GMOCK)
add_executable (logging_unittest
src/logging_unittest.cc
)
target_link_libraries (logging_unittest PRIVATE ${_GLOG_TEST_LIBS})
add_executable (stl_logging_unittest
src/stl_logging_unittest.cc
)
target_link_libraries (stl_logging_unittest PRIVATE ${_GLOG_TEST_LIBS})
if (HAVE_NO_DEPRECATED)
set_property (TARGET stl_logging_unittest APPEND PROPERTY COMPILE_OPTIONS
-Wno-deprecated)
endif (HAVE_NO_DEPRECATED)
if (HAVE_EXT_SLIST)
target_compile_definitions (stl_logging_unittest PRIVATE
GLOG_STL_LOGGING_FOR_EXT_SLIST)
endif (HAVE_EXT_SLIST)
if (HAVE_SYMBOLIZE)
add_executable (symbolize_unittest
src/symbolize_unittest.cc
)
target_link_libraries (symbolize_unittest PRIVATE ${_GLOG_TEST_LIBS})
endif (HAVE_SYMBOLIZE)
add_executable (demangle_unittest
src/demangle_unittest.cc
)
target_link_libraries (demangle_unittest PRIVATE ${_GLOG_TEST_LIBS})
if (HAVE_STACKTRACE)
add_executable (stacktrace_unittest
src/stacktrace_unittest.cc
)
target_link_libraries (stacktrace_unittest PRIVATE ${_GLOG_TEST_LIBS})
endif (HAVE_STACKTRACE)
add_executable (utilities_unittest
src/utilities_unittest.cc
)
target_link_libraries (utilities_unittest PRIVATE ${_GLOG_TEST_LIBS})
if (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
add_executable (signalhandler_unittest
src/signalhandler_unittest.cc
)
target_link_libraries (signalhandler_unittest PRIVATE ${_GLOG_TEST_LIBS})
endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
add_test (NAME demangle COMMAND demangle_unittest)
add_test (NAME logging COMMAND logging_unittest)
set_tests_properties (logging PROPERTIES TIMEOUT 30)
# MacOS diff is not deterministic: use the output to determine whether the
# test passed.
set_tests_properties (logging PROPERTIES PASS_REGULAR_EXPRESSION ".*\nPASS\n.*")
# FIXME: Skip flaky test
set_tests_properties (logging PROPERTIES SKIP_REGULAR_EXPRESSION
"Check failed: time_ns within LogTimes::LOG_PERIOD_TOL_NS of LogTimes::LOG_PERIOD_NS")
if (APPLE)
# FIXME: Skip flaky test
set_property (TEST logging APPEND PROPERTY SKIP_REGULAR_EXPRESSION
"unexpected new.*PASS\nTest with golden file failed. We'll try to show the diff:")
endif (APPLE)
if (TARGET signalhandler_unittest)
add_test (NAME signalhandler COMMAND signalhandler_unittest)
endif (TARGET signalhandler_unittest)
if (TARGET stacktrace_unittest)
add_test (NAME stacktrace COMMAND stacktrace_unittest)
set_tests_properties (stacktrace PROPERTIES TIMEOUT 30)
endif (TARGET stacktrace_unittest)
add_test (NAME stl_logging COMMAND stl_logging_unittest)
if (TARGET symbolize_unittest)
add_test (NAME symbolize COMMAND symbolize_unittest)
# FIXME: Skip flaky test when compiled in C++20 mode
set_tests_properties (symbolize PROPERTIES SKIP_REGULAR_EXPRESSION
[=[Check failed: streq\("nonstatic_func"\, TrySymbolize\(\(void \*\)\(&nonstatic_func\)\)\)]=])
endif (TARGET symbolize_unittest)
if (HAVE_LIB_GMOCK)
add_executable (mock-log_unittest
src/mock-log_unittest.cc
src/mock-log.h
)
target_link_libraries (mock-log_unittest PRIVATE ${_GLOG_TEST_LIBS})
add_test (NAME mock-log COMMAND mock-log_unittest)
endif (HAVE_LIB_GMOCK)
# Generate an initial cache
get_cache_variables (_CACHEVARS)
set (_INITIAL_CACHE
${CMAKE_CURRENT_BINARY_DIR}/test_package_config/glog_package_config_initial_cache.cmake)
# Package config test
add_test (NAME cmake_package_config_init COMMAND ${CMAKE_COMMAND}
-DTEST_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/test_package_config
-DINITIAL_CACHE=${_INITIAL_CACHE}
-DCACHEVARS=${_CACHEVARS}
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestInitPackageConfig.cmake
)
add_test (NAME cmake_package_config_generate COMMAND ${CMAKE_COMMAND}
-DGENERATOR=${CMAKE_GENERATOR}
-DGENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
-DGENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
-DINITIAL_CACHE=${_INITIAL_CACHE}
-DPACKAGE_DIR=${CMAKE_CURRENT_BINARY_DIR}
-DPATH=$ENV{PATH}
-DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/src/package_config_unittest/working_config
-DTEST_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/test_package_config/working_config
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestPackageConfig.cmake
)
add_test (NAME cmake_package_config_build COMMAND
${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/test_package_config/working_config
--config $<CONFIG>
)
add_test (NAME cmake_package_config_cleanup COMMAND ${CMAKE_COMMAND} -E
remove_directory
${CMAKE_CURRENT_BINARY_DIR}/test_package_config
)
# Fixtures setup
set_tests_properties (cmake_package_config_init PROPERTIES FIXTURES_SETUP
cmake_package_config)
set_tests_properties (cmake_package_config_generate PROPERTIES FIXTURES_SETUP
cmake_package_config_working)
# Fixtures cleanup
set_tests_properties (cmake_package_config_cleanup PROPERTIES FIXTURES_CLEANUP
cmake_package_config)
# Fixture requirements
set_tests_properties (cmake_package_config_generate PROPERTIES
FIXTURES_REQUIRED cmake_package_config)
set_tests_properties (cmake_package_config_build PROPERTIES
FIXTURES_REQUIRED "cmake_package_config;cmake_package_config_working")
add_executable (cleanup_immediately_unittest
src/cleanup_immediately_unittest.cc)
target_link_libraries (cleanup_immediately_unittest PRIVATE ${_GLOG_TEST_LIBS})
add_executable (cleanup_with_absolute_prefix_unittest
src/cleanup_with_absolute_prefix_unittest.cc)
target_link_libraries (cleanup_with_absolute_prefix_unittest PRIVATE ${_GLOG_TEST_LIBS})
add_executable (cleanup_with_relative_prefix_unittest
src/cleanup_with_relative_prefix_unittest.cc)
target_link_libraries (cleanup_with_relative_prefix_unittest PRIVATE ${_GLOG_TEST_LIBS})
set (CLEANUP_LOG_DIR ${CMAKE_CURRENT_BINARY_DIR}/cleanup_tests)
add_test (NAME cleanup_init COMMAND
${CMAKE_COMMAND} -E make_directory ${CLEANUP_LOG_DIR})
add_test (NAME cleanup_logdir COMMAND
${CMAKE_COMMAND} -E remove_directory ${CLEANUP_LOG_DIR})
add_test (NAME cleanup_immediately COMMAND
${CMAKE_COMMAND}
-DLOGCLEANUP=$<TARGET_FILE:cleanup_immediately_unittest>
# NOTE The trailing slash is important
-DTEST_DIR=${CLEANUP_LOG_DIR}/
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RunCleanerTest1.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test (NAME cleanup_with_absolute_prefix COMMAND
${CMAKE_COMMAND}
-DLOGCLEANUP=$<TARGET_FILE:cleanup_with_absolute_prefix_unittest>
-DTEST_DIR=${CMAKE_CURRENT_BINARY_DIR}/
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RunCleanerTest2.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test (NAME cleanup_with_relative_prefix COMMAND
${CMAKE_COMMAND}
-DLOGCLEANUP=$<TARGET_FILE:cleanup_with_relative_prefix_unittest>
-DTEST_DIR=${CMAKE_CURRENT_BINARY_DIR}/
-DTEST_SUBDIR=test_subdir/
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RunCleanerTest3.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# Fixtures setup
set_tests_properties (cleanup_init PROPERTIES FIXTURES_SETUP logcleanuptest)
## Fixtures cleanup
set_tests_properties (cleanup_logdir PROPERTIES FIXTURES_CLEANUP logcleanuptest)
# Fixture requirements
set_tests_properties (cleanup_immediately PROPERTIES FIXTURES_REQUIRED logcleanuptest)
set_tests_properties (cleanup_with_absolute_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)
set_tests_properties (cleanup_with_relative_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)
endif (BUILD_TESTING)
install (TARGETS glog
EXPORT glog-targets
RUNTIME DESTINATION ${_glog_CMake_BINDIR}
PUBLIC_HEADER DESTINATION ${_glog_CMake_INCLUDE_DIR}/glog
LIBRARY DESTINATION ${_glog_CMake_LIBDIR}
ARCHIVE DESTINATION ${_glog_CMake_LIBDIR})
if (WITH_PKGCONFIG)
install (
FILES "${PROJECT_BINARY_DIR}/libglog.pc"
DESTINATION "${_glog_CMake_LIBDIR}/pkgconfig"
)
endif (WITH_PKGCONFIG)
set (glog_CMake_VERSION 3.0)
if (gflags_FOUND)
# Ensure clients locate only the package config and not third party find
# modules having the same name. This avoid cmake_policy PUSH/POP errors.
if (CMAKE_VERSION VERSION_LESS 3.9)
set (gflags_DEPENDENCY "find_dependency (gflags ${gflags_VERSION})")
else (CMAKE_VERSION VERSION_LESS 3.9)
# Passing additional find_package arguments to find_dependency is possible
# starting with CMake 3.9.
set (glog_CMake_VERSION 3.9)
set (gflags_DEPENDENCY "find_dependency (gflags ${gflags_VERSION} NO_MODULE)")
endif (CMAKE_VERSION VERSION_LESS 3.9)
endif (gflags_FOUND)
configure_package_config_file (glog-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/glog-config.cmake
INSTALL_DESTINATION ${_glog_CMake_INSTALLDIR}
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
write_basic_package_version_file (
${CMAKE_CURRENT_BINARY_DIR}/glog-config-version.cmake
COMPATIBILITY SameMajorVersion)
export (TARGETS glog NAMESPACE glog:: FILE glog-targets.cmake)
export (PACKAGE glog)
get_filename_component (_PREFIX "${CMAKE_INSTALL_PREFIX}" ABSOLUTE)
# Directory containing the find modules relative to the config install
# directory.
file (RELATIVE_PATH glog_REL_CMake_MODULES
${_PREFIX}/${_glog_CMake_INSTALLDIR}
${_PREFIX}/${_glog_CMake_DATADIR}/glog-modules.cmake)
get_filename_component (glog_REL_CMake_DATADIR ${glog_REL_CMake_MODULES}
DIRECTORY)
set (glog_FULL_CMake_DATADIR
${CMAKE_CURRENT_BINARY_DIR}/${_glog_CMake_DATADIR})
configure_file (glog-modules.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/glog-modules.cmake @ONLY)
install (CODE
"
set (glog_FULL_CMake_DATADIR \"\\\${CMAKE_CURRENT_LIST_DIR}/${glog_REL_CMake_DATADIR}\")
set (glog_DATADIR_DESTINATION ${_glog_CMake_INSTALLDIR})
if (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR})
set (glog_DATADIR_DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${glog_DATADIR_DESTINATION}\")
endif (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR})
configure_file (\"${CMAKE_CURRENT_SOURCE_DIR}/glog-modules.cmake.in\"
\"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\" @ONLY)
file (INSTALL
\"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\"
DESTINATION
\"\${glog_DATADIR_DESTINATION}\")
"
COMPONENT Development
)
install (FILES
${CMAKE_CURRENT_BINARY_DIR}/glog-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/glog-config-version.cmake
DESTINATION ${_glog_CMake_INSTALLDIR})
# Find modules in share/glog/cmake
install (DIRECTORY ${_glog_BINARY_CMake_DATADIR}
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/glog
COMPONENT Development
FILES_MATCHING PATTERN "*.cmake"
)
install (EXPORT glog-targets NAMESPACE glog:: DESTINATION
${_glog_CMake_INSTALLDIR})

View File

@@ -0,0 +1,69 @@
macro(determine_gflags_namespace VARIABLE)
if (NOT DEFINED "${VARIABLE}")
if (CMAKE_REQUIRED_INCLUDES)
set (CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS "-DINCLUDE_DIRECTORIES=${CMAKE_REQUIRED_INCLUDES}")
else ()
set (CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS)
endif ()
set(MACRO_CHECK_INCLUDE_FILE_FLAGS ${CMAKE_REQUIRED_FLAGS})
set(_NAMESPACES gflags google)
set(_check_code
"
#include <gflags/gflags.h>
int main(int argc, char**argv)
{
GLOG_GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
}
")
if (NOT CMAKE_REQUIRED_QUIET)
message (STATUS "Looking for gflags namespace")
endif ()
if (${ARGC} EQUAL 3)
set (CMAKE_CXX_FLAGS_SAVE ${CMAKE_CXX_FLAGS})
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARGV2}")
endif ()
set (_check_file
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/DetermineGflagsNamespace.cxx)
foreach (_namespace ${_NAMESPACES})
file (WRITE "${_check_file}" "${_check_code}")
try_compile (${VARIABLE}
"${CMAKE_BINARY_DIR}" "${_check_file}"
COMPILE_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}" -DGLOG_GFLAGS_NAMESPACE=${_namespace}
LINK_LIBRARIES gflags
CMAKE_FLAGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
OUTPUT_VARIABLE OUTPUT)
if (${VARIABLE})
set (${VARIABLE} ${_namespace} CACHE INTERNAL "gflags namespace" FORCE)
break ()
else ()
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining the gflags namespace ${_namespace} failed with the following output:\n"
"${OUTPUT}\n\n")
endif ()
endforeach (_namespace)
if (${ARGC} EQUAL 3)
set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS_SAVE})
endif ()
if (${VARIABLE})
if (NOT CMAKE_REQUIRED_QUIET)
message (STATUS "Looking for gflags namespace - ${${VARIABLE}}")
endif ()
file (APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Determining the gflags namespace passed with the following output:\n"
"${OUTPUT}\n\n")
else ()
if (NOT CMAKE_REQUIRED_QUIET)
message (STATUS "Looking for gflags namespace - failed")
endif ()
set (${VARIABLE} ${_namespace} CACHE INTERNAL "gflags namespace")
endif ()
endif ()
endmacro ()

View File

@@ -0,0 +1,61 @@
# - Try to find libunwind
# Once done this will define
#
# Unwind_FOUND - system has libunwind
# unwind::unwind - cmake target for libunwind
include (FindPackageHandleStandardArgs)
find_path (Unwind_INCLUDE_DIR NAMES unwind.h libunwind.h DOC "unwind include directory")
find_library (Unwind_LIBRARY NAMES unwind DOC "unwind library")
mark_as_advanced (Unwind_INCLUDE_DIR Unwind_LIBRARY)
# Extract version information
if (Unwind_LIBRARY)
set (_Unwind_VERSION_HEADER ${Unwind_INCLUDE_DIR}/libunwind-common.h)
if (EXISTS ${_Unwind_VERSION_HEADER})
file (READ ${_Unwind_VERSION_HEADER} _Unwind_VERSION_CONTENTS)
string (REGEX REPLACE ".*#define UNW_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1"
Unwind_VERSION_MAJOR "${_Unwind_VERSION_CONTENTS}")
string (REGEX REPLACE ".*#define UNW_VERSION_MINOR[ \t]+([0-9]+).*" "\\1"
Unwind_VERSION_MINOR "${_Unwind_VERSION_CONTENTS}")
string (REGEX REPLACE ".*#define UNW_VERSION_EXTRA[ \t]+([0-9]+).*" "\\1"
Unwind_VERSION_PATCH "${_Unwind_VERSION_CONTENTS}")
set (Unwind_VERSION ${Unwind_VERSION_MAJOR}.${Unwind_VERSION_MINOR})
if (CMAKE_MATCH_0)
# Third version component may be empty
set (Unwind_VERSION ${Unwind_VERSION}.${Unwind_VERSION_PATCH})
set (Unwind_VERSION_COMPONENTS 3)
else (CMAKE_MATCH_0)
set (Unwind_VERSION_COMPONENTS 2)
endif (CMAKE_MATCH_0)
endif (EXISTS ${_Unwind_VERSION_HEADER})
endif (Unwind_LIBRARY)
# handle the QUIETLY and REQUIRED arguments and set Unwind_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args (Unwind
REQUIRED_VARS Unwind_INCLUDE_DIR Unwind_LIBRARY
VERSION_VAR Unwind_VERSION
)
if (Unwind_FOUND)
if (NOT TARGET unwind::unwind)
add_library (unwind::unwind INTERFACE IMPORTED)
set_property (TARGET unwind::unwind PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${Unwind_INCLUDE_DIR}
)
set_property (TARGET unwind::unwind PROPERTY
INTERFACE_LINK_LIBRARIES ${Unwind_LIBRARY}
)
set_property (TARGET unwind::unwind PROPERTY
IMPORTED_CONFIGURATIONS RELEASE
)
endif (NOT TARGET unwind::unwind)
endif (Unwind_FOUND)

View File

@@ -0,0 +1,70 @@
cmake_policy (PUSH)
cmake_policy (VERSION 3.3)
include (CMakeParseArguments)
function (get_cache_variables _CACHEVARS)
set (_SINGLE)
set (_MULTI EXCLUDE)
set (_OPTIONS)
cmake_parse_arguments (_ARGS "${_OPTIONS}" "${_SINGLE}" "${_MULTI}" ${ARGS} ${ARGN})
get_cmake_property (_VARIABLES VARIABLES)
set (CACHEVARS)
foreach (_VAR ${_VARIABLES})
if (DEFINED _ARGS_EXCLUDE)
if ("${_VAR}" IN_LIST _ARGS_EXCLUDE)
continue ()
endif ("${_VAR}" IN_LIST _ARGS_EXCLUDE)
endif (DEFINED _ARGS_EXCLUDE)
get_property (_CACHEVARTYPE CACHE ${_VAR} PROPERTY TYPE)
if ("${_CACHEVARTYPE}" STREQUAL INTERNAL OR
"${_CACHEVARTYPE}" STREQUAL STATIC OR
"${_CACHEVARTYPE}" STREQUAL UNINITIALIZED)
continue ()
endif ("${_CACHEVARTYPE}" STREQUAL INTERNAL OR
"${_CACHEVARTYPE}" STREQUAL STATIC OR
"${_CACHEVARTYPE}" STREQUAL UNINITIALIZED)
get_property (_CACHEVARVAL CACHE ${_VAR} PROPERTY VALUE)
if ("${_CACHEVARVAL}" STREQUAL "")
continue ()
endif ("${_CACHEVARVAL}" STREQUAL "")
get_property (_CACHEVARDOC CACHE ${_VAR} PROPERTY HELPSTRING)
# Escape " in values
string (REPLACE "\"" "\\\"" _CACHEVARVAL "${_CACHEVARVAL}")
# Escape " in help strings
string (REPLACE "\"" "\\\"" _CACHEVARDOC "${_CACHEVARDOC}")
# Escape ; in values
string (REPLACE ";" "\\\;" _CACHEVARVAL "${_CACHEVARVAL}")
# Escape ; in help strings
string (REPLACE ";" "\\\;" _CACHEVARDOC "${_CACHEVARDOC}")
# Escape backslashes in values except those that are followed by a
# quote.
string (REGEX REPLACE "\\\\([^\"])" "\\\\\\1" _CACHEVARVAL "${_CACHEVARVAL}")
# Escape backslashes in values that are followed by a letter to avoid
# invalid escape sequence errors.
string (REGEX REPLACE "\\\\([a-zA-Z])" "\\\\\\\\1" _CACHEVARVAL "${_CACHEVARVAL}")
string (REPLACE "\\\\" "\\\\\\\\" _CACHEVARDOC "${_CACHEVARDOC}")
if (NOT "${_CACHEVARTYPE}" STREQUAL BOOL)
set (_CACHEVARVAL "\"${_CACHEVARVAL}\"")
endif (NOT "${_CACHEVARTYPE}" STREQUAL BOOL)
if (NOT "${_CACHEVARTYPE}" STREQUAL "" AND NOT "${_CACHEVARVAL}" STREQUAL "")
set (CACHEVARS "${CACHEVARS}set (${_VAR} ${_CACHEVARVAL} CACHE ${_CACHEVARTYPE} \"${_CACHEVARDOC}\")\n")
endif (NOT "${_CACHEVARTYPE}" STREQUAL "" AND NOT "${_CACHEVARVAL}" STREQUAL "")
endforeach (_VAR)
set (${_CACHEVARS} ${CACHEVARS} PARENT_SCOPE)
endfunction (get_cache_variables)
cmake_policy (POP)

View File

@@ -0,0 +1,22 @@
set (RUNS 3)
foreach (iter RANGE 1 ${RUNS})
set (ENV{GOOGLE_LOG_DIR} ${TEST_DIR})
execute_process (COMMAND ${LOGCLEANUP} RESULT_VARIABLE _RESULT)
if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
endif (NOT _RESULT EQUAL 0)
# Ensure the log files to have different modification timestamps such that
# exactly one log file remains at the end. Otherwise all log files will be
# retained.
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 1)
endforeach (iter)
file (GLOB LOG_FILES ${TEST_DIR}/*.foobar)
list (LENGTH LOG_FILES NUM_FILES)
if (NOT NUM_FILES EQUAL 1)
message (SEND_ERROR "Expected 1 log file in log directory but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL 1)

View File

@@ -0,0 +1,22 @@
set (RUNS 3)
foreach (iter RANGE 1 ${RUNS})
execute_process (COMMAND ${LOGCLEANUP} -log_dir=${TEST_DIR}
RESULT_VARIABLE _RESULT)
if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
endif (NOT _RESULT EQUAL 0)
# Ensure the log files to have different modification timestamps such that
# exactly one log file remains at the end. Otherwise all log files will be
# retained.
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 1)
endforeach (iter)
file (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo)
list (LENGTH LOG_FILES NUM_FILES)
if (NOT NUM_FILES EQUAL 1)
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR} but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL 1)

View File

@@ -0,0 +1,28 @@
set (RUNS 3)
# Create the subdirectory required by this unit test.
file (MAKE_DIRECTORY ${TEST_DIR}/${TEST_SUBDIR})
foreach (iter RANGE 1 ${RUNS})
execute_process (COMMAND ${LOGCLEANUP} -log_dir=${TEST_DIR}
RESULT_VARIABLE _RESULT)
if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
endif (NOT _RESULT EQUAL 0)
# Ensure the log files to have different modification timestamps such that
# exactly one log file remains at the end. Otherwise all log files will be
# retained.
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 2)
endforeach (iter)
file (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo)
list (LENGTH LOG_FILES NUM_FILES)
if (NOT NUM_FILES EQUAL 1)
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL 1)
# Remove the subdirectory required by this unit test.
file (REMOVE_RECURSE ${TEST_DIR}/${TEST_SUBDIR})

View File

@@ -0,0 +1,11 @@
# Create the build directory
execute_process (
COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_BINARY_DIR}
RESULT_VARIABLE _DIRECTORY_CREATED_SUCCEEDED
)
if (NOT _DIRECTORY_CREATED_SUCCEEDED EQUAL 0)
message (FATAL_ERROR "Failed to create build directory")
endif (NOT _DIRECTORY_CREATED_SUCCEEDED EQUAL 0)
file (WRITE ${INITIAL_CACHE} "${CACHEVARS}")

View File

@@ -0,0 +1,40 @@
# Create the build directory
execute_process (
COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_BINARY_DIR}
RESULT_VARIABLE _DIRECTORY_CREATED_SUCCEEDED
)
if (NOT _DIRECTORY_CREATED_SUCCEEDED EQUAL 0)
message (FATAL_ERROR "Failed to create build directory")
endif (NOT _DIRECTORY_CREATED_SUCCEEDED EQUAL 0)
if (GENERATOR_TOOLSET)
list (APPEND _ADDITIONAL_ARGS -T ${GENERATOR_TOOLSET})
endif (GENERATOR_TOOLSET)
if (GENERATOR_PLATFORM)
list (APPEND _ADDITIONAL_ARGS -A ${GENERATOR_PLATFORM})
endif (GENERATOR_PLATFORM)
# Run CMake
execute_process (
# Capture the PATH environment variable content set during project generation
# stage. This is required because later during the build stage the PATH is
# modified again (e.g., for MinGW AppVeyor CI builds) by adding back the
# directory containing git.exe. Incidently, the Git installation directory
# also contains sh.exe which causes MinGW Makefile generation to fail.
COMMAND ${CMAKE_COMMAND} -E env PATH=${PATH}
${CMAKE_COMMAND} -C ${INITIAL_CACHE}
-G ${GENERATOR}
${_ADDITIONAL_ARGS}
-DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON
-DCMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY=ON
-DCMAKE_PREFIX_PATH=${PACKAGE_DIR}
${SOURCE_DIR}
WORKING_DIRECTORY ${TEST_BINARY_DIR}
RESULT_VARIABLE _GENERATE_SUCCEEDED
)
if (NOT _GENERATE_SUCCEEDED EQUAL 0)
message (FATAL_ERROR "Failed to generate project files using CMake")
endif (NOT _GENERATE_SUCCEEDED EQUAL 0)

View File

@@ -0,0 +1,13 @@
if (CMAKE_VERSION VERSION_LESS @glog_CMake_VERSION@)
message (FATAL_ERROR "CMake >= @glog_CMake_VERSION@ required")
endif (CMAKE_VERSION VERSION_LESS @glog_CMake_VERSION@)
@PACKAGE_INIT@
include (CMakeFindDependencyMacro)
include (${CMAKE_CURRENT_LIST_DIR}/glog-modules.cmake)
@gflags_DEPENDENCY@
@Unwind_DEPENDENCY@
include (${CMAKE_CURRENT_LIST_DIR}/glog-targets.cmake)

View File

@@ -0,0 +1,18 @@
cmake_policy (PUSH)
cmake_policy (SET CMP0057 NEW)
if (CMAKE_VERSION VERSION_LESS 3.3)
message (FATAL_ERROR "glog-modules.cmake requires the consumer "
"to use CMake 3.3 (or newer)")
endif (CMAKE_VERSION VERSION_LESS 3.3)
set (glog_MODULE_PATH "@glog_FULL_CMake_DATADIR@")
list (APPEND CMAKE_MODULE_PATH ${glog_MODULE_PATH})
if (NOT glog_MODULE_PATH IN_LIST CMAKE_MODULE_PATH)
message (FATAL_ERROR "Cannot add '${glog_MODULE_PATH}' to "
"CMAKE_MODULE_PATH. This will cause glog-config.cmake to fail at "
"locating required find modules. Make sure CMAKE_MODULE_PATH is not a cache variable.")
endif (NOT glog_MODULE_PATH IN_LIST CMAKE_MODULE_PATH)
cmake_policy (POP)

View File

@@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libglog
Description: Google Log (glog) C++ logging framework
Version: @VERSION@
Libs: -L${libdir} -lglog
Libs.private: @glog_libraries_options_for_static_linking@
Cflags: -I${includedir}

View File

@@ -0,0 +1,148 @@
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
// ---
// This file is a compatibility layer that defines Google's version of
// command line flags that are used for configuration.
//
// We put flags into their own namespace. It is purposefully
// named in an opaque way that people should have trouble typing
// directly. The idea is that DEFINE puts the flag in the weird
// namespace, and DECLARE imports the flag from there into the
// current namespace. The net result is to force people to use
// DECLARE to get access to a flag, rather than saying
// extern bool FLAGS_logtostderr;
// or some such instead. We want this so we can put extra
// functionality (like sanity-checking) in DECLARE if we want,
// and make sure it is picked up everywhere.
//
// We also put the type of the variable in the namespace, so that
// people can't DECLARE_int32 something that they DEFINE_bool'd
// elsewhere.
#ifndef BASE_COMMANDLINEFLAGS_H__
#define BASE_COMMANDLINEFLAGS_H__
#include "config.h"
#include <cstdlib> // for getenv
#include <cstring> // for memchr
#include <string>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
#else
#include <glog/logging.h>
#define DECLARE_VARIABLE(type, shorttype, name, tn) \
namespace fL##shorttype { \
extern GLOG_EXPORT type FLAGS_##name; \
} \
using fL##shorttype::FLAGS_##name
#define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \
namespace fL##shorttype { \
GLOG_EXPORT type FLAGS_##name(value); \
char FLAGS_no##name; \
} \
using fL##shorttype::FLAGS_##name
// bool specialization
#define DECLARE_bool(name) \
DECLARE_VARIABLE(bool, B, name, bool)
#define DEFINE_bool(name, value, meaning) \
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
// int32 specialization
#define DECLARE_int32(name) \
DECLARE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, int32)
#define DEFINE_int32(name, value, meaning) \
DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, value, meaning, int32)
// uint32 specialization
#ifndef DECLARE_uint32
#define DECLARE_uint32(name) \
DECLARE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, uint32)
#endif // DECLARE_uint64
#define DEFINE_uint32(name, value, meaning) \
DEFINE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, value, meaning, uint32)
// Special case for string, because we have to specify the namespace
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
#define DECLARE_string(name) \
namespace fLS { \
extern GLOG_EXPORT std::string& FLAGS_##name; \
} \
using fLS::FLAGS_##name
#define DEFINE_string(name, value, meaning) \
namespace fLS { \
std::string FLAGS_##name##_buf(value); \
GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \
char FLAGS_no##name; \
} \
using fLS::FLAGS_##name
#endif // HAVE_LIB_GFLAGS
// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
// have GLOG_* environ variables even if we have gflags installed.
//
// If both an environment variable and a flag are specified, the value
// specified by a flag wins. E.g., if GLOG_v=0 and --v=1, the
// verbosity will be 1, not 0.
#define GLOG_DEFINE_bool(name, value, meaning) \
DEFINE_bool(name, EnvToBool("GLOG_" #name, value), meaning)
#define GLOG_DEFINE_int32(name, value, meaning) \
DEFINE_int32(name, EnvToInt("GLOG_" #name, value), meaning)
#define GLOG_DEFINE_uint32(name, value, meaning) \
DEFINE_uint32(name, EnvToUInt("GLOG_" #name, value), meaning)
#define GLOG_DEFINE_string(name, value, meaning) \
DEFINE_string(name, EnvToString("GLOG_" #name, value), meaning)
// These macros (could be functions, but I don't want to bother with a .cc
// file), make it easier to initialize flags from the environment.
#define EnvToString(envname, dflt) \
(!getenv(envname) ? (dflt) : getenv(envname))
#define EnvToBool(envname, dflt) \
(!getenv(envname) ? (dflt) \
: memchr("tTyY1\0", getenv(envname)[0], 6) != nullptr)
#define EnvToInt(envname, dflt) \
(!getenv(envname) ? (dflt) : strtol(getenv(envname), nullptr, 10))
#define EnvToUInt(envname, dflt) \
(!getenv(envname) ? (dflt) : strtoul(getenv(envname), nullptr, 10))
#endif // BASE_COMMANDLINEFLAGS_H__

View File

@@ -0,0 +1,51 @@
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
// ---
// Author: Jacob Hoffman-Andrews
#ifndef _GOOGLEINIT_H
#define _GOOGLEINIT_H
class GoogleInitializer {
public:
using void_function = void (*)();
GoogleInitializer(const char*, void_function f) {
f();
}
};
#define REGISTER_MODULE_INITIALIZER(name, body) \
namespace { \
static void google_init_module_##name () { body; } \
GoogleInitializer google_initializer_module_##name(#name, \
google_init_module_##name); \
}
#endif /* _GOOGLEINIT_H */

View File

@@ -0,0 +1,333 @@
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// ---
// Author: Craig Silverstein.
//
// A simple mutex wrapper, supporting locks and read-write locks.
// You should assume the locks are *not* re-entrant.
//
// To use: you should define the following macros in your configure.ac:
// ACX_PTHREAD
// AC_RWLOCK
// The latter is defined in ../autoconf.
//
// This class is meant to be internal-only and should be wrapped by an
// internal namespace. Before you use this module, please give the
// name of your internal namespace for this module. Or, if you want
// to expose it, you'll want to move it to the Google namespace. We
// cannot put this class in global namespace because there can be some
// problems when we have multiple versions of Mutex in each shared object.
//
// NOTE: by default, we have #ifdef'ed out the TryLock() method.
// This is for two reasons:
// 1) TryLock() under Windows is a bit annoying (it requires a
// #define to be defined very early).
// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
// mode.
// If you need TryLock(), and either these two caveats are not a
// problem for you, or you're willing to work around them, then
// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
// in the code below.
//
// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
// Because of that, we might as well use windows locks for
// cygwin. They seem to be more reliable than the cygwin pthreads layer.
//
// TRICKY IMPLEMENTATION NOTE:
// This class is designed to be safe to use during
// dynamic-initialization -- that is, by global constructors that are
// run before main() starts. The issue in this case is that
// dynamic-initialization happens in an unpredictable order, and it
// could be that someone else's dynamic initializer could call a
// function that tries to acquire this mutex -- but that all happens
// before this mutex's constructor has run. (This can happen even if
// the mutex and the function that uses the mutex are in the same .cc
// file.) Basically, because Mutex does non-trivial work in its
// constructor, it's not, in the naive implementation, safe to use
// before dynamic initialization has run on it.
//
// The solution used here is to pair the actual mutex primitive with a
// bool that is set to true when the mutex is dynamically initialized.
// (Before that it's false.) Then we modify all mutex routines to
// look at the bool, and not try to lock/unlock until the bool makes
// it to true (which happens after the Mutex constructor has run.)
//
// This works because before main() starts -- particularly, during
// dynamic initialization -- there are no threads, so a) it's ok that
// the mutex operations are a no-op, since we don't need locking then
// anyway; and b) we can be quite confident our bool won't change
// state between a call to Lock() and a call to Unlock() (that would
// require a global constructor in one translation unit to call Lock()
// and another global constructor in another translation unit to call
// Unlock() later, which is pretty perverse).
//
// That said, it's tricky, and can conceivably fail; it's safest to
// avoid trying to acquire a mutex in a global constructor, if you
// can. One way it can fail is that a really smart compiler might
// initialize the bool to true at static-initialization time (too
// early) rather than at dynamic-initialization time. To discourage
// that, we set is_safe_ to true in code (not the constructor
// colon-initializer) and set it to true via a function that always
// evaluates to true, but that the compiler can't know always
// evaluates to true. This should be good enough.
#ifndef GOOGLE_MUTEX_H_
#define GOOGLE_MUTEX_H_
#include "config.h" // to figure out pthreads support
#if defined(NO_THREADS)
typedef int MutexType; // to keep a lock-count
#elif defined(_WIN32) || defined(__CYGWIN__)
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN // We only need minimal includes
# endif
# ifdef GMUTEX_TRYLOCK
// We need Windows NT or later for TryEnterCriticalSection(). If you
// don't need that functionality, you can remove these _WIN32_WINNT
// lines, and change TryLock() to assert(0) or something.
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0400
# endif
# endif
// To avoid macro definition of ERROR.
# ifndef NOGDI
# define NOGDI
# endif
// To avoid macro definition of min/max.
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
typedef CRITICAL_SECTION MutexType;
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
// Needed for pthread_rwlock_*. If it causes problems, you could take it
// out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
// *does* cause problems for FreeBSD, or MacOSX, but isn't needed
// for locking there.)
# ifdef __linux__
# ifndef _XOPEN_SOURCE // Some other header might have already set it for us.
# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
# endif
# endif
# include <pthread.h>
using MutexType = pthread_rwlock_t;
#elif defined(HAVE_PTHREAD)
# include <pthread.h>
typedef pthread_mutex_t MutexType;
#else
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
#endif
// We need to include these header files after defining _XOPEN_SOURCE
// as they may define the _XOPEN_SOURCE macro.
#include <cassert>
#include <cstdlib> // for abort()
#define MUTEX_NAMESPACE glog_internal_namespace_
namespace MUTEX_NAMESPACE {
class Mutex {
public:
// Create a Mutex that is not held by anybody. This constructor is
// typically used for Mutexes allocated on the heap or the stack.
// See below for a recommendation for constructing global Mutex
// objects.
inline Mutex();
// Destructor
inline ~Mutex();
inline void Lock(); // Block if needed until free then acquire exclusively
inline void Unlock(); // Release a lock acquired via Lock()
#ifdef GMUTEX_TRYLOCK
inline bool TryLock(); // If free, Lock() and return true, else return false
#endif
// Note that on systems that don't support read-write locks, these may
// be implemented as synonyms to Lock() and Unlock(). So you can use
// these for efficiency, but don't use them anyplace where being able
// to do shared reads is necessary to avoid deadlock.
inline void ReaderLock(); // Block until free or shared then acquire a share
inline void ReaderUnlock(); // Release a read share of this Mutex
inline void WriterLock() { Lock(); } // Acquire an exclusive lock
inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
// TODO(hamaji): Do nothing, implement correctly.
inline void AssertHeld() {}
private:
MutexType mutex_;
// We want to make sure that the compiler sets is_safe_ to true only
// when we tell it to, and never makes assumptions is_safe_ is
// always true. volatile is the most reliable way to do that.
volatile bool is_safe_;
inline void SetIsSafe() { is_safe_ = true; }
// Catch the error of writing Mutex when intending MutexLock.
explicit Mutex(Mutex * /*ignored*/) {}
// Disallow "evil" constructors
Mutex(const Mutex &) = delete;
void operator=(const Mutex &) = delete;
};
// Now the implementation of Mutex for various systems
#if defined(NO_THREADS)
// When we don't have threads, we can be either reading or writing,
// but not both. We can have lots of readers at once (in no-threads
// mode, that's most likely to happen in recursive function calls),
// but only one writer. We represent this by having mutex_ be -1 when
// writing and a number > 0 when reading (and 0 when no lock is held).
//
// In debug mode, we assert these invariants, while in non-debug mode
// we do nothing, for efficiency. That's why everything is in an
// assert.
Mutex::Mutex() : mutex_(0) { }
Mutex::~Mutex() { assert(mutex_ == 0); }
void Mutex::Lock() { assert(--mutex_ == -1); }
void Mutex::Unlock() { assert(mutex_++ == -1); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
#endif
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
#elif defined(_WIN32) || defined(__CYGWIN__)
Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
TryEnterCriticalSection(&mutex_) != 0 : true; }
#endif
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
void Mutex::ReaderUnlock() { Unlock(); }
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
SetIsSafe();
if (is_safe_ && pthread_rwlock_init(&mutex_, nullptr) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
pthread_rwlock_trywrlock(&mutex_) == 0 :
true; }
#endif
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#undef SAFE_PTHREAD
#elif defined(HAVE_PTHREAD)
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
SetIsSafe();
if (is_safe_ && pthread_mutex_init(&mutex_, nullptr) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
pthread_mutex_trylock(&mutex_) == 0 : true; }
#endif
void Mutex::ReaderLock() { Lock(); }
void Mutex::ReaderUnlock() { Unlock(); }
#undef SAFE_PTHREAD
#endif
// --------------------------------------------------------------------------
// Some helper classes
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
class MutexLock {
public:
explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
~MutexLock() { mu_->Unlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
MutexLock(const MutexLock &) = delete;
void operator=(const MutexLock &) = delete;
};
// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
class ReaderMutexLock {
public:
explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
~ReaderMutexLock() { mu_->ReaderUnlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
ReaderMutexLock(const ReaderMutexLock &) = delete;
void operator=(const ReaderMutexLock &) = delete;
};
class WriterMutexLock {
public:
explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
~WriterMutexLock() { mu_->WriterUnlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
WriterMutexLock(const WriterMutexLock &) = delete;
void operator=(const WriterMutexLock &) = delete;
};
// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
} // namespace MUTEX_NAMESPACE
using namespace MUTEX_NAMESPACE;
#undef MUTEX_NAMESPACE
#endif /* #define GOOGLE_MUTEX_H__ */

View File

@@ -0,0 +1,177 @@
#ifndef GLOG_CONFIG_H
#define GLOG_CONFIG_H
/* Namespace for Google classes */
#cmakedefine GOOGLE_NAMESPACE ${GOOGLE_NAMESPACE}
/* Define if you have the `dladdr' function */
#cmakedefine HAVE_DLADDR
/* Define if you have the `snprintf' function */
#cmakedefine HAVE_SNPRINTF
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H
/* Define if you have the `backtrace' function in <execinfo.h> */
#cmakedefine HAVE_EXECINFO_BACKTRACE
/* Define if you have the `backtrace_symbols' function in <execinfo.h> */
#cmakedefine HAVE_EXECINFO_BACKTRACE_SYMBOLS
/* Define if you have the `fcntl' function */
#cmakedefine HAVE_FCNTL
/* Define to 1 if you have the <glob.h> header file. */
#cmakedefine HAVE_GLOB_H
/* Define to 1 if you have the `pthread' library (-lpthread). */
#cmakedefine HAVE_LIBPTHREAD
/* define if you have google gflags library */
#cmakedefine HAVE_LIB_GFLAGS
/* define if you have google gmock library */
#cmakedefine HAVE_LIB_GMOCK
/* define if you have google gtest library */
#cmakedefine HAVE_LIB_GTEST
/* define if you have dbghelp library */
#cmakedefine HAVE_DBGHELP
/* define if you have libunwind */
#cmakedefine HAVE_LIB_UNWIND
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H
/* define to disable multithreading support. */
#cmakedefine NO_THREADS
/* Define if you have the 'pread' function */
#cmakedefine HAVE_PREAD
/* Define if you have POSIX threads libraries and header files. */
#cmakedefine HAVE_PTHREAD
/* Define to 1 if you have the <pwd.h> header file. */
#cmakedefine HAVE_PWD_H
/* Define if you have the 'pwrite' function */
#cmakedefine HAVE_PWRITE
/* define if the compiler implements pthread_rwlock_* */
#cmakedefine HAVE_RWLOCK
/* Define if you have the 'sigaction' function */
#cmakedefine HAVE_SIGACTION
/* Define if you have the `sigaltstack' function */
#cmakedefine HAVE_SIGALTSTACK
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine HAVE_STRINGS_H
/* Define to 1 if you have the <syscall.h> header file. */
#cmakedefine HAVE_SYSCALL_H
/* Define to 1 if you have the <syslog.h> header file. */
#cmakedefine HAVE_SYSLOG_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/syscall.h> header file. */
#cmakedefine HAVE_SYS_SYSCALL_H
/* Define to 1 if you have the <sys/time.h> header file. */
#cmakedefine HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
/* Define to 1 if you have the <sys/ucontext.h> header file. */
#cmakedefine HAVE_SYS_UCONTEXT_H
/* Define to 1 if you have the <sys/utsname.h> header file. */
#cmakedefine HAVE_SYS_UTSNAME_H
/* Define to 1 if you have the <sys/wait.h> header file. */
#cmakedefine HAVE_SYS_WAIT_H
/* Define to 1 if you have the <ucontext.h> header file. */
#cmakedefine HAVE_UCONTEXT_H
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
/* Define if you linking to _Unwind_Backtrace is possible. */
#cmakedefine HAVE__UNWIND_BACKTRACE
/* Define if you linking to _Unwind_GetIP is possible. */
#cmakedefine HAVE__UNWIND_GETIP
/* define if your compiler has __attribute__ */
#cmakedefine HAVE___ATTRIBUTE__
/* define if your compiler has __builtin_expect */
#cmakedefine HAVE___BUILTIN_EXPECT ${HAVE___BUILTIN_EXPECT}
/* define if your compiler has __sync_val_compare_and_swap */
#cmakedefine HAVE___SYNC_VAL_COMPARE_AND_SWAP
/* define if symbolize support is available */
#cmakedefine HAVE_SYMBOLIZE
/* define if localtime_r is available in time.h */
#cmakedefine HAVE_LOCALTIME_R
/* define if gmtime_r is available in time.h */
#cmakedefine HAVE_GMTIME_R
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#cmakedefine LT_OBJDIR
/* How to access the PC from a struct ucontext */
#cmakedefine PC_FROM_UCONTEXT
/* define if we should print file offsets in traces instead of symbolizing. */
#cmakedefine PRINT_UNSYMBOLIZED_STACK_TRACES
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#cmakedefine PTHREAD_CREATE_JOINABLE
/* The size of `void *', as computed by sizeof. */
#cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P}
/* location of source code */
#cmakedefine TEST_SRC_DIR ${TEST_SRC_DIR}
/* Define if thread-local storage is enabled. */
#cmakedefine GLOG_THREAD_LOCAL_STORAGE
#ifdef GLOG_BAZEL_BUILD
/* TODO(rodrigoq): remove this workaround once bazel#3979 is resolved:
* https://github.com/bazelbuild/bazel/issues/3979 */
#define _START_GOOGLE_NAMESPACE_ namespace GOOGLE_NAMESPACE {
#define _END_GOOGLE_NAMESPACE_ }
#else
/* Stops putting the code inside the Google namespace */
#cmakedefine _END_GOOGLE_NAMESPACE_ ${_END_GOOGLE_NAMESPACE_}
/* Puts following code inside the Google namespace */
#cmakedefine _START_GOOGLE_NAMESPACE_ ${_START_GOOGLE_NAMESPACE_}
#endif
/* Replacement for deprecated syscall(SYS_gettid) on macOS. */
#cmakedefine HAVE_PTHREAD_THREADID_NP ${HAVE_PTHREAD_THREADID_NP}
#endif // GLOG_CONFIG_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Author: Satoru Takabayashi
//
// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
// (aka G++ V3 ABI).
// The demangler is implemented to be used in async signal handlers to
// symbolize stack traces. We cannot use libstdc++'s
// abi::__cxa_demangle() in such signal handlers since it's not async
// signal safe (it uses malloc() internally).
//
// Note that this demangler doesn't support full demangling. More
// specifically, it doesn't print types of function parameters and
// types of template arguments. It just skips them. However, it's
// still very useful to extract basic information such as class,
// function, constructor, destructor, and operator names.
//
// See the implementation note in demangle.cc if you are interested.
//
// Example:
//
// | Mangled Name | The Demangler | abi::__cxa_demangle()
// |---------------|---------------|-----------------------
// | _Z1fv | f() | f()
// | _Z1fi | f() | f(int)
// | _Z3foo3bar | foo() | foo(bar)
// | _Z1fIiEvi | f<>() | void f<int>(int)
// | _ZN1N1fE | N::f | N::f
// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar()
// | _Zrm1XS_" | operator%() | operator%(X, X)
// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo()
// | _Z1fSs | f() | f(std::basic_string<char,
// | | | std::char_traits<char>,
// | | | std::allocator<char> >)
//
// See the unit test for more examples.
//
// Note: we might want to write demanglers for ABIs other than Itanium
// C++ ABI in the future.
//
#ifndef BASE_DEMANGLE_H_
#define BASE_DEMANGLE_H_
#include "config.h"
#include <glog/logging.h>
_START_GOOGLE_NAMESPACE_
// Demangle "mangled". On success, return true and write the
// demangled symbol name to "out". Otherwise, return false.
// "out" is modified even if demangling is unsuccessful.
bool GLOG_EXPORT Demangle(const char *mangled, char *out, size_t out_size);
_END_GOOGLE_NAMESPACE_
#endif // BASE_DEMANGLE_H_

View File

@@ -0,0 +1,32 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
#include <cstring>
#include "demangle.h"
extern "C" int LLVMFuzzerTestOneInput(const unsigned char *Data,
unsigned Size) {
if (Size >= 4095) {
return 0;
}
char Buffer[Size + 1];
std::memcpy(Buffer, Data, Size);
Buffer[Size] = 0;
char demangled[4096];
google::Demangle(Buffer, demangled, Size);
return 0;
}

View File

@@ -0,0 +1,98 @@
// Copyright (c) 2023, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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 BASE_LOG_SEVERITY_H__
#define BASE_LOG_SEVERITY_H__
// The recommended semantics of the log levels are as follows:
//
// INFO:
// Use for state changes or other major events, or to aid debugging.
// WARNING:
// Use for undesired but relatively expected events, which may indicate a
// problem
// ERROR:
// Use for undesired and unexpected events that the program can recover from.
// All ERRORs should be actionable - it should be appropriate to file a bug
// whenever an ERROR occurs in production.
// FATAL:
// Use for undesired and unexpected events that the program cannot recover
// from.
// Variables of type LogSeverity are widely taken to lie in the range
// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
// you ever need to change their values or add a new severity.
using LogSeverity = int;
const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3,
NUM_SEVERITIES = 4;
#ifndef GLOG_NO_ABBREVIATED_SEVERITIES
# ifdef ERROR
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
# endif
const int INFO = GLOG_INFO, WARNING = GLOG_WARNING,
ERROR = GLOG_ERROR, FATAL = GLOG_FATAL;
#endif
// DFATAL is FATAL in debug mode, ERROR in normal mode
#ifdef NDEBUG
#define DFATAL_LEVEL ERROR
#else
#define DFATAL_LEVEL FATAL
#endif
extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
// NDEBUG usage helpers related to (RAW_)DCHECK:
//
// DEBUG_MODE is for small !NDEBUG uses like
// if (DEBUG_MODE) foo.CheckThatFoo();
// instead of substantially more verbose
// #ifndef NDEBUG
// foo.CheckThatFoo();
// #endif
//
// IF_DEBUG_MODE is for small !NDEBUG uses like
// IF_DEBUG_MODE( string error; )
// DCHECK(Foo(&error)) << error;
// instead of substantially more verbose
// #ifndef NDEBUG
// string error;
// DCHECK(Foo(&error)) << error;
// #endif
//
#ifdef NDEBUG
enum { DEBUG_MODE = 0 };
#define IF_DEBUG_MODE(x)
#else
enum { DEBUG_MODE = 1 };
#define IF_DEBUG_MODE(x) x
#endif
#endif // BASE_LOG_SEVERITY_H__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Author: Shinichiro Hamaji
//
// Detect supported platforms.
#ifndef GLOG_PLATFORM_H
#define GLOG_PLATFORM_H
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#define GLOG_OS_WINDOWS
#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
#define GLOG_OS_CYGWIN
#elif defined(linux) || defined(__linux) || defined(__linux__)
#ifndef GLOG_OS_LINUX
#define GLOG_OS_LINUX
#endif
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
#define GLOG_OS_MACOSX
#elif defined(__FreeBSD__)
#define GLOG_OS_FREEBSD
#elif defined(__NetBSD__)
#define GLOG_OS_NETBSD
#elif defined(__OpenBSD__)
#define GLOG_OS_OPENBSD
#elif defined(__EMSCRIPTEN__)
#define GLOG_OS_EMSCRIPTEN
#else
// TODO(hamaji): Add other platforms.
#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github.
#endif
#endif // GLOG_PLATFORM_H

View File

@@ -0,0 +1,179 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Author: Maxim Lifantsev
//
// Thread-safe logging routines that do not allocate any memory or
// acquire any locks, and can therefore be used by low-level memory
// allocation and synchronization code.
#ifndef GLOG_RAW_LOGGING_H
#define GLOG_RAW_LOGGING_H
#include <ctime>
@ac_google_start_namespace@
#include <glog/log_severity.h>
#include <glog/logging.h>
#include <glog/vlog_is_on.h>
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wvariadic-macros"
#endif
// This is similar to LOG(severity) << format... and VLOG(level) << format..,
// but
// * it is to be used ONLY by low-level modules that can't use normal LOG()
// * it is desiged to be a low-level logger that does not allocate any
// memory and does not need any locks, hence:
// * it logs straight and ONLY to STDERR w/o buffering
// * it uses an explicit format and arguments list
// * it will silently chop off really long message strings
// Usage example:
// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
// RAW_VLOG(3, "status is %i", status);
// These will print an almost standard log lines like this to stderr only:
// E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
// I20200821 211317 file.cc:142] RAW: status is 20
#define RAW_LOG(severity, ...) \
do { \
switch (@ac_google_namespace@::GLOG_ ## severity) { \
case 0: \
RAW_LOG_INFO(__VA_ARGS__); \
break; \
case 1: \
RAW_LOG_WARNING(__VA_ARGS__); \
break; \
case 2: \
RAW_LOG_ERROR(__VA_ARGS__); \
break; \
case 3: \
RAW_LOG_FATAL(__VA_ARGS__); \
break; \
default: \
break; \
} \
} while (0)
// The following STRIP_LOG testing is performed in the header file so that it's
// possible to completely compile out the logging code and the log messages.
#if !defined(STRIP_LOG) || STRIP_LOG == 0
#define RAW_VLOG(verboselevel, ...) \
do { \
if (VLOG_IS_ON(verboselevel)) { \
RAW_LOG_INFO(__VA_ARGS__); \
} \
} while (0)
#else
#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0
#if !defined(STRIP_LOG) || STRIP_LOG == 0
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_INFO, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0
#if !defined(STRIP_LOG) || STRIP_LOG <= 1
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_WARNING, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 1
#if !defined(STRIP_LOG) || STRIP_LOG <= 2
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_ERROR, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 2
#if !defined(STRIP_LOG) || STRIP_LOG <= 3
#define RAW_LOG_FATAL(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_FATAL, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_FATAL(...) \
do { \
@ac_google_namespace@::RawLogStub__(0, __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
#endif // STRIP_LOG <= 3
// Similar to CHECK(condition) << message,
// but for low-level modules: we use only RAW_LOG that does not allocate memory.
// We do not want to provide args list here to encourage this usage:
// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
// so that the args are not computed when not needed.
#define RAW_CHECK(condition, message) \
do { \
if (!(condition)) { \
RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
} \
} while (0)
// Debug versions of RAW_LOG and RAW_CHECK
#ifndef NDEBUG
#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
#else // NDEBUG
#define RAW_DLOG(severity, ...) \
while (false) \
RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) \
while (false) \
RAW_CHECK(condition, message)
#endif // NDEBUG
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
// Stub log function used to work around for unused variable warnings when
// building with STRIP_LOG > 0.
static inline void RawLogStub__(int /* ignored */, ...) {
}
// Helper function to implement RAW_LOG and RAW_VLOG
// Logs format... at "severity" level, reporting it
// as called from file:line.
// This does not allocate memory or acquire locks.
GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...)
@ac_cv___attribute___printf_4_5@;
@ac_google_end_namespace@
#endif // GLOG_RAW_LOGGING_H

View File

@@ -0,0 +1,177 @@
// Copyright (c) 2003, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Stream output operators for STL containers; to be used for logging *only*.
// Inclusion of this file lets you do:
//
// list<string> x;
// LOG(INFO) << "data: " << x;
// vector<int> v1, v2;
// CHECK_EQ(v1, v2);
//
// If you want to use this header file with hash maps or slist, you
// need to define macros before including this file:
//
// - GLOG_STL_LOGGING_FOR_UNORDERED - <unordered_map> and <unordered_set>
// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - <tr1/unordered_(map|set)>
// - GLOG_STL_LOGGING_FOR_EXT_HASH - <ext/hash_(map|set)>
// - GLOG_STL_LOGGING_FOR_EXT_SLIST - <ext/slist>
//
#ifndef UTIL_GTL_STL_LOGGING_INL_H_
#define UTIL_GTL_STL_LOGGING_INL_H_
#include <deque>
#include <list>
#include <map>
#include <ostream>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
// Forward declare these two, and define them after all the container streams
// operators so that we can recurse from pair -> container -> container -> pair
// properly.
template<class First, class Second>
std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
@ac_google_start_namespace@
template<class Iter>
void PrintSequence(std::ostream& out, Iter begin, Iter end);
@ac_google_end_namespace@
#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \
template<class T1, class T2> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::deque)
OUTPUT_TWO_ARG_CONTAINER(std::list)
#undef OUTPUT_TWO_ARG_CONTAINER
#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER(
std::multiset)
#undef OUTPUT_THREE_ARG_CONTAINER
#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3, class T4> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER(
std::multimap) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set)
OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset)
#undef OUTPUT_FOUR_ARG_CONTAINER
#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3, class T4, class T5> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4, T5>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map)
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap)
#endif
#undef OUTPUT_FIVE_ARG_CONTAINER
template <class First, class Second>
inline std::ostream& operator<<(
std::ostream& out,
const std::pair<First, Second>& p) {
out << '(' << p.first << ", " << p.second << ')';
return out;
}
@ac_google_start_namespace@
template<class Iter>
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
// Output at most 100 elements -- appropriate if used for logging.
for (int i = 0; begin != end && i < 100; ++i, ++begin) {
if (i > 0) out << ' ';
out << *begin;
}
if (begin != end) {
out << " ...";
}
}
@ac_google_end_namespace@
// Note that this is technically undefined behavior! We are adding things into
// the std namespace for a reason though -- we are providing new operations on
// types which are themselves defined with this namespace. Without this, these
// operator overloads cannot be found via ADL. If these definitions are not
// found via ADL, they must be #included before they're used, which requires
// this header to be included before apparently independent other headers.
//
// For example, base/logging.h defines various template functions to implement
// CHECK_EQ(x, y) and stream x and y into the log in the event the check fails.
// It does so via the function template MakeCheckOpValueString:
// template<class T>
// void MakeCheckOpValueString(strstream* ss, const T& v) {
// (*ss) << v;
// }
// Because 'glog/logging.h' is included before 'glog/stl_logging.h',
// subsequent CHECK_EQ(v1, v2) for vector<...> typed variable v1 and v2 can only
// find these operator definitions via ADL.
//
// Even this solution has problems -- it may pull unintended operators into the
// namespace as well, allowing them to also be found via ADL, and creating code
// that only works with a particular order of includes. Long term, we need to
// move all of the *definitions* into namespace std, bet we need to ensure no
// one references them first. This lets us take that step. We cannot define them
// in both because that would create ambiguous overloads when both are found.
namespace std { using ::operator<<; }
#endif // UTIL_GTL_STL_LOGGING_INL_H_

View File

@@ -0,0 +1,120 @@
// Copyright (c) 2023, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Author: Ray Sidney and many others
//
// Defines the VLOG_IS_ON macro that controls the variable-verbosity
// conditional logging.
//
// It's used by VLOG and VLOG_IF in logging.h
// and by RAW_VLOG in raw_logging.h to trigger the logging.
//
// It can also be used directly e.g. like this:
// if (VLOG_IS_ON(2)) {
// // do some logging preparation and logging
// // that can't be accomplished e.g. via just VLOG(2) << ...;
// }
//
// The truth value that VLOG_IS_ON(level) returns is determined by
// the three verbosity level flags:
// --v=<n> Gives the default maximal active V-logging level;
// 0 is the default.
// Normally positive values are used for V-logging levels.
// --vmodule=<str> Gives the per-module maximal V-logging levels to override
// the value given by --v.
// E.g. "my_module=2,foo*=3" would change the logging level
// for all code in source files "my_module.*" and "foo*.*"
// ("-inl" suffixes are also disregarded for this matching).
//
// SetVLOGLevel helper function is provided to do limited dynamic control over
// V-logging by overriding the per-module settings given via --vmodule flag.
//
// CAVEAT: --vmodule functionality is not available in non gcc compilers.
//
#ifndef BASE_VLOG_IS_ON_H_
#define BASE_VLOG_IS_ON_H_
#include <glog/log_severity.h>
#include <cstddef>
#if defined(__GNUC__)
// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
// (Normally) the first time every VLOG_IS_ON(n) site is hit,
// we determine what variable will dynamically control logging at this site:
// it's either FLAGS_v or an appropriate internal variable
// matching the current source file that represents results of
// parsing of --vmodule flag and/or SetVLOGLevel calls.
#define VLOG_IS_ON(verboselevel) \
__extension__ \
({ static @ac_google_namespace@::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \
@ac_google_namespace@::int32 verbose_level__ = (verboselevel); \
(vlocal__.level == NULL ? @ac_google_namespace@::InitVLOG3__(&vlocal__, &FLAGS_v, \
__FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \
})
#else
// GNU extensions not available, so we do not support --vmodule.
// Dynamic value of FLAGS_v always controls the logging level.
#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
#endif
// Set VLOG(_IS_ON) level for module_pattern to log_level.
// This lets us dynamically control what is normally set by the --vmodule flag.
// Returns the level that previously applied to module_pattern.
// NOTE: To change the log level for VLOG(_IS_ON) sites
// that have already executed after/during InitGoogleLogging,
// one needs to supply the exact --vmodule pattern that applied to them.
// (If no --vmodule pattern applied to them
// the value of FLAGS_v will continue to control them.)
extern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level);
// Various declarations needed for VLOG_IS_ON above: =========================
struct SiteFlag {
@ac_google_namespace@::int32* level;
const char* base_name;
std::size_t base_len;
SiteFlag* next;
};
// Helper routine which determines the logging info for a particalur VLOG site.
// site_flag is the address of the site-local pointer to the controlling
// verbosity level
// site_default is the default to use for *site_flag
// fname is the current source file name
// verbose_level is the argument to VLOG_IS_ON
// We will return the return value for VLOG_IS_ON
// and if possible set *site_flag appropriately.
extern GLOG_EXPORT bool InitVLOG3__(
@ac_google_namespace@::SiteFlag* site_flag,
@ac_google_namespace@::int32* site_default, const char* fname,
@ac_google_namespace@::int32 verbose_level);
#endif // BASE_VLOG_IS_ON_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,155 @@
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Author: Zhanyong Wan
//
// Defines the ScopedMockLog class (using Google C++ Mocking
// Framework), which is convenient for testing code that uses LOG().
#ifndef GLOG_SRC_MOCK_LOG_H_
#define GLOG_SRC_MOCK_LOG_H_
// For GOOGLE_NAMESPACE. This must go first so we get _XOPEN_SOURCE.
#include "utilities.h"
#include <string>
#include <gmock/gmock.h>
#include <glog/logging.h>
_START_GOOGLE_NAMESPACE_
namespace glog_testing {
// A ScopedMockLog object intercepts LOG() messages issued during its
// lifespan. Using this together with Google C++ Mocking Framework,
// it's very easy to test how a piece of code calls LOG(). The
// typical usage:
//
// TEST(FooTest, LogsCorrectly) {
// ScopedMockLog log;
//
// // We expect the WARNING "Something bad!" exactly twice.
// EXPECT_CALL(log, Log(WARNING, _, "Something bad!"))
// .Times(2);
//
// // We allow foo.cc to call LOG(INFO) any number of times.
// EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _))
// .Times(AnyNumber());
//
// Foo(); // Exercises the code under test.
// }
class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
public:
// When a ScopedMockLog object is constructed, it starts to
// intercept logs.
ScopedMockLog() { AddLogSink(this); }
// When the object is destructed, it stops intercepting logs.
~ScopedMockLog() override { RemoveLogSink(this); }
// Implements the mock method:
//
// void Log(LogSeverity severity, const string& file_path,
// const string& message);
//
// The second argument to Send() is the full path of the source file
// in which the LOG() was issued.
//
// Note, that in a multi-threaded environment, all LOG() messages from a
// single thread will be handled in sequence, but that cannot be guaranteed
// for messages from different threads. In fact, if the same or multiple
// expectations are matched on two threads concurrently, their actions will
// be executed concurrently as well and may interleave.
MOCK_METHOD3(Log, void(GOOGLE_NAMESPACE::LogSeverity severity,
const std::string& file_path,
const std::string& message));
private:
// Implements the send() virtual function in class LogSink.
// Whenever a LOG() statement is executed, this function will be
// invoked with information presented in the LOG().
//
// The method argument list is long and carries much information a
// test usually doesn't care about, so we trim the list before
// forwarding the call to Log(), which is much easier to use in
// tests.
//
// We still cannot call Log() directly, as it may invoke other LOG()
// messages, either due to Invoke, or due to an error logged in
// Google C++ Mocking Framework code, which would trigger a deadlock
// since a lock is held during send().
//
// Hence, we save the message for WaitTillSent() which will be called after
// the lock on send() is released, and we'll call Log() inside
// WaitTillSent(). Since while a single send() call may be running at a
// time, multiple WaitTillSent() calls (along with the one send() call) may
// be running simultaneously, we ensure thread-safety of the exchange between
// send() and WaitTillSent(), and that for each message, LOG(), send(),
// WaitTillSent() and Log() are executed in the same thread.
void send(GOOGLE_NAMESPACE::LogSeverity severity, const char* full_filename,
const char* /*base_filename*/, int /*line*/,
const LogMessageTime& /*logmsgtime*/, const char* message,
size_t message_len) override {
// We are only interested in the log severity, full file name, and
// log message.
message_info_.severity = severity;
message_info_.file_path = full_filename;
message_info_.message = std::string(message, message_len);
}
// Implements the WaitTillSent() virtual function in class LogSink.
// It will be executed after send() and after the global logging lock is
// released, so calls within it (or rather within the Log() method called
// within) may also issue LOG() statements.
//
// LOG(), send(), WaitTillSent() and Log() will occur in the same thread for
// a given log message.
void WaitTillSent() override {
// First, and very importantly, we save a copy of the message being
// processed before calling Log(), since Log() may indirectly call send()
// and WaitTillSent() in the same thread again.
MessageInfo message_info = message_info_;
Log(message_info.severity, message_info.file_path, message_info.message);
}
// All relevant information about a logged message that needs to be passed
// from send() to WaitTillSent().
struct MessageInfo {
GOOGLE_NAMESPACE::LogSeverity severity;
std::string file_path;
std::string message;
};
MessageInfo message_info_;
};
} // namespace glog_testing
_END_GOOGLE_NAMESPACE_
#endif // GLOG_SRC_MOCK_LOG_H_

View File

@@ -0,0 +1,179 @@
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Author: Maxim Lifantsev
//
// logging_unittest.cc covers the functionality herein
#include <cerrno>
#include <cstdarg>
#include <cstdio>
#include "utilities.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h> // for close() and write()
#endif
#include <fcntl.h> // for open()
#include <ctime>
#include "config.h"
#include <glog/logging.h> // To pick up flag settings etc.
#include <glog/raw_logging.h>
#include "base/commandlineflags.h"
#ifdef HAVE_STACKTRACE
# include "stacktrace.h"
#endif
#if defined(HAVE_SYSCALL_H)
#include <syscall.h> // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H)
#include <sys/syscall.h> // for syscall()
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && \
(!(defined(GLOG_OS_MACOSX))) && !defined(GLOG_OS_EMSCRIPTEN)
#define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
#else
// Not so safe, but what can you do?
#define safe_write(fd, s, len) write(fd, s, len)
#endif
_START_GOOGLE_NAMESPACE_
#if defined(__GNUC__)
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
__attribute__((format(archetype, stringIndex, firstToCheck)))
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) \
__attribute__((format_arg(stringIndex)))
#else
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
#endif
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// that invoke malloc() and getenv() that might acquire some locks.
// If this becomes a problem we should reimplement a subset of vsnprintf
// that does not need locks and malloc.
// Helper for RawLog__ below.
// *DoRawLog writes to *buf of *size and move them past the written portion.
// It returns true iff there was no overflow or error.
GLOG_ATTRIBUTE_FORMAT(printf, 3, 4)
static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
va_list ap;
va_start(ap, format);
int n = vsnprintf(*buf, *size, format, ap);
va_end(ap);
if (n < 0 || static_cast<size_t>(n) > *size) return false;
*size -= static_cast<size_t>(n);
*buf += n;
return true;
}
// Helper for RawLog__ below.
inline static bool VADoRawLog(char** buf, size_t* size,
const char* format, va_list ap) {
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
int n = vsnprintf(*buf, *size, format, ap);
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
if (n < 0 || static_cast<size_t>(n) > *size) return false;
*size -= static_cast<size_t>(n);
*buf += n;
return true;
}
static const int kLogBufSize = 3000;
static bool crashed = false;
static CrashReason crash_reason;
static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0'
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...) {
if (!(FLAGS_logtostdout || FLAGS_logtostderr ||
severity >= FLAGS_stderrthreshold || FLAGS_alsologtostderr ||
!IsGoogleLoggingInitialized())) {
return; // this stderr log message is suppressed
}
// can't call localtime_r here: it can allocate
char buffer[kLogBufSize];
char* buf = buffer;
size_t size = sizeof(buffer);
// NOTE: this format should match the specification in base/logging.h
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
LogSeverityNames[severity][0],
static_cast<unsigned int>(GetTID()),
const_basename(const_cast<char *>(file)), line);
// Record the position and size of the buffer after the prefix
const char* msg_start = buf;
const size_t msg_size = size;
va_list ap;
va_start(ap, format);
bool no_chop = VADoRawLog(&buf, &size, format, ap);
va_end(ap);
if (no_chop) {
DoRawLog(&buf, &size, "\n");
} else {
DoRawLog(&buf, &size, "RAW_LOG ERROR: The Message was too long!\n");
}
// We make a raw syscall to write directly to the stderr file descriptor,
// avoiding FILE buffering (to avoid invoking malloc()), and bypassing
// libc (to side-step any libc interception).
// We write just once to avoid races with other invocations of RawLog__.
safe_write(STDERR_FILENO, buffer, strlen(buffer));
if (severity == GLOG_FATAL) {
if (!sync_val_compare_and_swap(&crashed, false, true)) {
crash_reason.filename = file;
crash_reason.line_number = line;
memcpy(crash_buf, msg_start, msg_size); // Don't include prefix
crash_reason.message = crash_buf;
#ifdef HAVE_STACKTRACE
crash_reason.depth =
GetStackTrace(crash_reason.stack, ARRAYSIZE(crash_reason.stack), 1);
#else
crash_reason.depth = 0;
#endif
SetCrashReason(&crash_reason);
}
LogMessage::Fail(); // abort()
}
}
_END_GOOGLE_NAMESPACE_

View File

@@ -0,0 +1,412 @@
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Author: Satoru Takabayashi
//
// Implementation of InstallFailureSignalHandler().
#include "utilities.h"
#include "stacktrace.h"
#include "symbolize.h"
#include <glog/logging.h>
#include <csignal>
#include <ctime>
#ifdef HAVE_UCONTEXT_H
# include <ucontext.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#include <algorithm>
_START_GOOGLE_NAMESPACE_
namespace {
// We'll install the failure signal handler for these signals. We could
// use strsignal() to get signal names, but we don't use it to avoid
// introducing yet another #ifdef complication.
//
// The list should be synced with the comment in signalhandler.h.
const struct {
int number;
const char *name;
} kFailureSignals[] = {
{ SIGSEGV, "SIGSEGV" },
{ SIGILL, "SIGILL" },
{ SIGFPE, "SIGFPE" },
{ SIGABRT, "SIGABRT" },
#if !defined(GLOG_OS_WINDOWS)
{ SIGBUS, "SIGBUS" },
#endif
{ SIGTERM, "SIGTERM" },
};
static bool kFailureSignalHandlerInstalled = false;
#if !defined(GLOG_OS_WINDOWS)
// Returns the program counter from signal context, nullptr if unknown.
void* GetPC(void* ucontext_in_void) {
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
if (ucontext_in_void != nullptr) {
ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
return (void*)context->PC_FROM_UCONTEXT;
}
#else
(void)ucontext_in_void;
#endif
return nullptr;
}
#endif
// The class is used for formatting error messages. We don't use printf()
// as it's not async signal safe.
class MinimalFormatter {
public:
MinimalFormatter(char *buffer, size_t size)
: buffer_(buffer),
cursor_(buffer),
end_(buffer + size) {
}
// Returns the number of bytes written in the buffer.
std::size_t num_bytes_written() const { return static_cast<std::size_t>(cursor_ - buffer_); }
// Appends string from "str" and updates the internal cursor.
void AppendString(const char* str) {
ptrdiff_t i = 0;
while (str[i] != '\0' && cursor_ + i < end_) {
cursor_[i] = str[i];
++i;
}
cursor_ += i;
}
// Formats "number" in "radix" and updates the internal cursor.
// Lowercase letters are used for 'a' - 'z'.
void AppendUint64(uint64 number, unsigned radix) {
unsigned i = 0;
while (cursor_ + i < end_) {
const uint64 tmp = number % radix;
number /= radix;
cursor_[i] = static_cast<char>(tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
++i;
if (number == 0) {
break;
}
}
// Reverse the bytes written.
std::reverse(cursor_, cursor_ + i);
cursor_ += i;
}
// Formats "number" as hexadecimal number, and updates the internal
// cursor. Padding will be added in front if needed.
void AppendHexWithPadding(uint64 number, int width) {
char* start = cursor_;
AppendString("0x");
AppendUint64(number, 16);
// Move to right and add padding in front if needed.
if (cursor_ < start + width) {
const int64 delta = start + width - cursor_;
std::copy(start, cursor_, start + delta);
std::fill(start, start + delta, ' ');
cursor_ = start + width;
}
}
private:
char *buffer_;
char *cursor_;
const char * const end_;
};
// Writes the given data with the size to the standard error.
void WriteToStderr(const char* data, size_t size) {
if (write(STDERR_FILENO, data, size) < 0) {
// Ignore errors.
}
}
// The writer function can be changed by InstallFailureWriter().
void (*g_failure_writer)(const char* data, size_t size) = WriteToStderr;
// Dumps time information. We don't dump human-readable time information
// as localtime() is not guaranteed to be async signal safe.
void DumpTimeInfo() {
time_t time_in_sec = time(nullptr);
char buf[256]; // Big enough for time info.
MinimalFormatter formatter(buf, sizeof(buf));
formatter.AppendString("*** Aborted at ");
formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);
formatter.AppendString(" (unix time)");
formatter.AppendString(" try \"date -d @");
formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);
formatter.AppendString("\" if you are using GNU date ***\n");
g_failure_writer(buf, formatter.num_bytes_written());
}
// TODO(hamaji): Use signal instead of sigaction?
#if defined(HAVE_STACKTRACE) && defined(HAVE_SIGACTION)
// Dumps information about the signal to STDERR.
void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
// Get the signal name.
const char* signal_name = nullptr;
for (auto kFailureSignal : kFailureSignals) {
if (signal_number == kFailureSignal.number) {
signal_name = kFailureSignal.name;
}
}
char buf[256]; // Big enough for signal info.
MinimalFormatter formatter(buf, sizeof(buf));
formatter.AppendString("*** ");
if (signal_name) {
formatter.AppendString(signal_name);
} else {
// Use the signal number if the name is unknown. The signal name
// should be known, but just in case.
formatter.AppendString("Signal ");
formatter.AppendUint64(static_cast<uint64>(signal_number), 10);
}
formatter.AppendString(" (@0x");
formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
formatter.AppendString(")");
formatter.AppendString(" received by PID ");
formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
formatter.AppendString(" (TID 0x");
// We assume pthread_t is an integral number or a pointer, rather
// than a complex struct. In some environments, pthread_self()
// returns an uint64 but in some other environments pthread_self()
// returns a pointer.
pthread_t id = pthread_self();
formatter.AppendUint64(
reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
formatter.AppendString(") ");
// Only linux has the PID of the signal sender in si_pid.
#ifdef GLOG_OS_LINUX
formatter.AppendString("from PID ");
formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
formatter.AppendString("; ");
#endif
formatter.AppendString("stack trace: ***\n");
g_failure_writer(buf, formatter.num_bytes_written());
}
#endif // HAVE_SIGACTION
// Dumps information about the stack frame to STDERR.
void DumpStackFrameInfo(const char* prefix, void* pc) {
// Get the symbol name.
const char *symbol = "(unknown)";
char symbolized[1024]; // Big enough for a sane symbol.
// Symbolizes the previous address of pc because pc may be in the
// next function.
if (Symbolize(reinterpret_cast<char *>(pc) - 1,
symbolized, sizeof(symbolized))) {
symbol = symbolized;
}
char buf[1024]; // Big enough for stack frame info.
MinimalFormatter formatter(buf, sizeof(buf));
formatter.AppendString(prefix);
formatter.AppendString("@ ");
const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
formatter.AppendString(" ");
formatter.AppendString(symbol);
formatter.AppendString("\n");
g_failure_writer(buf, formatter.num_bytes_written());
}
// Invoke the default signal handler.
void InvokeDefaultSignalHandler(int signal_number) {
#ifdef HAVE_SIGACTION
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL;
sigaction(signal_number, &sig_action, nullptr);
kill(getpid(), signal_number);
#elif defined(GLOG_OS_WINDOWS)
signal(signal_number, SIG_DFL);
raise(signal_number);
#endif
}
// This variable is used for protecting FailureSignalHandler() from
// dumping stuff while another thread is doing it. Our policy is to let
// the first thread dump stuff and let other threads wait.
// See also comments in FailureSignalHandler().
static pthread_t* g_entered_thread_id_pointer = nullptr;
// Dumps signal and stack frame information, and invokes the default
// signal handler once our job is done.
#if defined(GLOG_OS_WINDOWS)
void FailureSignalHandler(int signal_number)
#else
void FailureSignalHandler(int signal_number,
siginfo_t *signal_info,
void *ucontext)
#endif
{
// First check if we've already entered the function. We use an atomic
// compare and swap operation for platforms that support it. For other
// platforms, we use a naive method that could lead to a subtle race.
// We assume pthread_self() is async signal safe, though it's not
// officially guaranteed.
pthread_t my_thread_id = pthread_self();
// NOTE: We could simply use pthread_t rather than pthread_t* for this,
// if pthread_self() is guaranteed to return non-zero value for thread
// ids, but there is no such guarantee. We need to distinguish if the
// old value (value returned from __sync_val_compare_and_swap) is
// different from the original value (in this case nullptr).
pthread_t* old_thread_id_pointer =
glog_internal_namespace_::sync_val_compare_and_swap(
&g_entered_thread_id_pointer, static_cast<pthread_t*>(nullptr),
&my_thread_id);
if (old_thread_id_pointer != nullptr) {
// We've already entered the signal handler. What should we do?
if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
// It looks the current thread is reentering the signal handler.
// Something must be going wrong (maybe we are reentering by another
// type of signal?). Kill ourself by the default signal handler.
InvokeDefaultSignalHandler(signal_number);
}
// Another thread is dumping stuff. Let's wait until that thread
// finishes the job and kills the process.
while (true) {
sleep(1);
}
}
// This is the first time we enter the signal handler. We are going to
// do some interesting stuff from here.
// TODO(satorux): We might want to set timeout here using alarm(), but
// mixing alarm() and sleep() can be a bad idea.
// First dump time info.
DumpTimeInfo();
#if !defined(GLOG_OS_WINDOWS)
// Get the program counter from ucontext.
void *pc = GetPC(ucontext);
DumpStackFrameInfo("PC: ", pc);
#endif
#ifdef HAVE_STACKTRACE
// Get the stack traces.
void *stack[32];
// +1 to exclude this function.
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
# ifdef HAVE_SIGACTION
DumpSignalInfo(signal_number, signal_info);
#elif !defined(GLOG_OS_WINDOWS)
(void)signal_info;
# endif
// Dump the stack traces.
for (int i = 0; i < depth; ++i) {
DumpStackFrameInfo(" ", stack[i]);
}
#elif !defined(GLOG_OS_WINDOWS)
(void)signal_info;
#endif
// *** TRANSITION ***
//
// BEFORE this point, all code must be async-termination-safe!
// (See WARNING above.)
//
// AFTER this point, we do unsafe things, like using LOG()!
// The process could be terminated or hung at any time. We try to
// do more useful things first and riskier things later.
// Flush the logs before we do anything in case 'anything'
// causes problems.
FlushLogFilesUnsafe(0);
// Kill ourself by the default signal handler.
InvokeDefaultSignalHandler(signal_number);
}
} // namespace
namespace glog_internal_namespace_ {
bool IsFailureSignalHandlerInstalled() {
#ifdef HAVE_SIGACTION
// TODO(andschwa): Return kFailureSignalHandlerInstalled?
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sigaction(SIGABRT, nullptr, &sig_action);
if (sig_action.sa_sigaction == &FailureSignalHandler) {
return true;
}
#elif defined(GLOG_OS_WINDOWS)
return kFailureSignalHandlerInstalled;
#endif // HAVE_SIGACTION
return false;
}
} // namespace glog_internal_namespace_
void InstallFailureSignalHandler() {
#ifdef HAVE_SIGACTION
// Build the sigaction struct.
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sig_action.sa_flags |= SA_SIGINFO;
sig_action.sa_sigaction = &FailureSignalHandler;
for (auto kFailureSignal : kFailureSignals) {
CHECK_ERR(sigaction(kFailureSignal.number, &sig_action, nullptr));
}
kFailureSignalHandlerInstalled = true;
#elif defined(GLOG_OS_WINDOWS)
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
SIG_ERR);
}
kFailureSignalHandlerInstalled = true;
#endif // HAVE_SIGACTION
}
void InstallFailureWriter(void (*writer)(const char* data, size_t size)) {
#if defined(HAVE_SIGACTION) || defined(GLOG_OS_WINDOWS)
g_failure_writer = writer;
#endif // HAVE_SIGACTION
}
_END_GOOGLE_NAMESPACE_

View File

@@ -0,0 +1,61 @@
// Copyright (c) 2000 - 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Routines to extract the current stack trace. These functions are
// thread-safe.
#ifndef BASE_STACKTRACE_H_
#define BASE_STACKTRACE_H_
#include "config.h"
#include <glog/logging.h>
_START_GOOGLE_NAMESPACE_
// This is similar to the GetStackFrames routine, except that it returns
// the stack trace only, and not the stack frame sizes as well.
// Example:
// main() { foo(); }
// foo() { bar(); }
// bar() {
// void* result[10];
// int depth = GetStackFrames(result, 10, 1);
// }
//
// This produces:
// result[0] foo
// result[1] main
// .... ...
//
// "result" must not be nullptr.
GLOG_EXPORT int GetStackTrace(void** result, int max_depth, int skip_count);
_END_GOOGLE_NAMESPACE_
#endif // BASE_STACKTRACE_H_

View File

@@ -0,0 +1,64 @@
// Copyright (c) 2000 - 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
//
// Portable implementation - just use glibc
//
// Note: The glibc implementation may cause a call to malloc.
// This can cause a deadlock in HeapProfiler.
#include <execinfo.h>
#include <cstring>
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
static const int kStackLength = 64;
void * stack[kStackLength];
int size;
size = backtrace(stack, kStackLength);
skip_count++; // we want to skip the current frame as well
int result_count = size - skip_count;
if (result_count < 0) {
result_count = 0;
}
if (result_count > max_depth) {
result_count = max_depth;
}
for (int i = 0; i < result_count; i++) {
result[i] = stack[i + skip_count];
}
return result_count;
}
_END_GOOGLE_NAMESPACE_

Some files were not shown because too many files have changed in this diff Show More