Practices regarding wrapper for setDataBuffer (OCCI) - c++

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.

Related

C++ Macro to use enum to access a type?

I'm unsure how to word this. I have an enum that basically has values that represent other enum types. This is for a sorting algorithm I'm working on (think like filters on a shopping page).
So I have say
enum Sorting { COLOR, PRICE };
enum Color { RED, BLUE };
is there a way to make a Macro where I input COLOR and return the type Color?
#define ENUM_ASSOCIATION(A, B)
#define ENUM_TYPE(A) //returns B from ENUM_ASSOCIATION
enum Sorting{ COLOR, PRICE };
ENUM_ASSOCIATION(COLOR, Color);
enum Color { RED, BLUE };
void someFunc()
{
DoSomething<ENUM_TYPE(COLOR)>();
}
I'm new to C++ Preprocessors and trying to get a handle on them. I feel like this shouldn't be too difficult to accomplish, but I'm unsure how to go about it, if it's possible at all
EDIT:
So this is what I'm using. I have had no compile errors, though I haven't yet been able to test it. Any enum declared with these macros will use the Assoc struct, which may or may not cause issues. If it does, possibly just add an AliasName parameter to each macro and replace Assoc with that.
// Allow use of ENUM_ASSOCIATION to create type aliases
#define DECLARE_ENUM_ASSOCIATION(T) template<T> struct Assoc;
// Creates a type alias, allowing to call ENUM_TYPE() and get the type V
// Remember to use only after both T and V have been declared previously
#define ENUM_ASSOCIATION(T, V) \
template<> \
struct Assoc<T> \
{\
using type = V;\
};
#define ENUM_TYPE(T) Assoc<T>::type;
This kind of association in C++ is usually done with meta-functions. E.g.
template <Sorting> struct Assoc;
template <> Assoc<COLOR> struct Assoc {using type = Color};
DoSomething<Assoc<COLOR>::type>();
Of course, you can also #define ENUM_ASSOCIATION(COLOR, Color) to wrap
template <> Assoc<COLOR> struct Assoc {using type = Color};
and #define ENUM_TYPE(COLOR) to wrap
Assoc<COLOR>::type
This is text book application for meta-functions. Since the question is tagged C++, I'd avoid macro solutions and go with common practice.
Let's check the solution first:
enum Sorting { COLOR, PRICE };
enum Color { RED, BLUE };
enum Price { CHEAP, EXPENSIVE };
// auto is used for non type template parameters
template <auto any_enum_value>
struct SortCategory;
template <>
struct SortCategory<COLOR>
{
using type = Color;
};
template <>
struct SortCategory<PRICE>
{
using type = Price;
};
Demo
The code above provides a meta function called SortCategory; this is a struct that can be specialized for values of the Sorting enumeration. You can basically do anything this way, above the following mappings are chosen:
SortCategory<COLOR> -> Color
SortCategory<PRICE> -> Price
the mapped type (enumeration) is the nested type alias as shown in the demo.
EDIT: The SortCategory has been updated to accommodate any non type template argument. Using auto you can pass values of any enumeration which makes your mapping scale out of the sorting enum type.

Use Variadic templates (or a similar mechanism) to pass list of types to a function

I would like to implement a class wrapper for database.
Currently, I'm working on a createTable function.
The way I have tried to make it work is, that the user specifies the types
as a template parameters, and the column names as an initialiser list,
this is the template of the function:
template <typename ... Ts>
bool createTable(const std::string & tableName, const std::initializer_list<std::string> & columnNames);
And this is the body of the method:
template<typename ... Ts>
bool DatabaseConnection::createTable(const std::string &tableName, const std::initializer_list<std::string> & columnNames)
{
constexpr size_t num_cols = sizeof...(Ts);
assert(num_cols == columnNames.size());
auto typetuple = std::tuple<Ts...>();
std::vector<std::tuple<std::string, std::string>> columnNameAndType(num_cols);
auto columnNameIterator = columnNames.begin();
for(unsigned it = 0; it++ < columnNames.size(); it++){
typedef std::tuple_element<it, typetuple>::type c; // non-type template argument is not a constant expression
if(is_same<c, int> ...) //pseudocode
std::string dbtype = "INTEGER"; //pseudocode
}
}
Sadly, the tuple_element line doesn't work, because it's not really a
constant expression.
Now, someone might ask, why I want to call it like this:
createTable<int, std::string>("Users", {"ID", "Name"});
instead of just passing two initialiser lists?
Well I just want to distance the user from the interface - If I were able to determine
the it-h type I could just use something like decltype or is_same to determine the type used in database creation query - the user just says what type he/she wants and the Database class
determines the best database type to match the user's request.
Now, it could still be made with initaliser lists, but it wouldn't be compile time, and
I'm just curious to see if it's possible at comple time.
I hope my explanation of the problem is sufficient.
Of course this is mostly a theoretical problem, but I think many people
would be interested in such a syntax, and I haven't found any solutions on the internet yet.
This interface is certainly possible.
A for loop isn't going to do it, because one statement/variable/expression/etc. can't have different types on different evaluations of a for substatement. The loop will need to be via pack expansion instead.
One or more private helper member functions could help for this. It would be possible to get it all in one function definition using a generic lambda, but a little unpleasant.
// private static
template <typename T>
std::string DatabaseConnection::dbTypeName()
{
if constexpr (std::is_same_v<T, int>)
return "INTEGER";
// ...
else
static_assert(!std::is_same_v<T,T>, "Unsupported type argument");
}
template<typename ... Ts>
bool DatabaseConnection::createTable(
const std::string &tableName,
std::initializer_list<std::string> columnNames)
{
constexpr size_t num_cols = sizeof...(Ts);
assert(num_cols == columnNames.size());
std::vector<std::tuple<std::string, std::string>> columnNameAndType;
auto columnNameIterator = columnNames.begin();
(columnNameAndType.emplace_back(*columnNameIterator++, dbTypeName<Ts>()), ...);
// ...
}

Change the macros to pick separate definition according to hash_map key type

I have an interesting problem to deal with STL hash maps.
Consider this in my code :
HSH_table(char*, obj_a) hash_1;
char* a = "abc";
char* b = "abc";
And I am doing a typedef of HSH_table somewhere in .h files.
#define HSH_table(Key, Data) __gnu_cxx::hash_map(Key, Data)
Problem with __gnu_cxx::hash_map is that it does not work well with char*. If two char* are same(not the pointer, its values) then it shouldn't insert at same slot. In this scenario, both a and b should go to the same slot since they share the same value. Is that correct? I see that default behaviour is that it inserts both pointers at different slots due to their pointer different.
I do not want to change my source code but I can change the .h file. In case I want to insert at the same slot, we might need to write a comparator function. I want the comparator function-specific only to one key, i.e. char*.
Something like this:
#define HSH_table(Key, Data) \
if (key == <char*>) { \
__gnu_cxx::hash_map(Key, Data, Comparator) \
else \
__gnu_cxx::hash_map(Key, Data)
First, is it possible?
If yes, then what should we write so that it takes char* as different and everything else as different. What would the right way match char* which is an macro argument.
You might use the following:
template <typename Key, typename Value> struct hash_map_alias
{
using type = std::unordered_map<Key, Value>;
};
// Provide special comparer for C-string
template <typename Value> struct hash_map_alias<const char*, Value>
{
using type = std::unordered_map<Key, Value, StringComparer>;
};
template <typename Value> struct hash_map_alias<char*, Value>
{
using type = std::unordered_map<Key, Value, StringComparer>;
};
// And now your MACRO
#define HSH_table(Key, Data) typename hash_map_alias<Key, Data>::type

How to type-erase a C++ concept

I'm trying to implement a small networking library to learn about concepts and I'm trying to find a way to define succinct concepts without having to carry template parameters over dependent concepts. For instance, I have the following concepts:
template <typename ValueT>
concept bool Value = true;
template <typename BufferT>
concept bool Buffer = requires(BufferT buf)
{
{ buf.Size() } -> std::size_t;
{ buf.Capacity() } -> std::size_t;
{ buf.Put(Value</* How can I resolve this to any value */>) } -> bool;
{ buf.Take(Value</* How can I resolve this to any value */>) } -> bool;
};
template <typename ReadableT>
concept bool Readable = requires(ReadableT r)
{
{ r.Read(Buffer</* How can I resolve this to any buffer */>) } -> void;
};
template <typename WritableT>
concept bool Writable = requires(WritableT w)
{
{ w.Write(Buffer</* How can I resolve this to any buffer */>) } -> void;
};
template <typename ChannelT>
concept bool Channel = requires(ChannelT chan)
{
requires Readable<ChannelT>;
requires Writable<ChannelT>;
};
How can I define the Value and Buffer concepts without having to explicitly have a template parameter? Is it even possible? I would intuitively write it this way:
template <typename ReadableT>
concept bool Readable = requires(ReadableT r)
{
template <typename ValueT>
{ r.Read(Buffer<ValueT>) } -> void;
};
But this doesn't compile (obviously) and I can't figure out the right syntax.
EDIT: I have a feeling the right syntax is like so:
template <typename BufferT>
concept bool Buffer = requires(BufferT buf, Value val)
{
{ buf.Size() } -> std::size_t;
{ buf.Capacity() } -> std::size_t;
{ buf.Put(val) } -> bool;
{ buf.Take(val) } -> bool;
};
But GCC (8.3.0) prints this message:
internal compiler error: in synthesize_implicit_template_parm, at cp/parser.c:39141
concept bool Buffer = requires(BufferT buf, Value val)
^~~~~
Please submit a full bug report, with preprocessed source if appropriate.
the idea is that I should be able to put any struct, or an integer or a string, or anything really in a buffer
That is not a question that a concept is capable of answering. Nor is it meant to.
Concepts are meant to constrain templates. And a template is supposed to, on some level, know what it is doing. A specific template instantiation doesn't work on "any struct, or an integer or a string"; it works on specific types, defined by its template arguments and expressions dependent on them. The same goes for a concept.
So consider a template like this:
template<typename Buff, typename Iterator>
void InsertIntoBuffer(Buff &buf, Iterator beg, Iterator ed)
{
for(; beg != ed; ++beg)
buf.Put(*beg);
}
The constraint this function wants to put on Buff is not "has a Put function that can take any object." The actual constraint is "has a Put function that can take what Iterator's operator* returns."
So "putting" and "taking" is not just a constraint on Buff; it also needs to know what is being "put" or "taken".
To put it another way, it isn't the type that has a constraint; it's the operation as a whole which is constrained.
So you would have a base constraint for Buffer, which is a thing with size and capacity. But you should also have a PutBuffer constraint which imposes the requirement that Buffer can Put the given type.
Similarly, a Readable is really a ReadableFromBuffer, where the buffer type is provided.
You can’t have an unbounded family of constraints on a type—that it support put(int), put(int*), put(int**), etc., for example. (How would such a constraint be checked, in general?) And you really don’t want to claim that a template put exists that can take any T, because while the (traditional, unconstrained) syntax suggests that it can, there are almost always implicit constraints (or assumptions) that would be broken by instantiating with some T (consider abstruse things like void() const).
As a practical matter for serialization, you could just check that put accepts int, float, and const char*, perhaps along with a representative std::vector or so.

Call a vector's function given the vector's pointer as a void *

I am working on implementing a game engine using ECS principles as an excercise. My current design has a ComponentManager class that is to store all the vectors that correspond to each component type. A minimal version of the class looks like this:
class ComponentManager{
private:
std::vector<void*> componentHolder;
public:
bool destroyEntity(int entityID, componentSignature toDestroy);
template <class T>
int registerComponent();
template <class T>
bool addComponent(int entity, T initialComp);
template <class T>
bool removeComponent(int entity);
};
The componentHolder is a vector of void* where each entry is the vector containing a different component type. The reason I am doing this is because I want to store all the components in contiguous memory, however each component is a different type. If I was to use a vector of pointers to some base component class, that would defeat the cache coherence, data-flow oriented benefits that I am trying to exploit with this ECS engine.
Also, My engine is designed so that others can create custom components by simply defining a struct containing the data they wish that component to store and registering that component on the creation of a new game "world" (or instance if you prefer). This registration is done via the registerComponent() function seen above, creating a unique id for each component type, and is defined as:
template <class T>
int ComponentManager::registerComponent(){
componentHolder.push_back(new std::vector<T>);
return type_id<T>();
}
The type_id() function is a trick I found from this stackexchange question and is what allows me to map the component types to integers which I use as indices in the ComponentManager vector. This has worked well for the creation/access of components, as those functions are templates and get the type of the component passed in (and as a result I can static cast the void* that is at the index of the componentHolder vector to the right type), here's an example of this:
template <class T>
bool ComponentManager::addComponent(int entityID){
int compID = type_id<T>();
std::vector<T>* allComponents = (std::vector<T>*)componentHolder[compID];
if (compEntityID.find(entityID) == compEntityID.end()){
(*allComponents).push_back(T());
return true;
}
return false;
}
however the issue comes from when I want to destroy an entity entirely. My function for destroying an entity simply requires the entity ID, and the component signature (a bitset that has bits flipped to 1 corresponding to which components this entity has) which is stored in the gameWorld object and is passed in. However, since the destroyEntity function does not get types passed into it via template functions, and only has the bitset to know which type of component to destroy, I can't figure out a way to get the type so that I can cast the void* to the right vector. Here is an example of what I want the destroyEntity function to do:
bool ComponentManager::destroyEntity(int entityID, componentSignature toDestroy){
for (int x = 0; x < MAX_COMPONENT; x++){
if (toDestroy[x]){
std::vector<??>* allComponents = (std::vector<??>*)componentHolder[x]; // Here is where the issue lies
(*allComponents).erase((*allComponents).begin() + entityIndex);
}
}
}
Is there a way during component registration for example that I could store a function pointer to each vector's erase method that I could later call from the destroyEntity() function? Or some way to store a map from the integer componentID I create during registration to the type itself, and use that later to cast? The types of components that are in the game will be known at run time, so I feel like this should be doable somehow? Also as a caveat there is some additional logic I have to figure out which entity owns which component in each component vector in componentHolder that I omitted for brevity, so that won't be causing any issues.
Thank you in advanced for your help/any tips you can provide! I appreciate you reading through this long post, and I am open to suggestions!
template<class...Ts>
using operation = void(*)(void* t, void*state, Ts...);
template<class...Ts>
struct invoker{
operation<Ts...> f;
std::shared_ptr<void> state;
void operator()(void* t, Ts...ts)const{
f(t, state.get(), std::forward<Ts>(ts)...);
}
};
template<class T, class...Ts, class F>
invoker<Ts...> make_invoker(F&& f){
return {
[](void* pt, void* state, Ts...ts){
auto* pf=static_cast<std::decay_t<F>*>(state);
(*pf)( *static_cast<T*>(pt), std::forward<Ts>(ts)... );
},
std::make_shared<std::decay_t<F>>( std::forward<F>(f) )
};
}
so how does this help? Well you can store howto erase by index using this.
std::vector<??>* allComponents = (std::vector<??>*)componentHolder[x]; // Here is where the issue lies
(*allComponents).erase((*allComponents).begin() + entityIndex);
what you want is a f(void*, int) that does the above.
template<class T>
invoker<int> erase_at_index(){
return make_invoker<std::vector<T>,int>([]( auto&&vec, int index ){
vec.erase(vec.begin()+index);
};
}
simply store std::vector<invoker<int>> erasers;. When a new type is added , push a new eraser made by erase_at_index<T>.
Then:
erasers[x](componentHolder[x],entityIndex);
and done.
The shared ptr is once per type; if that overhead is too much, aligned storage and static asserts that the F isn't too big can be used instead.