WL#5825: Using C++ Standard Library with MySQL code

Affects: Server-Prototype Only   —   Status: Complete

The goal of this worklog is to allow the use of the C++ Standard Library
inside the code and to enable exceptions and RTTI for the MyQL code
base. The goal is *not* to start using the the standard C++ library
throughout the code base, just to ensure that it is possible.

Motivation
~~~~~~~~~~

There are a number of advantages to using the standard C++ library.
Chiefly, it is already written code that has been tested and tuned over
several years, which in various cases provide better performance and
maintainability than the "homegrown" alternatives. The STL in particular
provides a wide range of well-documented and standardized containers and
algorithms that can be applied interchangeably in many scenarios.

In particular, it can be immediately applied in the following ways:

- Gracefully handle out of memory conditions with std::no_throw.
- A associative container (map or similar) which is needed for WL#3584.
- Potential gain in performance by using std::sort instead of my_qsort.
- Improve maintainability by using std::vector instead of Dynamic_array.
- Remove the non-working overloading of new and delete operators.
- Demangled stack backtrace on crashes.

When-Which-How 
~~~~~~~~~~~~~~~~

When, which and how parts of the C++ Standard Library are to be used
will be regulated by the Coding Standard Committee.

http://forge.mysql.com/wiki/MySQL_Internals_Coding_Guidelines#How_we_maintain_th
e_server_coding_guidelines

Using a C++ Standard Library function or class 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

As an experiment, I replaced the DYNAMIC_ARRAY instance saved_table_locks
in sql_test.cc with an std::vector instance. The goal of this test was
to take an isolated use and see if a normal use of DYNAMIC_VECTOR could
be replaced with a C++ Standard Library container and what effects it
would have on the build.

Note that the goal is *not* to evaluate the performance of the C++
Standard Containers.

It proved to not be controversial to use this container instead of
DYNAMIC_ARRAY, but there is one construction that is widely used in
the server which caused a problem: the min and max macros.

These are macros defined in my_global.h and clash with the
definition of std::min and std::max in .  To handle
this, it is necessary to remove the macros from all C++ code.

It is not possible to just replace the uses of min and max with
std::min and std::max because these macros are used in three different
ways:

1. The macros rely on the standard conversions.
2. They are used in C code.
3. They are used in constant expressions, where function calls are not
   allowed.

Note that not all cases of using min and max in the current code base
is correct since there are comparisons between unsigned and signed
integral values. When using standard conversions, negative signed
values will be converted to an unsigned value in an
implementation-defined manner, which potentially can have unexpected
side-effects.  As an example, consider "max(some_ulong, some_int)",
and suppose that "some_int" happens to be negative. In this case, it
will (probably) be converted using two-complements arithmetic to a
very large number (since the other type is unsigned), which may lead
to strange results.

To handle the conflict with the macros and the standard functions,
there are two ways:

- Replace all instances of min and max with std::min and std::max.

  This has the advantage of being best way to switch to the standard
  library, but it requires a search-and-replace patch, which can have
  potential conflicts with existing code (just takes time to resolve
  the conflicts, nothing that is likely to introduce problems).

  It would require the type to be explicitly stated, for example:
  "std::max(int_value, ulong_value)".

- Write our own version of min and max that support the correct usage.

  This approach would allow us to not change any of the existing code
  (except to handle the last case below), but does require us to
  maintain our own version of min and max. See the example code I used
  below.

To handle the use in constant expressions, I think the best path is to
introduce macros MY_MIN and MY_MAX (or maybe just MIN and MAX) and use
those. The alternative is to expand the expressions in-place.

The introduction of MIN and MAX can also be used to provide the min
and max functions in the C code, with the alternative of introducing
inline functions min and max.

Code for creating a min/max that honors standard conversions. 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

template  struct MaxType;                                        
template  struct MaxType {
  typedef T Type;
};
template  struct MaxType {                                   
  typedef typename MaxType::Type Type;                                      
};                                                                             
#define MAX_TYPE(A, B, C) template <> struct MaxType {typedef C Type;}
MAX_TYPE( double,int,double);                                                
MAX_TYPE( double, unsigned int, double);                                       
MAX_TYPE( int, unsigned char, int);                                            
MAX_TYPE( long long, int, long long);                                          
MAX_TYPE( long, int, long);                                                    
MAX_TYPE( unsigned int,  unsigned short, unsigned int);                        
MAX_TYPE( unsigned int, char, unsigned int);                                   
MAX_TYPE( unsigned int, int, unsigned int);                                    
MAX_TYPE( unsigned int, short, unsigned int);                                  
MAX_TYPE( unsigned int, unsigned char, unsigned int);                          
MAX_TYPE( unsigned long long, int, unsigned long long);                        
MAX_TYPE( unsigned long long, unsigned char, unsigned long long);              
MAX_TYPE( unsigned long long, unsigned int, unsigned long long);               
MAX_TYPE( unsigned long long, unsigned long, unsigned long long);              
MAX_TYPE( unsigned long, int, unsigned long);                                  
MAX_TYPE( unsigned long, unsigned char, unsigned long);                        
MAX_TYPE( unsigned long, unsigned int, unsigned long);                         
#undef MAX_TYPE                                                                
template                                                     
typename MaxType::Type min(A a, B b) {                                    
  typedef typename MaxType::Type ReturnType;                                
  return ReturnType(a) > ReturnType(b) ? b : a;                                  
}                                                                              
template                                                     
typename MaxType::Type max(A a, B b) {                                    
  typedef typename MaxType::Type ReturnType;                                
  return ReturnType(a) > ReturnType(b) ? a : b;                                  
}