Skip to content

Commit f15d646

Browse files
author
Benedikt Führer
committed
improved const-correctness of internal Block structure as well as API interface
1 parent 1029eff commit f15d646

File tree

2 files changed

+85
-47
lines changed

2 files changed

+85
-47
lines changed

src/fbow.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ void Vocabulary::setParams(int aligment, int k, int desc_type, int desc_size, in
4242

4343
//give memory
4444
_params._total_size=_params._block_size_bytes_wp*_params._nblocks;
45-
_data = Data_ptr((char*)AlignedAlloc(_params._aligment, _params._total_size), &AlignedFree);
45+
_data = std::unique_ptr<char[], decltype(&AlignedFree)>((char*)AlignedAlloc(_params._aligment, _params._total_size), &AlignedFree);
46+
4647
memset(_data.get(), 0, _params._total_size);
4748

4849
}
4950

50-
void Vocabulary::transform(const cv::Mat &features, int level,fBow &result,fBow2&result2){
51+
void Vocabulary::transform(const cv::Mat &features, int level,fBow &result,fBow2&result2) const {
5152
if (features.rows==0) throw std::runtime_error("Vocabulary::transform No input data");
5253
if (features.type()!=_params._desc_type) throw std::runtime_error("Vocabulary::transform features are of different type than vocabulary");
5354
if (features.cols * features.elemSize() !=size_t(_params._desc_size)) throw std::runtime_error("Vocabulary::transform features are of different size than the vocabulary ones");
@@ -88,7 +89,7 @@ void Vocabulary::transform(const cv::Mat &features, int level,fBow &result,fBow2
8889

8990
}
9091

91-
fBow Vocabulary::transform(const cv::Mat &features)
92+
fBow Vocabulary::transform(const cv::Mat &features) const
9293
{
9394
if (features.rows==0) throw std::runtime_error("Vocabulary::transform No input data");
9495
if (features.type()!=_params._desc_type) throw std::runtime_error("Vocabulary::transform features are of different type than vocabulary");
@@ -183,8 +184,8 @@ void Vocabulary::fromStream(std::istream &str)
183184
if (sig!=55824124) throw std::runtime_error("Vocabulary::fromStream invalid signature");
184185
//read string
185186
str.read((char*)&_params,sizeof(params));
186-
_data = Data_ptr((char*)AlignedAlloc(_params._aligment, _params._total_size), &AlignedFree);
187-
if (_data==0) throw std::runtime_error("Vocabulary::fromStream Could not allocate data");
187+
_data = std::unique_ptr<char[], decltype(&AlignedFree)>((char*)AlignedAlloc(_params._aligment, _params._total_size), &AlignedFree);
188+
if (_data.get() == nullptr) throw std::runtime_error("Vocabulary::fromStream Could not allocate data");
188189
str.read(_data.get(), _params._total_size);
189190
}
190191

src/fbow.h

Lines changed: 79 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -72,24 +72,25 @@ class FBOW_API Vocabulary
7272
}
7373

7474
static inline void AlignedFree(void *ptr){
75+
if(ptr==nullptr)return;
7576
unsigned char *uptr=(unsigned char *)ptr;
7677
unsigned char off= *(uptr-1);
7778
uptr-=off;
7879
std::free(uptr);
7980
}
8081

81-
using Data_ptr = std::unique_ptr<char[], decltype(&AlignedFree)>;
82+
// using Data_ptr = std::unique_ptr<char[], decltype(&AlignedFree)>;
8283

8384
friend class VocabularyCreator;
8485

8586
public:
8687

87-
Vocabulary() = default;
88+
Vocabulary(): _data((char*)nullptr,&AlignedFree){}
8889
Vocabulary(Vocabulary&&) = default;
8990

9091
//transform the features stored as rows in the returned BagOfWords
91-
fBow transform(const cv::Mat &features);
92-
void transform(const cv::Mat &features, int level,fBow &result,fBow2&result2);
92+
fBow transform(const cv::Mat &features) const;
93+
void transform(const cv::Mat &features, int level,fBow &result,fBow2&result2) const;
9394

9495

9596
//loads/saves from a file
@@ -107,7 +108,7 @@ class FBOW_API Vocabulary
107108
//returns the branching factor (number of children per node)
108109
uint32_t getK()const{return _params._m_k;}
109110
//indicates whether this object is valid
110-
bool isValid()const{return _data!=0;}
111+
bool isValid()const{return _data.get()!=nullptr;}
111112
//total number of blocks
112113
size_t size()const{return _params._nblocks;}
113114
//removes all data
@@ -129,7 +130,8 @@ class FBOW_API Vocabulary
129130
uint32_t _m_k=0;//number of children per node
130131
};
131132
params _params;
132-
Data_ptr _data = Data_ptr(nullptr, &AlignedFree);//pointer to data
133+
std::unique_ptr<char[], decltype(&AlignedFree)> _data;
134+
133135

134136
//structure represeting a information about node in a block
135137
struct block_node_info{
@@ -168,24 +170,43 @@ class FBOW_API Vocabulary
168170
//CiWi are the so called block_node_info (see structure up)
169171
//Ci : either if the node is leaf (msb is set to 1) or not. If not leaf, the remaining 31 bits is the block where its children are. Else, it is the index of the feature that it represent
170172
//Wi: float value empkoyed to know the weight of a leaf node (employed in cases of bagofwords)
171-
struct Block{
172-
Block(char * bsptr,uint64_t ds,uint64_t ds_wp,uint64_t fo,uint64_t co):_blockstart(bsptr),_desc_size_bytes(ds),_desc_size_bytes_wp(ds_wp),_feature_off_start(fo),_child_off_start(co){}
173+
template<typename T>
174+
struct Block {
175+
176+
// conditionally qualifies its argument as const
177+
// depending on whether T is a const type as well
178+
template<typename TT>
179+
using conditional_const =
180+
std::conditional_t<
181+
std::is_const_v<T>,
182+
std::add_const_t<TT>,
183+
TT>;
184+
185+
Block(T* bsptr,uint64_t ds,uint64_t ds_wp,uint64_t fo,uint64_t co):_blockstart(bsptr),_desc_size_bytes(ds),_desc_size_bytes_wp(ds_wp),_feature_off_start(fo),_child_off_start(co){}
173186
Block(uint64_t ds,uint64_t ds_wp,uint64_t fo,uint64_t co):_desc_size_bytes(ds),_desc_size_bytes_wp(ds_wp),_feature_off_start(fo),_child_off_start(co){}
174187

175-
inline uint16_t getN()const{return (*((uint16_t*)(_blockstart)));}
176-
inline void setN(uint16_t n){ *((uint16_t*)(_blockstart))=n;}
188+
inline uint16_t getN() const { return (*((conditional_const<uint16_t>*)(_blockstart))); }
189+
inline void setN(uint16_t n) { *((conditional_const<uint16_t>*)(_blockstart)) = n; }
190+
191+
inline bool isLeaf() const { return *((conditional_const<uint16_t>*)(_blockstart) + 1); }
192+
inline void setLeaf(bool v) { *((conditional_const<uint16_t>*)(_blockstart) + 1) = 1; }
177193

178-
inline bool isLeaf()const{return *((uint16_t*)(_blockstart)+1);}
179-
inline void setLeaf(bool v)const{*((uint16_t*)(_blockstart)+1)=1;}
194+
inline void setParentId(uint32_t pid) { *(((conditional_const<uint32_t>*)(_blockstart)) + 1) = pid; }
195+
inline uint32_t getParentId() const { return *(((conditional_const<uint32_t>*)(_blockstart)) + 1); }
180196

181-
inline void setParentId(uint32_t pid){*(((uint32_t*)(_blockstart))+1)=pid;}
182-
inline uint32_t getParentId(){ return *(((uint32_t*)(_blockstart))+1);}
197+
inline conditional_const<block_node_info>* getBlockNodeInfo(int i) const
198+
{ return (conditional_const<block_node_info>*)(_blockstart + _child_off_start + i * sizeof(block_node_info)); }
183199

184-
inline block_node_info * getBlockNodeInfo(int i){ return (block_node_info *)(_blockstart+_child_off_start+i*sizeof(block_node_info)); }
185-
inline void setFeature(int i,const cv::Mat &feature){memcpy( _blockstart+_feature_off_start+i*_desc_size_bytes_wp,feature.ptr<char>(0),feature.elemSize1()*feature.cols); }
186-
inline void getFeature(int i,cv::Mat feature){ memcpy( feature.ptr<char>(0), _blockstart+_feature_off_start+i*_desc_size_bytes,_desc_size_bytes ); }
187-
template<typename T> inline T*getFeature(int i){return (T*) (_blockstart+_feature_off_start+i*_desc_size_bytes_wp);}
188-
char *_blockstart;
200+
inline void setFeature(int i,const cv::Mat &feature)
201+
{ memcpy(_blockstart + _feature_off_start + i * _desc_size_bytes_wp, feature.ptr<char>(0), feature.elemSize1()*feature.cols); }
202+
203+
inline void getFeature(int i,cv::Mat feature) const
204+
{ memcpy(feature.ptr<char>(0), _blockstart + _feature_off_start + i * _desc_size_bytes, _desc_size_bytes); }
205+
206+
template<typename T> inline conditional_const<T>*getFeature(int i)
207+
{ return (conditional_const<T>*)(_blockstart + _feature_off_start + i * _desc_size_bytes_wp); }
208+
209+
T* _blockstart;
189210
uint64_t _desc_size_bytes=0;//size of the descriptor(without padding)
190211
uint64_t _desc_size_bytes_wp=0;//size of the descriptor(includding padding)
191212
uint64_t _feature_off_start=0;
@@ -194,12 +215,26 @@ class FBOW_API Vocabulary
194215

195216

196217
//returns a block structure pointing at block b
197-
inline Block getBlock(uint32_t b) { assert(_data != 0); assert(b < _params._nblocks); return Block(_data.get() + b * _params._block_size_bytes_wp, _params._desc_size, _params._desc_size_bytes_wp, _params._feature_off_start, _params._child_off_start); }
218+
inline Block<const char> getBlock(uint32_t b) const
219+
{
220+
assert(_data != nullptr);
221+
assert(b < _params._nblocks);
222+
return Block<const char>(const_cast<const char*>(_data.get()) + b * _params._block_size_bytes_wp, _params._desc_size, _params._desc_size_bytes_wp, _params._feature_off_start, _params._child_off_start);
223+
}
224+
225+
inline Block<char> getBlock(uint32_t b)
226+
{
227+
assert(_data != nullptr);
228+
assert(b < _params._nblocks);
229+
return Block<char>(_data.get() + b * _params._block_size_bytes_wp, _params._desc_size, _params._desc_size_bytes_wp, _params._feature_off_start, _params._child_off_start);
230+
}
231+
198232
//given a block already create with getBlock, moves it to point to block b
199-
inline void setBlock(uint32_t b, Block &block) { block._blockstart = _data.get() + b * _params._block_size_bytes_wp; }
233+
template<typename T>
234+
inline void setBlock(uint32_t b, Block<T>& block) const { block._blockstart = _data.get() + b * _params._block_size_bytes_wp; }
200235

201236
//information about the cpu so that mmx,sse or avx extensions can be employed
202-
std::shared_ptr<cpu> cpu_info;
237+
mutable std::shared_ptr<cpu> cpu_info;
203238

204239

205240
////////////////////////////////////////////////////////////
@@ -226,33 +261,33 @@ class FBOW_API Vocabulary
226261
memset(feature,0,_nwords*sizeof(register_type ));
227262
}
228263
inline void startwithfeature(const register_type *feat_ptr){memcpy(feature,feat_ptr,_desc_size);}
229-
virtual distType computeDist(register_type *fptr)=0;
264+
virtual distType computeDist(const register_type *fptr)=0;
230265

231266
};
232267

233268

234269
struct L2_generic:public Lx<float,float,4>{
235270
virtual ~L2_generic(){ }
236-
inline float computeDist(float *fptr){
271+
inline float computeDist(const float *fptr){
237272
float d=0;
238273
for(int f=0;f<_nwords;f++) d+= (feature[f]-fptr[f])*(feature[f]-fptr[f]);
239274
return d;
240275
}
241276
};
242277
#ifdef __ANDROID__
243278
//fake elements to allow compilation
244-
struct L2_avx_generic:public Lx<uint64_t,float,32>{inline float computeDist(uint64_t *ptr){return std::numeric_limits<float>::max();}};
245-
struct L2_se3_generic:public Lx<uint64_t,float,32>{inline float computeDist(uint64_t *ptr){return std::numeric_limits<float>::max();}};
246-
struct L2_sse3_16w:public Lx<uint64_t,float,32>{inline float computeDist(uint64_t *ptr){return std::numeric_limits<float>::max();}};
247-
struct L2_avx_8w:public Lx<uint64_t,float,32>{inline float computeDist(uint64_t *ptr){return std::numeric_limits<float>::max();}};
279+
struct L2_avx_generic:public Lx<uint64_t,float,32>{inline float computeDist(const uint64_t *ptr){return std::numeric_limits<float>::max();}};
280+
struct L2_se3_generic:public Lx<uint64_t,float,32>{inline float computeDist(const uint64_t *ptr){return std::numeric_limits<float>::max();}};
281+
struct L2_sse3_16w:public Lx<uint64_t,float,32>{inline float computeDist(const uint64_t *ptr){return std::numeric_limits<float>::max();}};
282+
struct L2_avx_8w:public Lx<uint64_t,float,32>{inline float computeDist(const uint64_t *ptr){return std::numeric_limits<float>::max();}};
248283

249284

250285

251286

252287
#else
253288
struct L2_avx_generic:public Lx<__m256,float,32>{
254289
virtual ~L2_avx_generic(){}
255-
inline float computeDist(__m256 *ptr){
290+
inline float computeDist(const __m256 *ptr){
256291
__m256 sum=_mm256_setzero_ps(), sub_mult;
257292
//substract, multiply and accumulate
258293
for(int i=0;i<_nwords;i++){
@@ -267,7 +302,7 @@ class FBOW_API Vocabulary
267302
}
268303
};
269304
struct L2_se3_generic:public Lx<__m128,float,16>{
270-
inline float computeDist(__m128 *ptr){
305+
inline float computeDist(const __m128 *ptr){
271306
__m128 sum=_mm_setzero_ps(), sub_mult;
272307
//substract, multiply and accumulate
273308
for(int i=0;i<_nwords;i++){
@@ -283,7 +318,7 @@ class FBOW_API Vocabulary
283318
};
284319
struct L2_sse3_16w:public Lx<__m128,float,16> {
285320

286-
inline float computeDist(__m128 *ptr){
321+
inline float computeDist(const __m128 *ptr){
287322
__m128 sum=_mm_setzero_ps(), sub_mult;
288323
//substract, multiply and accumulate
289324
for(int i=0;i<16;i++){
@@ -300,7 +335,7 @@ class FBOW_API Vocabulary
300335
//specific for surf in avx
301336
struct L2_avx_8w:public Lx<__m256,float,32> {
302337

303-
inline float computeDist(__m256 *ptr){
338+
inline float computeDist(const __m256 *ptr){
304339
__m256 sum=_mm256_setzero_ps(), sub_mult;
305340
//substract, multiply and accumulate
306341

@@ -321,15 +356,15 @@ class FBOW_API Vocabulary
321356

322357
//generic hamming distance calculator
323358
struct L1_x64:public Lx<uint64_t,uint64_t,8>{
324-
inline uint64_t computeDist(uint64_t *feat_ptr){
359+
inline uint64_t computeDist(const uint64_t *feat_ptr){
325360
uint64_t result = 0;
326361
for(int i = 0; i < _nwords; ++i ) result += std::bitset<64>(feat_ptr[i] ^ feature[i]).count();
327362
return result;
328363
}
329364
};
330365

331366
struct L1_x32:public Lx<uint32_t,uint32_t,8>{
332-
inline uint32_t computeDist(uint32_t *feat_ptr){
367+
inline uint32_t computeDist(const uint32_t *feat_ptr){
333368
uint32_t result = 0;
334369
for(int i = 0; i < _nwords; ++i ) result += std::bitset<32>(feat_ptr[i] ^ feature[i]).count();
335370
return result;
@@ -339,7 +374,7 @@ class FBOW_API Vocabulary
339374

340375
//for orb
341376
struct L1_32bytes:public Lx<uint64_t,uint64_t,8>{
342-
inline uint64_t computeDist(uint64_t *feat_ptr){
377+
inline uint64_t computeDist(const uint64_t *feat_ptr){
343378
return uint64_popcnt(feat_ptr[0]^feature[0])+ uint64_popcnt(feat_ptr[1]^feature[1])+
344379
uint64_popcnt(feat_ptr[2]^feature[2])+uint64_popcnt(feat_ptr[3]^feature[3]);
345380
}
@@ -350,7 +385,7 @@ class FBOW_API Vocabulary
350385
};
351386
//for akaze
352387
struct L1_61bytes:public Lx<uint64_t,uint64_t,8>{
353-
inline uint64_t computeDist(uint64_t *feat_ptr){
388+
inline uint64_t computeDist(const uint64_t *feat_ptr){
354389

355390
return uint64_popcnt(feat_ptr[0]^feature[0])+ uint64_popcnt(feat_ptr[1]^feature[1])+
356391
uint64_popcnt(feat_ptr[2]^feature[2])+uint64_popcnt(feat_ptr[3]^feature[3])+
@@ -364,19 +399,20 @@ class FBOW_API Vocabulary
364399

365400

366401
template<typename Computer>
367-
fBow _transform(const cv::Mat &features){
402+
fBow _transform(const cv::Mat &features) const {
368403
Computer comp;
369404
comp.setParams(_params._desc_size,_params._desc_size_bytes_wp);
370405
using DType=typename Computer::DType;//distance type
371406
using TData=typename Computer::TData;//data type
372407

373408
fBow result;
374409
std::pair<DType,uint32_t> best_dist_idx(std::numeric_limits<uint32_t>::max(),0);//minimum distance found
375-
block_node_info *bn_info;
410+
const block_node_info *bn_info;
376411
for(int cur_feature=0;cur_feature<features.rows;cur_feature++){
377412
comp.startwithfeature(features.ptr<TData>(cur_feature));
378413
//ensure feature is in a
379-
Block c_block=getBlock(0);
414+
//(jbfuehrer: template type can automatically be deduced since C++17)
415+
Block<const char> c_block=getBlock(0);
380416
//copy to another structure and add padding with zeros
381417
do{
382418
//given the current block, finds the node with minimum distance
@@ -397,7 +433,7 @@ class FBOW_API Vocabulary
397433
return result;
398434
}
399435
template<typename Computer>
400-
void _transform2(const cv::Mat &features,uint32_t storeLevel,fBow &r1,fBow2 &r2){
436+
void _transform2(const cv::Mat &features,uint32_t storeLevel,fBow &r1,fBow2 &r2) const {
401437
Computer comp;
402438
comp.setParams(_params._desc_size,_params._desc_size_bytes_wp);
403439
using DType=typename Computer::DType;//distance type
@@ -406,12 +442,13 @@ class FBOW_API Vocabulary
406442
r1.clear();
407443
r2.clear();
408444
std::pair<DType,uint32_t> best_dist_idx(std::numeric_limits<uint32_t>::max(),0);//minimum distance found
409-
block_node_info *bn_info;
445+
const block_node_info *bn_info;
410446
int nbits=ceil(log2(_params._m_k));
411447
for(int cur_feature=0;cur_feature<features.rows;cur_feature++){
412448
comp.startwithfeature(features.ptr<TData>(cur_feature));
413449
//ensure feature is in a
414-
Block c_block=getBlock(0);
450+
//(jbfuehrer: template type can automatically be deduced since C++17)
451+
Block<const char> c_block=getBlock(0);
415452
uint32_t level=0;//current level of recursion
416453
uint32_t curNode=0;//id of the current node of the tree
417454
//copy to another structure and add padding with zeros

0 commit comments

Comments
 (0)