Boost multi_index_container with composite_key and bitwise-and comparison - c++

I want to achieve something like this with boost multi_index_container and composite_key:
struct LogicalAnd {
bool operator()(const int& argVal1, const int& argVal2) const {
return int(argVal1 & argVal2) == argVal1;
}
};
template<class T, class Enable = void>
class FooContainer;
template <class T>
struct FooContainer<T,typename boost::enable_if<boost::is_base_of<IFoo, T> >::type> {
typedef multi_index_container<
boost::shared_ptr<T>,
indexed_by<
hashed_non_unique<
composite_key<
T,
const_mem_fun<T,int,&T::getKey1>,
const_mem_fun<T,int,&T::getKey2>
>,
composite_key_equal_to<
LogicalAnd,
LogicalAnd
>
>
>
> shared_ptr_type;
};
Knowing that:
namespace CustomKey {
typedef enum {
VAL1 = 0x00000001,
VAL2 = 0x00000002,
ALL = 0xFFFFFFFF
} type;
}
The goal is to be able to perform the following:
container.find(boost::make_tuple(CustomKey::VAL1, CustomKey::ALL));
Which would allow me to retrieve all elements for which LogicalAnd returns true.
The problem is that I can't manage to get my LogicalAnd comparator to work with my multi_index_container.
I can get it to build by adding a composite_key_hash right before composite_key_equal_to:
composite_key_hash<
boost::hash<int>,
boost::hash<int>
>
But find operation does not work as expected so it does not change much...
I've searched boost documentation, and I've tryed various implementations, but I'm getting drown in the amount of information...
Any help is appreciated!

You're using a hash for your multi-index.
That means the LogicalAnd comparator never gets called unless something is found in the right hash bucket.
0x01 and 0xFF don't hash to the same value even though 0x01 & 0xFF == 0x01. That is, LogicalAnd would return true, but it's never invoked.
You would need a hash function which is invariant wrt. LogicalAnd, and I don't think that's possible. By design most hash functions are supposed to minimise collisions between different key values.
You need to come up with some different indexing system, I'm afraid.

Related

How to fix error c3848 or c2676 in c++ for this easy code

I am a beginner of C++, and I code what The Cherno teaches in his 100th video of the C++ series, showing at 16:50. But VS is always giving me error.
If without commenting the const part, VS gives me error c3848. After adding const, VS give me error c2676.
I have checked the way to use std::hash on cppreference, and searched for the error on Google, but get nothing. It's just "a little bit" too hard for a beginner like me.
Below is the code.
#include<iostream>
#include<map>
#include<unordered_map>
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longtitude;
};
namespace std {
template<>
struct hash<CityRecord>
{
size_t operator()(const CityRecord& key) //const noexcept
{
return hash<std::string>()(key.Name);
}
};
}
int main()
{
std::unordered_map<CityRecord, uint32_t> foundedMap;
foundedMap[CityRecord{ "London", 500000, 2.4, 9.4 }] = 1850;
uint32_t NewYorkYear = foundedMap[CityRecord{ "NY", 7000000, 2.4, 9.4 }];
}
As a beginner, I just want to know how to use the hash function in this case.
There is a much easier solution, without opening the std namespace and specializing the std::hash
If you look at the definition of the std::unordered_map in the CPP reference here, then you will read:
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;
It is clear and normal, to hand in template parameters for the key-type and the value-type value. However, if the key-type if a custom type, like in your case, then you need to add additional functionality.
First, you need to add hash functionionality. If you read here about std::hash, then the only function the will be called is the "function call operator".
And this must be a "const" function, which will fix one of your problems.
And of course, you may add this function to your struct. That is completely OK. Please see in the example code below. With taht, you can give your own class as a template parameter for the hash functionality to the std::unordered_map. Cool.
If we look at the next template parameter of the std::unordered_map, then we will find std::equal_to. And if we read about this in cppreference, then we will find the following statement:
Function object for performing comparisons. Unless specialised, invokes operator== on type T.
So, we need to add a comparison operator == to your custom struct to satisfy requirements.
Please note: It is a good approach to encapsulate the methods operating on the data of classes within the class and not define them as free functions. Because only the methods of the class should work on the data of the class. If you would later change something in a class and have a free function doing work on the class members. So, please try to follow that approach.
Then, next, the comparison. So, we define the "operator ==" in your class and then have to compare element by element.
For easing up this task, there is a library function called std::tie. Please see here. This basically creates a std::tuple from the given parameters with the advantage, that all comparison functions are already defined and can be immediately reused.
By following the above described approach, the whole implementation will be much simpler.
Please see the below example code:
#include<iostream>
#include<map>
#include<unordered_map>
#include<tuple>
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longtitude;
// For std::equal_to
bool operator == (const CityRecord& cr) const { return std::tie(Name, Population, Latitude, Longtitude) == std::tie(cr.Name, cr.Population, cr.Latitude, cr.Longtitude); }
// For hashing
size_t operator()(const CityRecord& key) const { return std::hash<std::string>{}(key.Name); }
};
int main() {
// Definition of the unordered_map
std::unordered_map<CityRecord, uint32_t, CityRecord> foundedMap;
// Adding data
foundedMap[CityRecord{ "London", 500000, 2.4, 9.4 }] = 1850;
uint32_t NewYorkYear = foundedMap[CityRecord{ "NY", 7000000, 2.4, 9.4 }];
}
You need to make the overloaded operator() for the specialization of hash for CityRecord a const member function as shown below. Additionally, we also need to overload operator== for CityRecord as shown below:
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longtitude;
//friend declaration for operator== not needed since we've a struct
};
//implement operator==
bool operator==(const CityRecord &lhs, const CityRecord &rhs)
{
return (lhs.Name == rhs.Name) && (lhs.Population == rhs.Population) && (lhs.Latitude ==rhs.Latitude) && (lhs.Longtitude == rhs.Longtitude);
}
namespace std {
template<>
struct hash<CityRecord>
{
//-----------------------------------------------vvvvv-->added this const
size_t operator()(const CityRecord& key) const
{
return hash<std::string>()(key.Name) ^ hash<uint64_t>()(key.Population) ^ hash<double>()(key.Latitude) ^ hash<double>()(key.Longtitude);
}
};
}
Working demo
Here we use an (unnamed) hash<string> object to generate a hash
code for Name, an object of type hash<uint64_t> to generate a hash from Population, and an object of type hash to generate a hash from Latitute and finally an object of type hash<double> to generate a hash from Longitute. Next, we exclusive OR these results to form an overall hash code for the given CityRecord object.
Note that we defined our hash function to hash all the four data members so that our hash function will be compatible with our definition of operator== for CityRecord.

std::map: Use only part of keytype for comparison and finding

I have a map that uses pairs of some datatype KT as keys to map to a matrix type, i.e. sth. like
std::map<std::pair<KT,KT>, MatType, PairCompare>
For comparison I only need the first element of the pair, so PairCompare is very simple
struct PairCompare
{
bool operator()(const std::pair<KT,KT>& lhs,const std::pair<KT,KT>& rhs) const
{return lhs.first<rhs.first;}
};
I would however like to use the whole pair as a key, as I constantly need the second element in operations while iterating through the map.
Sometimes, I also need to find a map entry based on a single KT only. Of course I should use a pair of KT in the find() routine, but I would like to avoid creating a dummy pair of KT, as I have to do this many times and that could get expensive. I would like to use something like
std::map<std::pair<KT,KT>, MatType, PairCompare> mymap;
KT mykey = // ... some implementation of KT;
// fill map
auto it = mymap.find(mykey); // <- will not work of course, but what I would like to use
auto it = mymap.find(std::pair<KT,KT>(mykey,mykey)); // <- what I am using so far (creating a dummy pair)
Mykey can in general be both lvalue and rvalue (in my application).
Is there any way of defining a different type of key that contains two KT instances and only uses one for map ordering and also enables finding by single KTs that works straight forward? Can it be done with some special comparison object? Maybe there is also a smart way of getting around using pairs of KT as Key at all, but still enabling access to the second KT in map iterations?
Thanks for your help!
P.S.: to be precise, as KT I am using
typedef std::vector<int> KT
Your problem is that you think of keys as "pair of X,Y". Think of the key as "an object that supports this and that operations":
template<typename K1, typename K2>
class Key
{
K1 v1_;
boost::optional<K2> v2_;
public:
Key(K1 v1): v1_{ std::move(v1) }, v2_{} {}
Key(K1 v1, K2 v2): v1_{ std::move(v1) }, v2_{ std::move(v2) } {}
bool operator==(const Key<K1,K2>& other)
{
if(!v2_ || !other.v2_)
return v1_ == other.v1_;
return std::tie(v1_, *v2_) == std::tie(other.v1_, *other.v2_);
}
// implement other comparisons, as required
};
using KeyType = Key<int,std::string>;
std::map<KeyType, MatType> YourMap;
// add key comparable by first element:
YourMap[KeyType{0}] = MatType{}; // match KeyType{0, "any string"}
// add key comparable by both elements:
YourMap[KeyType{1, "test"}] = MatType{}; // match KeyType{1, "test"}
Attempting to force the key to be a pair here complicates the problem.

boost::ptree and the KeyCompare function?

The Boost documentation doesn't elaborate much, but there is an (optional) KeyCompare function that can be passed to the ptree.
Anyone have a good example of using a custom KeyCompare function?
I have recently been working with a ptree that is real slow. My keys are long strings (paths), and I assuming it's the string comparisons that make it slow.
From what I can glean, the default KeyCompare is std::less(), I want to change this. I think something that just compares the hashes of the two strings.
It goes without saying (but I'll say it anyway) that I would use a different object for the key to facilitate this: Something that has (std::string+hash), rather than just a std::string. The hash would be calculated during construction.
Thanks,
Rik.
Found this from the boost source code: An example of a case-insensitive KeyCompare:
template<class T>
struct less_nocase
{
typedef typename T::value_type Ch;
std::locale m_locale;
inline bool operator()(Ch c1, Ch c2) const
{
return std::toupper(c1, m_locale) < std::toupper(c2, m_locale);
}
inline bool operator()(const T &t1, const T &t2) const
{
return std::lexicographical_compare(t1.begin(), t1.end(),
t2.begin(), t2.end(), *this);
}
};
Then all you need to do is pass it in to the basic_ptree class:
typedef basic_ptree<std::string, std::string,
less_nocase<std::string> > iptree;

Practices regarding wrapper for setDataBuffer (OCCI)

I have an OracleConnection class that uses the OCCI Oracle API to access the database. I now need to go fetch multiple rows of records from the database and this is done with the ResultSet::getDataBuffer(...) function of the API. This function takes a series of arguments, one of them being a big enum which defines the types of data can contain.
Obviously I don't want to strew my application code with Oracle API types, so other API's could be interchanged with this one. So my question is how would I best take this Type parameter in my function wrapper? Should I just create an enum and take only the types I will need or could templates help me here to map to the enum of OCCI in the OracleConnection class I have?
Occi setDataBuffer function:
void setDataBuffer(
unsigned int colIndex,
void *buffer,
Type type,
sb4 size = 0,
ub2 *length = NULL,
sb2 *ind = NULL,
ub2 *rc = NULL);
Type here is an enum that looks like this:
enum Type
{
OCCI_SQLT_CHR=SQLT_CHR,
OCCI_SQLT_NUM=SQLT_NUM,
OCCIINT = SQLT_INT,
OCCIFLOAT = SQLT_FLT,
OCCIBFLOAT = SQLT_BFLOAT,
OCCIBDOUBLE = SQLT_BDOUBLE,
OCCIIBFLOAT = SQLT_IBFLOAT,
OCCIIBDOUBLE = SQLT_IBDOUBLE,
OCCI_SQLT_STR=SQLT_STR,
OCCI_SQLT_VNU=SQLT_VNU,
OCCI_SQLT_PDN=SQLT_PDN,
OCCI_SQLT_LNG=SQLT_LNG,
OCCI_SQLT_VCS=SQLT_VCS,
.... (about 2x as many to go)
my wrapper looks as follows:
void setDataBuffer(unsigned int colIndex, void * buffer, unsigned long size = 0, int type /*use int or template or redefine own Type Enum?*/, unsigned short * length = NULL, signed short * ind = NULL, unsigned short * rc = NULL)
One option could be to make your function a template, and then use a traits class to convert the template type to the values representing the various Oracle types.
The traits class could look like this:
template <typename T>
struct oracle_type_traits;
template <> // create a specialization for each relevant type
struct oracle_type_traits<double> {
static const value = OCCIBDOUBLE // its value member should be the value you want to map to
};
Now, the following will give you the Oracle type id for a double:
oracle_type_traits<double>::value
and inside setDataBuffer<T>(...), you just check oracle_type_traits<T>::value to get the corresponding Oracle type ID.
From the POV of the users of your wrapper, the best would be if they would call either an overloaded function or a function (member) template that they pass an object to of the appropriate type and which will then magically do the right thing for that type. That is, the best would be to have a function getData(unsigned int colIndex, T&) for any type T your class (or the Oracle API) supports, which will find out the necessary buffer size, allocate the buffer, determine the right enum, and call the Oracle API function.
I'm sure you can work out most of the details, probably with the exception of how to map a type to the enum, so this is what I'll try to line out.
Basically, I see two possibilities for this, one of which (employing a compile-time list) is better suited if you have lots of types to support, while the other one (employing traits) needs to be used if there's more type-specific to this than just mapping a type to an enum.
The traits method is quite simple to use, but tedious if you have many types:
template<typename T>
struct get_data_buffer_traits;
template<>
struct get_data_buffer_traits<int> {
Type type OCCIINT;
};
template<>
struct get_data_buffer_traits<float> {
Type type OCCIBFLOAT;
};
You can then map the type passed to your template as T into the right enum value using get_data_buffer_traits<T>::type.
This traits template is also the place where you can put any other type-specific operation your generic data retrieval function might need (like converting between what's in the buffer and the actual type, if that isn't a straight-forward cast). If you don't have anything else to put into these traits, you could use a macro to make defining these easier:
#define DEFINE_GET_DATA_BUFFER_TRAITS(Type_,Enum_) \
template<> struct get_data_buffer_traits<Type_> { Type type Enum_; };
DEFINE_GET_DATA_BUFFER_TRAITS(int , OCCIINT );
DEFINE_GET_DATA_BUFFER_TRAITS(float, OCCIBFLOAT);
...
#undef DEFINE_GET_DATA_BUFFER_TRAITS
However, if that's the case, you might as well create a compile-time map that maps the two and search that (at compile-time) for the right enum value. If you don't have a template meta library at hand that provides this, here's the outline for an idea how to do that yourself:
// Beware, brain-compiled code ahead!
struct nil {};
template< typename HType
, Type HEnum
, class T >
struct set_data_buffer_type_map_node {
typedef HType head_type
enum { head_enum = HEnum };
typedef T tail_type;
};
typedef
set_data_buffer_type_map_node< int , OCCIINT
set_data_buffer_type_map_node< float, OCCIBFLOAT
...
nil
> > // either count or keep adding these until compiler accepts :)
set_data_buffer_type_map;
template< typename T, class Map >
struct getter {
// recurse towards tail
Type get_enum() { return getter<T,typename Map::tail_type>::get_enum(); }
};
template< typename T, Type HEnum, class Tail >
struct getter< T, set_data_buffer_type_map<T,HEnum,Tail> > {
// current node has T as HType
Type get_enum() { return set_data_buffer_type_map<T,HEnum,Tail>::head_enum; }
};
template< typename T, typename HType, Type HEnum, >
struct getter< T, set_data_buffer_type_map<T,HEnum,nil> > {
// no function here, so compile-time error
};
template< typename T>
Type get_type_enum()
{
return getter<T, set_data_buffer_type_map>::get_enum();
}
(Note: This is just an outline. I have not even attempted to compile it. )
I will suggest to go with enum option. Using it as template means your API users should have idea about all the types before which can be bit difficult. Using it as enum also give them as option to refer the enum and decide which SQL types suits the requirement.

Accessing a nested pair

To take apart a pair, the following can be done
boost::bind(&std::pair::second, _1); // returns the value of a pair
What about using combinations of different containers, how can a nested pair be accessed?
For example when I wanted to partition a vector into items contained in a supplemental map and items that where not contained in the supplemental map I used the following:
typedef int DWORD; typedef std::pair<std::string, bool> user_info;
typedef std::map<DWORD, user_info> USER_MAP;
typedef std::vector<DWORD> VEC_STAFF;
VEC_STAFF::iterator it = std::partition(
Staff.begin(), Staff.end(),
(bind(&USER_MAP::find, m_Users, _1) != m_Users.end()));
Now I have a second problem - during the running of the application the status bool of user_info can change, and later on I want to re-partition the vector with items that have a status bool of true rather than just being contained in the supplemental map.
However I seem to have a problem accessing the second item of a nested pair.
I tried the following but I cannot seem to access the nested pair!
VEC_STAFF::const_iterator itCurEnd = partition(Staff.begin(), Staff.end(),
bind(&USER_MAP::value_type::second::second,
bind(&USER_MAP::find, &m_Users, _1)) == true);
Not sure I follow what's going on there, but usually when I start running into problems with bind I give up and implement a functor. This might simplify things in your case.
To me, the following is a lot easier to read than all that messing around with multiple levels of binds
template <class Arg>
struct Whatever : public std::unary_function<Arg, bool>
{
bool operator()(const Arg &arg1) const {
//logic here
}
};
Whatever<???> functor;
std::partition(Staff.begin(), Staff.end(), functor);
The syntax you used obviously doesn't work. The first "::second" already signifies a non-static member and not a type. If you have a pair inside a pair you probably have to use two bind calls:
typedef std::pair< int, bool > foo_t;
typedef std::pair< int, foo_t > bar_t;
.....
bind( &foo_t::second, bind(&bar_t::second,
bind( &USER_MAP::find, _1 )
) )
(I didn't test this. Perhaps this is what you want)
But three levels if bind is quite challenging, in my opinion.
Edit: How about this?
template<typename Iter, typename Return>
struct deref_2nd_2nd : std::unary_function<Iter, Return> {
Return operator()(Iter const& it) const {
return (*it).second.second;
}
};
.....
bind(
deref_2nd_2nd<USER_MAP::iterator,bool>(),
bind( &USER_MAP::find, _1 )
)