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

1 year ago
  1. #pragma once
  2. #include "IAsyncContext.h"
  3. #include "IDescriptor.h"
  4. namespace fsdk {
  5. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  6. DECLARE_SMARTPTR(IStaticDescriptorStorage);
  7. DECLARE_SMARTPTR(IDynamicDescriptorStorage);
  8. DECLARE_SMARTPTR(IIndex);
  9. DECLARE_SMARTPTR(IDenseIndex);
  10. DECLARE_SMARTPTR(IDynamicIndex);
  11. DECLARE_SMARTPTR(IIndexBuilder);
  12. #endif
  13. /// Intergral type used as identification of descriptor in internal storage.
  14. using DescriptorId = size_t;
  15. /**
  16. * @brief Result of index search.
  17. * */
  18. struct SearchResult : MatchingResult {
  19. /// Identificator of descriptor in some storage.
  20. DescriptorId index;
  21. /// Default constructor.
  22. SearchResult() noexcept
  23. : MatchingResult()
  24. , index(std::numeric_limits<DescriptorId>::max())
  25. {}
  26. /**
  27. * @brief Construct structure with parameters.
  28. * @param [in] distance Distance between descriptors.
  29. * @param [in] similarity Similarity between descriptors.
  30. * @param [in] index Index of found descriptors in some storage.
  31. * */
  32. SearchResult(
  33. float distance,
  34. float similarity,
  35. DescriptorId index) noexcept
  36. : MatchingResult(distance, similarity)
  37. , index(index)
  38. {}
  39. };
  40. /**
  41. * @brief Static descriptor storage interface.
  42. * @details You may think of it as read only access to some internal container.
  43. * */
  44. struct IStaticDescriptorStorage {
  45. /**
  46. * @brief Requests descriptor data out of internal storage.
  47. * @param [in] index Identification value of some descriptor. Might be received either
  48. * by using @see IDynamicDescriptorStorage::append methods, or as output of
  49. * @see IIndex::search query. Must be less than @see size().
  50. * @param [out] descriptor Ptr to created descriptor object with correctly set
  51. * version and length. Only changes data of passed descriptor.
  52. * @return Result with error code.
  53. * @see IDescriptor, DescriptorId, Result and FSDKError for details.
  54. * */
  55. virtual Result<FSDKError> descriptorByIndex(
  56. const DescriptorId index,
  57. IDescriptor* descriptor) const noexcept = 0;
  58. /**
  59. * @brief Return version of stored descriptors.
  60. * @return Version of stored descriptors. If not initialized, 0 is returned.
  61. * */
  62. virtual uint32_t getDescriptorVersion() const noexcept = 0;
  63. /**
  64. * @brief Return size of internal storage.
  65. * @return Size of internal storage. If not initialized, 0 is returned.
  66. * */
  67. virtual uint64_t size() const noexcept = 0;
  68. };
  69. /**
  70. * @brief Dynamic descriptor storage interface.
  71. * @details You may think of it as read+write access to some internal container.
  72. * */
  73. struct IDynamicDescriptorStorage
  74. : IStaticDescriptorStorage {
  75. /**
  76. * @brief Appends descriptor to internal storage.
  77. * If used on @see IDynamicIndex graph updates itself too.
  78. * @param [in] descriptor Ptr to created descriptor with correct length, version
  79. * and data.
  80. * @return ResultValue with error code and identification
  81. * of appended descriptor. Such identification might be used to query descriptor
  82. * with @see IStaticDescriptorStorage::descriptorByIndex or remove it from storage
  83. * with @see removeDescriptor.
  84. * @see IDescriptor, DescriptorId, ResultValue and FSDKError for details.
  85. * */
  86. virtual ResultValue<FSDKError, DescriptorId> appendDescriptor(
  87. const IDescriptor* descriptor) noexcept = 0;
  88. /**
  89. * @brief Appends batch of descriptors to internal storage.
  90. * If used on @see IDynamicIndex graph updates itself too.
  91. * @param [in] batch Batch of descriptors with correct length, version and data.
  92. * @return ResultValue with error code and identification
  93. * of the first appended descriptor. Other descriptors from batch are appended
  94. * sequentially in the same order as they are in the batch. Such identification
  95. * might be used to query descriptor with
  96. * @see IStaticDescriptorStorage::descriptorByIndex or remove it from storage
  97. * with @see removeDescriptor.
  98. * @see IDescriptorBatch, DescriptorId, ResultValue and FSDKError for details.
  99. * */
  100. virtual ResultValue<FSDKError, DescriptorId> appendBatch(
  101. const IDescriptorBatch* batch) noexcept = 0;
  102. /**
  103. * @brief Removes descriptor out of internal storage.
  104. * If used on @see IDynamicIndex graph updates itself too.
  105. * @note IMPORTANT: If used on @see IDynamicIndex it will NOT actually erase
  106. * descriptor with given index out of internal storage. Instead, it will
  107. * remove it out of graph, so it is not searchable.
  108. * @note If used on @see IIndexBuilder, it WILL actually erase it. But beware:
  109. * if your storage is big enough performance might be very poor, because
  110. * descriptors are stored sequentially in vector-like data structure, so every
  111. * element after erased will be moved.
  112. * @param [in] index Identification of descriptors position in internal storage.
  113. * Is received by using append methods or @IIndex::search.
  114. * @return Result with error code.
  115. * @see DescriptorId, Result and FSDKError for details.
  116. * */
  117. virtual Result<FSDKError> removeDescriptor(const DescriptorId index) noexcept = 0;
  118. };
  119. /**
  120. * @brief Base index interface.
  121. * @details You may think of index as some data structure optimized for search queries.
  122. * */
  123. struct IIndex
  124. : IRefCounted {
  125. /**
  126. * @brief Search for descriptors with the shorter distance to passed descriptor.
  127. * @param [in] reference Descriptor to match against index.
  128. * @param [in] maxResultsCount Maximum count of results. It is upper bound value, it
  129. * does not guarantee to return exactly this amount of results.
  130. * @param [out] results C-Array of at least @see maxResultsCount size. Is filled with
  131. * query results.
  132. * @return ResultValue with error code and count of found descriptors.
  133. * @see IDescriptor, SearchResult, ResultValue and FSDKError for details.
  134. * */
  135. virtual ResultValue<FSDKError, int> search(
  136. const IDescriptor* reference,
  137. int maxResultsCount,
  138. SearchResult* results) const noexcept = 0;
  139. };
  140. /**
  141. * @brief Dense (read only) index interface.
  142. * */
  143. struct IDenseIndex
  144. : IStaticDescriptorStorage
  145. , IIndex {
  146. };
  147. /**
  148. * @brief Dynamic index interface.
  149. * */
  150. struct IDynamicIndex
  151. : IDynamicDescriptorStorage
  152. , IIndex {
  153. /**
  154. * @brief Saves index as dense.
  155. * @details To load saved index use @see IFaceEngine::loadDenseIndex method.
  156. * Dense index cannot be loaded as dynamic.
  157. * @param [in] path Path to file to be created and filled with index data. Any
  158. * extension is acceptable.
  159. * @return Result with error code.
  160. * @see Result and FSDKError for details.
  161. * */
  162. virtual Result<FSDKError> saveToDenseIndex(const char* path) const noexcept = 0;
  163. /**
  164. * @brief Saves index as dynamic.
  165. * @details To load saved index use @see IFaceEngine::loadDynamicIndex method.
  166. * Dynamic index cannot be loaded as dense.
  167. * @param [in] path Path to file to be created and filled with index data. Any
  168. * extension is acceptable.
  169. * @return Result with error code.
  170. * @see Result and FSDKError for details.
  171. * */
  172. virtual Result<FSDKError> saveToDynamicIndex(const char* path) const noexcept = 0;
  173. /**
  174. * @brief Returns count of indexed descriptors.
  175. * @details You may wonder why this method exists if IDynamicIndex already
  176. * inherits IStaticDescriptorStorage::size method. The reason is that
  177. * @see IDynamicDescriptorStorage::removeDescriptor behaves differently on
  178. * @see IIndexBuild and IDynamicIndex. On builder it does actually erases
  179. * descriptor out of internal storage, but it does not erase it if used on
  180. * IDynamicIndex. The reason is that graph data structure relies on indexes
  181. * being constant, so removeDescriptor only removes it out of graph, so it is not
  182. * discoverable by @see IIndex::search. So this methods returns actuall data
  183. * storage size minus count of removed descriptors.
  184. * @return Count of indexed descriptors.
  185. * */
  186. virtual uint64_t countOfIndexedDescriptors() const noexcept = 0;
  187. };
  188. /**
  189. * @brief Progress tracker interface.
  190. * @details Implement this interface to be able to get progress info on some operation.
  191. * */
  192. struct IProgressTracker {
  193. /**
  194. * @brief Function is called on some operation progress change.
  195. * @param [in] completion float value in [0..1] range.
  196. * */
  197. virtual void progress(const float completion) const noexcept = 0;
  198. };
  199. /**
  200. * @brief Index builder interface.
  201. * */
  202. struct IIndexBuilder
  203. : IDynamicDescriptorStorage
  204. , IRefCounted {
  205. /**
  206. * @brief Builds index with every descriptor appended. Blocks until completed.
  207. * @details Is very heavy method in terms of computing load.
  208. * @param [in] progressTracker Some object that is being reported to with progress.
  209. * If its nullptr, dont report progress.
  210. * @return ResultValue with error code and created index object.
  211. * @see IProgressTracker, IDynamicIndex, ResultValue and FSDKError for details.
  212. * */
  213. virtual ResultValue<FSDKError, IDynamicIndex*> buildIndex(
  214. const IProgressTracker* const progressTracker = nullptr) noexcept = 0;
  215. /**
  216. * @brief Builds index with every descriptor appended. Non blocking operation.
  217. * @details Is very heavy method in terms of computing load.
  218. * @param [in] asyncContext Asynchronous context to run build on.
  219. * @param [in] progressTracker Some object that is being reported to with progress.
  220. * If its nullptr, dont report progress.
  221. * @return ResultValue with error code and created index object.
  222. * @see IAsyncContext, IProgressTracker, Future, IDynamicIndex, ResultValue and FSDKError for details.
  223. * */
  224. virtual ResultValue<FSDKError, Future<ResultValue<FSDKError, IDynamicIndex*>>>
  225. buildIndexAsync(
  226. IAsyncContext* const asyncContext,
  227. const IProgressTracker* const progressTracker = nullptr) noexcept = 0;
  228. };
  229. }