Add the inspireface project to cpp-package.

This commit is contained in:
JingyuYan
2024-05-02 01:27:29 +08:00
parent e90dacb3cf
commit 08d7e96f79
431 changed files with 370534 additions and 0 deletions

View 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 ()

View File

@@ -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

View File

@@ -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

View 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;
}

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View 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

View 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 &param) {
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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,5 @@
//
// Created by Tunm-Air13 on 2023/9/11.
//
#include "feature_block_none.h"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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;
}
}

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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

View 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;
}
}

View File

@@ -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;
}
}

View 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

View 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

View File

@@ -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));
}
}

View 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;
}
}

View 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;
}
}

View 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

View 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;
}
}
}

View File

@@ -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

View File

@@ -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

View 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);
}
}
}

View 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

View File

@@ -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

View 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());
}
}
}

View 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();
}
}

View File

@@ -0,0 +1,300 @@
#include <assert.h>
#include <iterator>
#include <sstream>
#include "yaml-cpp/exceptions.h"
#include "yaml-cpp/node/detail/memory.h"
#include "yaml-cpp/node/detail/node.h" // IWYU pragma: keep
#include "yaml-cpp/node/detail/node_data.h"
#include "yaml-cpp/node/detail/node_iterator.h"
#include "yaml-cpp/node/ptr.h"
#include "yaml-cpp/node/type.h"
namespace YAML {
namespace detail {
std::string node_data::empty_scalar;
node_data::node_data()
: m_isDefined(false),
m_mark(Mark::null_mark()),
m_type(NodeType::Null),
m_style(EmitterStyle::Default),
m_seqSize(0) {}
void node_data::mark_defined() {
if (m_type == NodeType::Undefined)
m_type = NodeType::Null;
m_isDefined = true;
}
void node_data::set_mark(const Mark& mark) { m_mark = mark; }
void node_data::set_type(NodeType::value type) {
if (type == NodeType::Undefined) {
m_type = type;
m_isDefined = false;
return;
}
m_isDefined = true;
if (type == m_type)
return;
m_type = type;
switch (m_type) {
case NodeType::Null:
break;
case NodeType::Scalar:
m_scalar.clear();
break;
case NodeType::Sequence:
reset_sequence();
break;
case NodeType::Map:
reset_map();
break;
case NodeType::Undefined:
assert(false);
break;
}
}
void node_data::set_tag(const std::string& tag) { m_tag = tag; }
void node_data::set_style(EmitterStyle::value style) { m_style = style; }
void node_data::set_null() {
m_isDefined = true;
m_type = NodeType::Null;
}
void node_data::set_scalar(const std::string& scalar) {
m_isDefined = true;
m_type = NodeType::Scalar;
m_scalar = scalar;
}
// size/iterator
std::size_t node_data::size() const {
if (!m_isDefined)
return 0;
switch (m_type) {
case NodeType::Sequence:
compute_seq_size();
return m_seqSize;
case NodeType::Map:
compute_map_size();
return m_map.size() - m_undefinedPairs.size();
default:
return 0;
}
return 0;
}
void node_data::compute_seq_size() const {
while (m_seqSize < m_sequence.size() && m_sequence[m_seqSize]->is_defined())
m_seqSize++;
}
void node_data::compute_map_size() const {
kv_pairs::iterator it = m_undefinedPairs.begin();
while (it != m_undefinedPairs.end()) {
kv_pairs::iterator jt = std::next(it);
if (it->first->is_defined() && it->second->is_defined())
m_undefinedPairs.erase(it);
it = jt;
}
}
const_node_iterator node_data::begin() const {
if (!m_isDefined)
return const_node_iterator();
switch (m_type) {
case NodeType::Sequence:
return const_node_iterator(m_sequence.begin());
case NodeType::Map:
return const_node_iterator(m_map.begin(), m_map.end());
default:
return const_node_iterator();
}
}
node_iterator node_data::begin() {
if (!m_isDefined)
return node_iterator();
switch (m_type) {
case NodeType::Sequence:
return node_iterator(m_sequence.begin());
case NodeType::Map:
return node_iterator(m_map.begin(), m_map.end());
default:
return node_iterator();
}
}
const_node_iterator node_data::end() const {
if (!m_isDefined)
return const_node_iterator();
switch (m_type) {
case NodeType::Sequence:
return const_node_iterator(m_sequence.end());
case NodeType::Map:
return const_node_iterator(m_map.end(), m_map.end());
default:
return const_node_iterator();
}
}
node_iterator node_data::end() {
if (!m_isDefined)
return node_iterator();
switch (m_type) {
case NodeType::Sequence:
return node_iterator(m_sequence.end());
case NodeType::Map:
return node_iterator(m_map.end(), m_map.end());
default:
return node_iterator();
}
}
// sequence
void node_data::push_back(node& node, shared_memory_holder /* pMemory */) {
if (m_type == NodeType::Undefined || m_type == NodeType::Null) {
m_type = NodeType::Sequence;
reset_sequence();
}
if (m_type != NodeType::Sequence)
throw BadPushback();
m_sequence.push_back(&node);
}
void node_data::insert(node& key, node& 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 BadSubscript();
}
insert_map_pair(key, value);
}
// indexing
node* node_data::get(node& key, shared_memory_holder /* pMemory */) const {
if (m_type != NodeType::Map) {
return NULL;
}
for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
if (it->first->is(key))
return it->second;
}
return NULL;
}
node& node_data::get(node& key, 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 BadSubscript();
}
for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
if (it->first->is(key))
return *it->second;
}
node& value = pMemory->create_node();
insert_map_pair(key, value);
return value;
}
bool node_data::remove(node& key, shared_memory_holder /* pMemory */) {
if (m_type != NodeType::Map)
return false;
for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) {
if (it->first->is(key)) {
m_map.erase(it);
return true;
}
}
return false;
}
void node_data::reset_sequence() {
m_sequence.clear();
m_seqSize = 0;
}
void node_data::reset_map() {
m_map.clear();
m_undefinedPairs.clear();
}
void node_data::insert_map_pair(node& key, node& value) {
m_map.emplace_back(&key, &value);
if (!key.is_defined() || !value.is_defined())
m_undefinedPairs.emplace_back(&key, &value);
}
void node_data::convert_to_map(shared_memory_holder pMemory) {
switch (m_type) {
case NodeType::Undefined:
case NodeType::Null:
reset_map();
m_type = NodeType::Map;
break;
case NodeType::Sequence:
convert_sequence_to_map(pMemory);
break;
case NodeType::Map:
break;
case NodeType::Scalar:
assert(false);
break;
}
}
void node_data::convert_sequence_to_map(shared_memory_holder pMemory) {
assert(m_type == NodeType::Sequence);
reset_map();
for (std::size_t i = 0; i < m_sequence.size(); i++) {
std::stringstream stream;
stream << i;
node& key = pMemory->create_node();
key.set_scalar(stream.str());
insert_map_pair(key, *m_sequence[i]);
}
reset_sequence();
m_type = NodeType::Map;
}
}
}

View File

@@ -0,0 +1,130 @@
#include <assert.h>
#include <cassert>
#include "nodebuilder.h"
#include "yaml-cpp/node/detail/node.h"
#include "yaml-cpp/node/impl.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/type.h"
namespace YAML {
struct Mark;
NodeBuilder::NodeBuilder()
: m_pMemory(new detail::memory_holder), m_pRoot(0), m_mapDepth(0) {
m_anchors.push_back(0); // since the anchors start at 1
}
NodeBuilder::~NodeBuilder() {}
Node NodeBuilder::Root() {
if (!m_pRoot)
return Node();
return Node(*m_pRoot, m_pMemory);
}
void NodeBuilder::OnDocumentStart(const Mark&) {}
void NodeBuilder::OnDocumentEnd() {}
void NodeBuilder::OnNull(const Mark& mark, anchor_t anchor) {
detail::node& node = Push(mark, anchor);
node.set_null();
Pop();
}
void NodeBuilder::OnAlias(const Mark& /* mark */, anchor_t anchor) {
detail::node& node = *m_anchors[anchor];
Push(node);
Pop();
}
void NodeBuilder::OnScalar(const Mark& mark, const std::string& tag,
anchor_t anchor, const std::string& value) {
detail::node& node = Push(mark, anchor);
node.set_scalar(value);
node.set_tag(tag);
Pop();
}
void NodeBuilder::OnSequenceStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style) {
detail::node& node = Push(mark, anchor);
node.set_tag(tag);
node.set_type(NodeType::Sequence);
node.set_style(style);
}
void NodeBuilder::OnSequenceEnd() { Pop(); }
void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style) {
detail::node& node = Push(mark, anchor);
node.set_type(NodeType::Map);
node.set_tag(tag);
node.set_style(style);
m_mapDepth++;
}
void NodeBuilder::OnMapEnd() {
assert(m_mapDepth > 0);
m_mapDepth--;
Pop();
}
detail::node& NodeBuilder::Push(const Mark& mark, anchor_t anchor) {
detail::node& node = m_pMemory->create_node();
node.set_mark(mark);
RegisterAnchor(anchor, node);
Push(node);
return node;
}
void NodeBuilder::Push(detail::node& node) {
const bool needsKey =
(!m_stack.empty() && m_stack.back()->type() == NodeType::Map &&
m_keys.size() < m_mapDepth);
m_stack.push_back(&node);
if (needsKey)
m_keys.push_back(PushedKey(&node, false));
}
void NodeBuilder::Pop() {
assert(!m_stack.empty());
if (m_stack.size() == 1) {
m_pRoot = m_stack[0];
m_stack.pop_back();
return;
}
detail::node& node = *m_stack.back();
m_stack.pop_back();
detail::node& collection = *m_stack.back();
if (collection.type() == NodeType::Sequence) {
collection.push_back(node, m_pMemory);
} else if (collection.type() == NodeType::Map) {
assert(!m_keys.empty());
PushedKey& key = m_keys.back();
if (key.second) {
collection.insert(*key.first, node, m_pMemory);
m_keys.pop_back();
} else {
key.second = true;
}
} else {
assert(false);
m_stack.clear();
}
}
void NodeBuilder::RegisterAnchor(anchor_t anchor, detail::node& node) {
if (anchor) {
assert(anchor == m_anchors.size());
m_anchors.push_back(&node);
}
}
}

View File

@@ -0,0 +1,70 @@
#ifndef NODE_NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODE_NODEBUILDER_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 "yaml-cpp/anchor.h"
#include "yaml-cpp/emitterstyle.h"
#include "yaml-cpp/eventhandler.h"
#include "yaml-cpp/node/ptr.h"
namespace YAML {
namespace detail {
class node;
} // namespace detail
struct Mark;
} // namespace YAML
namespace YAML {
class Node;
class NodeBuilder : public EventHandler {
public:
NodeBuilder();
virtual ~NodeBuilder();
Node Root();
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:
detail::node& Push(const Mark& mark, anchor_t anchor);
void Push(detail::node& node);
void Pop();
void RegisterAnchor(anchor_t anchor, detail::node& node);
private:
detail::shared_memory_holder m_pMemory;
detail::node* m_pRoot;
typedef std::vector<detail::node*> Nodes;
Nodes m_stack;
Nodes m_anchors;
typedef std::pair<detail::node*, bool> PushedKey;
std::vector<PushedKey> m_keys;
std::size_t m_mapDepth;
};
}
#endif // NODE_NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -0,0 +1,101 @@
#include "nodeevents.h"
#include "yaml-cpp/eventhandler.h"
#include "yaml-cpp/mark.h"
#include "yaml-cpp/node/detail/node.h"
#include "yaml-cpp/node/detail/node_iterator.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/type.h"
namespace YAML {
void NodeEvents::AliasManager::RegisterReference(const detail::node& node) {
m_anchorByIdentity.insert(std::make_pair(node.ref(), _CreateNewAnchor()));
}
anchor_t NodeEvents::AliasManager::LookupAnchor(
const detail::node& node) const {
AnchorByIdentity::const_iterator it = m_anchorByIdentity.find(node.ref());
if (it == m_anchorByIdentity.end())
return 0;
return it->second;
}
NodeEvents::NodeEvents(const Node& node)
: m_pMemory(node.m_pMemory), m_root(node.m_pNode) {
if (m_root)
Setup(*m_root);
}
void NodeEvents::Setup(const detail::node& node) {
int& refCount = m_refCount[node.ref()];
refCount++;
if (refCount > 1)
return;
if (node.type() == NodeType::Sequence) {
for (detail::const_node_iterator it = node.begin(); it != node.end(); ++it)
Setup(**it);
} else if (node.type() == NodeType::Map) {
for (detail::const_node_iterator it = node.begin(); it != node.end();
++it) {
Setup(*it->first);
Setup(*it->second);
}
}
}
void NodeEvents::Emit(EventHandler& handler) {
AliasManager am;
handler.OnDocumentStart(Mark());
if (m_root)
Emit(*m_root, handler, am);
handler.OnDocumentEnd();
}
void NodeEvents::Emit(const detail::node& node, EventHandler& handler,
AliasManager& am) const {
anchor_t anchor = NullAnchor;
if (IsAliased(node)) {
anchor = am.LookupAnchor(node);
if (anchor) {
handler.OnAlias(Mark(), anchor);
return;
}
am.RegisterReference(node);
anchor = am.LookupAnchor(node);
}
switch (node.type()) {
case NodeType::Undefined:
break;
case NodeType::Null:
handler.OnNull(Mark(), anchor);
break;
case NodeType::Scalar:
handler.OnScalar(Mark(), node.tag(), anchor, node.scalar());
break;
case NodeType::Sequence:
handler.OnSequenceStart(Mark(), node.tag(), anchor, node.style());
for (detail::const_node_iterator it = node.begin(); it != node.end();
++it)
Emit(**it, handler, am);
handler.OnSequenceEnd();
break;
case NodeType::Map:
handler.OnMapStart(Mark(), node.tag(), anchor, node.style());
for (detail::const_node_iterator it = node.begin(); it != node.end();
++it) {
Emit(*it->first, handler, am);
Emit(*it->second, handler, am);
}
handler.OnMapEnd();
break;
}
}
bool NodeEvents::IsAliased(const detail::node& node) const {
RefCount::const_iterator it = m_refCount.find(node.ref());
return it != m_refCount.end() && it->second > 1;
}
}

View File

@@ -0,0 +1,64 @@
#ifndef NODE_NODEEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODE_NODEEVENTS_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 <map>
#include <vector>
#include "yaml-cpp/anchor.h"
#include "yaml-cpp/node/ptr.h"
namespace YAML {
namespace detail {
class node;
} // namespace detail
} // namespace YAML
namespace YAML {
class EventHandler;
class Node;
class NodeEvents {
public:
explicit NodeEvents(const Node& node);
void Emit(EventHandler& handler);
private:
class AliasManager {
public:
AliasManager() : m_curAnchor(0) {}
void RegisterReference(const detail::node& node);
anchor_t LookupAnchor(const detail::node& node) const;
private:
anchor_t _CreateNewAnchor() { return ++m_curAnchor; }
private:
typedef std::map<const detail::node_ref*, anchor_t> AnchorByIdentity;
AnchorByIdentity m_anchorByIdentity;
anchor_t m_curAnchor;
};
void Setup(const detail::node& node);
void Emit(const detail::node& node, EventHandler& handler,
AliasManager& am) const;
bool IsAliased(const detail::node& node) const;
private:
detail::shared_memory_holder m_pMemory;
detail::node* m_root;
typedef std::map<const detail::node_ref*, int> RefCount;
RefCount m_refCount;
};
}
#endif // NODE_NODEEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -0,0 +1,10 @@
#include "yaml-cpp/null.h"
namespace YAML {
_Null Null;
bool IsNullString(const std::string& str) {
return str.empty() || str == "~" || str == "null" || str == "Null" ||
str == "NULL";
}
}

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