You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

254 lines
9.5 KiB

#pragma once
#include "IAsyncContext.h"
#include "IDescriptor.h"
namespace fsdk {
#ifndef DOXYGEN_SHOULD_SKIP_THIS
DECLARE_SMARTPTR(IStaticDescriptorStorage);
DECLARE_SMARTPTR(IDynamicDescriptorStorage);
DECLARE_SMARTPTR(IIndex);
DECLARE_SMARTPTR(IDenseIndex);
DECLARE_SMARTPTR(IDynamicIndex);
DECLARE_SMARTPTR(IIndexBuilder);
#endif
/// Intergral type used as identification of descriptor in internal storage.
using DescriptorId = size_t;
/**
* @brief Result of index search.
* */
struct SearchResult : MatchingResult {
/// Identificator of descriptor in some storage.
DescriptorId index;
/// Default constructor.
SearchResult() noexcept
: MatchingResult()
, index(std::numeric_limits<DescriptorId>::max())
{}
/**
* @brief Construct structure with parameters.
* @param [in] distance Distance between descriptors.
* @param [in] similarity Similarity between descriptors.
* @param [in] index Index of found descriptors in some storage.
* */
SearchResult(
float distance,
float similarity,
DescriptorId index) noexcept
: MatchingResult(distance, similarity)
, index(index)
{}
};
/**
* @brief Static descriptor storage interface.
* @details You may think of it as read only access to some internal container.
* */
struct IStaticDescriptorStorage {
/**
* @brief Requests descriptor data out of internal storage.
* @param [in] index Identification value of some descriptor. Might be received either
* by using @see IDynamicDescriptorStorage::append methods, or as output of
* @see IIndex::search query. Must be less than @see size().
* @param [out] descriptor Ptr to created descriptor object with correctly set
* version and length. Only changes data of passed descriptor.
* @return Result with error code.
* @see IDescriptor, DescriptorId, Result and FSDKError for details.
* */
virtual Result<FSDKError> descriptorByIndex(
const DescriptorId index,
IDescriptor* descriptor) const noexcept = 0;
/**
* @brief Return version of stored descriptors.
* @return Version of stored descriptors. If not initialized, 0 is returned.
* */
virtual uint32_t getDescriptorVersion() const noexcept = 0;
/**
* @brief Return size of internal storage.
* @return Size of internal storage. If not initialized, 0 is returned.
* */
virtual uint64_t size() const noexcept = 0;
};
/**
* @brief Dynamic descriptor storage interface.
* @details You may think of it as read+write access to some internal container.
* */
struct IDynamicDescriptorStorage
: IStaticDescriptorStorage {
/**
* @brief Appends descriptor to internal storage.
* If used on @see IDynamicIndex graph updates itself too.
* @param [in] descriptor Ptr to created descriptor with correct length, version
* and data.
* @return ResultValue with error code and identification
* of appended descriptor. Such identification might be used to query descriptor
* with @see IStaticDescriptorStorage::descriptorByIndex or remove it from storage
* with @see removeDescriptor.
* @see IDescriptor, DescriptorId, ResultValue and FSDKError for details.
* */
virtual ResultValue<FSDKError, DescriptorId> appendDescriptor(
const IDescriptor* descriptor) noexcept = 0;
/**
* @brief Appends batch of descriptors to internal storage.
* If used on @see IDynamicIndex graph updates itself too.
* @param [in] batch Batch of descriptors with correct length, version and data.
* @return ResultValue with error code and identification
* of the first appended descriptor. Other descriptors from batch are appended
* sequentially in the same order as they are in the batch. Such identification
* might be used to query descriptor with
* @see IStaticDescriptorStorage::descriptorByIndex or remove it from storage
* with @see removeDescriptor.
* @see IDescriptorBatch, DescriptorId, ResultValue and FSDKError for details.
* */
virtual ResultValue<FSDKError, DescriptorId> appendBatch(
const IDescriptorBatch* batch) noexcept = 0;
/**
* @brief Removes descriptor out of internal storage.
* If used on @see IDynamicIndex graph updates itself too.
* @note IMPORTANT: If used on @see IDynamicIndex it will NOT actually erase
* descriptor with given index out of internal storage. Instead, it will
* remove it out of graph, so it is not searchable.
* @note If used on @see IIndexBuilder, it WILL actually erase it. But beware:
* if your storage is big enough performance might be very poor, because
* descriptors are stored sequentially in vector-like data structure, so every
* element after erased will be moved.
* @param [in] index Identification of descriptors position in internal storage.
* Is received by using append methods or @IIndex::search.
* @return Result with error code.
* @see DescriptorId, Result and FSDKError for details.
* */
virtual Result<FSDKError> removeDescriptor(const DescriptorId index) noexcept = 0;
};
/**
* @brief Base index interface.
* @details You may think of index as some data structure optimized for search queries.
* */
struct IIndex
: IRefCounted {
/**
* @brief Search for descriptors with the shorter distance to passed descriptor.
* @param [in] reference Descriptor to match against index.
* @param [in] maxResultsCount Maximum count of results. It is upper bound value, it
* does not guarantee to return exactly this amount of results.
* @param [out] results C-Array of at least @see maxResultsCount size. Is filled with
* query results.
* @return ResultValue with error code and count of found descriptors.
* @see IDescriptor, SearchResult, ResultValue and FSDKError for details.
* */
virtual ResultValue<FSDKError, int> search(
const IDescriptor* reference,
int maxResultsCount,
SearchResult* results) const noexcept = 0;
};
/**
* @brief Dense (read only) index interface.
* */
struct IDenseIndex
: IStaticDescriptorStorage
, IIndex {
};
/**
* @brief Dynamic index interface.
* */
struct IDynamicIndex
: IDynamicDescriptorStorage
, IIndex {
/**
* @brief Saves index as dense.
* @details To load saved index use @see IFaceEngine::loadDenseIndex method.
* Dense index cannot be loaded as dynamic.
* @param [in] path Path to file to be created and filled with index data. Any
* extension is acceptable.
* @return Result with error code.
* @see Result and FSDKError for details.
* */
virtual Result<FSDKError> saveToDenseIndex(const char* path) const noexcept = 0;
/**
* @brief Saves index as dynamic.
* @details To load saved index use @see IFaceEngine::loadDynamicIndex method.
* Dynamic index cannot be loaded as dense.
* @param [in] path Path to file to be created and filled with index data. Any
* extension is acceptable.
* @return Result with error code.
* @see Result and FSDKError for details.
* */
virtual Result<FSDKError> saveToDynamicIndex(const char* path) const noexcept = 0;
/**
* @brief Returns count of indexed descriptors.
* @details You may wonder why this method exists if IDynamicIndex already
* inherits IStaticDescriptorStorage::size method. The reason is that
* @see IDynamicDescriptorStorage::removeDescriptor behaves differently on
* @see IIndexBuild and IDynamicIndex. On builder it does actually erases
* descriptor out of internal storage, but it does not erase it if used on
* IDynamicIndex. The reason is that graph data structure relies on indexes
* being constant, so removeDescriptor only removes it out of graph, so it is not
* discoverable by @see IIndex::search. So this methods returns actuall data
* storage size minus count of removed descriptors.
* @return Count of indexed descriptors.
* */
virtual uint64_t countOfIndexedDescriptors() const noexcept = 0;
};
/**
* @brief Progress tracker interface.
* @details Implement this interface to be able to get progress info on some operation.
* */
struct IProgressTracker {
/**
* @brief Function is called on some operation progress change.
* @param [in] completion float value in [0..1] range.
* */
virtual void progress(const float completion) const noexcept = 0;
};
/**
* @brief Index builder interface.
* */
struct IIndexBuilder
: IDynamicDescriptorStorage
, IRefCounted {
/**
* @brief Builds index with every descriptor appended. Blocks until completed.
* @details Is very heavy method in terms of computing load.
* @param [in] progressTracker Some object that is being reported to with progress.
* If its nullptr, dont report progress.
* @return ResultValue with error code and created index object.
* @see IProgressTracker, IDynamicIndex, ResultValue and FSDKError for details.
* */
virtual ResultValue<FSDKError, IDynamicIndex*> buildIndex(
const IProgressTracker* const progressTracker = nullptr) noexcept = 0;
/**
* @brief Builds index with every descriptor appended. Non blocking operation.
* @details Is very heavy method in terms of computing load.
* @param [in] asyncContext Asynchronous context to run build on.
* @param [in] progressTracker Some object that is being reported to with progress.
* If its nullptr, dont report progress.
* @return ResultValue with error code and created index object.
* @see IAsyncContext, IProgressTracker, Future, IDynamicIndex, ResultValue and FSDKError for details.
* */
virtual ResultValue<FSDKError, Future<ResultValue<FSDKError, IDynamicIndex*>>>
buildIndexAsync(
IAsyncContext* const asyncContext,
const IProgressTracker* const progressTracker = nullptr) noexcept = 0;
};
}