mirror of
https://github.com/deepinsight/insightface.git
synced 2025-12-30 08:02:27 +00:00
Merge pull request #2569 from tunmx/inspireface
Add the inspireface project to cpp-package.
This commit is contained in:
9
cpp-package/inspireface/.gitignore
vendored
Normal file
9
cpp-package/inspireface/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
.idea/*
|
||||
cmake-build-debug/*
|
||||
build/*
|
||||
test_*.rknn
|
||||
test_zip_*
|
||||
test_res/*
|
||||
resource/*
|
||||
3rdparty
|
||||
pack/*
|
||||
171
cpp-package/inspireface/CMakeLists.txt
Normal file
171
cpp-package/inspireface/CMakeLists.txt
Normal file
@@ -0,0 +1,171 @@
|
||||
#cmake_minimum_required(VERSION 3.19)
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(InspireFace)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++14")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
|
||||
# Set the THIRD_PARTY_DIR variable to allow it to be set externally from the command line, or use the default path if it is not set
|
||||
set(THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty" CACHE PATH "Path to the third-party libraries directory")
|
||||
|
||||
# Check that the SANITIZE compile option is enabled
|
||||
set(SANITIZE_ADDRESS OFF CACHE BOOL "Enable AddressSanitizer")
|
||||
set(SANITIZE_LEAK OFF CACHE BOOL "Enable LeakSanitizer")
|
||||
|
||||
if (SANITIZE_ADDRESS AND SANITIZE_LEAK)
|
||||
message(FATAL_ERROR "Cannot enable both AddressSanitizer and LeakSanitizer.")
|
||||
endif()
|
||||
|
||||
# Enable AddressSanitizer
|
||||
if(SANITIZE_ADDRESS)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
endif()
|
||||
|
||||
# Enable LeakSanitizer
|
||||
if(SANITIZE_LEAK)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=leak")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=leak")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=leak")
|
||||
endif()
|
||||
|
||||
set(TARGET_PLATFORM "drawin-x86" CACHE STRING "Target platform")
|
||||
|
||||
# OpenCV dependency configuration
|
||||
option(USE_MOBILE_OPENCV_IN_LOCAL "Use mobile-opencv in local environment." OFF)
|
||||
set(MOBILE_OPENCV_VERSION "4.9.0" CACHE STRING "The mobile-opencv version number")
|
||||
if (USE_MOBILE_OPENCV_IN_LOCAL)
|
||||
message("Use mobile-opencv ${MOBILE_OPENCV_VERSION}, Target platform ${TARGET_PLATFORM}")
|
||||
endif ()
|
||||
|
||||
# RKNN dependency configuration
|
||||
option(ENABLE_RKNN "Use RKNPU." OFF)
|
||||
set(RK_DEVICE_TYPE "RV1109RV1126" CACHE STRING "Type of the device")
|
||||
if (ENABLE_RKNN)
|
||||
add_definitions("-DENABLE_RKNN")
|
||||
# Device list
|
||||
set(RKNPU1_DEVICES "RV1109RV1126")
|
||||
set(RKNPU2_DEVICES "RK356X" "RK3588" "RV1106")
|
||||
set(RKNPU_MAJOR "")
|
||||
list(FIND RKNPU1_DEVICES "${RK_DEVICE_TYPE}" INDEX_RKNPU1)
|
||||
list(FIND RKNPU2_DEVICES "${RK_DEVICE_TYPE}" INDEX_RKNPU2)
|
||||
if(INDEX_RKNPU1 GREATER_EQUAL 0)
|
||||
# match rknn1
|
||||
set(RKNPU_MAJOR "rknpu1")
|
||||
elseif(INDEX_RKNPU2 GREATER_EQUAL 0)
|
||||
# match rknn2
|
||||
set(RKNPU_MAJOR "rknpu2")
|
||||
endif()
|
||||
# Result
|
||||
message(STATUS "Use ${RKNPU_MAJOR}")
|
||||
endif ()
|
||||
|
||||
|
||||
option(BUILD_LINUX_ARM7 "Platform Armv7." OFF)
|
||||
option(BUILD_LINUX_AARCH64 "Platform Armv8." OFF)
|
||||
option(GLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA "The global inference backend uses MNN CUDA." OFF)
|
||||
|
||||
|
||||
if (BUILD_LINUX_ARM7)
|
||||
set(CPU_ARCH "armhf")
|
||||
endif()
|
||||
if (BUILD_LINUX_AARCH64)
|
||||
set(CPU_ARCH "aarch64")
|
||||
endif()
|
||||
|
||||
option(BUILD_WITH_TEST "Open Build Unit-Test." ON)
|
||||
option(BUILD_WITH_SAMPLE "Open Build Sample Exec." ON)
|
||||
|
||||
option(LINUX_FETCH_MNN "Fetch and build MNN from git" OFF)
|
||||
|
||||
|
||||
if (USE_MOBILE_OPENCV_IN_LOCAL)
|
||||
add_definitions(-DUSE_MOBILE_OPENCV_IN_LOCAL)
|
||||
endif ()
|
||||
|
||||
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cpp/)
|
||||
|
||||
# OpenCV Configuration
|
||||
string(REPLACE "." ";" VERSION_LIST ${MOBILE_OPENCV_VERSION})
|
||||
list(GET VERSION_LIST 0 VERSION_MAJOR)
|
||||
if (APPLE)
|
||||
set(PLAT darwin)
|
||||
if (USE_MOBILE_OPENCV_IN_LOCAL)
|
||||
set(OPENCV_FRAMEWORK "${THIRD_PARTY_DIR}/opencv-mobile/${MOBILE_OPENCV_VERSION}/${TARGET_PLATFORM}/opencv2.framework")
|
||||
list(APPEND CMAKE_FRAMEWORK_PATH "${OPENCV_FRAMEWORK}")
|
||||
include_directories("${OPENCV_FRAMEWORK}/Headers")
|
||||
message(OPENCV_FRAMEWORK=${OPENCV_FRAMEWORK})
|
||||
find_library(ACCELERATE_FRAMEWORK Accelerate)
|
||||
else ()
|
||||
find_package(OpenCV REQUIRED)
|
||||
endif ()
|
||||
else()
|
||||
if (BUILD_LINUX_ARM7 OR BUILD_LINUX_AARCH64)
|
||||
add_definitions("-DDISABLE_GUI")
|
||||
# set(OpenCV_DIR ${THIRD_PARTY_DIR}/opencv/opencv-linux-armhf/share/OpenCV)
|
||||
# set(OpenCV_STATIC_INCLUDE_DIR ${PATH_3RDPARTY}/opencv/opencv-linux-armhf/include/)
|
||||
if (RK_DEVICE_TYPE STREQUAL "RV1109RV1126")
|
||||
# In special cases, specialize for that version
|
||||
message("The OpenCV that builds the RV1109RV1126 version depends on is specialized!")
|
||||
set(OpenCV_DIR ${THIRD_PARTY_DIR}/opencv/3.4.5/opencv-linux-armhf/share/OpenCV)
|
||||
set(OpenCV_STATIC_INCLUDE_DIR ${PATH_3RDPARTY}/opencv/3.4.5/opencv-linux-armhf/include/)
|
||||
set(PLAT linux-arm7)
|
||||
else()
|
||||
if (VERSION_MAJOR STREQUAL "3")
|
||||
set(CV_CMAKE_FOLDER share/OpenCV)
|
||||
elseif(VERSION_MAJOR STREQUAL "4")
|
||||
set(CV_CMAKE_FOLDER lib/cmake/opencv4)
|
||||
endif ()
|
||||
if(BUILD_LINUX_ARM7)
|
||||
set(PLAT linux-arm7)
|
||||
set(OpenCV_DIR "${THIRD_PARTY_DIR}/opencv-mobile/${MOBILE_OPENCV_VERSION}/${TARGET_PLATFORM}/arm-linux-gnueabihf/${CV_CMAKE_FOLDER}")
|
||||
elseif(BUILD_LINUX_AARCH64)
|
||||
set(OpenCV_DIR "${THIRD_PARTY_DIR}/opencv-mobile/${MOBILE_OPENCV_VERSION}/${TARGET_PLATFORM}/aarch64-linux-gnu/${CV_CMAKE_FOLDER}")
|
||||
endif()
|
||||
endif()
|
||||
else ()
|
||||
set(PLAT linux)
|
||||
if (USE_MOBILE_OPENCV_IN_LOCAL)
|
||||
set(OpenCV_DIR "${THIRD_PARTY_DIR}/opencv-mobile/${MOBILE_OPENCV_VERSION}/ubuntu-2004/lib/cmake/opencv4")
|
||||
endif ()
|
||||
endif ()
|
||||
find_package(OpenCV REQUIRED)
|
||||
endif ()
|
||||
|
||||
# Set install path
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install")
|
||||
|
||||
add_subdirectory(cpp/inspireface) # Add a child project: InspireFace Source
|
||||
get_property(InspireFace TARGET InspireFace PROPERTY InspireFace)
|
||||
|
||||
if (BUILD_WITH_SAMPLE)
|
||||
add_subdirectory(cpp/sample) # Add a child project: Samples
|
||||
endif ()
|
||||
|
||||
if (BUILD_WITH_TEST)
|
||||
add_subdirectory(cpp/test) # Add a child project: Unit-Test
|
||||
endif ()
|
||||
|
||||
# Print Message
|
||||
message(STATUS "InspireFace Project Global:")
|
||||
message(STATUS "\t CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
|
||||
message(STATUS "\t CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||
message(STATUS "\t THIRD_PARTY_DIR: ${THIRD_PARTY_DIR}")
|
||||
message(STATUS "\t SANITIZE_ADDRESS: ${SANITIZE_ADDRESS}")
|
||||
message(STATUS "\t SANITIZE_LEAK: ${SANITIZE_LEAK}")
|
||||
message(STATUS "\t USE_MOBILE_OPENCV_IN_LOCAL: ${USE_MOBILE_OPENCV_IN_LOCAL}")
|
||||
message(STATUS "\t OpenCV_DIR: ${OpenCV_DIR}")
|
||||
message(STATUS "\t ENABLE_RKNN: ${ENABLE_RKNN}")
|
||||
if (ENABLE_RKNN)
|
||||
message(STATUS "\t RKNPU_MAJOR: ${RKNPU_MAJOR}")
|
||||
message(STATUS "\t RK_DEVICE_TYPE: ${RK_DEVICE_TYPE}")
|
||||
endif ()
|
||||
message(STATUS "\t BUILD_LINUX_ARM7: ${BUILD_LINUX_ARM7}")
|
||||
message(STATUS "\t BUILD_LINUX_AARCH64: ${BUILD_LINUX_AARCH64}")
|
||||
message(STATUS "\t BUILD_WITH_TEST: ${BUILD_WITH_TEST}")
|
||||
message(STATUS "\t BUILD_WITH_SAMPLE: ${BUILD_WITH_SAMPLE}")
|
||||
message(STATUS "\t CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
|
||||
282
cpp-package/inspireface/README.md
Normal file
282
cpp-package/inspireface/README.md
Normal file
@@ -0,0 +1,282 @@
|
||||
# InspireFace
|
||||
## 0. Overview
|
||||
InspireFace is a cross-platform face recognition SDK developed in C/C++, supporting multiple operating systems and various backend types for inference, such as CPU, GPU, and NPU.
|
||||
|
||||
## 1. Preparation
|
||||
### 1.1. Downloading 3rdparty Files
|
||||
You can download the third-party libraries necessary for the compilation process, **InspireFace-3rdparty**, from [Google Drive](https://drive.google.com/drive/folders/1krmv9Pj0XEZXR1GRPHjW_Sl7t4l0dNSS?usp=sharing) and extract them to any location on your disk.
|
||||
|
||||
### 1.2. Downloading Pack Files
|
||||
You can download the pack files containing models and configurations needed for compilation from [Google Drive](https://drive.google.com/drive/folders/1krmv9Pj0XEZXR1GRPHjW_Sl7t4l0dNSS?usp=sharing) and extract them to any location.
|
||||
|
||||
### 1.3. Installing OpenCV
|
||||
If you intend to use the SDK locally or on a server, ensure that OpenCV is installed on the host device beforehand to enable successful linking during the compilation process. For cross-compilation targets like Android or ARM embedded boards, you can use the pre-compiled OpenCV libraries provided by **InspireFace-3rdparty**.
|
||||
|
||||
### 1.4. Installing MNN
|
||||
**InspireFace-3rdparty** includes pre-compiled MNN libraries tailored for various platforms. However, due to differences in underlying device libraries, you may need to compile the MNN library yourself if the provided versions do not match your hardware.
|
||||
|
||||
### 1.5. Requirements
|
||||
|
||||
- CMake (version 3.10 or higher)
|
||||
- OpenCV (version 4.20 or higher)
|
||||
- Use the specific OpenCV-SDK supported by each target platform such as Android, iOS, and Linux.
|
||||
- NDK (version 16 or higher, only required for Android)
|
||||
- MNN (version 1.4.0 or higher)
|
||||
- C++ Compiler
|
||||
- Either GCC or Clang can be used (macOS does not require additional installation as Xcode is included)
|
||||
- Recommended GCC version is 4.9 or higher
|
||||
- Note that in some distributions, GCC (GNU C Compiler) and G++ (GNU C++ Compiler) are installed separately.
|
||||
- For instance, on Ubuntu, you need to install both gcc and g++
|
||||
- Recommended Clang version is 3.9 or higher
|
||||
- arm-linux-gnueabihf (for RV1109/RV1126)
|
||||
- Prepare the cross-compilation toolchain in advance, such as gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf
|
||||
- CUDA (version 10.1 or higher)
|
||||
- GPU-based inference requires installing NVIDIA's CUDA dependencies on the device.
|
||||
- RKNN
|
||||
- Adjust and select versions currently supported for specific requirements.
|
||||
|
||||
## 2. Compilation
|
||||
CMake option are used to control the various details of the compilation phase. Please select according to your actual requirements. [Parameter table](doc/CMake-Option.md).
|
||||
|
||||
### 2.1. Local Compilation
|
||||
Once **InspireFace-3rdparty** is prepared and OpenCV is installed, you can begin the compilation process. If you are using macOS or Linux, you can quickly compile using the shell scripts provided in the **command/** folder at the project root:
|
||||
```bash
|
||||
cd InspireFace/
|
||||
# Default, but you can also modify the shell script's -DTHIRD_PARTY_DIR=....
|
||||
ln -s YOUR_DIR/InspireFace-3rdparty ./3rdparty
|
||||
# Execute the local compilation script
|
||||
bash command/build.sh
|
||||
```
|
||||
After compilation, you can find the local file in the build directory, which contains the compilation results. The install directory structure is as follows:
|
||||
```bash
|
||||
install
|
||||
└── InspireFace
|
||||
├── include
|
||||
│ ├── herror.h
|
||||
│ └── inspireface.h
|
||||
└── lib
|
||||
└── libInspireFace.so
|
||||
```
|
||||
|
||||
- **libInspireFace.so**:Compiled dynamic linking library.
|
||||
- **inspireface.h**:Header file definition.
|
||||
- **herror.h**:Reference error number definition.
|
||||
### 2.2. Cross Compilation
|
||||
Cross compilation requires you to prepare the target platform's cross-compilation toolchain on the host machine in advance. Here, compiling for Rockchip's embedded devices RV1109/RV1126 is used as an example:
|
||||
```bash
|
||||
# Set the path for the cross-compilation toolchain
|
||||
export ARM_CROSS_COMPILE_TOOLCHAIN=YOUR_DIR/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf
|
||||
# Execute the cross-compilation script for RV1109/RV1126
|
||||
bash command/build_cross_rv1109rv1126_armhf.sh
|
||||
```
|
||||
After the compilation is complete, you can find the compiled results in the **build/rv1109rv1126_armhf/install** directory.
|
||||
### 2.3. Supported Platforms and Architectures
|
||||
We have completed the adaptation and testing of the software across various operating systems and CPU architectures. This includes compatibility verification for platforms such as Linux, macOS, iOS, and Android, as well as testing for specific hardware support to ensure stable operation in diverse environments.
|
||||
|
||||
| **No.** | **Operating System** | **CPU Architecture** | **Special Device Support** | **Adapted** | **Passed Tests** | **Verification Device** | **Remarks** |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| 1 | **Linux** | ARMv7 | - | - [x] | - [x] | RV1126 | |
|
||||
| 2 | | ARMv8 | - | - [x] | - [x] | RK3399 | |
|
||||
| 3 | | x86/x86_64 | - | - [x] | - [x] | | |
|
||||
| 4 | | ARMv7 | rv1109rv1126 | - [x] | - [x] | RV1126 | NPU |
|
||||
| 5 | | x86/x86_64 | CUDA | - [x] | - [ ] ⚠️ | RTX3090 | Some issues in inference remain unresolved |
|
||||
| 6 | **macOS** | Intel x86 | - | - [x] | - [x] | MacBook Pro 16 | |
|
||||
| 7 | | Apple Silicon | - | - [ ] | - [ ] | | |
|
||||
| 8 | **iOS** | ARM | - | - [ ] | - [ ] | | |
|
||||
| 9 | **Android** | ARMv7 | - | - [ ] | - [ ] | | |
|
||||
| 10 | | ARMv8 | - | - [ ] | - [ ] | | |
|
||||
|
||||
- Complete compilation scripts and successful compilation.
|
||||
- Pass unit tests on physical devices.
|
||||
- Meet all performance benchmarks in tests.
|
||||
|
||||
## 3. Example
|
||||
### 3.1. C/C++ Sample
|
||||
To integrate InspireFace into a C/C++ project, you simply need to link the InspireFace library and include the appropriate header files. Below is a basic example demonstrating face detection:
|
||||
|
||||
```cpp
|
||||
HResult ret;
|
||||
// The resource file must be loaded before it can be used
|
||||
ret = HFLaunchInspireFace(packPath);
|
||||
if (ret != HSUCCEED) {
|
||||
std::cout << "Load Resource error: " << ret << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Enable the functions in the pipeline: mask detection, live detection, and face quality detection
|
||||
HOption option = HF_ENABLE_QUALITY | HF_ENABLE_MASK_DETECT | HF_ENABLE_LIVENESS;
|
||||
// Non-video or frame sequence mode uses IMAGE-MODE, which is always face detection without tracking
|
||||
HFDetectMode detMode = HF_DETECT_MODE_IMAGE;
|
||||
// Maximum number of faces detected
|
||||
HInt32 maxDetectNum = 5;
|
||||
// Handle of the current face SDK algorithm context
|
||||
HFSession session = {0};
|
||||
ret = HFCreateInspireFaceSessionOptional(option, detMode, maxDetectNum, &session);
|
||||
if (ret != HSUCCEED) {
|
||||
std::cout << "Create FaceContext error: " << ret << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Load a image
|
||||
cv::Mat image = cv::imread(sourcePath);
|
||||
if (image.empty()) {
|
||||
std::cout << "The source entered is not a picture or read error." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// Prepare an image parameter structure for configuration
|
||||
HFImageData imageParam = {0};
|
||||
imageParam.data = image.data; // Data buffer
|
||||
imageParam.width = image.cols; // Target view width
|
||||
imageParam.height = image.rows; // Target view width
|
||||
imageParam.rotation = HF_CAMERA_ROTATION_0; // Data source rotate
|
||||
imageParam.format = HF_STREAM_BGR; // Data source format
|
||||
|
||||
// Create an image data stream
|
||||
HFImageStream imageHandle = {0};
|
||||
ret = HFCreateImageStream(&imageParam, &imageHandle);
|
||||
if (ret != HSUCCEED) {
|
||||
std::cout << "Create ImageStream error: " << ret << std::endl;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Execute HF_FaceContextRunFaceTrack captures face information in an image
|
||||
HFMultipleFaceData multipleFaceData = {0};
|
||||
ret = HFExecuteFaceTrack(session, imageHandle, &multipleFaceData);
|
||||
if (ret != HSUCCEED) {
|
||||
std::cout << "Execute HFExecuteFaceTrack error: " << ret << std::endl;
|
||||
return ret;
|
||||
}
|
||||
// Print the number of faces detected
|
||||
auto faceNum = multipleFaceData.detectedNum;
|
||||
std::cout << "Num of face: " << faceNum << std::endl;
|
||||
|
||||
ret = HFReleaseImageStream(imageHandle);
|
||||
if (ret != HSUCCEED) {
|
||||
printf("Release image stream error: %lu\n", ret);
|
||||
}
|
||||
// The memory must be freed at the end of the program
|
||||
ret = HFReleaseInspireFaceSession(session);
|
||||
if (ret != HSUCCEED) {
|
||||
printf("Release session error: %lu\n", ret);
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
For more examples, you can refer to the **cpp/sample** sub-project located in the root directory. You can compile these sample executables by enabling the **BUILD_WITH_SAMPLE** option during the compilation process.
|
||||
|
||||
**Note**: For each error code feedback, you can click on this [link](doc/Error-Feedback-Codes.md) to view detailed explanations.
|
||||
|
||||
### 3.2. Python Native Sample
|
||||
We provide a Python API that allows for more efficient use of the InspireFace library. After compiling the dynamic link library, you need to either symlink or copy it to the **python/inspireface/modules/core** directory within the root directory. You can then start testing by navigating to the **[python/](python/)** directory. Your Python environment will need to have some dependencies installed:
|
||||
|
||||
- python >= 3.7
|
||||
- opencv-python
|
||||
- loguru
|
||||
- tqdm
|
||||
- numpy
|
||||
- ctypes
|
||||
```bash
|
||||
# Use a symbolic link
|
||||
ln -s YOUR_BUILD_DIR/install/InspireFace/lib/libInspireFace.so python/inspireface/modules/core
|
||||
# Navigate to the sub-project directory
|
||||
cd python
|
||||
|
||||
```
|
||||
|
||||
Import inspireface for a quick facial detection example:
|
||||
```python
|
||||
import cv2
|
||||
import inspireface as ifac
|
||||
from inspireface.param import *
|
||||
|
||||
# Step 1: Initialize the SDK and load the algorithm resource files.
|
||||
resource_path = "pack/Pikachu"
|
||||
ret = ifac.launch(resource_path)
|
||||
assert ret, "Launch failure. Please ensure the resource path is correct."
|
||||
|
||||
# Optional features, loaded during session creation based on the modules specified.
|
||||
opt = HF_ENABLE_NONE
|
||||
session = ifac.InspireFaceSession(opt, HF_DETECT_MODE_IMAGE)
|
||||
|
||||
# Load the image using OpenCV.
|
||||
image = cv2.imread(image_path)
|
||||
assert image is not None, "Please check that the image path is correct."
|
||||
|
||||
# Perform face detection on the image.
|
||||
faces = session.face_detection(image)
|
||||
print(f"face detection: {len(faces)} found")
|
||||
|
||||
# Copy the image for drawing the bounding boxes.
|
||||
draw = image.copy()
|
||||
for idx, face in enumerate(faces):
|
||||
print(f"{'==' * 20}")
|
||||
print(f"idx: {idx}")
|
||||
# Print Euler angles of the face.
|
||||
print(f"roll: {face.roll}, yaw: {face.yaw}, pitch: {face.pitch}")
|
||||
# Draw bounding box around the detected face.
|
||||
x1, y1, x2, y2 = face.location
|
||||
cv2.rectangle(draw, (x1, y1), (x2, y2), (0, 0, 255), 2)
|
||||
```
|
||||
In the project, more usage examples are provided:
|
||||
|
||||
- sample_face_detection.py: Facial detection example
|
||||
- sample_face_recognition.py: Facial recognition example
|
||||
- sample_face_track_from_video.py: Facial tracking from video stream example
|
||||
|
||||
## 4. Test
|
||||
In the project, there is a subproject called cpp/test. To compile it, you need to enable the BUILD_WITH_TEST switch, which will allow you to compile executable programs for testing.
|
||||
|
||||
```bash
|
||||
cmake -DBUILD_WITH_TEST=ON ..
|
||||
```
|
||||
If you need to run test cases, you will need to download the required [resource files](https://drive.google.com/file/d/1i4uC-dZTQxdVgn2rP0ZdfJTMkJIXgYY4/view?usp=sharing), which are **test_res** and **pack** respectively. Unzip the pack file into the test_res folder. The directory structure of test_res should be prepared as follows before testing:
|
||||
|
||||
```bash
|
||||
|
||||
test_res
|
||||
├── data
|
||||
├── images
|
||||
├── pack <- unzip pack.zip
|
||||
├── save
|
||||
├── valid_lfw_funneled.txt
|
||||
├── video
|
||||
└── video_frames
|
||||
|
||||
```
|
||||
After compilation, you can find the executable program "Test" in **install/test**. The program accepts two optional parameters:
|
||||
|
||||
- **test_dir**:Path to the test resource files
|
||||
- **pack**:Name of the model to be tested
|
||||
```bash
|
||||
./Test --test_dir PATH/test_res --pack Pikachu
|
||||
```
|
||||
During the process of building the test program using CMake, it will involve selecting CMake parameters. For specific details, you can refer to the parameter configuration table.
|
||||
|
||||
**Note**: If you want to view the benchmark test report, you can click on the [link](doc/Benchmark-Remark(Updating).md).
|
||||
|
||||
## 5. Function support
|
||||
The following functionalities and technologies are currently supported.
|
||||
|
||||
| Index | Function | Adaptation | Note |
|
||||
| -- | --- | --- | --- |
|
||||
| 1 | Face Detection | - [x] | SCRFD |
|
||||
| 2 | Facial Landmark Detection | - [x] | HyperLandmark |
|
||||
| 3 | Face Recognition | - [x] | ArcFace |
|
||||
| 4 | Face Tracking | - [x] | |
|
||||
| 5 | Mask Detection | - [x] | |
|
||||
| 6 | Silent Liveness Detection | - [x] | MiniVision |
|
||||
| 7 | Face Quality Detection | - [x] | |
|
||||
| 8 | Face Pose Estimation | - [x] | |
|
||||
| 9 | Age Prediction | - [ ] | |
|
||||
| 10 | Cooperative Liveness Detection | - [ ] | |
|
||||
|
||||
|
||||
## 6. Models Pack List
|
||||
|
||||
For different scenarios, we currently provide several Packs, each containing multiple models and configurations.
|
||||
|
||||
| Name | Supported Devices | Note | Link |
|
||||
| --- | --- | --- | --- |
|
||||
| Pikachu | CPU | Lightweight edge-side model | [GDrive](https://drive.google.com/file/d/1i4uC-dZTQxdVgn2rP0ZdfJTMkJIXgYY4/view?usp=drive_link) |
|
||||
| Megatron | CPU, GPU | Local or server-side model | [GDrive](https://drive.google.com/file/d/1i4uC-dZTQxdVgn2rP0ZdfJTMkJIXgYY4/view?usp=drive_link) |
|
||||
| Gundam-RV1109 | RKNPU | Supports RK1109 and RK1126 | [GDrive](https://drive.google.com/file/d/1i4uC-dZTQxdVgn2rP0ZdfJTMkJIXgYY4/view?usp=drive_link) |
|
||||
|
||||
15
cpp-package/inspireface/command/build.sh
Normal file
15
cpp-package/inspireface/command/build.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
mkdir -p build/local
|
||||
# shellcheck disable=SC2164
|
||||
cd build/local
|
||||
# export cross_compile_toolchain=/home/s4129/software/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf
|
||||
cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DTHIRD_PARTY_DIR=3rdparty \
|
||||
-DBUILD_WITH_SAMPLE=ON \
|
||||
-DBUILD_WITH_TEST=OFF \
|
||||
-DENABLE_BENCHMARK=OFF \
|
||||
-DENABLE_USE_LFW_DATA=OFF \
|
||||
-DENABLE_TEST_EVALUATION=OFF \
|
||||
-DBUILD_SHARED_LIBS=ON ../../
|
||||
|
||||
make -j4
|
||||
make install
|
||||
@@ -0,0 +1,25 @@
|
||||
mkdir -p build/rv1109rv1126_armhf
|
||||
# shellcheck disable=SC2164
|
||||
cd build/rv1109rv1126_armhf
|
||||
# export cross_compile_toolchain=/home/s4129/software/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf
|
||||
cmake -DCMAKE_SYSTEM_NAME=Linux \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DTHIRD_PARTY_DIR=3rdparty \
|
||||
-DCMAKE_SYSTEM_VERSION=1 \
|
||||
-DCMAKE_SYSTEM_PROCESSOR=armv7 \
|
||||
-DCMAKE_C_COMPILER=$ARM_CROSS_COMPILE_TOOLCHAIN/bin/arm-linux-gnueabihf-gcc \
|
||||
-DCMAKE_CXX_COMPILER=$ARM_CROSS_COMPILE_TOOLCHAIN/bin/arm-linux-gnueabihf-g++ \
|
||||
-DTARGET_PLATFORM=armlinux \
|
||||
-DBUILD_LINUX_ARM7=ON \
|
||||
-DENABLE_RKNN=ON \
|
||||
-DRK_DEVICE_TYPE=RV1109RV1126 \
|
||||
-DBUILD_WITH_SAMPLE=OFF \
|
||||
-DBUILD_WITH_TEST=OFF \
|
||||
-DENABLE_BENCHMARK=OFF \
|
||||
-DENABLE_USE_LFW_DATA=OFF \
|
||||
-DENABLE_TEST_EVALUATION=OFF \
|
||||
-DBUILD_SHARED_LIBS=ON ../..
|
||||
|
||||
make -j4
|
||||
make install
|
||||
|
||||
17
cpp-package/inspireface/command/build_linux_cuda.sh
Normal file
17
cpp-package/inspireface/command/build_linux_cuda.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
mkdir -p build/linux_cuda
|
||||
# shellcheck disable=SC2164
|
||||
cd build/linux_cuda
|
||||
# export cross_compile_toolchain=/home/s4129/software/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf
|
||||
cmake -DCMAKE_SYSTEM_NAME=Linux \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DTHIRD_PARTY_DIR=3rdparty \
|
||||
-DBUILD_WITH_SAMPLE=OFF \
|
||||
-DBUILD_WITH_TEST=OFF \
|
||||
-DENABLE_BENCHMARK=OFF \
|
||||
-DENABLE_USE_LFW_DATA=OFF \
|
||||
-DENABLE_TEST_EVALUATION=OFF \
|
||||
-DGLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA=ON \
|
||||
-DLINUX_MNN_CUDA=/home/tunm/software/MNN-2.7.0/build_cuda/install \
|
||||
-DBUILD_SHARED_LIBS=ON ../..
|
||||
|
||||
make -j4
|
||||
191
cpp-package/inspireface/cpp/inspireface/CMakeLists.txt
Normal file
191
cpp-package/inspireface/cpp/inspireface/CMakeLists.txt
Normal file
@@ -0,0 +1,191 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(InspireFaceSDK)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++14")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
|
||||
# Current version
|
||||
set(INSPIRE_FACE_VERSION_MAJOR 1)
|
||||
set(INSPIRE_FACE_VERSION_MINOR 0)
|
||||
set(INSPIRE_FACE_VERSION_PATCH 0)
|
||||
# Converts the version number to a string
|
||||
string(CONCAT INSPIRE_FACE_VERSION_MAJOR_STR ${INSPIRE_FACE_VERSION_MAJOR})
|
||||
string(CONCAT INSPIRE_FACE_VERSION_MINOR_STR ${INSPIRE_FACE_VERSION_MINOR})
|
||||
string(CONCAT INSPIRE_FACE_VERSION_PATCH_STR ${INSPIRE_FACE_VERSION_PATCH})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/information.h.in ${CMAKE_CURRENT_SOURCE_DIR}/information.h)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.txt.in ${CMAKE_CURRENT_SOURCE_DIR}/version.txt)
|
||||
|
||||
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." ON)
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
set(SOURCE_FILES ${SOURCE_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/c_api/inspireface.cc) # Add C_API file
|
||||
|
||||
|
||||
if(NOT APPLE)
|
||||
find_package(OpenCV REQUIRED)
|
||||
endif()
|
||||
|
||||
if (NOT ANDROID)
|
||||
|
||||
if (LINUX_FETCH_MNN)
|
||||
# Include FetchContent module
|
||||
include(FetchContent)
|
||||
# Fetch MNN
|
||||
message("Downloading MNN from https://github.com/alibaba/MNN.git, this may take a while.")
|
||||
FetchContent_Declare(
|
||||
mnn
|
||||
GIT_REPOSITORY https://github.com/alibaba/MNN.git
|
||||
GIT_TAG 2.7.0
|
||||
)
|
||||
set(MNN_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||
set(MNN_BUILD_TOOLS OFF CACHE BOOL "" FORCE)
|
||||
set(MNN_BUILD_CONVERTER OFF CACHE BOOL "" FORCE)
|
||||
if(GLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA)
|
||||
set(MNN_CUDA ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
||||
FetchContent_MakeAvailable(mnn)
|
||||
set(MNN_INCLUDE_DIRS ${mnn_SOURCE_DIR}/include)
|
||||
if (MNN_BUILD_SHARED_LIBS)
|
||||
set(MNN_LIBS ${mnn_BINARY_DIR})
|
||||
else()
|
||||
set(MNN_LIBS ${mnn_BINARY_DIR}/libMNN.a)
|
||||
endif ()
|
||||
|
||||
elseif (GLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA)
|
||||
# Use MNN Cuda
|
||||
message("Global MNN CUDA device inference")
|
||||
add_definitions("-DGLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA")
|
||||
set(MNN_INCLUDE_DIRS ${LINUX_MNN_CUDA}/include)
|
||||
link_directories(${LINUX_MNN_CUDA}/lib)
|
||||
set(MNN_LIBS MNN)
|
||||
|
||||
elseif(DEFINED MNN_STATIC_PATH)
|
||||
message("Using static MNN from specified path: ${MNN_STATIC_PATH}")
|
||||
set(MNN_INCLUDE_DIRS "${MNN_STATIC_PATH}/include")
|
||||
set(MNN_LIBS "${MNN_STATIC_PATH}/lib/libMNN.a")
|
||||
else ()
|
||||
# Default or fallback case for MNN setup
|
||||
message("Default or fallback case for MNN setup")
|
||||
set(MNN_INCLUDE_DIRS ${THIRD_PARTY_DIR}/MNN/${PLAT}-static/include)
|
||||
set(MNN_LIBS ${THIRD_PARTY_DIR}/MNN/${PLAT}-static/lib/libMNN.a)
|
||||
endif ()
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
if (ENABLE_RKNN)
|
||||
set(RKNN_API_INCLUDE_DIRS ${THIRD_PARTY_DIR}/${RKNPU_MAJOR}/runtime/${RK_DEVICE_TYPE}/Linux/librknn_api/include)
|
||||
set(RKNN_API_LIB ${THIRD_PARTY_DIR}/${RKNPU_MAJOR}/runtime/${RK_DEVICE_TYPE}/Linux/librknn_api/${CPU_ARCH}/)
|
||||
link_directories(${RKNN_API_LIB})
|
||||
endif()
|
||||
|
||||
# OpenCV
|
||||
if(APPLE AND USE_MOBILE_OPENCV_IN_LOCAL)
|
||||
set(LINK_THIRD_LIBS ${LINK_THIRD_LIBS} "${OPENCV_FRAMEWORK}" ${MNN_LIBS} "${ACCELERATE_FRAMEWORK}")
|
||||
else()
|
||||
set(LINK_THIRD_LIBS ${OpenCV_LIBS} ${MNN_LIBS})
|
||||
endif()
|
||||
|
||||
# sqlite3
|
||||
set(SOURCE_FILES ${SOURCE_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/middleware/sqlite/sqlite3.c) # Add C_API file
|
||||
|
||||
if (ENABLE_RKNN)
|
||||
set(LINK_THIRD_LIBS ${LINK_THIRD_LIBS} rknn_api dl)
|
||||
# InferenceHelp use RkNN
|
||||
add_definitions("-DINFERENCE_HELPER_ENABLE_RKNN")
|
||||
|
||||
endif()
|
||||
|
||||
# cpp yaml
|
||||
file(GLOB_RECURSE CPP_YAML_SRC ${CMAKE_CURRENT_SOURCE_DIR}/middleware/cpp_yaml/src/*.cpp)
|
||||
set(SOURCE_FILES ${SOURCE_FILES} ${CPP_YAML_SRC})
|
||||
set(CPP_YAML_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/middleware/cpp_yaml/include)
|
||||
|
||||
# archive
|
||||
set(SOURCE_FILES ${SOURCE_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/middleware/model_archive/microtar/microtar.c)
|
||||
|
||||
# MNN
|
||||
link_directories(${MNN_LIBS})
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
add_library(InspireFace SHARED ${SOURCE_FILES})
|
||||
else()
|
||||
add_library(InspireFace STATIC ${SOURCE_FILES})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(InspireFace PUBLIC INFERENCE_HELPER_ENABLE_MNN)
|
||||
target_compile_definitions(InspireFace PUBLIC FEATURE_BLOCK_ENABLE_OPENCV)
|
||||
|
||||
# Include files
|
||||
set(NEED_INCLUDE . ${MNN_INCLUDE_DIRS})
|
||||
if (ENABLE_RKNN)
|
||||
set(NEED_INCLUDE ${NEED_INCLUDE} ${RKNN_API_INCLUDE_DIRS})
|
||||
endif ()
|
||||
if (BUILD_LINUX_ARM7)
|
||||
set(NEED_INCLUDE ${NEED_INCLUDE} ${OpenCV_STATIC_INCLUDE_DIR})
|
||||
endif ()
|
||||
|
||||
# add cpp yaml header
|
||||
set(NEED_INCLUDE ${NEED_INCLUDE} ${CPP_YAML_INCLUDE})
|
||||
|
||||
if(PLAT STREQUAL "linux")
|
||||
find_package(Threads REQUIRED)
|
||||
set(LINK_THIRD_LIBS ${LINK_THIRD_LIBS} ${CMAKE_THREAD_LIBS_INIT} dl)
|
||||
endif()
|
||||
|
||||
target_include_directories(InspireFace PUBLIC
|
||||
${NEED_INCLUDE}
|
||||
)
|
||||
|
||||
if (NOT ANDROID)
|
||||
target_link_libraries(InspireFace PUBLIC ${LINK_THIRD_LIBS})
|
||||
|
||||
set_target_properties(InspireFace PROPERTIES
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/
|
||||
)
|
||||
else()
|
||||
|
||||
endif()
|
||||
|
||||
# Print Message
|
||||
message(STATUS "InspireFace Core:")
|
||||
message(STATUS "\t Version: ${INSPIRE_FACE_VERSION_MAJOR}.${INSPIRE_FACE_VERSION_MINOR}.${INSPIRE_FACE_VERSION_PATCH}")
|
||||
message(STATUS "\t LINUX_FETCH_MNN: ${LINUX_FETCH_MNN}")
|
||||
message(STATUS "\t MNN_INCLUDE_DIRS: ${MNN_INCLUDE_DIRS}")
|
||||
message(STATUS "\t MNN_LIBS: ${MNN_LIBS}")
|
||||
message(STATUS "\t ENABLE_RKNN: ${ENABLE_RKNN}")
|
||||
if (ENABLE_RKNN)
|
||||
message(STATUS "\t RKNN_API_INCLUDE_DIRS: ${RKNN_API_INCLUDE_DIRS}")
|
||||
message(STATUS "\t RKNN_API_LIB: ${RKNN_API_LIB}")
|
||||
endif ()
|
||||
message(STATUS "\t BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}")
|
||||
if (GLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA)
|
||||
message(STATUS "\t GLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA: ${GLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA}")
|
||||
endif ()
|
||||
|
||||
|
||||
# Install lib
|
||||
install(TARGETS InspireFace
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib
|
||||
)
|
||||
|
||||
# Install header file
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/c_api/inspireface.h DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/include)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/herror.h DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/include)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/version.txt DESTINATION ${CMAKE_INSTALL_PREFIX}/)
|
||||
|
||||
if (ENABLE_RKNN)
|
||||
# Install rknn 3rd lib
|
||||
install(FILES ${RKNN_API_LIB}/librknn_api.so DESTINATION ${CMAKE_INSTALL_PREFIX}/InspireFace/lib)
|
||||
endif ()
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Created by tunm on 2024/4/17.
|
||||
//
|
||||
|
||||
#include "launch.h"
|
||||
#include "log.h"
|
||||
#include "herror.h"
|
||||
|
||||
|
||||
namespace inspire {
|
||||
|
||||
std::mutex Launch::mutex_;
|
||||
std::shared_ptr<Launch> Launch::instance_ = nullptr;
|
||||
|
||||
InspireArchive& Launch::getMArchive() {
|
||||
return m_archive_;
|
||||
}
|
||||
|
||||
std::shared_ptr<Launch> Launch::GetInstance() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!instance_) {
|
||||
instance_ = std::shared_ptr<Launch>(new Launch());
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int32_t Launch::Load(const std::string &path) {
|
||||
if (!m_load_) {
|
||||
m_archive_.ReLoad(path);
|
||||
if (m_archive_.QueryStatus() == SARC_SUCCESS) {
|
||||
m_load_ = true;
|
||||
return HSUCCEED;
|
||||
} else {
|
||||
return HERR_ARCHIVE_LOAD_MODEL_FAILURE;
|
||||
}
|
||||
} else {
|
||||
INSPIRE_LOGW("There is no need to call launch more than once, as subsequent calls will not affect the initialization.");
|
||||
return HSUCCEED;
|
||||
}
|
||||
}
|
||||
|
||||
bool Launch::isMLoad() const {
|
||||
return m_load_;
|
||||
}
|
||||
|
||||
} // namespace inspire
|
||||
@@ -0,0 +1,49 @@
|
||||
// Created by tunm on 2024/04/17.
|
||||
#pragma once
|
||||
#ifndef INSPIREFACE_LAUNCH_H
|
||||
#define INSPIREFACE_LAUNCH_H
|
||||
#include "middleware/model_archive/inspire_archive.h"
|
||||
#include <mutex>
|
||||
|
||||
#ifndef INSPIRE_API
|
||||
#define INSPIRE_API
|
||||
#endif
|
||||
|
||||
#define INSPIRE_LAUNCH inspire::Launch::GetInstance()
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// The Launch class acts as the main entry point for the InspireFace system.
|
||||
// It is responsible for loading static resources such as models, configurations, and parameters.
|
||||
class INSPIRE_API Launch {
|
||||
public:
|
||||
Launch(const Launch&) = delete; // Delete the copy constructor to prevent copying.
|
||||
Launch& operator=(const Launch&) = delete; // Delete the assignment operator to prevent assignment.
|
||||
|
||||
// Retrieves the singleton instance of Launch, ensuring that only one instance exists.
|
||||
static std::shared_ptr<Launch> GetInstance();
|
||||
|
||||
// Loads the necessary resources from a specified path.
|
||||
// Returns an integer status code: 0 on success, non-zero on failure.
|
||||
int32_t Load(const std::string &path);
|
||||
|
||||
// Provides access to the loaded InspireArchive instance.
|
||||
InspireArchive& getMArchive();
|
||||
|
||||
// Checks if the resources have been successfully loaded.
|
||||
bool isMLoad() const;
|
||||
|
||||
private:
|
||||
Launch() : m_load_(false) {} ///< Private constructor for the singleton pattern.
|
||||
|
||||
static std::mutex mutex_; ///< Mutex for synchronizing access to the singleton instance.
|
||||
static std::shared_ptr<Launch> instance_; ///< The singleton instance of Launch.
|
||||
|
||||
InspireArchive m_archive_; ///< The archive containing all necessary resources.
|
||||
bool m_load_; ///< Flag indicating whether the resources have been successfully loaded.
|
||||
};
|
||||
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif //INSPIREFACE_LAUNCH_H
|
||||
625
cpp-package/inspireface/cpp/inspireface/c_api/inspireface.cc
Normal file
625
cpp-package/inspireface/cpp/inspireface/c_api/inspireface.cc
Normal file
@@ -0,0 +1,625 @@
|
||||
//
|
||||
// Created by tunm on 2023/10/3.
|
||||
//
|
||||
|
||||
#include "inspireface.h"
|
||||
#include "intypedef.h"
|
||||
#include "inspireface_internal.h"
|
||||
#include "information.h"
|
||||
#include "feature_hub/feature_hub.h"
|
||||
#include "Initialization_module/launch.h"
|
||||
|
||||
using namespace inspire;
|
||||
|
||||
HYPER_CAPI_EXPORT extern HResult HFCreateImageStream(PHFImageData data, HFImageStream* handle) {
|
||||
if (data == nullptr || handle == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
|
||||
auto stream = new HF_CameraStream();
|
||||
switch (data->rotation) {
|
||||
case HF_CAMERA_ROTATION_90: stream->impl.SetRotationMode(ROTATION_90); break;
|
||||
case HF_CAMERA_ROTATION_180: stream->impl.SetRotationMode(ROTATION_180); break;
|
||||
case HF_CAMERA_ROTATION_270: stream->impl.SetRotationMode(ROTATION_270); break;
|
||||
default: stream->impl.SetRotationMode(ROTATION_0); break;
|
||||
}
|
||||
switch (data->format) {
|
||||
case HF_STREAM_RGB: stream->impl.SetDataFormat(RGB); break;
|
||||
case HF_STREAM_BGR: stream->impl.SetDataFormat(BGR); break;
|
||||
case HF_STREAM_RGBA: stream->impl.SetDataFormat(RGBA); break;
|
||||
case HF_STREAM_BGRA: stream->impl.SetDataFormat(BGRA); break;
|
||||
case HF_STREAM_YUV_NV12: stream->impl.SetDataFormat(NV12); break;
|
||||
case HF_STREAM_YUV_NV21: stream->impl.SetDataFormat(NV21); break;
|
||||
default: return HERR_INVALID_IMAGE_STREAM_PARAM; // Assume there's a return code for unsupported formats
|
||||
}
|
||||
stream->impl.SetDataBuffer(data->data, data->height, data->width);
|
||||
|
||||
*handle = (HFImageStream)stream;
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
HYPER_CAPI_EXPORT extern HResult HFReleaseImageStream(HFImageStream streamHandle) {
|
||||
if (streamHandle == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
delete (HF_CameraStream*)streamHandle;
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
void HFDeBugImageStreamImShow(HFImageStream streamHandle) {
|
||||
if (streamHandle == nullptr) {
|
||||
INSPIRE_LOGE("Handle error");
|
||||
}
|
||||
HF_CameraStream *stream = (HF_CameraStream* ) streamHandle;
|
||||
if (stream == nullptr) {
|
||||
INSPIRE_LOGE("Image error");
|
||||
return;
|
||||
}
|
||||
auto image = stream->impl.GetScaledImage(1.0f, true);
|
||||
# ifdef DISABLE_GUI
|
||||
cv::imwrite("tmp.jpg", image);
|
||||
#else
|
||||
cv::imshow("Debug", image);
|
||||
cv::waitKey(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
HResult HFReleaseInspireFaceSession(HFSession handle) {
|
||||
if (handle == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
delete (HF_FaceAlgorithmSession*)handle;
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
HResult HFCreateInspireFaceSession(HFSessionCustomParameter parameter, HFDetectMode detectMode, HInt32 maxDetectFaceNum, HFSession *handle) {
|
||||
inspire::ContextCustomParameter param;
|
||||
param.enable_mask_detect = parameter.enable_mask_detect;
|
||||
param.enable_age = parameter.enable_age;
|
||||
param.enable_liveness = parameter.enable_liveness;
|
||||
param.enable_face_quality = parameter.enable_face_quality;
|
||||
param.enable_gender = parameter.enable_gender;
|
||||
param.enable_interaction_liveness = parameter.enable_interaction_liveness;
|
||||
param.enable_ir_liveness = parameter.enable_ir_liveness;
|
||||
param.enable_recognition = parameter.enable_recognition;
|
||||
inspire::DetectMode detMode = inspire::DETECT_MODE_IMAGE;
|
||||
if (detectMode == HF_DETECT_MODE_VIDEO) {
|
||||
detMode = inspire::DETECT_MODE_VIDEO;
|
||||
}
|
||||
|
||||
HF_FaceAlgorithmSession *ctx = new HF_FaceAlgorithmSession();
|
||||
auto ret = ctx->impl.Configuration(detMode, maxDetectFaceNum, param);
|
||||
if (ret != HSUCCEED) {
|
||||
delete ctx;
|
||||
*handle = nullptr;
|
||||
} else {
|
||||
*handle = ctx;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFCreateInspireFaceSessionOptional(HOption customOption, HFDetectMode detectMode, HInt32 maxDetectFaceNum, HFSession *handle) {
|
||||
inspire::ContextCustomParameter param;
|
||||
if (customOption & HF_ENABLE_FACE_RECOGNITION) {
|
||||
param.enable_recognition = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_LIVENESS) {
|
||||
param.enable_liveness = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_IR_LIVENESS) {
|
||||
param.enable_ir_liveness = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_AGE_PREDICT) {
|
||||
param.enable_age = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_GENDER_PREDICT) {
|
||||
param.enable_gender = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_MASK_DETECT) {
|
||||
param.enable_mask_detect = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_QUALITY) {
|
||||
param.enable_face_quality = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_INTERACTION) {
|
||||
param.enable_interaction_liveness = true;
|
||||
}
|
||||
inspire::DetectMode detMode = inspire::DETECT_MODE_IMAGE;
|
||||
if (detectMode == HF_DETECT_MODE_VIDEO) {
|
||||
detMode = inspire::DETECT_MODE_VIDEO;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = new HF_FaceAlgorithmSession();
|
||||
auto ret = ctx->impl.Configuration(detMode, maxDetectFaceNum, param);
|
||||
if (ret != HSUCCEED) {
|
||||
delete ctx;
|
||||
*handle = nullptr;
|
||||
} else {
|
||||
*handle = ctx;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFLaunchInspireFace(HPath resourcePath) {
|
||||
std::string path(resourcePath);
|
||||
return INSPIRE_LAUNCH->Load(resourcePath);
|
||||
}
|
||||
|
||||
HResult HFFeatureHubDataDisable() {
|
||||
return FEATURE_HUB->DisableHub();
|
||||
}
|
||||
|
||||
HResult HFFeatureHubDataEnable(HFFeatureHubConfiguration configuration) {
|
||||
inspire::DatabaseConfiguration param = {0};
|
||||
param.db_path = (configuration.dbPath != nullptr) ? std::string(configuration.dbPath) : std::string();
|
||||
param.enable_use_db = configuration.enablePersistence;
|
||||
param.feature_block_num = configuration.featureBlockNum;
|
||||
param.recognition_threshold = configuration.searchThreshold;
|
||||
param.search_mode = (SearchMode )configuration.searchMode;
|
||||
auto ret = FEATURE_HUB->EnableHub(param);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFSessionSetTrackPreviewSize(HFSession session, HInt32 previewSize) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
return ctx->impl.SetTrackPreviewSize(previewSize);
|
||||
}
|
||||
|
||||
HResult HFSessionSetFaceTrackMode(HFSession session, HFDetectMode detectMode) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
inspire::DetectMode detMode = inspire::DETECT_MODE_IMAGE;
|
||||
if (detectMode == HF_DETECT_MODE_VIDEO) {
|
||||
detMode = inspire::DETECT_MODE_VIDEO;
|
||||
}
|
||||
return ctx->impl.SetDetectMode(detMode);
|
||||
}
|
||||
|
||||
HResult HFSessionSetFaceDetectThreshold(HFSession session, HFloat threshold) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
return ctx->impl.SetFaceDetectThreshold(threshold);
|
||||
}
|
||||
|
||||
HResult HFExecuteFaceTrack(HFSession session, HFImageStream streamHandle, PHFMultipleFaceData results) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
if (streamHandle == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_CameraStream *stream = (HF_CameraStream* ) streamHandle;
|
||||
if (stream == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
auto ret = ctx->impl.FaceDetectAndTrack(stream->impl);
|
||||
results->detectedNum = ctx->impl.GetNumberOfFacesCurrentlyDetected();
|
||||
results->rects = (HFaceRect *) ctx->impl.GetFaceRectsCache().data();
|
||||
results->trackIds = (HInt32 *) ctx->impl.GetTrackIDCache().data();
|
||||
results->angles.pitch = (HFloat *) ctx->impl.GetPitchResultsCache().data();
|
||||
results->angles.roll = (HFloat *) ctx->impl.GetRollResultsCache().data();
|
||||
results->angles.yaw = (HFloat *) ctx->impl.GetYawResultsCache().data();
|
||||
results->tokens = (HFFaceBasicToken *) ctx->impl.GetFaceBasicDataCache().data();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFCopyFaceBasicToken(HFFaceBasicToken token, HPBuffer buffer, HInt32 bufferSize) {
|
||||
if (bufferSize < sizeof(inspire::HyperFaceData)) {
|
||||
return HERR_INVALID_BUFFER_SIZE;
|
||||
}
|
||||
std::memcpy(buffer, token.data, sizeof(inspire::HyperFaceData));
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFGetFaceBasicTokenSize(HPInt32 bufferSize) {
|
||||
*bufferSize = sizeof(inspire::HyperFaceData);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubFaceSearchThresholdSetting(float threshold) {
|
||||
FEATURE_HUB->SetRecognitionThreshold(threshold);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFaceFeatureExtract(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace, PHFFaceFeature feature) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
if (streamHandle == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_CameraStream *stream = (HF_CameraStream* ) streamHandle;
|
||||
if (stream == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
if (singleFace.data == nullptr || singleFace.size <= 0) {
|
||||
return HERR_INVALID_FACE_TOKEN;
|
||||
}
|
||||
inspire::FaceBasicData data;
|
||||
data.dataSize = singleFace.size;
|
||||
data.data = singleFace.data;
|
||||
auto ret = ctx->impl.FaceFeatureExtract(stream->impl, data);
|
||||
feature->size = ctx->impl.GetFaceFeatureCache().size();
|
||||
feature->data = (HFloat *)ctx->impl.GetFaceFeatureCache().data();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
HResult HFFaceFeatureExtractCpy(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace, HPFloat feature) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
if (streamHandle == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_CameraStream *stream = (HF_CameraStream* ) streamHandle;
|
||||
if (stream == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
if (singleFace.data == nullptr || singleFace.size <= 0) {
|
||||
return HERR_INVALID_FACE_TOKEN;
|
||||
}
|
||||
inspire::FaceBasicData data;
|
||||
data.dataSize = singleFace.size;
|
||||
data.data = singleFace.data;
|
||||
auto ret = ctx->impl.FaceFeatureExtract(stream->impl, data);
|
||||
for (int i = 0; i < ctx->impl.GetFaceFeatureCache().size(); ++i) {
|
||||
feature[i] = ctx->impl.GetFaceFeatureCache()[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HResult HFFaceComparison(HFFaceFeature feature1, HFFaceFeature feature2, HPFloat result) {
|
||||
if (feature1.data == nullptr || feature2.data == nullptr) {
|
||||
return HERR_INVALID_FACE_FEATURE;
|
||||
}
|
||||
if (feature1.size != feature2.size) {
|
||||
INSPIRE_LOGE("feature1.size: %d, feature2.size: %d", feature1.size, feature2.size);
|
||||
return HERR_INVALID_FACE_FEATURE;
|
||||
}
|
||||
*result = 0.0f;
|
||||
float res = -1.0f;
|
||||
auto ret = FEATURE_HUB->CosineSimilarity(feature1.data, feature2.data, feature1.size, res);
|
||||
*result = res;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFGetFeatureLength(HPInt32 num) {
|
||||
*num = FEATURE_HUB->GetFeatureNum();
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
HResult HFFeatureHubInsertFeature(HFFaceFeatureIdentity featureIdentity) {
|
||||
if (featureIdentity.feature->data == nullptr) {
|
||||
return HERR_INVALID_FACE_FEATURE;
|
||||
}
|
||||
std::vector<float> feat;
|
||||
feat.reserve(featureIdentity.feature->size);
|
||||
for (int i = 0; i < featureIdentity.feature->size; ++i) {
|
||||
feat.push_back(featureIdentity.feature->data[i]);
|
||||
}
|
||||
std::string tag(featureIdentity.tag);
|
||||
HInt32 ret = FEATURE_HUB->FaceFeatureInsertFromCustomId(feat, tag, featureIdentity.customId);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
HResult HFFeatureHubFaceSearch(HFFaceFeature searchFeature, HPFloat confidence, PHFFaceFeatureIdentity mostSimilar) {
|
||||
if (searchFeature.data == nullptr) {
|
||||
return HERR_INVALID_FACE_FEATURE;
|
||||
}
|
||||
std::vector<float> feat;
|
||||
feat.reserve(searchFeature.size);
|
||||
for (int i = 0; i < searchFeature.size; ++i) {
|
||||
feat.push_back(searchFeature.data[i]);
|
||||
}
|
||||
inspire::SearchResult result;
|
||||
HInt32 ret = FEATURE_HUB->SearchFaceFeature(feat, result);
|
||||
mostSimilar->feature = (HFFaceFeature* ) FEATURE_HUB->GetFaceFeaturePtrCache().get();
|
||||
mostSimilar->feature->data = (HFloat* ) FEATURE_HUB->GetSearchFaceFeatureCache().data();
|
||||
mostSimilar->feature->size = FEATURE_HUB->GetSearchFaceFeatureCache().size();
|
||||
mostSimilar->tag = FEATURE_HUB->GetStringCache();
|
||||
mostSimilar->customId = result.customId;
|
||||
*confidence = result.score;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubFaceSearchTopK(HFFaceFeature searchFeature, HInt32 topK, PHFSearchTopKResults results) {
|
||||
if (searchFeature.data == nullptr) {
|
||||
return HERR_INVALID_FACE_FEATURE;
|
||||
}
|
||||
std::vector<float> feat;
|
||||
feat.reserve(searchFeature.size);
|
||||
for (int i = 0; i < searchFeature.size; ++i) {
|
||||
feat.push_back(searchFeature.data[i]);
|
||||
}
|
||||
HInt32 ret = FEATURE_HUB->SearchFaceFeatureTopK(feat, topK);
|
||||
if (ret == HSUCCEED) {
|
||||
results->size = FEATURE_HUB->GetTopKConfidence().size();
|
||||
results->confidence = FEATURE_HUB->GetTopKConfidence().data();
|
||||
results->customIds = FEATURE_HUB->GetTopKCustomIdsCache().data();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubFaceRemove(HInt32 customId) {
|
||||
auto ret = FEATURE_HUB->FaceFeatureRemoveFromCustomId(customId);
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubFaceUpdate(HFFaceFeatureIdentity featureIdentity) {
|
||||
if (featureIdentity.feature->data == nullptr) {
|
||||
return HERR_INVALID_FACE_FEATURE;
|
||||
}
|
||||
std::vector<float> feat;
|
||||
feat.reserve(featureIdentity.feature->size);
|
||||
for (int i = 0; i < featureIdentity.feature->size; ++i) {
|
||||
feat.push_back(featureIdentity.feature->data[i]);
|
||||
}
|
||||
std::string tag(featureIdentity.tag);
|
||||
|
||||
auto ret = FEATURE_HUB->FaceFeatureUpdateFromCustomId(feat, tag, featureIdentity.customId);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubGetFaceIdentity(HInt32 customId, PHFFaceFeatureIdentity identity) {
|
||||
auto ret = FEATURE_HUB->GetFaceFeatureFromCustomId(customId);
|
||||
if (ret == HSUCCEED) {
|
||||
identity->tag = FEATURE_HUB->GetStringCache();
|
||||
identity->customId = customId;
|
||||
identity->feature = (HFFaceFeature* ) FEATURE_HUB->GetFaceFeaturePtrCache().get();
|
||||
identity->feature->data = (HFloat* ) FEATURE_HUB->GetFaceFeaturePtrCache()->data;
|
||||
identity->feature->size = FEATURE_HUB->GetFaceFeaturePtrCache()->dataSize;
|
||||
} else {
|
||||
identity->customId = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HResult HFMultipleFacePipelineProcess(HFSession session, HFImageStream streamHandle, PHFMultipleFaceData faces, HFSessionCustomParameter parameter) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
if (streamHandle == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_CameraStream *stream = (HF_CameraStream* ) streamHandle;
|
||||
if (stream == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
if (faces->detectedNum <= 0 || faces->tokens->data == nullptr) {
|
||||
return HERR_INVALID_FACE_LIST;
|
||||
}
|
||||
inspire::ContextCustomParameter param;
|
||||
param.enable_mask_detect = parameter.enable_mask_detect;
|
||||
param.enable_age = parameter.enable_age;
|
||||
param.enable_liveness = parameter.enable_liveness;
|
||||
param.enable_face_quality = parameter.enable_face_quality;
|
||||
param.enable_gender = parameter.enable_gender;
|
||||
param.enable_interaction_liveness = parameter.enable_interaction_liveness;
|
||||
param.enable_ir_liveness = parameter.enable_ir_liveness;
|
||||
param.enable_recognition = parameter.enable_recognition;
|
||||
|
||||
HResult ret;
|
||||
std::vector<inspire::HyperFaceData> data;
|
||||
data.resize(faces->detectedNum);
|
||||
for (int i = 0; i < faces->detectedNum; ++i) {
|
||||
auto &face = data[i];
|
||||
ret = DeserializeHyperFaceData((char* )faces->tokens[i].data, faces->tokens[i].size, face);
|
||||
if (ret != HSUCCEED) {
|
||||
return HERR_INVALID_FACE_TOKEN;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ctx->impl.FacesProcess(stream->impl, data, param);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
HResult HFMultipleFacePipelineProcessOptional(HFSession session, HFImageStream streamHandle, PHFMultipleFaceData faces, HInt32 customOption) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
if (streamHandle == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_CameraStream *stream = (HF_CameraStream* ) streamHandle;
|
||||
if (stream == nullptr) {
|
||||
return HERR_INVALID_IMAGE_STREAM_HANDLE;
|
||||
}
|
||||
if (faces->detectedNum <= 0 || faces->tokens->data == nullptr) {
|
||||
return HERR_INVALID_FACE_LIST;
|
||||
}
|
||||
|
||||
inspire::ContextCustomParameter param;
|
||||
if (customOption & HF_ENABLE_FACE_RECOGNITION) {
|
||||
param.enable_recognition = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_LIVENESS) {
|
||||
param.enable_liveness = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_IR_LIVENESS) {
|
||||
param.enable_ir_liveness = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_AGE_PREDICT) {
|
||||
param.enable_age = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_GENDER_PREDICT) {
|
||||
param.enable_gender = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_MASK_DETECT) {
|
||||
param.enable_mask_detect = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_QUALITY) {
|
||||
param.enable_face_quality = true;
|
||||
}
|
||||
if (customOption & HF_ENABLE_INTERACTION) {
|
||||
param.enable_interaction_liveness = true;
|
||||
}
|
||||
|
||||
|
||||
HResult ret;
|
||||
std::vector<inspire::HyperFaceData> data;
|
||||
data.resize(faces->detectedNum);
|
||||
for (int i = 0; i < faces->detectedNum; ++i) {
|
||||
auto &face = data[i];
|
||||
ret = DeserializeHyperFaceData((char* )faces->tokens[i].data, faces->tokens[i].size, face);
|
||||
if (ret != HSUCCEED) {
|
||||
return HERR_INVALID_FACE_TOKEN;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ctx->impl.FacesProcess(stream->impl, data, param);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
HResult HFGetRGBLivenessConfidence(HFSession session, PHFRGBLivenessConfidence confidence) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
|
||||
confidence->num = ctx->impl.GetRgbLivenessResultsCache().size();
|
||||
confidence->confidence = (HFloat* )ctx->impl.GetRgbLivenessResultsCache().data();
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFGetFaceMaskConfidence(HFSession session, PHFFaceMaskConfidence confidence) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
|
||||
confidence->num = ctx->impl.GetMaskResultsCache().size();
|
||||
confidence->confidence = (HFloat* )ctx->impl.GetMaskResultsCache().data();
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFGetFaceQualityConfidence(HFSession session, PHFFaceQualityConfidence confidence) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
|
||||
confidence->num = ctx->impl.GetFaceQualityScoresResultsCache().size();
|
||||
confidence->confidence = (HFloat* )ctx->impl.GetFaceQualityScoresResultsCache().data();
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFaceQualityDetect(HFSession session, HFFaceBasicToken singleFace, HFloat *confidence) {
|
||||
if (session == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
HF_FaceAlgorithmSession *ctx = (HF_FaceAlgorithmSession* ) session;
|
||||
if (ctx == nullptr) {
|
||||
return HERR_INVALID_CONTEXT_HANDLE;
|
||||
}
|
||||
|
||||
inspire::FaceBasicData data;
|
||||
data.dataSize = singleFace.size;
|
||||
data.data = singleFace.data;
|
||||
|
||||
auto ret = inspire::FaceContext::FaceQualityDetect(data, *confidence);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
HResult HFFeatureHubGetFaceCount(HInt32* count) {
|
||||
*count = FEATURE_HUB->GetFaceFeatureCount();
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFFeatureHubViewDBTable() {
|
||||
return FEATURE_HUB->ViewDBTable();
|
||||
}
|
||||
|
||||
|
||||
HResult HFQueryInspireFaceVersion(PHFInspireFaceVersion version) {
|
||||
version->major = std::stoi(INSPIRE_FACE_VERSION_MAJOR_STR);
|
||||
version->minor = std::stoi(INSPIRE_FACE_VERSION_MINOR_STR);
|
||||
version->patch = std::stoi(INSPIRE_FACE_VERSION_PATCH_STR);
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFSetLogLevel(HFLogLevel level) {
|
||||
INSPIRE_SET_LOG_LEVEL(LogLevel(level));
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
HResult HFLogDisable() {
|
||||
INSPIRE_SET_LOG_LEVEL(inspire::LOG_NONE);
|
||||
return HSUCCEED;
|
||||
}
|
||||
671
cpp-package/inspireface/cpp/inspireface/c_api/inspireface.h
Normal file
671
cpp-package/inspireface/cpp/inspireface/c_api/inspireface.h
Normal file
@@ -0,0 +1,671 @@
|
||||
//
|
||||
// Created by tunm on 2023/10/3.
|
||||
//
|
||||
|
||||
#ifndef HYPERFACEREPO_INSPIREFACE_H
|
||||
#define HYPERFACEREPO_INSPIREFACE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "intypedef.h"
|
||||
#include "herror.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifdef HYPER_BUILD_SHARED_LIB
|
||||
#define HYPER_CAPI_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define HYPER_CAPI_EXPORT
|
||||
#endif
|
||||
#else
|
||||
#define HYPER_CAPI_EXPORT __attribute__((visibility("default")))
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HF_ENABLE_NONE 0x00000000 ///< Flag to enable no features.
|
||||
#define HF_ENABLE_FACE_RECOGNITION 0x00000002 ///< Flag to enable face recognition feature.
|
||||
#define HF_ENABLE_LIVENESS 0x00000004 ///< Flag to enable RGB liveness detection feature.
|
||||
#define HF_ENABLE_IR_LIVENESS 0x00000008 ///< Flag to enable IR (Infrared) liveness detection feature.
|
||||
#define HF_ENABLE_MASK_DETECT 0x00000010 ///< Flag to enable mask detection feature.
|
||||
#define HF_ENABLE_AGE_PREDICT 0x00000020 ///< Flag to enable age prediction feature.
|
||||
#define HF_ENABLE_GENDER_PREDICT 0x00000040 ///< Flag to enable gender prediction feature.
|
||||
#define HF_ENABLE_QUALITY 0x00000080 ///< Flag to enable face quality assessment feature.
|
||||
#define HF_ENABLE_INTERACTION 0x00000100 ///< Flag to enable interaction feature.
|
||||
|
||||
|
||||
/**
|
||||
* Camera stream format.
|
||||
* Contains several common camera stream formats available in the market.
|
||||
*/
|
||||
typedef enum HFImageFormat {
|
||||
HF_STREAM_RGB = 0, ///< Image in RGB format.
|
||||
HF_STREAM_BGR = 1, ///< Image in BGR format (Opencv Mat default).
|
||||
HF_STREAM_RGBA = 2, ///< Image in RGB format with alpha channel.
|
||||
HF_STREAM_BGRA = 3, ///< Image in BGR format with alpha channel.
|
||||
HF_STREAM_YUV_NV12 = 4, ///< Image in YUV NV12 format.
|
||||
HF_STREAM_YUV_NV21 = 5, ///< Image in YUV NV21 format.
|
||||
} HFImageFormat;
|
||||
|
||||
|
||||
/**
|
||||
* Camera picture rotation mode.
|
||||
* To accommodate the rotation of certain devices, four image rotation modes are provided.
|
||||
*/
|
||||
typedef enum HFRotation {
|
||||
HF_CAMERA_ROTATION_0 = 0, ///< 0 degree rotation.
|
||||
HF_CAMERA_ROTATION_90 = 1, ///< 90 degree rotation.
|
||||
HF_CAMERA_ROTATION_180 = 2, ///< 180 degree rotation.
|
||||
HF_CAMERA_ROTATION_270 = 3, ///< 270 degree rotation.
|
||||
} HFRotation;
|
||||
|
||||
|
||||
/**
|
||||
* Image Buffer Data structure.
|
||||
* Defines the structure for image data stream.
|
||||
*/
|
||||
typedef struct HFImageData {
|
||||
uint8_t *data; ///< Pointer to the image data stream.
|
||||
HInt32 width; ///< Width of the image.
|
||||
HInt32 height; ///< Height of the image.
|
||||
HFImageFormat format; ///< Format of the image, indicating the data stream format to be parsed.
|
||||
HFRotation rotation; ///< Rotation angle of the image.
|
||||
} HFImageData, *PHFImageData;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Create a data buffer stream instantiation object.
|
||||
*
|
||||
* This function is used to create an instance of a data buffer stream with the given image data.
|
||||
*
|
||||
* @param data Pointer to the image buffer data structure.
|
||||
* @param handle Pointer to the stream handle that will be returned.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFCreateImageStream(PHFImageData data, HFImageStream *handle);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Release the instantiated DataBuffer object.
|
||||
*
|
||||
* This function is used to release the DataBuffer object that has been previously instantiated.
|
||||
*
|
||||
* @param streamHandle Pointer to the DataBuffer handle representing the camera stream component.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFReleaseImageStream(HFImageStream streamHandle);
|
||||
|
||||
/************************************************************************
|
||||
* Resource Function
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Launch InspireFace SDK
|
||||
* Start the InspireFace SDK at the initialization stage of your program, as it is global and designed to be used only once.
|
||||
* It serves as a prerequisite for other function interfaces, so it is essential to ensure it is initialized before calling any other APIs.
|
||||
* @param resourcePath Initializes the path to the resource file that needs to be loaded
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
* */
|
||||
HYPER_CAPI_EXPORT extern HResult HFLaunchInspireFace(HPath resourcePath);
|
||||
|
||||
/************************************************************************
|
||||
* FaceContext
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Struct for custom parameters in face recognition context.
|
||||
*
|
||||
* This struct holds various flags to enable or disable specific features
|
||||
* in the face recognition context, such as face recognition, liveness detection,
|
||||
* mask detection, age and gender prediction, etc.
|
||||
*/
|
||||
typedef struct HFSessionCustomParameter {
|
||||
HInt32 enable_recognition; ///< Enable face recognition feature.
|
||||
HInt32 enable_liveness; ///< Enable RGB liveness detection feature.
|
||||
HInt32 enable_ir_liveness; ///< Enable IR liveness detection feature.
|
||||
HInt32 enable_mask_detect; ///< Enable mask detection feature.
|
||||
HInt32 enable_age; ///< Enable age prediction feature.
|
||||
HInt32 enable_gender; ///< Enable gender prediction feature.
|
||||
HInt32 enable_face_quality; ///< Enable face quality detection feature.
|
||||
HInt32 enable_interaction_liveness; ///< Enable interaction for liveness detection feature.
|
||||
} HFSessionCustomParameter, *PHFSessionCustomParameter;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enumeration for face detection modes.
|
||||
*/
|
||||
typedef enum HFDetectMode {
|
||||
HF_DETECT_MODE_IMAGE, ///< Image detection mode, always detect.
|
||||
HF_DETECT_MODE_VIDEO, ///< Video detection mode, face tracking.
|
||||
} HFDetectMode;
|
||||
|
||||
/**
|
||||
* @brief Create a session from a resource file.
|
||||
*
|
||||
* @param parameter Custom parameters for session.
|
||||
* @param detectMode Detection mode to be used.
|
||||
* @param maxDetectFaceNum Maximum number of faces to detect.
|
||||
* @param handle Pointer to the context handle that will be returned.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFCreateInspireFaceSession(
|
||||
HFSessionCustomParameter parameter,
|
||||
HFDetectMode detectMode,
|
||||
HInt32 maxDetectFaceNum,
|
||||
HFSession *handle
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Create a session from a resource file with additional options.
|
||||
*
|
||||
* @param customOption Custom option for additional configuration.
|
||||
* @param detectMode Detection mode to be used.
|
||||
* @param maxDetectFaceNum Maximum number of faces to detect.
|
||||
* @param handle Pointer to the context handle that will be returned.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFCreateInspireFaceSessionOptional(
|
||||
HOption customOption,
|
||||
HFDetectMode detectMode,
|
||||
HInt32 maxDetectFaceNum,
|
||||
HFSession *handle
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Release the session.
|
||||
*
|
||||
* @param handle Handle to the session to be released.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFReleaseInspireFaceSession(HFSession handle);
|
||||
|
||||
/**
|
||||
* @brief Struct representing a basic token for face data.
|
||||
*
|
||||
* This struct holds the size and data pointer for a basic token associated with face data.
|
||||
*/
|
||||
typedef struct HFFaceBasicToken {
|
||||
HInt32 size; ///< Size of the token.
|
||||
HPVoid data; ///< Pointer to the token data.
|
||||
} HFFaceBasicToken, *PHFFaceBasicToken;
|
||||
|
||||
/**
|
||||
* @brief Struct for face Euler angles.
|
||||
*
|
||||
* This struct represents the Euler angles (roll, yaw, pitch) for face orientation.
|
||||
*/
|
||||
typedef struct HFFaceEulerAngle {
|
||||
HFloat *roll; ///< Roll angle of the face.
|
||||
HFloat *yaw; ///< Yaw angle of the face.
|
||||
HFloat *pitch; ///< Pitch angle of the face.
|
||||
} HFFaceEulerAngle;
|
||||
|
||||
/**
|
||||
* @brief Struct for holding data of multiple detected faces.
|
||||
*
|
||||
* This struct stores the data related to multiple faces detected, including the number of faces,
|
||||
* their bounding rectangles, track IDs, angles, and tokens.
|
||||
*/
|
||||
typedef struct HFMultipleFaceData {
|
||||
HInt32 detectedNum; ///< Number of faces detected.
|
||||
HFaceRect *rects; ///< Array of bounding rectangles for each face.
|
||||
HInt32 *trackIds; ///< Array of track IDs for each face.
|
||||
HFFaceEulerAngle angles; ///< Euler angles for each face.
|
||||
PHFFaceBasicToken tokens; ///< Tokens associated with each face.
|
||||
} HFMultipleFaceData, *PHFMultipleFaceData;
|
||||
|
||||
/**
|
||||
* @brief Set the track preview size in the session, it works with face detection and tracking algorithms.
|
||||
* Default preview size is 192(px).
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param previewSize The size of the preview for tracking.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFSessionSetTrackPreviewSize(HFSession session, HInt32 previewSize);
|
||||
|
||||
/**
|
||||
* @brief Set the face track mode in the session.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param detectMode The mode of the detection mode for tracking.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFSessionSetFaceTrackMode(HFSession session, HFDetectMode detectMode);
|
||||
|
||||
/**
|
||||
* @brief Set the face detect threshold in the session.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param detectMode The mode of the detection mode for tracking.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFSessionSetFaceDetectThreshold(HFSession session, HFloat threshold);
|
||||
|
||||
/**
|
||||
* @brief Run face tracking in the session.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param streamHandle Handle to the data buffer representing the camera stream component.
|
||||
* @param results Pointer to the structure where the results will be stored.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFExecuteFaceTrack(HFSession session, HFImageStream streamHandle, PHFMultipleFaceData results);
|
||||
|
||||
/**
|
||||
* @brief Copies the data from a HF_FaceBasicToken to a specified buffer.
|
||||
*
|
||||
* This function copies the data pointed to by the HF_FaceBasicToken's data field
|
||||
* into a user-provided buffer. The caller is responsible for ensuring that the buffer
|
||||
* is large enough to hold the data being copied.
|
||||
*
|
||||
* @param token The HF_FaceBasicToken containing the data to be copied.
|
||||
* @param buffer The buffer where the data will be copied to.
|
||||
* @param bufferSize The size of the buffer provided by the caller. Must be large enough
|
||||
* to hold the data pointed to by the token's data field.
|
||||
* @return HResult indicating the success or failure of the operation. Returns HSUCCEED
|
||||
* if the operation was successful, or an error code if the buffer was too small
|
||||
* or if any other error occurred.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFCopyFaceBasicToken(HFFaceBasicToken token, HPBuffer buffer, HInt32 bufferSize);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the size of the data contained in a HF_FaceBasicToken.
|
||||
*
|
||||
* This function is used to query the size of the data that a HF_FaceBasicToken is
|
||||
* expected to contain. This is useful for allocating a buffer of appropriate size
|
||||
* before copying data from a HF_FaceBasicToken.
|
||||
*
|
||||
* @param bufferSize Pointer to an integer where the size of the data will be stored.
|
||||
* On successful completion, this will contain the size of the data in bytes.
|
||||
* @return HResult indicating the success or failure of the operation. Returns HSUCCEED
|
||||
* if the operation was successful, or an error code if it failed.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFGetFaceBasicTokenSize(HPInt32 bufferSize);
|
||||
|
||||
/************************************************************************
|
||||
* Face Recognition
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Struct representing a face feature.
|
||||
*
|
||||
* This struct holds the data related to a face feature, including size and actual feature data.
|
||||
*/
|
||||
typedef struct HFFaceFeature {
|
||||
HInt32 size; ///< Size of the feature data.
|
||||
HPFloat data; ///< Pointer to the feature data.
|
||||
} HFFaceFeature, *PHFFaceFeature;
|
||||
|
||||
/**
|
||||
* @brief Extract a face feature from a given face.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param streamHandle Handle to the data buffer representing the camera stream component.
|
||||
* @param singleFace Basic token representing a single face.
|
||||
* @param feature Pointer to the extracted face feature.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult
|
||||
HFFaceFeatureExtract(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace, PHFFaceFeature feature);
|
||||
|
||||
/**
|
||||
* @brief Extract a face feature from a given face and copy it to the provided feature buffer.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param streamHandle Handle to the data buffer representing the camera stream component.
|
||||
* @param singleFace Basic token representing a single face.
|
||||
* @param feature Pointer to the buffer where the extracted feature will be copied.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult
|
||||
HFFaceFeatureExtractCpy(HFSession session, HFImageStream streamHandle, HFFaceBasicToken singleFace, HPFloat feature);
|
||||
|
||||
/************************************************************************
|
||||
* Feature Hub
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Select the search mode in the process of face recognition search,
|
||||
* and different modes will affect the execution efficiency and results
|
||||
* */
|
||||
typedef enum HFSearchMode {
|
||||
HF_SEARCH_MODE_EAGER = 0, // Eager mode: Stops when a vector meets the threshold.
|
||||
HF_SEARCH_MODE_EXHAUSTIVE, // Exhaustive mode: Searches until the best match is found.
|
||||
} HFSearchMode;
|
||||
|
||||
/**
|
||||
* @brief Struct for database configuration.
|
||||
*
|
||||
* This struct holds the configuration settings for using a database in the face recognition context.
|
||||
*/
|
||||
typedef struct HFFeatureHubConfiguration {
|
||||
HInt32 featureBlockNum; ///< The order of magnitude of face feature database is N * 512, and 20 is recommended by default
|
||||
HInt32 enablePersistence; ///< Flag to enable or disable the use of the database.
|
||||
HString dbPath; ///< Path to the database file.
|
||||
float searchThreshold; ///< Threshold for face search
|
||||
HFSearchMode searchMode; ///< Mode of face search
|
||||
} HFFeatureHubConfiguration;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A lightweight face feature vector management.
|
||||
* @details FeatureHub is a built-in global lightweight face feature vector management functionality provided in the InspireFace-SDK.
|
||||
* It supports basic face feature search, deletion, and modification functions, and offers two optional data storage modes:
|
||||
* an in-memory model and a persistence model. If you have simple storage needs, you can enable it.
|
||||
*
|
||||
* @param configuration FeatureHub configuration details.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubDataEnable(HFFeatureHubConfiguration configuration);
|
||||
|
||||
/**
|
||||
* @brief Disable the global FeatureHub feature, and you can enable it again if needed.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
* */
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubDataDisable();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Struct representing the identity of a face feature.
|
||||
*
|
||||
* This struct associates a custom identifier and a tag with a specific face feature.
|
||||
*/
|
||||
typedef struct HFFaceFeatureIdentity {
|
||||
HInt32 customId; ///< Custom identifier for the face feature.
|
||||
HString tag; ///< Tag associated with the face feature.
|
||||
PHFFaceFeature feature; ///< Pointer to the face feature.
|
||||
} HFFaceFeatureIdentity, *PHFFaceFeatureIdentity;
|
||||
|
||||
/**
|
||||
* Search structure for top-k mode
|
||||
* */
|
||||
typedef struct HFSearchTopKResults {
|
||||
HInt32 size; ///< The number of faces searched
|
||||
HPFloat confidence; ///< Search confidence(it has already been filtered once by the threshold)
|
||||
HPInt32 customIds; ///< fACE customIds
|
||||
} HFSearchTopKResults, *PHFSearchTopKResults;
|
||||
|
||||
/**
|
||||
* @brief Set the face recognition search threshold.
|
||||
*
|
||||
* This function sets the threshold for face recognition, which determines the sensitivity
|
||||
* of the recognition process. A lower threshold may yield more matches but with less confidence.
|
||||
*
|
||||
* @param threshold The threshold value to set for face recognition (default is 0.48, suitable for access control scenarios).
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubFaceSearchThresholdSetting(float threshold);
|
||||
|
||||
/**
|
||||
* @brief Perform a one-to-one comparison of two face features.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param feature1 The first face feature for comparison.
|
||||
* @param feature2 The second face feature for comparison.
|
||||
* @param result Pointer to the floating-point value where the comparison result will be stored.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFaceComparison(HFFaceFeature feature1, HFFaceFeature feature2, HPFloat result);
|
||||
|
||||
/**
|
||||
* @brief Get the length of the face feature.
|
||||
*
|
||||
* @param num Pointer to an integer where the length of the feature will be stored.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFGetFeatureLength(HPInt32 num);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Insert a face feature identity into the features group.
|
||||
*
|
||||
* @param featureIdentity The face feature identity to be inserted.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubInsertFeature(HFFaceFeatureIdentity featureIdentity);
|
||||
|
||||
/**
|
||||
* @brief Search for the most similar face feature in the features group.
|
||||
*
|
||||
* @param searchFeature The face feature to be searched.
|
||||
* @param confidence Pointer to a floating-point value where the confidence level of the match will be stored.
|
||||
* @param mostSimilar Pointer to the most similar face feature identity found.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubFaceSearch(HFFaceFeature searchFeature, HPFloat confidence, PHFFaceFeatureIdentity mostSimilar);
|
||||
|
||||
/**
|
||||
* @brief Search for the most similar k facial features in the feature group
|
||||
*
|
||||
* @param searchFeature The face feature to be searched.
|
||||
* @param confidence topK Maximum number of searches
|
||||
* @param PHFSearchTopKResults Output search result
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubFaceSearchTopK(HFFaceFeature searchFeature, HInt32 topK, PHFSearchTopKResults results);
|
||||
|
||||
/**
|
||||
* @brief Remove a face feature from the features group based on custom ID.
|
||||
*
|
||||
* @param customId The custom ID of the feature to be removed.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubFaceRemove(HInt32 customId);
|
||||
|
||||
/**
|
||||
* @brief Update a face feature identity in the features group.
|
||||
*
|
||||
* @param featureIdentity The face feature identity to be updated.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubFaceUpdate(HFFaceFeatureIdentity featureIdentity);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a face feature identity from the features group based on custom ID.
|
||||
*
|
||||
* @param customId The custom ID of the feature.
|
||||
* @param identity Pointer to the face feature identity to be retrieved.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubGetFaceIdentity(HInt32 customId, PHFFaceFeatureIdentity identity);
|
||||
|
||||
/**
|
||||
* @brief Get the count of face features in the features group.
|
||||
*
|
||||
* @param count Pointer to an integer where the count of features will be stored.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubGetFaceCount(HInt32 *count);
|
||||
|
||||
/**
|
||||
* @brief View the face database table.
|
||||
*
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFeatureHubViewDBTable();
|
||||
|
||||
/************************************************************************
|
||||
* Face Pipeline
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Process multiple faces in a pipeline.
|
||||
*
|
||||
* This function processes multiple faces detected in an image or video frame, applying
|
||||
* various face recognition and analysis features as specified in the parameters.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param streamHandle Handle to the data buffer representing the camera stream component.
|
||||
* @param faces Pointer to the structure containing data of multiple detected faces.
|
||||
* @param parameter Custom parameters for processing the faces.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult
|
||||
HFMultipleFacePipelineProcess(HFSession session, HFImageStream streamHandle, PHFMultipleFaceData faces,
|
||||
HFSessionCustomParameter parameter);
|
||||
|
||||
/**
|
||||
* @brief Process multiple faces in a pipeline with an optional custom option.
|
||||
*
|
||||
* Similar to HFMultipleFacePipelineProcess, but allows for additional custom options
|
||||
* to modify the face processing behavior.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param streamHandle Handle to the data buffer representing the camera stream component.
|
||||
* @param faces Pointer to the structure containing data of multiple detected faces.
|
||||
* @param customOption An integer representing a custom option for processing.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult
|
||||
HFMultipleFacePipelineProcessOptional(HFSession session, HFImageStream streamHandle,
|
||||
PHFMultipleFaceData faces, HInt32 customOption);
|
||||
|
||||
/**
|
||||
* @brief Struct representing RGB liveness confidence.
|
||||
*
|
||||
* This struct holds the number of faces and the confidence level of liveness detection
|
||||
* for each face, using RGB analysis.
|
||||
*/
|
||||
typedef struct HFRGBLivenessConfidence {
|
||||
HInt32 num; ///< Number of faces detected.
|
||||
HPFloat confidence; ///< Confidence level of RGB liveness detection for each face.
|
||||
} HFRGBLivenessConfidence, *PHFRGBLivenessConfidence;
|
||||
|
||||
/**
|
||||
* @brief Get the RGB liveness confidence.
|
||||
*
|
||||
* This function retrieves the confidence level of RGB liveness detection for faces detected
|
||||
* in the current context.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param confidence Pointer to the structure where RGB liveness confidence data will be stored.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult
|
||||
HFGetRGBLivenessConfidence(HFSession session, PHFRGBLivenessConfidence confidence);
|
||||
|
||||
/**
|
||||
* @brief Struct representing face mask confidence.
|
||||
*
|
||||
* This struct holds the number of faces and the confidence level of mask detection
|
||||
* for each face.
|
||||
*/
|
||||
typedef struct HFFaceMaskConfidence {
|
||||
HInt32 num; ///< Number of faces detected.
|
||||
HPFloat confidence; ///< Confidence level of mask detection for each face.
|
||||
} HFFaceMaskConfidence, *PHFFaceMaskConfidence;
|
||||
|
||||
/**
|
||||
* @brief Get the face mask confidence.
|
||||
*
|
||||
* This function retrieves the confidence level of mask detection for faces detected
|
||||
* in the current context.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param confidence Pointer to the structure where face mask confidence data will be stored.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFGetFaceMaskConfidence(HFSession session, PHFFaceMaskConfidence confidence);
|
||||
|
||||
/**
|
||||
* @brief Struct representing face quality predict confidence.
|
||||
*
|
||||
* This struct holds the number of faces and the confidence level of face quality predict
|
||||
* for each face.
|
||||
*/
|
||||
typedef struct HFFaceQualityConfidence {
|
||||
HInt32 num; ///< Number of faces detected.
|
||||
HPFloat confidence; ///< Confidence level of face quality predict for each face.
|
||||
} HFFaceQualityConfidence, *PHFFaceQualityConfidence;
|
||||
|
||||
/**
|
||||
* @brief Get the face quality predict confidence.
|
||||
*
|
||||
* This function retrieves the confidence level of face quality predict for faces detected
|
||||
* in the current context.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param confidence Pointer to the structure where face mask confidence data will be stored.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFGetFaceQualityConfidence(HFSession session, PHFFaceQualityConfidence confidence);
|
||||
|
||||
/**
|
||||
* @brief Detect the quality of a face in an image.
|
||||
*
|
||||
* This function assesses the quality of a detected face, such as its clarity and visibility.
|
||||
*
|
||||
* @param session Handle to the session.
|
||||
* @param singleFace A token representing a single face.
|
||||
* @param confidence Pointer to a floating-point value where the quality confidence will be stored.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFFaceQualityDetect(HFSession session, HFFaceBasicToken singleFace, HFloat *confidence);
|
||||
|
||||
/************************************************************************
|
||||
* System Function
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Structure representing the version information of the InspireFace library.
|
||||
*/
|
||||
typedef struct HFInspireFaceVersion {
|
||||
int major; ///< Major version number.
|
||||
int minor; ///< Minor version number.
|
||||
int patch; ///< Patch version number.
|
||||
} HFInspireFaceVersion, *PHFInspireFaceVersion;
|
||||
|
||||
/**
|
||||
* @brief Function to query the version information of the InspireFace library.
|
||||
*
|
||||
* This function retrieves the version information of the InspireFace library.
|
||||
*
|
||||
* @param version Pointer to the structure where the version information will be stored.
|
||||
* @return HResult indicating the success or failure of the operation.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern HResult HFQueryInspireFaceVersion(PHFInspireFaceVersion version);
|
||||
|
||||
/**
|
||||
* @brief SDK built-in log level mode
|
||||
* */
|
||||
typedef enum HFLogLevel {
|
||||
HF_LOG_NONE = 0, // No logging, disables all log output
|
||||
HF_LOG_DEBUG, // Debug level for detailed system information mostly useful for developers
|
||||
HF_LOG_INFO, // Information level for general system information about operational status
|
||||
HF_LOG_WARN, // Warning level for non-critical issues that might need attention
|
||||
HF_LOG_ERROR, // Error level for error events that might still allow the application to continue running
|
||||
HF_LOG_FATAL // Fatal level for severe error events that will presumably lead the application to abort
|
||||
} HFLogLevel;
|
||||
|
||||
/**
|
||||
* @brief Set the log level built into the SDK.The default is HF LOG DEBUG
|
||||
* */
|
||||
HYPER_CAPI_EXPORT extern HResult HFSetLogLevel(HFLogLevel level);
|
||||
|
||||
/**
|
||||
* @brief Disable the log function. Like HFSetLogLevel(HF_LOG_NONE)
|
||||
* */
|
||||
HYPER_CAPI_EXPORT extern HResult HFLogDisable();
|
||||
|
||||
/********************************DEBUG Utils****************************************/
|
||||
|
||||
/**
|
||||
* @brief Display an image stream for debugging purposes.
|
||||
*
|
||||
* This function is used for debugging, allowing the visualization of the image stream
|
||||
* as it is being processed. It can be useful to understand the data being received
|
||||
* from the camera or image source.
|
||||
*
|
||||
* @param streamHandle Handle to the data buffer representing the camera stream component.
|
||||
*/
|
||||
HYPER_CAPI_EXPORT extern void HFDeBugImageStreamImShow(HFImageStream streamHandle);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif //HYPERFACEREPO_INSPIREFACE_H
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Created by tunm on 2023/10/3.
|
||||
//
|
||||
|
||||
#ifndef HYPERFACEREPO_INSPIREFACE_INTERNAL_H
|
||||
#define HYPERFACEREPO_INSPIREFACE_INTERNAL_H
|
||||
|
||||
#include "face_context.h"
|
||||
|
||||
typedef struct HF_FaceAlgorithmSession {
|
||||
inspire::FaceContext impl; ///< Implementation of the face context.
|
||||
} HF_FaceAlgorithmSession; ///< Handle for managing face context.
|
||||
|
||||
typedef struct HF_CameraStream {
|
||||
inspire::CameraStream impl; ///< Implementation of the camera stream.
|
||||
} HF_CameraStream; ///< Handle for managing camera stream.
|
||||
|
||||
|
||||
#endif //HYPERFACEREPO_INSPIREFACE_INTERNAL_H
|
||||
35
cpp-package/inspireface/cpp/inspireface/c_api/intypedef.h
Normal file
35
cpp-package/inspireface/cpp/inspireface/c_api/intypedef.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Created by tunm on 2023/10/3.
|
||||
//
|
||||
|
||||
#ifndef HYPERFACEREPO_INTYPEDEF_H
|
||||
#define HYPERFACEREPO_INTYPEDEF_H
|
||||
|
||||
typedef void* HPVoid; ///< Pointer to Void.
|
||||
typedef void* HFImageStream; ///< Handle for image.
|
||||
typedef void* HFSession; ///< Handle for context.
|
||||
typedef long HLong; ///< Long integer.
|
||||
typedef float HFloat; ///< Single-precision floating point.
|
||||
typedef float* HPFloat; ///< Pointer to Single-precision floating point.
|
||||
typedef double HDouble; ///< Double-precision floating point.
|
||||
typedef unsigned char HUInt8; ///< Unsigned 8-bit integer.
|
||||
typedef signed int HInt32; ///< Signed 32-bit integer.
|
||||
typedef signed int HOption; ///< Signed 32-bit integer option.
|
||||
typedef signed int* HPInt32; ///< Pointer to signed 32-bit integer.
|
||||
typedef long HResult; ///< Result code.
|
||||
typedef char* HString; ///< String.
|
||||
typedef const char* HPath; ///< Const String.
|
||||
typedef char HBuffer; ///< Character.
|
||||
typedef char* HPBuffer; ///< Pointer Character.
|
||||
typedef long HSize; ///< Size
|
||||
typedef long* HPSize; ///< Pointer Size
|
||||
|
||||
typedef struct HFaceRect {
|
||||
HInt32 x; ///< X-coordinate of the top-left corner of the rectangle.
|
||||
HInt32 y; ///< Y-coordinate of the top-left corner of the rectangle.
|
||||
HInt32 width; ///< Width of the rectangle.
|
||||
HInt32 height; ///< Height of the rectangle.
|
||||
} HFaceRect; ///< Rectangle representing a face region.
|
||||
|
||||
|
||||
#endif //HYPERFACEREPO_INTYPEDEF_H
|
||||
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// Created by tunm on 2023/9/17.
|
||||
//
|
||||
|
||||
#ifndef HYPERFACEREPO_DATATOOLS_H
|
||||
#define HYPERFACEREPO_DATATOOLS_H
|
||||
#include "opencv2/opencv.hpp"
|
||||
#include "face_data_type.h"
|
||||
#include "../face_info/face_object.h"
|
||||
#include "herror.h"
|
||||
#include "data_type.h"
|
||||
|
||||
// Define the namespace "inspire" for encapsulation
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @brief Print the transformation matrix.
|
||||
* @param matrix The transformation matrix to print.
|
||||
*/
|
||||
inline void PrintTransMatrix(const TransMatrix& matrix) {
|
||||
std::cout << "Transformation Matrix:" << std::endl;
|
||||
std::cout << "m00: " << matrix.m00 << "\t";
|
||||
std::cout << "m01: " << matrix.m01 << "\t";
|
||||
std::cout << "tx: " << matrix.tx << std::endl;
|
||||
|
||||
std::cout << "m10: " << matrix.m10 << "\t";
|
||||
std::cout << "m11: " << matrix.m11 << "\t";
|
||||
std::cout << "ty: " << matrix.ty << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print HyperFaceData structure.
|
||||
* @param data The HyperFaceData structure to print.
|
||||
*/
|
||||
inline void INSPIRE_API PrintHyperFaceData(const HyperFaceData& data) {
|
||||
std::cout << "Track State: " << data.trackState << std::endl;
|
||||
std::cout << "In Group Index: " << data.inGroupIndex << std::endl;
|
||||
std::cout << "Track ID: " << data.trackId << std::endl;
|
||||
std::cout << "Track Count: " << data.trackCount << std::endl;
|
||||
|
||||
std::cout << "Face Rectangle:" << std::endl;
|
||||
std::cout << "x: " << data.rect.x << "\t";
|
||||
std::cout << "y: " << data.rect.y << "\t";
|
||||
std::cout << "width: " << data.rect.width << "\t";
|
||||
std::cout << "height: " << data.rect.height << std::endl;
|
||||
|
||||
PrintTransMatrix(data.trans);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a FaceObject to HyperFaceData.
|
||||
* @param obj The FaceObject to convert.
|
||||
* @param group_index The group index.
|
||||
* @return The converted HyperFaceData structure.
|
||||
*/
|
||||
inline HyperFaceData INSPIRE_API FaceObjectToHyperFaceData(const FaceObject& obj, int group_index = -1) {
|
||||
HyperFaceData data;
|
||||
// Face rect
|
||||
data.rect.x = obj.bbox_.x;
|
||||
data.rect.y = obj.bbox_.y;
|
||||
data.rect.width = obj.bbox_.width;
|
||||
data.rect.height = obj.bbox_.height;
|
||||
// Trans matrix
|
||||
data.trans.m00 = obj.getTransMatrix().at<double>(0, 0);
|
||||
data.trans.m01 = obj.getTransMatrix().at<double>(0, 1);
|
||||
data.trans.m10 = obj.getTransMatrix().at<double>(1, 0);
|
||||
data.trans.m11 = obj.getTransMatrix().at<double>(1, 1);
|
||||
data.trans.tx = obj.getTransMatrix().at<double>(0, 2);
|
||||
data.trans.ty = obj.getTransMatrix().at<double>(1, 2);
|
||||
// KetPoints five
|
||||
if (!obj.high_result.lmk.empty()) {
|
||||
for (int i = 0; i < obj.high_result.lmk.size(); ++i) {
|
||||
data.keyPoints[i].x = obj.high_result.lmk[i].x;
|
||||
data.keyPoints[i].y = obj.high_result.lmk[i].y;
|
||||
}
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
data.quality[i] = obj.high_result.lmk_quality[i];
|
||||
}
|
||||
// LOGD("HIGHT");
|
||||
} else {
|
||||
for (int i = 0; i < obj.keyPointFive.size(); ++i) {
|
||||
data.keyPoints[i].x = obj.keyPointFive[i].x;
|
||||
data.keyPoints[i].y = obj.keyPointFive[i].y;
|
||||
}
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
data.quality[i] = -1.0f;
|
||||
}
|
||||
}
|
||||
// Basic data
|
||||
data.inGroupIndex = group_index;
|
||||
data.trackCount = obj.tracking_count_;
|
||||
data.trackId = obj.GetTrackingId();
|
||||
data.trackState = obj.TrackingState();
|
||||
// Face 3D Angle
|
||||
data.face3DAngle.pitch = obj.high_result.pitch;
|
||||
data.face3DAngle.roll = obj.high_result.roll;
|
||||
data.face3DAngle.yaw = obj.high_result.yaw;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a TransMatrix to a cv::Mat.
|
||||
* @param trans The TransMatrix to convert.
|
||||
* @return The converted cv::Mat.
|
||||
*/
|
||||
inline cv::Mat INSPIRE_API TransMatrixToMat(const TransMatrix& trans) {
|
||||
cv::Mat mat(2, 3, CV_64F);
|
||||
mat.at<double>(0, 0) = trans.m00;
|
||||
mat.at<double>(0, 1) = trans.m01;
|
||||
mat.at<double>(1, 0) = trans.m10;
|
||||
mat.at<double>(1, 1) = trans.m11;
|
||||
mat.at<double>(0, 2) = trans.tx;
|
||||
mat.at<double>(1, 2) = trans.ty;
|
||||
return mat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a FaceRect to cv::Rect.
|
||||
* @param faceRect The FaceRect to convert.
|
||||
* @return The converted cv::Rect.
|
||||
*/
|
||||
inline cv::Rect INSPIRE_API FaceRectToRect(const FaceRect& faceRect) {
|
||||
return {faceRect.x, faceRect.y, faceRect.width, faceRect.height};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a Point2F to cv::Point2f.
|
||||
* @param point The Point2F to convert.
|
||||
* @return The converted cv::Point2f.
|
||||
*/
|
||||
inline cv::Point2f INSPIRE_API HPointToPoint2f(const Point2F& point) {
|
||||
return {point.x, point.y};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize HyperFaceData to a byte stream.
|
||||
* @param data The HyperFaceData to serialize.
|
||||
* @param byteArray The output byte stream.
|
||||
* @return The result code.
|
||||
*/
|
||||
inline int32_t INSPIRE_API SerializeHyperFaceData(const HyperFaceData& data, ByteArray& byteArray) {
|
||||
byteArray.reserve(sizeof(data));
|
||||
|
||||
// Serialize the HyperFaceData structure itself
|
||||
const char* dataBytes = reinterpret_cast<const char*>(&data);
|
||||
byteArray.insert(byteArray.end(), dataBytes, dataBytes + sizeof(data));
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize a byte stream to HyperFaceData.
|
||||
* @param byteArray The input byte stream.
|
||||
* @param data The output HyperFaceData structure.
|
||||
* @return The result code.
|
||||
*/
|
||||
inline int32_t INSPIRE_API DeserializeHyperFaceData(const ByteArray& byteArray, HyperFaceData &data) {
|
||||
// Check if the byte stream size is sufficient
|
||||
if (byteArray.size() >= sizeof(data)) {
|
||||
// Copy data from the byte stream to the HyperFaceData structure
|
||||
std::memcpy(&data, byteArray.data(), sizeof(data));
|
||||
} else {
|
||||
INSPIRE_LOGE("The byte stream size is insufficient to restore HyperFaceData");
|
||||
return HERR_SESS_FACE_DATA_ERROR;
|
||||
}
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deserialize a byte stream to HyperFaceData.
|
||||
* @param byteArray The input byte stream as a character array.
|
||||
* @param byteCount The size of the byte stream.
|
||||
* @param data The output HyperFaceData structure.
|
||||
* @return The result code.
|
||||
*/
|
||||
inline int32_t INSPIRE_API DeserializeHyperFaceData(const char* byteArray, size_t byteCount, HyperFaceData& data) {
|
||||
// Check if the byte stream size is sufficient
|
||||
if (byteCount >= sizeof(data)) {
|
||||
// Copy data from the byte stream to the HyperFaceData structure
|
||||
std::memcpy(&data, byteArray, sizeof(data));
|
||||
} else {
|
||||
INSPIRE_LOGE("The byte stream size is insufficient to restore HyperFaceData");
|
||||
return HERR_SESS_FACE_DATA_ERROR;
|
||||
}
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
} // namespace hyper
|
||||
#endif //HYPERFACEREPO_DATATOOLS_H
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Created by tunm on 2023/9/17.
|
||||
//
|
||||
|
||||
// Include guard to prevent double inclusion of this header file
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_FACEDATATYPE_H
|
||||
#define HYPERFACEREPO_FACEDATATYPE_H
|
||||
|
||||
// Include the necessary header files
|
||||
#include "../../data_type.h"
|
||||
#include "../face_info/face_object.h"
|
||||
|
||||
// Define the namespace "inspire" for encapsulation
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* Struct to represent 3D angles of a face.
|
||||
*/
|
||||
typedef struct Face3DAngle {
|
||||
float roll; ///< Roll angle
|
||||
float yaw; ///< Yaw angle
|
||||
float pitch; ///< Pitch angle
|
||||
} Face3DAngle;
|
||||
|
||||
/**
|
||||
* Struct to represent the rectangle coordinates of a face.
|
||||
*/
|
||||
typedef struct FaceRect {
|
||||
int x; ///< X-coordinate of the top-left corner
|
||||
int y; ///< Y-coordinate of the top-left corner
|
||||
int width; ///< Width of the rectangle
|
||||
int height; ///< Height of the rectangle
|
||||
} FaceRect;
|
||||
|
||||
/**
|
||||
* Struct to represent 2D point coordinates.
|
||||
*/
|
||||
typedef struct Point2F {
|
||||
float x; ///< X-coordinate
|
||||
float y; ///< Y-coordinate
|
||||
} HPoint;
|
||||
|
||||
/**
|
||||
* Struct to represent a 2D transformation matrix.
|
||||
*/
|
||||
typedef struct TransMatrix {
|
||||
double m00; ///< Element (0,0) of the matrix
|
||||
double m01; ///< Element (0,1) of the matrix
|
||||
double m10; ///< Element (1,0) of the matrix
|
||||
double m11; ///< Element (1,1) of the matrix
|
||||
double tx; ///< Translation in the X-axis
|
||||
double ty; ///< Translation in the Y-axis
|
||||
} TransMatrix;
|
||||
|
||||
/**
|
||||
* Struct to represent hyper face data.
|
||||
*/
|
||||
typedef struct HyperFaceData {
|
||||
int trackState; ///< Track state
|
||||
int inGroupIndex; ///< Index within a group
|
||||
int trackId; ///< Track ID
|
||||
int trackCount; ///< Track count
|
||||
FaceRect rect; ///< Face rectangle
|
||||
TransMatrix trans; ///< Transformation matrix
|
||||
Point2F keyPoints[5]; ///< Key points (e.g., landmarks)
|
||||
Face3DAngle face3DAngle; ///< 3D face angles
|
||||
float quality[5]; ///< Quality values for key points
|
||||
} HyperFaceData;
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif //HYPERFACEREPO_FACEDATATYPE_H
|
||||
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// Created by tunm on 2023/8/29.
|
||||
//
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_FO_ALL_H
|
||||
#define HYPERFACEREPO_FO_ALL_H
|
||||
|
||||
#include "face_object.h"
|
||||
|
||||
#endif //HYPERFACEREPO_FO_ALL_H
|
||||
321
cpp-package/inspireface/cpp/inspireface/common/face_info/face_object.h
Executable file
321
cpp-package/inspireface/cpp/inspireface/common/face_info/face_object.h
Executable file
@@ -0,0 +1,321 @@
|
||||
#ifndef FACE_INFO_H
|
||||
#define FACE_INFO_H
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
//#include "face_action.h"
|
||||
#include "opencv2/opencv.hpp"
|
||||
#include "middleware/utils.h"
|
||||
#include "data_type.h"
|
||||
#include "face_process.h"
|
||||
#include "track_module/quality/face_pose_quality.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
enum TRACK_STATE {
|
||||
UNTRACKING = -1, DETECT = 0, READY = 1, TRACKING = 2
|
||||
};
|
||||
|
||||
class INSPIRE_API FaceObject {
|
||||
public:
|
||||
FaceObject(int instance_id, cv::Rect bbox, int num_landmark = 106) {
|
||||
face_id_ = instance_id;
|
||||
landmark_.resize(num_landmark);
|
||||
bbox_ = std::move(bbox);
|
||||
tracking_state_ = DETECT;
|
||||
confidence_ = 1.0;
|
||||
tracking_count_ = 0;
|
||||
pose_euler_angle_.resize(3);
|
||||
keyPointFive.resize(5);
|
||||
// face_action_ = std::make_shared<FaceAction>(10);
|
||||
}
|
||||
|
||||
void UpdateMatrix(const cv::Mat &matrix) {
|
||||
assert(trans_matrix_.rows == 2 && trans_matrix_.cols == 3);
|
||||
double a00 = matrix.at<double>(0, 0);
|
||||
double a01 = matrix.at<double>(0, 1);
|
||||
double a10 = matrix.at<double>(1, 0);
|
||||
double a11 = matrix.at<double>(1, 1);
|
||||
double t1x = matrix.at<double>(0, 2);
|
||||
double t1y = matrix.at<double>(1, 2);
|
||||
|
||||
double m00 = trans_matrix_.at<double>(0, 0);
|
||||
double m01 = trans_matrix_.at<double>(0, 1);
|
||||
double m10 = trans_matrix_.at<double>(1, 0);
|
||||
double m11 = trans_matrix_.at<double>(1, 1);
|
||||
double t0x = trans_matrix_.at<double>(0, 2);
|
||||
double t0y = trans_matrix_.at<double>(1, 2);
|
||||
|
||||
double n_m00 = a00 * m00 + a01 * m10;
|
||||
double n_m01 = a00 * m01 + a01 * m11;
|
||||
double n_m02 = a00 * t0x + a01 * t0y + t1x;
|
||||
double n_m10 = a10 * m00 + a11 * m10;
|
||||
double n_m11 = a10 * m01 + a11 * m11;
|
||||
double n_m12 = a10 * t0x + a11 * t0y + t1y;
|
||||
|
||||
trans_matrix_.at<double>(0, 0) = n_m00;
|
||||
trans_matrix_.at<double>(0, 1) = n_m01;
|
||||
trans_matrix_.at<double>(0, 2) = n_m02;
|
||||
trans_matrix_.at<double>(1, 0) = n_m10;
|
||||
trans_matrix_.at<double>(1, 1) = n_m11;
|
||||
trans_matrix_.at<double>(1, 2) = n_m12;
|
||||
}
|
||||
|
||||
void SetLandmark(const std::vector<cv::Point2f> &lmk, bool update_rect = true,
|
||||
bool update_matrix = true) {
|
||||
if (lmk.size() != landmark_.size()) {
|
||||
INSPIRE_LOGW("The SetLandmark function displays an exception indicating that the lmk number does not match");
|
||||
return;
|
||||
}
|
||||
std::copy(lmk.begin(), lmk.end(), landmark_.begin());
|
||||
DynamicSmoothParamUpdate(landmark_, landmark_smooth_aux_, 106 * 2, 0.06);
|
||||
|
||||
// cv::Vec3d euler_angle;
|
||||
EstimateHeadPose(landmark_, euler_angle_);
|
||||
// DynamicSmoothParamUpdate(landmark_, landmark_smooth_aux_, 106 * 2, 0.06);
|
||||
if (update_rect)
|
||||
bbox_ = cv::boundingRect(lmk);
|
||||
if (update_matrix && tracking_state_ == TRACKING) {
|
||||
// pass
|
||||
}
|
||||
|
||||
keyPointFive[0] = landmark_[55];
|
||||
keyPointFive[1] = landmark_[105];
|
||||
keyPointFive[2] = landmark_[69];
|
||||
keyPointFive[3] = landmark_[45];
|
||||
keyPointFive[4] = landmark_[50];
|
||||
|
||||
}
|
||||
|
||||
void setAlignMeanSquareError(const std::vector<cv::Point2f> &lmk_5) {
|
||||
float src_pts[] = {30.2946, 51.6963, 65.5318, 51.5014, 48.0252,
|
||||
71.7366, 33.5493, 92.3655, 62.7299, 92.2041};
|
||||
for (int i = 0; i < 5; i++) {
|
||||
*(src_pts + 2 * i) += 8.0;
|
||||
}
|
||||
float sum = 0;
|
||||
for (int i = 0; i < lmk_5.size(); i++) {
|
||||
float l2 = L2norm(src_pts[i * 2 + 0], src_pts[i * 2 + 1], lmk_5[i].x, lmk_5[i].y);
|
||||
sum += l2;
|
||||
}
|
||||
|
||||
align_mse_ = sum / 5.0f;
|
||||
}
|
||||
|
||||
// 增加跟踪次数
|
||||
void IncrementTrackingCount() {
|
||||
tracking_count_++;
|
||||
}
|
||||
|
||||
// 获取跟踪次数
|
||||
int GetTrackingCount() const {
|
||||
return tracking_count_;
|
||||
}
|
||||
|
||||
float GetAlignMSE() const { return align_mse_; }
|
||||
|
||||
std::vector<cv::Point2f> GetLanmdark() const { return landmark_; }
|
||||
|
||||
cv::Rect GetRect() const { return bbox_; }
|
||||
|
||||
cv::Rect GetRectSquare(float padding_ratio = 0.0) const {
|
||||
int cx = bbox_.x + bbox_.width / 2;
|
||||
int cy = bbox_.y + bbox_.height / 2;
|
||||
int R = std::max(bbox_.width, bbox_.height) / 2;
|
||||
int R_padding = static_cast<int>(R * (1 + padding_ratio));
|
||||
int x1 = cx - R_padding;
|
||||
int y1 = cy - R_padding;
|
||||
int x2 = cx + R_padding;
|
||||
int y2 = cy + R_padding;
|
||||
int width = x2 - x1;
|
||||
int height = y2 - y1;
|
||||
assert(width > 0);
|
||||
assert(height > 0);
|
||||
assert(height == width);
|
||||
cv::Rect box_square(x1, y1, width, height);
|
||||
return box_square;
|
||||
}
|
||||
|
||||
void UpdateFaceAction() {
|
||||
// face_action_->RecordActionFrame(landmark_, euler_angle_);
|
||||
// face_action_->AnalysisFaceAction();
|
||||
}
|
||||
|
||||
void DisableTracking() { tracking_state_ = UNTRACKING; }
|
||||
|
||||
void EnableTracking() { tracking_state_ = TRACKING; }
|
||||
|
||||
void ReadyTracking() { tracking_state_ = READY; }
|
||||
|
||||
TRACK_STATE TrackingState() const { return tracking_state_; }
|
||||
|
||||
float GetConfidence() const { return confidence_; }
|
||||
|
||||
void SetConfidence(float confidence) { confidence_ = confidence; }
|
||||
|
||||
int GetTrackingId() const { return face_id_; }
|
||||
|
||||
const cv::Mat &getTransMatrix() const { return trans_matrix_; }
|
||||
|
||||
void setTransMatrix(const cv::Mat &transMatrix) {
|
||||
transMatrix.copyTo(trans_matrix_);
|
||||
}
|
||||
|
||||
static float L2norm(float x0, float y0, float x1, float y1) {
|
||||
return sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1));
|
||||
}
|
||||
|
||||
void RequestFaceAction(
|
||||
std::vector<cv::Point2f> &landmarks,
|
||||
std::vector<std::vector<cv::Point2f>> &landmarks_lastNframes,
|
||||
int lm_length, float h) {
|
||||
int n = 5;
|
||||
std::vector<cv::Point2f> landmarks_temp;
|
||||
landmarks_temp.assign(landmarks.begin(), landmarks.end());
|
||||
if (landmarks_lastNframes.size() == n) {
|
||||
for (int i = 0; i < lm_length / 2; i++) {
|
||||
float sum_d = 1;
|
||||
float max_d = 0;
|
||||
for (int j = 0; j < n; j++) {
|
||||
float d = L2norm(landmarks_temp[i].x, landmarks_temp[i].y,
|
||||
landmarks_lastNframes[j][i].x,
|
||||
landmarks_lastNframes[j][i].y);
|
||||
if (d > max_d)
|
||||
max_d = d;
|
||||
}
|
||||
for (int j = 0; j < n; j++) {
|
||||
float d = exp(-max_d * (n - j) * h);
|
||||
sum_d += d;
|
||||
landmarks[i].x = landmarks[i].x + d * landmarks_lastNframes[j][i].x;
|
||||
landmarks[i].y = landmarks[i].y + d * landmarks_lastNframes[j][i].y;
|
||||
}
|
||||
landmarks[i].x = landmarks[i].x / sum_d;
|
||||
landmarks[i].y = landmarks[i].y / sum_d;
|
||||
}
|
||||
}
|
||||
std::vector<cv::Point2f> landmarks_frame;
|
||||
for (int i = 0; i < lm_length / 2; i++) {
|
||||
landmarks_frame.push_back(cv::Point2f(landmarks[i].x, landmarks[i].y));
|
||||
}
|
||||
landmarks_lastNframes.push_back(landmarks_frame);
|
||||
if (landmarks_lastNframes.size() > 5)
|
||||
landmarks_lastNframes.erase(landmarks_lastNframes.begin());
|
||||
}
|
||||
|
||||
void DynamicSmoothParamUpdate(
|
||||
std::vector<cv::Point2f> &landmarks,
|
||||
std::vector<std::vector<cv::Point2f>> &landmarks_lastNframes,
|
||||
int lm_length, float h) {
|
||||
int n = 5;
|
||||
std::vector<cv::Point2f> landmarks_temp;
|
||||
landmarks_temp.assign(landmarks.begin(), landmarks.end());
|
||||
if (landmarks_lastNframes.size() == n) {
|
||||
for (int i = 0; i < lm_length / 2; i++) {
|
||||
float sum_d = 1;
|
||||
float max_d = 0;
|
||||
for (int j = 0; j < n; j++) {
|
||||
float d = L2norm(landmarks_temp[i].x, landmarks_temp[i].y,
|
||||
landmarks_lastNframes[j][i].x,
|
||||
landmarks_lastNframes[j][i].y);
|
||||
if (d > max_d)
|
||||
max_d = d;
|
||||
}
|
||||
for (int j = 0; j < n; j++) {
|
||||
float d = exp(-max_d * (n - j) * h);
|
||||
sum_d += d;
|
||||
landmarks[i].x = landmarks[i].x + d * landmarks_lastNframes[j][i].x;
|
||||
landmarks[i].y = landmarks[i].y + d * landmarks_lastNframes[j][i].y;
|
||||
}
|
||||
landmarks[i].x = landmarks[i].x / sum_d;
|
||||
landmarks[i].y = landmarks[i].y / sum_d;
|
||||
}
|
||||
}
|
||||
std::vector<cv::Point2f> landmarks_frame;
|
||||
for (int i = 0; i < lm_length / 2; i++) {
|
||||
landmarks_frame.push_back(cv::Point2f(landmarks[i].x, landmarks[i].y));
|
||||
}
|
||||
landmarks_lastNframes.push_back(landmarks_frame);
|
||||
if (landmarks_lastNframes.size() > 5)
|
||||
landmarks_lastNframes.erase(landmarks_lastNframes.begin());
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<cv::Point2f> landmark_;
|
||||
std::vector<std::vector<cv::Point2f>> landmark_smooth_aux_;
|
||||
cv::Rect bbox_;
|
||||
cv::Vec3f euler_angle_;
|
||||
std::vector<float> pose_euler_angle_;
|
||||
|
||||
float align_mse_{};
|
||||
|
||||
const cv::Vec3f &getEulerAngle() const { return euler_angle_; }
|
||||
|
||||
const std::vector<float> &getPoseEulerAngle() const { return pose_euler_angle_; }
|
||||
|
||||
void setPoseEulerAngle(const std::vector<float> &poseEulerAngle) {
|
||||
pose_euler_angle_[0] = poseEulerAngle[0];
|
||||
pose_euler_angle_[1] = poseEulerAngle[1];
|
||||
pose_euler_angle_[2] = poseEulerAngle[2];
|
||||
|
||||
if (abs(pose_euler_angle_[0]) < 0.5 && abs(pose_euler_angle_[1]) < 0.48) {
|
||||
is_standard_ = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool isStandard() const {
|
||||
return is_standard_;
|
||||
}
|
||||
|
||||
const cv::Rect &getBbox() const { return bbox_; }
|
||||
|
||||
std::vector<cv::Point2f> getRotateLandmark(int height, int width, int rotate = 0) {
|
||||
if (rotate != 0) {
|
||||
std::vector<cv::Point2f> result = RotatePoints(landmark_, rotate, cv::Size(height, width));
|
||||
return result;
|
||||
} else {
|
||||
return GetLanmdark();
|
||||
}
|
||||
}
|
||||
|
||||
cv::Rect getRotateBbox(int height, int width, int rotate = 0, bool use_flip = false) {
|
||||
if (rotate != 0) {
|
||||
cv::Rect src_bbox = bbox_;
|
||||
std::vector<cv::Point2f> points;
|
||||
cv::Rect trans_rect;
|
||||
RotateRect(src_bbox, points, trans_rect, rotate, cv::Size(height, width));
|
||||
if (use_flip)
|
||||
trans_rect = flipRectWidth(trans_rect, cv::Size(width, height));
|
||||
return trans_rect;
|
||||
} else {
|
||||
return getBbox();
|
||||
}
|
||||
}
|
||||
|
||||
void setBbox(const cv::Rect &bbox) { bbox_ = bbox; }
|
||||
|
||||
cv::Mat trans_matrix_;
|
||||
float confidence_;
|
||||
cv::Rect detect_bbox_;
|
||||
int tracking_count_; // 跟踪次数
|
||||
|
||||
bool is_standard_;
|
||||
|
||||
FacePoseQualityResult high_result;
|
||||
|
||||
FaceProcess faceProcess;
|
||||
|
||||
std::vector<Point2f> keyPointFive;
|
||||
|
||||
private:
|
||||
TRACK_STATE tracking_state_;
|
||||
// std::shared_ptr<FaceAction> face_action_;
|
||||
int face_id_;
|
||||
};
|
||||
|
||||
typedef std::vector<FaceObject> FaceObjectList;
|
||||
|
||||
} // namespace hyper
|
||||
|
||||
#endif // FACE_INFO_H
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Created by tunm on 2023/9/12.
|
||||
//
|
||||
|
||||
// Include guard to prevent double inclusion of this header file
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_FACEPROCESS_H
|
||||
#define HYPERFACEREPO_FACEPROCESS_H
|
||||
|
||||
// Include the necessary header file "data_type.h"
|
||||
#include "data_type.h"
|
||||
|
||||
// Define the namespace "inspire" for encapsulation
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* Enumeration to represent different mask information.
|
||||
*/
|
||||
typedef enum MaskInfo {
|
||||
UNKNOWN_MASK = -1, ///< Unknown mask status
|
||||
UNMASKED = 0, ///< No mask
|
||||
MASKED = 1, ///< Wearing a mask
|
||||
} MaskInfo;
|
||||
|
||||
/**
|
||||
* Enumeration to represent different RGB liveness information.
|
||||
*/
|
||||
typedef enum RGBLivenessInfo {
|
||||
UNKNOWN_RGB_LIVENESS = -1, ///< Unknown RGB liveness status
|
||||
LIVENESS_FAKE = 0, ///< Fake liveness
|
||||
LIVENESS_REAL = 1, ///< Real liveness
|
||||
} RGBLivenessInfo;
|
||||
|
||||
/**
|
||||
* Class definition for FaceProcess.
|
||||
*/
|
||||
class INSPIRE_API FaceProcess {
|
||||
public:
|
||||
/**
|
||||
* Member variable to store mask information, initialized to UNKNOWN_MASK.
|
||||
*/
|
||||
MaskInfo maskInfo = UNKNOWN_MASK;
|
||||
|
||||
/**
|
||||
* Member variable to store RGB liveness information, initialized to UNKNOWN_RGB_LIVENESS.
|
||||
*/
|
||||
RGBLivenessInfo rgbLivenessInfo = UNKNOWN_RGB_LIVENESS;
|
||||
|
||||
};
|
||||
|
||||
} // namespace hyper
|
||||
|
||||
#endif //HYPERFACEREPO_FACEPROCESS_H
|
||||
197
cpp-package/inspireface/cpp/inspireface/data_type.h
Normal file
197
cpp-package/inspireface/cpp/inspireface/data_type.h
Normal file
@@ -0,0 +1,197 @@
|
||||
//
|
||||
// Created by tunm on 2023/5/5.
|
||||
//
|
||||
#pragma once
|
||||
#ifndef HYPERFACE_DATATYPE_H
|
||||
#define HYPERFACE_DATATYPE_H
|
||||
|
||||
#include <cstdint>
|
||||
#if defined(_WIN32) && (defined(_DEBUG) || defined(DEBUG))
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include "crtdbg.h"
|
||||
#endif
|
||||
|
||||
#ifndef INSPIRE_API
|
||||
#define INSPIRE_API
|
||||
#endif
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846264338327950288
|
||||
#endif
|
||||
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @defgroup DataType Definitions
|
||||
* @brief Defines various data types used in the HyperFace project.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined(int64)
|
||||
/** @typedef int64
|
||||
* @brief 64-bit integer type.
|
||||
*/
|
||||
typedef int64_t int64;
|
||||
#endif
|
||||
|
||||
#if !defined(uint64)
|
||||
/** @typedef uint64
|
||||
* @brief 64-bit unsigned integer type.
|
||||
*/
|
||||
typedef uint64_t uint64;
|
||||
#endif
|
||||
|
||||
#if !defined(int32)
|
||||
/** @typedef int32
|
||||
* @brief 32-bit integer type.
|
||||
*/
|
||||
typedef int32_t int32;
|
||||
#endif
|
||||
|
||||
#if !defined(uint32)
|
||||
/** @typedef uint32
|
||||
* @brief 32-bit unsigned integer type.
|
||||
*/
|
||||
typedef uint32_t uint32;
|
||||
#endif
|
||||
|
||||
#if !defined(int8)
|
||||
/** @typedef int8
|
||||
* @brief 8-bit integer type.
|
||||
*/
|
||||
typedef int8_t int8;
|
||||
#endif
|
||||
|
||||
#if !defined(uint8)
|
||||
/** @typedef uint8
|
||||
* @brief 8-bit unsigned integer type.
|
||||
*/
|
||||
typedef uint8_t uint8;
|
||||
#endif
|
||||
|
||||
/** @typedef ByteArray
|
||||
* @brief Type definition for a byte array (vector of chars).
|
||||
*/
|
||||
typedef std::vector<char> ByteArray;
|
||||
|
||||
/** @typedef Point2i
|
||||
* @brief 2D coordinate point with integer precision.
|
||||
*/
|
||||
typedef cv::Point Point2i;
|
||||
|
||||
/** @typedef Point2f
|
||||
* @brief 2D coordinate point with float precision.
|
||||
*/
|
||||
typedef cv::Point2f Point2f;
|
||||
|
||||
/** @typedef PointsList2i
|
||||
* @brief List of 2D coordinate points with integer precision.
|
||||
*/
|
||||
typedef std::vector<Point2i> PointsList2i;
|
||||
|
||||
/** @typedef PointsList2f
|
||||
* @brief List of 2D coordinate points with float precision.
|
||||
*/
|
||||
typedef std::vector<Point2f> PointsList2f;
|
||||
|
||||
/** @typedef Contours2i
|
||||
* @brief Contours represented as a list of 2D integer points.
|
||||
*/
|
||||
typedef std::vector<PointsList2i> Contours2i;
|
||||
|
||||
/** @typedef Contours2f
|
||||
* @brief Contours represented as a list of 2D float points.
|
||||
*/
|
||||
typedef std::vector<PointsList2f> Contours2f;
|
||||
|
||||
/** @typedef Textures2i
|
||||
* @brief Texture lines represented as integer contours.
|
||||
*/
|
||||
typedef Contours2i Textures2i;
|
||||
|
||||
/** @typedef AnyTensorFp32
|
||||
* @brief Generic tensor representation using a vector of floats.
|
||||
*/
|
||||
typedef std::vector<float> AnyTensorFp32;
|
||||
|
||||
/** @typedef Matrix
|
||||
* @brief Generic matrix representation.
|
||||
*/
|
||||
typedef cv::Mat Matrix;
|
||||
|
||||
/** @typedef Rectangle
|
||||
* @brief Rectangle representation using integer values.
|
||||
*/
|
||||
typedef cv::Rect_<int> Rectangle;
|
||||
|
||||
/** @typedef Size
|
||||
* @brief Size representation using integer values.
|
||||
*/
|
||||
typedef cv::Size_<int> Size;
|
||||
|
||||
/** @typedef Embedded
|
||||
* @brief Dense vector for feature embedding.
|
||||
*/
|
||||
typedef std::vector<float> Embedded;
|
||||
|
||||
/** @typedef EmbeddedList
|
||||
* @brief List of dense vectors for feature embedding.
|
||||
*/
|
||||
typedef std::vector<Embedded> EmbeddedList;
|
||||
|
||||
/** @typedef String
|
||||
* @brief String type definition.
|
||||
*/
|
||||
typedef std::string String;
|
||||
|
||||
/** @typedef IndexList
|
||||
* @brief List of indices.
|
||||
*/
|
||||
typedef std::vector<int> IndexList;
|
||||
|
||||
/** @struct FaceLoc
|
||||
* @brief Struct representing standardized face landmarks for detection.
|
||||
*
|
||||
* Contains coordinates for the face, detection score, and landmarks.
|
||||
*/
|
||||
typedef struct FaceLoc {
|
||||
float x1;
|
||||
float y1;
|
||||
float x2;
|
||||
float y2;
|
||||
float score;
|
||||
float lmk[10];
|
||||
} FaceLoc;
|
||||
|
||||
/** @typedef FaceLocList
|
||||
* @brief List of FaceLoc structures.
|
||||
*/
|
||||
typedef std::vector<FaceLoc> FaceLocList;
|
||||
|
||||
/** @struct FaceBasicData
|
||||
* @brief Struct for basic face data.
|
||||
*
|
||||
* Contains the size of the data and a pointer to the data.
|
||||
*/
|
||||
typedef struct FaceBasicData {
|
||||
int32_t dataSize;
|
||||
void* data;
|
||||
} FaceBasicData;
|
||||
|
||||
/** @struct FaceFeatureEntity
|
||||
* @brief Struct for face feature data.
|
||||
*
|
||||
* Contains the size of the feature data and a pointer to the feature array.
|
||||
*/
|
||||
typedef struct FaceFeatureEntity {
|
||||
int32_t dataSize;
|
||||
float *data;
|
||||
} FaceFeaturePtr;
|
||||
|
||||
/** @} */
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif //HYPERFACE_DATATYPE_H
|
||||
271
cpp-package/inspireface/cpp/inspireface/face_context.cpp
Normal file
271
cpp-package/inspireface/cpp/inspireface/face_context.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/7.
|
||||
//
|
||||
|
||||
#include "face_context.h"
|
||||
#include "Initialization_module/launch.h"
|
||||
#include <utility>
|
||||
#include "log.h"
|
||||
#include "herror.h"
|
||||
#include "middleware/utils.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
|
||||
FaceContext::FaceContext() = default;
|
||||
|
||||
int32_t FaceContext::Configuration(DetectMode detect_mode, int32_t max_detect_face,
|
||||
CustomPipelineParameter param) {
|
||||
m_detect_mode_ = detect_mode;
|
||||
m_max_detect_face_ = max_detect_face;
|
||||
m_parameter_ = param;
|
||||
if (!INSPIRE_LAUNCH->isMLoad()) {
|
||||
return HERR_ARCHIVE_NOT_LOAD;
|
||||
}
|
||||
if (INSPIRE_LAUNCH->getMArchive().QueryStatus() != SARC_SUCCESS) {
|
||||
return HERR_ARCHIVE_LOAD_FAILURE;
|
||||
}
|
||||
|
||||
m_face_track_ = std::make_shared<FaceTrack>(m_max_detect_face_);
|
||||
m_face_track_->Configuration(INSPIRE_LAUNCH->getMArchive());
|
||||
SetDetectMode(m_detect_mode_);
|
||||
|
||||
m_face_recognition_ = std::make_shared<FeatureExtraction>(INSPIRE_LAUNCH->getMArchive(), m_parameter_.enable_recognition);
|
||||
if (m_face_recognition_->QueryStatus() != HSUCCEED) {
|
||||
return m_face_recognition_->QueryStatus();
|
||||
}
|
||||
|
||||
m_face_pipeline_ = std::make_shared<FacePipeline>(
|
||||
INSPIRE_LAUNCH->getMArchive(),
|
||||
param.enable_liveness,
|
||||
param.enable_mask_detect,
|
||||
param.enable_age,
|
||||
param.enable_gender,
|
||||
param.enable_interaction_liveness
|
||||
);
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
int32_t FaceContext::FaceDetectAndTrack(CameraStream &image) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
m_detect_cache_.clear();
|
||||
m_face_basic_data_cache_.clear();
|
||||
m_face_rects_cache_.clear();
|
||||
m_track_id_cache_.clear();
|
||||
m_quality_results_cache_.clear();
|
||||
m_roll_results_cache_.clear();
|
||||
m_yaw_results_cache_.clear();
|
||||
m_pitch_results_cache_.clear();
|
||||
m_quality_score_results_cache_.clear();
|
||||
if (m_face_track_ == nullptr) {
|
||||
return HERR_SESS_TRACKER_FAILURE;
|
||||
}
|
||||
m_face_track_->UpdateStream(image, m_always_detect_);
|
||||
for (int i = 0; i < m_face_track_->trackingFace.size(); ++i) {
|
||||
auto &face = m_face_track_->trackingFace[i];
|
||||
HyperFaceData data = FaceObjectToHyperFaceData(face, i);
|
||||
ByteArray byteArray;
|
||||
auto ret = SerializeHyperFaceData(data, byteArray);
|
||||
if (ret != HSUCCEED) {
|
||||
return HERR_INVALID_SERIALIZATION_FAILED;
|
||||
}
|
||||
m_detect_cache_.push_back(byteArray);
|
||||
m_track_id_cache_.push_back(face.GetTrackingId());
|
||||
m_face_rects_cache_.push_back(data.rect);
|
||||
m_quality_results_cache_.push_back(face.high_result);
|
||||
m_roll_results_cache_.push_back(face.high_result.roll);
|
||||
m_yaw_results_cache_.push_back(face.high_result.yaw);
|
||||
m_pitch_results_cache_.push_back(face.high_result.pitch);
|
||||
// Process quality scores
|
||||
float avg = 0.0f;
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
avg += data.quality[j];
|
||||
}
|
||||
avg /= 5.0f;
|
||||
float quality_score = 1.0f - avg; // reversal
|
||||
m_quality_score_results_cache_.push_back(quality_score);
|
||||
}
|
||||
// ptr face_basic
|
||||
m_face_basic_data_cache_.resize(m_face_track_->trackingFace.size());
|
||||
for (int i = 0; i < m_face_basic_data_cache_.size(); ++i) {
|
||||
auto &basic = m_face_basic_data_cache_[i];
|
||||
basic.dataSize = m_detect_cache_[i].size();
|
||||
basic.data = m_detect_cache_[i].data();
|
||||
}
|
||||
|
||||
|
||||
// LOGD("Track COST: %f", m_face_track_->GetTrackTotalUseTime());
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FaceContext::SetFaceDetectThreshold(float value) {
|
||||
m_face_track_->SetDetectThreshold(value);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
FaceObjectList& FaceContext::GetTrackingFaceList() {
|
||||
return m_face_track_->trackingFace;
|
||||
}
|
||||
|
||||
const std::shared_ptr<FeatureExtraction>& FaceContext::FaceRecognitionModule() {
|
||||
return m_face_recognition_;
|
||||
}
|
||||
|
||||
const std::shared_ptr<FacePipeline>& FaceContext::FacePipelineModule() {
|
||||
return m_face_pipeline_;
|
||||
}
|
||||
|
||||
|
||||
const int32_t FaceContext::GetNumberOfFacesCurrentlyDetected() const {
|
||||
return m_face_track_->trackingFace.size();
|
||||
}
|
||||
|
||||
int32_t FaceContext::FacesProcess(CameraStream &image, const std::vector<HyperFaceData> &faces, const CustomPipelineParameter ¶m) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
m_mask_results_cache_.resize(faces.size(), -1.0f);
|
||||
m_rgb_liveness_results_cache_.resize(faces.size(), -1.0f);
|
||||
for (int i = 0; i < faces.size(); ++i) {
|
||||
const auto &face = faces[i];
|
||||
// RGB Liveness Detect
|
||||
if (param.enable_liveness) {
|
||||
auto ret = m_face_pipeline_->Process(image, face, PROCESS_RGB_LIVENESS);
|
||||
if (ret != HSUCCEED) {
|
||||
return ret;
|
||||
}
|
||||
m_rgb_liveness_results_cache_[i] = m_face_pipeline_->faceLivenessCache;
|
||||
}
|
||||
// Mask detection
|
||||
if (param.enable_mask_detect) {
|
||||
auto ret = m_face_pipeline_->Process(image, face, PROCESS_MASK);
|
||||
if (ret != HSUCCEED) {
|
||||
return ret;
|
||||
}
|
||||
m_mask_results_cache_[i] = m_face_pipeline_->faceMaskCache;
|
||||
}
|
||||
// Age prediction
|
||||
if (param.enable_age) {
|
||||
auto ret = m_face_pipeline_->Process(image, face, PROCESS_AGE);
|
||||
if (ret != HSUCCEED) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
// Gender prediction
|
||||
if (param.enable_age) {
|
||||
auto ret = m_face_pipeline_->Process(image, face, PROCESS_GENDER);
|
||||
if (ret != HSUCCEED) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<ByteArray>& FaceContext::GetDetectCache() const {
|
||||
return m_detect_cache_;
|
||||
}
|
||||
|
||||
const std::vector<FaceBasicData>& FaceContext::GetFaceBasicDataCache() const {
|
||||
return m_face_basic_data_cache_;
|
||||
}
|
||||
|
||||
const std::vector<FaceRect>& FaceContext::GetFaceRectsCache() const {
|
||||
return m_face_rects_cache_;
|
||||
}
|
||||
|
||||
const std::vector<int32_t>& FaceContext::GetTrackIDCache() const {
|
||||
return m_track_id_cache_;
|
||||
}
|
||||
|
||||
const std::vector<float>& FaceContext::GetRollResultsCache() const {
|
||||
return m_roll_results_cache_;
|
||||
}
|
||||
|
||||
const std::vector<float>& FaceContext::GetYawResultsCache() const {
|
||||
return m_yaw_results_cache_;
|
||||
}
|
||||
|
||||
const std::vector<float>& FaceContext::GetPitchResultsCache() const {
|
||||
return m_pitch_results_cache_;
|
||||
}
|
||||
|
||||
const std::vector<FacePoseQualityResult>& FaceContext::GetQualityResultsCache() const {
|
||||
return m_quality_results_cache_;
|
||||
}
|
||||
|
||||
const std::vector<float>& FaceContext::GetMaskResultsCache() const {
|
||||
return m_mask_results_cache_;
|
||||
}
|
||||
|
||||
const std::vector<float>& FaceContext::GetRgbLivenessResultsCache() const {
|
||||
return m_rgb_liveness_results_cache_;
|
||||
}
|
||||
|
||||
const std::vector<float>& FaceContext::GetFaceQualityScoresResultsCache() const {
|
||||
return m_quality_score_results_cache_;
|
||||
}
|
||||
|
||||
|
||||
const Embedded& FaceContext::GetFaceFeatureCache() const {
|
||||
return m_face_feature_cache_;
|
||||
}
|
||||
|
||||
int32_t FaceContext::FaceFeatureExtract(CameraStream &image, FaceBasicData& data) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
int32_t ret;
|
||||
HyperFaceData face = {0};
|
||||
ret = DeserializeHyperFaceData((char* )data.data, data.dataSize, face);
|
||||
if (ret != HSUCCEED) {
|
||||
return ret;
|
||||
}
|
||||
m_face_feature_cache_.clear();
|
||||
ret = m_face_recognition_->FaceExtract(image, face, m_face_feature_cache_);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
const CustomPipelineParameter &FaceContext::getMParameter() const {
|
||||
return m_parameter_;
|
||||
}
|
||||
|
||||
|
||||
int32_t FaceContext::FaceQualityDetect(FaceBasicData& data, float &result) {
|
||||
int32_t ret;
|
||||
HyperFaceData face = {0};
|
||||
ret = DeserializeHyperFaceData((char* )data.data, data.dataSize, face);
|
||||
// PrintHyperFaceData(face);
|
||||
if (ret != HSUCCEED) {
|
||||
return ret;
|
||||
}
|
||||
float avg = 0.0f;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
avg += face.quality[i];
|
||||
}
|
||||
avg /= 5.0f;
|
||||
result = 1.0f - avg; // reversal
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int32_t FaceContext::SetDetectMode(DetectMode mode) {
|
||||
m_detect_mode_ = mode;
|
||||
if (m_detect_mode_ == DetectMode::DETECT_MODE_IMAGE) {
|
||||
m_always_detect_ = true;
|
||||
} else {
|
||||
m_always_detect_ = false;
|
||||
}
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FaceContext::SetTrackPreviewSize(const int32_t preview_size) {
|
||||
m_face_track_->SetTrackPreviewSize(preview_size);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
} // namespace hyper
|
||||
273
cpp-package/inspireface/cpp/inspireface/face_context.h
Normal file
273
cpp-package/inspireface/cpp/inspireface/face_context.h
Normal file
@@ -0,0 +1,273 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/7.
|
||||
//
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_FACE_CONTEXT_H
|
||||
#define HYPERFACEREPO_FACE_CONTEXT_H
|
||||
|
||||
/**
|
||||
* @file face_context.h
|
||||
* @brief Face context handling for HyperFaceRepo project.
|
||||
* Includes definitions for face detection, tracking, and feature extraction.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include "track_module/face_track.h"
|
||||
#include "data_type.h"
|
||||
#include "pipeline_module/face_pipeline.h"
|
||||
#include "recognition_module/face_feature_extraction.h"
|
||||
#include "middleware/model_archive/inspire_archive.h"
|
||||
|
||||
/**
|
||||
* @def DB_FILE_NAME
|
||||
* @brief Default database file name used in the FaceContext.
|
||||
*/
|
||||
#define DB_FILE_NAME ".E63520A95DD5B3892C56DA38C3B28E551D8173FD"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @enum DetectMode
|
||||
* @brief Enumeration for different detection modes.
|
||||
*/
|
||||
enum DetectMode {
|
||||
DETECT_MODE_IMAGE = 0, ///< Image detection mode: Always detect
|
||||
DETECT_MODE_VIDEO, ///< Image detection mode: Face track
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct CustomPipelineParameter
|
||||
* @brief Structure to hold custom parameters for the face detection and processing pipeline.
|
||||
*
|
||||
* Includes options for enabling various features such as recognition, liveness detection, and quality assessment.
|
||||
*/
|
||||
typedef struct CustomPipelineParameter {
|
||||
bool enable_recognition = false; ///< Enable face recognition feature
|
||||
bool enable_liveness = false; ///< Enable RGB liveness detection feature
|
||||
bool enable_ir_liveness = false; ///< Enable IR (Infrared) liveness detection feature
|
||||
bool enable_mask_detect = false; ///< Enable mask detection feature
|
||||
bool enable_age = false; ///< Enable age prediction feature
|
||||
bool enable_gender = false; ///< Enable gender prediction feature
|
||||
bool enable_face_quality = false; ///< Enable face quality assessment feature
|
||||
bool enable_interaction_liveness = false; ///< Enable interactive liveness detection feature
|
||||
|
||||
} ContextCustomParameter;
|
||||
|
||||
/**
|
||||
* @class FaceContext
|
||||
* @brief Manages the context for face detection, tracking, and feature extraction in the HyperFaceRepo project.
|
||||
*
|
||||
* Provides interfaces to configure face detection modes, manage face tracking, perform recognition,
|
||||
* and handle other face-related features. Integrates with various modules such as FaceTrack, FaceRecognition, and FacePipeline.
|
||||
*/
|
||||
class INSPIRE_API FaceContext {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor for the FaceContext class.
|
||||
*/
|
||||
explicit FaceContext();
|
||||
|
||||
/**
|
||||
* @brief Configures the face context with given parameters.
|
||||
* @param model_file_path Path to the model file for face detection.
|
||||
* @param detect_mode The detection mode to be used (image or video).
|
||||
* @param max_detect_face The maximum number of faces to detect.
|
||||
* @param param Custom parameters for the face pipeline.
|
||||
* @return int32_t Returns 0 on success, non-zero for any error.
|
||||
*/
|
||||
int32_t Configuration(DetectMode detect_mode, int32_t max_detect_face, CustomPipelineParameter param);
|
||||
|
||||
/**
|
||||
* @brief Performs face detection and tracking on a given image stream.
|
||||
* @param image The camera stream to process for face detection and tracking.
|
||||
* @return int32_t Returns the number of faces detected and tracked.
|
||||
*/// Method for face detection and tracking
|
||||
int32_t FaceDetectAndTrack(CameraStream &image);
|
||||
|
||||
/**
|
||||
* @brief Set the threshold of face detection function, which only acts on the detection model
|
||||
* @param value threshold value
|
||||
* @return int32_t Returns the number of faces detected and tracked.
|
||||
* */
|
||||
int32_t SetFaceDetectThreshold(float value);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the list of currently tracked faces.
|
||||
* @return FaceObjectList A list of face objects currently being tracked.
|
||||
*/
|
||||
FaceObjectList& GetTrackingFaceList();
|
||||
|
||||
/**
|
||||
* @brief Processes faces using the provided pipeline parameters.
|
||||
* @param image Camera stream containing faces.
|
||||
* @param faces Vector of HyperFaceData for detected faces.
|
||||
* @param param Custom pipeline parameters.
|
||||
* @return int32_t Status code of the processing.
|
||||
*/
|
||||
int32_t FacesProcess(CameraStream &image, const std::vector<HyperFaceData> &faces, const CustomPipelineParameter& param);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the face recognition module.
|
||||
* @return std::shared_ptr<FaceRecognition> Shared pointer to the FaceRecognition module.
|
||||
*/
|
||||
const std::shared_ptr<FeatureExtraction>& FaceRecognitionModule();
|
||||
|
||||
/**
|
||||
* @brief Retrieves the face pipeline module.
|
||||
* @return std::shared_ptr<FacePipeline> Shared pointer to the FacePipeline module.
|
||||
*/
|
||||
const std::shared_ptr<FacePipeline>& FacePipelineModule();
|
||||
|
||||
/**
|
||||
* @brief Gets the number of faces currently detected.
|
||||
* @return int32_t Number of faces currently detected.
|
||||
*/
|
||||
const int32_t GetNumberOfFacesCurrentlyDetected() const;
|
||||
|
||||
/**
|
||||
* @brief Extracts features of a face from an image.
|
||||
* @param image Camera stream containing the face.
|
||||
* @param data FaceBasicData to store extracted features.
|
||||
* @return int32_t Status code of the feature extraction.
|
||||
*/
|
||||
int32_t FaceFeatureExtract(CameraStream &image, FaceBasicData& data);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the custom pipeline parameters.
|
||||
* @return CustomPipelineParameter Current custom pipeline parameters.
|
||||
*/
|
||||
const CustomPipelineParameter &getMParameter() const;
|
||||
|
||||
/**
|
||||
* @brief Static method for detecting face quality.
|
||||
* @param data FaceBasicData containing the face information.
|
||||
* @param result Float to store the face quality result.
|
||||
* @return int32_t Status code of the quality detection.
|
||||
*/
|
||||
static int32_t FaceQualityDetect(FaceBasicData& data, float &result);
|
||||
|
||||
/**
|
||||
* @brief Sets the preview size for face tracking.
|
||||
* @param preview_size Integer specifying the new preview size.
|
||||
* @return int32_t Status code of the operation.
|
||||
*/
|
||||
int32_t SetTrackPreviewSize(int32_t preview_size);
|
||||
|
||||
/**
|
||||
* @brief Sets the mode for face detection.
|
||||
* @param mode You can select mode for track or detect.
|
||||
* @return int32_t Status code of the operation.
|
||||
* */
|
||||
int32_t SetDetectMode(DetectMode mode);
|
||||
|
||||
public:
|
||||
// Accessor methods for various cached data
|
||||
/**
|
||||
* @brief Retrieves the cache of detected face data.
|
||||
* @return std::vector<ByteArray> Cache of detected face data.
|
||||
*/
|
||||
const std::vector<ByteArray>& GetDetectCache() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the cache of basic face data.
|
||||
* @return std::vector<FaceBasicData> Cache of basic face data.
|
||||
*/
|
||||
const std::vector<FaceBasicData>& GetFaceBasicDataCache() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the cache of face rectangles.
|
||||
* @return std::vector<FaceRect> Cache of face rectangles.
|
||||
*/
|
||||
const std::vector<FaceRect>& GetFaceRectsCache() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the cache of tracking IDs.
|
||||
* @return std::vector<int32_t> Cache of tracking IDs.
|
||||
*/
|
||||
const std::vector<int32_t>& GetTrackIDCache() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the cache of roll results from face pose estimation.
|
||||
* @return std::vector<float> Cache of roll results.
|
||||
*/
|
||||
const std::vector<float>& GetRollResultsCache() const;
|
||||
|
||||
/**
|
||||
* @brief Retrieves the cache of yaw results from face pose estimation.
|
||||
* @return std::vector<float> Cache of yaw results.
|
||||
*/
|
||||
const std::vector<float>& GetYawResultsCache() const;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the cache of pitch results from face pose estimation.
|
||||
* @return A const reference to a vector containing pitch results.
|
||||
*/
|
||||
const std::vector<float>& GetPitchResultsCache() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the cache of face pose quality results.
|
||||
* @return A const reference to a vector of FacePoseQualityResult objects.
|
||||
*/
|
||||
const std::vector<FacePoseQualityResult>& GetQualityResultsCache() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the cache of mask detection results.
|
||||
* @return A const reference to a vector containing mask detection results.
|
||||
*/
|
||||
const std::vector<float>& GetMaskResultsCache() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the cache of RGB liveness detection results.
|
||||
* @return A const reference to a vector containing RGB liveness results.
|
||||
*/
|
||||
const std::vector<float>& GetRgbLivenessResultsCache() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the cache of face quality predict results.
|
||||
* @return A const reference to a vector containing face quality predict results.
|
||||
*/
|
||||
const std::vector<float>& GetFaceQualityScoresResultsCache() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the cache of the current face features.
|
||||
* @return A const reference to the Embedded object containing current face feature data.
|
||||
*/
|
||||
const Embedded& GetFaceFeatureCache() const;
|
||||
|
||||
|
||||
private:
|
||||
// Private member variables
|
||||
CustomPipelineParameter m_parameter_; ///< Stores custom parameters for the pipeline
|
||||
int32_t m_max_detect_face_{}; ///< Maximum number of faces that can be detected
|
||||
DetectMode m_detect_mode_; ///< Current detection mode (image or video)
|
||||
bool m_always_detect_{}; ///< Flag to determine if detection should always occur
|
||||
|
||||
std::shared_ptr<FaceTrack> m_face_track_; ///< Shared pointer to the FaceTrack object
|
||||
std::shared_ptr<FeatureExtraction> m_face_recognition_; ///< Shared pointer to the FaceRecognition object
|
||||
std::shared_ptr<FacePipeline> m_face_pipeline_; ///< Shared pointer to the FacePipeline object
|
||||
|
||||
private:
|
||||
// Cache data
|
||||
std::vector<ByteArray> m_detect_cache_; ///< Cache for storing serialized detected face data
|
||||
std::vector<FaceBasicData> m_face_basic_data_cache_; ///< Cache for basic face data extracted from detection
|
||||
std::vector<FaceRect> m_face_rects_cache_; ///< Cache for face rectangle data from detection
|
||||
std::vector<int32_t> m_track_id_cache_; ///< Cache for tracking IDs of detected faces
|
||||
std::vector<float> m_roll_results_cache_; ///< Cache for storing roll results from face pose estimation
|
||||
std::vector<float> m_yaw_results_cache_; ///< Cache for storing yaw results from face pose estimation
|
||||
std::vector<float> m_pitch_results_cache_; ///< Cache for storing pitch results from face pose estimation
|
||||
std::vector<FacePoseQualityResult> m_quality_results_cache_; ///< Cache for face pose quality results
|
||||
std::vector<float> m_mask_results_cache_; ///< Cache for mask detection results
|
||||
std::vector<float> m_rgb_liveness_results_cache_; ///< Cache for RGB liveness detection results
|
||||
std::vector<float> m_quality_score_results_cache_; ///< Cache for RGB face quality score results
|
||||
Embedded m_face_feature_cache_; ///< Cache for current face feature data
|
||||
|
||||
std::mutex m_mtx_; ///< Mutex for thread safety.
|
||||
|
||||
};
|
||||
|
||||
} // namespace hyper
|
||||
|
||||
#endif //HYPERFACEREPO_FACE_CONTEXT_H
|
||||
@@ -0,0 +1,536 @@
|
||||
//
|
||||
// Created by tunm on 2023/9/8.
|
||||
//
|
||||
|
||||
#include "feature_hub.h"
|
||||
#include "simd.h"
|
||||
#include "herror.h"
|
||||
#include <thread>
|
||||
|
||||
|
||||
namespace inspire {
|
||||
|
||||
std::mutex FeatureHub::mutex_;
|
||||
std::shared_ptr<FeatureHub> FeatureHub::instance_ = nullptr;
|
||||
|
||||
FeatureHub::FeatureHub(){}
|
||||
|
||||
std::shared_ptr<FeatureHub> FeatureHub::GetInstance() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!instance_) {
|
||||
instance_ = std::shared_ptr<FeatureHub>(new FeatureHub());
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::DisableHub() {
|
||||
if (!m_enable_) {
|
||||
INSPIRE_LOGW("FeatureHub is already disabled.");
|
||||
return HERR_FT_HUB_DISABLE_REPETITION;
|
||||
}
|
||||
// Close the database if it starts
|
||||
if (m_db_) {
|
||||
int ret = m_db_->CloseDatabase();
|
||||
if (ret != HSUCCEED) {
|
||||
INSPIRE_LOGE("Failed to close the database: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
m_db_.reset();
|
||||
}
|
||||
|
||||
m_feature_matrix_list_.clear();
|
||||
m_search_face_feature_cache_.clear();
|
||||
|
||||
m_db_configuration_ = DatabaseConfiguration(); // Reset using the default constructor
|
||||
m_recognition_threshold_ = 0.0f;
|
||||
m_search_mode_ = SEARCH_MODE_EAGER;
|
||||
|
||||
m_face_feature_ptr_cache_.reset();
|
||||
m_enable_ = false;
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::EnableHub(const DatabaseConfiguration &configuration, MatrixCore core) {
|
||||
int32_t ret;
|
||||
if (m_enable_) {
|
||||
INSPIRE_LOGW("You have enabled the FeatureHub feature. It is not valid to do so again");
|
||||
return HERR_FT_HUB_ENABLE_REPETITION;
|
||||
}
|
||||
// Config
|
||||
m_db_configuration_ = configuration;
|
||||
m_recognition_threshold_ = m_db_configuration_.recognition_threshold;
|
||||
if (m_recognition_threshold_ < -1.0f || m_recognition_threshold_ > 1.0f) {
|
||||
INSPIRE_LOGW("The search threshold entered does not fit the required range (-1.0f, 1.0f) and has been set to 0.5 by default");
|
||||
m_recognition_threshold_ = 0.5f;
|
||||
}
|
||||
m_search_mode_ = m_db_configuration_.search_mode;
|
||||
if (m_db_configuration_.feature_block_num <= 0) {
|
||||
m_db_configuration_.feature_block_num = 10;
|
||||
INSPIRE_LOGW("The number of feature blocks cannot be 0, but has been set to the default number of 10, that is, the maximum number of stored faces is supported: 5120");
|
||||
} else if (m_db_configuration_.feature_block_num > 25) {
|
||||
m_db_configuration_.feature_block_num = 25;
|
||||
INSPIRE_LOGW("The number of feature blocks cannot exceed 25, which has been set to the maximum value, that is, the maximum number of stored faces supported: 12800");
|
||||
}
|
||||
// Allocate memory for the feature matrix
|
||||
for (int i = 0; i < m_db_configuration_.feature_block_num; ++i) {
|
||||
std::shared_ptr<FeatureBlock> block;
|
||||
block.reset(FeatureBlock::Create(core, 512, 512));
|
||||
m_feature_matrix_list_.push_back(block);
|
||||
}
|
||||
if (m_db_configuration_.enable_use_db) {
|
||||
m_db_ = std::make_shared<SQLiteFaceManage>();
|
||||
if (IsDirectory(m_db_configuration_.db_path)){
|
||||
std::string dbFile = m_db_configuration_.db_path + "/" + DB_FILE_NAME;
|
||||
ret = m_db_->OpenDatabase(dbFile);
|
||||
} else {
|
||||
ret = m_db_->OpenDatabase(m_db_configuration_.db_path);
|
||||
}
|
||||
if (ret != HSUCCEED) {
|
||||
INSPIRE_LOGE("An error occurred while opening the database: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<FaceFeatureInfo> infos;
|
||||
ret = m_db_->GetTotalFeatures(infos);
|
||||
if (ret == HSUCCEED) {
|
||||
if (infos.empty()) {
|
||||
for (auto const &info: infos) {
|
||||
ret = InsertFaceFeature(info.feature, info.tag, info.customId);
|
||||
if (ret != HSUCCEED) {
|
||||
INSPIRE_LOGE("ID: %d, Inserting error: %d", info.customId, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_enable_ = true;
|
||||
} else {
|
||||
INSPIRE_LOGE("Failed to get the vector from the database.");
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
m_enable_ = true;
|
||||
}
|
||||
|
||||
m_face_feature_ptr_cache_ = std::make_shared<FaceFeatureEntity>();
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::CosineSimilarity(const std::vector<float>& v1, const std::vector<float>& v2, float &res) {
|
||||
if (v1.size() != v2.size() || v1.empty()) {
|
||||
return HERR_SESS_REC_CONTRAST_FEAT_ERR; // The similarity cannot be calculated if the vector lengths are not equal
|
||||
}
|
||||
// Calculate the cosine similarity
|
||||
res = simd_dot(v1.data(), v2.data(), v1.size());
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
int32_t FeatureHub::CosineSimilarity(const float *v1, const float *v2, int32_t size, float &res) {
|
||||
res = simd_dot(v1, v2, size);
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
int32_t FeatureHub::RegisterFaceFeature(const std::vector<float>& feature, int featureIndex, const std::string &tag, int32_t customId) {
|
||||
if (featureIndex < 0 || featureIndex >= m_feature_matrix_list_.size() * NUM_OF_FEATURES_IN_BLOCK) {
|
||||
return HERR_SESS_REC_INVALID_INDEX; // Invalid feature index number
|
||||
}
|
||||
|
||||
// Compute which FeatureBlock and which row the feature vector should be stored in
|
||||
int blockIndex = featureIndex / NUM_OF_FEATURES_IN_BLOCK; // The FeatureBlock where the computation is located
|
||||
int rowIndex = featureIndex % NUM_OF_FEATURES_IN_BLOCK; // Calculate the line number in the FeatureBlock
|
||||
|
||||
// Call the appropriate FeatureBlock registration function
|
||||
int32_t result = m_feature_matrix_list_[blockIndex]->RegisterFeature(rowIndex, feature, tag, customId);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::InsertFaceFeature(const std::vector<float>& feature, const std::string &tag, int32_t customId) {
|
||||
int32_t ret = HSUCCEED;
|
||||
for (int i = 0; i < m_feature_matrix_list_.size(); ++i) {
|
||||
auto &block = m_feature_matrix_list_[i];
|
||||
ret = block->AddFeature(feature, tag, customId);
|
||||
if (ret != HERR_SESS_REC_BLOCK_FULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::SearchFaceFeature(const std::vector<float>& queryFeature, SearchResult &searchResult, float threshold, bool mostSimilar) {
|
||||
if (queryFeature.size() != NUM_OF_FEATURES_IN_BLOCK) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR; // Query feature size does not match expectations
|
||||
}
|
||||
|
||||
bool found = false; // Whether matching features are found
|
||||
float maxScore = -1.0f; // The maximum score is initialized to a negative number
|
||||
int maxIndex = -1; // The index corresponding to the maximum score
|
||||
std::string tag = "None";
|
||||
int maxCid = -1;
|
||||
|
||||
for (int blockIndex = 0; blockIndex < m_feature_matrix_list_.size(); ++blockIndex) {
|
||||
if (m_feature_matrix_list_[blockIndex]->GetUsedCount() == 0) {
|
||||
// If the FeatureBlock has no used features, skip to the next block
|
||||
continue;
|
||||
}
|
||||
|
||||
int startIndex = blockIndex * NUM_OF_FEATURES_IN_BLOCK;
|
||||
SearchResult tempResult;
|
||||
|
||||
// Call the appropriate FeatureBlock search function
|
||||
int32_t result = m_feature_matrix_list_[blockIndex]->SearchNearest(queryFeature, tempResult);
|
||||
|
||||
if (result != HSUCCEED) {
|
||||
// Error
|
||||
return result;
|
||||
}
|
||||
|
||||
// If you find a higher score feature
|
||||
if (tempResult.score > maxScore) {
|
||||
maxScore = tempResult.score;
|
||||
maxIndex = startIndex + tempResult.index;
|
||||
tag = tempResult.tag;
|
||||
maxCid = tempResult.customId;
|
||||
if (maxScore >= threshold) {
|
||||
found = true;
|
||||
if (!mostSimilar) {
|
||||
// Use Eager-Mode: When the score is greater than or equal to the threshold, stop searching for the next FeatureBlock
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
searchResult.score = maxScore;
|
||||
searchResult.index = maxIndex;
|
||||
searchResult.tag = tag;
|
||||
searchResult.customId = maxCid;
|
||||
} else {
|
||||
searchResult.score = -1.0f;
|
||||
searchResult.index = -1;
|
||||
searchResult.tag = "None";
|
||||
searchResult.customId = -1;
|
||||
}
|
||||
|
||||
return HSUCCEED; // No matching feature found but not an error
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t FeatureHub::SearchFaceFeatureTopK(const std::vector<float>& queryFeature, std::vector<SearchResult> &searchResultList, size_t maxTopK, float threshold) {
|
||||
if (queryFeature.size() != NUM_OF_FEATURES_IN_BLOCK) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR;
|
||||
}
|
||||
|
||||
std::vector<SearchResult> tempResultList;
|
||||
searchResultList.clear();
|
||||
|
||||
for (int blockIndex = 0; blockIndex < m_feature_matrix_list_.size(); ++blockIndex) {
|
||||
if (m_feature_matrix_list_[blockIndex]->GetUsedCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tempResultList.clear();
|
||||
int32_t result = m_feature_matrix_list_[blockIndex]->SearchTopKNearest(queryFeature, maxTopK, tempResultList);
|
||||
if (result != HSUCCEED) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const SearchResult& result : tempResultList) {
|
||||
if (result.score >= threshold) {
|
||||
searchResultList.push_back(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(searchResultList.begin(), searchResultList.end(), [](const SearchResult& a, const SearchResult& b) {
|
||||
return a.score > b.score;
|
||||
});
|
||||
|
||||
if (searchResultList.size() > maxTopK) {
|
||||
searchResultList.resize(maxTopK);
|
||||
}
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::DeleteFaceFeature(int featureIndex) {
|
||||
if (featureIndex < 0 || featureIndex >= m_feature_matrix_list_.size() * NUM_OF_FEATURES_IN_BLOCK) {
|
||||
return HERR_SESS_REC_INVALID_INDEX; // Invalid feature index number
|
||||
}
|
||||
|
||||
// Calculate which FeatureBlock and which row the feature vector should be removed in
|
||||
int blockIndex = featureIndex / NUM_OF_FEATURES_IN_BLOCK; // The FeatureBlock where the computation is located
|
||||
int rowIndex = featureIndex % NUM_OF_FEATURES_IN_BLOCK; // Calculate the line number in the FeatureBlock
|
||||
|
||||
// Call the appropriate FeatureBlock delete function
|
||||
int32_t result = m_feature_matrix_list_[blockIndex]->DeleteFeature(rowIndex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::GetFaceFeature(int featureIndex, Embedded &feature) {
|
||||
if (featureIndex < 0 || featureIndex >= m_feature_matrix_list_.size() * NUM_OF_FEATURES_IN_BLOCK) {
|
||||
return HERR_SESS_REC_INVALID_INDEX; // Invalid feature index number
|
||||
}
|
||||
// Calculate which FeatureBlock and which row the feature vector should be removed in
|
||||
int blockIndex = featureIndex / NUM_OF_FEATURES_IN_BLOCK; // The FeatureBlock where the computation is located
|
||||
int rowIndex = featureIndex % NUM_OF_FEATURES_IN_BLOCK; // Calculate the line number in the FeatureBlock
|
||||
|
||||
int32_t result = m_feature_matrix_list_[blockIndex]->GetFeature(rowIndex, feature);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::GetFaceEntity(int featureIndex, Embedded &feature, std::string& tag, FEATURE_STATE& status) {
|
||||
if (featureIndex < 0 || featureIndex >= m_feature_matrix_list_.size() * NUM_OF_FEATURES_IN_BLOCK) {
|
||||
return HERR_SESS_REC_INVALID_INDEX; // Invalid feature index number
|
||||
}
|
||||
// Calculate which FeatureBlock and which row the feature vector should be removed in
|
||||
int blockIndex = featureIndex / NUM_OF_FEATURES_IN_BLOCK; // The FeatureBlock where the computation is located
|
||||
int rowIndex = featureIndex % NUM_OF_FEATURES_IN_BLOCK; // Calculate the line number in the FeatureBlock
|
||||
|
||||
int32_t result = m_feature_matrix_list_[blockIndex]->GetFeature(rowIndex, feature);
|
||||
tag = m_feature_matrix_list_[blockIndex]->GetTagFromRow(rowIndex);
|
||||
status = m_feature_matrix_list_[blockIndex]->GetStateFromRow(rowIndex);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::GetFaceFeatureCount() {
|
||||
int totalFeatureCount = 0;
|
||||
|
||||
// Iterate over all FeatureBlocks and add up the number of feature vectors used
|
||||
for (const auto& block : m_feature_matrix_list_) {
|
||||
totalFeatureCount += block->GetUsedCount();
|
||||
}
|
||||
|
||||
return totalFeatureCount;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::GetFeatureNum() const {
|
||||
return NUM_OF_FEATURES_IN_BLOCK;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::UpdateFaceFeature(const std::vector<float> &feature, int featureIndex, const std::string &tag, int32_t customId) {
|
||||
if (featureIndex < 0 || featureIndex >= m_feature_matrix_list_.size() * NUM_OF_FEATURES_IN_BLOCK) {
|
||||
return HERR_SESS_REC_INVALID_INDEX; // Invalid feature index number
|
||||
}
|
||||
|
||||
// Calculate which FeatureBlock and which row the feature vector should be removed in
|
||||
int blockIndex = featureIndex / NUM_OF_FEATURES_IN_BLOCK; // The FeatureBlock where the computation is located
|
||||
int rowIndex = featureIndex % NUM_OF_FEATURES_IN_BLOCK; // Calculate the line number in the FeatureBlock
|
||||
|
||||
// Call the appropriate FeatureBlock registration function
|
||||
int32_t result = m_feature_matrix_list_[blockIndex]->UpdateFeature(rowIndex, feature, tag, customId);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FeatureHub::PrintFeatureMatrixInfo() {
|
||||
m_feature_matrix_list_[0]->PrintMatrix();
|
||||
}
|
||||
|
||||
|
||||
int32_t FeatureHub::FindFeatureIndexByCustomId(int32_t customId) {
|
||||
// Iterate over all FeatureBlocks
|
||||
for (int blockIndex = 0; blockIndex < m_feature_matrix_list_.size(); ++blockIndex) {
|
||||
int startIndex = blockIndex * NUM_OF_FEATURES_IN_BLOCK;
|
||||
|
||||
// Query the customId from the current FeatureBlock
|
||||
int rowIndex = m_feature_matrix_list_[blockIndex]->FindIndexByCustomId(customId);
|
||||
|
||||
if (rowIndex != -1) {
|
||||
return startIndex + rowIndex; // 返回行号
|
||||
}
|
||||
}
|
||||
|
||||
return -1; // If none of the featureBlocks is found, -1 is returned
|
||||
}
|
||||
|
||||
|
||||
int32_t FeatureHub::SearchFaceFeature(const Embedded &queryFeature, SearchResult &searchResult) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
m_search_face_feature_cache_.clear();
|
||||
std::memset(m_string_cache_, 0, sizeof(m_string_cache_)); // Initial Zero
|
||||
auto ret = SearchFaceFeature(queryFeature, searchResult, m_recognition_threshold_,
|
||||
m_search_mode_ == SEARCH_MODE_EXHAUSTIVE);
|
||||
if (ret == HSUCCEED) {
|
||||
if (searchResult.index != -1) {
|
||||
ret = GetFaceFeature(searchResult.index, m_search_face_feature_cache_);
|
||||
}
|
||||
m_face_feature_ptr_cache_->data = m_search_face_feature_cache_.data();
|
||||
m_face_feature_ptr_cache_->dataSize = m_search_face_feature_cache_.size();
|
||||
// Ensure that buffer overflows do not occur
|
||||
size_t copy_length = std::min(searchResult.tag.size(), sizeof(m_string_cache_) - 1);
|
||||
std::strncpy(m_string_cache_, searchResult.tag.c_str(), copy_length);
|
||||
// Make sure the string ends with a null character
|
||||
m_string_cache_[copy_length] = '\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::SearchFaceFeatureTopK(const Embedded& queryFeature, size_t topK) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
m_top_k_confidence_.clear();
|
||||
m_top_k_custom_ids_cache_.clear();
|
||||
auto ret = SearchFaceFeatureTopK(queryFeature, m_search_top_k_cache_, topK, m_recognition_threshold_);
|
||||
if (ret == HSUCCEED) {
|
||||
for (int i = 0; i < m_search_top_k_cache_.size(); ++i) {
|
||||
auto &item = m_search_top_k_cache_[i];
|
||||
m_top_k_custom_ids_cache_.push_back(item.customId);
|
||||
m_top_k_confidence_.push_back(item.score);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::FaceFeatureInsertFromCustomId(const std::vector<float> &feature, const std::string &tag,
|
||||
int32_t customId) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
auto index = FindFeatureIndexByCustomId(customId);
|
||||
if (index != -1) {
|
||||
return HERR_SESS_REC_ID_ALREADY_EXIST;
|
||||
}
|
||||
auto ret = InsertFaceFeature(feature, tag, customId);
|
||||
if (ret == HSUCCEED && m_db_ != nullptr) {
|
||||
// operational database
|
||||
FaceFeatureInfo item = {0};
|
||||
item.customId = customId;
|
||||
item.tag = tag;
|
||||
item.feature = feature;
|
||||
ret = m_db_->InsertFeature(item);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::FaceFeatureRemoveFromCustomId(int32_t customId) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
auto index = FindFeatureIndexByCustomId(customId);
|
||||
if (index == -1) {
|
||||
return HERR_SESS_REC_INVALID_INDEX;
|
||||
}
|
||||
auto ret = DeleteFaceFeature(index);
|
||||
if (ret == HSUCCEED && m_db_ != nullptr) {
|
||||
ret = m_db_->DeleteFeature(customId);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::FaceFeatureUpdateFromCustomId(const std::vector<float> &feature, const std::string &tag,
|
||||
int32_t customId) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
auto index = FindFeatureIndexByCustomId(customId);
|
||||
if (index == -1) {
|
||||
return HERR_SESS_REC_INVALID_INDEX;
|
||||
}
|
||||
auto ret = UpdateFaceFeature(feature, index, tag, customId);
|
||||
if (ret == HSUCCEED && m_db_ != nullptr) {
|
||||
FaceFeatureInfo item = {0};
|
||||
item.customId = customId;
|
||||
item.tag = tag;
|
||||
item.feature = feature;
|
||||
ret = m_db_->UpdateFeature(item);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::GetFaceFeatureFromCustomId(int32_t customId) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (!m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
auto index = FindFeatureIndexByCustomId(customId);
|
||||
if (index == -1) {
|
||||
return HERR_SESS_REC_INVALID_INDEX;
|
||||
}
|
||||
m_getter_face_feature_cache_.clear();
|
||||
std::string tag;
|
||||
FEATURE_STATE status;
|
||||
auto ret = GetFaceEntity(index, m_getter_face_feature_cache_, tag, status);
|
||||
m_face_feature_ptr_cache_->data = m_getter_face_feature_cache_.data();
|
||||
m_face_feature_ptr_cache_->dataSize = m_getter_face_feature_cache_.size();
|
||||
// Ensure that buffer overflows do not occur
|
||||
size_t copy_length = std::min(tag.size(), sizeof(m_string_cache_) - 1);
|
||||
std::strncpy(m_string_cache_, tag.c_str(), copy_length);
|
||||
// Make sure the string ends with a null character
|
||||
m_string_cache_[copy_length] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t FeatureHub::ViewDBTable() {
|
||||
if (!m_enable_) {
|
||||
INSPIRE_LOGE("FeatureHub is disabled, please enable it before it can be served");
|
||||
return HERR_FT_HUB_DISABLE;
|
||||
}
|
||||
auto ret = m_db_->ViewTotal();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FeatureHub::SetRecognitionThreshold(float threshold) {
|
||||
m_recognition_threshold_ = threshold;
|
||||
}
|
||||
|
||||
void FeatureHub::SetRecognitionSearchMode(SearchMode mode) {
|
||||
m_search_mode_ = mode;
|
||||
}
|
||||
|
||||
// =========== Getter ===========
|
||||
|
||||
const Embedded& FeatureHub::GetSearchFaceFeatureCache() const {
|
||||
return m_search_face_feature_cache_;
|
||||
}
|
||||
|
||||
char *FeatureHub::GetStringCache() {
|
||||
return m_string_cache_;
|
||||
}
|
||||
|
||||
const std::shared_ptr<FaceFeaturePtr>& FeatureHub::GetFaceFeaturePtrCache() const {
|
||||
return m_face_feature_ptr_cache_;
|
||||
}
|
||||
|
||||
std::vector<float> &FeatureHub::GetTopKConfidence() {
|
||||
return m_top_k_confidence_;
|
||||
}
|
||||
|
||||
std::vector<int32_t> &FeatureHub::GetTopKCustomIdsCache() {
|
||||
return m_top_k_custom_ids_cache_;
|
||||
}
|
||||
|
||||
|
||||
} // namespace hyper
|
||||
@@ -0,0 +1,352 @@
|
||||
//
|
||||
// Created by tunm on 2023/9/8.
|
||||
//
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_FACERECOGNITION_H
|
||||
#define HYPERFACEREPO_FACERECOGNITION_H
|
||||
|
||||
#include <mutex>
|
||||
#include "common/face_info/face_object.h"
|
||||
#include "common/face_data/data_tools.h"
|
||||
#include "middleware/camera_stream/camera_stream.h"
|
||||
#include "feature_hub/features_block/feature_block.h"
|
||||
#include "feature_hub/persistence/sqlite_faces_manage.h"
|
||||
#include "middleware/model_archive/inspire_archive.h"
|
||||
|
||||
/**
|
||||
* @def DB_FILE_NAME
|
||||
* @brief Default database file name used in the FaceContext.
|
||||
*/
|
||||
#define DB_FILE_NAME ".E63520A95DD5B3892C56DA38C3B28E551D8173FD"
|
||||
|
||||
#define FEATURE_HUB FeatureHub::GetInstance()
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Comparator function object to sort SearchResult by score (descending order)
|
||||
struct CompareByScore {
|
||||
bool operator()(const SearchResult& a, const SearchResult& b) const {
|
||||
return a.score > b.score;
|
||||
}
|
||||
};
|
||||
|
||||
typedef enum SearchMode {
|
||||
SEARCH_MODE_EAGER = 0, // Eager mode: Stops when a vector meets the threshold.
|
||||
SEARCH_MODE_EXHAUSTIVE, // Exhaustive mode: Searches until the best match is found.
|
||||
} SearchMode;
|
||||
|
||||
|
||||
/**
|
||||
* @struct DatabaseConfiguration
|
||||
* @brief Structure to configure database settings for FaceRecognition.
|
||||
*/
|
||||
using DatabaseConfiguration = struct DatabaseConfiguration {
|
||||
int feature_block_num = 20;
|
||||
bool enable_use_db = false; ///< Whether to enable data persistence.
|
||||
std::string db_path; ///< Path to the database file.
|
||||
float recognition_threshold = 0.48f; ///< Face search threshold
|
||||
SearchMode search_mode = SEARCH_MODE_EAGER; ///< Search mode
|
||||
};
|
||||
|
||||
/**
|
||||
* @class FeatureHub
|
||||
* @brief Service for internal feature vector storage.
|
||||
*
|
||||
* This class provides methods for face feature extraction, registration, update, search, and more.
|
||||
*/
|
||||
class INSPIRE_API FeatureHub {
|
||||
private:
|
||||
static std::mutex mutex_; ///< Mutex lock
|
||||
static std::shared_ptr<FeatureHub> instance_; ///< FeatureHub Instance
|
||||
const int32_t NUM_OF_FEATURES_IN_BLOCK = 512; ///< Number of features in each feature block.
|
||||
|
||||
FeatureHub(const FeatureHub&) = delete;
|
||||
FeatureHub& operator=(const FeatureHub&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Enables the feature hub with the specified configuration and matrix core.
|
||||
*
|
||||
* This function initializes and configures the feature hub based on the provided database
|
||||
* configuration and the specified matrix processing core. It prepares the hub for operation,
|
||||
* setting up necessary resources such as database connections and data processing pipelines.
|
||||
*
|
||||
* @param configuration The database configuration settings used to configure the hub.
|
||||
* @param core The matrix core used for processing, defaulting to OpenCV if not specified.
|
||||
* @return int32_t Returns a status code indicating success (0) or failure (non-zero).
|
||||
*/
|
||||
int32_t EnableHub(const DatabaseConfiguration& configuration, MatrixCore core = MC_OPENCV);
|
||||
|
||||
/**
|
||||
* @brief Disables the feature hub, freeing all associated resources.
|
||||
*
|
||||
* This function stops all operations within the hub, releases all occupied resources,
|
||||
* such as database connections and internal data structures. It is used to safely
|
||||
* shutdown the hub when it is no longer needed or before the application exits, ensuring
|
||||
* that all resources are properly cleaned up.
|
||||
*
|
||||
* @return int32_t Returns a status code indicating success (0) or failure (non-zero).
|
||||
*/
|
||||
int32_t DisableHub();
|
||||
|
||||
|
||||
static std::shared_ptr<FeatureHub> GetInstance();
|
||||
|
||||
/**
|
||||
* @brief Searches for a face feature within stored data.
|
||||
* @param queryFeature Embedded feature to search for.
|
||||
* @param searchResult SearchResult object to store search results.
|
||||
* @return int32_t Status code of the search operation.
|
||||
*/
|
||||
int32_t SearchFaceFeature(const Embedded& queryFeature, SearchResult &searchResult);
|
||||
|
||||
/**
|
||||
* @brief Search the stored data for the top k facial features that are most similar.
|
||||
* @param topK Maximum search
|
||||
* @return int32_t Status code of the search operation.
|
||||
*/
|
||||
int32_t SearchFaceFeatureTopK(const Embedded& queryFeature, size_t topK);
|
||||
|
||||
/**
|
||||
* @brief Inserts a face feature with a custom ID.
|
||||
* @param feature Vector of floats representing the face feature.
|
||||
* @param tag String tag associated with the feature.
|
||||
* @param customId Custom ID for the feature.
|
||||
* @return int32_t Status code of the insertion operation.
|
||||
*/
|
||||
int32_t FaceFeatureInsertFromCustomId(const std::vector<float>& feature, const std::string &tag, int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Removes a face feature by its custom ID.
|
||||
* @param customId Custom ID of the feature to remove.
|
||||
* @return int32_t Status code of the removal operation.
|
||||
*/
|
||||
int32_t FaceFeatureRemoveFromCustomId(int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Updates a face feature by its custom ID.
|
||||
* @param feature Vector of floats representing the new face feature.
|
||||
* @param tag String tag associated with the feature.
|
||||
* @param customId Custom ID of the feature to update.
|
||||
* @return int32_t Status code of the update operation.
|
||||
*/
|
||||
int32_t FaceFeatureUpdateFromCustomId(const std::vector<float>& feature, const std::string &tag, int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a face feature by its custom ID.
|
||||
* @param customId Custom ID of the feature to retrieve.
|
||||
* @return int32_t Status code of the retrieval operation.
|
||||
*/
|
||||
int32_t GetFaceFeatureFromCustomId(int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Views the database table containing face data.
|
||||
* @return int32_t Status code of the operation.
|
||||
*/
|
||||
int32_t ViewDBTable();
|
||||
|
||||
/**
|
||||
* @brief Sets the recognition threshold for face recognition.
|
||||
* @param threshold Float value of the new threshold.
|
||||
*/
|
||||
void SetRecognitionThreshold(float threshold);
|
||||
|
||||
/**
|
||||
* @brief Sets the search mode for face recognition.
|
||||
* @param mode Search mode.
|
||||
*/
|
||||
void SetRecognitionSearchMode(SearchMode mode);
|
||||
|
||||
/**
|
||||
* @brief Computes the cosine similarity between two feature vectors.
|
||||
*
|
||||
* @param v1 First feature vector.
|
||||
* @param v2 Second feature vector.
|
||||
* @param res Output parameter to store the cosine similarity result.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
static int32_t CosineSimilarity(const std::vector<float>& v1, const std::vector<float>& v2, float &res);
|
||||
|
||||
/**
|
||||
* @brief Computes the cosine similarity between two feature vectors.
|
||||
*
|
||||
* @param v1 Pointer to the first feature vector.
|
||||
* @param v2 Pointer to the second feature vector.
|
||||
* @param size Size of the feature vectors.
|
||||
* @param res Output parameter to store the cosine similarity result.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
static int32_t CosineSimilarity(const float* v1, const float *v2, int32_t size, float &res);
|
||||
|
||||
public:
|
||||
// Getter Function
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the cache used for search operations in face feature data.
|
||||
* @return A const reference to the Embedded object containing face feature data for search.
|
||||
*/
|
||||
const Embedded& GetSearchFaceFeatureCache() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the cache of face feature pointers.
|
||||
* @return A shared pointer to the cache of face feature pointers.
|
||||
*/
|
||||
const std::shared_ptr<FaceFeaturePtr>& GetFaceFeaturePtrCache() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the cache for temporary string storage.
|
||||
* @return A pointer to the character array used as a string cache.
|
||||
*/
|
||||
char* GetStringCache();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the number of features in the feature block.
|
||||
*
|
||||
* @return int32_t Number of features.
|
||||
*/
|
||||
int32_t GetFeatureNum() const;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieves the total number of facial features stored in the feature block.
|
||||
*
|
||||
* @return int32_t Total number of facial features.
|
||||
*/
|
||||
int32_t GetFaceFeatureCount();
|
||||
|
||||
std::vector<float> &GetTopKConfidence();
|
||||
|
||||
std::vector<int32_t> &GetTopKCustomIdsCache();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor for FeatureHub class.
|
||||
*/
|
||||
FeatureHub();
|
||||
|
||||
/**
|
||||
* @brief Registers a facial feature in the feature block.
|
||||
*
|
||||
* @param feature Vector of floats representing the feature.
|
||||
* @param featureIndex Index of the feature in the block.
|
||||
* @param tag String tag associated with the feature.
|
||||
* @param customId Custom identifier for the feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t RegisterFaceFeature(const std::vector<float>& feature, int featureIndex, const std::string &tag, int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Updates a facial feature in the feature block.
|
||||
*
|
||||
* @param feature Vector of floats representing the updated feature.
|
||||
* @param featureIndex Index of the feature in the block.
|
||||
* @param tag New string tag for the feature.
|
||||
* @param customId Custom identifier for the feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t UpdateFaceFeature(const std::vector<float>& feature, int featureIndex, const std::string &tag, int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Searches for the nearest facial feature in the feature block to a given query feature.
|
||||
*
|
||||
* @param queryFeature Query feature vector.
|
||||
* @param searchResult SearchResult structure to store the search results.
|
||||
* @param threshold Threshold for considering a match.
|
||||
* @param mostSimilar Whether to find the most similar feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t SearchFaceFeature(const std::vector<float>& queryFeature, SearchResult &searchResult, float threshold, bool mostSimilar=true);
|
||||
|
||||
/**
|
||||
* Search for the top K face features that are most similar to a given query feature.
|
||||
* @param queryFeature A vector of floats representing the feature to query against.
|
||||
* @param searchResultList A reference to a vector where the top K search results will be stored.
|
||||
* @param maxTopK The maximum number of top results to return.
|
||||
* @param threshold A float representing the minimum similarity score threshold.
|
||||
* @return int32_t Returns a status code (0 for success, non-zero for any errors).
|
||||
*/
|
||||
int32_t SearchFaceFeatureTopK(const std::vector<float>& queryFeature, std::vector<SearchResult> &searchResultList, size_t maxTopK, float threshold);
|
||||
|
||||
/**
|
||||
* @brief Inserts a facial feature into the feature block.
|
||||
*
|
||||
* @param feature Vector of floats representing the feature.
|
||||
* @param tag String tag associated with the feature.
|
||||
* @param customId Custom identifier for the feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t InsertFaceFeature(const std::vector<float>& feature, const std::string &tag, int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Deletes a facial feature from the feature block.
|
||||
*
|
||||
* @param featureIndex Index of the feature to delete.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t DeleteFaceFeature(int featureIndex);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a facial feature from the feature block.
|
||||
*
|
||||
* @param featureIndex Index of the feature to retrieve.
|
||||
* @param feature Output parameter to store the retrieved feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t GetFaceFeature(int featureIndex, Embedded &feature);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a facial entity from the feature block.
|
||||
*
|
||||
* @param featureIndex Index of the feature to retrieve.
|
||||
* @param result Output parameter to store the retrieved entity.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t GetFaceEntity(int featureIndex, Embedded &feature, std::string& tag, FEATURE_STATE& status);
|
||||
|
||||
/**
|
||||
* @brief Finds the index of a feature by its custom ID.
|
||||
*
|
||||
* @param customId Custom identifier to search for.
|
||||
* @return int32_t Index of the feature with the given custom ID, or -1 if not found.
|
||||
*/
|
||||
int32_t FindFeatureIndexByCustomId(int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Prints information about the feature matrix.
|
||||
*/
|
||||
void PrintFeatureMatrixInfo();
|
||||
|
||||
private:
|
||||
|
||||
Embedded m_search_face_feature_cache_; ///< Cache for face feature data used in search operations
|
||||
Embedded m_getter_face_feature_cache_; ///< Cache for face feature data used in search operations
|
||||
std::shared_ptr<FaceFeaturePtr> m_face_feature_ptr_cache_; ///< Shared pointer to cache of face feature pointers
|
||||
char m_string_cache_[256]; ///< Cache for temporary string storage
|
||||
|
||||
std::vector<SearchResult> m_search_top_k_cache_; ///<
|
||||
std::vector<float> m_top_k_confidence_;
|
||||
std::vector<int32_t> m_top_k_custom_ids_cache_;
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<FeatureBlock>> m_feature_matrix_list_; ///< List of feature blocks.
|
||||
|
||||
DatabaseConfiguration m_db_configuration_; ///< Configuration settings for the database
|
||||
float m_recognition_threshold_{0.48f}; ///< Threshold value for face recognition
|
||||
SearchMode m_search_mode_{SEARCH_MODE_EAGER}; ///< Flag to determine if the search should find the most similar feature
|
||||
|
||||
std::shared_ptr<SQLiteFaceManage> m_db_; ///< Shared pointer to the SQLiteFaceManage object
|
||||
|
||||
bool m_enable_{false}; ///< Running status
|
||||
|
||||
std::mutex m_res_mtx_; ///< Mutex for thread safety.
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif //HYPERFACEREPO_FACERECOGNITION_H
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/11.
|
||||
//
|
||||
|
||||
#include "feature_block.h"
|
||||
#include "log.h"
|
||||
#include "feature_hub/features_block/implement/feature_block_none.h"
|
||||
|
||||
#ifdef FEATURE_BLOCK_ENABLE_OPENCV
|
||||
#include "feature_hub/features_block/implement/feature_block_opencv.h"
|
||||
#endif
|
||||
|
||||
namespace inspire {
|
||||
|
||||
|
||||
FeatureBlock *FeatureBlock::Create(const MatrixCore crop_type, int32_t features_max, int32_t feature_length) {
|
||||
FeatureBlock* p = nullptr;
|
||||
switch (crop_type) {
|
||||
#ifdef FEATURE_BLOCK_ENABLE_OPENCV
|
||||
case MC_OPENCV:
|
||||
p = new FeatureBlockOpenCV(features_max, feature_length);
|
||||
break;
|
||||
#endif
|
||||
#ifdef FEATURE_BLOCK_ENABLE_EIGEN
|
||||
case MC_EIGEN:
|
||||
LOGD("Not Implement");
|
||||
break;
|
||||
#endif
|
||||
case MC_NONE:
|
||||
INSPIRE_LOGD("Not Implement");
|
||||
break;
|
||||
}
|
||||
|
||||
if (p != nullptr) {
|
||||
p->m_matrix_core_ = crop_type;
|
||||
p->m_features_max_ = features_max; // Number of facial features
|
||||
p->m_feature_length_ = feature_length; // Face feature length (default: 512)
|
||||
p->m_feature_state_.resize(features_max, FEATURE_STATE::IDLE);
|
||||
p->m_tag_list_.resize(features_max, "None");
|
||||
p->m_custom_id_list_.resize(features_max, -1);
|
||||
} else {
|
||||
INSPIRE_LOGE("Create FeatureBlock error.");
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace hyper
|
||||
@@ -0,0 +1,290 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/11.
|
||||
//
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_FEATUREBLOCK_H
|
||||
#define HYPERFACEREPO_FEATUREBLOCK_H
|
||||
#include <mutex>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include "data_type.h"
|
||||
|
||||
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @enum MatrixCore
|
||||
* @brief Enumeration for different types of matrix cores used in feature extraction.
|
||||
*/
|
||||
typedef enum {
|
||||
MC_NONE, ///< C/C++ Native matrix core.
|
||||
MC_OPENCV, ///< OpenCV Mat based matrix core.
|
||||
MC_EIGEN, ///< Eigen3 Mat based matrix core.
|
||||
} MatrixCore;
|
||||
|
||||
/**
|
||||
* @enum FEATURE_STATE
|
||||
* @brief Enumeration for states of feature slots in the feature block.
|
||||
*/
|
||||
typedef enum {
|
||||
IDLE = 0, ///< Slot is idle.
|
||||
USED, ///< Slot is used.
|
||||
} FEATURE_STATE;
|
||||
|
||||
|
||||
/**
|
||||
* @struct SearchResult
|
||||
* @brief Structure to store the results of a feature search.
|
||||
*/
|
||||
typedef struct SearchResult {
|
||||
float score = -1.0f; ///< Score of the search result.
|
||||
int32_t index = -1; ///< Index of the result in the feature block.
|
||||
std::string tag = "None"; ///< Tag associated with the feature.
|
||||
int32_t customId = -1; ///< Custom identifier for the feature.
|
||||
} SearchResult;
|
||||
|
||||
/**
|
||||
* @class FeatureBlock
|
||||
* @brief Class for managing and operating on a block of facial features.
|
||||
*
|
||||
* This class provides methods to add, delete, update, and search facial features
|
||||
* in a feature block, with thread safety using mutexes.
|
||||
*/
|
||||
class INSPIRE_API FeatureBlock {
|
||||
public:
|
||||
static FeatureBlock* Create(const MatrixCore crop_type, int32_t features_max = 512, int32_t feature_length = 512);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Destructor for the FeatureBlock class.
|
||||
*/
|
||||
virtual ~FeatureBlock() {}
|
||||
|
||||
/**
|
||||
* @brief Adds a feature to the feature block.
|
||||
* @param feature Vector of floats representing the feature.
|
||||
* @param tag String tag associated with the feature.
|
||||
* @param customId Custom identifier for the feature.
|
||||
* @return int32_t Status of the feature addition.
|
||||
*/
|
||||
virtual int32_t AddFeature(const std::vector<float>& feature, const std::string &tag, int32_t customId) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_); // Use mutex to protect shared data
|
||||
return UnsafeAddFeature(feature, tag, customId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes a feature from the feature block.
|
||||
* @param rowToDelete Index of the feature to be deleted.
|
||||
* @return int32_t Status of the feature deletion.
|
||||
*/
|
||||
virtual int32_t DeleteFeature(int rowToDelete) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
return UnsafeDeleteFeature(rowToDelete);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates a feature in the feature block.
|
||||
* @param rowToUpdate Index of the feature to be updated.
|
||||
* @param newFeature New feature vector to replace the old one.
|
||||
* @param tag New tag for the updated feature.
|
||||
* @param customId Custom identifier for the updated feature.
|
||||
* @return int32_t Status of the feature update.
|
||||
*/
|
||||
virtual int32_t UpdateFeature(int rowToUpdate, const std::vector<float>& newFeature, const std::string &tag, int32_t customId) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
return UnsafeUpdateFeature(rowToUpdate, newFeature, tag, customId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers a feature at a specific index in the feature block.
|
||||
* @param rowToUpdate Index at which to register the new feature.
|
||||
* @param feature Feature vector to be registered.
|
||||
* @param tag Tag associated with the feature.
|
||||
* @param customId Custom identifier for the feature.
|
||||
* @return int32_t Status of the feature registration.
|
||||
*/
|
||||
virtual int32_t RegisterFeature(int rowToUpdate, const std::vector<float>& feature, const std::string &tag, int32_t customId) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
return UnsafeRegisterFeature(rowToUpdate, feature, tag, customId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Searches for the nearest feature in the block to a given query feature.
|
||||
* @param queryFeature Query feature vector.
|
||||
* @param searchResult SearchResult structure to store the search results.
|
||||
* @return int32_t Status of the search operation.
|
||||
*/
|
||||
virtual int32_t SearchNearest(const std::vector<float>& queryFeature, SearchResult &searchResult) = 0;
|
||||
|
||||
/**
|
||||
* @brief Search the first k features in a block that are closest to a given query feature.
|
||||
* @param topK Maximum number of similarities
|
||||
* @param searchResults outputs
|
||||
* */
|
||||
virtual int32_t SearchTopKNearest(const std::vector<float>& queryFeature, size_t topK, std::vector<SearchResult> &searchResults) = 0;
|
||||
|
||||
/**
|
||||
* @brief Retrieves a feature from the feature block.
|
||||
* @param row Index of the feature to retrieve.
|
||||
* @param feature Vector to store the retrieved feature.
|
||||
* @return int32_t Status of the retrieval operation.
|
||||
*/
|
||||
virtual int32_t GetFeature(int row, std::vector<float>& feature) = 0;
|
||||
|
||||
/**
|
||||
* @brief Prints the size of the feature matrix.
|
||||
*/
|
||||
virtual void PrintMatrixSize() = 0;
|
||||
|
||||
/**
|
||||
* @brief Prints the entire feature matrix.
|
||||
*/
|
||||
virtual void PrintMatrix() = 0;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Retrieves the tag associated with a feature at a given row index.
|
||||
* @param row Index of the feature to retrieve the tag for.
|
||||
* @return std::string Tag associated with the feature at the given row, or an empty string if the row is invalid.
|
||||
*/
|
||||
std::string GetTagFromRow(int row) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_); // Ensure thread safety
|
||||
if (row >= 0 && row < m_tag_list_.size() && m_feature_state_[row] == FEATURE_STATE::USED) {
|
||||
return m_tag_list_[row];
|
||||
} else {
|
||||
return ""; // Return an empty string for invalid row or unused slot
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves the state of a feature slot at a given row index.
|
||||
* @param row Index of the feature slot to retrieve the state for.
|
||||
* @return FEATURE_STATE State of the feature slot at the given row, or IDLE if the row is invalid.
|
||||
*/
|
||||
FEATURE_STATE GetStateFromRow(int row) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_); // Ensure thread safety
|
||||
if (row >= 0 && row < m_feature_state_.size()) {
|
||||
return m_feature_state_[row];
|
||||
} else {
|
||||
return FEATURE_STATE::IDLE; // Treat invalid rows as IDLE
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds the index of the first idle (unused) feature slot.
|
||||
* @return int Index of the first idle slot, or -1 if no idle slot is found.
|
||||
*/
|
||||
int FindFirstIdleIndex() const {
|
||||
for (int i = 0; i < m_feature_state_.size(); ++i) {
|
||||
if (m_feature_state_[i] == FEATURE_STATE::IDLE) {
|
||||
return i; // Find the first IDLE index
|
||||
}
|
||||
}
|
||||
return -1; // No IDLE found
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds the index of the first used feature slot.
|
||||
* @return int Index of the first used slot, or -1 if no used slot is found.
|
||||
*/
|
||||
int FindFirstUsedIndex() const {
|
||||
for (int i = 0; i < m_feature_state_.size(); ++i) {
|
||||
if (m_feature_state_[i] == FEATURE_STATE::USED) {
|
||||
return i; // Find the first USED index
|
||||
}
|
||||
}
|
||||
return -1; // not fond USED
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Counts the number of used feature slots.
|
||||
* @return int Count of used feature slots.
|
||||
*/
|
||||
int GetUsedCount() const {
|
||||
int usedCount = 0;
|
||||
for (const FEATURE_STATE& state : m_feature_state_) {
|
||||
if (state == FEATURE_STATE::USED) {
|
||||
usedCount++;
|
||||
}
|
||||
}
|
||||
return usedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if all feature slots are used.
|
||||
* @return bool True if all slots are used, false otherwise.
|
||||
*/
|
||||
bool IsUsedFull() const {
|
||||
int usedCount = GetUsedCount();
|
||||
return usedCount >= m_features_max_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds the index of a feature slot by its custom ID.
|
||||
* @param customId The custom ID to search for.
|
||||
* @return size_t Index of the slot with the given custom ID, or -1 if not found.
|
||||
*/
|
||||
size_t FindIndexByCustomId(int32_t customId) {
|
||||
auto it = std::find(m_custom_id_list_.begin(), m_custom_id_list_.end(), customId);
|
||||
if (it != m_custom_id_list_.end()) {
|
||||
return std::distance(m_custom_id_list_.begin(), it); // return index
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Adds a feature to the feature block without thread safety.
|
||||
* This method should be overridden in derived classes.
|
||||
* @param feature Vector of floats representing the feature.
|
||||
* @param tag String tag associated with the feature.
|
||||
* @param customId Custom identifier for the feature.
|
||||
* @return int32_t Status of the feature addition.
|
||||
*/
|
||||
virtual int32_t UnsafeAddFeature(const std::vector<float>& feature, const std::string &tag, int32_t customId) = 0;
|
||||
|
||||
/**
|
||||
* @brief Registers a feature at a specific index in the feature block without thread safety.
|
||||
* This method should be overridden in derived classes.
|
||||
* @param rowToUpdate Index at which to register the new feature.
|
||||
* @param feature Feature vector to be registered.
|
||||
* @param tag Tag associated with the feature.
|
||||
* @param customId Custom identifier for the feature.
|
||||
* @return int32_t Status of the feature registration.
|
||||
*/
|
||||
virtual int32_t UnsafeRegisterFeature(int rowToUpdate, const std::vector<float>& feature, const std::string &tag, int32_t customId) = 0;
|
||||
|
||||
/**
|
||||
* @brief Deletes a feature from the feature block without thread safety.
|
||||
* This method should be overridden in derived classes.
|
||||
* @param rowToDelete Index of the feature to be deleted.
|
||||
* @return int32_t Status of the feature deletion.
|
||||
*/
|
||||
virtual int32_t UnsafeDeleteFeature(int rowToDelete) = 0;
|
||||
|
||||
/**
|
||||
* @brief Updates a feature in the feature block without thread safety.
|
||||
* This method should be overridden in derived classes.
|
||||
* @param rowToUpdate Index of the feature to be updated.
|
||||
* @param newFeature New feature vector to replace the old one.
|
||||
* @param tag New tag for the updated feature.
|
||||
* @param customId Custom identifier for the updated feature.
|
||||
* @return int32_t Status of the feature update.
|
||||
*/
|
||||
virtual int32_t UnsafeUpdateFeature(int rowToUpdate, const std::vector<float>& newFeature, const std::string &tag, int32_t customId) = 0;
|
||||
|
||||
protected:
|
||||
MatrixCore m_matrix_core_; ///< Type of matrix core used.
|
||||
int32_t m_features_max_; ///< Maximum number of features in the block.
|
||||
int32_t m_feature_length_; ///< Length of each feature vector.
|
||||
std::mutex m_mtx_; ///< Mutex for thread safety.
|
||||
std::vector<FEATURE_STATE> m_feature_state_; ///< State of each feature slot.
|
||||
std::vector<String> m_tag_list_; ///< List of tags associated with each feature.
|
||||
std::vector<int32_t> m_custom_id_list_; ///< List of custom IDs associated with each feature.
|
||||
|
||||
};
|
||||
|
||||
} // namespace hyper
|
||||
|
||||
#endif //HYPERFACEREPO_FEATUREBLOCK_H
|
||||
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/11.
|
||||
//
|
||||
|
||||
#include "feature_block_none.h"
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/11.
|
||||
//
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_FEATUREBLOCKNONE_H
|
||||
#define HYPERFACEREPO_FEATUREBLOCKNONE_H
|
||||
|
||||
#include "feature_hub/features_block/feature_block.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
class INSPIRE_API FeatureBlockNone {
|
||||
public:
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
} // namespace hyper
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //HYPERFACEREPO_FEATUREBLOCKNONE_H
|
||||
@@ -0,0 +1,246 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/11.
|
||||
//
|
||||
|
||||
#include "feature_block_opencv.h"
|
||||
#include "herror.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
|
||||
FeatureBlockOpenCV::FeatureBlockOpenCV(int32_t features_max, int32_t feature_length)
|
||||
:m_feature_matrix_(features_max, feature_length, CV_32F, cv::Scalar(0.0f)){
|
||||
|
||||
}
|
||||
|
||||
int32_t FeatureBlockOpenCV::UnsafeAddFeature(const std::vector<float> &feature, const std::string &tag, int32_t customId) {
|
||||
if (feature.empty()) {
|
||||
return HERR_SESS_REC_ADD_FEAT_EMPTY; // If the feature is empty, it is not added
|
||||
}
|
||||
if (feature.size() != m_feature_length_) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR;
|
||||
}
|
||||
|
||||
if (IsUsedFull()) {
|
||||
return HERR_SESS_REC_BLOCK_FULL;
|
||||
}
|
||||
|
||||
cv::Mat newFeatureMat(1, feature.size(), CV_32FC1);
|
||||
for (int i = 0; i < feature.size(); ++i) {
|
||||
newFeatureMat.at<float>(0, i) = feature[i];
|
||||
}
|
||||
auto idx = FindFirstIdleIndex(); // Find the first free vector position
|
||||
if (idx == -1) {
|
||||
return HERR_SESS_REC_BLOCK_FULL;
|
||||
}
|
||||
cv::Mat rowToUpdate = m_feature_matrix_.row(idx);
|
||||
newFeatureMat.copyTo(rowToUpdate);
|
||||
|
||||
m_feature_state_[idx] = FEATURE_STATE::USED; // Set feature vector used
|
||||
m_tag_list_[idx] = tag;
|
||||
m_custom_id_list_[idx] = customId;
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureBlockOpenCV::UnsafeDeleteFeature(int rowToDelete) {
|
||||
if (m_feature_matrix_.empty() || rowToDelete < 0 || rowToDelete >= m_feature_matrix_.rows) {
|
||||
return HERR_SESS_REC_DEL_FAILURE; // Invalid row numbers or matrices are empty and will not be deleted
|
||||
}
|
||||
|
||||
cv::Mat rowToUpdate = m_feature_matrix_.row(rowToDelete);
|
||||
if (m_feature_state_[rowToDelete] == FEATURE_STATE::IDLE) {
|
||||
return HERR_SESS_REC_BLOCK_DEL_FAILURE; // Rows are idle and will not be deleted
|
||||
}
|
||||
|
||||
m_feature_state_[rowToDelete] = FEATURE_STATE::IDLE;
|
||||
m_custom_id_list_[rowToDelete] = -1;
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
int32_t FeatureBlockOpenCV::UnsafeRegisterFeature(int rowToUpdate, const std::vector<float> &feature, const std::string &tag, int32_t customId) {
|
||||
if (rowToUpdate < 0 || rowToUpdate >= m_feature_matrix_.rows) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR; // Invalid line number, not updated
|
||||
}
|
||||
|
||||
if (feature.size() != m_feature_length_) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR; // The new feature does not match the expected size and will not be updated
|
||||
}
|
||||
cv::Mat rowToUpdateMat = m_feature_matrix_.row(rowToUpdate);
|
||||
// 将新特征拷贝到指定行
|
||||
for (int i = 0; i < feature.size(); ++i) {
|
||||
rowToUpdateMat.at<float>(0, i) = feature[i];
|
||||
}
|
||||
m_feature_state_[rowToUpdate] = USED;
|
||||
m_tag_list_[rowToUpdate] = tag;
|
||||
m_custom_id_list_[rowToUpdate] = customId;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FeatureBlockOpenCV::UnsafeUpdateFeature(int rowToUpdate, const std::vector<float> &newFeature, const std::string &tag, int32_t customId) {
|
||||
if (rowToUpdate < 0 || rowToUpdate >= m_feature_matrix_.rows) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR; // Invalid line number, not updated
|
||||
}
|
||||
|
||||
if (newFeature.size() != m_feature_length_) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR; // The new feature does not match the expected size and will not be updated
|
||||
}
|
||||
|
||||
cv::Mat rowToUpdateMat = m_feature_matrix_.row(rowToUpdate);
|
||||
if (m_feature_state_[rowToUpdate] == FEATURE_STATE::IDLE) {
|
||||
return HERR_SESS_REC_BLOCK_UPDATE_FAILURE; // Rows are idle and not updated
|
||||
}
|
||||
|
||||
// Copies the new feature to the specified row
|
||||
for (int i = 0; i < newFeature.size(); ++i) {
|
||||
rowToUpdateMat.at<float>(0, i) = newFeature[i];
|
||||
}
|
||||
m_tag_list_[rowToUpdate] = tag;
|
||||
m_custom_id_list_[rowToUpdate] = customId;
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t FeatureBlockOpenCV::SearchNearest(const std::vector<float>& queryFeature, SearchResult &searchResult) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
|
||||
if (queryFeature.size() != m_feature_length_) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR;
|
||||
}
|
||||
|
||||
if (GetUsedCount() == 0) {
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
cv::Mat queryMat(queryFeature.size(), 1, CV_32FC1, (void*)queryFeature.data());
|
||||
|
||||
// Calculate the cosine similarity matrix
|
||||
cv::Mat cosineSimilarities;
|
||||
cv::gemm(m_feature_matrix_, queryMat, 1, cv::Mat(), 0, cosineSimilarities);
|
||||
// Asserts that cosineSimilarities are the vector of m_features_max_ x 1
|
||||
assert(cosineSimilarities.rows == m_features_max_ && cosineSimilarities.cols == 1);
|
||||
|
||||
// Used to store similarity scores and their indexes
|
||||
std::vector<std::pair<float, int>> similarityScores;
|
||||
|
||||
for (int i = 0; i < m_features_max_; ++i) {
|
||||
// Check whether the status is IDLE
|
||||
if (m_feature_state_[i] == FEATURE_STATE::IDLE) {
|
||||
continue; // Skip the eigenvector of IDLE state
|
||||
}
|
||||
|
||||
// Gets the similarity score for line i
|
||||
float similarityScore = cosineSimilarities.at<float>(i, 0);
|
||||
|
||||
// Adds the similarity score and index to the vector as a pair
|
||||
similarityScores.push_back(std::make_pair(similarityScore, i));
|
||||
}
|
||||
|
||||
// Find the index of the largest scores in similarityScores
|
||||
if (!similarityScores.empty()) {
|
||||
auto maxScoreIter = std::max_element(similarityScores.begin(), similarityScores.end());
|
||||
float maxScore = maxScoreIter->first;
|
||||
int maxScoreIndex = maxScoreIter->second;
|
||||
|
||||
// Sets the value in the searchResult
|
||||
searchResult.score = maxScore;
|
||||
searchResult.index = maxScoreIndex;
|
||||
searchResult.tag = m_tag_list_[maxScoreIndex];
|
||||
searchResult.customId = m_custom_id_list_[maxScoreIndex];
|
||||
|
||||
return HSUCCEED; // Indicates that the maximum score is found
|
||||
}
|
||||
|
||||
|
||||
searchResult.score = -1.0f;
|
||||
searchResult.index = -1;
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
int32_t FeatureBlockOpenCV::SearchTopKNearest(const std::vector<float> &queryFeature, size_t topK, std::vector<SearchResult> &searchResults) {
|
||||
std::lock_guard<std::mutex> lock(m_mtx_);
|
||||
|
||||
if (queryFeature.size() != m_feature_length_) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR;
|
||||
}
|
||||
|
||||
if (GetUsedCount() == 0) {
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
cv::Mat queryMat(queryFeature.size(), 1, CV_32FC1, (void*)queryFeature.data());
|
||||
|
||||
// Calculate the cosine similarity matrix
|
||||
cv::Mat cosineSimilarities;
|
||||
cv::gemm(m_feature_matrix_, queryMat, 1, cv::Mat(), 0, cosineSimilarities);
|
||||
// Asserts that cosineSimilarities are the vector of m_features_max_ x 1
|
||||
assert(cosineSimilarities.rows == m_features_max_ && cosineSimilarities.cols == 1);
|
||||
|
||||
// Used to store similarity scores and their indexes
|
||||
std::vector<std::pair<float, int>> similarityScores;
|
||||
|
||||
for (int i = 0; i < m_features_max_; ++i) {
|
||||
// Check whether the status is IDLE
|
||||
if (m_feature_state_[i] == FEATURE_STATE::IDLE) {
|
||||
continue; // Skip the eigenvector of IDLE state
|
||||
}
|
||||
|
||||
// Gets the similarity score for line i
|
||||
float similarityScore = cosineSimilarities.at<float>(i, 0);
|
||||
|
||||
// Adds the similarity score and index to the vector as a pair
|
||||
similarityScores.push_back(std::make_pair(similarityScore, i));
|
||||
}
|
||||
|
||||
searchResults.clear();
|
||||
if (similarityScores.size() < topK) {
|
||||
topK = similarityScores.size();
|
||||
}
|
||||
std::partial_sort(similarityScores.begin(), similarityScores.begin() + topK, similarityScores.end(),
|
||||
[](const std::pair<float, int>& a, const std::pair<float, int>& b) {
|
||||
return a.first > b.first;
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < topK; i++) {
|
||||
SearchResult result;
|
||||
result.score = similarityScores[i].first;
|
||||
result.index = similarityScores[i].second;
|
||||
result.tag = m_tag_list_[result.index];
|
||||
result.customId = m_custom_id_list_[result.index];
|
||||
searchResults.push_back(result);
|
||||
}
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
void FeatureBlockOpenCV::PrintMatrixSize() {
|
||||
std::cout << m_feature_matrix_.size << std::endl;
|
||||
}
|
||||
|
||||
void FeatureBlockOpenCV::PrintMatrix() {
|
||||
INSPIRE_LOGD("Num of Features: %d", m_feature_matrix_.cols);
|
||||
INSPIRE_LOGD("Feature length: %d", m_feature_matrix_.rows);
|
||||
}
|
||||
|
||||
int32_t FeatureBlockOpenCV::GetFeature(int row, std::vector<float> &feature) {
|
||||
if (row < 0 || row >= m_feature_matrix_.rows) {
|
||||
return HERR_SESS_REC_FEAT_SIZE_ERR; // Invalid line number, not updated
|
||||
}
|
||||
cv::Mat feat = m_feature_matrix_.row(row);
|
||||
// Copies the new feature to the specified row
|
||||
for (int i = 0; i < m_feature_length_; ++i) {
|
||||
feature.push_back(feat.at<float>(0, i));
|
||||
}
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace hyper
|
||||
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/11.
|
||||
//
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_FEATUREBLOCKOPENCV_H
|
||||
#define HYPERFACEREPO_FEATUREBLOCKOPENCV_H
|
||||
#include "feature_hub/features_block/feature_block.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @class FeatureBlockOpenCV
|
||||
* @brief Class derived from FeatureBlock for managing facial features using OpenCV.
|
||||
*
|
||||
* This class provides an implementation of FeatureBlock using OpenCV's Mat data structure
|
||||
* for storing and manipulating facial features.
|
||||
*/
|
||||
class INSPIRE_API FeatureBlockOpenCV : public FeatureBlock{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor for FeatureBlockOpenCV.
|
||||
* @param features_max Maximum number of features that can be stored.
|
||||
* @param feature_length Length of each feature vector.
|
||||
*/
|
||||
explicit FeatureBlockOpenCV(int32_t features_max = 512, int32_t feature_length = 512);
|
||||
|
||||
/**
|
||||
* @brief Searches for the nearest feature in the block to a given query feature.
|
||||
* @param queryFeature Query feature vector.
|
||||
* @param searchResult SearchResult structure to store the search results.
|
||||
* @return int32_t Status of the search operation.
|
||||
*/
|
||||
int32_t SearchNearest(const std::vector<float>& queryFeature, SearchResult &searchResult) override;
|
||||
|
||||
/**
|
||||
* @brief Search the first k features in a block that are closest to a given query feature.
|
||||
* @param topK Maximum number of similarities
|
||||
* @param searchResults outputs
|
||||
* */
|
||||
int32_t SearchTopKNearest(const std::vector<float>& queryFeature, size_t topK, std::vector<SearchResult> &searchResults) override;
|
||||
|
||||
/**
|
||||
* @brief Retrieves a feature from the feature block.
|
||||
* @param row Index of the feature to retrieve.
|
||||
* @param feature Vector to store the retrieved feature.
|
||||
* @return int32_t Status of the retrieval operation.
|
||||
*/
|
||||
int32_t GetFeature(int row, std::vector<float> &feature) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Adds a feature to the feature block without thread safety.
|
||||
* This method should be overridden in derived classes.
|
||||
* @param feature Vector of floats representing the feature.
|
||||
* @param tag String tag associated with the feature.
|
||||
* @param customId Custom identifier for the feature.
|
||||
* @return int32_t Status of the feature addition.
|
||||
*/
|
||||
int32_t UnsafeAddFeature(const std::vector<float> &feature, const std::string &tag, int32_t customId) override;
|
||||
|
||||
/**
|
||||
* @brief Registers a feature at a specific index in the feature block without thread safety.
|
||||
* This method should be overridden in derived classes.
|
||||
* @param rowToUpdate Index at which to register the new feature.
|
||||
* @param feature Feature vector to be registered.
|
||||
* @param tag Tag associated with the feature.
|
||||
* @param customId Custom identifier for the feature.
|
||||
* @return int32_t Status of the feature registration.
|
||||
*/
|
||||
int32_t UnsafeDeleteFeature(int rowToDelete) override;
|
||||
|
||||
/**
|
||||
* @brief Deletes a feature from the feature block without thread safety.
|
||||
* This method should be overridden in derived classes.
|
||||
* @param rowToDelete Index of the feature to be deleted.
|
||||
* @return int32_t Status of the feature deletion.
|
||||
*/
|
||||
int32_t UnsafeUpdateFeature(int rowToUpdate, const std::vector<float> &newFeature, const std::string &tag, int32_t customId) override;
|
||||
|
||||
/**
|
||||
* @brief Updates a feature in the feature block without thread safety.
|
||||
* This method should be overridden in derived classes.
|
||||
* @param rowToUpdate Index of the feature to be updated.
|
||||
* @param newFeature New feature vector to replace the old one.
|
||||
* @param tag New tag for the updated feature.
|
||||
* @param customId Custom identifier for the updated feature.
|
||||
* @return int32_t Status of the feature update.
|
||||
*/
|
||||
int32_t UnsafeRegisterFeature(int rowToUpdate, const std::vector<float> &feature, const std::string &tag, int32_t customId) override;
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Prints the size of the feature matrix.
|
||||
*/
|
||||
void PrintMatrixSize() override;
|
||||
|
||||
/**
|
||||
* @brief Prints the entire feature matrix.
|
||||
*/
|
||||
void PrintMatrix() override;
|
||||
|
||||
private:
|
||||
|
||||
cv::Mat m_feature_matrix_; ///< Matrix for storing feature vectors.
|
||||
|
||||
};
|
||||
|
||||
} // namespace hyper
|
||||
|
||||
|
||||
#endif //HYPERFACEREPO_FEATUREBLOCKOPENCV_H
|
||||
@@ -0,0 +1,346 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/10/11.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip> // for std::setw
|
||||
#include "sqlite_faces_manage.h"
|
||||
#include "herror.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
|
||||
SQLiteFaceManage::SQLiteFaceManage() {
|
||||
|
||||
}
|
||||
|
||||
SQLiteFaceManage::~SQLiteFaceManage() {
|
||||
CloseDatabase();
|
||||
// Optionally, you can add logging here if needed:
|
||||
// LOG_INFO("SQLiteFaceManage object destroyed and database connection closed.");
|
||||
}
|
||||
|
||||
struct SQLiteDeleter {
|
||||
void operator()(sqlite3* ptr) const {
|
||||
sqlite3_close(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int32_t SQLiteFaceManage::OpenDatabase(const std::string &dbPath) {
|
||||
sqlite3* rawDb;
|
||||
if (sqlite3_open(dbPath.c_str(), &rawDb) != SQLITE_OK) {
|
||||
// Handle error
|
||||
return HERR_FT_HUB_OPEN_ERROR;
|
||||
}
|
||||
|
||||
m_db_ = std::shared_ptr<sqlite3>(rawDb, SQLiteDeleter());
|
||||
|
||||
// Check if the table exists
|
||||
const char* checkTableSQL = "SELECT name FROM sqlite_master WHERE type='table' AND name='FaceFeatures';";
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
|
||||
if (sqlite3_prepare_v2(m_db_.get(), checkTableSQL, -1, &stmt, nullptr) != SQLITE_OK) {
|
||||
INSPIRE_LOGE("Error checking for table existence: %s", sqlite3_errmsg(m_db_.get()));
|
||||
return HERR_FT_HUB_CHECK_TABLE_ERROR; // Assuming you have this error code
|
||||
}
|
||||
|
||||
int result = sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
// If table doesn't exist, create it
|
||||
if (result != SQLITE_ROW) {
|
||||
return CreateTable();
|
||||
}
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
int32_t SQLiteFaceManage::CloseDatabase() {
|
||||
if (!m_db_) {
|
||||
// LOGE("Attempted to close an already closed or uninitialized database.");
|
||||
return HERR_FT_HUB_NOT_OPENED;
|
||||
}
|
||||
|
||||
// Reset the shared_ptr. This will decrease its reference count.
|
||||
// If this is the last reference, the database will be closed due to the custom deleter.
|
||||
m_db_.reset();
|
||||
|
||||
// Optionally, log that the database was successfully closed
|
||||
// LOGD("Database successfully closed.");
|
||||
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t SQLiteFaceManage::CreateTable() {
|
||||
if (!m_db_) {
|
||||
INSPIRE_LOGE("Database is not opened. Please open the database first.");
|
||||
return HERR_FT_HUB_NOT_OPENED; // Example error code for unopened database
|
||||
}
|
||||
|
||||
const char* createTableSQL = R"(
|
||||
CREATE TABLE IF NOT EXISTS FaceFeatures (
|
||||
customId INTEGER PRIMARY KEY,
|
||||
tag TEXT,
|
||||
feature BLOB
|
||||
)
|
||||
)";
|
||||
|
||||
char* errMsg = nullptr;
|
||||
int result = sqlite3_exec(m_db_.get(), createTableSQL, 0, 0, &errMsg);
|
||||
|
||||
if (result != SQLITE_OK) {
|
||||
INSPIRE_LOGE("Error creating table: %s" , errMsg);
|
||||
sqlite3_free(errMsg);
|
||||
return result;
|
||||
}
|
||||
|
||||
// LOGD("Table successfully created or already exists.");
|
||||
return SQLITE_OK; // or SUCCESS_CODE, based on your error code system
|
||||
}
|
||||
|
||||
int32_t SQLiteFaceManage::InsertFeature(const FaceFeatureInfo& info) {
|
||||
if (!m_db_) {
|
||||
INSPIRE_LOGE("Database is not opened. Please open the database first.");
|
||||
return HERR_FT_HUB_NOT_OPENED; // Example error code for unopened database
|
||||
}
|
||||
|
||||
const char* insertSQL = "INSERT INTO FaceFeatures (customId, tag, feature) VALUES (?, ?, ?)";
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
|
||||
int result = sqlite3_prepare_v2(m_db_.get(), insertSQL, -1, &stmt, nullptr);
|
||||
if (result != SQLITE_OK) {
|
||||
INSPIRE_LOGE("Error preparing the SQL statement: %s", sqlite3_errmsg(m_db_.get()));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Binding values
|
||||
sqlite3_bind_int(stmt, 1, info.customId);
|
||||
sqlite3_bind_text(stmt, 2, info.tag.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_blob(stmt, 3, info.feature.data(), info.feature.size() * sizeof(float), SQLITE_STATIC);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
INSPIRE_LOGE("Error inserting new feature: %s" , sqlite3_errmsg(m_db_.get()));
|
||||
sqlite3_finalize(stmt);
|
||||
return HERR_FT_HUB_INSERT_FAILURE;
|
||||
}
|
||||
|
||||
// Clean up the statement
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
// LOGD("Feature successfully inserted.");
|
||||
return SQLITE_OK; // or SUCCESS_CODE, based on your error code system
|
||||
}
|
||||
|
||||
int32_t SQLiteFaceManage::GetFeature(int32_t customId, FaceFeatureInfo& outInfo) {
|
||||
if (!m_db_) {
|
||||
INSPIRE_LOGE("Database is not opened. Please open the database first.");
|
||||
return HERR_FT_HUB_NOT_OPENED;
|
||||
}
|
||||
|
||||
const char* selectSQL = "SELECT customId, tag, feature FROM FaceFeatures WHERE customId = ?";
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
|
||||
int result = sqlite3_prepare_v2(m_db_.get(), selectSQL, -1, &stmt, nullptr);
|
||||
if (result != SQLITE_OK) {
|
||||
INSPIRE_LOGE("Error preparing the SQL statement: %s", sqlite3_errmsg(m_db_.get()));
|
||||
return HERR_FT_HUB_PREPARING_FAILURE;
|
||||
}
|
||||
|
||||
// Bind the customId to the prepared statement
|
||||
sqlite3_bind_int(stmt, 1, customId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result == SQLITE_ROW) {
|
||||
outInfo.customId = sqlite3_column_int(stmt, 0);
|
||||
outInfo.tag = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
|
||||
|
||||
const void* blobData = sqlite3_column_blob(stmt, 2);
|
||||
int blobSize = sqlite3_column_bytes(stmt, 2) / sizeof(float);
|
||||
const float* begin = static_cast<const float*>(blobData);
|
||||
outInfo.feature = std::vector<float>(begin, begin + blobSize);
|
||||
|
||||
} else if (result == SQLITE_DONE) {
|
||||
INSPIRE_LOGE("No feature found with customId: %d", customId);
|
||||
sqlite3_finalize(stmt);
|
||||
return HERR_FT_HUB_NO_RECORD_FOUND; // Assuming you have an error code for record not found
|
||||
} else {
|
||||
INSPIRE_LOGE("Error executing the SQL statement: %s", sqlite3_errmsg(m_db_.get()));
|
||||
sqlite3_finalize(stmt);
|
||||
return HERR_FT_HUB_EXECUTING_FAILURE;
|
||||
}
|
||||
|
||||
// Clean up the statement
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
INSPIRE_LOGD("Feature successfully retrieved.");
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t SQLiteFaceManage::DeleteFeature(int32_t customId) {
|
||||
if (!m_db_) {
|
||||
INSPIRE_LOGE("Database is not opened. Please open the database first.");
|
||||
return HERR_FT_HUB_NOT_OPENED;
|
||||
}
|
||||
|
||||
const char* deleteSQL = "DELETE FROM FaceFeatures WHERE customId = ?";
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
|
||||
int result = sqlite3_prepare_v2(m_db_.get(), deleteSQL, -1, &stmt, nullptr);
|
||||
if (result != SQLITE_OK) {
|
||||
INSPIRE_LOGE("Error preparing the SQL statement: %s", sqlite3_errmsg(m_db_.get()));
|
||||
return HERR_FT_HUB_PREPARING_FAILURE;
|
||||
}
|
||||
|
||||
// Bind the customId to the prepared statement
|
||||
sqlite3_bind_int(stmt, 1, customId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
INSPIRE_LOGE("Error deleting feature with customId: %d, Error: %s", customId, sqlite3_errmsg(m_db_.get()));
|
||||
sqlite3_finalize(stmt);
|
||||
return HERR_FT_HUB_EXECUTING_FAILURE;
|
||||
}
|
||||
|
||||
int changes = sqlite3_changes(m_db_.get());
|
||||
if (changes == 0) {
|
||||
INSPIRE_LOGE("No feature found with customId: %d. Nothing was deleted.", customId);
|
||||
sqlite3_finalize(stmt);
|
||||
return HERR_FT_HUB_NO_RECORD_FOUND; // Assuming you have an error code for record not found
|
||||
}
|
||||
|
||||
// Clean up the statement
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
// LOGD("Feature with customId: %d successfully deleted.", customId);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t SQLiteFaceManage::UpdateFeature(const FaceFeatureInfo& info) {
|
||||
if (!m_db_) {
|
||||
INSPIRE_LOGE("Database is not opened. Please open the database first.");
|
||||
return HERR_FT_HUB_NOT_OPENED;
|
||||
}
|
||||
|
||||
const char* updateSQL = "UPDATE FaceFeatures SET tag = ?, feature = ? WHERE customId = ?";
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
|
||||
int result = sqlite3_prepare_v2(m_db_.get(), updateSQL, -1, &stmt, nullptr);
|
||||
if (result != SQLITE_OK) {
|
||||
INSPIRE_LOGE("Error preparing the SQL statement: %s", sqlite3_errmsg(m_db_.get()));
|
||||
return HERR_FT_HUB_PREPARING_FAILURE;
|
||||
}
|
||||
|
||||
// Binding values
|
||||
sqlite3_bind_text(stmt, 1, info.tag.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_blob(stmt, 2, info.feature.data(), info.feature.size() * sizeof(float), SQLITE_STATIC);
|
||||
sqlite3_bind_int(stmt, 3, info.customId);
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_DONE) {
|
||||
INSPIRE_LOGE("Error updating feature with customId: %d, Error: %s", info.customId, sqlite3_errmsg(m_db_.get()));
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
}
|
||||
|
||||
int changes = sqlite3_changes(m_db_.get());
|
||||
if (changes == 0) {
|
||||
INSPIRE_LOGE("No feature found with customId: %d. Nothing was updated.", info.customId);
|
||||
sqlite3_finalize(stmt);
|
||||
return HERR_FT_HUB_NO_RECORD_FOUND; // Assuming you have an error code for record not found
|
||||
}
|
||||
|
||||
// Clean up the statement
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
// LOGD("Feature with customId: %d successfully updated.", info.customId);
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t SQLiteFaceManage::ViewTotal() {
|
||||
if (!m_db_) {
|
||||
INSPIRE_LOGE("Database is not opened. Please open the database first.");
|
||||
return HERR_FT_HUB_NOT_OPENED;
|
||||
}
|
||||
|
||||
const char* selectSQL = "SELECT customId, tag FROM FaceFeatures";
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
|
||||
int result = sqlite3_prepare_v2(m_db_.get(), selectSQL, -1, &stmt, nullptr);
|
||||
if (result != SQLITE_OK) {
|
||||
INSPIRE_LOGE("Error preparing the SQL statement: %s", sqlite3_errmsg(m_db_.get()));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Print table header
|
||||
std::cout << "+----------+-----------------------+\n";
|
||||
std::cout << "| customId | tag |\n";
|
||||
std::cout << "+----------+-----------------------+\n";
|
||||
|
||||
while ((result = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||
int32_t customId = sqlite3_column_int(stmt, 0);
|
||||
const unsigned char* tag = sqlite3_column_text(stmt, 1);
|
||||
|
||||
std::cout << "| " << std::setw(8) << customId << " | " << std::setw(21) << tag << " |\n";
|
||||
}
|
||||
std::cout << "+----------+-----------------------+\n";
|
||||
|
||||
if (result != SQLITE_DONE) {
|
||||
INSPIRE_LOGE("Error executing the SQL statement: %s", sqlite3_errmsg(m_db_.get()));
|
||||
sqlite3_finalize(stmt);
|
||||
return HERR_FT_HUB_PREPARING_FAILURE;
|
||||
}
|
||||
|
||||
// Clean up the statement
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
INSPIRE_LOGD("Successfully displayed all records.");
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
int32_t SQLiteFaceManage::GetTotalFeatures(std::vector<FaceFeatureInfo>& infoList) {
|
||||
if (!m_db_) {
|
||||
INSPIRE_LOGE("Database is not opened. Please open the database first.");
|
||||
return HERR_FT_HUB_NOT_OPENED;
|
||||
}
|
||||
|
||||
const char* selectSQL = "SELECT customId, tag, feature FROM FaceFeatures";
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
|
||||
int result = sqlite3_prepare_v2(m_db_.get(), selectSQL, -1, &stmt, nullptr);
|
||||
if (result != SQLITE_OK) {
|
||||
INSPIRE_LOGE("Error preparing the SQL statement: %s", sqlite3_errmsg(m_db_.get()));
|
||||
return HERR_FT_HUB_PREPARING_FAILURE;
|
||||
}
|
||||
|
||||
while ((result = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||
FaceFeatureInfo featureInfo;
|
||||
|
||||
featureInfo.customId = sqlite3_column_int(stmt, 0);
|
||||
featureInfo.tag = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
|
||||
|
||||
const void* blobData = sqlite3_column_blob(stmt, 2);
|
||||
int blobSize = sqlite3_column_bytes(stmt, 2) / sizeof(float);
|
||||
const float* begin = static_cast<const float*>(blobData);
|
||||
featureInfo.feature = std::vector<float>(begin, begin + blobSize);
|
||||
|
||||
infoList.push_back(featureInfo);
|
||||
}
|
||||
|
||||
if (result != SQLITE_DONE) {
|
||||
INSPIRE_LOGE("Error executing the SQL statement: %s", sqlite3_errmsg(m_db_.get()));
|
||||
sqlite3_finalize(stmt);
|
||||
return HERR_FT_HUB_EXECUTING_FAILURE;
|
||||
}
|
||||
|
||||
// Clean up the statement
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
// LOGD("Successfully retrieved all features.");
|
||||
return HSUCCEED;
|
||||
}
|
||||
|
||||
|
||||
} // namespace hyper
|
||||
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/10/11.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_SQLITEFACEMANAGE_H
|
||||
#define HYPERFACEREPO_SQLITEFACEMANAGE_H
|
||||
|
||||
#include "data_type.h"
|
||||
#include "log.h"
|
||||
#include "middleware/sqlite/sqlite3.h" // Include the SQLite3 header
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "memory"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @struct FaceFeatureInfo
|
||||
* @brief Structure to represent information about a facial feature.
|
||||
*/
|
||||
typedef struct {
|
||||
int32_t customId; ///< Custom identifier for the feature.
|
||||
std::string tag; ///< Tag associated with the feature.
|
||||
std::vector<float> feature; ///< Vector of floats representing the feature.
|
||||
} FaceFeatureInfo;
|
||||
|
||||
/**
|
||||
* @class SQLiteFaceManage
|
||||
* @brief Class for managing facial features using SQLite database.
|
||||
*
|
||||
* This class provides methods to open, close, create tables, insert, retrieve, delete, and update
|
||||
* facial features in an SQLite database. It also allows viewing the total number of features in the database.
|
||||
*/
|
||||
class INSPIRE_API SQLiteFaceManage {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for SQLiteFaceManage class.
|
||||
*/
|
||||
SQLiteFaceManage();
|
||||
|
||||
/**
|
||||
* @brief Destructor for SQLiteFaceManage class.
|
||||
*/
|
||||
~SQLiteFaceManage();
|
||||
|
||||
/**
|
||||
* @brief Opens an SQLite database at the specified path.
|
||||
*
|
||||
* @param dbPath Path to the SQLite database file.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t OpenDatabase(const std::string& dbPath);
|
||||
|
||||
/**
|
||||
* @brief Closes the currently open SQLite database.
|
||||
*
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t CloseDatabase();
|
||||
|
||||
/**
|
||||
* @brief Creates an SQLite table for storing facial features if it doesn't exist.
|
||||
*
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t CreateTable();
|
||||
|
||||
/**
|
||||
* @brief Inserts a facial feature into the SQLite database.
|
||||
*
|
||||
* @param info Information about the facial feature to be inserted.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t InsertFeature(const FaceFeatureInfo& info);
|
||||
|
||||
/**
|
||||
* @brief Retrieves information about a facial feature from the SQLite database by custom ID.
|
||||
*
|
||||
* @param customId Custom identifier of the facial feature to retrieve.
|
||||
* @param outInfo Output parameter to store the retrieved feature information.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t GetFeature(int32_t customId, FaceFeatureInfo& outInfo);
|
||||
|
||||
/**
|
||||
* @brief Deletes a facial feature from the SQLite database by custom ID.
|
||||
*
|
||||
* @param customId Custom identifier of the facial feature to delete.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t DeleteFeature(int32_t customId);
|
||||
|
||||
/**
|
||||
* @brief Updates a facial feature in the SQLite database.
|
||||
*
|
||||
* @param info Updated information about the facial feature.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t UpdateFeature(const FaceFeatureInfo& info);
|
||||
|
||||
/**
|
||||
* @brief Retrieves information about all facial features stored in the SQLite database.
|
||||
*
|
||||
* @param infoList Output parameter to store the list of facial feature information.
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t GetTotalFeatures(std::vector<FaceFeatureInfo>& infoList);
|
||||
|
||||
/**
|
||||
* @brief Displays the total number of facial features stored in the SQLite database.
|
||||
*
|
||||
* @return int32_t Status code indicating success (0) or failure.
|
||||
*/
|
||||
int32_t ViewTotal();
|
||||
|
||||
private:
|
||||
std::shared_ptr<sqlite3> m_db_; ///< Pointer to the SQLite database.
|
||||
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif //HYPERFACEREPO_SQLITEFACEMANAGE_H
|
||||
60
cpp-package/inspireface/cpp/inspireface/feature_hub/simd.h
Executable file
60
cpp-package/inspireface/cpp/inspireface/feature_hub/simd.h
Executable file
@@ -0,0 +1,60 @@
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/* Microsoft C/C++-compatible compiler */
|
||||
#include <intrin.h>
|
||||
#elif (defined(__x86_64__) || defined(__i386__))
|
||||
/* GCC-compatible compiler, targeting x86/x86-64 */
|
||||
#include <x86intrin.h>
|
||||
#elif defined(__ARM_NEON__)
|
||||
/* GCC-compatible compiler, targeting ARM with NEON */
|
||||
#include <arm_neon.h>
|
||||
#pragma message("USE SSE")
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && \
|
||||
(defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER))
|
||||
inline float simd_dot(const float *x, const float *y, const long &len) {
|
||||
//#pragma message("USE SSE")
|
||||
float inner_prod = 0.0f;
|
||||
__m128 X, Y, Z; // 128-bit values
|
||||
__m128 acc = _mm_setzero_ps(); // set to (0, 0, 0, 0)
|
||||
float temp[4];
|
||||
|
||||
long i;
|
||||
for (i = 0; i + 4 < len; i += 4) {
|
||||
X = _mm_loadu_ps(x + i); // load chunk of 4 floats
|
||||
Y = _mm_loadu_ps(y + i);
|
||||
Z = _mm_mul_ps(X, Y);
|
||||
acc = _mm_add_ps(acc, Z);
|
||||
}
|
||||
_mm_storeu_ps(&temp[0], acc); // store acc into an array
|
||||
inner_prod = temp[0] + temp[1] + temp[2] + temp[3];
|
||||
|
||||
// add the remaining values
|
||||
for (; i < len; ++i) {
|
||||
inner_prod += x[i] * y[i];
|
||||
}
|
||||
return inner_prod;
|
||||
}
|
||||
#else
|
||||
inline float simd_dot(const float *x, const float *y, const long &len) {
|
||||
//#pragma message("USE NEON")
|
||||
float inner_prod = 0.0f;
|
||||
float32x4_t X, Y, Z; // 128-bit values
|
||||
float32x4_t acc = vdupq_n_f32(0.0f); // set to (0, 0, 0, 0)
|
||||
long i;
|
||||
for (i = 0; i + 4 < len; i += 4) {
|
||||
X = vld1q_f32(x + i); // load chunk of 4 floats
|
||||
Y = vld1q_f32(y + i);
|
||||
Z = vmulq_f32(X, Y);
|
||||
acc = vaddq_f32(acc, Z);
|
||||
}
|
||||
inner_prod = vgetq_lane_f32(acc, 0) + vgetq_lane_f32(acc, 1) +
|
||||
vgetq_lane_f32(acc, 2) + vgetq_lane_f32(acc, 3);
|
||||
for (; i < len; ++i) {
|
||||
inner_prod += x[i] * y[i];
|
||||
}
|
||||
return inner_prod;
|
||||
}
|
||||
#endif
|
||||
68
cpp-package/inspireface/cpp/inspireface/herror.h
Normal file
68
cpp-package/inspireface/cpp/inspireface/herror.h
Normal file
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/11.
|
||||
//
|
||||
|
||||
#ifndef HYPERFACEREPO_HERROR_H
|
||||
#define HYPERFACEREPO_HERROR_H
|
||||
|
||||
|
||||
// [Anchor-Begin]
|
||||
|
||||
#define HSUCCEED (0) // Success
|
||||
#define HERR_BASIC_BASE 0X0001 // Basic error types
|
||||
#define HERR_UNKNOWN HERR_BASIC_BASE // Unknown error
|
||||
#define HERR_INVALID_PARAM (HERR_BASIC_BASE+1) // Invalid parameter
|
||||
#define HERR_INVALID_IMAGE_STREAM_HANDLE (HERR_BASIC_BASE+24) // Invalid image stream handle
|
||||
#define HERR_INVALID_CONTEXT_HANDLE (HERR_BASIC_BASE+25) // Invalid context handle
|
||||
#define HERR_INVALID_FACE_TOKEN (HERR_BASIC_BASE+30) // Invalid face token
|
||||
#define HERR_INVALID_FACE_FEATURE (HERR_BASIC_BASE+31) // Invalid face feature
|
||||
#define HERR_INVALID_FACE_LIST (HERR_BASIC_BASE+32) // Invalid face feature list
|
||||
#define HERR_INVALID_BUFFER_SIZE (HERR_BASIC_BASE+33) // Invalid copy token
|
||||
#define HERR_INVALID_IMAGE_STREAM_PARAM (HERR_BASIC_BASE+34) // Invalid image param
|
||||
#define HERR_INVALID_SERIALIZATION_FAILED (HERR_BASIC_BASE+35) // Invalid face serialization failed
|
||||
|
||||
#define HERR_SESS_BASE 0X500 // Session error types
|
||||
#define HERR_SESS_FUNCTION_UNUSABLE (HERR_SESS_BASE+2) // Function not usable
|
||||
#define HERR_SESS_TRACKER_FAILURE (HERR_SESS_BASE+3) // Tracker module not initialized
|
||||
#define HERR_SESS_INVALID_RESOURCE (HERR_SESS_BASE+10) // Invalid static resource
|
||||
#define HERR_SESS_NUM_OF_MODELS_NOT_MATCH (HERR_SESS_BASE+11) // Number of models does not match
|
||||
|
||||
#define HERR_SESS_PIPELINE_FAILURE (HERR_SESS_BASE+8) // Pipeline module not initialized
|
||||
|
||||
#define HERR_SESS_REC_EXTRACT_FAILURE (HERR_SESS_BASE+15) // Face feature extraction not registered
|
||||
#define HERR_SESS_REC_DEL_FAILURE (HERR_SESS_BASE+16) // Face feature deletion failed due to out of range index
|
||||
#define HERR_SESS_REC_UPDATE_FAILURE (HERR_SESS_BASE+17) // Face feature update failed due to out of range index
|
||||
#define HERR_SESS_REC_ADD_FEAT_EMPTY (HERR_SESS_BASE+18) // Feature vector for registration cannot be empty
|
||||
#define HERR_SESS_REC_FEAT_SIZE_ERR (HERR_SESS_BASE+19) // Incorrect length of feature vector for registration
|
||||
#define HERR_SESS_REC_INVALID_INDEX (HERR_SESS_BASE+20) // Invalid index number
|
||||
#define HERR_SESS_REC_CONTRAST_FEAT_ERR (HERR_SESS_BASE+23) // Incorrect length of feature vector for comparison
|
||||
#define HERR_SESS_REC_BLOCK_FULL (HERR_SESS_BASE+24) // Feature vector block full
|
||||
#define HERR_SESS_REC_BLOCK_DEL_FAILURE (HERR_SESS_BASE+25) // Deletion failed
|
||||
#define HERR_SESS_REC_BLOCK_UPDATE_FAILURE (HERR_SESS_BASE+26) // Update failed
|
||||
#define HERR_SESS_REC_ID_ALREADY_EXIST (HERR_SESS_BASE+27) // ID already exists
|
||||
|
||||
#define HERR_SESS_FACE_DATA_ERROR (HERR_SESS_BASE+30) // Face data parsing
|
||||
|
||||
#define HERR_SESS_FACE_REC_OPTION_ERROR (HERR_SESS_BASE+40) // An optional parameter is incorrect
|
||||
|
||||
#define HERR_FT_HUB_DISABLE (HERR_SESS_BASE+49) // FeatureHub is disabled
|
||||
#define HERR_FT_HUB_OPEN_ERROR (HERR_SESS_BASE+50) // Database open error
|
||||
#define HERR_FT_HUB_NOT_OPENED (HERR_SESS_BASE+51) // Database not opened
|
||||
#define HERR_FT_HUB_NO_RECORD_FOUND (HERR_SESS_BASE+52) // No record found
|
||||
#define HERR_FT_HUB_CHECK_TABLE_ERROR (HERR_SESS_BASE+53) // Data table check error
|
||||
#define HERR_FT_HUB_INSERT_FAILURE (HERR_SESS_BASE+54) // Data insertion error
|
||||
#define HERR_FT_HUB_PREPARING_FAILURE (HERR_SESS_BASE+55) // Data preparation error
|
||||
#define HERR_FT_HUB_EXECUTING_FAILURE (HERR_SESS_BASE+56) // SQL execution error
|
||||
#define HERR_FT_HUB_NOT_VALID_FOLDER_PATH (HERR_SESS_BASE+57) // Invalid folder path
|
||||
#define HERR_FT_HUB_ENABLE_REPETITION (HERR_SESS_BASE+58) // Enable db function repeatedly
|
||||
#define HERR_FT_HUB_DISABLE_REPETITION (HERR_SESS_BASE+59) // Disable db function repeatedly
|
||||
|
||||
#define HERR_ARCHIVE_LOAD_FAILURE (HERR_SESS_BASE+80) // Archive load failure
|
||||
#define HERR_ARCHIVE_LOAD_MODEL_FAILURE (HERR_SESS_BASE+81) // Model load failure
|
||||
#define HERR_ARCHIVE_FILE_FORMAT_ERROR (HERR_SESS_BASE+82) // The archive format is incorrect
|
||||
#define HERR_ARCHIVE_REPETITION_LOAD (HERR_SESS_BASE+83) // Do not reload the model
|
||||
#define HERR_ARCHIVE_NOT_LOAD (HERR_SESS_BASE+84) // Model not loaded
|
||||
|
||||
// [Anchor-End]
|
||||
|
||||
#endif //HYPERFACEREPO_HERROR_H
|
||||
12
cpp-package/inspireface/cpp/inspireface/information.h
Normal file
12
cpp-package/inspireface/cpp/inspireface/information.h
Normal file
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// Created by tunm on 2024/1/31.
|
||||
//
|
||||
|
||||
#ifndef HYPERFACEREPO_INFORMATION_H
|
||||
#define HYPERFACEREPO_INFORMATION_H
|
||||
|
||||
#define INSPIRE_FACE_VERSION_MAJOR_STR "1"
|
||||
#define INSPIRE_FACE_VERSION_MINOR_STR "0"
|
||||
#define INSPIRE_FACE_VERSION_PATCH_STR "0"
|
||||
|
||||
#endif //HYPERFACEREPO_INFORMATION_H
|
||||
12
cpp-package/inspireface/cpp/inspireface/information.h.in
Normal file
12
cpp-package/inspireface/cpp/inspireface/information.h.in
Normal file
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// Created by tunm on 2024/1/31.
|
||||
//
|
||||
|
||||
#ifndef HYPERFACEREPO_INFORMATION_H
|
||||
#define HYPERFACEREPO_INFORMATION_H
|
||||
|
||||
#define INSPIRE_FACE_VERSION_MAJOR_STR "@INSPIRE_FACE_VERSION_MAJOR_STR@"
|
||||
#define INSPIRE_FACE_VERSION_MINOR_STR "@INSPIRE_FACE_VERSION_MINOR_STR@"
|
||||
#define INSPIRE_FACE_VERSION_PATCH_STR "@INSPIRE_FACE_VERSION_PATCH_STR@"
|
||||
|
||||
#endif //HYPERFACEREPO_INFORMATION_H
|
||||
12
cpp-package/inspireface/cpp/inspireface/log.cpp
Normal file
12
cpp-package/inspireface/cpp/inspireface/log.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// Created by tunm on 2024/4/8.
|
||||
//
|
||||
#include "log.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Static Logger initialization
|
||||
LogManager* LogManager::instance = nullptr;
|
||||
std::mutex LogManager::mutex;
|
||||
|
||||
} // namespace inspire
|
||||
157
cpp-package/inspireface/cpp/inspireface/log.h
Executable file
157
cpp-package/inspireface/cpp/inspireface/log.h
Executable file
@@ -0,0 +1,157 @@
|
||||
#ifndef LOG_MANAGER_H
|
||||
#define LOG_MANAGER_H
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef INSPIRE_API
|
||||
#define INSPIRE_API
|
||||
#endif
|
||||
|
||||
// Macro to extract the filename from the full path
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
|
||||
#ifdef ANDROID
|
||||
// Android platform log macros
|
||||
const std::string TAG = "InspireFace";
|
||||
#define INSPIRE_LOGD(...) inspire::LogManager::getInstance()->logAndroid(inspire::LOG_DEBUG, TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGI(...) inspire::LogManager::getInstance()->logAndroid(inspire::LOG_INFO, TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGW(...) inspire::LogManager::getInstance()->logAndroid(inspire::LOG_WARN, TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGE(...) inspire::LogManager::getInstance()->logAndroid(inspire::LOG_ERROR, TAG, __VA_ARGS__)
|
||||
#define INSPIRE_LOGF(...) inspire::LogManager::getInstance()->logAndroid(inspire::LOG_FATAL, TAG, __VA_ARGS__)
|
||||
#else
|
||||
// Standard platform log macros
|
||||
#define INSPIRE_LOGD(...) inspire::LogManager::getInstance()->logStandard(inspire::LOG_DEBUG, __FILENAME__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define INSPIRE_LOGI(...) inspire::LogManager::getInstance()->logStandard(inspire::LOG_INFO, "", "", -1, __VA_ARGS__)
|
||||
#define INSPIRE_LOGW(...) inspire::LogManager::getInstance()->logStandard(inspire::LOG_WARN, __FILENAME__, "", __LINE__, __VA_ARGS__)
|
||||
#define INSPIRE_LOGE(...) inspire::LogManager::getInstance()->logStandard(inspire::LOG_ERROR, __FILENAME__, "", __LINE__, __VA_ARGS__)
|
||||
#define INSPIRE_LOGF(...) inspire::LogManager::getInstance()->logStandard(inspire::LOG_FATAL, __FILENAME__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
||||
// Macro to set the global log level
|
||||
#define INSPIRE_SET_LOG_LEVEL(level) inspire::LogManager::getInstance()->setLogLevel(level)
|
||||
|
||||
namespace inspire {
|
||||
|
||||
// Log levels
|
||||
enum LogLevel {
|
||||
LOG_NONE = 0,
|
||||
LOG_DEBUG,
|
||||
LOG_INFO,
|
||||
LOG_WARN,
|
||||
LOG_ERROR,
|
||||
LOG_FATAL
|
||||
};
|
||||
|
||||
class INSPIRE_API LogManager {
|
||||
private:
|
||||
LogLevel currentLevel;
|
||||
static LogManager* instance;
|
||||
static std::mutex mutex;
|
||||
|
||||
// Private constructor
|
||||
LogManager() : currentLevel(LOG_DEBUG) {} // Default log level is DEBUG
|
||||
|
||||
public:
|
||||
// Disable copy construction and assignment
|
||||
LogManager(const LogManager&) = delete;
|
||||
LogManager& operator=(const LogManager&) = delete;
|
||||
|
||||
// Get the singleton instance
|
||||
static LogManager* getInstance() {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (instance == nullptr) {
|
||||
instance = new LogManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Set the log level
|
||||
void setLogLevel(LogLevel level) {
|
||||
currentLevel = level;
|
||||
}
|
||||
|
||||
// Get the current log level
|
||||
LogLevel getLogLevel() const {
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
// Method for logging on the Android platform
|
||||
void logAndroid(LogLevel level, const char* tag, const char* format, ...) const {
|
||||
if (level < currentLevel) return;
|
||||
|
||||
int androidLevel;
|
||||
switch (level) {
|
||||
case LOG_DEBUG: androidLevel = ANDROID_LOG_DEBUG; break;
|
||||
case LOG_INFO: androidLevel = ANDROID_LOG_INFO; break;
|
||||
case LOG_WARN: androidLevel = ANDROID_LOG_WARN; break;
|
||||
case LOG_ERROR: androidLevel = ANDROID_LOG_ERROR; break;
|
||||
case LOG_FATAL: androidLevel = ANDROID_LOG_FATAL; break;
|
||||
default: androidLevel = ANDROID_LOG_DEFAULT;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
__android_log_vprint(androidLevel, tag, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
#else
|
||||
// Method for standard platform logging
|
||||
void logStandard(LogLevel level, const char* filename, const char* function, int line, const char* format, ...) const {
|
||||
// Check whether the current level is LOG NONE or the log level is not enough to log
|
||||
if (currentLevel == LOG_NONE || level < currentLevel) return;
|
||||
|
||||
// Build log prefix dynamically based on available data
|
||||
bool hasPrintedPrefix = false;
|
||||
if (filename && strlen(filename) > 0) {
|
||||
printf("[%s]", filename);
|
||||
hasPrintedPrefix = true;
|
||||
}
|
||||
if (function && strlen(function) > 0) {
|
||||
printf("[%s]", function);
|
||||
hasPrintedPrefix = true;
|
||||
}
|
||||
if (line != -1) {
|
||||
printf("[%d]", line);
|
||||
hasPrintedPrefix = true;
|
||||
}
|
||||
|
||||
// Only add colon and space if any prefix was printed
|
||||
if (hasPrintedPrefix) {
|
||||
printf(": ");
|
||||
}
|
||||
|
||||
// Set text color for different log levels
|
||||
if (level == LOG_ERROR || level == LOG_FATAL) {
|
||||
printf("\033[1;31m"); // Red color for errors and fatal issues
|
||||
} else if (level == LOG_WARN) {
|
||||
printf("\033[1;33m"); // Yellow color for warnings
|
||||
}
|
||||
|
||||
// Print the actual log message
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
// Reset text color if needed
|
||||
if (level == LOG_ERROR || level == LOG_WARN || level == LOG_FATAL) {
|
||||
printf("\033[0m"); // Reset color
|
||||
}
|
||||
|
||||
printf("\n"); // New line after log message
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
} // namespace inspire
|
||||
|
||||
#endif // LOG_MANAGER_H
|
||||
266
cpp-package/inspireface/cpp/inspireface/middleware/any_net.h
Normal file
266
cpp-package/inspireface/cpp/inspireface/middleware/any_net.h
Normal file
@@ -0,0 +1,266 @@
|
||||
//
|
||||
// Created by tunm on 2023/5/6.
|
||||
//
|
||||
#pragma once
|
||||
#ifndef BIGGUYSMAIN_ANYNET_H
|
||||
#define BIGGUYSMAIN_ANYNET_H
|
||||
#include <utility>
|
||||
|
||||
#include "../data_type.h"
|
||||
#include "inference_helper/inference_helper.h"
|
||||
#include "configurable.h"
|
||||
#include "opencv2/opencv.hpp"
|
||||
#include "../log.h"
|
||||
#include "model_archive/inspire_archive.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
using AnyTensorOutputs = std::vector<std::pair<std::string, std::vector<float>>>;
|
||||
|
||||
/**
|
||||
* @class AnyNet
|
||||
* @brief Generic neural network class for various inference tasks.
|
||||
*
|
||||
* This class provides a general interface for different types of neural networks,
|
||||
* facilitating loading parameters, initializing models, and executing forward passes.
|
||||
*/
|
||||
class INSPIRE_API AnyNet {
|
||||
CONFIGURABLE_SUPPORT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for AnyNet.
|
||||
* @param name Name of the neural network.
|
||||
*/
|
||||
explicit AnyNet(std::string name):m_name_(std::move(name)) {}
|
||||
|
||||
~AnyNet() {
|
||||
m_nn_inference_->Finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads parameters and initializes the model for inference.
|
||||
* @param param Parameters for network configuration.
|
||||
* @param model Pointer to the model.
|
||||
* @param type Type of the inference helper (default: kMnn).
|
||||
* @return int32_t Status of the loading and initialization process.
|
||||
*/
|
||||
int32_t loadData(InspireModel &model, InferenceHelper::HelperType type = InferenceHelper::kMnn) {
|
||||
m_infer_type_ = type;
|
||||
// must
|
||||
pushData<int>(model.Config(), "model_index", 0);
|
||||
pushData<std::string>(model.Config(), "input_layer", "");
|
||||
pushData<std::vector<std::string>>(model.Config(), "outputs_layers", {"", });
|
||||
pushData<std::vector<int>>(model.Config(), "input_size", {320, 320});
|
||||
pushData<std::vector<float>>(model.Config(), "mean", {127.5f, 127.5f, 127.5f});
|
||||
pushData<std::vector<float>>(model.Config(), "norm", {0.0078125f, 0.0078125f, 0.0078125f});
|
||||
// rarely
|
||||
pushData<int>(model.Config(), "input_channel", 3);
|
||||
pushData<int>(model.Config(), "input_image_channel", 3);
|
||||
pushData<bool>(model.Config(), "nchw", true);
|
||||
pushData<bool>(model.Config(), "swap_color", false);
|
||||
pushData<int>(model.Config(), "data_type", InputTensorInfo::InputTensorInfo::kDataTypeImage);
|
||||
pushData<int>(model.Config(), "input_tensor_type", InputTensorInfo::TensorInfo::kTensorTypeFp32);
|
||||
pushData<int>(model.Config(), "output_tensor_type", InputTensorInfo::TensorInfo::kTensorTypeFp32);
|
||||
pushData<int>(model.Config(), "threads", 1);
|
||||
|
||||
m_nn_inference_.reset(InferenceHelper::Create(m_infer_type_));
|
||||
m_nn_inference_->SetNumThreads(getData<int>("threads"));
|
||||
#if defined(GLOBAL_INFERENCE_BACKEND_USE_MNN_CUDA) && !defined(ENABLE_RKNN)
|
||||
LOGW("You have forced the global use of MNN_CUDA as the neural network inference backend");
|
||||
m_nn_inference_->SetSpecialBackend(InferenceHelper::kMnnCuda);
|
||||
#endif
|
||||
m_output_tensor_info_list_.clear();
|
||||
std::vector<std::string> outputs_layers = getData<std::vector<std::string>>("outputs_layers");
|
||||
int tensor_type = getData<int>("input_tensor_type");
|
||||
int out_tensor_type = getData<int>("output_tensor_type");
|
||||
for (auto &name: outputs_layers) {
|
||||
m_output_tensor_info_list_.push_back(OutputTensorInfo(name, out_tensor_type));
|
||||
}
|
||||
auto ret = m_nn_inference_->Initialize(model.buffer, model.bufferSize, m_input_tensor_info_list_, m_output_tensor_info_list_);
|
||||
if (ret != InferenceHelper::kRetOk) {
|
||||
INSPIRE_LOGE("NN Initialize fail");
|
||||
return ret;
|
||||
}
|
||||
|
||||
m_input_tensor_info_list_.clear();
|
||||
InputTensorInfo input_tensor_info(getData<std::string>("input_layer"), tensor_type, getData<bool>("nchw"));
|
||||
std::vector<int> input_size = getData<std::vector<int>>("input_size");
|
||||
int width = input_size[0];
|
||||
int height = input_size[1];
|
||||
m_input_image_size_ = {width, height};
|
||||
int channel = getData<int>("input_channel");
|
||||
if (getData<bool>("nchw")) {
|
||||
input_tensor_info.tensor_dims = { 1, channel, m_input_image_size_.height, m_input_image_size_.width };
|
||||
} else {
|
||||
input_tensor_info.tensor_dims = { 1, m_input_image_size_.height, m_input_image_size_.width, channel };
|
||||
}
|
||||
|
||||
input_tensor_info.data_type = getData<int>("data_type");
|
||||
int image_channel = getData<int>("input_image_channel");
|
||||
input_tensor_info.image_info.channel = image_channel;
|
||||
|
||||
std::vector<float> mean = getData<std::vector<float>>("mean");
|
||||
std::vector<float> norm = getData<std::vector<float>>("norm");
|
||||
input_tensor_info.normalize.mean[0] = mean[0];
|
||||
input_tensor_info.normalize.mean[1] = mean[1];
|
||||
input_tensor_info.normalize.mean[2] = mean[2];
|
||||
input_tensor_info.normalize.norm[0] = norm[0];
|
||||
input_tensor_info.normalize.norm[1] = norm[1];
|
||||
input_tensor_info.normalize.norm[2] = norm[2];
|
||||
|
||||
input_tensor_info.image_info.width = width;
|
||||
input_tensor_info.image_info.height = height;
|
||||
input_tensor_info.image_info.channel = channel;
|
||||
input_tensor_info.image_info.crop_x = 0;
|
||||
input_tensor_info.image_info.crop_y = 0;
|
||||
input_tensor_info.image_info.crop_width = width;
|
||||
input_tensor_info.image_info.crop_height = height;
|
||||
input_tensor_info.image_info.is_bgr = getData<bool>("nchw");
|
||||
input_tensor_info.image_info.swap_color = getData<bool>("swap_color");
|
||||
|
||||
m_input_tensor_info_list_.push_back(input_tensor_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a forward pass of the network with given input data.
|
||||
* @param data The input matrix (image) to process.
|
||||
* @param outputs Outputs of the network (tensor outputs).
|
||||
*/
|
||||
void Forward(const Matrix &data, AnyTensorOutputs& outputs) {
|
||||
InputTensorInfo& input_tensor_info = getMInputTensorInfoList()[0];
|
||||
if (m_infer_type_ == InferenceHelper::kRknn) {
|
||||
// Start by simply implementing a temporary color shift on the outside
|
||||
if (getData<bool>("swap_color")) {
|
||||
cv::cvtColor(data, m_cache_, cv::COLOR_BGR2RGB);
|
||||
input_tensor_info.data = m_cache_.data;
|
||||
} else {
|
||||
input_tensor_info.data = data.data;
|
||||
}
|
||||
} else {
|
||||
input_tensor_info.data = data.data;
|
||||
}
|
||||
Forward(outputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a forward pass of the network.
|
||||
* @param outputs Outputs of the network (tensor outputs).
|
||||
*/
|
||||
void Forward(AnyTensorOutputs& outputs) {
|
||||
|
||||
// LOGD("ppPreProcess");
|
||||
if (m_nn_inference_->PreProcess(m_input_tensor_info_list_) != InferenceHelper::kRetOk) {
|
||||
INSPIRE_LOGD("PreProcess error");
|
||||
}
|
||||
// LOGD("PreProcess");
|
||||
if (m_nn_inference_->Process(m_output_tensor_info_list_) != InferenceHelper::kRetOk) {
|
||||
INSPIRE_LOGD("Process error");
|
||||
}
|
||||
// LOGD("Process");
|
||||
for (int i = 0; i < m_output_tensor_info_list_.size(); ++i) {
|
||||
std::vector<float> output_score_raw_list(m_output_tensor_info_list_[i].GetDataAsFloat(),
|
||||
m_output_tensor_info_list_[i].GetDataAsFloat() +
|
||||
m_output_tensor_info_list_[i].GetElementNum());
|
||||
// LOGE("m_output_tensor_info_list_[i].GetElementNum(): %d",m_output_tensor_info_list_[i].GetElementNum());
|
||||
outputs.push_back(std::make_pair(m_output_tensor_info_list_[i].name, output_score_raw_list));
|
||||
}
|
||||
|
||||
m_cache_.release();
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Gets a reference to the input tensor information list.
|
||||
* @return Reference to the vector of input tensor information.
|
||||
*/
|
||||
std::vector<InputTensorInfo> &getMInputTensorInfoList() {
|
||||
return m_input_tensor_info_list_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a reference to the output tensor information list.
|
||||
* @return Reference to the vector of output tensor information.
|
||||
*/
|
||||
std::vector<OutputTensorInfo> &getMOutputTensorInfoList() {
|
||||
return m_output_tensor_info_list_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the size of the input image.
|
||||
* @return Size of the input image.
|
||||
*/
|
||||
cv::Size &getMInputImageSize() {
|
||||
return m_input_image_size_;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string m_name_; ///< Name of the neural network.
|
||||
|
||||
private:
|
||||
InferenceHelper::HelperType m_infer_type_; ///< Inference engine type
|
||||
std::shared_ptr<InferenceHelper> m_nn_inference_; ///< Shared pointer to the inference helper.
|
||||
std::vector<InputTensorInfo> m_input_tensor_info_list_; ///< List of input tensor information.
|
||||
std::vector<OutputTensorInfo> m_output_tensor_info_list_; ///< List of output tensor information.
|
||||
cv::Size m_input_image_size_{}; ///< Size of the input image.
|
||||
cv::Mat m_cache_; ///< Cached matrix for image data.
|
||||
|
||||
};
|
||||
|
||||
template <typename ImageT, typename TensorT>
|
||||
AnyTensorOutputs ForwardService(
|
||||
std::shared_ptr<AnyNet> net,
|
||||
const ImageT &input,
|
||||
std::function<void(const ImageT&, TensorT&)> transform) {
|
||||
InputTensorInfo& input_tensor_info = net->getMInputTensorInfoList()[0];
|
||||
TensorT transform_tensor;
|
||||
transform(input, transform_tensor);
|
||||
input_tensor_info.data = transform_tensor.data; // input tensor only support cv2::Mat
|
||||
|
||||
AnyTensorOutputs outputs;
|
||||
net->Forward(outputs);
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Executes a forward pass through the neural network for a given input, with preprocessing.
|
||||
* @tparam ImageT Type of the input image.
|
||||
* @tparam TensorT Type of the transformed tensor.
|
||||
* @tparam PreprocessCallbackT Type of the preprocessing callback function.
|
||||
* @param net Shared pointer to the AnyNet neural network object.
|
||||
* @param input The input image to be processed.
|
||||
* @param callback Preprocessing callback function to be applied to the input.
|
||||
* @param transform Transformation function to convert the input image to a tensor.
|
||||
* @return AnyTensorOutputs Outputs of the network (tensor outputs).
|
||||
*
|
||||
* This template function handles the preprocessing of the input image, transformation to tensor,
|
||||
* and then passes it through the neural network to get the output. The function is generic and
|
||||
* can work with different types of images and tensors, as specified by the template parameters.
|
||||
*/
|
||||
template <typename ImageT, typename TensorT, typename PreprocessCallbackT>
|
||||
AnyTensorOutputs ForwardService(
|
||||
std::shared_ptr<AnyNet> net,
|
||||
const ImageT &input,
|
||||
PreprocessCallbackT &callback,
|
||||
std::function<void(const ImageT&, TensorT&, PreprocessCallbackT&)> transform) {
|
||||
InputTensorInfo& input_tensor_info = net->getMInputTensorInfoList()[0];
|
||||
TensorT transform_tensor;
|
||||
transform(input, transform_tensor, callback);
|
||||
input_tensor_info.data = transform_tensor.data; // input tensor only support cv2::Mat
|
||||
|
||||
AnyTensorOutputs outputs;
|
||||
net->Forward(outputs);
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif //BIGGUYSMAIN_ANYNET_H
|
||||
363
cpp-package/inspireface/cpp/inspireface/middleware/camera_stream/camera_stream.h
Executable file
363
cpp-package/inspireface/cpp/inspireface/middleware/camera_stream/camera_stream.h
Executable file
@@ -0,0 +1,363 @@
|
||||
#ifndef CAMERA_STREAM_H
|
||||
#define CAMERA_STREAM_H
|
||||
#include <memory>
|
||||
#include "MNN/ImageProcess.hpp"
|
||||
//#include "basic_types.h"
|
||||
#include "opencv2/opencv.hpp"
|
||||
#include "log.h"
|
||||
//
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @brief Enum to represent rotation modes.
|
||||
*/
|
||||
enum ROTATION_MODE {
|
||||
ROTATION_0 = 0,
|
||||
ROTATION_90 = 1,
|
||||
ROTATION_180 = 2,
|
||||
ROTATION_270 = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum to represent rotation modes.
|
||||
*/
|
||||
enum DATA_FORMAT {
|
||||
NV21 = 0, NV12 = 1, RGBA = 2, RGB = 3, BGR = 4, BGRA = 5
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class to handle camera stream and image processing.
|
||||
*/
|
||||
class CameraStream {
|
||||
public:
|
||||
|
||||
CameraStream() {
|
||||
config_.sourceFormat = MNN::CV::YUV_NV21;
|
||||
config_.destFormat = MNN::CV::BGR;
|
||||
// config_.filterType = MNN::CV::BICUBIC;
|
||||
config_.filterType = MNN::CV::BILINEAR;
|
||||
// config_.filterType = MNN::CV::NEAREST;
|
||||
config_.wrap = MNN::CV::ZERO;
|
||||
rotation_mode_ = ROTATION_0;
|
||||
preview_size_ = 192;
|
||||
// preview_size_ = 352;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the data buffer, height, and width of the camera stream.
|
||||
*
|
||||
* @param data_buffer Pointer to the data buffer.
|
||||
* @param height Height of the image.
|
||||
* @param width Width of the image.
|
||||
*/
|
||||
void SetDataBuffer(const uint8_t *data_buffer, int height, int width) {
|
||||
this->buffer_ = data_buffer;
|
||||
this->height_ = height;
|
||||
this->width_ = width;
|
||||
preview_scale_ = preview_size_ / static_cast<float>(std::max(height,width));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the preview size.
|
||||
*
|
||||
* @param size Preview size.
|
||||
*/
|
||||
void SetPreviewSize(const int size)
|
||||
{
|
||||
preview_size_ = size;
|
||||
preview_scale_ = preview_size_ / static_cast<float>(std::max(this->height_,this->width_));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the rotation mode.
|
||||
*
|
||||
* @param mode Rotation mode (e.g., ROTATION_0, ROTATION_90).
|
||||
*/
|
||||
void SetRotationMode(ROTATION_MODE mode) { rotation_mode_ = mode; }
|
||||
|
||||
/**
|
||||
* @brief Set the data format.
|
||||
*
|
||||
* @param data_format Data format (e.g., NV21, RGBA).
|
||||
*/
|
||||
void SetDataFormat(DATA_FORMAT data_format) {
|
||||
if (data_format == NV21) {
|
||||
config_.sourceFormat = MNN::CV::YUV_NV21;
|
||||
}
|
||||
if (data_format == NV12) {
|
||||
config_.sourceFormat = MNN::CV::YUV_NV12;
|
||||
}
|
||||
if (data_format == RGBA) {
|
||||
config_.sourceFormat = MNN::CV::RGBA;
|
||||
}
|
||||
if (data_format == RGB) {
|
||||
config_.sourceFormat = MNN::CV::RGB;
|
||||
}
|
||||
if (data_format == BGR) {
|
||||
config_.sourceFormat = MNN::CV::BGR;
|
||||
}
|
||||
if (data_format == BGRA) {
|
||||
config_.sourceFormat = MNN::CV::BGRA;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get an affine-transformed RGB image.
|
||||
*
|
||||
* @param affine_matrix Affine transformation matrix.
|
||||
* @param width_out Width of the output image.
|
||||
* @param height_out Height of the output image.
|
||||
* @return cv::Mat Affine-transformed RGB image.
|
||||
*/
|
||||
cv::Mat GetAffineRGBImage(const cv::Mat &affine_matrix, const int width_out,
|
||||
const int height_out) const {
|
||||
int sw = width_;
|
||||
int sh = height_;
|
||||
int rot_sw = sw;
|
||||
int rot_sh = sh;
|
||||
MNN::CV::Matrix tr;
|
||||
assert(affine_matrix.rows == 2);
|
||||
assert(affine_matrix.cols == 3);
|
||||
assert(affine_matrix.type() == CV_64F);
|
||||
cv::Mat trans_matrix;
|
||||
affine_matrix.convertTo(trans_matrix, CV_32F);
|
||||
std::vector<float> tr_cv({1, 0, 0, 0, 1, 0, 0, 0, 1});
|
||||
memcpy(tr_cv.data(), trans_matrix.data, sizeof(float) * 6);
|
||||
tr.set9(tr_cv.data());
|
||||
MNN::CV::Matrix tr_inv;
|
||||
tr.invert(&tr_inv);
|
||||
std::shared_ptr<MNN::CV::ImageProcess> process(
|
||||
MNN::CV::ImageProcess::create(config_));
|
||||
process->setMatrix(tr_inv);
|
||||
cv::Mat img_out(height_out, width_out, CV_8UC3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(MNN::Tensor::create<uint8_t>(
|
||||
std::vector<int>{1, height_out, width_out, 3}, img_out.data));
|
||||
process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
// std::cout << std::to_string(1) << std::endl;
|
||||
return img_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a preview image with optional rotation.
|
||||
*
|
||||
* @param with_rotation True if rotation is applied, false otherwise.
|
||||
* @return cv::Mat Preview image.
|
||||
*/
|
||||
cv::Mat GetPreviewImage(bool with_rotation){
|
||||
return GetScaledImage(preview_scale_ , with_rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the preview scale.
|
||||
*
|
||||
* @return float Preview scale.
|
||||
*/
|
||||
float GetPreviewScale()
|
||||
{
|
||||
return preview_scale_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a scaled image with optional rotation.
|
||||
*
|
||||
* @param scale Scaling factor.
|
||||
* @param with_rotation True if rotation is applied, false otherwise.
|
||||
* @return cv::Mat Scaled image.
|
||||
*/
|
||||
cv::Mat GetScaledImage(const float scale, bool with_rotation) {
|
||||
int sw = width_;
|
||||
int sh = height_;
|
||||
int rot_sw = sw;
|
||||
int rot_sh = sh;
|
||||
// MNN::CV::Matrix tr;
|
||||
std::shared_ptr<MNN::CV::ImageProcess> process(
|
||||
MNN::CV::ImageProcess::create(config_));
|
||||
if (rotation_mode_ == ROTATION_270 && with_rotation) {
|
||||
float srcPoints[] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ - 1),
|
||||
(float)(width_ - 1),
|
||||
0.0f,
|
||||
(float)(width_ - 1),
|
||||
(float)(height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {(float)(height_ * scale - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * scale - 1),
|
||||
(float)(width_ * scale - 1),
|
||||
0.0f,
|
||||
(float)(width_ * scale - 1)};
|
||||
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints,
|
||||
(MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(tr_);
|
||||
int scaled_height = static_cast<int>(width_ * scale);
|
||||
int scaled_width = static_cast<int>(height_ * scale);
|
||||
cv::Mat img_out(scaled_height, scaled_width, CV_8UC3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(MNN::Tensor::create<uint8_t>(
|
||||
std::vector<int>{1, scaled_height, scaled_width, 3}, img_out.data));
|
||||
process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
return img_out;
|
||||
} else if (rotation_mode_ == ROTATION_90 && with_rotation) {
|
||||
float srcPoints[] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ - 1),
|
||||
(float)(width_ - 1),
|
||||
0.0f,
|
||||
(float)(width_ - 1),
|
||||
(float)(height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
0.0f,
|
||||
(float)(width_ * scale - 1),
|
||||
(float)(height_ * scale - 1),
|
||||
(float)(width_ * scale - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * scale - 1),
|
||||
0.0f,
|
||||
};
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints,
|
||||
(MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(tr_);
|
||||
int scaled_height = static_cast<int>(width_ * scale);
|
||||
int scaled_width = static_cast<int>(height_ * scale);
|
||||
cv::Mat img_out(scaled_height, scaled_width, CV_8UC3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(MNN::Tensor::create<uint8_t>(
|
||||
std::vector<int>{1, scaled_height, scaled_width, 3}, img_out.data));
|
||||
process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
return img_out;
|
||||
} else if (rotation_mode_ == ROTATION_180 && with_rotation) {
|
||||
float srcPoints[] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ - 1),
|
||||
(float)(width_ - 1),
|
||||
0.0f,
|
||||
(float)(width_ - 1),
|
||||
(float)(height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
(float)(width_ * scale - 1),
|
||||
(float)(height_ * scale - 1),
|
||||
(float)(width_ * scale - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * scale - 1),
|
||||
0.0f,
|
||||
0.0f,
|
||||
};
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints,
|
||||
(MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(tr_);
|
||||
int scaled_height = static_cast<int>(height_ * scale);
|
||||
int scaled_width = static_cast<int>(width_ * scale);
|
||||
cv::Mat img_out(scaled_height, scaled_width, CV_8UC3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(MNN::Tensor::create<uint8_t>(
|
||||
std::vector<int>{1, scaled_height, scaled_width, 3}, img_out.data));
|
||||
process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
return img_out;
|
||||
} else {
|
||||
float srcPoints[] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ - 1),
|
||||
(float)(width_ - 1),
|
||||
0.0f,
|
||||
(float)(width_ - 1),
|
||||
(float)(height_ - 1),
|
||||
};
|
||||
float dstPoints[] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
(float)(height_ * scale - 1),
|
||||
(float)(width_ * scale - 1),
|
||||
0.0f,
|
||||
(float)(width_ * scale - 1),
|
||||
(float)(height_ * scale - 1),
|
||||
};
|
||||
tr_.setPolyToPoly((MNN::CV::Point *)dstPoints,
|
||||
(MNN::CV::Point *)srcPoints, 4);
|
||||
process->setMatrix(tr_);
|
||||
int scaled_height = static_cast<int>(height_ * scale);
|
||||
int scaled_width = static_cast<int>(width_ * scale);
|
||||
cv::Mat img_out(scaled_height, scaled_width, CV_8UC3);
|
||||
std::shared_ptr<MNN::Tensor> tensor(MNN::Tensor::create<uint8_t>(
|
||||
std::vector<int>{1, scaled_height, scaled_width, 3}, img_out.data));
|
||||
auto err = process->convert(buffer_, sw, sh, 0, tensor.get());
|
||||
return img_out;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the affine transformation matrix.
|
||||
*
|
||||
* @return cv::Mat Affine transformation matrix.
|
||||
*/
|
||||
cv::Mat GetAffineMatrix() const {
|
||||
cv::Mat affine_matrix(3, 3, CV_32F);
|
||||
tr_.get9((float *)affine_matrix.data);
|
||||
cv::Mat affine = affine_matrix.rowRange(0, 2);
|
||||
cv::Mat affine_64;
|
||||
affine.convertTo(affine_64, CV_64F);
|
||||
assert(affine_64.rows == 2);
|
||||
assert(affine_64.cols == 3);
|
||||
assert(affine_64.type() == CV_64F);
|
||||
return affine_64;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the height of the camera stream image.
|
||||
*
|
||||
* @return int Height.
|
||||
*/
|
||||
int GetHeight() const{
|
||||
return height_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the width of the camera stream image.
|
||||
*
|
||||
* @return int Width.
|
||||
*/
|
||||
int GetWidth() const{
|
||||
return width_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current rotation mode.
|
||||
*
|
||||
* @return ROTATION_MODE Current rotation mode.
|
||||
*/
|
||||
ROTATION_MODE getRotationMode() const {
|
||||
return rotation_mode_;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
const uint8_t *buffer_; ///< Pointer to the data buffer.
|
||||
int buffer_size_; ///< Size of the data buffer.
|
||||
std::vector<float> rotation_matrix; ///< Rotation matrix.
|
||||
int height_; ///< Height of the camera stream image.
|
||||
int width_; ///< Width of the camera stream image.
|
||||
float preview_scale_; ///< Scaling factor for the preview image.
|
||||
int preview_size_; ///< Size of the preview image.
|
||||
MNN::CV::Matrix tr_; ///< Affine transformation matrix.
|
||||
ROTATION_MODE rotation_mode_; ///< Current rotation mode.
|
||||
MNN::CV::ImageProcess::Config config_; ///< Configuration for image processing.
|
||||
std::shared_ptr<MNN::CV::ImageProcess> process_; ///< Image processing instance.
|
||||
|
||||
};
|
||||
|
||||
} // inspire
|
||||
|
||||
#endif // CAMERA_STREAM_H
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Created by tunm on 2023/5/5.
|
||||
//
|
||||
|
||||
#include "configurable.h"
|
||||
|
||||
namespace inspire {
|
||||
|
||||
|
||||
std::string Configurable::toString(int indent) const {
|
||||
if (indent != 0)
|
||||
return m_configuration.dump(indent);
|
||||
else
|
||||
return m_configuration.dump();
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::string> Configurable::getNameList() const {
|
||||
std::vector<std::string> keys;
|
||||
for (const auto& element : m_configuration.items()) {
|
||||
keys.push_back(element.key());
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
Configurable &Configurable::operator=(const Configurable &other) {
|
||||
if (this != &other) { // Check the self-assignment
|
||||
m_configuration = other.m_configuration; // Deep copy using the assignment operator of nlohmann::json
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
} // namespace hyper
|
||||
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// Created by tunm on 2023/5/5.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef HYPERAI_PARAMETER_H
|
||||
#define HYPERAI_PARAMETER_H
|
||||
#include "nlohmann/json.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
#ifndef INSPIRE_API
|
||||
#define INSPIRE_API
|
||||
#endif
|
||||
|
||||
namespace inspire {
|
||||
|
||||
/**
|
||||
* @class Configurable
|
||||
* @brief Class for managing parameters as JSON data.
|
||||
*
|
||||
* This class provides methods to set, get, and load parameters as JSON data.
|
||||
*/
|
||||
class INSPIRE_API Configurable {
|
||||
public:
|
||||
Configurable() = default;;
|
||||
|
||||
Configurable(const Configurable& p) : m_configuration(p.m_configuration) {}
|
||||
|
||||
virtual ~Configurable() {}
|
||||
|
||||
Configurable& operator=(const Configurable& other);
|
||||
|
||||
/**
|
||||
* @brief Get a list of parameter names.
|
||||
* @return std::vector<std::string> A list of parameter names.
|
||||
*/
|
||||
std::vector<std::string> getNameList() const;
|
||||
|
||||
/**
|
||||
* @brief Convert parameters to a formatted JSON string.
|
||||
* @param indent The indentation level for formatting.
|
||||
* @return std::string The formatted JSON string representing the parameters.
|
||||
*/
|
||||
std::string toString(int indent = 4) const;
|
||||
|
||||
/**
|
||||
* @brief Check if a parameter exists by name.
|
||||
* @param name The name of the parameter to check.
|
||||
* @return bool True if the parameter exists, false otherwise.
|
||||
*/
|
||||
bool has(const std::string& name) const noexcept {
|
||||
return m_configuration.contains(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a parameter with a specific name and value.
|
||||
* @param name The name of the parameter.
|
||||
* @param value The value to set for the parameter.
|
||||
*/
|
||||
template <typename ValueType>
|
||||
void set(const std::string& name, const ValueType& value) {
|
||||
m_configuration[name] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a parameter with a specific name and value.
|
||||
* @param name The name of the parameter.
|
||||
* @param value The value to set for the parameter.
|
||||
*/
|
||||
template <typename ValueType>
|
||||
ValueType get(const std::string& name) const {
|
||||
if (!has(name)) {
|
||||
throw std::out_of_range("out_of_range in Parameter::get : " + name);
|
||||
}
|
||||
return m_configuration.at(name).get<ValueType>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load parameters from a JSON object.
|
||||
* @param j The JSON object containing parameters.
|
||||
*/
|
||||
void load(const nlohmann::json& j) {
|
||||
for (const auto& item : j.items()) {
|
||||
const auto& key = item.key();
|
||||
const auto& value = item.value();
|
||||
|
||||
if (value.is_boolean()) {
|
||||
set<bool>(key, value.get<bool>());
|
||||
} else if (value.is_number_integer()) {
|
||||
set<int>(key, value.get<int>());
|
||||
} else if (value.is_number_float()) {
|
||||
set<float>(key, value.get<float>());
|
||||
} else if (value.is_string()) {
|
||||
set<std::string>(key, value.get<std::string>());
|
||||
} else if (value.is_array()) {
|
||||
if (!value.empty()) {
|
||||
if (value[0].is_number_integer()) {
|
||||
set<std::vector<int>>(key, value.get<std::vector<int>>());
|
||||
} else if (value[0].is_number_float()) {
|
||||
set<std::vector<float>>(key, value.get<std::vector<float>>());
|
||||
} // add more types as needed
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// Add handling for other types as needed
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
json m_configuration; ///< JSON object to store parameters.
|
||||
};
|
||||
|
||||
#define CONFIGURABLE_SUPPORT \
|
||||
protected: \
|
||||
inspire::Configurable m_configuration; \
|
||||
\
|
||||
public: \
|
||||
const inspire::Configurable& getConfiguration() const { \
|
||||
return m_configuration; \
|
||||
} \
|
||||
\
|
||||
void setConfiguration(const inspire::Configurable& param) { \
|
||||
m_configuration = param; \
|
||||
} \
|
||||
\
|
||||
bool hasData(const std::string& name) const noexcept { \
|
||||
return m_configuration.has(name); \
|
||||
} \
|
||||
\
|
||||
template <typename ValueType> \
|
||||
void setData(const std::string& name, const ValueType& value) { \
|
||||
m_configuration.set<ValueType>(name, value); \
|
||||
} \
|
||||
\
|
||||
template <typename ValueType> \
|
||||
ValueType getData(const std::string& name) const { \
|
||||
return m_configuration.get<ValueType>(name); \
|
||||
} \
|
||||
\
|
||||
template <typename ValueType> \
|
||||
void pushData(const inspire::Configurable& param, const std::string& name, \
|
||||
const ValueType& default_value) { \
|
||||
if (param.has(name)) { \
|
||||
setData<ValueType>(name, param.get<ValueType>(name)); \
|
||||
} else { \
|
||||
setData<ValueType>(name, default_value); \
|
||||
} \
|
||||
} \
|
||||
void loadData(const nlohmann::json& j) { \
|
||||
m_configuration.load(j); \
|
||||
} \
|
||||
std::string toStr(int indent = 4) { \
|
||||
return m_configuration.toString(indent); \
|
||||
}
|
||||
|
||||
} // namespace hyper
|
||||
#endif //HYPERAI_PARAMETER_H
|
||||
37
cpp-package/inspireface/cpp/inspireface/middleware/costman.h
Normal file
37
cpp-package/inspireface/cpp/inspireface/middleware/costman.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Created by Tunm-Air13 on 2023/9/21.
|
||||
//
|
||||
#pragma once
|
||||
#ifndef HYPERFACEREPO_TIMER_H
|
||||
#define HYPERFACEREPO_TIMER_H
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
namespace inspire {
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
|
||||
Timer() {
|
||||
current_time = (double) cv::getTickCount();
|
||||
}
|
||||
|
||||
double GetCostTime() const {
|
||||
return ((double) cv::getTickCount() - current_time) / cv::getTickFrequency() * 1000;
|
||||
}
|
||||
|
||||
double GetCostTimeUpdate() {
|
||||
auto cost = ((double) cv::getTickCount() - current_time) / cv::getTickFrequency() * 1000;
|
||||
current_time = (double) cv::getTickCount();
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
double current_time;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //HYPERFACEREPO_TIMER_H
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace YAML {
|
||||
typedef std::size_t anchor_t;
|
||||
const anchor_t NullAnchor = 0;
|
||||
}
|
||||
|
||||
#endif // ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
|
||||
namespace YAML {
|
||||
YAML_CPP_API std::string EncodeBase64(const unsigned char *data,
|
||||
std::size_t size);
|
||||
YAML_CPP_API std::vector<unsigned char> DecodeBase64(const std::string &input);
|
||||
|
||||
class YAML_CPP_API Binary {
|
||||
public:
|
||||
Binary() : m_unownedData(0), m_unownedSize(0) {}
|
||||
Binary(const unsigned char *data_, std::size_t size_)
|
||||
: m_unownedData(data_), m_unownedSize(size_) {}
|
||||
|
||||
bool owned() const { return !m_unownedData; }
|
||||
std::size_t size() const { return owned() ? m_data.size() : m_unownedSize; }
|
||||
const unsigned char *data() const {
|
||||
return owned() ? &m_data[0] : m_unownedData;
|
||||
}
|
||||
|
||||
void swap(std::vector<unsigned char> &rhs) {
|
||||
if (m_unownedData) {
|
||||
m_data.swap(rhs);
|
||||
rhs.clear();
|
||||
rhs.resize(m_unownedSize);
|
||||
std::copy(m_unownedData, m_unownedData + m_unownedSize, rhs.begin());
|
||||
m_unownedData = 0;
|
||||
m_unownedSize = 0;
|
||||
} else {
|
||||
m_data.swap(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const Binary &rhs) const {
|
||||
const std::size_t s = size();
|
||||
if (s != rhs.size())
|
||||
return false;
|
||||
const unsigned char *d1 = data();
|
||||
const unsigned char *d2 = rhs.data();
|
||||
for (std::size_t i = 0; i < s; i++) {
|
||||
if (*d1++ != *d2++)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const Binary &rhs) const { return !(*this == rhs); }
|
||||
|
||||
private:
|
||||
std::vector<unsigned char> m_data;
|
||||
const unsigned char *m_unownedData;
|
||||
std::size_t m_unownedSize;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../anchor.h"
|
||||
|
||||
namespace YAML {
|
||||
/**
|
||||
* An object that stores and retrieves values correlating to {@link anchor_t}
|
||||
* values.
|
||||
*
|
||||
* <p>Efficient implementation that can make assumptions about how
|
||||
* {@code anchor_t} values are assigned by the {@link Parser} class.
|
||||
*/
|
||||
template <class T>
|
||||
class AnchorDict {
|
||||
public:
|
||||
void Register(anchor_t anchor, T value) {
|
||||
if (anchor > m_data.size()) {
|
||||
m_data.resize(anchor);
|
||||
}
|
||||
m_data[anchor - 1] = value;
|
||||
}
|
||||
|
||||
T Get(anchor_t anchor) const { return m_data[anchor - 1]; }
|
||||
|
||||
private:
|
||||
std::vector<T> m_data;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,149 @@
|
||||
#ifndef GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/mark.h"
|
||||
#include <string>
|
||||
|
||||
namespace YAML {
|
||||
class Parser;
|
||||
|
||||
// GraphBuilderInterface
|
||||
// . Abstraction of node creation
|
||||
// . pParentNode is always NULL or the return value of one of the NewXXX()
|
||||
// functions.
|
||||
class GraphBuilderInterface {
|
||||
public:
|
||||
virtual ~GraphBuilderInterface() = 0;
|
||||
|
||||
// Create and return a new node with a null value.
|
||||
virtual void *NewNull(const Mark &mark, void *pParentNode) = 0;
|
||||
|
||||
// Create and return a new node with the given tag and value.
|
||||
virtual void *NewScalar(const Mark &mark, const std::string &tag,
|
||||
void *pParentNode, const std::string &value) = 0;
|
||||
|
||||
// Create and return a new sequence node
|
||||
virtual void *NewSequence(const Mark &mark, const std::string &tag,
|
||||
void *pParentNode) = 0;
|
||||
|
||||
// Add pNode to pSequence. pNode was created with one of the NewXxx()
|
||||
// functions and pSequence with NewSequence().
|
||||
virtual void AppendToSequence(void *pSequence, void *pNode) = 0;
|
||||
|
||||
// Note that no moew entries will be added to pSequence
|
||||
virtual void SequenceComplete(void *pSequence) { (void)pSequence; }
|
||||
|
||||
// Create and return a new map node
|
||||
virtual void *NewMap(const Mark &mark, const std::string &tag,
|
||||
void *pParentNode) = 0;
|
||||
|
||||
// Add the pKeyNode => pValueNode mapping to pMap. pKeyNode and pValueNode
|
||||
// were created with one of the NewXxx() methods and pMap with NewMap().
|
||||
virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) = 0;
|
||||
|
||||
// Note that no more assignments will be made in pMap
|
||||
virtual void MapComplete(void *pMap) { (void)pMap; }
|
||||
|
||||
// Return the node that should be used in place of an alias referencing
|
||||
// pNode (pNode by default)
|
||||
virtual void *AnchorReference(const Mark &mark, void *pNode) {
|
||||
(void)mark;
|
||||
return pNode;
|
||||
}
|
||||
};
|
||||
|
||||
// Typesafe wrapper for GraphBuilderInterface. Assumes that Impl defines
|
||||
// Node, Sequence, and Map types. Sequence and Map must derive from Node
|
||||
// (unless Node is defined as void). Impl must also implement function with
|
||||
// all of the same names as the virtual functions in GraphBuilderInterface
|
||||
// -- including the ones with default implementations -- but with the
|
||||
// prototypes changed to accept an explicit Node*, Sequence*, or Map* where
|
||||
// appropriate.
|
||||
template <class Impl>
|
||||
class GraphBuilder : public GraphBuilderInterface {
|
||||
public:
|
||||
typedef typename Impl::Node Node;
|
||||
typedef typename Impl::Sequence Sequence;
|
||||
typedef typename Impl::Map Map;
|
||||
|
||||
GraphBuilder(Impl &impl) : m_impl(impl) {
|
||||
Map *pMap = NULL;
|
||||
Sequence *pSeq = NULL;
|
||||
Node *pNode = NULL;
|
||||
|
||||
// Type consistency checks
|
||||
pNode = pMap;
|
||||
pNode = pSeq;
|
||||
}
|
||||
|
||||
GraphBuilderInterface &AsBuilderInterface() { return *this; }
|
||||
|
||||
virtual void *NewNull(const Mark &mark, void *pParentNode) {
|
||||
return CheckType<Node>(m_impl.NewNull(mark, AsNode(pParentNode)));
|
||||
}
|
||||
|
||||
virtual void *NewScalar(const Mark &mark, const std::string &tag,
|
||||
void *pParentNode, const std::string &value) {
|
||||
return CheckType<Node>(
|
||||
m_impl.NewScalar(mark, tag, AsNode(pParentNode), value));
|
||||
}
|
||||
|
||||
virtual void *NewSequence(const Mark &mark, const std::string &tag,
|
||||
void *pParentNode) {
|
||||
return CheckType<Sequence>(
|
||||
m_impl.NewSequence(mark, tag, AsNode(pParentNode)));
|
||||
}
|
||||
virtual void AppendToSequence(void *pSequence, void *pNode) {
|
||||
m_impl.AppendToSequence(AsSequence(pSequence), AsNode(pNode));
|
||||
}
|
||||
virtual void SequenceComplete(void *pSequence) {
|
||||
m_impl.SequenceComplete(AsSequence(pSequence));
|
||||
}
|
||||
|
||||
virtual void *NewMap(const Mark &mark, const std::string &tag,
|
||||
void *pParentNode) {
|
||||
return CheckType<Map>(m_impl.NewMap(mark, tag, AsNode(pParentNode)));
|
||||
}
|
||||
virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) {
|
||||
m_impl.AssignInMap(AsMap(pMap), AsNode(pKeyNode), AsNode(pValueNode));
|
||||
}
|
||||
virtual void MapComplete(void *pMap) { m_impl.MapComplete(AsMap(pMap)); }
|
||||
|
||||
virtual void *AnchorReference(const Mark &mark, void *pNode) {
|
||||
return CheckType<Node>(m_impl.AnchorReference(mark, AsNode(pNode)));
|
||||
}
|
||||
|
||||
private:
|
||||
Impl &m_impl;
|
||||
|
||||
// Static check for pointer to T
|
||||
template <class T, class U>
|
||||
static T *CheckType(U *p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
static Node *AsNode(void *pNode) { return static_cast<Node *>(pNode); }
|
||||
static Sequence *AsSequence(void *pSeq) {
|
||||
return static_cast<Sequence *>(pSeq);
|
||||
}
|
||||
static Map *AsMap(void *pMap) { return static_cast<Map *>(pMap); }
|
||||
};
|
||||
|
||||
void *BuildGraphOfNextDocument(Parser &parser,
|
||||
GraphBuilderInterface &graphBuilder);
|
||||
|
||||
template <class Impl>
|
||||
typename Impl::Node *BuildGraphOfNextDocument(Parser &parser, Impl &impl) {
|
||||
GraphBuilder<Impl> graphBuilder(impl);
|
||||
return static_cast<typename Impl::Node *>(
|
||||
BuildGraphOfNextDocument(parser, graphBuilder));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// The following ifdef block is the standard way of creating macros which make
|
||||
// exporting from a DLL simpler. All files within this DLL are compiled with the
|
||||
// yaml_cpp_EXPORTS symbol defined on the command line. This symbol should not
|
||||
// be defined on any project that uses this DLL. This way any other project
|
||||
// whose source files include this file see YAML_CPP_API functions as being
|
||||
// imported from a DLL, whereas this DLL sees symbols defined with this macro as
|
||||
// being exported.
|
||||
#undef YAML_CPP_API
|
||||
|
||||
#ifdef YAML_CPP_DLL // Using or Building YAML-CPP DLL (definition defined
|
||||
// manually)
|
||||
#ifdef yaml_cpp_EXPORTS // Building YAML-CPP DLL (definition created by CMake
|
||||
// or defined manually)
|
||||
// #pragma message( "Defining YAML_CPP_API for DLL export" )
|
||||
#define YAML_CPP_API __declspec(dllexport)
|
||||
#else // yaml_cpp_EXPORTS
|
||||
// #pragma message( "Defining YAML_CPP_API for DLL import" )
|
||||
#define YAML_CPP_API __declspec(dllimport)
|
||||
#endif // yaml_cpp_EXPORTS
|
||||
#else // YAML_CPP_DLL
|
||||
#define YAML_CPP_API
|
||||
#endif // YAML_CPP_DLL
|
||||
|
||||
#endif // DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <stack>
|
||||
|
||||
#include "yaml-cpp/anchor.h"
|
||||
#include "yaml-cpp/emitterstyle.h"
|
||||
#include "yaml-cpp/eventhandler.h"
|
||||
|
||||
namespace YAML {
|
||||
struct Mark;
|
||||
} // namespace YAML
|
||||
|
||||
namespace YAML {
|
||||
class Emitter;
|
||||
|
||||
class EmitFromEvents : public EventHandler {
|
||||
public:
|
||||
EmitFromEvents(Emitter& emitter);
|
||||
|
||||
virtual void OnDocumentStart(const Mark& mark);
|
||||
virtual void OnDocumentEnd();
|
||||
|
||||
virtual void OnNull(const Mark& mark, anchor_t anchor);
|
||||
virtual void OnAlias(const Mark& mark, anchor_t anchor);
|
||||
virtual void OnScalar(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, const std::string& value);
|
||||
|
||||
virtual void OnSequenceStart(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, EmitterStyle::value style);
|
||||
virtual void OnSequenceEnd();
|
||||
|
||||
virtual void OnMapStart(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, EmitterStyle::value style);
|
||||
virtual void OnMapEnd();
|
||||
|
||||
private:
|
||||
void BeginNode();
|
||||
void EmitProps(const std::string& tag, anchor_t anchor);
|
||||
|
||||
private:
|
||||
Emitter& m_emitter;
|
||||
|
||||
struct State {
|
||||
enum value { WaitingForSequenceEntry, WaitingForKey, WaitingForValue };
|
||||
};
|
||||
std::stack<State::value> m_stateStack;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,254 @@
|
||||
#ifndef EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "yaml-cpp/binary.h"
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/emitterdef.h"
|
||||
#include "yaml-cpp/emittermanip.h"
|
||||
#include "yaml-cpp/noncopyable.h"
|
||||
#include "yaml-cpp/null.h"
|
||||
#include "yaml-cpp/ostream_wrapper.h"
|
||||
|
||||
namespace YAML {
|
||||
class Binary;
|
||||
struct _Null;
|
||||
} // namespace YAML
|
||||
|
||||
namespace YAML {
|
||||
class EmitterState;
|
||||
|
||||
class YAML_CPP_API Emitter : private noncopyable {
|
||||
public:
|
||||
Emitter();
|
||||
explicit Emitter(std::ostream& stream);
|
||||
~Emitter();
|
||||
|
||||
// output
|
||||
const char* c_str() const;
|
||||
std::size_t size() const;
|
||||
|
||||
// state checking
|
||||
bool good() const;
|
||||
const std::string GetLastError() const;
|
||||
|
||||
// global setters
|
||||
bool SetOutputCharset(EMITTER_MANIP value);
|
||||
bool SetStringFormat(EMITTER_MANIP value);
|
||||
bool SetBoolFormat(EMITTER_MANIP value);
|
||||
bool SetIntBase(EMITTER_MANIP value);
|
||||
bool SetSeqFormat(EMITTER_MANIP value);
|
||||
bool SetMapFormat(EMITTER_MANIP value);
|
||||
bool SetIndent(std::size_t n);
|
||||
bool SetPreCommentIndent(std::size_t n);
|
||||
bool SetPostCommentIndent(std::size_t n);
|
||||
bool SetFloatPrecision(std::size_t n);
|
||||
bool SetDoublePrecision(std::size_t n);
|
||||
|
||||
// local setters
|
||||
Emitter& SetLocalValue(EMITTER_MANIP value);
|
||||
Emitter& SetLocalIndent(const _Indent& indent);
|
||||
Emitter& SetLocalPrecision(const _Precision& precision);
|
||||
|
||||
// overloads of write
|
||||
Emitter& Write(const std::string& str);
|
||||
Emitter& Write(bool b);
|
||||
Emitter& Write(char ch);
|
||||
Emitter& Write(const _Alias& alias);
|
||||
Emitter& Write(const _Anchor& anchor);
|
||||
Emitter& Write(const _Tag& tag);
|
||||
Emitter& Write(const _Comment& comment);
|
||||
Emitter& Write(const _Null& n);
|
||||
Emitter& Write(const Binary& binary);
|
||||
|
||||
template <typename T>
|
||||
Emitter& WriteIntegralType(T value);
|
||||
|
||||
template <typename T>
|
||||
Emitter& WriteStreamable(T value);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void SetStreamablePrecision(std::stringstream&) {}
|
||||
std::size_t GetFloatPrecision() const;
|
||||
std::size_t GetDoublePrecision() const;
|
||||
|
||||
void PrepareIntegralStream(std::stringstream& stream) const;
|
||||
void StartedScalar();
|
||||
|
||||
private:
|
||||
void EmitBeginDoc();
|
||||
void EmitEndDoc();
|
||||
void EmitBeginSeq();
|
||||
void EmitEndSeq();
|
||||
void EmitBeginMap();
|
||||
void EmitEndMap();
|
||||
void EmitNewline();
|
||||
void EmitKindTag();
|
||||
void EmitTag(bool verbatim, const _Tag& tag);
|
||||
|
||||
void PrepareNode(EmitterNodeType::value child);
|
||||
void PrepareTopNode(EmitterNodeType::value child);
|
||||
void FlowSeqPrepareNode(EmitterNodeType::value child);
|
||||
void BlockSeqPrepareNode(EmitterNodeType::value child);
|
||||
|
||||
void FlowMapPrepareNode(EmitterNodeType::value child);
|
||||
|
||||
void FlowMapPrepareLongKey(EmitterNodeType::value child);
|
||||
void FlowMapPrepareLongKeyValue(EmitterNodeType::value child);
|
||||
void FlowMapPrepareSimpleKey(EmitterNodeType::value child);
|
||||
void FlowMapPrepareSimpleKeyValue(EmitterNodeType::value child);
|
||||
|
||||
void BlockMapPrepareNode(EmitterNodeType::value child);
|
||||
|
||||
void BlockMapPrepareLongKey(EmitterNodeType::value child);
|
||||
void BlockMapPrepareLongKeyValue(EmitterNodeType::value child);
|
||||
void BlockMapPrepareSimpleKey(EmitterNodeType::value child);
|
||||
void BlockMapPrepareSimpleKeyValue(EmitterNodeType::value child);
|
||||
|
||||
void SpaceOrIndentTo(bool requireSpace, std::size_t indent);
|
||||
|
||||
const char* ComputeFullBoolName(bool b) const;
|
||||
bool CanEmitNewline() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<EmitterState> m_pState;
|
||||
ostream_wrapper m_stream;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& Emitter::WriteIntegralType(T value) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
std::stringstream stream;
|
||||
PrepareIntegralStream(stream);
|
||||
stream << value;
|
||||
m_stream << stream.str();
|
||||
|
||||
StartedScalar();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& Emitter::WriteStreamable(T value) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
std::stringstream stream;
|
||||
SetStreamablePrecision<T>(stream);
|
||||
stream << value;
|
||||
m_stream << stream.str();
|
||||
|
||||
StartedScalar();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Emitter::SetStreamablePrecision<float>(std::stringstream& stream) {
|
||||
stream.precision(static_cast<std::streamsize>(GetFloatPrecision()));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Emitter::SetStreamablePrecision<double>(std::stringstream& stream) {
|
||||
stream.precision(static_cast<std::streamsize>(GetDoublePrecision()));
|
||||
}
|
||||
|
||||
// overloads of insertion
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::string& v) {
|
||||
return emitter.Write(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, bool v) {
|
||||
return emitter.Write(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, char v) {
|
||||
return emitter.Write(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, unsigned char v) {
|
||||
return emitter.Write(static_cast<char>(v));
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, const _Alias& v) {
|
||||
return emitter.Write(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, const _Anchor& v) {
|
||||
return emitter.Write(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, const _Tag& v) {
|
||||
return emitter.Write(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, const _Comment& v) {
|
||||
return emitter.Write(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, const _Null& v) {
|
||||
return emitter.Write(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, const Binary& b) {
|
||||
return emitter.Write(b);
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, const char* v) {
|
||||
return emitter.Write(std::string(v));
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, int v) {
|
||||
return emitter.WriteIntegralType(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, unsigned int v) {
|
||||
return emitter.WriteIntegralType(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, short v) {
|
||||
return emitter.WriteIntegralType(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, unsigned short v) {
|
||||
return emitter.WriteIntegralType(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, long v) {
|
||||
return emitter.WriteIntegralType(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, unsigned long v) {
|
||||
return emitter.WriteIntegralType(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, long long v) {
|
||||
return emitter.WriteIntegralType(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, unsigned long long v) {
|
||||
return emitter.WriteIntegralType(v);
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, float v) {
|
||||
return emitter.WriteStreamable(v);
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, double v) {
|
||||
return emitter.WriteStreamable(v);
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, EMITTER_MANIP value) {
|
||||
return emitter.SetLocalValue(value);
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, _Indent indent) {
|
||||
return emitter.SetLocalIndent(indent);
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, _Precision precision) {
|
||||
return emitter.SetLocalPrecision(precision);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef EMITTERDEF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EMITTERDEF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace YAML {
|
||||
struct EmitterNodeType {
|
||||
enum value { NoType, Property, Scalar, FlowSeq, BlockSeq, FlowMap, BlockMap };
|
||||
};
|
||||
}
|
||||
|
||||
#endif // EMITTERDEF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,137 @@
|
||||
#ifndef EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace YAML {
|
||||
enum EMITTER_MANIP {
|
||||
// general manipulators
|
||||
Auto,
|
||||
TagByKind,
|
||||
Newline,
|
||||
|
||||
// output character set
|
||||
EmitNonAscii,
|
||||
EscapeNonAscii,
|
||||
|
||||
// string manipulators
|
||||
// Auto, // duplicate
|
||||
SingleQuoted,
|
||||
DoubleQuoted,
|
||||
Literal,
|
||||
|
||||
// bool manipulators
|
||||
YesNoBool, // yes, no
|
||||
TrueFalseBool, // true, false
|
||||
OnOffBool, // on, off
|
||||
UpperCase, // TRUE, N
|
||||
LowerCase, // f, yes
|
||||
CamelCase, // No, Off
|
||||
LongBool, // yes, On
|
||||
ShortBool, // y, t
|
||||
|
||||
// int manipulators
|
||||
Dec,
|
||||
Hex,
|
||||
Oct,
|
||||
|
||||
// document manipulators
|
||||
BeginDoc,
|
||||
EndDoc,
|
||||
|
||||
// sequence manipulators
|
||||
BeginSeq,
|
||||
EndSeq,
|
||||
Flow,
|
||||
Block,
|
||||
|
||||
// map manipulators
|
||||
BeginMap,
|
||||
EndMap,
|
||||
Key,
|
||||
Value,
|
||||
// Flow, // duplicate
|
||||
// Block, // duplicate
|
||||
// Auto, // duplicate
|
||||
LongKey
|
||||
};
|
||||
|
||||
struct _Indent {
|
||||
_Indent(int value_) : value(value_) {}
|
||||
int value;
|
||||
};
|
||||
|
||||
inline _Indent Indent(int value) { return _Indent(value); }
|
||||
|
||||
struct _Alias {
|
||||
_Alias(const std::string& content_) : content(content_) {}
|
||||
std::string content;
|
||||
};
|
||||
|
||||
inline _Alias Alias(const std::string content) { return _Alias(content); }
|
||||
|
||||
struct _Anchor {
|
||||
_Anchor(const std::string& content_) : content(content_) {}
|
||||
std::string content;
|
||||
};
|
||||
|
||||
inline _Anchor Anchor(const std::string content) { return _Anchor(content); }
|
||||
|
||||
struct _Tag {
|
||||
struct Type {
|
||||
enum value { Verbatim, PrimaryHandle, NamedHandle };
|
||||
};
|
||||
|
||||
explicit _Tag(const std::string& prefix_, const std::string& content_,
|
||||
Type::value type_)
|
||||
: prefix(prefix_), content(content_), type(type_) {}
|
||||
std::string prefix;
|
||||
std::string content;
|
||||
Type::value type;
|
||||
};
|
||||
|
||||
inline _Tag VerbatimTag(const std::string content) {
|
||||
return _Tag("", content, _Tag::Type::Verbatim);
|
||||
}
|
||||
|
||||
inline _Tag LocalTag(const std::string content) {
|
||||
return _Tag("", content, _Tag::Type::PrimaryHandle);
|
||||
}
|
||||
|
||||
inline _Tag LocalTag(const std::string& prefix, const std::string content) {
|
||||
return _Tag(prefix, content, _Tag::Type::NamedHandle);
|
||||
}
|
||||
|
||||
inline _Tag SecondaryTag(const std::string content) {
|
||||
return _Tag("", content, _Tag::Type::NamedHandle);
|
||||
}
|
||||
|
||||
struct _Comment {
|
||||
_Comment(const std::string& content_) : content(content_) {}
|
||||
std::string content;
|
||||
};
|
||||
|
||||
inline _Comment Comment(const std::string content) { return _Comment(content); }
|
||||
|
||||
struct _Precision {
|
||||
_Precision(int floatPrecision_, int doublePrecision_)
|
||||
: floatPrecision(floatPrecision_), doublePrecision(doublePrecision_) {}
|
||||
|
||||
int floatPrecision;
|
||||
int doublePrecision;
|
||||
};
|
||||
|
||||
inline _Precision FloatPrecision(int n) { return _Precision(n, -1); }
|
||||
|
||||
inline _Precision DoublePrecision(int n) { return _Precision(-1, n); }
|
||||
|
||||
inline _Precision Precision(int n) { return _Precision(n, n); }
|
||||
}
|
||||
|
||||
#endif // EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace YAML {
|
||||
struct EmitterStyle {
|
||||
enum value { Default, Block, Flow };
|
||||
};
|
||||
}
|
||||
|
||||
#endif // EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "yaml-cpp/anchor.h"
|
||||
#include "yaml-cpp/emitterstyle.h"
|
||||
|
||||
namespace YAML {
|
||||
struct Mark;
|
||||
|
||||
class EventHandler {
|
||||
public:
|
||||
virtual ~EventHandler() {}
|
||||
|
||||
virtual void OnDocumentStart(const Mark& mark) = 0;
|
||||
virtual void OnDocumentEnd() = 0;
|
||||
|
||||
virtual void OnNull(const Mark& mark, anchor_t anchor) = 0;
|
||||
virtual void OnAlias(const Mark& mark, anchor_t anchor) = 0;
|
||||
virtual void OnScalar(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, const std::string& value) = 0;
|
||||
|
||||
virtual void OnSequenceStart(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, EmitterStyle::value style) = 0;
|
||||
virtual void OnSequenceEnd() = 0;
|
||||
|
||||
virtual void OnMapStart(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, EmitterStyle::value style) = 0;
|
||||
virtual void OnMapEnd() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,267 @@
|
||||
#ifndef EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/mark.h"
|
||||
#include "yaml-cpp/traits.h"
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// This is here for compatibility with older versions of Visual Studio
|
||||
// which don't support noexcept
|
||||
#ifdef _MSC_VER
|
||||
#define YAML_CPP_NOEXCEPT _NOEXCEPT
|
||||
#else
|
||||
#define YAML_CPP_NOEXCEPT noexcept
|
||||
#endif
|
||||
|
||||
namespace YAML {
|
||||
// error messages
|
||||
namespace ErrorMsg {
|
||||
const char* const YAML_DIRECTIVE_ARGS =
|
||||
"YAML directives must have exactly one argument";
|
||||
const char* const YAML_VERSION = "bad YAML version: ";
|
||||
const char* const YAML_MAJOR_VERSION = "YAML major version too large";
|
||||
const char* const REPEATED_YAML_DIRECTIVE = "repeated YAML directive";
|
||||
const char* const TAG_DIRECTIVE_ARGS =
|
||||
"TAG directives must have exactly two arguments";
|
||||
const char* const REPEATED_TAG_DIRECTIVE = "repeated TAG directive";
|
||||
const char* const CHAR_IN_TAG_HANDLE =
|
||||
"illegal character found while scanning tag handle";
|
||||
const char* const TAG_WITH_NO_SUFFIX = "tag handle with no suffix";
|
||||
const char* const END_OF_VERBATIM_TAG = "end of verbatim tag not found";
|
||||
const char* const END_OF_MAP = "end of map not found";
|
||||
const char* const END_OF_MAP_FLOW = "end of map flow not found";
|
||||
const char* const END_OF_SEQ = "end of sequence not found";
|
||||
const char* const END_OF_SEQ_FLOW = "end of sequence flow not found";
|
||||
const char* const MULTIPLE_TAGS =
|
||||
"cannot assign multiple tags to the same node";
|
||||
const char* const MULTIPLE_ANCHORS =
|
||||
"cannot assign multiple anchors to the same node";
|
||||
const char* const MULTIPLE_ALIASES =
|
||||
"cannot assign multiple aliases to the same node";
|
||||
const char* const ALIAS_CONTENT =
|
||||
"aliases can't have any content, *including* tags";
|
||||
const char* const INVALID_HEX = "bad character found while scanning hex number";
|
||||
const char* const INVALID_UNICODE = "invalid unicode: ";
|
||||
const char* const INVALID_ESCAPE = "unknown escape character: ";
|
||||
const char* const UNKNOWN_TOKEN = "unknown token";
|
||||
const char* const DOC_IN_SCALAR = "illegal document indicator in scalar";
|
||||
const char* const EOF_IN_SCALAR = "illegal EOF in scalar";
|
||||
const char* const CHAR_IN_SCALAR = "illegal character in scalar";
|
||||
const char* const TAB_IN_INDENTATION =
|
||||
"illegal tab when looking for indentation";
|
||||
const char* const FLOW_END = "illegal flow end";
|
||||
const char* const BLOCK_ENTRY = "illegal block entry";
|
||||
const char* const MAP_KEY = "illegal map key";
|
||||
const char* const MAP_VALUE = "illegal map value";
|
||||
const char* const ALIAS_NOT_FOUND = "alias not found after *";
|
||||
const char* const ANCHOR_NOT_FOUND = "anchor not found after &";
|
||||
const char* const CHAR_IN_ALIAS =
|
||||
"illegal character found while scanning alias";
|
||||
const char* const CHAR_IN_ANCHOR =
|
||||
"illegal character found while scanning anchor";
|
||||
const char* const ZERO_INDENT_IN_BLOCK =
|
||||
"cannot set zero indentation for a block scalar";
|
||||
const char* const CHAR_IN_BLOCK = "unexpected character in block scalar";
|
||||
const char* const AMBIGUOUS_ANCHOR =
|
||||
"cannot assign the same alias to multiple nodes";
|
||||
const char* const UNKNOWN_ANCHOR = "the referenced anchor is not defined";
|
||||
|
||||
const char* const INVALID_NODE =
|
||||
"invalid node; this may result from using a map iterator as a sequence "
|
||||
"iterator, or vice-versa";
|
||||
const char* const INVALID_SCALAR = "invalid scalar";
|
||||
const char* const KEY_NOT_FOUND = "key not found";
|
||||
const char* const BAD_CONVERSION = "bad conversion";
|
||||
const char* const BAD_DEREFERENCE = "bad dereference";
|
||||
const char* const BAD_SUBSCRIPT = "operator[] call on a scalar";
|
||||
const char* const BAD_PUSHBACK = "appending to a non-sequence";
|
||||
const char* const BAD_INSERT = "inserting in a non-convertible-to-map";
|
||||
|
||||
const char* const UNMATCHED_GROUP_TAG = "unmatched group tag";
|
||||
const char* const UNEXPECTED_END_SEQ = "unexpected end sequence token";
|
||||
const char* const UNEXPECTED_END_MAP = "unexpected end map token";
|
||||
const char* const SINGLE_QUOTED_CHAR =
|
||||
"invalid character in single-quoted string";
|
||||
const char* const INVALID_ANCHOR = "invalid anchor";
|
||||
const char* const INVALID_ALIAS = "invalid alias";
|
||||
const char* const INVALID_TAG = "invalid tag";
|
||||
const char* const BAD_FILE = "bad file";
|
||||
|
||||
template <typename T>
|
||||
inline const std::string KEY_NOT_FOUND_WITH_KEY(
|
||||
const T&, typename disable_if<is_numeric<T>>::type* = 0) {
|
||||
return KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) {
|
||||
std::stringstream stream;
|
||||
stream << KEY_NOT_FOUND << ": " << key;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const std::string KEY_NOT_FOUND_WITH_KEY(
|
||||
const T& key, typename enable_if<is_numeric<T>>::type* = 0) {
|
||||
std::stringstream stream;
|
||||
stream << KEY_NOT_FOUND << ": " << key;
|
||||
return stream.str();
|
||||
}
|
||||
}
|
||||
|
||||
class YAML_CPP_API Exception : public std::runtime_error {
|
||||
public:
|
||||
Exception(const Mark& mark_, const std::string& msg_)
|
||||
: std::runtime_error(build_what(mark_, msg_)), mark(mark_), msg(msg_) {}
|
||||
virtual ~Exception() YAML_CPP_NOEXCEPT;
|
||||
|
||||
Exception(const Exception&) = default;
|
||||
|
||||
Mark mark;
|
||||
std::string msg;
|
||||
|
||||
private:
|
||||
static const std::string build_what(const Mark& mark,
|
||||
const std::string& msg) {
|
||||
if (mark.is_null()) {
|
||||
return msg.c_str();
|
||||
}
|
||||
|
||||
std::stringstream output;
|
||||
output << "yaml-cpp: error at line " << mark.line + 1 << ", column "
|
||||
<< mark.column + 1 << ": " << msg;
|
||||
return output.str();
|
||||
}
|
||||
};
|
||||
|
||||
class YAML_CPP_API ParserException : public Exception {
|
||||
public:
|
||||
ParserException(const Mark& mark_, const std::string& msg_)
|
||||
: Exception(mark_, msg_) {}
|
||||
ParserException(const ParserException&) = default;
|
||||
virtual ~ParserException() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
class YAML_CPP_API RepresentationException : public Exception {
|
||||
public:
|
||||
RepresentationException(const Mark& mark_, const std::string& msg_)
|
||||
: Exception(mark_, msg_) {}
|
||||
RepresentationException(const RepresentationException&) = default;
|
||||
virtual ~RepresentationException() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
// representation exceptions
|
||||
class YAML_CPP_API InvalidScalar : public RepresentationException {
|
||||
public:
|
||||
InvalidScalar(const Mark& mark_)
|
||||
: RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {}
|
||||
InvalidScalar(const InvalidScalar&) = default;
|
||||
virtual ~InvalidScalar() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
class YAML_CPP_API KeyNotFound : public RepresentationException {
|
||||
public:
|
||||
template <typename T>
|
||||
KeyNotFound(const Mark& mark_, const T& key_)
|
||||
: RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {
|
||||
}
|
||||
KeyNotFound(const KeyNotFound&) = default;
|
||||
virtual ~KeyNotFound() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class YAML_CPP_API TypedKeyNotFound : public KeyNotFound {
|
||||
public:
|
||||
TypedKeyNotFound(const Mark& mark_, const T& key_)
|
||||
: KeyNotFound(mark_, key_), key(key_) {}
|
||||
virtual ~TypedKeyNotFound() YAML_CPP_NOEXCEPT {}
|
||||
|
||||
T key;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline TypedKeyNotFound<T> MakeTypedKeyNotFound(const Mark& mark,
|
||||
const T& key) {
|
||||
return TypedKeyNotFound<T>(mark, key);
|
||||
}
|
||||
|
||||
class YAML_CPP_API InvalidNode : public RepresentationException {
|
||||
public:
|
||||
InvalidNode()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::INVALID_NODE) {}
|
||||
InvalidNode(const InvalidNode&) = default;
|
||||
virtual ~InvalidNode() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
class YAML_CPP_API BadConversion : public RepresentationException {
|
||||
public:
|
||||
explicit BadConversion(const Mark& mark_)
|
||||
: RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {}
|
||||
BadConversion(const BadConversion&) = default;
|
||||
virtual ~BadConversion() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypedBadConversion : public BadConversion {
|
||||
public:
|
||||
explicit TypedBadConversion(const Mark& mark_) : BadConversion(mark_) {}
|
||||
};
|
||||
|
||||
class YAML_CPP_API BadDereference : public RepresentationException {
|
||||
public:
|
||||
BadDereference()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_DEREFERENCE) {}
|
||||
BadDereference(const BadDereference&) = default;
|
||||
virtual ~BadDereference() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
class YAML_CPP_API BadSubscript : public RepresentationException {
|
||||
public:
|
||||
BadSubscript()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_SUBSCRIPT) {}
|
||||
BadSubscript(const BadSubscript&) = default;
|
||||
virtual ~BadSubscript() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
class YAML_CPP_API BadPushback : public RepresentationException {
|
||||
public:
|
||||
BadPushback()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_PUSHBACK) {}
|
||||
BadPushback(const BadPushback&) = default;
|
||||
virtual ~BadPushback() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
class YAML_CPP_API BadInsert : public RepresentationException {
|
||||
public:
|
||||
BadInsert()
|
||||
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_INSERT) {}
|
||||
BadInsert(const BadInsert&) = default;
|
||||
virtual ~BadInsert() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
class YAML_CPP_API EmitterException : public Exception {
|
||||
public:
|
||||
EmitterException(const std::string& msg_)
|
||||
: Exception(Mark::null_mark(), msg_) {}
|
||||
EmitterException(const EmitterException&) = default;
|
||||
virtual ~EmitterException() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
|
||||
class YAML_CPP_API BadFile : public Exception {
|
||||
public:
|
||||
BadFile() : Exception(Mark::null_mark(), ErrorMsg::BAD_FILE) {}
|
||||
BadFile(const BadFile&) = default;
|
||||
virtual ~BadFile() YAML_CPP_NOEXCEPT;
|
||||
};
|
||||
}
|
||||
|
||||
#undef YAML_CPP_NOEXCEPT
|
||||
|
||||
#endif // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
|
||||
namespace YAML {
|
||||
struct YAML_CPP_API Mark {
|
||||
Mark() : pos(0), line(0), column(0) {}
|
||||
|
||||
static const Mark null_mark() { return Mark(-1, -1, -1); }
|
||||
|
||||
bool is_null() const { return pos == -1 && line == -1 && column == -1; }
|
||||
|
||||
int pos;
|
||||
int line, column;
|
||||
|
||||
private:
|
||||
Mark(int pos_, int line_, int column_)
|
||||
: pos(pos_), line(line_), column(column_) {}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,331 @@
|
||||
#ifndef NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "yaml-cpp/binary.h"
|
||||
#include "yaml-cpp/node/impl.h"
|
||||
#include "yaml-cpp/node/iterator.h"
|
||||
#include "yaml-cpp/node/node.h"
|
||||
#include "yaml-cpp/node/type.h"
|
||||
#include "yaml-cpp/null.h"
|
||||
|
||||
namespace YAML {
|
||||
class Binary;
|
||||
struct _Null;
|
||||
template <typename T>
|
||||
struct convert;
|
||||
} // namespace YAML
|
||||
|
||||
namespace YAML {
|
||||
namespace conversion {
|
||||
inline bool IsInfinity(const std::string& input) {
|
||||
return input == ".inf" || input == ".Inf" || input == ".INF" ||
|
||||
input == "+.inf" || input == "+.Inf" || input == "+.INF";
|
||||
}
|
||||
|
||||
inline bool IsNegativeInfinity(const std::string& input) {
|
||||
return input == "-.inf" || input == "-.Inf" || input == "-.INF";
|
||||
}
|
||||
|
||||
inline bool IsNaN(const std::string& input) {
|
||||
return input == ".nan" || input == ".NaN" || input == ".NAN";
|
||||
}
|
||||
}
|
||||
|
||||
// Node
|
||||
template <>
|
||||
struct convert<Node> {
|
||||
static Node encode(const Node& rhs) { return rhs; }
|
||||
|
||||
static bool decode(const Node& node, Node& rhs) {
|
||||
rhs.reset(node);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// std::string
|
||||
template <>
|
||||
struct convert<std::string> {
|
||||
static Node encode(const std::string& rhs) { return Node(rhs); }
|
||||
|
||||
static bool decode(const Node& node, std::string& rhs) {
|
||||
if (!node.IsScalar())
|
||||
return false;
|
||||
rhs = node.Scalar();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// C-strings can only be encoded
|
||||
template <>
|
||||
struct convert<const char*> {
|
||||
static Node encode(const char*& rhs) { return Node(rhs); }
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct convert<const char[N]> {
|
||||
static Node encode(const char(&rhs)[N]) { return Node(rhs); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct convert<_Null> {
|
||||
static Node encode(const _Null& /* rhs */) { return Node(); }
|
||||
|
||||
static bool decode(const Node& node, _Null& /* rhs */) {
|
||||
return node.IsNull();
|
||||
}
|
||||
};
|
||||
|
||||
#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \
|
||||
template <> \
|
||||
struct convert<type> { \
|
||||
static Node encode(const type& rhs) { \
|
||||
std::stringstream stream; \
|
||||
stream.precision(std::numeric_limits<type>::digits10 + 1); \
|
||||
stream << rhs; \
|
||||
return Node(stream.str()); \
|
||||
} \
|
||||
\
|
||||
static bool decode(const Node& node, type& rhs) { \
|
||||
if (node.Type() != NodeType::Scalar) \
|
||||
return false; \
|
||||
const std::string& input = node.Scalar(); \
|
||||
std::stringstream stream(input); \
|
||||
stream.unsetf(std::ios::dec); \
|
||||
if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) \
|
||||
return true; \
|
||||
if (std::numeric_limits<type>::has_infinity) { \
|
||||
if (conversion::IsInfinity(input)) { \
|
||||
rhs = std::numeric_limits<type>::infinity(); \
|
||||
return true; \
|
||||
} else if (conversion::IsNegativeInfinity(input)) { \
|
||||
rhs = negative_op std::numeric_limits<type>::infinity(); \
|
||||
return true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (std::numeric_limits<type>::has_quiet_NaN && \
|
||||
conversion::IsNaN(input)) { \
|
||||
rhs = std::numeric_limits<type>::quiet_NaN(); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \
|
||||
YAML_DEFINE_CONVERT_STREAMABLE(type, -)
|
||||
|
||||
#define YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(type) \
|
||||
YAML_DEFINE_CONVERT_STREAMABLE(type, +)
|
||||
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(int);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(short);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long long);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned short);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long long);
|
||||
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(char);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(signed char);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned char);
|
||||
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(float);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(double);
|
||||
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long double);
|
||||
|
||||
#undef YAML_DEFINE_CONVERT_STREAMABLE_SIGNED
|
||||
#undef YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED
|
||||
#undef YAML_DEFINE_CONVERT_STREAMABLE
|
||||
|
||||
// bool
|
||||
template <>
|
||||
struct convert<bool> {
|
||||
static Node encode(bool rhs) { return rhs ? Node("true") : Node("false"); }
|
||||
|
||||
YAML_CPP_API static bool decode(const Node& node, bool& rhs);
|
||||
};
|
||||
|
||||
// std::map
|
||||
template <typename K, typename V>
|
||||
struct convert<std::map<K, V>> {
|
||||
static Node encode(const std::map<K, V>& rhs) {
|
||||
Node node(NodeType::Map);
|
||||
for (typename std::map<K, V>::const_iterator it = rhs.begin();
|
||||
it != rhs.end(); ++it)
|
||||
node.force_insert(it->first, it->second);
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, std::map<K, V>& rhs) {
|
||||
if (!node.IsMap())
|
||||
return false;
|
||||
|
||||
rhs.clear();
|
||||
for (const_iterator it = node.begin(); it != node.end(); ++it)
|
||||
#if defined(__GNUC__) && __GNUC__ < 4
|
||||
// workaround for GCC 3:
|
||||
rhs[it->first.template as<K>()] = it->second.template as<V>();
|
||||
#else
|
||||
rhs[it->first.as<K>()] = it->second.as<V>();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// std::vector
|
||||
template <typename T>
|
||||
struct convert<std::vector<T>> {
|
||||
static Node encode(const std::vector<T>& rhs) {
|
||||
Node node(NodeType::Sequence);
|
||||
for (typename std::vector<T>::const_iterator it = rhs.begin();
|
||||
it != rhs.end(); ++it)
|
||||
node.push_back(*it);
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, std::vector<T>& rhs) {
|
||||
if (!node.IsSequence())
|
||||
return false;
|
||||
|
||||
rhs.clear();
|
||||
for (const_iterator it = node.begin(); it != node.end(); ++it)
|
||||
#if defined(__GNUC__) && __GNUC__ < 4
|
||||
// workaround for GCC 3:
|
||||
rhs.push_back(it->template as<T>());
|
||||
#else
|
||||
rhs.push_back(it->as<T>());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// std::list
|
||||
template <typename T>
|
||||
struct convert<std::list<T>> {
|
||||
static Node encode(const std::list<T>& rhs) {
|
||||
Node node(NodeType::Sequence);
|
||||
for (typename std::list<T>::const_iterator it = rhs.begin();
|
||||
it != rhs.end(); ++it)
|
||||
node.push_back(*it);
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, std::list<T>& rhs) {
|
||||
if (!node.IsSequence())
|
||||
return false;
|
||||
|
||||
rhs.clear();
|
||||
for (const_iterator it = node.begin(); it != node.end(); ++it)
|
||||
#if defined(__GNUC__) && __GNUC__ < 4
|
||||
// workaround for GCC 3:
|
||||
rhs.push_back(it->template as<T>());
|
||||
#else
|
||||
rhs.push_back(it->as<T>());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// std::array
|
||||
template <typename T, std::size_t N>
|
||||
struct convert<std::array<T, N>> {
|
||||
static Node encode(const std::array<T, N>& rhs) {
|
||||
Node node(NodeType::Sequence);
|
||||
for (const auto& element : rhs) {
|
||||
node.push_back(element);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, std::array<T, N>& rhs) {
|
||||
if (!isNodeValid(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto i = 0u; i < node.size(); ++i) {
|
||||
#if defined(__GNUC__) && __GNUC__ < 4
|
||||
// workaround for GCC 3:
|
||||
rhs[i] = node[i].template as<T>();
|
||||
#else
|
||||
rhs[i] = node[i].as<T>();
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool isNodeValid(const Node& node) {
|
||||
return node.IsSequence() && node.size() == N;
|
||||
}
|
||||
};
|
||||
|
||||
// std::pair
|
||||
template <typename T, typename U>
|
||||
struct convert<std::pair<T, U>> {
|
||||
static Node encode(const std::pair<T, U>& rhs) {
|
||||
Node node(NodeType::Sequence);
|
||||
node.push_back(rhs.first);
|
||||
node.push_back(rhs.second);
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, std::pair<T, U>& rhs) {
|
||||
if (!node.IsSequence())
|
||||
return false;
|
||||
if (node.size() != 2)
|
||||
return false;
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 4
|
||||
// workaround for GCC 3:
|
||||
rhs.first = node[0].template as<T>();
|
||||
#else
|
||||
rhs.first = node[0].as<T>();
|
||||
#endif
|
||||
#if defined(__GNUC__) && __GNUC__ < 4
|
||||
// workaround for GCC 3:
|
||||
rhs.second = node[1].template as<U>();
|
||||
#else
|
||||
rhs.second = node[1].as<U>();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// binary
|
||||
template <>
|
||||
struct convert<Binary> {
|
||||
static Node encode(const Binary& rhs) {
|
||||
return Node(EncodeBase64(rhs.data(), rhs.size()));
|
||||
}
|
||||
|
||||
static bool decode(const Node& node, Binary& rhs) {
|
||||
if (!node.IsScalar())
|
||||
return false;
|
||||
|
||||
std::vector<unsigned char> data = DecodeBase64(node.Scalar());
|
||||
if (data.empty() && !node.Scalar().empty())
|
||||
return false;
|
||||
|
||||
rhs.swap(data);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef NODE_DETAIL_BOOL_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define NODE_DETAIL_BOOL_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
struct unspecified_bool {
|
||||
struct NOT_ALLOWED;
|
||||
static void true_value(NOT_ALLOWED*) {}
|
||||
};
|
||||
typedef void (*unspecified_bool_type)(unspecified_bool::NOT_ALLOWED*);
|
||||
}
|
||||
}
|
||||
|
||||
#define YAML_CPP_OPERATOR_BOOL() \
|
||||
operator YAML::detail::unspecified_bool_type() const { \
|
||||
return this->operator!() ? 0 \
|
||||
: &YAML::detail::unspecified_bool::true_value; \
|
||||
}
|
||||
|
||||
#endif // NODE_DETAIL_BOOL_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,185 @@
|
||||
#ifndef NODE_DETAIL_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define NODE_DETAIL_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/node/detail/node.h"
|
||||
#include "yaml-cpp/node/detail/node_data.h"
|
||||
#include <type_traits>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
template <typename Key, typename Enable = void>
|
||||
struct get_idx {
|
||||
static node* get(const std::vector<node*>& /* sequence */,
|
||||
const Key& /* key */, shared_memory_holder /* pMemory */) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
struct get_idx<Key,
|
||||
typename std::enable_if<std::is_unsigned<Key>::value &&
|
||||
!std::is_same<Key, bool>::value>::type> {
|
||||
static node* get(const std::vector<node*>& sequence, const Key& key,
|
||||
shared_memory_holder /* pMemory */) {
|
||||
return key < sequence.size() ? sequence[key] : 0;
|
||||
}
|
||||
|
||||
static node* get(std::vector<node*>& sequence, const Key& key,
|
||||
shared_memory_holder pMemory) {
|
||||
if (key > sequence.size() || (key > 0 && !sequence[key-1]->is_defined()))
|
||||
return 0;
|
||||
if (key == sequence.size())
|
||||
sequence.push_back(&pMemory->create_node());
|
||||
return sequence[key];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
struct get_idx<Key, typename std::enable_if<std::is_signed<Key>::value>::type> {
|
||||
static node* get(const std::vector<node*>& sequence, const Key& key,
|
||||
shared_memory_holder pMemory) {
|
||||
return key >= 0 ? get_idx<std::size_t>::get(
|
||||
sequence, static_cast<std::size_t>(key), pMemory)
|
||||
: 0;
|
||||
}
|
||||
static node* get(std::vector<node*>& sequence, const Key& key,
|
||||
shared_memory_holder pMemory) {
|
||||
return key >= 0 ? get_idx<std::size_t>::get(
|
||||
sequence, static_cast<std::size_t>(key), pMemory)
|
||||
: 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline bool node::equals(const T& rhs, shared_memory_holder pMemory) {
|
||||
T lhs;
|
||||
if (convert<T>::decode(Node(*this, pMemory), lhs)) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool node::equals(const char* rhs, shared_memory_holder pMemory) {
|
||||
return equals<std::string>(rhs, pMemory);
|
||||
}
|
||||
|
||||
// indexing
|
||||
template <typename Key>
|
||||
inline node* node_data::get(const Key& key,
|
||||
shared_memory_holder pMemory) const {
|
||||
switch (m_type) {
|
||||
case NodeType::Map:
|
||||
break;
|
||||
case NodeType::Undefined:
|
||||
case NodeType::Null:
|
||||
return NULL;
|
||||
case NodeType::Sequence:
|
||||
if (node* pNode = get_idx<Key>::get(m_sequence, key, pMemory))
|
||||
return pNode;
|
||||
return NULL;
|
||||
case NodeType::Scalar:
|
||||
throw BadSubscript();
|
||||
}
|
||||
|
||||
for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
if (it->first->equals(key, pMemory)) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
inline node& node_data::get(const Key& key, shared_memory_holder pMemory) {
|
||||
switch (m_type) {
|
||||
case NodeType::Map:
|
||||
break;
|
||||
case NodeType::Undefined:
|
||||
case NodeType::Null:
|
||||
case NodeType::Sequence:
|
||||
if (node* pNode = get_idx<Key>::get(m_sequence, key, pMemory)) {
|
||||
m_type = NodeType::Sequence;
|
||||
return *pNode;
|
||||
}
|
||||
|
||||
convert_to_map(pMemory);
|
||||
break;
|
||||
case NodeType::Scalar:
|
||||
throw BadSubscript();
|
||||
}
|
||||
|
||||
for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
if (it->first->equals(key, pMemory)) {
|
||||
return *it->second;
|
||||
}
|
||||
}
|
||||
|
||||
node& k = convert_to_node(key, pMemory);
|
||||
node& v = pMemory->create_node();
|
||||
insert_map_pair(k, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
inline bool node_data::remove(const Key& key, shared_memory_holder pMemory) {
|
||||
if (m_type != NodeType::Map)
|
||||
return false;
|
||||
|
||||
for (kv_pairs::iterator it = m_undefinedPairs.begin();
|
||||
it != m_undefinedPairs.end();) {
|
||||
kv_pairs::iterator jt = std::next(it);
|
||||
if (it->first->equals(key, pMemory))
|
||||
m_undefinedPairs.erase(it);
|
||||
it = jt;
|
||||
}
|
||||
|
||||
for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
if (it->first->equals(key, pMemory)) {
|
||||
m_map.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// map
|
||||
template <typename Key, typename Value>
|
||||
inline void node_data::force_insert(const Key& key, const Value& value,
|
||||
shared_memory_holder pMemory) {
|
||||
switch (m_type) {
|
||||
case NodeType::Map:
|
||||
break;
|
||||
case NodeType::Undefined:
|
||||
case NodeType::Null:
|
||||
case NodeType::Sequence:
|
||||
convert_to_map(pMemory);
|
||||
break;
|
||||
case NodeType::Scalar:
|
||||
throw BadInsert();
|
||||
}
|
||||
|
||||
node& k = convert_to_node(key, pMemory);
|
||||
node& v = convert_to_node(value, pMemory);
|
||||
insert_map_pair(k, v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline node& node_data::convert_to_node(const T& rhs,
|
||||
shared_memory_holder pMemory) {
|
||||
Node value = convert<T>::encode(rhs);
|
||||
value.EnsureNodeExists();
|
||||
pMemory->merge(*value.m_pMemory);
|
||||
return *value.m_pNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NODE_DETAIL_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,92 @@
|
||||
#ifndef VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/node/node.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include "yaml-cpp/node/detail/node_iterator.h"
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
struct iterator_value;
|
||||
|
||||
template <typename V>
|
||||
class iterator_base : public std::iterator<std::forward_iterator_tag, V,
|
||||
std::ptrdiff_t, V*, V> {
|
||||
|
||||
private:
|
||||
template <typename>
|
||||
friend class iterator_base;
|
||||
struct enabler {};
|
||||
typedef node_iterator base_type;
|
||||
|
||||
struct proxy {
|
||||
explicit proxy(const V& x) : m_ref(x) {}
|
||||
V* operator->() { return std::addressof(m_ref); }
|
||||
operator V*() { return std::addressof(m_ref); }
|
||||
|
||||
V m_ref;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef typename iterator_base::value_type value_type;
|
||||
|
||||
public:
|
||||
iterator_base() : m_iterator(), m_pMemory() {}
|
||||
explicit iterator_base(base_type rhs, shared_memory_holder pMemory)
|
||||
: m_iterator(rhs), m_pMemory(pMemory) {}
|
||||
|
||||
template <class W>
|
||||
iterator_base(const iterator_base<W>& rhs,
|
||||
typename std::enable_if<std::is_convertible<W*, V*>::value,
|
||||
enabler>::type = enabler())
|
||||
: m_iterator(rhs.m_iterator), m_pMemory(rhs.m_pMemory) {}
|
||||
|
||||
iterator_base<V>& operator++() {
|
||||
++m_iterator;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator_base<V> operator++(int) {
|
||||
iterator_base<V> iterator_pre(*this);
|
||||
++(*this);
|
||||
return iterator_pre;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator==(const iterator_base<W>& rhs) const {
|
||||
return m_iterator == rhs.m_iterator;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator!=(const iterator_base<W>& rhs) const {
|
||||
return m_iterator != rhs.m_iterator;
|
||||
}
|
||||
|
||||
value_type operator*() const {
|
||||
const typename base_type::value_type& v = *m_iterator;
|
||||
if (v.pNode)
|
||||
return value_type(Node(*v, m_pMemory));
|
||||
if (v.first && v.second)
|
||||
return value_type(Node(*v.first, m_pMemory), Node(*v.second, m_pMemory));
|
||||
return value_type();
|
||||
}
|
||||
|
||||
proxy operator->() const { return proxy(**this); }
|
||||
|
||||
private:
|
||||
base_type m_iterator;
|
||||
shared_memory_holder m_pMemory;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace YAML {
|
||||
|
||||
namespace detail {
|
||||
struct iterator_value;
|
||||
template <typename V>
|
||||
class iterator_base;
|
||||
}
|
||||
|
||||
typedef detail::iterator_base<detail::iterator_value> iterator;
|
||||
typedef detail::iterator_base<const detail::iterator_value> const_iterator;
|
||||
}
|
||||
|
||||
#endif // VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class node;
|
||||
} // namespace detail
|
||||
} // namespace YAML
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class YAML_CPP_API memory {
|
||||
public:
|
||||
node& create_node();
|
||||
void merge(const memory& rhs);
|
||||
|
||||
private:
|
||||
typedef std::set<shared_node> Nodes;
|
||||
Nodes m_nodes;
|
||||
};
|
||||
|
||||
class YAML_CPP_API memory_holder {
|
||||
public:
|
||||
memory_holder() : m_pMemory(new memory) {}
|
||||
|
||||
node& create_node() { return m_pMemory->create_node(); }
|
||||
void merge(memory_holder& rhs);
|
||||
|
||||
private:
|
||||
shared_memory m_pMemory;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,169 @@
|
||||
#ifndef NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/emitterstyle.h"
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/node/type.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include "yaml-cpp/node/detail/node_ref.h"
|
||||
#include <set>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class node {
|
||||
public:
|
||||
node() : m_pRef(new node_ref) {}
|
||||
node(const node&) = delete;
|
||||
node& operator=(const node&) = delete;
|
||||
|
||||
bool is(const node& rhs) const { return m_pRef == rhs.m_pRef; }
|
||||
const node_ref* ref() const { return m_pRef.get(); }
|
||||
|
||||
bool is_defined() const { return m_pRef->is_defined(); }
|
||||
const Mark& mark() const { return m_pRef->mark(); }
|
||||
NodeType::value type() const { return m_pRef->type(); }
|
||||
|
||||
const std::string& scalar() const { return m_pRef->scalar(); }
|
||||
const std::string& tag() const { return m_pRef->tag(); }
|
||||
EmitterStyle::value style() const { return m_pRef->style(); }
|
||||
|
||||
template <typename T>
|
||||
bool equals(const T& rhs, shared_memory_holder pMemory);
|
||||
bool equals(const char* rhs, shared_memory_holder pMemory);
|
||||
|
||||
void mark_defined() {
|
||||
if (is_defined())
|
||||
return;
|
||||
|
||||
m_pRef->mark_defined();
|
||||
for (nodes::iterator it = m_dependencies.begin();
|
||||
it != m_dependencies.end(); ++it)
|
||||
(*it)->mark_defined();
|
||||
m_dependencies.clear();
|
||||
}
|
||||
|
||||
void add_dependency(node& rhs) {
|
||||
if (is_defined())
|
||||
rhs.mark_defined();
|
||||
else
|
||||
m_dependencies.insert(&rhs);
|
||||
}
|
||||
|
||||
void set_ref(const node& rhs) {
|
||||
if (rhs.is_defined())
|
||||
mark_defined();
|
||||
m_pRef = rhs.m_pRef;
|
||||
}
|
||||
void set_data(const node& rhs) {
|
||||
if (rhs.is_defined())
|
||||
mark_defined();
|
||||
m_pRef->set_data(*rhs.m_pRef);
|
||||
}
|
||||
|
||||
void set_mark(const Mark& mark) { m_pRef->set_mark(mark); }
|
||||
|
||||
void set_type(NodeType::value type) {
|
||||
if (type != NodeType::Undefined)
|
||||
mark_defined();
|
||||
m_pRef->set_type(type);
|
||||
}
|
||||
void set_null() {
|
||||
mark_defined();
|
||||
m_pRef->set_null();
|
||||
}
|
||||
void set_scalar(const std::string& scalar) {
|
||||
mark_defined();
|
||||
m_pRef->set_scalar(scalar);
|
||||
}
|
||||
void set_tag(const std::string& tag) {
|
||||
mark_defined();
|
||||
m_pRef->set_tag(tag);
|
||||
}
|
||||
|
||||
// style
|
||||
void set_style(EmitterStyle::value style) {
|
||||
mark_defined();
|
||||
m_pRef->set_style(style);
|
||||
}
|
||||
|
||||
// size/iterator
|
||||
std::size_t size() const { return m_pRef->size(); }
|
||||
|
||||
const_node_iterator begin() const {
|
||||
return static_cast<const node_ref&>(*m_pRef).begin();
|
||||
}
|
||||
node_iterator begin() { return m_pRef->begin(); }
|
||||
|
||||
const_node_iterator end() const {
|
||||
return static_cast<const node_ref&>(*m_pRef).end();
|
||||
}
|
||||
node_iterator end() { return m_pRef->end(); }
|
||||
|
||||
// sequence
|
||||
void push_back(node& input, shared_memory_holder pMemory) {
|
||||
m_pRef->push_back(input, pMemory);
|
||||
input.add_dependency(*this);
|
||||
}
|
||||
void insert(node& key, node& value, shared_memory_holder pMemory) {
|
||||
m_pRef->insert(key, value, pMemory);
|
||||
key.add_dependency(*this);
|
||||
value.add_dependency(*this);
|
||||
}
|
||||
|
||||
// indexing
|
||||
template <typename Key>
|
||||
node* get(const Key& key, shared_memory_holder pMemory) const {
|
||||
// NOTE: this returns a non-const node so that the top-level Node can wrap
|
||||
// it, and returns a pointer so that it can be NULL (if there is no such
|
||||
// key).
|
||||
return static_cast<const node_ref&>(*m_pRef).get(key, pMemory);
|
||||
}
|
||||
template <typename Key>
|
||||
node& get(const Key& key, shared_memory_holder pMemory) {
|
||||
node& value = m_pRef->get(key, pMemory);
|
||||
value.add_dependency(*this);
|
||||
return value;
|
||||
}
|
||||
template <typename Key>
|
||||
bool remove(const Key& key, shared_memory_holder pMemory) {
|
||||
return m_pRef->remove(key, pMemory);
|
||||
}
|
||||
|
||||
node* get(node& key, shared_memory_holder pMemory) const {
|
||||
// NOTE: this returns a non-const node so that the top-level Node can wrap
|
||||
// it, and returns a pointer so that it can be NULL (if there is no such
|
||||
// key).
|
||||
return static_cast<const node_ref&>(*m_pRef).get(key, pMemory);
|
||||
}
|
||||
node& get(node& key, shared_memory_holder pMemory) {
|
||||
node& value = m_pRef->get(key, pMemory);
|
||||
key.add_dependency(*this);
|
||||
value.add_dependency(*this);
|
||||
return value;
|
||||
}
|
||||
bool remove(node& key, shared_memory_holder pMemory) {
|
||||
return m_pRef->remove(key, pMemory);
|
||||
}
|
||||
|
||||
// map
|
||||
template <typename Key, typename Value>
|
||||
void force_insert(const Key& key, const Value& value,
|
||||
shared_memory_holder pMemory) {
|
||||
m_pRef->force_insert(key, value, pMemory);
|
||||
}
|
||||
|
||||
private:
|
||||
shared_node_ref m_pRef;
|
||||
typedef std::set<node*> nodes;
|
||||
nodes m_dependencies;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,127 @@
|
||||
#ifndef VALUE_DETAIL_NODE_DATA_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_DETAIL_NODE_DATA_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/node/detail/node_iterator.h"
|
||||
#include "yaml-cpp/node/iterator.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include "yaml-cpp/node/type.h"
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class node;
|
||||
} // namespace detail
|
||||
} // namespace YAML
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class YAML_CPP_API node_data {
|
||||
public:
|
||||
node_data();
|
||||
node_data(const node_data&) = delete;
|
||||
node_data& operator=(const node_data&) = delete;
|
||||
|
||||
void mark_defined();
|
||||
void set_mark(const Mark& mark);
|
||||
void set_type(NodeType::value type);
|
||||
void set_tag(const std::string& tag);
|
||||
void set_null();
|
||||
void set_scalar(const std::string& scalar);
|
||||
void set_style(EmitterStyle::value style);
|
||||
|
||||
bool is_defined() const { return m_isDefined; }
|
||||
const Mark& mark() const { return m_mark; }
|
||||
NodeType::value type() const {
|
||||
return m_isDefined ? m_type : NodeType::Undefined;
|
||||
}
|
||||
const std::string& scalar() const { return m_scalar; }
|
||||
const std::string& tag() const { return m_tag; }
|
||||
EmitterStyle::value style() const { return m_style; }
|
||||
|
||||
// size/iterator
|
||||
std::size_t size() const;
|
||||
|
||||
const_node_iterator begin() const;
|
||||
node_iterator begin();
|
||||
|
||||
const_node_iterator end() const;
|
||||
node_iterator end();
|
||||
|
||||
// sequence
|
||||
void push_back(node& node, shared_memory_holder pMemory);
|
||||
void insert(node& key, node& value, shared_memory_holder pMemory);
|
||||
|
||||
// indexing
|
||||
template <typename Key>
|
||||
node* get(const Key& key, shared_memory_holder pMemory) const;
|
||||
template <typename Key>
|
||||
node& get(const Key& key, shared_memory_holder pMemory);
|
||||
template <typename Key>
|
||||
bool remove(const Key& key, shared_memory_holder pMemory);
|
||||
|
||||
node* get(node& key, shared_memory_holder pMemory) const;
|
||||
node& get(node& key, shared_memory_holder pMemory);
|
||||
bool remove(node& key, shared_memory_holder pMemory);
|
||||
|
||||
// map
|
||||
template <typename Key, typename Value>
|
||||
void force_insert(const Key& key, const Value& value,
|
||||
shared_memory_holder pMemory);
|
||||
|
||||
public:
|
||||
static std::string empty_scalar;
|
||||
|
||||
private:
|
||||
void compute_seq_size() const;
|
||||
void compute_map_size() const;
|
||||
|
||||
void reset_sequence();
|
||||
void reset_map();
|
||||
|
||||
void insert_map_pair(node& key, node& value);
|
||||
void convert_to_map(shared_memory_holder pMemory);
|
||||
void convert_sequence_to_map(shared_memory_holder pMemory);
|
||||
|
||||
template <typename T>
|
||||
static node& convert_to_node(const T& rhs, shared_memory_holder pMemory);
|
||||
|
||||
private:
|
||||
bool m_isDefined;
|
||||
Mark m_mark;
|
||||
NodeType::value m_type;
|
||||
std::string m_tag;
|
||||
EmitterStyle::value m_style;
|
||||
|
||||
// scalar
|
||||
std::string m_scalar;
|
||||
|
||||
// sequence
|
||||
typedef std::vector<node*> node_seq;
|
||||
node_seq m_sequence;
|
||||
|
||||
mutable std::size_t m_seqSize;
|
||||
|
||||
// map
|
||||
typedef std::vector<std::pair<node*, node*>> node_map;
|
||||
node_map m_map;
|
||||
|
||||
typedef std::pair<node*, node*> kv_pair;
|
||||
typedef std::list<kv_pair> kv_pairs;
|
||||
mutable kv_pairs m_undefinedPairs;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VALUE_DETAIL_NODE_DATA_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,180 @@
|
||||
#ifndef VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
struct iterator_type {
|
||||
enum value { NoneType, Sequence, Map };
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
struct node_iterator_value : public std::pair<V*, V*> {
|
||||
typedef std::pair<V*, V*> kv;
|
||||
|
||||
node_iterator_value() : kv(), pNode(0) {}
|
||||
explicit node_iterator_value(V& rhs) : kv(), pNode(&rhs) {}
|
||||
explicit node_iterator_value(V& key, V& value) : kv(&key, &value), pNode(0) {}
|
||||
|
||||
V& operator*() const { return *pNode; }
|
||||
V& operator->() const { return *pNode; }
|
||||
|
||||
V* pNode;
|
||||
};
|
||||
|
||||
typedef std::vector<node*> node_seq;
|
||||
typedef std::vector<std::pair<node*, node*>> node_map;
|
||||
|
||||
template <typename V>
|
||||
struct node_iterator_type {
|
||||
typedef node_seq::iterator seq;
|
||||
typedef node_map::iterator map;
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
struct node_iterator_type<const V> {
|
||||
typedef node_seq::const_iterator seq;
|
||||
typedef node_map::const_iterator map;
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
class node_iterator_base
|
||||
: public std::iterator<std::forward_iterator_tag, node_iterator_value<V>,
|
||||
std::ptrdiff_t, node_iterator_value<V>*,
|
||||
node_iterator_value<V>> {
|
||||
private:
|
||||
struct enabler {};
|
||||
|
||||
struct proxy {
|
||||
explicit proxy(const node_iterator_value<V>& x) : m_ref(x) {}
|
||||
node_iterator_value<V>* operator->() { return std::addressof(m_ref); }
|
||||
operator node_iterator_value<V>*() { return std::addressof(m_ref); }
|
||||
|
||||
node_iterator_value<V> m_ref;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef typename node_iterator_type<V>::seq SeqIter;
|
||||
typedef typename node_iterator_type<V>::map MapIter;
|
||||
typedef node_iterator_value<V> value_type;
|
||||
|
||||
node_iterator_base()
|
||||
: m_type(iterator_type::NoneType), m_seqIt(), m_mapIt(), m_mapEnd() {}
|
||||
explicit node_iterator_base(SeqIter seqIt)
|
||||
: m_type(iterator_type::Sequence),
|
||||
m_seqIt(seqIt),
|
||||
m_mapIt(),
|
||||
m_mapEnd() {}
|
||||
explicit node_iterator_base(MapIter mapIt, MapIter mapEnd)
|
||||
: m_type(iterator_type::Map),
|
||||
m_seqIt(),
|
||||
m_mapIt(mapIt),
|
||||
m_mapEnd(mapEnd) {
|
||||
m_mapIt = increment_until_defined(m_mapIt);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
node_iterator_base(const node_iterator_base<W>& rhs,
|
||||
typename std::enable_if<std::is_convertible<W*, V*>::value,
|
||||
enabler>::type = enabler())
|
||||
: m_type(rhs.m_type),
|
||||
m_seqIt(rhs.m_seqIt),
|
||||
m_mapIt(rhs.m_mapIt),
|
||||
m_mapEnd(rhs.m_mapEnd) {}
|
||||
|
||||
template <typename>
|
||||
friend class node_iterator_base;
|
||||
|
||||
template <typename W>
|
||||
bool operator==(const node_iterator_base<W>& rhs) const {
|
||||
if (m_type != rhs.m_type)
|
||||
return false;
|
||||
|
||||
switch (m_type) {
|
||||
case iterator_type::NoneType:
|
||||
return true;
|
||||
case iterator_type::Sequence:
|
||||
return m_seqIt == rhs.m_seqIt;
|
||||
case iterator_type::Map:
|
||||
return m_mapIt == rhs.m_mapIt;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator!=(const node_iterator_base<W>& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
node_iterator_base<V>& operator++() {
|
||||
switch (m_type) {
|
||||
case iterator_type::NoneType:
|
||||
break;
|
||||
case iterator_type::Sequence:
|
||||
++m_seqIt;
|
||||
break;
|
||||
case iterator_type::Map:
|
||||
++m_mapIt;
|
||||
m_mapIt = increment_until_defined(m_mapIt);
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator_base<V> operator++(int) {
|
||||
node_iterator_base<V> iterator_pre(*this);
|
||||
++(*this);
|
||||
return iterator_pre;
|
||||
}
|
||||
|
||||
value_type operator*() const {
|
||||
switch (m_type) {
|
||||
case iterator_type::NoneType:
|
||||
return value_type();
|
||||
case iterator_type::Sequence:
|
||||
return value_type(**m_seqIt);
|
||||
case iterator_type::Map:
|
||||
return value_type(*m_mapIt->first, *m_mapIt->second);
|
||||
}
|
||||
return value_type();
|
||||
}
|
||||
|
||||
proxy operator->() const { return proxy(**this); }
|
||||
|
||||
MapIter increment_until_defined(MapIter it) {
|
||||
while (it != m_mapEnd && !is_defined(it))
|
||||
++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
bool is_defined(MapIter it) const {
|
||||
return it->first->is_defined() && it->second->is_defined();
|
||||
}
|
||||
|
||||
private:
|
||||
typename iterator_type::value m_type;
|
||||
|
||||
SeqIter m_seqIt;
|
||||
MapIter m_mapIt, m_mapEnd;
|
||||
};
|
||||
|
||||
typedef node_iterator_base<node> node_iterator;
|
||||
typedef node_iterator_base<const node> const_node_iterator;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,98 @@
|
||||
#ifndef VALUE_DETAIL_NODE_REF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_DETAIL_NODE_REF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/node/type.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include "yaml-cpp/node/detail/node_data.h"
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class node_ref {
|
||||
public:
|
||||
node_ref() : m_pData(new node_data) {}
|
||||
node_ref(const node_ref&) = delete;
|
||||
node_ref& operator=(const node_ref&) = delete;
|
||||
|
||||
bool is_defined() const { return m_pData->is_defined(); }
|
||||
const Mark& mark() const { return m_pData->mark(); }
|
||||
NodeType::value type() const { return m_pData->type(); }
|
||||
const std::string& scalar() const { return m_pData->scalar(); }
|
||||
const std::string& tag() const { return m_pData->tag(); }
|
||||
EmitterStyle::value style() const { return m_pData->style(); }
|
||||
|
||||
void mark_defined() { m_pData->mark_defined(); }
|
||||
void set_data(const node_ref& rhs) { m_pData = rhs.m_pData; }
|
||||
|
||||
void set_mark(const Mark& mark) { m_pData->set_mark(mark); }
|
||||
void set_type(NodeType::value type) { m_pData->set_type(type); }
|
||||
void set_tag(const std::string& tag) { m_pData->set_tag(tag); }
|
||||
void set_null() { m_pData->set_null(); }
|
||||
void set_scalar(const std::string& scalar) { m_pData->set_scalar(scalar); }
|
||||
void set_style(EmitterStyle::value style) { m_pData->set_style(style); }
|
||||
|
||||
// size/iterator
|
||||
std::size_t size() const { return m_pData->size(); }
|
||||
|
||||
const_node_iterator begin() const {
|
||||
return static_cast<const node_data&>(*m_pData).begin();
|
||||
}
|
||||
node_iterator begin() { return m_pData->begin(); }
|
||||
|
||||
const_node_iterator end() const {
|
||||
return static_cast<const node_data&>(*m_pData).end();
|
||||
}
|
||||
node_iterator end() { return m_pData->end(); }
|
||||
|
||||
// sequence
|
||||
void push_back(node& node, shared_memory_holder pMemory) {
|
||||
m_pData->push_back(node, pMemory);
|
||||
}
|
||||
void insert(node& key, node& value, shared_memory_holder pMemory) {
|
||||
m_pData->insert(key, value, pMemory);
|
||||
}
|
||||
|
||||
// indexing
|
||||
template <typename Key>
|
||||
node* get(const Key& key, shared_memory_holder pMemory) const {
|
||||
return static_cast<const node_data&>(*m_pData).get(key, pMemory);
|
||||
}
|
||||
template <typename Key>
|
||||
node& get(const Key& key, shared_memory_holder pMemory) {
|
||||
return m_pData->get(key, pMemory);
|
||||
}
|
||||
template <typename Key>
|
||||
bool remove(const Key& key, shared_memory_holder pMemory) {
|
||||
return m_pData->remove(key, pMemory);
|
||||
}
|
||||
|
||||
node* get(node& key, shared_memory_holder pMemory) const {
|
||||
return static_cast<const node_data&>(*m_pData).get(key, pMemory);
|
||||
}
|
||||
node& get(node& key, shared_memory_holder pMemory) {
|
||||
return m_pData->get(key, pMemory);
|
||||
}
|
||||
bool remove(node& key, shared_memory_holder pMemory) {
|
||||
return m_pData->remove(key, pMemory);
|
||||
}
|
||||
|
||||
// map
|
||||
template <typename Key, typename Value>
|
||||
void force_insert(const Key& key, const Value& value,
|
||||
shared_memory_holder pMemory) {
|
||||
m_pData->force_insert(key, value, pMemory);
|
||||
}
|
||||
|
||||
private:
|
||||
shared_node_data m_pData;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VALUE_DETAIL_NODE_REF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
|
||||
namespace YAML {
|
||||
class Emitter;
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* Emits the node to the given {@link Emitter}. If there is an error in writing,
|
||||
* {@link Emitter#good} will return false.
|
||||
*/
|
||||
YAML_CPP_API Emitter& operator<<(Emitter& out, const Node& node);
|
||||
|
||||
/** Emits the node to the given output stream. */
|
||||
YAML_CPP_API std::ostream& operator<<(std::ostream& out, const Node& node);
|
||||
|
||||
/** Converts the node to a YAML string. */
|
||||
YAML_CPP_API std::string Dump(const Node& node);
|
||||
} // namespace YAML
|
||||
|
||||
#endif // NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,448 @@
|
||||
#ifndef NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/node/node.h"
|
||||
#include "yaml-cpp/node/iterator.h"
|
||||
#include "yaml-cpp/node/detail/memory.h"
|
||||
#include "yaml-cpp/node/detail/node.h"
|
||||
#include "yaml-cpp/exceptions.h"
|
||||
#include <string>
|
||||
|
||||
namespace YAML {
|
||||
inline Node::Node() : m_isValid(true), m_pNode(NULL) {}
|
||||
|
||||
inline Node::Node(NodeType::value type)
|
||||
: m_isValid(true),
|
||||
m_pMemory(new detail::memory_holder),
|
||||
m_pNode(&m_pMemory->create_node()) {
|
||||
m_pNode->set_type(type);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Node::Node(const T& rhs)
|
||||
: m_isValid(true),
|
||||
m_pMemory(new detail::memory_holder),
|
||||
m_pNode(&m_pMemory->create_node()) {
|
||||
Assign(rhs);
|
||||
}
|
||||
|
||||
inline Node::Node(const detail::iterator_value& rhs)
|
||||
: m_isValid(rhs.m_isValid),
|
||||
m_pMemory(rhs.m_pMemory),
|
||||
m_pNode(rhs.m_pNode) {}
|
||||
|
||||
inline Node::Node(const Node& rhs)
|
||||
: m_isValid(rhs.m_isValid),
|
||||
m_pMemory(rhs.m_pMemory),
|
||||
m_pNode(rhs.m_pNode) {}
|
||||
|
||||
inline Node::Node(Zombie) : m_isValid(false), m_pNode(NULL) {}
|
||||
|
||||
inline Node::Node(detail::node& node, detail::shared_memory_holder pMemory)
|
||||
: m_isValid(true), m_pMemory(pMemory), m_pNode(&node) {}
|
||||
|
||||
inline Node::~Node() {}
|
||||
|
||||
inline void Node::EnsureNodeExists() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
if (!m_pNode) {
|
||||
m_pMemory.reset(new detail::memory_holder);
|
||||
m_pNode = &m_pMemory->create_node();
|
||||
m_pNode->set_null();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Node::IsDefined() const {
|
||||
if (!m_isValid) {
|
||||
return false;
|
||||
}
|
||||
return m_pNode ? m_pNode->is_defined() : true;
|
||||
}
|
||||
|
||||
inline Mark Node::Mark() const {
|
||||
if (!m_isValid) {
|
||||
throw InvalidNode();
|
||||
}
|
||||
return m_pNode ? m_pNode->mark() : Mark::null_mark();
|
||||
}
|
||||
|
||||
inline NodeType::value Node::Type() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return m_pNode ? m_pNode->type() : NodeType::Null;
|
||||
}
|
||||
|
||||
// access
|
||||
|
||||
// template helpers
|
||||
template <typename T, typename S>
|
||||
struct as_if {
|
||||
explicit as_if(const Node& node_) : node(node_) {}
|
||||
const Node& node;
|
||||
|
||||
T operator()(const S& fallback) const {
|
||||
if (!node.m_pNode)
|
||||
return fallback;
|
||||
|
||||
T t;
|
||||
if (convert<T>::decode(node, t))
|
||||
return t;
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
struct as_if<std::string, S> {
|
||||
explicit as_if(const Node& node_) : node(node_) {}
|
||||
const Node& node;
|
||||
|
||||
std::string operator()(const S& fallback) const {
|
||||
if (node.Type() != NodeType::Scalar)
|
||||
return fallback;
|
||||
return node.Scalar();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct as_if<T, void> {
|
||||
explicit as_if(const Node& node_) : node(node_) {}
|
||||
const Node& node;
|
||||
|
||||
T operator()() const {
|
||||
if (!node.m_pNode)
|
||||
throw TypedBadConversion<T>(node.Mark());
|
||||
|
||||
T t;
|
||||
if (convert<T>::decode(node, t))
|
||||
return t;
|
||||
throw TypedBadConversion<T>(node.Mark());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct as_if<std::string, void> {
|
||||
explicit as_if(const Node& node_) : node(node_) {}
|
||||
const Node& node;
|
||||
|
||||
std::string operator()() const {
|
||||
if (node.Type() != NodeType::Scalar)
|
||||
throw TypedBadConversion<std::string>(node.Mark());
|
||||
return node.Scalar();
|
||||
}
|
||||
};
|
||||
|
||||
// access functions
|
||||
template <typename T>
|
||||
inline T Node::as() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return as_if<T, void>(*this)();
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
inline T Node::as(const S& fallback) const {
|
||||
if (!m_isValid)
|
||||
return fallback;
|
||||
return as_if<T, S>(*this)(fallback);
|
||||
}
|
||||
|
||||
inline const std::string& Node::Scalar() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return m_pNode ? m_pNode->scalar() : detail::node_data::empty_scalar;
|
||||
}
|
||||
|
||||
inline const std::string& Node::Tag() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return m_pNode ? m_pNode->tag() : detail::node_data::empty_scalar;
|
||||
}
|
||||
|
||||
inline void Node::SetTag(const std::string& tag) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
m_pNode->set_tag(tag);
|
||||
}
|
||||
|
||||
inline EmitterStyle::value Node::Style() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return m_pNode ? m_pNode->style() : EmitterStyle::Default;
|
||||
}
|
||||
|
||||
inline void Node::SetStyle(EmitterStyle::value style) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
m_pNode->set_style(style);
|
||||
}
|
||||
|
||||
// assignment
|
||||
inline bool Node::is(const Node& rhs) const {
|
||||
if (!m_isValid || !rhs.m_isValid)
|
||||
throw InvalidNode();
|
||||
if (!m_pNode || !rhs.m_pNode)
|
||||
return false;
|
||||
return m_pNode->is(*rhs.m_pNode);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Node& Node::operator=(const T& rhs) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
Assign(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void Node::reset(const YAML::Node& rhs) {
|
||||
if (!m_isValid || !rhs.m_isValid)
|
||||
throw InvalidNode();
|
||||
m_pMemory = rhs.m_pMemory;
|
||||
m_pNode = rhs.m_pNode;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Node::Assign(const T& rhs) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
AssignData(convert<T>::encode(rhs));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Node::Assign(const std::string& rhs) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
m_pNode->set_scalar(rhs);
|
||||
}
|
||||
|
||||
inline void Node::Assign(const char* rhs) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
m_pNode->set_scalar(rhs);
|
||||
}
|
||||
|
||||
inline void Node::Assign(char* rhs) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
m_pNode->set_scalar(rhs);
|
||||
}
|
||||
|
||||
inline Node& Node::operator=(const Node& rhs) {
|
||||
if (!m_isValid || !rhs.m_isValid)
|
||||
throw InvalidNode();
|
||||
if (is(rhs))
|
||||
return *this;
|
||||
AssignNode(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void Node::AssignData(const Node& rhs) {
|
||||
if (!m_isValid || !rhs.m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
rhs.EnsureNodeExists();
|
||||
|
||||
m_pNode->set_data(*rhs.m_pNode);
|
||||
m_pMemory->merge(*rhs.m_pMemory);
|
||||
}
|
||||
|
||||
inline void Node::AssignNode(const Node& rhs) {
|
||||
if (!m_isValid || !rhs.m_isValid)
|
||||
throw InvalidNode();
|
||||
rhs.EnsureNodeExists();
|
||||
|
||||
if (!m_pNode) {
|
||||
m_pNode = rhs.m_pNode;
|
||||
m_pMemory = rhs.m_pMemory;
|
||||
return;
|
||||
}
|
||||
|
||||
m_pNode->set_ref(*rhs.m_pNode);
|
||||
m_pMemory->merge(*rhs.m_pMemory);
|
||||
m_pNode = rhs.m_pNode;
|
||||
}
|
||||
|
||||
// size/iterator
|
||||
inline std::size_t Node::size() const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
return m_pNode ? m_pNode->size() : 0;
|
||||
}
|
||||
|
||||
inline const_iterator Node::begin() const {
|
||||
if (!m_isValid)
|
||||
return const_iterator();
|
||||
return m_pNode ? const_iterator(m_pNode->begin(), m_pMemory)
|
||||
: const_iterator();
|
||||
}
|
||||
|
||||
inline iterator Node::begin() {
|
||||
if (!m_isValid)
|
||||
return iterator();
|
||||
return m_pNode ? iterator(m_pNode->begin(), m_pMemory) : iterator();
|
||||
}
|
||||
|
||||
inline const_iterator Node::end() const {
|
||||
if (!m_isValid)
|
||||
return const_iterator();
|
||||
return m_pNode ? const_iterator(m_pNode->end(), m_pMemory) : const_iterator();
|
||||
}
|
||||
|
||||
inline iterator Node::end() {
|
||||
if (!m_isValid)
|
||||
return iterator();
|
||||
return m_pNode ? iterator(m_pNode->end(), m_pMemory) : iterator();
|
||||
}
|
||||
|
||||
// sequence
|
||||
template <typename T>
|
||||
inline void Node::push_back(const T& rhs) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
push_back(Node(rhs));
|
||||
}
|
||||
|
||||
inline void Node::push_back(const Node& rhs) {
|
||||
if (!m_isValid || !rhs.m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
rhs.EnsureNodeExists();
|
||||
|
||||
m_pNode->push_back(*rhs.m_pNode, m_pMemory);
|
||||
m_pMemory->merge(*rhs.m_pMemory);
|
||||
}
|
||||
|
||||
// helpers for indexing
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct to_value_t {
|
||||
explicit to_value_t(const T& t_) : t(t_) {}
|
||||
const T& t;
|
||||
typedef const T& return_type;
|
||||
|
||||
const T& operator()() const { return t; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_value_t<const char*> {
|
||||
explicit to_value_t(const char* t_) : t(t_) {}
|
||||
const char* t;
|
||||
typedef std::string return_type;
|
||||
|
||||
const std::string operator()() const { return t; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_value_t<char*> {
|
||||
explicit to_value_t(char* t_) : t(t_) {}
|
||||
const char* t;
|
||||
typedef std::string return_type;
|
||||
|
||||
const std::string operator()() const { return t; }
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct to_value_t<char[N]> {
|
||||
explicit to_value_t(const char* t_) : t(t_) {}
|
||||
const char* t;
|
||||
typedef std::string return_type;
|
||||
|
||||
const std::string operator()() const { return t; }
|
||||
};
|
||||
|
||||
// converts C-strings to std::strings so they can be copied
|
||||
template <typename T>
|
||||
inline typename to_value_t<T>::return_type to_value(const T& t) {
|
||||
return to_value_t<T>(t)();
|
||||
}
|
||||
}
|
||||
|
||||
// indexing
|
||||
template <typename Key>
|
||||
inline const Node Node::operator[](const Key& key) const {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
detail::node* value = static_cast<const detail::node&>(*m_pNode)
|
||||
.get(detail::to_value(key), m_pMemory);
|
||||
if (!value) {
|
||||
return Node(ZombieNode);
|
||||
}
|
||||
return Node(*value, m_pMemory);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
inline Node Node::operator[](const Key& key) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
detail::node& value = m_pNode->get(detail::to_value(key), m_pMemory);
|
||||
return Node(value, m_pMemory);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
inline bool Node::remove(const Key& key) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
return m_pNode->remove(detail::to_value(key), m_pMemory);
|
||||
}
|
||||
|
||||
inline const Node Node::operator[](const Node& key) const {
|
||||
if (!m_isValid || !key.m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
key.EnsureNodeExists();
|
||||
m_pMemory->merge(*key.m_pMemory);
|
||||
detail::node* value =
|
||||
static_cast<const detail::node&>(*m_pNode).get(*key.m_pNode, m_pMemory);
|
||||
if (!value) {
|
||||
return Node(ZombieNode);
|
||||
}
|
||||
return Node(*value, m_pMemory);
|
||||
}
|
||||
|
||||
inline Node Node::operator[](const Node& key) {
|
||||
if (!m_isValid || !key.m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
key.EnsureNodeExists();
|
||||
m_pMemory->merge(*key.m_pMemory);
|
||||
detail::node& value = m_pNode->get(*key.m_pNode, m_pMemory);
|
||||
return Node(value, m_pMemory);
|
||||
}
|
||||
|
||||
inline bool Node::remove(const Node& key) {
|
||||
if (!m_isValid || !key.m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
key.EnsureNodeExists();
|
||||
return m_pNode->remove(*key.m_pNode, m_pMemory);
|
||||
}
|
||||
|
||||
// map
|
||||
template <typename Key, typename Value>
|
||||
inline void Node::force_insert(const Key& key, const Value& value) {
|
||||
if (!m_isValid)
|
||||
throw InvalidNode();
|
||||
EnsureNodeExists();
|
||||
m_pNode->force_insert(detail::to_value(key), detail::to_value(value),
|
||||
m_pMemory);
|
||||
}
|
||||
|
||||
// free functions
|
||||
inline bool operator==(const Node& lhs, const Node& rhs) { return lhs.is(rhs); }
|
||||
}
|
||||
|
||||
#endif // NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef VALUE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/node/node.h"
|
||||
#include "yaml-cpp/node/detail/iterator_fwd.h"
|
||||
#include "yaml-cpp/node/detail/iterator.h"
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
struct iterator_value : public Node, std::pair<Node, Node> {
|
||||
iterator_value() {}
|
||||
explicit iterator_value(const Node& rhs)
|
||||
: Node(rhs),
|
||||
std::pair<Node, Node>(Node(Node::ZombieNode), Node(Node::ZombieNode)) {}
|
||||
explicit iterator_value(const Node& key, const Node& value)
|
||||
: Node(Node::ZombieNode), std::pair<Node, Node>(key, value) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VALUE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,145 @@
|
||||
#ifndef NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/emitterstyle.h"
|
||||
#include "yaml-cpp/mark.h"
|
||||
#include "yaml-cpp/node/detail/bool_type.h"
|
||||
#include "yaml-cpp/node/detail/iterator_fwd.h"
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
#include "yaml-cpp/node/type.h"
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class node;
|
||||
class node_data;
|
||||
struct iterator_value;
|
||||
} // namespace detail
|
||||
} // namespace YAML
|
||||
|
||||
namespace YAML {
|
||||
class YAML_CPP_API Node {
|
||||
public:
|
||||
friend class NodeBuilder;
|
||||
friend class NodeEvents;
|
||||
friend struct detail::iterator_value;
|
||||
friend class detail::node;
|
||||
friend class detail::node_data;
|
||||
template <typename>
|
||||
friend class detail::iterator_base;
|
||||
template <typename T, typename S>
|
||||
friend struct as_if;
|
||||
|
||||
typedef YAML::iterator iterator;
|
||||
typedef YAML::const_iterator const_iterator;
|
||||
|
||||
Node();
|
||||
explicit Node(NodeType::value type);
|
||||
template <typename T>
|
||||
explicit Node(const T& rhs);
|
||||
explicit Node(const detail::iterator_value& rhs);
|
||||
Node(const Node& rhs);
|
||||
~Node();
|
||||
|
||||
YAML::Mark Mark() const;
|
||||
NodeType::value Type() const;
|
||||
bool IsDefined() const;
|
||||
bool IsNull() const { return Type() == NodeType::Null; }
|
||||
bool IsScalar() const { return Type() == NodeType::Scalar; }
|
||||
bool IsSequence() const { return Type() == NodeType::Sequence; }
|
||||
bool IsMap() const { return Type() == NodeType::Map; }
|
||||
|
||||
// bool conversions
|
||||
YAML_CPP_OPERATOR_BOOL()
|
||||
bool operator!() const { return !IsDefined(); }
|
||||
|
||||
// access
|
||||
template <typename T>
|
||||
T as() const;
|
||||
template <typename T, typename S>
|
||||
T as(const S& fallback) const;
|
||||
const std::string& Scalar() const;
|
||||
|
||||
const std::string& Tag() const;
|
||||
void SetTag(const std::string& tag);
|
||||
|
||||
// style
|
||||
// WARNING: This API might change in future releases.
|
||||
EmitterStyle::value Style() const;
|
||||
void SetStyle(EmitterStyle::value style);
|
||||
|
||||
// assignment
|
||||
bool is(const Node& rhs) const;
|
||||
template <typename T>
|
||||
Node& operator=(const T& rhs);
|
||||
Node& operator=(const Node& rhs);
|
||||
void reset(const Node& rhs = Node());
|
||||
|
||||
// size/iterator
|
||||
std::size_t size() const;
|
||||
|
||||
const_iterator begin() const;
|
||||
iterator begin();
|
||||
|
||||
const_iterator end() const;
|
||||
iterator end();
|
||||
|
||||
// sequence
|
||||
template <typename T>
|
||||
void push_back(const T& rhs);
|
||||
void push_back(const Node& rhs);
|
||||
|
||||
// indexing
|
||||
template <typename Key>
|
||||
const Node operator[](const Key& key) const;
|
||||
template <typename Key>
|
||||
Node operator[](const Key& key);
|
||||
template <typename Key>
|
||||
bool remove(const Key& key);
|
||||
|
||||
const Node operator[](const Node& key) const;
|
||||
Node operator[](const Node& key);
|
||||
bool remove(const Node& key);
|
||||
|
||||
// map
|
||||
template <typename Key, typename Value>
|
||||
void force_insert(const Key& key, const Value& value);
|
||||
|
||||
private:
|
||||
enum Zombie { ZombieNode };
|
||||
explicit Node(Zombie);
|
||||
explicit Node(detail::node& node, detail::shared_memory_holder pMemory);
|
||||
|
||||
void EnsureNodeExists() const;
|
||||
|
||||
template <typename T>
|
||||
void Assign(const T& rhs);
|
||||
void Assign(const char* rhs);
|
||||
void Assign(char* rhs);
|
||||
|
||||
void AssignData(const Node& rhs);
|
||||
void AssignNode(const Node& rhs);
|
||||
|
||||
private:
|
||||
bool m_isValid;
|
||||
mutable detail::shared_memory_holder m_pMemory;
|
||||
mutable detail::node* m_pNode;
|
||||
};
|
||||
|
||||
YAML_CPP_API bool operator==(const Node& lhs, const Node& rhs);
|
||||
|
||||
YAML_CPP_API Node Clone(const Node& node);
|
||||
|
||||
template <typename T>
|
||||
struct convert;
|
||||
}
|
||||
|
||||
#endif // NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,78 @@
|
||||
#ifndef VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
|
||||
namespace YAML {
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* Loads the input string as a single YAML document.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API Node Load(const std::string& input);
|
||||
|
||||
/**
|
||||
* Loads the input string as a single YAML document.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API Node Load(const char* input);
|
||||
|
||||
/**
|
||||
* Loads the input stream as a single YAML document.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API Node Load(std::istream& input);
|
||||
|
||||
/**
|
||||
* Loads the input file as a single YAML document.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
* @throws {@link BadFile} if the file cannot be loaded.
|
||||
*/
|
||||
YAML_CPP_API Node LoadFile(const std::string& filename);
|
||||
|
||||
/**
|
||||
* Loads the input string as a list of YAML documents.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API std::vector<Node> LoadAll(const std::string& input);
|
||||
|
||||
/**
|
||||
* Loads the input string as a list of YAML documents.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API std::vector<Node> LoadAll(const char* input);
|
||||
|
||||
/**
|
||||
* Loads the input stream as a list of YAML documents.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
*/
|
||||
YAML_CPP_API std::vector<Node> LoadAll(std::istream& input);
|
||||
|
||||
/**
|
||||
* Loads the input file as a list of YAML documents.
|
||||
*
|
||||
* @throws {@link ParserException} if it is malformed.
|
||||
* @throws {@link BadFile} if the file cannot be loaded.
|
||||
*/
|
||||
YAML_CPP_API std::vector<Node> LoadAllFromFile(const std::string& filename);
|
||||
} // namespace YAML
|
||||
|
||||
#endif // VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef VALUE_PTR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_PTR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include <memory>
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
class node;
|
||||
class node_ref;
|
||||
class node_data;
|
||||
class memory;
|
||||
class memory_holder;
|
||||
|
||||
typedef std::shared_ptr<node> shared_node;
|
||||
typedef std::shared_ptr<node_ref> shared_node_ref;
|
||||
typedef std::shared_ptr<node_data> shared_node_data;
|
||||
typedef std::shared_ptr<memory_holder> shared_memory_holder;
|
||||
typedef std::shared_ptr<memory> shared_memory;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VALUE_PTR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace YAML {
|
||||
struct NodeType {
|
||||
enum value { Undefined, Null, Scalar, Sequence, Map };
|
||||
};
|
||||
}
|
||||
|
||||
#endif // VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
|
||||
namespace YAML {
|
||||
// this is basically boost::noncopyable
|
||||
class YAML_CPP_API noncopyable {
|
||||
protected:
|
||||
noncopyable() {}
|
||||
~noncopyable() {}
|
||||
|
||||
private:
|
||||
noncopyable(const noncopyable&);
|
||||
const noncopyable& operator=(const noncopyable&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include <string>
|
||||
|
||||
namespace YAML {
|
||||
class Node;
|
||||
|
||||
struct YAML_CPP_API _Null {};
|
||||
inline bool operator==(const _Null&, const _Null&) { return true; }
|
||||
inline bool operator!=(const _Null&, const _Null&) { return false; }
|
||||
|
||||
YAML_CPP_API bool IsNull(const Node& node); // old API only
|
||||
YAML_CPP_API bool IsNullString(const std::string& str);
|
||||
|
||||
extern YAML_CPP_API _Null Null;
|
||||
}
|
||||
|
||||
#endif // NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,72 @@
|
||||
#ifndef OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
|
||||
namespace YAML {
|
||||
class YAML_CPP_API ostream_wrapper {
|
||||
public:
|
||||
ostream_wrapper();
|
||||
explicit ostream_wrapper(std::ostream& stream);
|
||||
~ostream_wrapper();
|
||||
|
||||
void write(const std::string& str);
|
||||
void write(const char* str, std::size_t size);
|
||||
|
||||
void set_comment() { m_comment = true; }
|
||||
|
||||
const char* str() const {
|
||||
if (m_pStream) {
|
||||
return 0;
|
||||
} else {
|
||||
m_buffer[m_pos] = '\0';
|
||||
return &m_buffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t row() const { return m_row; }
|
||||
std::size_t col() const { return m_col; }
|
||||
std::size_t pos() const { return m_pos; }
|
||||
bool comment() const { return m_comment; }
|
||||
|
||||
private:
|
||||
void update_pos(char ch);
|
||||
|
||||
private:
|
||||
mutable std::vector<char> m_buffer;
|
||||
std::ostream* const m_pStream;
|
||||
|
||||
std::size_t m_pos;
|
||||
std::size_t m_row, m_col;
|
||||
bool m_comment;
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
inline ostream_wrapper& operator<<(ostream_wrapper& stream,
|
||||
const char(&str)[N]) {
|
||||
stream.write(str, N - 1);
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline ostream_wrapper& operator<<(ostream_wrapper& stream,
|
||||
const std::string& str) {
|
||||
stream.write(str);
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline ostream_wrapper& operator<<(ostream_wrapper& stream, char ch) {
|
||||
stream.write(&ch, 1);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,86 @@
|
||||
#ifndef PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <ios>
|
||||
#include <memory>
|
||||
|
||||
#include "yaml-cpp/dll.h"
|
||||
#include "yaml-cpp/noncopyable.h"
|
||||
|
||||
namespace YAML {
|
||||
class EventHandler;
|
||||
class Node;
|
||||
class Scanner;
|
||||
struct Directives;
|
||||
struct Token;
|
||||
|
||||
/**
|
||||
* A parser turns a stream of bytes into one stream of "events" per YAML
|
||||
* document in the input stream.
|
||||
*/
|
||||
class YAML_CPP_API Parser : private noncopyable {
|
||||
public:
|
||||
/** Constructs an empty parser (with no input. */
|
||||
Parser();
|
||||
|
||||
/**
|
||||
* Constructs a parser from the given input stream. The input stream must
|
||||
* live as long as the parser.
|
||||
*/
|
||||
explicit Parser(std::istream& in);
|
||||
|
||||
~Parser();
|
||||
|
||||
/** Evaluates to true if the parser has some valid input to be read. */
|
||||
explicit operator bool() const;
|
||||
|
||||
/**
|
||||
* Resets the parser with the given input stream. Any existing state is
|
||||
* erased.
|
||||
*/
|
||||
void Load(std::istream& in);
|
||||
|
||||
/**
|
||||
* Handles the next document by calling events on the {@code eventHandler}.
|
||||
*
|
||||
* @throw a ParserException on error.
|
||||
* @return false if there are no more documents
|
||||
*/
|
||||
bool HandleNextDocument(EventHandler& eventHandler);
|
||||
|
||||
void PrintTokens(std::ostream& out);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Reads any directives that are next in the queue, setting the internal
|
||||
* {@code m_pDirectives} state.
|
||||
*/
|
||||
void ParseDirectives();
|
||||
|
||||
void HandleDirective(const Token& token);
|
||||
|
||||
/**
|
||||
* Handles a "YAML" directive, which should be of the form 'major.minor' (like
|
||||
* a version number).
|
||||
*/
|
||||
void HandleYamlDirective(const Token& token);
|
||||
|
||||
/**
|
||||
* Handles a "TAG" directive, which should be of the form 'handle prefix',
|
||||
* where 'handle' is converted to 'prefix' in the file.
|
||||
*/
|
||||
void HandleTagDirective(const Token& token);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Scanner> m_pScanner;
|
||||
std::unique_ptr<Directives> m_pDirectives;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
namespace YAML {
|
||||
template <typename Seq>
|
||||
inline Emitter& EmitSeq(Emitter& emitter, const Seq& seq) {
|
||||
emitter << BeginSeq;
|
||||
for (typename Seq::const_iterator it = seq.begin(); it != seq.end(); ++it)
|
||||
emitter << *it;
|
||||
emitter << EndSeq;
|
||||
return emitter;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::vector<T>& v) {
|
||||
return EmitSeq(emitter, v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::list<T>& v) {
|
||||
return EmitSeq(emitter, v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::set<T>& v) {
|
||||
return EmitSeq(emitter, v);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::map<K, V>& m) {
|
||||
typedef typename std::map<K, V> map;
|
||||
emitter << BeginMap;
|
||||
for (typename map::const_iterator it = m.begin(); it != m.end(); ++it)
|
||||
emitter << Key << it->first << Value << it->second;
|
||||
emitter << EndMap;
|
||||
return emitter;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,103 @@
|
||||
#ifndef TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace YAML {
|
||||
template <typename>
|
||||
struct is_numeric {
|
||||
enum { value = false };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_numeric<char> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<unsigned char> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<int> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<unsigned int> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<long int> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<unsigned long int> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<short int> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<unsigned short int> {
|
||||
enum { value = true };
|
||||
};
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1310)
|
||||
template <>
|
||||
struct is_numeric<__int64> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<unsigned __int64> {
|
||||
enum { value = true };
|
||||
};
|
||||
#else
|
||||
template <>
|
||||
struct is_numeric<long long> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<unsigned long long> {
|
||||
enum { value = true };
|
||||
};
|
||||
#endif
|
||||
template <>
|
||||
struct is_numeric<float> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<double> {
|
||||
enum { value = true };
|
||||
};
|
||||
template <>
|
||||
struct is_numeric<long double> {
|
||||
enum { value = true };
|
||||
};
|
||||
|
||||
template <bool, class T = void>
|
||||
struct enable_if_c {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct enable_if_c<false, T> {};
|
||||
|
||||
template <class Cond, class T = void>
|
||||
struct enable_if : public enable_if_c<Cond::value, T> {};
|
||||
|
||||
template <bool, class T = void>
|
||||
struct disable_if_c {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct disable_if_c<true, T> {};
|
||||
|
||||
template <class Cond, class T = void>
|
||||
struct disable_if : public disable_if_c<Cond::value, T> {};
|
||||
}
|
||||
|
||||
#endif // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "yaml-cpp/parser.h"
|
||||
#include "yaml-cpp/emitter.h"
|
||||
#include "yaml-cpp/emitterstyle.h"
|
||||
#include "yaml-cpp/stlemitter.h"
|
||||
#include "yaml-cpp/exceptions.h"
|
||||
|
||||
#include "yaml-cpp/node/node.h"
|
||||
#include "yaml-cpp/node/impl.h"
|
||||
#include "yaml-cpp/node/convert.h"
|
||||
#include "yaml-cpp/node/iterator.h"
|
||||
#include "yaml-cpp/node/detail/impl.h"
|
||||
#include "yaml-cpp/node/parse.h"
|
||||
#include "yaml-cpp/node/emit.h"
|
||||
|
||||
#endif // YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
93
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/binary.cpp
Executable file
93
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/binary.cpp
Executable file
@@ -0,0 +1,93 @@
|
||||
#include "yaml-cpp/binary.h"
|
||||
|
||||
namespace YAML {
|
||||
static const char encoding[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
std::string EncodeBase64(const unsigned char *data, std::size_t size) {
|
||||
const char PAD = '=';
|
||||
|
||||
std::string ret;
|
||||
ret.resize(4 * size / 3 + 3);
|
||||
char *out = &ret[0];
|
||||
|
||||
std::size_t chunks = size / 3;
|
||||
std::size_t remainder = size % 3;
|
||||
|
||||
for (std::size_t i = 0; i < chunks; i++, data += 3) {
|
||||
*out++ = encoding[data[0] >> 2];
|
||||
*out++ = encoding[((data[0] & 0x3) << 4) | (data[1] >> 4)];
|
||||
*out++ = encoding[((data[1] & 0xf) << 2) | (data[2] >> 6)];
|
||||
*out++ = encoding[data[2] & 0x3f];
|
||||
}
|
||||
|
||||
switch (remainder) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
*out++ = encoding[data[0] >> 2];
|
||||
*out++ = encoding[((data[0] & 0x3) << 4)];
|
||||
*out++ = PAD;
|
||||
*out++ = PAD;
|
||||
break;
|
||||
case 2:
|
||||
*out++ = encoding[data[0] >> 2];
|
||||
*out++ = encoding[((data[0] & 0x3) << 4) | (data[1] >> 4)];
|
||||
*out++ = encoding[((data[1] & 0xf) << 2)];
|
||||
*out++ = PAD;
|
||||
break;
|
||||
}
|
||||
|
||||
ret.resize(out - &ret[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const unsigned char decoding[] = {
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255,
|
||||
255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
|
||||
255, 0, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33,
|
||||
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
|
||||
49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255,
|
||||
};
|
||||
|
||||
std::vector<unsigned char> DecodeBase64(const std::string &input) {
|
||||
typedef std::vector<unsigned char> ret_type;
|
||||
if (input.empty())
|
||||
return ret_type();
|
||||
|
||||
ret_type ret(3 * input.size() / 4 + 1);
|
||||
unsigned char *out = &ret[0];
|
||||
|
||||
unsigned value = 0;
|
||||
for (std::size_t i = 0; i < input.size(); i++) {
|
||||
unsigned char d = decoding[static_cast<unsigned>(input[i])];
|
||||
if (d == 255)
|
||||
return ret_type();
|
||||
|
||||
value = (value << 6) | d;
|
||||
if (i % 4 == 3) {
|
||||
*out++ = value >> 16;
|
||||
if (i > 0 && input[i - 1] != '=')
|
||||
*out++ = value >> 8;
|
||||
if (input[i] != '=')
|
||||
*out++ = value;
|
||||
}
|
||||
}
|
||||
|
||||
ret.resize(out - &ret[0]);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <stack>
|
||||
#include <cassert>
|
||||
|
||||
namespace YAML {
|
||||
struct CollectionType {
|
||||
enum value { NoCollection, BlockMap, BlockSeq, FlowMap, FlowSeq, CompactMap };
|
||||
};
|
||||
|
||||
class CollectionStack {
|
||||
public:
|
||||
CollectionType::value GetCurCollectionType() const {
|
||||
if (collectionStack.empty())
|
||||
return CollectionType::NoCollection;
|
||||
return collectionStack.top();
|
||||
}
|
||||
|
||||
void PushCollectionType(CollectionType::value type) {
|
||||
collectionStack.push(type);
|
||||
}
|
||||
void PopCollectionType(CollectionType::value type) {
|
||||
assert(type == GetCurCollectionType());
|
||||
collectionStack.pop();
|
||||
}
|
||||
|
||||
private:
|
||||
std::stack<CollectionType::value> collectionStack;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "graphbuilderadapter.h"
|
||||
|
||||
#include "yaml-cpp/parser.h" // IWYU pragma: keep
|
||||
|
||||
namespace YAML {
|
||||
class GraphBuilderInterface;
|
||||
|
||||
void* BuildGraphOfNextDocument(Parser& parser,
|
||||
GraphBuilderInterface& graphBuilder) {
|
||||
GraphBuilderAdapter eventHandler(graphBuilder);
|
||||
if (parser.HandleNextDocument(eventHandler)) {
|
||||
return eventHandler.RootNode();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "graphbuilderadapter.h"
|
||||
#include "yaml-cpp/contrib/graphbuilder.h"
|
||||
|
||||
namespace YAML {
|
||||
struct Mark;
|
||||
|
||||
int GraphBuilderAdapter::ContainerFrame::sequenceMarker;
|
||||
|
||||
void GraphBuilderAdapter::OnNull(const Mark &mark, anchor_t anchor) {
|
||||
void *pParent = GetCurrentParent();
|
||||
void *pNode = m_builder.NewNull(mark, pParent);
|
||||
RegisterAnchor(anchor, pNode);
|
||||
|
||||
DispositionNode(pNode);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnAlias(const Mark &mark, anchor_t anchor) {
|
||||
void *pReffedNode = m_anchors.Get(anchor);
|
||||
DispositionNode(m_builder.AnchorReference(mark, pReffedNode));
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnScalar(const Mark &mark, const std::string &tag,
|
||||
anchor_t anchor, const std::string &value) {
|
||||
void *pParent = GetCurrentParent();
|
||||
void *pNode = m_builder.NewScalar(mark, tag, pParent, value);
|
||||
RegisterAnchor(anchor, pNode);
|
||||
|
||||
DispositionNode(pNode);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnSequenceStart(const Mark &mark,
|
||||
const std::string &tag,
|
||||
anchor_t anchor,
|
||||
EmitterStyle::value /* style */) {
|
||||
void *pNode = m_builder.NewSequence(mark, tag, GetCurrentParent());
|
||||
m_containers.push(ContainerFrame(pNode));
|
||||
RegisterAnchor(anchor, pNode);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnSequenceEnd() {
|
||||
void *pSequence = m_containers.top().pContainer;
|
||||
m_containers.pop();
|
||||
|
||||
DispositionNode(pSequence);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnMapStart(const Mark &mark, const std::string &tag,
|
||||
anchor_t anchor,
|
||||
EmitterStyle::value /* style */) {
|
||||
void *pNode = m_builder.NewMap(mark, tag, GetCurrentParent());
|
||||
m_containers.push(ContainerFrame(pNode, m_pKeyNode));
|
||||
m_pKeyNode = NULL;
|
||||
RegisterAnchor(anchor, pNode);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnMapEnd() {
|
||||
void *pMap = m_containers.top().pContainer;
|
||||
m_pKeyNode = m_containers.top().pPrevKeyNode;
|
||||
m_containers.pop();
|
||||
DispositionNode(pMap);
|
||||
}
|
||||
|
||||
void *GraphBuilderAdapter::GetCurrentParent() const {
|
||||
if (m_containers.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
return m_containers.top().pContainer;
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::RegisterAnchor(anchor_t anchor, void *pNode) {
|
||||
if (anchor) {
|
||||
m_anchors.Register(anchor, pNode);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::DispositionNode(void *pNode) {
|
||||
if (m_containers.empty()) {
|
||||
m_pRootNode = pNode;
|
||||
return;
|
||||
}
|
||||
|
||||
void *pContainer = m_containers.top().pContainer;
|
||||
if (m_containers.top().isMap()) {
|
||||
if (m_pKeyNode) {
|
||||
m_builder.AssignInMap(pContainer, m_pKeyNode, pNode);
|
||||
m_pKeyNode = NULL;
|
||||
} else {
|
||||
m_pKeyNode = pNode;
|
||||
}
|
||||
} else {
|
||||
m_builder.AppendToSequence(pContainer, pNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
#include "yaml-cpp/anchor.h"
|
||||
#include "yaml-cpp/contrib/anchordict.h"
|
||||
#include "yaml-cpp/contrib/graphbuilder.h"
|
||||
#include "yaml-cpp/emitterstyle.h"
|
||||
#include "yaml-cpp/eventhandler.h"
|
||||
|
||||
namespace YAML {
|
||||
class GraphBuilderInterface;
|
||||
struct Mark;
|
||||
} // namespace YAML
|
||||
|
||||
namespace YAML {
|
||||
class GraphBuilderAdapter : public EventHandler {
|
||||
public:
|
||||
GraphBuilderAdapter(GraphBuilderInterface& builder)
|
||||
: m_builder(builder), m_pRootNode(NULL), m_pKeyNode(NULL) {}
|
||||
|
||||
virtual void OnDocumentStart(const Mark& mark) { (void)mark; }
|
||||
virtual void OnDocumentEnd() {}
|
||||
|
||||
virtual void OnNull(const Mark& mark, anchor_t anchor);
|
||||
virtual void OnAlias(const Mark& mark, anchor_t anchor);
|
||||
virtual void OnScalar(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, const std::string& value);
|
||||
|
||||
virtual void OnSequenceStart(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, EmitterStyle::value style);
|
||||
virtual void OnSequenceEnd();
|
||||
|
||||
virtual void OnMapStart(const Mark& mark, const std::string& tag,
|
||||
anchor_t anchor, EmitterStyle::value style);
|
||||
virtual void OnMapEnd();
|
||||
|
||||
void* RootNode() const { return m_pRootNode; }
|
||||
|
||||
private:
|
||||
struct ContainerFrame {
|
||||
ContainerFrame(void* pSequence)
|
||||
: pContainer(pSequence), pPrevKeyNode(&sequenceMarker) {}
|
||||
ContainerFrame(void* pMap, void* pPrevKeyNode)
|
||||
: pContainer(pMap), pPrevKeyNode(pPrevKeyNode) {}
|
||||
|
||||
void* pContainer;
|
||||
void* pPrevKeyNode;
|
||||
|
||||
bool isMap() const { return pPrevKeyNode != &sequenceMarker; }
|
||||
|
||||
private:
|
||||
static int sequenceMarker;
|
||||
};
|
||||
typedef std::stack<ContainerFrame> ContainerStack;
|
||||
typedef AnchorDict<void*> AnchorMap;
|
||||
|
||||
GraphBuilderInterface& m_builder;
|
||||
ContainerStack m_containers;
|
||||
AnchorMap m_anchors;
|
||||
void* m_pRootNode;
|
||||
void* m_pKeyNode;
|
||||
|
||||
void* GetCurrentParent() const;
|
||||
void RegisterAnchor(anchor_t anchor, void* pNode);
|
||||
void DispositionNode(void* pNode);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
75
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/convert.cpp
Executable file
75
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/convert.cpp
Executable file
@@ -0,0 +1,75 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "yaml-cpp/node/convert.h"
|
||||
|
||||
namespace {
|
||||
// we're not gonna mess with the mess that is all the isupper/etc. functions
|
||||
bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; }
|
||||
bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; }
|
||||
char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; }
|
||||
|
||||
std::string tolower(const std::string& str) {
|
||||
std::string s(str);
|
||||
std::transform(s.begin(), s.end(), s.begin(), ToLower);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool IsEntirely(const std::string& str, T func) {
|
||||
for (std::size_t i = 0; i < str.size(); i++)
|
||||
if (!func(str[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// IsFlexibleCase
|
||||
// . Returns true if 'str' is:
|
||||
// . UPPERCASE
|
||||
// . lowercase
|
||||
// . Capitalized
|
||||
bool IsFlexibleCase(const std::string& str) {
|
||||
if (str.empty())
|
||||
return true;
|
||||
|
||||
if (IsEntirely(str, IsLower))
|
||||
return true;
|
||||
|
||||
bool firstcaps = IsUpper(str[0]);
|
||||
std::string rest = str.substr(1);
|
||||
return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper));
|
||||
}
|
||||
}
|
||||
|
||||
namespace YAML {
|
||||
bool convert<bool>::decode(const Node& node, bool& rhs) {
|
||||
if (!node.IsScalar())
|
||||
return false;
|
||||
|
||||
// we can't use iostream bool extraction operators as they don't
|
||||
// recognize all possible values in the table below (taken from
|
||||
// http://yaml.org/type/bool.html)
|
||||
static const struct {
|
||||
std::string truename, falsename;
|
||||
} names[] = {
|
||||
{"y", "n"}, {"yes", "no"}, {"true", "false"}, {"on", "off"},
|
||||
};
|
||||
|
||||
if (!IsFlexibleCase(node.Scalar()))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
|
||||
if (names[i].truename == tolower(node.Scalar())) {
|
||||
rhs = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (names[i].falsename == tolower(node.Scalar())) {
|
||||
rhs = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "directives.h"
|
||||
|
||||
namespace YAML {
|
||||
Directives::Directives() {
|
||||
// version
|
||||
version.isDefault = true;
|
||||
version.major = 1;
|
||||
version.minor = 2;
|
||||
}
|
||||
|
||||
const std::string Directives::TranslateTagHandle(
|
||||
const std::string& handle) const {
|
||||
std::map<std::string, std::string>::const_iterator it = tags.find(handle);
|
||||
if (it == tags.end()) {
|
||||
if (handle == "!!")
|
||||
return "tag:yaml.org,2002:";
|
||||
return handle;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
29
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/directives.h
Executable file
29
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/directives.h
Executable file
@@ -0,0 +1,29 @@
|
||||
#ifndef DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace YAML {
|
||||
struct Version {
|
||||
bool isDefault;
|
||||
int major, minor;
|
||||
};
|
||||
|
||||
struct Directives {
|
||||
Directives();
|
||||
|
||||
const std::string TranslateTagHandle(const std::string& handle) const;
|
||||
|
||||
Version version;
|
||||
std::map<std::string, std::string> tags;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
25
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emit.cpp
Executable file
25
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emit.cpp
Executable file
@@ -0,0 +1,25 @@
|
||||
#include "yaml-cpp/node/emit.h"
|
||||
#include "yaml-cpp/emitfromevents.h"
|
||||
#include "yaml-cpp/emitter.h"
|
||||
#include "nodeevents.h"
|
||||
|
||||
namespace YAML {
|
||||
Emitter& operator<<(Emitter& out, const Node& node) {
|
||||
EmitFromEvents emitFromEvents(out);
|
||||
NodeEvents events(node);
|
||||
events.Emit(emitFromEvents);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const Node& node) {
|
||||
Emitter emitter(out);
|
||||
emitter << node;
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string Dump(const Node& node) {
|
||||
Emitter emitter;
|
||||
emitter << node;
|
||||
return emitter.c_str();
|
||||
}
|
||||
} // namespace YAML
|
||||
@@ -0,0 +1,119 @@
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
#include "yaml-cpp/emitfromevents.h"
|
||||
#include "yaml-cpp/emitter.h"
|
||||
#include "yaml-cpp/emittermanip.h"
|
||||
#include "yaml-cpp/null.h"
|
||||
|
||||
namespace YAML {
|
||||
struct Mark;
|
||||
} // namespace YAML
|
||||
|
||||
namespace {
|
||||
std::string ToString(YAML::anchor_t anchor) {
|
||||
std::stringstream stream;
|
||||
stream << anchor;
|
||||
return stream.str();
|
||||
}
|
||||
}
|
||||
|
||||
namespace YAML {
|
||||
EmitFromEvents::EmitFromEvents(Emitter& emitter) : m_emitter(emitter) {}
|
||||
|
||||
void EmitFromEvents::OnDocumentStart(const Mark&) {}
|
||||
|
||||
void EmitFromEvents::OnDocumentEnd() {}
|
||||
|
||||
void EmitFromEvents::OnNull(const Mark&, anchor_t anchor) {
|
||||
BeginNode();
|
||||
EmitProps("", anchor);
|
||||
m_emitter << Null;
|
||||
}
|
||||
|
||||
void EmitFromEvents::OnAlias(const Mark&, anchor_t anchor) {
|
||||
BeginNode();
|
||||
m_emitter << Alias(ToString(anchor));
|
||||
}
|
||||
|
||||
void EmitFromEvents::OnScalar(const Mark&, const std::string& tag,
|
||||
anchor_t anchor, const std::string& value) {
|
||||
BeginNode();
|
||||
EmitProps(tag, anchor);
|
||||
m_emitter << value;
|
||||
}
|
||||
|
||||
void EmitFromEvents::OnSequenceStart(const Mark&, const std::string& tag,
|
||||
anchor_t anchor,
|
||||
EmitterStyle::value style) {
|
||||
BeginNode();
|
||||
EmitProps(tag, anchor);
|
||||
switch (style) {
|
||||
case EmitterStyle::Block:
|
||||
m_emitter << Block;
|
||||
break;
|
||||
case EmitterStyle::Flow:
|
||||
m_emitter << Flow;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_emitter << BeginSeq;
|
||||
m_stateStack.push(State::WaitingForSequenceEntry);
|
||||
}
|
||||
|
||||
void EmitFromEvents::OnSequenceEnd() {
|
||||
m_emitter << EndSeq;
|
||||
assert(m_stateStack.top() == State::WaitingForSequenceEntry);
|
||||
m_stateStack.pop();
|
||||
}
|
||||
|
||||
void EmitFromEvents::OnMapStart(const Mark&, const std::string& tag,
|
||||
anchor_t anchor, EmitterStyle::value style) {
|
||||
BeginNode();
|
||||
EmitProps(tag, anchor);
|
||||
switch (style) {
|
||||
case EmitterStyle::Block:
|
||||
m_emitter << Block;
|
||||
break;
|
||||
case EmitterStyle::Flow:
|
||||
m_emitter << Flow;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_emitter << BeginMap;
|
||||
m_stateStack.push(State::WaitingForKey);
|
||||
}
|
||||
|
||||
void EmitFromEvents::OnMapEnd() {
|
||||
m_emitter << EndMap;
|
||||
assert(m_stateStack.top() == State::WaitingForKey);
|
||||
m_stateStack.pop();
|
||||
}
|
||||
|
||||
void EmitFromEvents::BeginNode() {
|
||||
if (m_stateStack.empty())
|
||||
return;
|
||||
|
||||
switch (m_stateStack.top()) {
|
||||
case State::WaitingForKey:
|
||||
m_emitter << Key;
|
||||
m_stateStack.top() = State::WaitingForValue;
|
||||
break;
|
||||
case State::WaitingForValue:
|
||||
m_emitter << Value;
|
||||
m_stateStack.top() = State::WaitingForKey;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EmitFromEvents::EmitProps(const std::string& tag, anchor_t anchor) {
|
||||
if (!tag.empty() && tag != "?" && tag != "!")
|
||||
m_emitter << VerbatimTag(tag);
|
||||
if (anchor)
|
||||
m_emitter << Anchor(ToString(anchor));
|
||||
}
|
||||
}
|
||||
911
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emitter.cpp
Executable file
911
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emitter.cpp
Executable file
@@ -0,0 +1,911 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "emitterutils.h"
|
||||
#include "indentation.h" // IWYU pragma: keep
|
||||
#include "yaml-cpp/emitter.h"
|
||||
#include "yaml-cpp/emitterdef.h"
|
||||
#include "yaml-cpp/emittermanip.h"
|
||||
#include "yaml-cpp/exceptions.h" // IWYU pragma: keep
|
||||
|
||||
namespace YAML {
|
||||
class Binary;
|
||||
struct _Null;
|
||||
|
||||
Emitter::Emitter() : m_pState(new EmitterState) {}
|
||||
|
||||
Emitter::Emitter(std::ostream& stream)
|
||||
: m_pState(new EmitterState), m_stream(stream) {}
|
||||
|
||||
Emitter::~Emitter() {}
|
||||
|
||||
const char* Emitter::c_str() const { return m_stream.str(); }
|
||||
|
||||
std::size_t Emitter::size() const { return m_stream.pos(); }
|
||||
|
||||
// state checking
|
||||
bool Emitter::good() const { return m_pState->good(); }
|
||||
|
||||
const std::string Emitter::GetLastError() const {
|
||||
return m_pState->GetLastError();
|
||||
}
|
||||
|
||||
// global setters
|
||||
bool Emitter::SetOutputCharset(EMITTER_MANIP value) {
|
||||
return m_pState->SetOutputCharset(value, FmtScope::Global);
|
||||
}
|
||||
|
||||
bool Emitter::SetStringFormat(EMITTER_MANIP value) {
|
||||
return m_pState->SetStringFormat(value, FmtScope::Global);
|
||||
}
|
||||
|
||||
bool Emitter::SetBoolFormat(EMITTER_MANIP value) {
|
||||
bool ok = false;
|
||||
if (m_pState->SetBoolFormat(value, FmtScope::Global))
|
||||
ok = true;
|
||||
if (m_pState->SetBoolCaseFormat(value, FmtScope::Global))
|
||||
ok = true;
|
||||
if (m_pState->SetBoolLengthFormat(value, FmtScope::Global))
|
||||
ok = true;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Emitter::SetIntBase(EMITTER_MANIP value) {
|
||||
return m_pState->SetIntFormat(value, FmtScope::Global);
|
||||
}
|
||||
|
||||
bool Emitter::SetSeqFormat(EMITTER_MANIP value) {
|
||||
return m_pState->SetFlowType(GroupType::Seq, value, FmtScope::Global);
|
||||
}
|
||||
|
||||
bool Emitter::SetMapFormat(EMITTER_MANIP value) {
|
||||
bool ok = false;
|
||||
if (m_pState->SetFlowType(GroupType::Map, value, FmtScope::Global))
|
||||
ok = true;
|
||||
if (m_pState->SetMapKeyFormat(value, FmtScope::Global))
|
||||
ok = true;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Emitter::SetIndent(std::size_t n) {
|
||||
return m_pState->SetIndent(n, FmtScope::Global);
|
||||
}
|
||||
|
||||
bool Emitter::SetPreCommentIndent(std::size_t n) {
|
||||
return m_pState->SetPreCommentIndent(n, FmtScope::Global);
|
||||
}
|
||||
|
||||
bool Emitter::SetPostCommentIndent(std::size_t n) {
|
||||
return m_pState->SetPostCommentIndent(n, FmtScope::Global);
|
||||
}
|
||||
|
||||
bool Emitter::SetFloatPrecision(std::size_t n) {
|
||||
return m_pState->SetFloatPrecision(n, FmtScope::Global);
|
||||
}
|
||||
|
||||
bool Emitter::SetDoublePrecision(std::size_t n) {
|
||||
return m_pState->SetDoublePrecision(n, FmtScope::Global);
|
||||
}
|
||||
|
||||
// SetLocalValue
|
||||
// . Either start/end a group, or set a modifier locally
|
||||
Emitter& Emitter::SetLocalValue(EMITTER_MANIP value) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
switch (value) {
|
||||
case BeginDoc:
|
||||
EmitBeginDoc();
|
||||
break;
|
||||
case EndDoc:
|
||||
EmitEndDoc();
|
||||
break;
|
||||
case BeginSeq:
|
||||
EmitBeginSeq();
|
||||
break;
|
||||
case EndSeq:
|
||||
EmitEndSeq();
|
||||
break;
|
||||
case BeginMap:
|
||||
EmitBeginMap();
|
||||
break;
|
||||
case EndMap:
|
||||
EmitEndMap();
|
||||
break;
|
||||
case Key:
|
||||
case Value:
|
||||
// deprecated (these can be deduced by the parity of nodes in a map)
|
||||
break;
|
||||
case TagByKind:
|
||||
EmitKindTag();
|
||||
break;
|
||||
case Newline:
|
||||
EmitNewline();
|
||||
break;
|
||||
default:
|
||||
m_pState->SetLocalValue(value);
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Emitter& Emitter::SetLocalIndent(const _Indent& indent) {
|
||||
m_pState->SetIndent(indent.value, FmtScope::Local);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Emitter& Emitter::SetLocalPrecision(const _Precision& precision) {
|
||||
if (precision.floatPrecision >= 0)
|
||||
m_pState->SetFloatPrecision(precision.floatPrecision, FmtScope::Local);
|
||||
if (precision.doublePrecision >= 0)
|
||||
m_pState->SetDoublePrecision(precision.doublePrecision, FmtScope::Local);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// EmitBeginDoc
|
||||
void Emitter::EmitBeginDoc() {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
if (m_pState->CurGroupType() != GroupType::NoType) {
|
||||
m_pState->SetError("Unexpected begin document");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pState->HasAnchor() || m_pState->HasTag()) {
|
||||
m_pState->SetError("Unexpected begin document");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_stream.col() > 0)
|
||||
m_stream << "\n";
|
||||
m_stream << "---\n";
|
||||
|
||||
m_pState->StartedDoc();
|
||||
}
|
||||
|
||||
// EmitEndDoc
|
||||
void Emitter::EmitEndDoc() {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
if (m_pState->CurGroupType() != GroupType::NoType) {
|
||||
m_pState->SetError("Unexpected begin document");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pState->HasAnchor() || m_pState->HasTag()) {
|
||||
m_pState->SetError("Unexpected begin document");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_stream.col() > 0)
|
||||
m_stream << "\n";
|
||||
m_stream << "...\n";
|
||||
}
|
||||
|
||||
// EmitBeginSeq
|
||||
void Emitter::EmitBeginSeq() {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
PrepareNode(m_pState->NextGroupType(GroupType::Seq));
|
||||
|
||||
m_pState->StartedGroup(GroupType::Seq);
|
||||
}
|
||||
|
||||
// EmitEndSeq
|
||||
void Emitter::EmitEndSeq() {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
m_pState->ForceFlow();
|
||||
|
||||
if (m_pState->CurGroupFlowType() == FlowType::Flow) {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(m_pState->CurIndent());
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
m_stream << "[";
|
||||
m_stream << "]";
|
||||
}
|
||||
|
||||
m_pState->EndedGroup(GroupType::Seq);
|
||||
}
|
||||
|
||||
// EmitBeginMap
|
||||
void Emitter::EmitBeginMap() {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
PrepareNode(m_pState->NextGroupType(GroupType::Map));
|
||||
|
||||
m_pState->StartedGroup(GroupType::Map);
|
||||
}
|
||||
|
||||
// EmitEndMap
|
||||
void Emitter::EmitEndMap() {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
m_pState->ForceFlow();
|
||||
|
||||
if (m_pState->CurGroupFlowType() == FlowType::Flow) {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(m_pState->CurIndent());
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
m_stream << "{";
|
||||
m_stream << "}";
|
||||
}
|
||||
|
||||
m_pState->EndedGroup(GroupType::Map);
|
||||
}
|
||||
|
||||
// EmitNewline
|
||||
void Emitter::EmitNewline() {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
PrepareNode(EmitterNodeType::NoType);
|
||||
m_stream << "\n";
|
||||
m_pState->SetNonContent();
|
||||
}
|
||||
|
||||
bool Emitter::CanEmitNewline() const { return true; }
|
||||
|
||||
// Put the stream in a state so we can simply write the next node
|
||||
// E.g., if we're in a sequence, write the "- "
|
||||
void Emitter::PrepareNode(EmitterNodeType::value child) {
|
||||
switch (m_pState->CurGroupNodeType()) {
|
||||
case EmitterNodeType::NoType:
|
||||
PrepareTopNode(child);
|
||||
break;
|
||||
case EmitterNodeType::FlowSeq:
|
||||
FlowSeqPrepareNode(child);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
BlockSeqPrepareNode(child);
|
||||
break;
|
||||
case EmitterNodeType::FlowMap:
|
||||
FlowMapPrepareNode(child);
|
||||
break;
|
||||
case EmitterNodeType::BlockMap:
|
||||
BlockMapPrepareNode(child);
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::PrepareTopNode(EmitterNodeType::value child) {
|
||||
if (child == EmitterNodeType::NoType)
|
||||
return;
|
||||
|
||||
if (m_pState->CurGroupChildCount() > 0 && m_stream.col() > 0) {
|
||||
if (child != EmitterNodeType::NoType)
|
||||
EmitBeginDoc();
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
// TODO: if we were writing null, and
|
||||
// we wanted it blank, we wouldn't want a space
|
||||
SpaceOrIndentTo(m_pState->HasBegunContent(), 0);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
if (m_pState->HasBegunNode())
|
||||
m_stream << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::FlowSeqPrepareNode(EmitterNodeType::value child) {
|
||||
const std::size_t lastIndent = m_pState->LastIndent();
|
||||
|
||||
if (!m_pState->HasBegunNode()) {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(lastIndent);
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
m_stream << "[";
|
||||
else
|
||||
m_stream << ",";
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
SpaceOrIndentTo(
|
||||
m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
|
||||
lastIndent);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::BlockSeqPrepareNode(EmitterNodeType::value child) {
|
||||
const std::size_t curIndent = m_pState->CurIndent();
|
||||
const std::size_t nextIndent = curIndent + m_pState->CurGroupIndent();
|
||||
|
||||
if (child == EmitterNodeType::NoType)
|
||||
return;
|
||||
|
||||
if (!m_pState->HasBegunContent()) {
|
||||
if (m_pState->CurGroupChildCount() > 0 || m_stream.comment()) {
|
||||
m_stream << "\n";
|
||||
}
|
||||
m_stream << IndentTo(curIndent);
|
||||
m_stream << "-";
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
SpaceOrIndentTo(m_pState->HasBegunContent(), nextIndent);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
m_stream << "\n";
|
||||
break;
|
||||
case EmitterNodeType::BlockMap:
|
||||
if (m_pState->HasBegunContent() || m_stream.comment())
|
||||
m_stream << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::FlowMapPrepareNode(EmitterNodeType::value child) {
|
||||
if (m_pState->CurGroupChildCount() % 2 == 0) {
|
||||
if (m_pState->GetMapKeyFormat() == LongKey)
|
||||
m_pState->SetLongKey();
|
||||
|
||||
if (m_pState->CurGroupLongKey())
|
||||
FlowMapPrepareLongKey(child);
|
||||
else
|
||||
FlowMapPrepareSimpleKey(child);
|
||||
} else {
|
||||
if (m_pState->CurGroupLongKey())
|
||||
FlowMapPrepareLongKeyValue(child);
|
||||
else
|
||||
FlowMapPrepareSimpleKeyValue(child);
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::FlowMapPrepareLongKey(EmitterNodeType::value child) {
|
||||
const std::size_t lastIndent = m_pState->LastIndent();
|
||||
|
||||
if (!m_pState->HasBegunNode()) {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(lastIndent);
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
m_stream << "{ ?";
|
||||
else
|
||||
m_stream << ", ?";
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
SpaceOrIndentTo(
|
||||
m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
|
||||
lastIndent);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::FlowMapPrepareLongKeyValue(EmitterNodeType::value child) {
|
||||
const std::size_t lastIndent = m_pState->LastIndent();
|
||||
|
||||
if (!m_pState->HasBegunNode()) {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(lastIndent);
|
||||
m_stream << ":";
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
SpaceOrIndentTo(
|
||||
m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
|
||||
lastIndent);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::FlowMapPrepareSimpleKey(EmitterNodeType::value child) {
|
||||
const std::size_t lastIndent = m_pState->LastIndent();
|
||||
|
||||
if (!m_pState->HasBegunNode()) {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(lastIndent);
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
m_stream << "{";
|
||||
else
|
||||
m_stream << ",";
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
SpaceOrIndentTo(
|
||||
m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
|
||||
lastIndent);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::FlowMapPrepareSimpleKeyValue(EmitterNodeType::value child) {
|
||||
const std::size_t lastIndent = m_pState->LastIndent();
|
||||
|
||||
if (!m_pState->HasBegunNode()) {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(lastIndent);
|
||||
m_stream << ":";
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
SpaceOrIndentTo(
|
||||
m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0,
|
||||
lastIndent);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::BlockMapPrepareNode(EmitterNodeType::value child) {
|
||||
if (m_pState->CurGroupChildCount() % 2 == 0) {
|
||||
if (m_pState->GetMapKeyFormat() == LongKey)
|
||||
m_pState->SetLongKey();
|
||||
if (child == EmitterNodeType::BlockSeq ||
|
||||
child == EmitterNodeType::BlockMap)
|
||||
m_pState->SetLongKey();
|
||||
|
||||
if (m_pState->CurGroupLongKey())
|
||||
BlockMapPrepareLongKey(child);
|
||||
else
|
||||
BlockMapPrepareSimpleKey(child);
|
||||
} else {
|
||||
if (m_pState->CurGroupLongKey())
|
||||
BlockMapPrepareLongKeyValue(child);
|
||||
else
|
||||
BlockMapPrepareSimpleKeyValue(child);
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::BlockMapPrepareLongKey(EmitterNodeType::value child) {
|
||||
const std::size_t curIndent = m_pState->CurIndent();
|
||||
const std::size_t childCount = m_pState->CurGroupChildCount();
|
||||
|
||||
if (child == EmitterNodeType::NoType)
|
||||
return;
|
||||
|
||||
if (!m_pState->HasBegunContent()) {
|
||||
if (childCount > 0) {
|
||||
m_stream << "\n";
|
||||
}
|
||||
if (m_stream.comment()) {
|
||||
m_stream << "\n";
|
||||
}
|
||||
m_stream << IndentTo(curIndent);
|
||||
m_stream << "?";
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
SpaceOrIndentTo(true, curIndent + 1);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::BlockMapPrepareLongKeyValue(EmitterNodeType::value child) {
|
||||
const std::size_t curIndent = m_pState->CurIndent();
|
||||
|
||||
if (child == EmitterNodeType::NoType)
|
||||
return;
|
||||
|
||||
if (!m_pState->HasBegunContent()) {
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(curIndent);
|
||||
m_stream << ":";
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
SpaceOrIndentTo(true, curIndent + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::BlockMapPrepareSimpleKey(EmitterNodeType::value child) {
|
||||
const std::size_t curIndent = m_pState->CurIndent();
|
||||
const std::size_t childCount = m_pState->CurGroupChildCount();
|
||||
|
||||
if (child == EmitterNodeType::NoType)
|
||||
return;
|
||||
|
||||
if (!m_pState->HasBegunNode()) {
|
||||
if (childCount > 0) {
|
||||
m_stream << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
SpaceOrIndentTo(m_pState->HasBegunContent(), curIndent);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::BlockMapPrepareSimpleKeyValue(EmitterNodeType::value child) {
|
||||
const std::size_t curIndent = m_pState->CurIndent();
|
||||
const std::size_t nextIndent = curIndent + m_pState->CurGroupIndent();
|
||||
|
||||
if (!m_pState->HasBegunNode()) {
|
||||
m_stream << ":";
|
||||
}
|
||||
|
||||
switch (child) {
|
||||
case EmitterNodeType::NoType:
|
||||
break;
|
||||
case EmitterNodeType::Property:
|
||||
case EmitterNodeType::Scalar:
|
||||
case EmitterNodeType::FlowSeq:
|
||||
case EmitterNodeType::FlowMap:
|
||||
SpaceOrIndentTo(true, nextIndent);
|
||||
break;
|
||||
case EmitterNodeType::BlockSeq:
|
||||
case EmitterNodeType::BlockMap:
|
||||
m_stream << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SpaceOrIndentTo
|
||||
// . Prepares for some more content by proper spacing
|
||||
void Emitter::SpaceOrIndentTo(bool requireSpace, std::size_t indent) {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
if (m_stream.col() > 0 && requireSpace)
|
||||
m_stream << " ";
|
||||
m_stream << IndentTo(indent);
|
||||
}
|
||||
|
||||
void Emitter::PrepareIntegralStream(std::stringstream& stream) const {
|
||||
|
||||
switch (m_pState->GetIntFormat()) {
|
||||
case Dec:
|
||||
stream << std::dec;
|
||||
break;
|
||||
case Hex:
|
||||
stream << "0x";
|
||||
stream << std::hex;
|
||||
break;
|
||||
case Oct:
|
||||
stream << "0";
|
||||
stream << std::oct;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Emitter::StartedScalar() { m_pState->StartedScalar(); }
|
||||
|
||||
// *******************************************************************************************
|
||||
// overloads of Write
|
||||
|
||||
Emitter& Emitter::Write(const std::string& str) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
const bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii;
|
||||
const StringFormat::value strFormat =
|
||||
Utils::ComputeStringFormat(str, m_pState->GetStringFormat(),
|
||||
m_pState->CurGroupFlowType(), escapeNonAscii);
|
||||
|
||||
if (strFormat == StringFormat::Literal)
|
||||
m_pState->SetMapKeyFormat(YAML::LongKey, FmtScope::Local);
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
switch (strFormat) {
|
||||
case StringFormat::Plain:
|
||||
m_stream << str;
|
||||
break;
|
||||
case StringFormat::SingleQuoted:
|
||||
Utils::WriteSingleQuotedString(m_stream, str);
|
||||
break;
|
||||
case StringFormat::DoubleQuoted:
|
||||
Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii);
|
||||
break;
|
||||
case StringFormat::Literal:
|
||||
Utils::WriteLiteralString(m_stream, str,
|
||||
m_pState->CurIndent() + m_pState->GetIndent());
|
||||
break;
|
||||
}
|
||||
|
||||
StartedScalar();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t Emitter::GetFloatPrecision() const {
|
||||
return m_pState->GetFloatPrecision();
|
||||
}
|
||||
|
||||
std::size_t Emitter::GetDoublePrecision() const {
|
||||
return m_pState->GetDoublePrecision();
|
||||
}
|
||||
|
||||
const char* Emitter::ComputeFullBoolName(bool b) const {
|
||||
const EMITTER_MANIP mainFmt = (m_pState->GetBoolLengthFormat() == ShortBool
|
||||
? YesNoBool
|
||||
: m_pState->GetBoolFormat());
|
||||
const EMITTER_MANIP caseFmt = m_pState->GetBoolCaseFormat();
|
||||
switch (mainFmt) {
|
||||
case YesNoBool:
|
||||
switch (caseFmt) {
|
||||
case UpperCase:
|
||||
return b ? "YES" : "NO";
|
||||
case CamelCase:
|
||||
return b ? "Yes" : "No";
|
||||
case LowerCase:
|
||||
return b ? "yes" : "no";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OnOffBool:
|
||||
switch (caseFmt) {
|
||||
case UpperCase:
|
||||
return b ? "ON" : "OFF";
|
||||
case CamelCase:
|
||||
return b ? "On" : "Off";
|
||||
case LowerCase:
|
||||
return b ? "on" : "off";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TrueFalseBool:
|
||||
switch (caseFmt) {
|
||||
case UpperCase:
|
||||
return b ? "TRUE" : "FALSE";
|
||||
case CamelCase:
|
||||
return b ? "True" : "False";
|
||||
case LowerCase:
|
||||
return b ? "true" : "false";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return b ? "y" : "n"; // should never get here, but it can't hurt to give
|
||||
// these answers
|
||||
}
|
||||
|
||||
Emitter& Emitter::Write(bool b) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
const char* name = ComputeFullBoolName(b);
|
||||
if (m_pState->GetBoolLengthFormat() == ShortBool)
|
||||
m_stream << name[0];
|
||||
else
|
||||
m_stream << name;
|
||||
|
||||
StartedScalar();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Emitter& Emitter::Write(char ch) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
Utils::WriteChar(m_stream, ch);
|
||||
StartedScalar();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Emitter& Emitter::Write(const _Alias& alias) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
if (m_pState->HasAnchor() || m_pState->HasTag()) {
|
||||
m_pState->SetError(ErrorMsg::INVALID_ALIAS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
if (!Utils::WriteAlias(m_stream, alias.content)) {
|
||||
m_pState->SetError(ErrorMsg::INVALID_ALIAS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
StartedScalar();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Emitter& Emitter::Write(const _Anchor& anchor) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
if (m_pState->HasAnchor()) {
|
||||
m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrepareNode(EmitterNodeType::Property);
|
||||
|
||||
if (!Utils::WriteAnchor(m_stream, anchor.content)) {
|
||||
m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
|
||||
return *this;
|
||||
}
|
||||
|
||||
m_pState->SetAnchor();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Emitter& Emitter::Write(const _Tag& tag) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
if (m_pState->HasTag()) {
|
||||
m_pState->SetError(ErrorMsg::INVALID_TAG);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PrepareNode(EmitterNodeType::Property);
|
||||
|
||||
bool success = false;
|
||||
if (tag.type == _Tag::Type::Verbatim)
|
||||
success = Utils::WriteTag(m_stream, tag.content, true);
|
||||
else if (tag.type == _Tag::Type::PrimaryHandle)
|
||||
success = Utils::WriteTag(m_stream, tag.content, false);
|
||||
else
|
||||
success = Utils::WriteTagWithPrefix(m_stream, tag.prefix, tag.content);
|
||||
|
||||
if (!success) {
|
||||
m_pState->SetError(ErrorMsg::INVALID_TAG);
|
||||
return *this;
|
||||
}
|
||||
|
||||
m_pState->SetTag();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Emitter::EmitKindTag() { Write(LocalTag("")); }
|
||||
|
||||
Emitter& Emitter::Write(const _Comment& comment) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
PrepareNode(EmitterNodeType::NoType);
|
||||
|
||||
if (m_stream.col() > 0)
|
||||
m_stream << Indentation(m_pState->GetPreCommentIndent());
|
||||
Utils::WriteComment(m_stream, comment.content,
|
||||
m_pState->GetPostCommentIndent());
|
||||
|
||||
m_pState->SetNonContent();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Emitter& Emitter::Write(const _Null& /*null*/) {
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
|
||||
m_stream << "~";
|
||||
|
||||
StartedScalar();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Emitter& Emitter::Write(const Binary& binary) {
|
||||
Write(SecondaryTag("binary"));
|
||||
|
||||
if (!good())
|
||||
return *this;
|
||||
|
||||
PrepareNode(EmitterNodeType::Scalar);
|
||||
Utils::WriteBinary(m_stream, binary);
|
||||
StartedScalar();
|
||||
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
365
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emitterstate.cpp
Executable file
365
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emitterstate.cpp
Executable file
@@ -0,0 +1,365 @@
|
||||
#include <limits>
|
||||
|
||||
#include "emitterstate.h"
|
||||
#include "yaml-cpp/exceptions.h" // IWYU pragma: keep
|
||||
|
||||
namespace YAML {
|
||||
EmitterState::EmitterState()
|
||||
: m_isGood(true),
|
||||
m_curIndent(0),
|
||||
m_hasAnchor(false),
|
||||
m_hasTag(false),
|
||||
m_hasNonContent(false),
|
||||
m_docCount(0) {
|
||||
// set default global manipulators
|
||||
m_charset.set(EmitNonAscii);
|
||||
m_strFmt.set(Auto);
|
||||
m_boolFmt.set(TrueFalseBool);
|
||||
m_boolLengthFmt.set(LongBool);
|
||||
m_boolCaseFmt.set(LowerCase);
|
||||
m_intFmt.set(Dec);
|
||||
m_indent.set(2);
|
||||
m_preCommentIndent.set(2);
|
||||
m_postCommentIndent.set(1);
|
||||
m_seqFmt.set(Block);
|
||||
m_mapFmt.set(Block);
|
||||
m_mapKeyFmt.set(Auto);
|
||||
m_floatPrecision.set(std::numeric_limits<float>::digits10 + 1);
|
||||
m_doublePrecision.set(std::numeric_limits<double>::digits10 + 1);
|
||||
}
|
||||
|
||||
EmitterState::~EmitterState() {}
|
||||
|
||||
// SetLocalValue
|
||||
// . We blindly tries to set all possible formatters to this value
|
||||
// . Only the ones that make sense will be accepted
|
||||
void EmitterState::SetLocalValue(EMITTER_MANIP value) {
|
||||
SetOutputCharset(value, FmtScope::Local);
|
||||
SetStringFormat(value, FmtScope::Local);
|
||||
SetBoolFormat(value, FmtScope::Local);
|
||||
SetBoolCaseFormat(value, FmtScope::Local);
|
||||
SetBoolLengthFormat(value, FmtScope::Local);
|
||||
SetIntFormat(value, FmtScope::Local);
|
||||
SetFlowType(GroupType::Seq, value, FmtScope::Local);
|
||||
SetFlowType(GroupType::Map, value, FmtScope::Local);
|
||||
SetMapKeyFormat(value, FmtScope::Local);
|
||||
}
|
||||
|
||||
void EmitterState::SetAnchor() { m_hasAnchor = true; }
|
||||
|
||||
void EmitterState::SetTag() { m_hasTag = true; }
|
||||
|
||||
void EmitterState::SetNonContent() { m_hasNonContent = true; }
|
||||
|
||||
void EmitterState::SetLongKey() {
|
||||
assert(!m_groups.empty());
|
||||
if (m_groups.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(m_groups.back()->type == GroupType::Map);
|
||||
m_groups.back()->longKey = true;
|
||||
}
|
||||
|
||||
void EmitterState::ForceFlow() {
|
||||
assert(!m_groups.empty());
|
||||
if (m_groups.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_groups.back()->flowType = FlowType::Flow;
|
||||
}
|
||||
|
||||
void EmitterState::StartedNode() {
|
||||
if (m_groups.empty()) {
|
||||
m_docCount++;
|
||||
} else {
|
||||
m_groups.back()->childCount++;
|
||||
if (m_groups.back()->childCount % 2 == 0) {
|
||||
m_groups.back()->longKey = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_hasAnchor = false;
|
||||
m_hasTag = false;
|
||||
m_hasNonContent = false;
|
||||
}
|
||||
|
||||
EmitterNodeType::value EmitterState::NextGroupType(
|
||||
GroupType::value type) const {
|
||||
if (type == GroupType::Seq) {
|
||||
if (GetFlowType(type) == Block)
|
||||
return EmitterNodeType::BlockSeq;
|
||||
else
|
||||
return EmitterNodeType::FlowSeq;
|
||||
} else {
|
||||
if (GetFlowType(type) == Block)
|
||||
return EmitterNodeType::BlockMap;
|
||||
else
|
||||
return EmitterNodeType::FlowMap;
|
||||
}
|
||||
|
||||
// can't happen
|
||||
assert(false);
|
||||
return EmitterNodeType::NoType;
|
||||
}
|
||||
|
||||
void EmitterState::StartedDoc() {
|
||||
m_hasAnchor = false;
|
||||
m_hasTag = false;
|
||||
m_hasNonContent = false;
|
||||
}
|
||||
|
||||
void EmitterState::EndedDoc() {
|
||||
m_hasAnchor = false;
|
||||
m_hasTag = false;
|
||||
m_hasNonContent = false;
|
||||
}
|
||||
|
||||
void EmitterState::StartedScalar() {
|
||||
StartedNode();
|
||||
ClearModifiedSettings();
|
||||
}
|
||||
|
||||
void EmitterState::StartedGroup(GroupType::value type) {
|
||||
StartedNode();
|
||||
|
||||
const std::size_t lastGroupIndent =
|
||||
(m_groups.empty() ? 0 : m_groups.back()->indent);
|
||||
m_curIndent += lastGroupIndent;
|
||||
|
||||
// TODO: Create move constructors for settings types to simplify transfer
|
||||
std::unique_ptr<Group> pGroup(new Group(type));
|
||||
|
||||
// transfer settings (which last until this group is done)
|
||||
//
|
||||
// NB: if pGroup->modifiedSettings == m_modifiedSettings,
|
||||
// m_modifiedSettings is not changed!
|
||||
pGroup->modifiedSettings = std::move(m_modifiedSettings);
|
||||
|
||||
// set up group
|
||||
if (GetFlowType(type) == Block) {
|
||||
pGroup->flowType = FlowType::Block;
|
||||
} else {
|
||||
pGroup->flowType = FlowType::Flow;
|
||||
}
|
||||
pGroup->indent = GetIndent();
|
||||
|
||||
m_groups.push_back(std::move(pGroup));
|
||||
}
|
||||
|
||||
void EmitterState::EndedGroup(GroupType::value type) {
|
||||
if (m_groups.empty()) {
|
||||
if (type == GroupType::Seq) {
|
||||
return SetError(ErrorMsg::UNEXPECTED_END_SEQ);
|
||||
} else {
|
||||
return SetError(ErrorMsg::UNEXPECTED_END_MAP);
|
||||
}
|
||||
}
|
||||
|
||||
// get rid of the current group
|
||||
{
|
||||
std::unique_ptr<Group> pFinishedGroup = std::move(m_groups.back());
|
||||
m_groups.pop_back();
|
||||
if (pFinishedGroup->type != type) {
|
||||
return SetError(ErrorMsg::UNMATCHED_GROUP_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
// reset old settings
|
||||
std::size_t lastIndent = (m_groups.empty() ? 0 : m_groups.back()->indent);
|
||||
assert(m_curIndent >= lastIndent);
|
||||
m_curIndent -= lastIndent;
|
||||
|
||||
// some global settings that we changed may have been overridden
|
||||
// by a local setting we just popped, so we need to restore them
|
||||
m_globalModifiedSettings.restore();
|
||||
|
||||
ClearModifiedSettings();
|
||||
}
|
||||
|
||||
EmitterNodeType::value EmitterState::CurGroupNodeType() const {
|
||||
if (m_groups.empty()) {
|
||||
return EmitterNodeType::NoType;
|
||||
}
|
||||
|
||||
return m_groups.back()->NodeType();
|
||||
}
|
||||
|
||||
GroupType::value EmitterState::CurGroupType() const {
|
||||
return m_groups.empty() ? GroupType::NoType : m_groups.back()->type;
|
||||
}
|
||||
|
||||
FlowType::value EmitterState::CurGroupFlowType() const {
|
||||
return m_groups.empty() ? FlowType::NoType : m_groups.back()->flowType;
|
||||
}
|
||||
|
||||
std::size_t EmitterState::CurGroupIndent() const {
|
||||
return m_groups.empty() ? 0 : m_groups.back()->indent;
|
||||
}
|
||||
|
||||
std::size_t EmitterState::CurGroupChildCount() const {
|
||||
return m_groups.empty() ? m_docCount : m_groups.back()->childCount;
|
||||
}
|
||||
|
||||
bool EmitterState::CurGroupLongKey() const {
|
||||
return m_groups.empty() ? false : m_groups.back()->longKey;
|
||||
}
|
||||
|
||||
std::size_t EmitterState::LastIndent() const {
|
||||
if (m_groups.size() <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_curIndent - m_groups[m_groups.size() - 2]->indent;
|
||||
}
|
||||
|
||||
void EmitterState::ClearModifiedSettings() { m_modifiedSettings.clear(); }
|
||||
|
||||
bool EmitterState::SetOutputCharset(EMITTER_MANIP value,
|
||||
FmtScope::value scope) {
|
||||
switch (value) {
|
||||
case EmitNonAscii:
|
||||
case EscapeNonAscii:
|
||||
_Set(m_charset, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetStringFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
||||
switch (value) {
|
||||
case Auto:
|
||||
case SingleQuoted:
|
||||
case DoubleQuoted:
|
||||
case Literal:
|
||||
_Set(m_strFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetBoolFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
||||
switch (value) {
|
||||
case OnOffBool:
|
||||
case TrueFalseBool:
|
||||
case YesNoBool:
|
||||
_Set(m_boolFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetBoolLengthFormat(EMITTER_MANIP value,
|
||||
FmtScope::value scope) {
|
||||
switch (value) {
|
||||
case LongBool:
|
||||
case ShortBool:
|
||||
_Set(m_boolLengthFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetBoolCaseFormat(EMITTER_MANIP value,
|
||||
FmtScope::value scope) {
|
||||
switch (value) {
|
||||
case UpperCase:
|
||||
case LowerCase:
|
||||
case CamelCase:
|
||||
_Set(m_boolCaseFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetIntFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
||||
switch (value) {
|
||||
case Dec:
|
||||
case Hex:
|
||||
case Oct:
|
||||
_Set(m_intFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetIndent(std::size_t value, FmtScope::value scope) {
|
||||
if (value <= 1)
|
||||
return false;
|
||||
|
||||
_Set(m_indent, value, scope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetPreCommentIndent(std::size_t value,
|
||||
FmtScope::value scope) {
|
||||
if (value == 0)
|
||||
return false;
|
||||
|
||||
_Set(m_preCommentIndent, value, scope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetPostCommentIndent(std::size_t value,
|
||||
FmtScope::value scope) {
|
||||
if (value == 0)
|
||||
return false;
|
||||
|
||||
_Set(m_postCommentIndent, value, scope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetFlowType(GroupType::value groupType, EMITTER_MANIP value,
|
||||
FmtScope::value scope) {
|
||||
switch (value) {
|
||||
case Block:
|
||||
case Flow:
|
||||
_Set(groupType == GroupType::Seq ? m_seqFmt : m_mapFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
EMITTER_MANIP EmitterState::GetFlowType(GroupType::value groupType) const {
|
||||
// force flow style if we're currently in a flow
|
||||
if (CurGroupFlowType() == FlowType::Flow)
|
||||
return Flow;
|
||||
|
||||
// otherwise, go with what's asked of us
|
||||
return (groupType == GroupType::Seq ? m_seqFmt.get() : m_mapFmt.get());
|
||||
}
|
||||
|
||||
bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope) {
|
||||
switch (value) {
|
||||
case Auto:
|
||||
case LongKey:
|
||||
_Set(m_mapKeyFmt, value, scope);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitterState::SetFloatPrecision(std::size_t value, FmtScope::value scope) {
|
||||
if (value > std::numeric_limits<float>::digits10 + 1)
|
||||
return false;
|
||||
_Set(m_floatPrecision, value, scope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitterState::SetDoublePrecision(std::size_t value,
|
||||
FmtScope::value scope) {
|
||||
if (value > std::numeric_limits<double>::digits10 + 1)
|
||||
return false;
|
||||
_Set(m_doublePrecision, value, scope);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
203
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emitterstate.h
Executable file
203
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emitterstate.h
Executable file
@@ -0,0 +1,203 @@
|
||||
#ifndef EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "setting.h"
|
||||
#include "yaml-cpp/emitterdef.h"
|
||||
#include "yaml-cpp/emittermanip.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace YAML {
|
||||
struct FmtScope {
|
||||
enum value { Local, Global };
|
||||
};
|
||||
struct GroupType {
|
||||
enum value { NoType, Seq, Map };
|
||||
};
|
||||
struct FlowType {
|
||||
enum value { NoType, Flow, Block };
|
||||
};
|
||||
|
||||
class EmitterState {
|
||||
public:
|
||||
EmitterState();
|
||||
~EmitterState();
|
||||
|
||||
// basic state checking
|
||||
bool good() const { return m_isGood; }
|
||||
const std::string GetLastError() const { return m_lastError; }
|
||||
void SetError(const std::string& error) {
|
||||
m_isGood = false;
|
||||
m_lastError = error;
|
||||
}
|
||||
|
||||
// node handling
|
||||
void SetAnchor();
|
||||
void SetTag();
|
||||
void SetNonContent();
|
||||
void SetLongKey();
|
||||
void ForceFlow();
|
||||
void StartedDoc();
|
||||
void EndedDoc();
|
||||
void StartedScalar();
|
||||
void StartedGroup(GroupType::value type);
|
||||
void EndedGroup(GroupType::value type);
|
||||
|
||||
EmitterNodeType::value NextGroupType(GroupType::value type) const;
|
||||
EmitterNodeType::value CurGroupNodeType() const;
|
||||
|
||||
GroupType::value CurGroupType() const;
|
||||
FlowType::value CurGroupFlowType() const;
|
||||
std::size_t CurGroupIndent() const;
|
||||
std::size_t CurGroupChildCount() const;
|
||||
bool CurGroupLongKey() const;
|
||||
|
||||
std::size_t LastIndent() const;
|
||||
std::size_t CurIndent() const { return m_curIndent; }
|
||||
bool HasAnchor() const { return m_hasAnchor; }
|
||||
bool HasTag() const { return m_hasTag; }
|
||||
bool HasBegunNode() const {
|
||||
return m_hasAnchor || m_hasTag || m_hasNonContent;
|
||||
}
|
||||
bool HasBegunContent() const { return m_hasAnchor || m_hasTag; }
|
||||
|
||||
void ClearModifiedSettings();
|
||||
|
||||
// formatters
|
||||
void SetLocalValue(EMITTER_MANIP value);
|
||||
|
||||
bool SetOutputCharset(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetOutputCharset() const { return m_charset.get(); }
|
||||
|
||||
bool SetStringFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetStringFormat() const { return m_strFmt.get(); }
|
||||
|
||||
bool SetBoolFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetBoolFormat() const { return m_boolFmt.get(); }
|
||||
|
||||
bool SetBoolLengthFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetBoolLengthFormat() const { return m_boolLengthFmt.get(); }
|
||||
|
||||
bool SetBoolCaseFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetBoolCaseFormat() const { return m_boolCaseFmt.get(); }
|
||||
|
||||
bool SetIntFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetIntFormat() const { return m_intFmt.get(); }
|
||||
|
||||
bool SetIndent(std::size_t value, FmtScope::value scope);
|
||||
std::size_t GetIndent() const { return m_indent.get(); }
|
||||
|
||||
bool SetPreCommentIndent(std::size_t value, FmtScope::value scope);
|
||||
std::size_t GetPreCommentIndent() const { return m_preCommentIndent.get(); }
|
||||
bool SetPostCommentIndent(std::size_t value, FmtScope::value scope);
|
||||
std::size_t GetPostCommentIndent() const { return m_postCommentIndent.get(); }
|
||||
|
||||
bool SetFlowType(GroupType::value groupType, EMITTER_MANIP value,
|
||||
FmtScope::value scope);
|
||||
EMITTER_MANIP GetFlowType(GroupType::value groupType) const;
|
||||
|
||||
bool SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope);
|
||||
EMITTER_MANIP GetMapKeyFormat() const { return m_mapKeyFmt.get(); }
|
||||
|
||||
bool SetFloatPrecision(std::size_t value, FmtScope::value scope);
|
||||
std::size_t GetFloatPrecision() const { return m_floatPrecision.get(); }
|
||||
bool SetDoublePrecision(std::size_t value, FmtScope::value scope);
|
||||
std::size_t GetDoublePrecision() const { return m_doublePrecision.get(); }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void _Set(Setting<T>& fmt, T value, FmtScope::value scope);
|
||||
|
||||
void StartedNode();
|
||||
|
||||
private:
|
||||
// basic state ok?
|
||||
bool m_isGood;
|
||||
std::string m_lastError;
|
||||
|
||||
// other state
|
||||
Setting<EMITTER_MANIP> m_charset;
|
||||
Setting<EMITTER_MANIP> m_strFmt;
|
||||
Setting<EMITTER_MANIP> m_boolFmt;
|
||||
Setting<EMITTER_MANIP> m_boolLengthFmt;
|
||||
Setting<EMITTER_MANIP> m_boolCaseFmt;
|
||||
Setting<EMITTER_MANIP> m_intFmt;
|
||||
Setting<std::size_t> m_indent;
|
||||
Setting<std::size_t> m_preCommentIndent, m_postCommentIndent;
|
||||
Setting<EMITTER_MANIP> m_seqFmt;
|
||||
Setting<EMITTER_MANIP> m_mapFmt;
|
||||
Setting<EMITTER_MANIP> m_mapKeyFmt;
|
||||
Setting<std::size_t> m_floatPrecision;
|
||||
Setting<std::size_t> m_doublePrecision;
|
||||
|
||||
SettingChanges m_modifiedSettings;
|
||||
SettingChanges m_globalModifiedSettings;
|
||||
|
||||
struct Group {
|
||||
explicit Group(GroupType::value type_)
|
||||
: type(type_), indent(0), childCount(0), longKey(false) {}
|
||||
|
||||
GroupType::value type;
|
||||
FlowType::value flowType;
|
||||
std::size_t indent;
|
||||
std::size_t childCount;
|
||||
bool longKey;
|
||||
|
||||
SettingChanges modifiedSettings;
|
||||
|
||||
EmitterNodeType::value NodeType() const {
|
||||
if (type == GroupType::Seq) {
|
||||
if (flowType == FlowType::Flow)
|
||||
return EmitterNodeType::FlowSeq;
|
||||
else
|
||||
return EmitterNodeType::BlockSeq;
|
||||
} else {
|
||||
if (flowType == FlowType::Flow)
|
||||
return EmitterNodeType::FlowMap;
|
||||
else
|
||||
return EmitterNodeType::BlockMap;
|
||||
}
|
||||
|
||||
// can't get here
|
||||
assert(false);
|
||||
return EmitterNodeType::NoType;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<Group>> m_groups;
|
||||
std::size_t m_curIndent;
|
||||
bool m_hasAnchor;
|
||||
bool m_hasTag;
|
||||
bool m_hasNonContent;
|
||||
std::size_t m_docCount;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void EmitterState::_Set(Setting<T>& fmt, T value, FmtScope::value scope) {
|
||||
switch (scope) {
|
||||
case FmtScope::Local:
|
||||
m_modifiedSettings.push(fmt.set(value));
|
||||
break;
|
||||
case FmtScope::Global:
|
||||
fmt.set(value);
|
||||
m_globalModifiedSettings.push(
|
||||
fmt.set(value)); // this pushes an identity set, so when we restore,
|
||||
// it restores to the value here, and not the previous one
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
483
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emitterutils.cpp
Executable file
483
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/emitterutils.cpp
Executable file
@@ -0,0 +1,483 @@
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "emitterutils.h"
|
||||
#include "exp.h"
|
||||
#include "indentation.h"
|
||||
#include "regex_yaml.h"
|
||||
#include "regeximpl.h"
|
||||
#include "stringsource.h"
|
||||
#include "yaml-cpp/binary.h" // IWYU pragma: keep
|
||||
#include "yaml-cpp/ostream_wrapper.h"
|
||||
#include "yaml-cpp/null.h"
|
||||
|
||||
namespace YAML {
|
||||
namespace Utils {
|
||||
namespace {
|
||||
enum { REPLACEMENT_CHARACTER = 0xFFFD };
|
||||
|
||||
bool IsAnchorChar(int ch) { // test for ns-anchor-char
|
||||
switch (ch) {
|
||||
case ',':
|
||||
case '[':
|
||||
case ']':
|
||||
case '{':
|
||||
case '}': // c-flow-indicator
|
||||
case ' ':
|
||||
case '\t': // s-white
|
||||
case 0xFEFF: // c-byte-order-mark
|
||||
case 0xA:
|
||||
case 0xD: // b-char
|
||||
return false;
|
||||
case 0x85:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ch < 0x20) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ch < 0x7E) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ch < 0xA0) {
|
||||
return false;
|
||||
}
|
||||
if (ch >= 0xD800 && ch <= 0xDFFF) {
|
||||
return false;
|
||||
}
|
||||
if ((ch & 0xFFFE) == 0xFFFE) {
|
||||
return false;
|
||||
}
|
||||
if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) {
|
||||
return false;
|
||||
}
|
||||
if (ch > 0x10FFFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Utf8BytesIndicated(char ch) {
|
||||
int byteVal = static_cast<unsigned char>(ch);
|
||||
switch (byteVal >> 4) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
return 1;
|
||||
case 12:
|
||||
case 13:
|
||||
return 2;
|
||||
case 14:
|
||||
return 3;
|
||||
case 15:
|
||||
return 4;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsTrailingByte(char ch) { return (ch & 0xC0) == 0x80; }
|
||||
|
||||
bool GetNextCodePointAndAdvance(int& codePoint,
|
||||
std::string::const_iterator& first,
|
||||
std::string::const_iterator last) {
|
||||
if (first == last)
|
||||
return false;
|
||||
|
||||
int nBytes = Utf8BytesIndicated(*first);
|
||||
if (nBytes < 1) {
|
||||
// Bad lead byte
|
||||
++first;
|
||||
codePoint = REPLACEMENT_CHARACTER;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nBytes == 1) {
|
||||
codePoint = *first++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gather bits from trailing bytes
|
||||
codePoint = static_cast<unsigned char>(*first) & ~(0xFF << (7 - nBytes));
|
||||
++first;
|
||||
--nBytes;
|
||||
for (; nBytes > 0; ++first, --nBytes) {
|
||||
if ((first == last) || !IsTrailingByte(*first)) {
|
||||
codePoint = REPLACEMENT_CHARACTER;
|
||||
break;
|
||||
}
|
||||
codePoint <<= 6;
|
||||
codePoint |= *first & 0x3F;
|
||||
}
|
||||
|
||||
// Check for illegal code points
|
||||
if (codePoint > 0x10FFFF)
|
||||
codePoint = REPLACEMENT_CHARACTER;
|
||||
else if (codePoint >= 0xD800 && codePoint <= 0xDFFF)
|
||||
codePoint = REPLACEMENT_CHARACTER;
|
||||
else if ((codePoint & 0xFFFE) == 0xFFFE)
|
||||
codePoint = REPLACEMENT_CHARACTER;
|
||||
else if (codePoint >= 0xFDD0 && codePoint <= 0xFDEF)
|
||||
codePoint = REPLACEMENT_CHARACTER;
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteCodePoint(ostream_wrapper& out, int codePoint) {
|
||||
if (codePoint < 0 || codePoint > 0x10FFFF) {
|
||||
codePoint = REPLACEMENT_CHARACTER;
|
||||
}
|
||||
if (codePoint < 0x7F) {
|
||||
out << static_cast<char>(codePoint);
|
||||
} else if (codePoint < 0x7FF) {
|
||||
out << static_cast<char>(0xC0 | (codePoint >> 6))
|
||||
<< static_cast<char>(0x80 | (codePoint & 0x3F));
|
||||
} else if (codePoint < 0xFFFF) {
|
||||
out << static_cast<char>(0xE0 | (codePoint >> 12))
|
||||
<< static_cast<char>(0x80 | ((codePoint >> 6) & 0x3F))
|
||||
<< static_cast<char>(0x80 | (codePoint & 0x3F));
|
||||
} else {
|
||||
out << static_cast<char>(0xF0 | (codePoint >> 18))
|
||||
<< static_cast<char>(0x80 | ((codePoint >> 12) & 0x3F))
|
||||
<< static_cast<char>(0x80 | ((codePoint >> 6) & 0x3F))
|
||||
<< static_cast<char>(0x80 | (codePoint & 0x3F));
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
|
||||
bool allowOnlyAscii) {
|
||||
// check against null
|
||||
if (IsNullString(str)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check the start
|
||||
const RegEx& start = (flowType == FlowType::Flow ? Exp::PlainScalarInFlow()
|
||||
: Exp::PlainScalar());
|
||||
if (!start.Matches(str)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// and check the end for plain whitespace (which can't be faithfully kept in a
|
||||
// plain scalar)
|
||||
if (!str.empty() && *str.rbegin() == ' ') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// then check until something is disallowed
|
||||
static const RegEx& disallowed_flow =
|
||||
Exp::EndScalarInFlow() || (Exp::BlankOrBreak() + Exp::Comment()) ||
|
||||
Exp::NotPrintable() || Exp::Utf8_ByteOrderMark() || Exp::Break() ||
|
||||
Exp::Tab();
|
||||
static const RegEx& disallowed_block =
|
||||
Exp::EndScalar() || (Exp::BlankOrBreak() + Exp::Comment()) ||
|
||||
Exp::NotPrintable() || Exp::Utf8_ByteOrderMark() || Exp::Break() ||
|
||||
Exp::Tab();
|
||||
const RegEx& disallowed =
|
||||
flowType == FlowType::Flow ? disallowed_flow : disallowed_block;
|
||||
|
||||
StringCharSource buffer(str.c_str(), str.size());
|
||||
while (buffer) {
|
||||
if (disallowed.Matches(buffer)) {
|
||||
return false;
|
||||
}
|
||||
if (allowOnlyAscii && (0x80 <= static_cast<unsigned char>(buffer[0]))) {
|
||||
return false;
|
||||
}
|
||||
++buffer;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValidSingleQuotedScalar(const std::string& str, bool escapeNonAscii) {
|
||||
// TODO: check for non-printable characters?
|
||||
for (std::size_t i = 0; i < str.size(); i++) {
|
||||
if (escapeNonAscii && (0x80 <= static_cast<unsigned char>(str[i]))) {
|
||||
return false;
|
||||
}
|
||||
if (str[i] == '\n') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValidLiteralScalar(const std::string& str, FlowType::value flowType,
|
||||
bool escapeNonAscii) {
|
||||
if (flowType == FlowType::Flow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: check for non-printable characters?
|
||||
for (std::size_t i = 0; i < str.size(); i++) {
|
||||
if (escapeNonAscii && (0x80 <= static_cast<unsigned char>(str[i]))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteDoubleQuoteEscapeSequence(ostream_wrapper& out, int codePoint) {
|
||||
static const char hexDigits[] = "0123456789abcdef";
|
||||
|
||||
out << "\\";
|
||||
int digits = 8;
|
||||
if (codePoint < 0xFF) {
|
||||
out << "x";
|
||||
digits = 2;
|
||||
} else if (codePoint < 0xFFFF) {
|
||||
out << "u";
|
||||
digits = 4;
|
||||
} else {
|
||||
out << "U";
|
||||
digits = 8;
|
||||
}
|
||||
|
||||
// Write digits into the escape sequence
|
||||
for (; digits > 0; --digits)
|
||||
out << hexDigits[(codePoint >> (4 * (digits - 1))) & 0xF];
|
||||
}
|
||||
|
||||
bool WriteAliasName(ostream_wrapper& out, const std::string& str) {
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
if (!IsAnchorChar(codePoint)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteCodePoint(out, codePoint);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
StringFormat::value ComputeStringFormat(const std::string& str,
|
||||
EMITTER_MANIP strFormat,
|
||||
FlowType::value flowType,
|
||||
bool escapeNonAscii) {
|
||||
switch (strFormat) {
|
||||
case Auto:
|
||||
if (IsValidPlainScalar(str, flowType, escapeNonAscii)) {
|
||||
return StringFormat::Plain;
|
||||
}
|
||||
return StringFormat::DoubleQuoted;
|
||||
case SingleQuoted:
|
||||
if (IsValidSingleQuotedScalar(str, escapeNonAscii)) {
|
||||
return StringFormat::SingleQuoted;
|
||||
}
|
||||
return StringFormat::DoubleQuoted;
|
||||
case DoubleQuoted:
|
||||
return StringFormat::DoubleQuoted;
|
||||
case Literal:
|
||||
if (IsValidLiteralScalar(str, flowType, escapeNonAscii)) {
|
||||
return StringFormat::Literal;
|
||||
}
|
||||
return StringFormat::DoubleQuoted;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return StringFormat::DoubleQuoted;
|
||||
}
|
||||
|
||||
bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str) {
|
||||
out << "'";
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
if (codePoint == '\n') {
|
||||
return false; // We can't handle a new line and the attendant indentation
|
||||
// yet
|
||||
}
|
||||
|
||||
if (codePoint == '\'') {
|
||||
out << "''";
|
||||
} else {
|
||||
WriteCodePoint(out, codePoint);
|
||||
}
|
||||
}
|
||||
out << "'";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
|
||||
bool escapeNonAscii) {
|
||||
out << "\"";
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
switch (codePoint) {
|
||||
case '\"':
|
||||
out << "\\\"";
|
||||
break;
|
||||
case '\\':
|
||||
out << "\\\\";
|
||||
break;
|
||||
case '\n':
|
||||
out << "\\n";
|
||||
break;
|
||||
case '\t':
|
||||
out << "\\t";
|
||||
break;
|
||||
case '\r':
|
||||
out << "\\r";
|
||||
break;
|
||||
case '\b':
|
||||
out << "\\b";
|
||||
break;
|
||||
default:
|
||||
if (codePoint < 0x20 ||
|
||||
(codePoint >= 0x80 &&
|
||||
codePoint <= 0xA0)) { // Control characters and non-breaking space
|
||||
WriteDoubleQuoteEscapeSequence(out, codePoint);
|
||||
} else if (codePoint == 0xFEFF) { // Byte order marks (ZWNS) should be
|
||||
// escaped (YAML 1.2, sec. 5.2)
|
||||
WriteDoubleQuoteEscapeSequence(out, codePoint);
|
||||
} else if (escapeNonAscii && codePoint > 0x7E) {
|
||||
WriteDoubleQuoteEscapeSequence(out, codePoint);
|
||||
} else {
|
||||
WriteCodePoint(out, codePoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
out << "\"";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
|
||||
std::size_t indent) {
|
||||
out << "|\n";
|
||||
out << IndentTo(indent);
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
if (codePoint == '\n') {
|
||||
out << "\n" << IndentTo(indent);
|
||||
} else {
|
||||
WriteCodePoint(out, codePoint);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteChar(ostream_wrapper& out, char ch) {
|
||||
if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) {
|
||||
out << ch;
|
||||
} else if (ch == '\"') {
|
||||
out << "\"\\\"\"";
|
||||
} else if (ch == '\t') {
|
||||
out << "\"\\t\"";
|
||||
} else if (ch == '\n') {
|
||||
out << "\"\\n\"";
|
||||
} else if (ch == '\b') {
|
||||
out << "\"\\b\"";
|
||||
} else if (ch == '\\') {
|
||||
out << "\"\\\\\"";
|
||||
} else if ((0x20 <= ch && ch <= 0x7e) || ch == ' ') {
|
||||
out << "\"" << ch << "\"";
|
||||
} else {
|
||||
out << "\"";
|
||||
WriteDoubleQuoteEscapeSequence(out, ch);
|
||||
out << "\"";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteComment(ostream_wrapper& out, const std::string& str,
|
||||
std::size_t postCommentIndent) {
|
||||
const std::size_t curIndent = out.col();
|
||||
out << "#" << Indentation(postCommentIndent);
|
||||
out.set_comment();
|
||||
int codePoint;
|
||||
for (std::string::const_iterator i = str.begin();
|
||||
GetNextCodePointAndAdvance(codePoint, i, str.end());) {
|
||||
if (codePoint == '\n') {
|
||||
out << "\n" << IndentTo(curIndent) << "#"
|
||||
<< Indentation(postCommentIndent);
|
||||
out.set_comment();
|
||||
} else {
|
||||
WriteCodePoint(out, codePoint);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteAlias(ostream_wrapper& out, const std::string& str) {
|
||||
out << "*";
|
||||
return WriteAliasName(out, str);
|
||||
}
|
||||
|
||||
bool WriteAnchor(ostream_wrapper& out, const std::string& str) {
|
||||
out << "&";
|
||||
return WriteAliasName(out, str);
|
||||
}
|
||||
|
||||
bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim) {
|
||||
out << (verbatim ? "!<" : "!");
|
||||
StringCharSource buffer(str.c_str(), str.size());
|
||||
const RegEx& reValid = verbatim ? Exp::URI() : Exp::Tag();
|
||||
while (buffer) {
|
||||
int n = reValid.Match(buffer);
|
||||
if (n <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (--n >= 0) {
|
||||
out << buffer[0];
|
||||
++buffer;
|
||||
}
|
||||
}
|
||||
if (verbatim) {
|
||||
out << ">";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix,
|
||||
const std::string& tag) {
|
||||
out << "!";
|
||||
StringCharSource prefixBuffer(prefix.c_str(), prefix.size());
|
||||
while (prefixBuffer) {
|
||||
int n = Exp::URI().Match(prefixBuffer);
|
||||
if (n <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (--n >= 0) {
|
||||
out << prefixBuffer[0];
|
||||
++prefixBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
out << "!";
|
||||
StringCharSource tagBuffer(tag.c_str(), tag.size());
|
||||
while (tagBuffer) {
|
||||
int n = Exp::Tag().Match(tagBuffer);
|
||||
if (n <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (--n >= 0) {
|
||||
out << tagBuffer[0];
|
||||
++tagBuffer;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteBinary(ostream_wrapper& out, const Binary& binary) {
|
||||
WriteDoubleQuotedString(out, EncodeBase64(binary.data(), binary.size()),
|
||||
false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "emitterstate.h"
|
||||
#include "yaml-cpp/emittermanip.h"
|
||||
#include "yaml-cpp/ostream_wrapper.h"
|
||||
|
||||
namespace YAML {
|
||||
class ostream_wrapper;
|
||||
} // namespace YAML
|
||||
|
||||
namespace YAML {
|
||||
class Binary;
|
||||
|
||||
struct StringFormat {
|
||||
enum value { Plain, SingleQuoted, DoubleQuoted, Literal };
|
||||
};
|
||||
|
||||
namespace Utils {
|
||||
StringFormat::value ComputeStringFormat(const std::string& str,
|
||||
EMITTER_MANIP strFormat,
|
||||
FlowType::value flowType,
|
||||
bool escapeNonAscii);
|
||||
|
||||
bool WriteSingleQuotedString(ostream_wrapper& out, const std::string& str);
|
||||
bool WriteDoubleQuotedString(ostream_wrapper& out, const std::string& str,
|
||||
bool escapeNonAscii);
|
||||
bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
|
||||
std::size_t indent);
|
||||
bool WriteChar(ostream_wrapper& out, char ch);
|
||||
bool WriteComment(ostream_wrapper& out, const std::string& str,
|
||||
std::size_t postCommentIndent);
|
||||
bool WriteAlias(ostream_wrapper& out, const std::string& str);
|
||||
bool WriteAnchor(ostream_wrapper& out, const std::string& str);
|
||||
bool WriteTag(ostream_wrapper& out, const std::string& str, bool verbatim);
|
||||
bool WriteTagWithPrefix(ostream_wrapper& out, const std::string& prefix,
|
||||
const std::string& tag);
|
||||
bool WriteBinary(ostream_wrapper& out, const Binary& binary);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "yaml-cpp/exceptions.h"
|
||||
|
||||
// This is here for compatibility with older versions of Visual Studio
|
||||
// which don't support noexcept
|
||||
#ifdef _MSC_VER
|
||||
#define YAML_CPP_NOEXCEPT _NOEXCEPT
|
||||
#else
|
||||
#define YAML_CPP_NOEXCEPT noexcept
|
||||
#endif
|
||||
|
||||
namespace YAML {
|
||||
|
||||
// These destructors are defined out-of-line so the vtable is only emitted once.
|
||||
Exception::~Exception() YAML_CPP_NOEXCEPT {}
|
||||
ParserException::~ParserException() YAML_CPP_NOEXCEPT {}
|
||||
RepresentationException::~RepresentationException() YAML_CPP_NOEXCEPT {}
|
||||
InvalidScalar::~InvalidScalar() YAML_CPP_NOEXCEPT {}
|
||||
KeyNotFound::~KeyNotFound() YAML_CPP_NOEXCEPT {}
|
||||
InvalidNode::~InvalidNode() YAML_CPP_NOEXCEPT {}
|
||||
BadConversion::~BadConversion() YAML_CPP_NOEXCEPT {}
|
||||
BadDereference::~BadDereference() YAML_CPP_NOEXCEPT {}
|
||||
BadSubscript::~BadSubscript() YAML_CPP_NOEXCEPT {}
|
||||
BadPushback::~BadPushback() YAML_CPP_NOEXCEPT {}
|
||||
BadInsert::~BadInsert() YAML_CPP_NOEXCEPT {}
|
||||
EmitterException::~EmitterException() YAML_CPP_NOEXCEPT {}
|
||||
BadFile::~BadFile() YAML_CPP_NOEXCEPT {}
|
||||
}
|
||||
|
||||
#undef YAML_CPP_NOEXCEPT
|
||||
|
||||
|
||||
136
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/exp.cpp
Executable file
136
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/exp.cpp
Executable file
@@ -0,0 +1,136 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "exp.h"
|
||||
#include "stream.h"
|
||||
#include "yaml-cpp/exceptions.h" // IWYU pragma: keep
|
||||
|
||||
namespace YAML {
|
||||
struct Mark;
|
||||
} // namespace YAML
|
||||
|
||||
namespace YAML {
|
||||
namespace Exp {
|
||||
unsigned ParseHex(const std::string& str, const Mark& mark) {
|
||||
unsigned value = 0;
|
||||
for (std::size_t i = 0; i < str.size(); i++) {
|
||||
char ch = str[i];
|
||||
int digit = 0;
|
||||
if ('a' <= ch && ch <= 'f')
|
||||
digit = ch - 'a' + 10;
|
||||
else if ('A' <= ch && ch <= 'F')
|
||||
digit = ch - 'A' + 10;
|
||||
else if ('0' <= ch && ch <= '9')
|
||||
digit = ch - '0';
|
||||
else
|
||||
throw ParserException(mark, ErrorMsg::INVALID_HEX);
|
||||
|
||||
value = (value << 4) + digit;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string Str(unsigned ch) { return std::string(1, static_cast<char>(ch)); }
|
||||
|
||||
// Escape
|
||||
// . Translates the next 'codeLength' characters into a hex number and returns
|
||||
// the result.
|
||||
// . Throws if it's not actually hex.
|
||||
std::string Escape(Stream& in, int codeLength) {
|
||||
// grab string
|
||||
std::string str;
|
||||
for (int i = 0; i < codeLength; i++)
|
||||
str += in.get();
|
||||
|
||||
// get the value
|
||||
unsigned value = ParseHex(str, in.mark());
|
||||
|
||||
// legal unicode?
|
||||
if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) {
|
||||
std::stringstream msg;
|
||||
msg << ErrorMsg::INVALID_UNICODE << value;
|
||||
throw ParserException(in.mark(), msg.str());
|
||||
}
|
||||
|
||||
// now break it up into chars
|
||||
if (value <= 0x7F)
|
||||
return Str(value);
|
||||
else if (value <= 0x7FF)
|
||||
return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F));
|
||||
else if (value <= 0xFFFF)
|
||||
return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) +
|
||||
Str(0x80 + (value & 0x3F));
|
||||
else
|
||||
return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) +
|
||||
Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F));
|
||||
}
|
||||
|
||||
// Escape
|
||||
// . Escapes the sequence starting 'in' (it must begin with a '\' or single
|
||||
// quote)
|
||||
// and returns the result.
|
||||
// . Throws if it's an unknown escape character.
|
||||
std::string Escape(Stream& in) {
|
||||
// eat slash
|
||||
char escape = in.get();
|
||||
|
||||
// switch on escape character
|
||||
char ch = in.get();
|
||||
|
||||
// first do single quote, since it's easier
|
||||
if (escape == '\'' && ch == '\'')
|
||||
return "\'";
|
||||
|
||||
// now do the slash (we're not gonna check if it's a slash - you better pass
|
||||
// one!)
|
||||
switch (ch) {
|
||||
case '0':
|
||||
return std::string(1, '\x00');
|
||||
case 'a':
|
||||
return "\x07";
|
||||
case 'b':
|
||||
return "\x08";
|
||||
case 't':
|
||||
case '\t':
|
||||
return "\x09";
|
||||
case 'n':
|
||||
return "\x0A";
|
||||
case 'v':
|
||||
return "\x0B";
|
||||
case 'f':
|
||||
return "\x0C";
|
||||
case 'r':
|
||||
return "\x0D";
|
||||
case 'e':
|
||||
return "\x1B";
|
||||
case ' ':
|
||||
return "\x20";
|
||||
case '\"':
|
||||
return "\"";
|
||||
case '\'':
|
||||
return "\'";
|
||||
case '\\':
|
||||
return "\\";
|
||||
case '/':
|
||||
return "/";
|
||||
case 'N':
|
||||
return "\x85";
|
||||
case '_':
|
||||
return "\xA0";
|
||||
case 'L':
|
||||
return "\xE2\x80\xA8"; // LS (#x2028)
|
||||
case 'P':
|
||||
return "\xE2\x80\xA9"; // PS (#x2029)
|
||||
case 'x':
|
||||
return Escape(in, 2);
|
||||
case 'u':
|
||||
return Escape(in, 4);
|
||||
case 'U':
|
||||
return Escape(in, 8);
|
||||
}
|
||||
|
||||
std::stringstream msg;
|
||||
throw ParserException(in.mark(), std::string(ErrorMsg::INVALID_ESCAPE) + ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
222
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/exp.h
Executable file
222
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/exp.h
Executable file
@@ -0,0 +1,222 @@
|
||||
#ifndef EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <ios>
|
||||
#include <string>
|
||||
|
||||
#include "regex_yaml.h"
|
||||
#include "stream.h"
|
||||
|
||||
namespace YAML {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Here we store a bunch of expressions for matching different parts of the
|
||||
// file.
|
||||
|
||||
namespace Exp {
|
||||
// misc
|
||||
inline const RegEx& Empty() {
|
||||
static const RegEx e;
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Space() {
|
||||
static const RegEx e = RegEx(' ');
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Tab() {
|
||||
static const RegEx e = RegEx('\t');
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Blank() {
|
||||
static const RegEx e = Space() || Tab();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Break() {
|
||||
static const RegEx e = RegEx('\n') || RegEx("\r\n");
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& BlankOrBreak() {
|
||||
static const RegEx e = Blank() || Break();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Digit() {
|
||||
static const RegEx e = RegEx('0', '9');
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Alpha() {
|
||||
static const RegEx e = RegEx('a', 'z') || RegEx('A', 'Z');
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& AlphaNumeric() {
|
||||
static const RegEx e = Alpha() || Digit();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Word() {
|
||||
static const RegEx e = AlphaNumeric() || RegEx('-');
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Hex() {
|
||||
static const RegEx e = Digit() || RegEx('A', 'F') || RegEx('a', 'f');
|
||||
return e;
|
||||
}
|
||||
// Valid Unicode code points that are not part of c-printable (YAML 1.2, sec.
|
||||
// 5.1)
|
||||
inline const RegEx& NotPrintable() {
|
||||
static const RegEx e =
|
||||
RegEx(0) ||
|
||||
RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) ||
|
||||
RegEx(0x0E, 0x1F) ||
|
||||
(RegEx('\xC2') + (RegEx('\x80', '\x84') || RegEx('\x86', '\x9F')));
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Utf8_ByteOrderMark() {
|
||||
static const RegEx e = RegEx("\xEF\xBB\xBF");
|
||||
return e;
|
||||
}
|
||||
|
||||
// actual tags
|
||||
|
||||
inline const RegEx& DocStart() {
|
||||
static const RegEx e = RegEx("---") + (BlankOrBreak() || RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& DocEnd() {
|
||||
static const RegEx e = RegEx("...") + (BlankOrBreak() || RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& DocIndicator() {
|
||||
static const RegEx e = DocStart() || DocEnd();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& BlockEntry() {
|
||||
static const RegEx e = RegEx('-') + (BlankOrBreak() || RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Key() {
|
||||
static const RegEx e = RegEx('?') + BlankOrBreak();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& KeyInFlow() {
|
||||
static const RegEx e = RegEx('?') + BlankOrBreak();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Value() {
|
||||
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& ValueInFlow() {
|
||||
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx(",}", REGEX_OR));
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& ValueInJSONFlow() {
|
||||
static const RegEx e = RegEx(':');
|
||||
return e;
|
||||
}
|
||||
inline const RegEx Comment() {
|
||||
static const RegEx e = RegEx('#');
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Anchor() {
|
||||
static const RegEx e = !(RegEx("[]{},", REGEX_OR) || BlankOrBreak());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& AnchorEnd() {
|
||||
static const RegEx e = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak();
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& URI() {
|
||||
static const RegEx e = Word() || RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) ||
|
||||
(RegEx('%') + Hex() + Hex());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Tag() {
|
||||
static const RegEx e = Word() || RegEx("#;/?:@&=+$_.~*'()", REGEX_OR) ||
|
||||
(RegEx('%') + Hex() + Hex());
|
||||
return e;
|
||||
}
|
||||
|
||||
// Plain scalar rules:
|
||||
// . Cannot start with a blank.
|
||||
// . Can never start with any of , [ ] { } # & * ! | > \' \" % @ `
|
||||
// . In the block context - ? : must be not be followed with a space.
|
||||
// . In the flow context ? is illegal and : and - must not be followed with a
|
||||
// space.
|
||||
inline const RegEx& PlainScalar() {
|
||||
static const RegEx e =
|
||||
!(BlankOrBreak() || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) ||
|
||||
(RegEx("-?:", REGEX_OR) + (BlankOrBreak() || RegEx())));
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& PlainScalarInFlow() {
|
||||
static const RegEx e =
|
||||
!(BlankOrBreak() || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) ||
|
||||
(RegEx("-:", REGEX_OR) + Blank()));
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& EndScalar() {
|
||||
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& EndScalarInFlow() {
|
||||
static const RegEx e =
|
||||
(RegEx(':') + (BlankOrBreak() || RegEx() || RegEx(",]}", REGEX_OR))) ||
|
||||
RegEx(",?[]{}", REGEX_OR);
|
||||
return e;
|
||||
}
|
||||
|
||||
inline const RegEx& ScanScalarEndInFlow() {
|
||||
static const RegEx e = (EndScalarInFlow() || (BlankOrBreak() + Comment()));
|
||||
return e;
|
||||
}
|
||||
|
||||
inline const RegEx& ScanScalarEnd() {
|
||||
static const RegEx e = EndScalar() || (BlankOrBreak() + Comment());
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& EscSingleQuote() {
|
||||
static const RegEx e = RegEx("\'\'");
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& EscBreak() {
|
||||
static const RegEx e = RegEx('\\') + Break();
|
||||
return e;
|
||||
}
|
||||
|
||||
inline const RegEx& ChompIndicator() {
|
||||
static const RegEx e = RegEx("+-", REGEX_OR);
|
||||
return e;
|
||||
}
|
||||
inline const RegEx& Chomp() {
|
||||
static const RegEx e = (ChompIndicator() + Digit()) ||
|
||||
(Digit() + ChompIndicator()) || ChompIndicator() ||
|
||||
Digit();
|
||||
return e;
|
||||
}
|
||||
|
||||
// and some functions
|
||||
std::string Escape(Stream& in);
|
||||
} // namespace Exp
|
||||
|
||||
namespace Keys {
|
||||
const char Directive = '%';
|
||||
const char FlowSeqStart = '[';
|
||||
const char FlowSeqEnd = ']';
|
||||
const char FlowMapStart = '{';
|
||||
const char FlowMapEnd = '}';
|
||||
const char FlowEntry = ',';
|
||||
const char Alias = '*';
|
||||
const char Anchor = '&';
|
||||
const char Tag = '!';
|
||||
const char LiteralScalar = '|';
|
||||
const char FoldedScalar = '>';
|
||||
const char VerbatimTagStart = '<';
|
||||
const char VerbatimTagEnd = '>';
|
||||
} // namespace Keys
|
||||
} // namespace YAML
|
||||
|
||||
#endif // EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#if defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
||||
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <cstddef>
|
||||
|
||||
#include "yaml-cpp/ostream_wrapper.h"
|
||||
|
||||
namespace YAML {
|
||||
struct Indentation {
|
||||
Indentation(std::size_t n_) : n(n_) {}
|
||||
std::size_t n;
|
||||
};
|
||||
|
||||
inline ostream_wrapper& operator<<(ostream_wrapper& out,
|
||||
const Indentation& indent) {
|
||||
for (std::size_t i = 0; i < indent.n; i++)
|
||||
out << ' ';
|
||||
return out;
|
||||
}
|
||||
|
||||
struct IndentTo {
|
||||
IndentTo(std::size_t n_) : n(n_) {}
|
||||
std::size_t n;
|
||||
};
|
||||
|
||||
inline ostream_wrapper& operator<<(ostream_wrapper& out,
|
||||
const IndentTo& indent) {
|
||||
while (out.col() < indent.n)
|
||||
out << ' ';
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
26
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/memory.cpp
Executable file
26
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/memory.cpp
Executable file
@@ -0,0 +1,26 @@
|
||||
#include "yaml-cpp/node/detail/memory.h"
|
||||
#include "yaml-cpp/node/detail/node.h" // IWYU pragma: keep
|
||||
#include "yaml-cpp/node/ptr.h"
|
||||
|
||||
namespace YAML {
|
||||
namespace detail {
|
||||
|
||||
void memory_holder::merge(memory_holder& rhs) {
|
||||
if (m_pMemory == rhs.m_pMemory)
|
||||
return;
|
||||
|
||||
m_pMemory->merge(*rhs.m_pMemory);
|
||||
rhs.m_pMemory = m_pMemory;
|
||||
}
|
||||
|
||||
node& memory::create_node() {
|
||||
shared_node pNode(new node);
|
||||
m_nodes.insert(pNode);
|
||||
return *pNode;
|
||||
}
|
||||
|
||||
void memory::merge(const memory& rhs) {
|
||||
m_nodes.insert(rhs.m_nodes.begin(), rhs.m_nodes.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
12
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/node.cpp
Executable file
12
cpp-package/inspireface/cpp/inspireface/middleware/cpp_yaml/src/node.cpp
Executable file
@@ -0,0 +1,12 @@
|
||||
#include "yaml-cpp/node/node.h"
|
||||
#include "nodebuilder.h"
|
||||
#include "nodeevents.h"
|
||||
|
||||
namespace YAML {
|
||||
Node Clone(const Node& node) {
|
||||
NodeEvents events(node);
|
||||
NodeBuilder builder;
|
||||
events.Emit(builder);
|
||||
return builder.Root();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user