uves_utils_wrappers.c

00001 /*                                                                              *
00002  *   This file is part of the ESO UVES Pipeline                                 *
00003  *   Copyright (C) 2004,2005 European Southern Observatory                      *
00004  *                                                                              *
00005  *   This library is free software; you can redistribute it and/or modify       *
00006  *   it under the terms of the GNU General Public License as published by       *
00007  *   the Free Software Foundation; either version 2 of the License, or          *
00008  *   (at your option) any later version.                                        *
00009  *                                                                              *
00010  *   This program is distributed in the hope that it will be useful,            *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
00013  *   GNU General Public License for more details.                               *
00014  *                                                                              *
00015  *   You should have received a copy of the GNU General Public License          *
00016  *   along with this program; if not, write to the Free Software                *
00017  *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA       *
00018  *                                                                              */
00019 
00020 /*
00021  * $Author: amodigli $
00022  * $Date: 2007/06/06 08:17:33 $
00023  * $Revision: 1.106 $
00024  * $Name: uves-3_3_1 $
00025  * $Log: uves_utils_wrappers.c,v $
00026  * Revision 1.106  2007/06/06 08:17:33  amodigli
00027  * replace tab with 4 spaces
00028  *
00029  * Revision 1.105  2007/06/06 06:28:30  jmlarsen
00030  * Renamed non-header file uves_tools_body.h -> uves_tools_body.c
00031  *
00032  * Revision 1.104  2007/05/23 12:50:36  jmlarsen
00033  * Added missing include directive
00034  *
00035  * Revision 1.103  2007/05/23 12:50:07  jmlarsen
00036  * Replace isnan/isinf -> irplib_isnan/irplib_isinf
00037  *
00038  * Revision 1.102  2007/05/11 08:41:20  jmlarsen
00039  * Added support for type float in table selection functions
00040  *
00041  * Revision 1.101  2007/05/08 14:27:18  jmlarsen
00042  * Avoid exporting workaround functions
00043  *
00044  * Revision 1.100  2007/05/07 10:17:44  jmlarsen
00045  * Added uves_image_reject_all
00046  *
00047  * Revision 1.99  2007/05/04 13:14:32  jmlarsen
00048  * Added workaround code
00049  *
00050  * Revision 1.98  2007/05/03 15:24:27  jmlarsen
00051  * Added deallocator functions
00052  *
00053  * Revision 1.97  2007/04/24 12:50:29  jmlarsen
00054  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00055  *
00056  * Revision 1.96  2007/04/24 09:43:17  jmlarsen
00057  * Renamed uves_propertylist_append -> uves_propertylist_append_property
00058  *
00059  * Revision 1.95  2007/04/20 14:45:37  jmlarsen
00060  * Added uves_sort_table_3()
00061  *
00062  * Revision 1.94  2007/04/19 06:26:28  jmlarsen
00063  * Fixed: set slope to input value, not zero in first iteration
00064  *
00065  * Revision 1.93  2007/04/03 11:03:01  jmlarsen
00066  * Added uves_free_float
00067  *
00068  * Revision 1.92  2007/03/19 13:51:02  jmlarsen
00069  * Added workaround for cpl_table_and_selected_invalid
00070  *
00071  * Revision 1.91  2007/03/15 12:34:52  jmlarsen
00072  * Declared functions static
00073  *
00074  * Revision 1.90  2007/03/13 15:36:19  jmlarsen
00075  * Implemented yet another faster and uglier workaround for the slow cpl_table_erase_selected()
00076  *
00077  * Revision 1.89  2007/03/05 10:15:20  jmlarsen
00078  * Support slope parameter in 1d fitting
00079  *
00080  * Revision 1.88  2007/02/26 11:55:52  jmlarsen
00081  * Renamed and generalized function uves_raise_to_median() -> uves_raise_to_median_frac()
00082  *
00083  * Revision 1.87  2007/02/22 15:36:29  jmlarsen
00084  * Don't use workaround for cpl_table_erase_selected with newer CPL versions
00085  *
00086  * Revision 1.86  2007/02/09 09:00:57  jmlarsen
00087  * Added context as parameter of uves_set_parameter_default
00088  *
00089  * Revision 1.85  2007/01/17 13:28:32  jmlarsen
00090  * Added uves_free_frame
00091  *
00092  * Revision 1.84  2007/01/15 08:49:26  jmlarsen
00093  * More accurate Gaussian centering
00094  *
00095  * Revision 1.83  2006/12/08 07:41:43  jmlarsen
00096  * Minor doc. change
00097  *
00098  * Revision 1.82  2006/12/01 12:31:28  jmlarsen
00099  * Added uves_free_string_const
00100  *
00101  * Revision 1.81  2006/11/24 09:37:43  jmlarsen
00102  * Removed inline directive of uves_fit_1d_compare
00103  *
00104  * Revision 1.80  2006/11/15 15:02:15  jmlarsen
00105  * Implemented const safe workarounds for CPL functions
00106  *
00107  * Revision 1.78  2006/11/15 14:04:08  jmlarsen
00108  * Removed non-const version of parameterlist_get_first/last/next which is 
00109  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00110  *
00111  * Revision 1.77  2006/11/13 14:23:55  jmlarsen
00112  * Removed workarounds for CPL const bugs
00113  *
00114  * Revision 1.76  2006/11/13 12:50:03  jmlarsen
00115  * Added type-safe wrappers of cpl_free
00116  *
00117  * Revision 1.75  2006/11/07 14:06:02  jmlarsen
00118  * Added cpl_array_delete wrapper
00119  *
00120  * Revision 1.74  2006/11/03 14:56:47  jmlarsen
00121  * uves_table_erase_selected_dfs02356: Support CPL 3d tables
00122  *
00123  * Revision 1.73  2006/09/20 12:53:57  jmlarsen
00124  * Replaced stringcat functions with uves_sprintf()
00125  *
00126  * Revision 1.72  2006/09/19 14:23:33  jmlarsen
00127  * uves_find_frame(): Support returning pointer to frame
00128  *
00129  * Revision 1.71  2006/09/06 14:47:55  jmlarsen
00130  * Added option to easily switch on/off debugging the LM algorithm
00131  *
00132  * Revision 1.70  2006/09/01 14:01:16  jmlarsen
00133  * Exported function uves_fit
00134  *
00135  * Revision 1.69  2006/08/23 15:08:29  jmlarsen
00136  * Added uves_free_bivector()
00137  *
00138  * Revision 1.68  2006/08/17 14:40:06  jmlarsen
00139  * Added missing documentation
00140  *
00141  * Revision 1.67  2006/08/17 14:11:25  jmlarsen
00142  * Use assure_mem macro to check for memory allocation failure
00143  *
00144  * Revision 1.66  2006/08/17 13:56:53  jmlarsen
00145  * Reduced max line length
00146  *
00147  * Revision 1.65  2006/08/14 12:19:32  jmlarsen
00148  * Improved parameter estimation, made workaround for optimization related
00149  * numerical instability in uves_fit
00150  *
00151  * Revision 1.64  2006/08/11 14:36:11  jmlarsen
00152  * Implemented workaround for slow cpl_table_erase_selected
00153  *
00154  * Revision 1.63  2006/08/11 09:42:57  jmlarsen
00155  * Use the new cpl_parameter_set_default to have the correct recipe 
00156  * default parameter values also with Gasgano
00157  *
00158  * Revision 1.62  2006/08/10 10:54:25  jmlarsen
00159  * Removed workaround for cpl_image_get_bpm
00160  *
00161  * Revision 1.61  2006/08/08 11:27:18  amodigli
00162  * upgrade to CPL3
00163  *
00164  * Revision 1.60  2006/07/14 12:43:15  jmlarsen
00165  * Added uves_extract_table_rows_local
00166  *
00167  * Revision 1.59  2006/07/03 13:21:41  jmlarsen
00168  * Changed 1d-fit parameter estimation method when only sky needs to be determined
00169  *
00170  * Revision 1.58  2006/06/16 08:26:41  jmlarsen
00171  * Doc bugfix
00172  *
00173  * Revision 1.57  2006/06/13 12:02:53  jmlarsen
00174  * Renamed y0 -> y_0
00175  *
00176  * Revision 1.56  2006/06/06 08:40:11  jmlarsen
00177  * Shortened max line length
00178  *
00179  * Revision 1.55  2006/06/01 14:43:17  jmlarsen
00180  * Added missing documentation
00181  *
00182  * Revision 1.54  2006/05/12 15:12:43  jmlarsen
00183  * Pass image bpm as extra parameter to fitting routine for efficiency reasons
00184  *
00185  * Revision 1.53  2006/05/05 14:00:03  jmlarsen
00186  * Bugfix: proper handling of bad pixels when fitting image data
00187  *
00188  * Revision 1.52  2006/04/24 09:33:16  jmlarsen
00189  * Added function that factors out profile for 1d gaussian-like fit
00190  *
00191  * Revision 1.51  2006/04/06 08:52:48  jmlarsen
00192  * Added raise-to-median of table column function
00193  *
00194  * Revision 1.50  2006/03/23 14:14:40  jmlarsen
00195  * Corrected spelling mistake causing infinite recursion in uves_get_image_bpm
00196  *
00197  * Revision 1.49  2006/03/03 13:54:11  jmlarsen
00198  * Changed syntax of check macro
00199  *
00200  * Revision 1.48  2006/02/28 09:15:23  jmlarsen
00201  * Minor update
00202  *
00203  * Revision 1.47  2006/02/15 13:19:15  jmlarsen
00204  * Reduced source code max. line length
00205  *
00206  * Revision 1.46  2006/01/31 08:25:08  jmlarsen
00207  * Wrapper for cpl_image_get_bpm
00208  *
00209  * Revision 1.45  2006/01/25 16:13:20  jmlarsen
00210  * Changed interface of gauss.fitting routine
00211  *
00212  * Revision 1.44  2005/12/19 16:17:56  jmlarsen
00213  * Replaced bool -> int
00214  *
00215  */
00216 
00217 #ifdef HAVE_CONFIG_H
00218 #  include <config.h>
00219 #endif
00220 
00221 /*----------------------------------------------------------------------------*/
00229 /*----------------------------------------------------------------------------*/
00230 
00231 #include <uves_utils_wrappers.h>
00232 
00233 #include <uves_utils.h>
00234 #include <uves_utils_cpl.h>
00235 #include <uves_error.h>
00236 #include <uves_dump.h>
00237 #include <cpl.h>
00238 
00239 #include <irplib_utils.h>
00240 #include <irplib_access.h>
00241 #include <stdbool.h>
00242 #include <assert.h>
00243 
00244 /*-----------------------------------------------------------------------------
00245                                    Local functions
00246  -----------------------------------------------------------------------------*/
00247 
00248 static int get_candidate(const double *a, const int ia[],
00249              int M, int N, int D,
00250              double lambda,
00251              int    (*f)(const double x[], const double a[], 
00252                      double *result),
00253              int (*dfda)(const double x[], const double a[], 
00254                      double result[]),
00255              const double *x,
00256              const double *y,
00257              const double *sigma,
00258              double *partials,
00259              cpl_matrix *alpha,
00260              cpl_matrix *beta,
00261              double *a_da);
00262 
00263 static double get_chisq(int N, int D,
00264             int (*f)(const double x[], const double a[], 
00265                  double *result),
00266             const double *a,
00267             const double *x,
00268             const double *y,
00269             const double *sigma);
00270 
00271 /*-----------------------------------------------------------------------------
00272                                    Defines
00273  -----------------------------------------------------------------------------*/
00274 
00276 #define image_is_rejected(badmap, x, y) \
00277   ((badmap) != NULL && (badmap)[((x)-1) + ((y)-1)*nx] == CPL_BINARY_1)
00278 
00279 #ifndef UVES_FIT_MAXITER
00280 #define UVES_FIT_MAXITER 1000
00281 #endif
00282 
00283 /*-----------------------------------------------------------------------------
00284                                    Types
00285  -----------------------------------------------------------------------------*/
00286 /* @cond */
00287 typedef struct {
00288     double x;
00289     double y;
00290 } uves_fit_1d_input;
00291 /* @endcond */
00292 
00293 /*-----------------------------------------------------------------------------
00294                                    Implementation
00295  -----------------------------------------------------------------------------*/
00299 /*----------------------------------------------------------------------------*/
00306 /*----------------------------------------------------------------------------*/
00307 void uves_image_reject_all(cpl_image *image)
00308 {
00309     int nx, ny;
00310     int x, y;
00311 
00312     assure_nomsg( image != NULL, CPL_ERROR_NULL_INPUT );
00313     nx = cpl_image_get_size_x(image);
00314     ny = cpl_image_get_size_y(image);
00315 
00316     for (y = 1; y <= ny; y++) {
00317         for (x = 1; x <= nx; x++) {
00318             cpl_image_reject(image, x, y);
00319         }
00320     }
00321     
00322   cleanup:
00323     return;    
00324 }
00325 
00326 
00327 /*----------------------------------------------------------------------------*/
00386 /*----------------------------------------------------------------------------*/
00387 
00388 cpl_error_code
00389 uves_fit_1d_image(const cpl_image *image, const cpl_image *noise,
00390           const cpl_binary *image_badmap,
00391           bool horizontal, bool fix_back, bool fit_back,
00392           int xlo, int xhi, int y_0,
00393           double *x0, double *sigma, double *norm, double *background,
00394                   double *slope,
00395           double *mse, double *red_chisq,
00396           cpl_matrix **covariance,
00397           int (*f)   (const double x[], const double a[], double *result),
00398           int (*dfda)(const double x[], const double a[], double result[]),
00399           int M)
00400 {
00401     cpl_vector *x = NULL;
00402     cpl_vector *y = NULL;
00403     cpl_vector *sigma_y = NULL;     /* Noise vector          */
00404     
00405     cpl_fit_mode fit_pattern;
00406     int nx, ny;                     /* Image size            */
00407     int N;                          /* Number of good pixels */
00408     int i, j;
00409     cpl_type image_type;
00410 
00411     const double *image_data       = NULL;        /* Pointer to data */
00412     const double *noise_data       = NULL;        /* Pointer to data */
00413 
00414     assure( x0 != NULL        , CPL_ERROR_NULL_INPUT, "Null fit parameter");
00415     assure( sigma != NULL     , CPL_ERROR_NULL_INPUT, "Null fit parameter");
00416     assure( norm != NULL      , CPL_ERROR_NULL_INPUT, "Null fit parameter");
00417     assure( background != NULL, CPL_ERROR_NULL_INPUT, "Null fit parameter");
00418     /* mse, red_chisq, covariance may be NULL */
00419 
00420     assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
00421    
00422     image_type = cpl_image_get_type(image);
00423 
00424     /* To support the following types, use cpl_image_get() or
00425        more multiple type pointers to data buffer.
00426        cpl_ensure_code( image_type == CPL_TYPE_INT ||
00427        image_type == CPL_TYPE_FLOAT ||
00428        image_type == CPL_TYPE_DOUBLE,
00429        CPL_ERROR_TYPE_MISMATCH);
00430     */
00431 
00432     assure( image_type == CPL_TYPE_DOUBLE, CPL_ERROR_UNSUPPORTED_MODE,
00433         "Unsupported type: %s", uves_tostring_cpl_type(image_type));
00434 
00435     image_data = irplib_image_get_data_double_const(image);
00436 
00437     if (noise != NULL)
00438     {
00439         image_type = cpl_image_get_type(noise);
00440         /*  See comment above.
00441           cpl_ensure_code( image_type == CPL_TYPE_INT ||
00442           image_type == CPL_TYPE_FLOAT ||
00443           image_type == CPL_TYPE_DOUBLE,
00444           CPL_ERROR_TYPE_MISMATCH);
00445         */
00446         assure( image_type == CPL_TYPE_DOUBLE, CPL_ERROR_UNSUPPORTED_MODE, 
00447             "Unsupported type: %s", uves_tostring_cpl_type(image_type));
00448 
00449         noise_data = irplib_image_get_data_double_const(noise);
00450     }   
00451 
00452     nx = cpl_image_get_size_x(image);
00453     ny = cpl_image_get_size_y(image);
00454 
00455     if (horizontal)
00456     {
00457         assure( 1 <= xlo && xlo <= xhi && xhi <= nx &&
00458             1 <= y_0  && y_0  <= ny, CPL_ERROR_ACCESS_OUT_OF_RANGE,
00459             "Illegal window (%d, %d)-(%d, %d), image: %dx%d",
00460             xlo, y_0, xhi, y_0,
00461             nx, ny);
00462     }
00463     else
00464     {
00465         assure( 1 <= xlo && xlo <= xhi && xhi <= ny &&
00466             1 <= y_0  && y_0  <= nx,
00467             CPL_ERROR_ACCESS_OUT_OF_RANGE,
00468             "Illegal window (%d, %d)-(%d, %d), image: %dx%d",
00469             y_0, xlo, y_0, xhi,
00470             nx, ny);
00471     }
00472     
00473     /* Noise image must have same size
00474      * as the input image
00475      */
00476     if (noise != NULL)
00477     {
00478         assure( cpl_image_get_size_x(noise) == nx &&
00479             cpl_image_get_size_y(noise) == ny,
00480             CPL_ERROR_INCOMPATIBLE_INPUT, "Noise image: %dx%d, image: %dx%d:",
00481             cpl_image_get_size_x(noise),
00482             cpl_image_get_size_y(noise),
00483             nx, ny);
00484     }
00485    
00486     /* Count good pixels in sub-window, check that noise image is positive */
00487     N = 0;
00488     for (i = xlo; i <= xhi; i++)
00489     {
00490         if ( !image_is_rejected(image_badmap,
00491                     (horizontal) ? i : y_0,
00492                     (horizontal) ? y_0 : i) )
00493         {
00494             if ( noise != NULL)
00495             {
00496                 if( !image_is_rejected(image_badmap,
00497                            (horizontal) ? i : y_0,
00498                            (horizontal) ? y_0 : i) )
00499                 {
00500                     /* Noise image must be positive (only check
00501                        pixels that are actually used) */
00502                     assure( /*cpl_image_get(noise,
00503                           (horizontal) ? i : y_0,
00504                           (horizontal) ? y_0 : i,
00505                           &pis_rejected)*/
00506                     noise_data[(((horizontal) ? i : y_0) - 1) +
00507                            (((horizontal) ? y_0 : i) - 1) * nx]
00508                     > 0,
00509                     CPL_ERROR_ILLEGAL_INPUT,
00510                     "Non-positive noise at (%d, %d): %e",
00511                     (horizontal) ? i : y_0,
00512                     (horizontal) ? y_0 : i,
00513                     noise_data[(((horizontal) ? i : y_0) - 1) +
00514                            (((horizontal) ? y_0 : i) - 1) * nx]
00515                     );
00516                     
00517                     N += 1;
00518                 }
00519                 else
00520                 {
00521                     /* Pixel value is good, but noise pixel is
00522                        bad. Don't use. */
00523                 }
00524             }
00525             else
00526             {
00527                 /* Pixel is good. No noise image */
00528                 N += 1;
00529             }
00530         }
00531     }
00532    
00533     /* Check that there is at least one good pixel */
00534     assure( N >= 1, CPL_ERROR_ILLEGAL_INPUT, "Only %d good pixel(s)", N);
00535 
00536     /* Allocate space */
00537     x = cpl_vector_new(N);
00538     y = cpl_vector_new(N);
00539     if (noise != NULL)
00540     {
00541         sigma_y = cpl_vector_new(N);
00542         assure_mem( sigma_y );
00543     }
00544 
00545     if (fix_back)
00546     {
00547         fit_pattern = CPL_FIT_CENTROID | CPL_FIT_STDEV | CPL_FIT_AREA;
00548     }
00549     else if (fit_back)
00550     {
00551         fit_pattern = CPL_FIT_AREA | CPL_FIT_OFFSET;
00552     }
00553     else
00554     {
00555         fit_pattern = CPL_FIT_ALL;
00556     }
00557    
00558     assure_mem( x );
00559     assure_mem( y );
00560     
00561     /* Copy the N good pixels from the input image to vectors,
00562        j count good pixels */
00563     for (i = xlo, j = 0;
00564      i <= xhi;
00565      i++)
00566     {
00567         double flux;
00568         
00569         /*
00570           flux = cpl_image_get(image,
00571           (horizontal) ? xlo+i : y_0,
00572           (horizontal) ? y_0 : xlo+i,
00573           &pis_rejected);
00574         */
00575         
00576         flux = image_data[(((horizontal) ? i : y_0) - 1) +
00577                   (((horizontal) ? y_0 : i) - 1) * nx];
00578        
00579         //if (!pis_rejected)
00580         if ( !image_is_rejected(image_badmap,
00581                     (horizontal) ? i : y_0,
00582                     (horizontal) ? y_0 : i) )
00583         {
00584             if (noise != NULL)
00585             {
00586                 double flux_noise;
00587                
00588                 /* flux_noise = cpl_image_get(noise,
00589                    (horizontal) ? xlo+i : y_0,
00590                    (horizontal) ? y_0 : xlo+i,
00591                    &pis_rejected);
00592                 */
00593                
00594                 flux_noise = noise_data
00595                 [(((horizontal) ? i : y_0) - 1) +
00596                  (((horizontal) ? y_0 : i) - 1) * nx];
00597                
00598                 //if (!pis_rejected)
00599                 if ( !image_is_rejected(image_badmap,
00600                             (horizontal) ?
00601                             i : y_0,
00602                             (horizontal)
00603                             ? y_0 : i) )
00604                 {
00605                     cpl_vector_set(x,       j, i);
00606                     cpl_vector_set(y,       j, flux);
00607                     cpl_vector_set(sigma_y, j, flux_noise);
00608                     j++;
00609                 }
00610             }
00611             else
00612             {
00613                 cpl_vector_set(x, j, i);
00614                 cpl_vector_set(y, j, flux);
00615                 j++;
00616             }
00617         }
00618     }
00619     passure( j == N, "%d %d", j, N);
00620     
00621     check( uves_fit_1d(x, NULL,      /* x, sigma_x */
00622                y, sigma_y,
00623                fit_pattern, fit_back,
00624                x0, sigma, norm, background,
00625                        slope,
00626                mse, red_chisq,
00627                covariance,
00628                f, dfda, M),
00629        "Fit failed");
00630 
00631     
00632   cleanup:
00633     uves_free_vector(&x);
00634     uves_free_vector(&y);
00635     uves_free_vector(&sigma_y);
00636 
00637     return cpl_error_get_code();
00638 }
00639 
00640 /*----------------------------------------------------------------------------*/
00648 /*----------------------------------------------------------------------------*/
00649 static int uves_fit_1d_compare(const void *left,
00650                    const void *right)
00651 {
00652     return 
00653     (((uves_fit_1d_input *)left )->x <  
00654      ((uves_fit_1d_input *)right)->x) ? -1 :
00655     (((uves_fit_1d_input *)left )->x == 
00656      ((uves_fit_1d_input *)right)->x) ? 0  : 1;
00657 }
00658 
00659 /*----------------------------------------------------------------------------*/
00681 cpl_error_code
00682 uves_fit_1d(const cpl_vector *x, const cpl_vector *sigma_x,
00683         const cpl_vector *y, const cpl_vector *sigma_y,
00684         cpl_fit_mode fit_pars, bool fit_back,
00685         double *x0, double *sigma, double *area, double *offset, double *slope,
00686             double *mse, double *red_chisq,
00687         cpl_matrix **covariance,
00688         int (*f)   (const double x[], const double a[], double *result),
00689         int (*dfda)(const double x[], const double a[], double result[]),
00690         int M)
00691 {
00692     const cpl_matrix *x_matrix = NULL; /* LM algorithm needs a matrix,
00693                       not a vector                 */
00694 
00695     int N;                          /* Number of data points        */
00696     double xlo, xhi;                /* Min/max x                    */
00697 
00698     /* Initial parameter values */
00699     double x0_guess    = 0;  /* Avoid warnings about uninitialized variables */
00700     double sigma_guess = 0;
00701     double area_guess;
00702     double offset_guess;
00703 
00704     cpl_ensure_code( M == 4 || M == 5, CPL_ERROR_UNSUPPORTED_MODE);
00705 
00706     /* Validate input */
00707     cpl_ensure_code( x       != NULL, CPL_ERROR_NULL_INPUT);
00708     cpl_ensure_code( sigma_x == NULL, CPL_ERROR_UNSUPPORTED_MODE);
00709     cpl_ensure_code( y       != NULL, CPL_ERROR_NULL_INPUT);
00710     /* sigma_y may be NULL or non-NULL */
00711     
00712     N = cpl_vector_get_size(x);
00713 
00714     cpl_ensure_code( N == cpl_vector_get_size(y),
00715              CPL_ERROR_INCOMPATIBLE_INPUT);
00716 
00717     if (sigma_x != NULL)
00718     {
00719         cpl_ensure_code( N == cpl_vector_get_size(sigma_x),
00720                  CPL_ERROR_INCOMPATIBLE_INPUT);
00721     }
00722     if (sigma_y != NULL)
00723     {
00724         cpl_ensure_code( N == cpl_vector_get_size(sigma_y),
00725                  CPL_ERROR_INCOMPATIBLE_INPUT);
00726     }
00727 
00728     cpl_ensure_code( x0     != NULL &&
00729              sigma  != NULL &&
00730              area   != NULL &&
00731              offset != NULL &&
00732                      (M != 5 || slope != NULL), CPL_ERROR_NULL_INPUT);
00733 
00734     if (! (fit_pars & CPL_FIT_STDEV))
00735     {
00736         cpl_ensure_code( *sigma > 0, CPL_ERROR_ILLEGAL_INPUT);
00737     }
00738 
00739     cpl_ensure_code( !fit_back || fit_pars == (CPL_FIT_OFFSET | CPL_FIT_AREA),
00740              CPL_ERROR_INCOMPATIBLE_INPUT);
00741 
00742     /* Input area must be positive if fit_back is false */
00743     if (! (fit_pars & CPL_FIT_AREA) && !fit_back)
00744     {
00745         cpl_ensure_code( *area > 0, CPL_ERROR_ILLEGAL_INPUT);
00746     }
00747 
00748     /* mse, red_chisq may be NULL */
00749 
00750     /* Need more than number_of_parameters points to calculate chi^2.
00751      * There are less than 5 parameters. */
00752     cpl_ensure_code( red_chisq == NULL || N >= 5, CPL_ERROR_ILLEGAL_INPUT);
00753     
00754     if (covariance != NULL) *covariance = NULL;
00755     /* If covariance computation is requested, then
00756      * return either the covariance matrix or NULL
00757      * (don't return undefined pointer).
00758      */
00759     
00760     /* Cannot compute chi square & covariance without sigma_y */
00761     cpl_ensure_code( (red_chisq == NULL && covariance == NULL) || 
00762              sigma_y != NULL,
00763              CPL_ERROR_INCOMPATIBLE_INPUT);
00764     
00765     /* Create matrix from x-data */
00766     x_matrix = irplib_matrix_wrap_const(N, 1, irplib_vector_get_data_const(x));
00767     if (x_matrix == NULL)
00768     {
00769         cpl_ensure_code(
00770                 CPL_FALSE,
00771         CPL_ERROR_ILLEGAL_OUTPUT);
00772     }
00773     
00774     /* Check that any provided sigmas are positive. */
00775     if (sigma_x != NULL && cpl_vector_get_min(sigma_x) <= 0)
00776     {
00777         irplib_matrix_unwrap_const(x_matrix);
00778         cpl_ensure_code(
00779         CPL_FALSE,
00780         CPL_ERROR_ILLEGAL_INPUT);
00781     }
00782     if (sigma_y != NULL && cpl_vector_get_min(sigma_y) <= 0)
00783     {
00784         irplib_matrix_unwrap_const(x_matrix);
00785         cpl_ensure_code(
00786         CPL_FALSE,
00787         CPL_ERROR_ILLEGAL_INPUT);
00788     }
00789 
00790     /* Compute guess parameters using robust estimation
00791      * (This step might be improved by taking into account the 
00792      * uncertainties but for simplicity's sake do not)
00793      */
00794     if (fit_back)
00795     {
00796         /* We need to estimate only these two parameters */
00797         assert( fit_pars == CPL_FIT_OFFSET || CPL_FIT_AREA);
00798 
00799         offset_guess = cpl_vector_get_median(y);
00800         area_guess = N*(cpl_vector_get_mean(y) - offset_guess);
00801         /* Sum of (flux-offset) */
00802 
00803         x0_guess = *x0;
00804         sigma_guess = *sigma;
00805     }
00806     else {
00807     double sum  = 0.0;
00808     double quartile[3];
00809     double fraction[3] = {0.25 , 0.50 , 0.75};
00810     const double *y_data = irplib_vector_get_data_const(y);
00811 
00812     if (fit_pars & CPL_FIT_OFFSET)
00813         {
00814         /* Estimate offset as 25% percentile of y-values.
00815            (The minimum value may be too low for noisy input,
00816            the median is too high if there is not much
00817            background in the supplied data, so use
00818            something inbetween).
00819         */
00820 
00821         cpl_vector *y_dup = cpl_vector_duplicate(y);
00822         
00823         if (y_dup == NULL)
00824             {
00825             irplib_matrix_unwrap_const(x_matrix);
00826             cpl_ensure_code(
00827                 CPL_FALSE,
00828                 CPL_ERROR_ILLEGAL_OUTPUT);
00829             }
00830         
00831         offset_guess = uves_utils_get_kth_double(
00832             irplib_vector_get_data(y_dup), N, N/4);
00833         
00834         cpl_vector_delete(y_dup);
00835         }
00836     else
00837         {
00838         offset_guess = *offset;
00839         }
00840     
00841     /* Get quartiles of distribution
00842        (only bother if it's needed for estimation of x0 or sigma) */
00843     if ( (fit_pars & CPL_FIT_CENTROID) ||
00844          (fit_pars & CPL_FIT_STDEV   )
00845         )
00846         {
00847         /* The algorithm requires the input to be sorted
00848            as function of x, so do that (using qsort), and
00849            work on the sorted copy. Of course, the y-vector
00850            must be re-ordered along with x.
00851            sigma_x and sigma_y are not used, so don't copy those.
00852         */
00853         
00854         uves_fit_1d_input
00855             *sorted_input = cpl_malloc(N * sizeof(*sorted_input));
00856         const double *x_data = irplib_matrix_get_data_const(x_matrix);
00857         cpl_boolean is_sorted = CPL_TRUE;
00858         int i;
00859         
00860         if (sorted_input == NULL)
00861             {
00862             irplib_matrix_unwrap_const(x_matrix);
00863             cpl_ensure_code(
00864                 CPL_FALSE,
00865                 CPL_ERROR_ILLEGAL_INPUT);
00866             }
00867         
00868         for (i = 0; i < N; i++)
00869             {
00870             sorted_input[i].x = x_data[i];
00871             sorted_input[i].y = y_data[i];
00872             
00873             is_sorted = is_sorted && 
00874                 (i==0 || (x_data[i-1] < x_data[i]));
00875             }            
00876         
00877         if (!is_sorted)
00878             {
00879             qsort(sorted_input, N, sizeof(*sorted_input),
00880                   &uves_fit_1d_compare);
00881             }
00882 
00883         for(i = 0; i < N; i++)
00884             {
00885             double flux = sorted_input[i].y;
00886             
00887             sum += (flux - offset_guess);
00888             }
00889         /* Note that 'sum' must be calculated the same way as
00890            'running_sum' below, Otherwise (due to round-off error)
00891            'running_sum' might end up being different from 'sum'(!).
00892            Specifically, it will not work to calculate 'sum' as
00893            
00894            (flux1 + ... + fluxN)  -  N*offset_guess
00895         */
00896         
00897         if (sum > 0.0)
00898             {
00899             double flux, x1, x2;
00900             double running_sum = 0.0;
00901             int j;
00902             
00903             i = 0;
00904             flux = sorted_input[i].y - offset_guess;
00905             
00906             for (j = 0; j < 3; j++)
00907                 {
00908                 double limit = fraction[j] * sum;
00909                 double k;
00910                 
00911                 while (running_sum + flux < limit && i < N-1)
00912                     {
00913                     running_sum += flux;
00914                     i++;
00915                     flux = sorted_input[i].y - offset_guess;
00916                     }
00917 
00918                 /* Fraction [0;1] of current flux needed
00919                    to reach the quartile */
00920                 k = (limit - running_sum)/flux;
00921                 
00922                 if (k <= 0.5)
00923                     {
00924                     /* Interpolate linearly between
00925                        current and previous position
00926                     */
00927                     if (0 < i)
00928                         {
00929                         x1 = sorted_input[i-1].x;
00930                         x2 = sorted_input[i].x;
00931                         
00932                         quartile[j] = 
00933                             x1*(0.5-k) +
00934                             x2*(0.5+k);
00935                         /*
00936                           k=0   => quartile = midpoint,
00937                           k=0.5 => quartile = x2
00938                         */
00939                         }
00940                     else
00941                         {
00942                         quartile[j] = sorted_input[i].x;
00943                         }
00944                     }
00945                 else
00946                     {
00947                     /* Interpolate linearly between
00948                        current and next position */
00949                     if (i < N-1)
00950                         {
00951                         x1 = sorted_input[i].x;
00952                         x2 = sorted_input[i+1].x;
00953                         
00954                         quartile[j] = 
00955                             x1*( 1.5-k) +
00956                             x2*(-0.5+k);
00957                         /*
00958                           k=0.5 => quartile = x1,
00959                           k=1.0 => quartile = midpoint
00960                         */
00961                         }
00962                     else
00963                         {
00964                         quartile[j] = sorted_input[i].x;
00965                         }
00966                     }
00967                 }
00968             }
00969         else
00970             {
00971             /* If there's no flux (sum = 0) then
00972                set quartiles to something that's not 
00973                completely insensible.
00974             */
00975             quartile[1] = cpl_matrix_get_mean(x_matrix);
00976             
00977             quartile[2] = quartile[1];
00978             quartile[0] = quartile[2] - 1.0;
00979             /* Then sigma_guess = 1.0 */
00980             }
00981 
00982         cpl_free(sorted_input);
00983         } /* If need to compute quartiles */
00984         
00985     /* x0_guess = median of distribution */
00986     x0_guess = (fit_pars & CPL_FIT_CENTROID) ? quartile[1] : *x0;
00987     
00988     /* sigma_guess = median of absolute residuals
00989      *
00990      *  (68% is within 1 sigma, and 50% is within 0.6744
00991      *  sigma,  => quartile3-quartile1 = 2*0.6744 sigma)
00992      */
00993     sigma_guess = (fit_pars & CPL_FIT_STDEV) ? 
00994         (quartile[2] - quartile[0]) / (2*0.6744) : *sigma;
00995     
00996     area_guess  = (fit_pars & CPL_FIT_AREA) ?
00997         (cpl_vector_get_max(y) - offset_guess) * sqrt(2*M_PI) * sigma_guess : *area;
00998     /* This formula makes sense only if the area is positive */
00999     
01000     /* Make sure that the area is a positive number */
01001     if ( area_guess <= 0)  area_guess = 1.0;
01002     if (sigma_guess <= 0) sigma_guess = 1.0;
01003     }
01004     
01005     /* Wrap parameters, fit, unwrap */
01006     {
01007     cpl_vector *a;
01008     int ia[5];            /* The last element
01009                  is ignored if
01010                  M = 4 */
01011     cpl_error_code ec;
01012 
01013     assert(M == 4 || M == 5);
01014     a = cpl_vector_new(M);
01015 
01016     if (a == NULL)
01017         {
01018         irplib_matrix_unwrap_const(x_matrix);
01019         cpl_ensure_code(
01020             CPL_FALSE,
01021             CPL_ERROR_ILLEGAL_OUTPUT);
01022         }
01023 
01024     cpl_vector_set(a, 0, x0_guess);
01025     cpl_vector_set(a, 1, sigma_guess);
01026     cpl_vector_set(a, 2, area_guess);
01027     cpl_vector_set(a, 3, offset_guess);
01028     
01029     ia[0] = fit_pars & CPL_FIT_CENTROID;
01030     ia[1] = fit_pars & CPL_FIT_STDEV;
01031     ia[2] = fit_pars & CPL_FIT_AREA;
01032     ia[3] = fit_pars & CPL_FIT_OFFSET;
01033 
01034     if (M == 5)
01035         {
01036         /* linear sky-term, first hold it constant,
01037          * then call LM-fitting a second time where
01038          * it is non-constant */
01039         if (fit_pars & CPL_FIT_OFFSET)
01040                     {
01041                         cpl_vector_set(a, 4, 0);
01042                     }
01043                 else
01044                     {
01045                         cpl_vector_set(a, 4, *slope);
01046                     }
01047 
01048         ia[4] = 0;
01049         }
01050     
01051     ec = uves_fit(x_matrix, NULL,
01052             y, sigma_y, 
01053             a, ia, f, dfda,
01054             mse, red_chisq,
01055             covariance);
01056     
01057 //    printf("Sky: e='%s'\n", cpl_error_get_message()); cpl_vector_dump(a, stdout);
01058     if (M == 5)
01059         {
01060         ia[4] = fit_pars & CPL_FIT_OFFSET;
01061 
01062         if (covariance != NULL)
01063             {
01064             uves_free_matrix(covariance);
01065             }
01066 
01067         ec = uves_fit(x_matrix, NULL,
01068                 y, sigma_y, 
01069                 a, ia, f, dfda,
01070                 mse, red_chisq,
01071                 covariance);
01072 //    printf("Sky: e='%s'\n", cpl_error_get_message()); cpl_vector_dump(a, stdout);
01073         }
01074 
01075     irplib_matrix_unwrap_const(x_matrix);
01076     
01077     /* Check return status of fitting routine */
01078     if (ec == CPL_ERROR_NONE      ||
01079         ec == CPL_ERROR_SINGULAR_MATRIX)
01080         {
01081         /* The LM algorithm converged. The computation
01082          *  of the covariance matrix might have failed.
01083          */
01084         
01085         /* In principle, the LM algorithm might have converged
01086          * to a negative sigma (even if the guess value was
01087          * positive). Make sure that the returned sigma is positive
01088          * (by convention).
01089          */
01090 
01091         if (CPL_FIT_CENTROID) *x0     = cpl_vector_get(a, 0);
01092         if (CPL_FIT_STDEV   ) *sigma  = fabs(cpl_vector_get(a, 1));
01093         if (CPL_FIT_AREA    ) *area   = cpl_vector_get(a, 2);
01094         if (CPL_FIT_OFFSET  ) {
01095                     *offset = cpl_vector_get(a, 3);
01096                     if (M == 5) *slope = cpl_vector_get(a, 4);
01097                 }
01098         }
01099     
01100     cpl_vector_delete(a);
01101     
01102     xlo = cpl_vector_get_min(x);
01103     xhi = cpl_vector_get_max(x);
01104 
01105     if (ec == CPL_ERROR_CONTINUE ||
01106         !(
01107         !irplib_isnan(*x0    ) && !irplib_isinf(*x0    ) &&
01108         !irplib_isnan(*sigma ) && !irplib_isinf(*sigma ) &&
01109         !irplib_isnan(*area  ) && !irplib_isinf(*area  ) &&
01110         !irplib_isnan(*offset) && !irplib_isinf(*offset) &&
01111         ((M != 5) || (!irplib_isnan(*slope ) && !irplib_isinf(*slope ))) &&
01112         xlo <= *x0 && *x0 <= xhi &&
01113         0 < *sigma && *sigma < (xhi - xlo + 1) &&
01114         (fit_back || 0 < *area)
01115         /* This extra check on the background level makes sense
01116            iff the input flux is assumed to be positive
01117            && *offset > - *area  */
01118         )
01119         )
01120         {
01121         /* The LM algorithm did not converge, or it converged to
01122          * a non-sensical result. Return the guess parameter values
01123          * in order to enable the caller to recover. */
01124 
01125         *x0         = x0_guess;
01126         *sigma      = sigma_guess;
01127         *area       = area_guess;
01128         *offset     = offset_guess;
01129                 if (M == 5) *slope = 0;
01130         
01131         /* In this case the covariance matrix will not make sense
01132            (because the LM algorithm failed), so delete it */
01133         if (covariance != NULL && *covariance != NULL)
01134             {
01135             cpl_matrix_delete(*covariance);
01136             *covariance = NULL;
01137             }
01138 
01139         /* Return CPL_ERROR_CONTINUE if the fitting routine failed */
01140         cpl_ensure_code(
01141             CPL_FALSE,
01142             CPL_ERROR_CONTINUE);
01143         }
01144     }
01145     
01146     return CPL_ERROR_NONE;
01147 }
01148 /* @endcond */
01149 
01150 #define DEBUG_LM 0   /* Set to non-zero to print info on the error msg level */
01151 /*----------------------------------------------------------------------------*/
01218 /*----------------------------------------------------------------------------*/
01219 cpl_error_code
01220 uves_fit(const cpl_matrix *x, const cpl_matrix *sigma_x,
01221      const cpl_vector *y, const cpl_vector *sigma_y,
01222      cpl_vector *a, const int ia[],
01223      int    (*f)(const double x[], const double a[], double *result),
01224      int (*dfda)(const double x[], const double a[], double result[]),
01225      double *mse,
01226      double *red_chisq,
01227      cpl_matrix **covariance)
01228 {
01229     const double *x_data     = NULL; /* Pointer to input data                  */
01230     const double *y_data     = NULL; /* Pointer to input data                  */
01231     const double *sigma_data = NULL; /* Pointer to input data                  */
01232     int N    = 0;                    /* Number of data points                  */
01233     int D    = 0;                    /* Dimension of x-points                  */
01234     int M    = 0;                    /* Number of fit parameters               */
01235     int Mfit = 0;                    /* Number of non-constant fit
01236                         parameters                             */
01237 
01238     double lambda    = 0.0;          /* Lambda in L-M algorithm                */
01239     double MAXLAMBDA = 10e40;        /* Parameter to control the graceful exit
01240                     if steepest descent unexpectedly fails */
01241     double chi_sq    = 0.0;          /* Current  chi^2                         */
01242     int count        = 0;            /* Number of successive small improvements
01243                     in chi^2 */
01244     int iterations   = 0;
01245    
01246     cpl_matrix *alpha  = NULL;       /* The MxM ~curvature matrix used in L-M  */
01247     cpl_matrix *beta   = NULL;       /* Mx1 matrix = -.5 grad(chi^2)           */
01248     double *a_data     = NULL;       /* Parameters, a                          */
01249     double *a_da       = NULL;       /* Candidate position a+da                */
01250     double *part       = NULL;       /* The partial derivatives df/da          */
01251     int *ia_local      = NULL;       /* non-NULL version of ia                 */
01252    
01253     /* If covariance computation is requested, then either
01254      * return the covariance matrix or return NULL.
01255      */
01256     if (covariance != NULL) *covariance = NULL;
01257 
01258     /* Validate input */
01259     cpl_ensure_code(x       != NULL, CPL_ERROR_NULL_INPUT);
01260     cpl_ensure_code(sigma_x == NULL, CPL_ERROR_UNSUPPORTED_MODE);
01261     cpl_ensure_code(y       != NULL, CPL_ERROR_NULL_INPUT);
01262     cpl_ensure_code(a       != NULL, CPL_ERROR_NULL_INPUT);
01263     /* ia may be NULL */
01264     cpl_ensure_code(f       != NULL, CPL_ERROR_NULL_INPUT);
01265     cpl_ensure_code(dfda    != NULL, CPL_ERROR_NULL_INPUT);
01266 
01267     /* Chi^2 and covariance computations require sigmas to be known */
01268     cpl_ensure_code( sigma_y != NULL || (red_chisq == NULL && covariance == NULL),
01269              CPL_ERROR_INCOMPATIBLE_INPUT);
01270 
01271     D = cpl_matrix_get_ncol(x);
01272     N = cpl_matrix_get_nrow(x);
01273     M = cpl_vector_get_size(a);
01274     cpl_ensure_code(N > 0 && D > 0 && M > 0, CPL_ERROR_ILLEGAL_INPUT);
01275 
01276     cpl_ensure_code( cpl_vector_get_size(y) == N,
01277              CPL_ERROR_INCOMPATIBLE_INPUT);
01278 
01279     x_data = irplib_matrix_get_data_const(x);
01280     y_data = irplib_vector_get_data_const(y);
01281     a_data = irplib_vector_get_data(a);
01282 
01283     if (sigma_y != NULL)
01284     {
01285         cpl_ensure_code( cpl_vector_get_size(sigma_y) == N,
01286                  CPL_ERROR_INCOMPATIBLE_INPUT);
01287         /* Sigmas must be positive */
01288         cpl_ensure_code( cpl_vector_get_min (sigma_y) > 0,
01289                  CPL_ERROR_ILLEGAL_INPUT);
01290         sigma_data = irplib_vector_get_data_const(sigma_y);
01291     }
01292 
01293     ia_local = cpl_malloc(M * sizeof(int));
01294     cpl_ensure_code(ia_local != NULL, CPL_ERROR_ILLEGAL_OUTPUT);
01295 
01296     /* Count non-constant fit parameters, copy ia */
01297     if (ia != NULL)
01298     {
01299         int i;
01300 
01301         Mfit = 0;
01302         for (i = 0; i < M; i++)
01303         {
01304             ia_local[i] = ia[i];
01305 
01306             if (ia[i] != 0) 
01307             {
01308                 Mfit += 1;
01309             }
01310         }
01311         
01312         if (! (Mfit > 0))
01313         {
01314             cpl_free(ia_local);
01315             cpl_ensure_code( CPL_FALSE,
01316                      CPL_ERROR_ILLEGAL_INPUT);
01317         }
01318     }
01319     else
01320     {
01321         /* All parameters participate */
01322         int i;
01323         
01324         Mfit = M;
01325         
01326         for (i = 0; i < M; i++)
01327         {
01328             ia_local[i] = 1;
01329         }
01330     }
01331 
01332     /* To compute reduced chi^2, we need N > Mfit */
01333     if (! ( red_chisq == NULL || N > Mfit ) )
01334     {
01335         cpl_free(ia_local);
01336         cpl_ensure_code(
01337         CPL_FALSE,
01338         CPL_ERROR_ILLEGAL_INPUT);
01339     }
01340 
01341     /* Create alpha, beta, a_da, part  work space */
01342     alpha = cpl_matrix_new(Mfit, Mfit);
01343     if (alpha == NULL)
01344     {
01345         cpl_free(ia_local);
01346         cpl_ensure_code(
01347         CPL_FALSE,
01348         CPL_ERROR_ILLEGAL_OUTPUT);
01349     }
01350    
01351     beta = cpl_matrix_new(Mfit, 1);
01352     if (beta == NULL)
01353     {
01354         cpl_free(ia_local);
01355         cpl_matrix_delete(alpha);
01356         cpl_ensure_code(
01357         CPL_FALSE,
01358         CPL_ERROR_ILLEGAL_OUTPUT);
01359     }
01360 
01361     a_da = cpl_malloc(M * sizeof(double));
01362     if (a_da == NULL)
01363     {
01364         cpl_free(ia_local);
01365         cpl_matrix_delete(alpha);
01366         cpl_matrix_delete(beta);
01367         cpl_ensure_code(
01368         CPL_FALSE,
01369         CPL_ERROR_ILLEGAL_OUTPUT);
01370     }
01371 
01372     part = cpl_malloc(M * sizeof(double));
01373     if (part == NULL)
01374     {
01375         cpl_free(ia_local);
01376         cpl_matrix_delete(alpha);
01377         cpl_matrix_delete(beta);
01378         cpl_free(a_da);
01379         cpl_ensure_code(
01380         CPL_FALSE,
01381         CPL_ERROR_ILLEGAL_OUTPUT);
01382     }
01383 
01384     /* Initialize loop variables */
01385     lambda = 0.001;
01386     count = 0;
01387     iterations = 0;
01388     if( (chi_sq = get_chisq(N, D, f, a_data, x_data, y_data, sigma_data)) < 0)
01389     {
01390         cpl_free(ia_local);
01391         cpl_matrix_delete(alpha);
01392         cpl_matrix_delete(beta);
01393         cpl_free(a_da);
01394         cpl_free(part);
01395         cpl_ensure_code(
01396         CPL_FALSE,
01397         cpl_error_get_code());
01398     }
01399 
01400 #if DEBUG_LM    
01401      uves_msg_error("Initial chi^2 = %f", chi_sq); 
01402      {int i;
01403      for (i = 0; i < M; i++) 
01404      {
01405          uves_msg_error("Initial a[%d] = %e", i, a_data[i]); 
01406      }
01407      }
01408 #endif
01409 
01410     /* Iterate until chi^2 didn't improve substantially many (say, 5)
01411        times in a row */
01412     while (count < 5 && lambda < MAXLAMBDA && iterations < UVES_FIT_MAXITER)
01413     {
01414         /* In each iteration lambda increases, or chi^2 decreases or
01415            count increases. Because chi^2 is bounded from below
01416            (and lambda and count from above), the loop will terminate */
01417 
01418         double chi_sq_candidate = 0.0;
01419         int returncode = 0;
01420 
01421         /* Get candidate position in parameter space = a+da,
01422          * where  alpha * da = beta .
01423          * Increase lambda until alpha is non-singular
01424          */
01425        
01426         while( (returncode = get_candidate(a_data, ia_local,
01427                            M, N, D,
01428                            lambda, f, dfda,
01429                            x_data, y_data, sigma_data,
01430                            part, alpha, beta, a_da)
01431                ) != 0
01432            && cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX
01433            && lambda < MAXLAMBDA)
01434         {
01435 #if DEBUG_LM    
01436             uves_msg_error("Singular matrix. lambda = %e", lambda);
01437 #endif
01438             cpl_error_reset();
01439             lambda *= 9.0;
01440         }
01441        
01442         /* Set error if lambda diverged */
01443         if ( !( lambda < MAXLAMBDA ) )
01444         {
01445             cpl_free(ia_local);
01446             cpl_matrix_delete(alpha);
01447             cpl_matrix_delete(beta);
01448             cpl_free(a_da);
01449             cpl_free(part);
01450             cpl_ensure_code(
01451             CPL_FALSE,
01452             CPL_ERROR_CONTINUE);
01453         }
01454        
01455         if (returncode != 0)
01456         {
01457             cpl_free(ia_local);
01458             cpl_matrix_delete(alpha);
01459             cpl_matrix_delete(beta);
01460             cpl_free(a_da);
01461             cpl_free(part);
01462             cpl_ensure_code(
01463             CPL_FALSE,
01464             cpl_error_get_code());
01465         }
01466 
01467         /* Get chi^2(a+da) */
01468         if ((chi_sq_candidate = get_chisq(N, D, f, a_da,
01469                           x_data, y_data, sigma_data)) < 0)
01470         {
01471             cpl_free(ia_local);
01472             cpl_matrix_delete(alpha);
01473             cpl_matrix_delete(beta);
01474             cpl_free(a_da);
01475             cpl_free(part);
01476             cpl_ensure_code(
01477             CPL_FALSE,
01478             cpl_error_get_code());
01479         }
01480 
01481         if (chi_sq_candidate > 1.000001 * chi_sq)
01482         {
01483             /* Move towards steepest descent */
01484 #if DEBUG_LM
01485             uves_msg_error("Chi^2 = %f  Candidate = %f  Lambda = %e",
01486                chi_sq, chi_sq_candidate, lambda); 
01487 #endif            
01488             lambda *= 9.0;
01489         }
01490         else
01491         {
01492 #if DEBUG_LM
01493             uves_msg_error("Chi^2 = %f  Candidate = %f* Lambda = %e count = %d",
01494                chi_sq, chi_sq_candidate, lambda, count);
01495 #endif
01496        
01497             /* Move towards Newton's algorithm */
01498             lambda /= 10.0;
01499 
01500             /* Count the number of successive improvements in chi^2 of
01501                less than 0.01 relative */
01502             if ( chi_sq == 0 ||
01503              (chi_sq - chi_sq_candidate)/chi_sq < .01)
01504             {
01505                 count += 1;
01506             }
01507             else
01508             {
01509                 /* Chi^2 improved by a significant amount,
01510                    reset counter */
01511                 count = 0;
01512             }
01513 
01514             if (chi_sq_candidate < chi_sq)
01515             {
01516                 /* chi^2 improved, update a and chi^2 */
01517                 int i;
01518                 for (i = 0; i < M; i++) 
01519                 {
01520                     a_data[i] = a_da[i];
01521 #if DEBUG_LM
01522                     uves_msg_error("-> a[%d] = %e", i, a_da[i]); 
01523 #endif
01524                 }
01525                 chi_sq = chi_sq_candidate;
01526             }
01527         }
01528         iterations++;
01529     }
01530 
01531     /* Set error if we didn't converge */
01532     if ( !( lambda < MAXLAMBDA && iterations < UVES_FIT_MAXITER ) )
01533     {
01534 #if DEBUG_LM
01535         uves_msg_error("Failed to converge, lambda=%f iterations=%d",
01536                lambda, iterations);
01537 #endif
01538         cpl_free(ia_local);
01539         cpl_matrix_delete(alpha);
01540         cpl_matrix_delete(beta);
01541         cpl_free(a_da);
01542         cpl_free(part);
01543         cpl_ensure_code(
01544         CPL_FALSE,
01545         CPL_ERROR_CONTINUE);
01546     }
01547 
01548     /* Compute mse if requested */
01549     if (mse != NULL)
01550     {
01551         int i;
01552 
01553         *mse = 0.0;
01554        
01555         for(i = 0; i < N; i++)
01556         {
01557             double fx_i = 0.0;
01558             double residual = 0.0;
01559            
01560             /* Evaluate f(x_i) at the best fit parameters */
01561             if( f(&(x_data[i*D]),
01562               a_data,
01563               &fx_i) != 0)
01564             {
01565                 cpl_free(ia_local);
01566                 cpl_matrix_delete(alpha);
01567                 cpl_matrix_delete(beta);
01568                 cpl_free(a_da);
01569                 cpl_free(part);
01570                 cpl_ensure_code(
01571                 CPL_FALSE,
01572                 CPL_ERROR_ILLEGAL_INPUT);
01573             }
01574 
01575             residual = y_data[i] - fx_i;
01576             *mse += residual * residual;
01577         }
01578         *mse /= N;
01579     }
01580 
01581     /* Compute reduced chi^2 if requested */
01582     if (red_chisq != NULL)
01583     {
01584         /* We already know the optimal chi^2 (and that N > Mfit)*/
01585         *red_chisq = chi_sq / (N-Mfit);
01586     }
01587 
01588     /* Compute covariance matrix if requested
01589      * cov = alpha(lambda=0)^-1              
01590      */
01591     if (covariance != NULL)
01592     {
01593         cpl_matrix *cov;
01594 
01595         if( get_candidate(a_data, ia_local, 
01596                   M, N, D, 0.0, f, dfda, 
01597                   x_data, y_data, sigma_data,
01598                   part, alpha, beta, a_da)
01599         != 0)
01600         {
01601             cpl_free(ia_local);
01602             cpl_matrix_delete(alpha);
01603             cpl_matrix_delete(beta);
01604             cpl_free(a_da);
01605             cpl_free(part);
01606             cpl_ensure_code(
01607             CPL_FALSE,
01608             cpl_error_get_code());
01609         }
01610        
01611         cov = cpl_matrix_invert_create(alpha);
01612         if (cov == NULL)
01613         {
01614             cpl_free(ia_local);
01615             cpl_matrix_delete(alpha);
01616             cpl_matrix_delete(beta);
01617             cpl_free(a_da);
01618             cpl_free(part);
01619             cpl_ensure_code(
01620             CPL_FALSE,
01621             cpl_error_get_code());
01622         }
01623        
01624         /* Make sure that variances are positive */
01625         {
01626         int i;
01627         for (i = 0; i < Mfit; i++)
01628             {
01629             if ( !(cpl_matrix_get(cov, i, i) > 0) )
01630                 {
01631                 cpl_free(ia_local);
01632                 cpl_matrix_delete(alpha);
01633                 cpl_matrix_delete(beta);
01634                 cpl_free(a_da);
01635                 cpl_free(part);
01636                 cpl_matrix_delete(cov);
01637                 *covariance = NULL;
01638                 cpl_ensure_code(
01639                     CPL_FALSE,
01640                     CPL_ERROR_SINGULAR_MATRIX);
01641                 }
01642             }
01643         }
01644 
01645         /* Expand covariance matrix from Mfit x Mfit
01646            to M x M. Set rows/columns corresponding to fixed
01647            parameters to zero */
01648 
01649         *covariance = cpl_matrix_new(M, M);
01650         if (*covariance == NULL)
01651         {
01652             cpl_free(ia_local);
01653             cpl_matrix_delete(alpha);
01654             cpl_matrix_delete(beta);
01655             cpl_free(a_da);
01656             cpl_free(part);
01657             cpl_matrix_delete(cov);
01658             cpl_ensure_code(
01659             CPL_FALSE,
01660             CPL_ERROR_ILLEGAL_OUTPUT);
01661         }
01662 
01663         {
01664         int j, jmfit;
01665 
01666         for (j = 0, jmfit = 0; j < M; j++)
01667             if (ia_local[j] != 0)
01668             {
01669                 int i, imfit;
01670 
01671                 for (i = 0, imfit = 0; i < M; i++)
01672                 if (ia_local[i] != 0)
01673                     {
01674                     cpl_matrix_set(*covariance, i, j,
01675                                cpl_matrix_get(
01676                                cov, imfit, jmfit));
01677                     imfit += 1;
01678                     }
01679                 
01680                 assert( imfit == Mfit );
01681 
01682                 jmfit += 1;
01683             }
01684         
01685         assert( jmfit == Mfit );
01686         }
01687 
01688         cpl_matrix_delete(cov);
01689     }
01690     
01691     cpl_free(ia_local);
01692     cpl_matrix_delete(alpha);
01693     cpl_matrix_delete(beta);
01694     cpl_free(a_da);
01695     cpl_free(part);
01696    
01697     return CPL_ERROR_NONE;
01698 }
01699 
01700 /*----------------------------------------------------------------------------*/
01710 /*----------------------------------------------------------------------------*/
01711 cpl_error_code
01712 uves_cast_image(cpl_image **image, cpl_type to_type)
01713 {
01714     cpl_image *temp = NULL;
01715     
01716     assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
01717 
01718     temp = *image;
01719     
01720     check( *image = cpl_image_cast(temp, to_type), "Couldn't convert image to %s", 
01721        uves_tostring_cpl_type(to_type));
01722     
01723   cleanup:
01724     uves_free_image(&temp);
01725     return cpl_error_get_code();    
01726 }
01727 
01728 
01729 /*-----------------------------------------------------------------------------*/
01744 /*-----------------------------------------------------------------------------*/
01745 cpl_error_code
01746 uves_crop_image(cpl_image **image, int x1, int y_1, int x2, int y2)
01747 {
01748     cpl_image *temp = NULL;
01749     
01750     assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
01751 
01752     temp = *image;
01753     
01754     check( *image = cpl_image_extract(temp, x1, y_1, x2, y2), 
01755        "Could not extract image");
01756     
01757   cleanup:
01758     uves_free_image(&temp);
01759     return cpl_error_get_code();    
01760 }
01761 
01762 /*----------------------------------------------------------------------------*/
01786 /*----------------------------------------------------------------------------*/
01787 cpl_error_code
01788 uves_get_property_value(const uves_propertylist *plist, const char *keyword, 
01789             cpl_type keywordtype, void *result)
01790 {
01791     cpl_type t;
01792     
01793     /* Check input */
01794     assure( plist != NULL  , CPL_ERROR_NULL_INPUT, "Null property list");
01795     assure( keyword != NULL, CPL_ERROR_NULL_INPUT, "Null keyword");
01796     
01797     /* Check for existence... */
01798     assure( uves_propertylist_contains(plist, keyword), CPL_ERROR_DATA_NOT_FOUND,
01799         "Keyword %s does not exist", keyword );
01800     /* ...and type of keyword */
01801     check( t = uves_propertylist_get_type(plist, keyword) ,
01802        "Could not read type of keyword '%s'", keyword );
01803     assure(t == keywordtype , CPL_ERROR_TYPE_MISMATCH, 
01804        "Keyword '%s' has wrong type (%s). %s expected",
01805        keyword, uves_tostring_cpl_type(t), uves_tostring_cpl_type(keywordtype));
01806     
01807     /* Read the keyword */
01808     switch (keywordtype)
01809     {
01810     case CPL_TYPE_INT   : 
01811         check( *((      int    *)result) =
01812         uves_propertylist_get_int(plist, keyword),
01813         "Could not get (integer) value of %s", keyword );
01814         break;
01815     case CPL_TYPE_BOOL  : 
01816         check( *((      bool   *)result) =
01817            uves_propertylist_get_bool(plist, keyword), 
01818            "Could not get (boolean) value of %s", keyword ); 
01819         break;
01820     case CPL_TYPE_DOUBLE:
01821         check( *((      double *)result) = 
01822            uves_propertylist_get_double(plist, keyword), 
01823            "Could not get (double) value of %s" , keyword );
01824         break;
01825     case CPL_TYPE_STRING: 
01826         check( *((const char * *)result) = 
01827            uves_propertylist_get_string(plist, keyword), 
01828            "Could not get (string) value of %s" , keyword ); 
01829         break;
01830     default:
01831         assure( false, CPL_ERROR_INVALID_TYPE, "Unknown type");
01832         break;
01833     }
01834     
01835   cleanup:
01836     return cpl_error_get_code();
01837 }
01838 
01839 
01840 /*----------------------------------------------------------------------------*/
01865 /*----------------------------------------------------------------------------*/
01866 
01867 const char *
01868 uves_find_frame(const cpl_frameset *frames, const char **wanted, int N, int *found,
01869         const cpl_frame **frame)
01870 {
01871     const char *filename = NULL;  /* Return NULL in case of error */
01872     int i;
01873     const cpl_frame *f = NULL;
01874     
01875     /* Return well-defined pointers in case of error */
01876     *found = 0;
01877     if (frame != NULL)
01878     {
01879         *frame = NULL;
01880     }
01881 
01882     for (i = 0; i < N; i++)
01883     {
01884         check( f = irplib_frameset_find_const(frames, wanted[i]), 
01885            "Could not search through frame set");
01886         if (f != NULL) 
01887         {
01888             check( filename = cpl_frame_get_filename(f), 
01889                "Could not read frame filename");
01890             *found = i;
01891             if (frame != NULL)
01892             {
01893                 *frame = f;
01894             }
01895             /* break */
01896             i = N;
01897         }
01898     }
01899     
01900     /* Set an error if a matching frame wasn't found */
01901     assure(filename != NULL, CPL_ERROR_DATA_NOT_FOUND, "No such frame in frame set");
01902 
01903   cleanup:
01904     return filename;
01905 }
01906 
01907 
01908 /*----------------------------------------------------------------------------*/
01915 /*----------------------------------------------------------------------------*/
01916 int
01917 uves_get_nextensions(const char *filename)
01918 {
01919     int result = 0;
01920     cpl_frame *f = NULL;
01921     
01922     /* CPL only supports reading the number of extensions of a FITS
01923        file if this is in a frame, so create a frame for the specified file */
01924       
01925     check(( f = cpl_frame_new(),
01926         cpl_frame_set_filename(f, filename)),
01927       "Could not create frame");
01928 
01929     check( result = cpl_frame_get_nextensions(f),
01930        "Error reading number of extensions of file '%s'", filename);
01931   cleanup:
01932     cpl_frame_delete(f);
01933     return result;
01934 }
01935 
01936 /*----------------------------------------------------------------------------*/
01957 /*----------------------------------------------------------------------------*/
01958 cpl_error_code
01959 uves_get_parameter(const cpl_parameterlist *parameters, const char *context,
01960            const char *recipe_id, const char *name, cpl_type type, 
01961            void *value)
01962 {
01963     char *fullname = NULL;
01964     const cpl_parameter *p = NULL;
01965     
01966     passure( parameters != NULL, " ");
01967     /* 'context' may be NULL */
01968     passure( recipe_id != NULL, " ");
01969     passure( name != NULL, " ");
01970     passure( value != NULL, " ");
01971 
01972     if (context != NULL)
01973     {
01974         check( fullname = uves_sprintf("%s.%s.%s", context, recipe_id, name),
01975            "Error getting full parameter name");
01976     }
01977     else
01978     {
01979         check( fullname = uves_sprintf("%s.%s", recipe_id, name),
01980            "Error getting full parameter name");
01981     }
01982 
01983     /* Const cast */
01984     check( p = irplib_parameterlist_find_const(parameters, fullname), 
01985        "Error searching for parameter '%s'", fullname);
01986     assure( p != NULL, CPL_ERROR_DATA_NOT_FOUND, 
01987         "No parameter '%s' in parameter list", fullname);
01988     
01989     /* Check that parameter has the correct type */
01990     {
01991     cpl_type partype;
01992     check(  partype = cpl_parameter_get_type(p), 
01993         "Could not read type of parameter '%s'", fullname);
01994     assure( partype == type, CPL_ERROR_TYPE_MISMATCH,
01995         "Parameter '%s' has type %s. Expected type was %s", 
01996         fullname,
01997         uves_tostring_cpl_type(partype), uves_tostring_cpl_type(type));    
01998     }
01999 
02000     /* Read the parameter */
02001     switch(type)
02002     {
02003     case CPL_TYPE_INT:
02004         check( *(int *         )value = 
02005            cpl_parameter_get_int   (p),
02006            "Could not read integer parameter '%s'", fullname);  
02007         break;
02008     case CPL_TYPE_BOOL:
02009         check( *(bool *        )value = 
02010            cpl_parameter_get_bool  (p),
02011            "Could not read boolean parameter '%s'", fullname);  
02012         break;
02013     case CPL_TYPE_DOUBLE:    
02014         check( *(double *      )value = 
02015            cpl_parameter_get_double(p),
02016            "Could not read double parameter '%s'" , fullname );  
02017         break;
02018     case CPL_TYPE_STRING:
02019         check( *(const char ** )value = 
02020            cpl_parameter_get_string(p),
02021            "Could not read string parameter '%s'" , fullname );  
02022         break;
02023     default:
02024         assure(false, CPL_ERROR_UNSUPPORTED_MODE,
02025            "Don't know how to read parameter '%s' of type %s",
02026            fullname, uves_tostring_cpl_type(type));
02027         break;
02028     }
02029     
02030   cleanup:
02031     cpl_free(fullname); fullname = NULL;
02032     return cpl_error_get_code();
02033 }
02034 
02035 /*----------------------------------------------------------------------------*/
02051 /*----------------------------------------------------------------------------*/
02052 cpl_error_code
02053 uves_set_parameter(cpl_parameterlist *parameters, 
02054            const char *context,
02055            const char *name, cpl_type type, void *value)
02056 {
02057     char *fullname = NULL;
02058     cpl_parameter *p = NULL;
02059     
02060     check( fullname = uves_sprintf("%s.%s", context, name),
02061        "Error getting full parameter name");
02062 
02063     /* Const cast */
02064     check( p = cpl_parameterlist_find(parameters, fullname), 
02065        "Error searching for parameter '%s'", fullname);
02066     assure( p != NULL, CPL_ERROR_DATA_NOT_FOUND, 
02067         "No parameter '%s' in parameter list", fullname);
02068 
02069     /* Check that parameter has the correct type */
02070     {
02071     cpl_type partype;
02072     check(  partype = cpl_parameter_get_type(p), 
02073         "Could not read type of parameter '%s'", fullname);
02074     assure( partype == type, CPL_ERROR_TYPE_MISMATCH,
02075         "Parameter '%s' has type %s. Expected type was %s", 
02076         fullname, uves_tostring_cpl_type(partype),
02077         uves_tostring_cpl_type(type));    
02078     }
02079 
02080     /* Set the parameter */
02081     switch(type)
02082     {
02083     case CPL_TYPE_INT:
02084         check( cpl_parameter_set_int   (p, *((int *)    value)), 
02085            "Could not set integer parameter '%s'", fullname);  
02086         break;
02087     case CPL_TYPE_BOOL:    
02088         check( cpl_parameter_set_bool  (p, *((bool *)    value)), 
02089            "Could not set boolean parameter '%s'", fullname);
02090         break;
02091     case CPL_TYPE_DOUBLE:
02092         check( cpl_parameter_set_double(p, *((double *) value)), 
02093            "Could not set double parameter '%s'" , fullname);
02094         break;
02095     case CPL_TYPE_STRING:
02096         check( cpl_parameter_set_string(p, *((char **)  value)),
02097            "Could not set string parameter '%s'" , fullname);  
02098         break;
02099     default:
02100         assure(false, CPL_ERROR_UNSUPPORTED_MODE,
02101            "Don't know how to set parameter of type %s", 
02102            uves_tostring_cpl_type(type));
02103         break;
02104     }
02105     
02106   cleanup:
02107     cpl_free(fullname); fullname = NULL;
02108     return cpl_error_get_code();
02109 }
02110 
02111 /*----------------------------------------------------------------------------*/
02125 /*----------------------------------------------------------------------------*/
02126 
02127 cpl_error_code
02128 uves_set_parameter_default(cpl_parameterlist *parameters, const char *context,
02129                const char *parname, 
02130                cpl_type type, void *value)
02131 {
02132     const char *full_name = NULL;
02133     cpl_parameter *p = NULL;
02134     cpl_type partype;
02135 
02136     if (context != NULL)
02137     {
02138         full_name = uves_sprintf("%s.%s", context, parname);
02139     }
02140     else
02141     {
02142         full_name = uves_sprintf("%s", parname);
02143     }
02144 
02145     if (full_name == NULL)
02146     {
02147         return CPL_ERROR_ILLEGAL_OUTPUT;
02148     }
02149 
02150 
02151     if ( (p = cpl_parameterlist_find(parameters, full_name)) == NULL)
02152     {
02153         uves_msg_error("Missing parameter: '%s'", full_name);
02154 
02155         uves_free_string_const(&full_name);
02156         if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
02157         else return CPL_ERROR_DATA_NOT_FOUND;
02158     }
02159     
02160     partype = cpl_parameter_get_type(p);
02161     
02162     if (partype != type)
02163     {
02164         uves_msg_error("Parameter '%s' has type %s. Expected type was %s", 
02165               full_name, uves_tostring_cpl_type(partype), 
02166               uves_tostring_cpl_type(type));
02167 
02168         uves_free_string_const(&full_name);
02169         return CPL_ERROR_TYPE_MISMATCH;
02170     }
02171 
02172     switch(type)
02173     {
02174     case CPL_TYPE_INT:
02175         cpl_parameter_set_default_int   (p, *((int *)    value)); 
02176         break;
02177     case CPL_TYPE_BOOL:
02178         cpl_parameter_set_default_bool  (p, *((bool *)   value)); 
02179         break;
02180     case CPL_TYPE_DOUBLE:
02181         cpl_parameter_set_default_double(p, *((double *) value)); 
02182         break;
02183     case CPL_TYPE_STRING:
02184         cpl_parameter_set_default_string(p, *((char **)  value)); 
02185         break;
02186     default:
02187         uves_msg_error("Unknown type: %s", uves_tostring_cpl_type(type));
02188 
02189         uves_free_string_const(&full_name);
02190         return CPL_ERROR_INVALID_TYPE;
02191     }
02192 
02193     if (cpl_error_get_code() != CPL_ERROR_NONE)
02194     {
02195         uves_msg_error("Error changing value of parameter '%s'", 
02196                full_name);
02197 
02198         uves_free_string_const(&full_name);
02199         return cpl_error_get_code();
02200     }
02201 
02202 
02203     uves_free_string_const(&full_name);
02204     return CPL_ERROR_NONE;
02205 }
02206 
02207 
02208 /*----------------------------------------------------------------------------*/
02220 /*----------------------------------------------------------------------------*/
02221 void 
02222 uves_raise_to_median_frac(cpl_table *t, const char *column, double fraction)
02223 {
02224     int i = 0;
02225     double threshold;
02226 
02227     assure_nomsg(t != NULL, CPL_ERROR_NULL_INPUT);
02228     assure(cpl_table_has_column(t, column), CPL_ERROR_DATA_NOT_FOUND,
02229        "No such column: %s", column);
02230 
02231     assure(cpl_table_get_column_type(t, column) == CPL_TYPE_DOUBLE,
02232        CPL_ERROR_UNSUPPORTED_MODE, "Column %s has type %s. %s expected",
02233        column,
02234        uves_tostring_cpl_type(cpl_table_get_column_type(t, column)),
02235        uves_tostring_cpl_type(CPL_TYPE_DOUBLE));
02236 
02237 
02238     threshold = fraction * cpl_table_get_column_median(t, column);
02239     for (i = 0; i < cpl_table_get_nrow(t); i++)
02240     {
02241         if (cpl_table_get_double(t, column, i, NULL) < threshold)
02242         {
02243             cpl_table_set_double(t, column, i, threshold);
02244         }
02245     }
02246 
02247   cleanup:
02248     return;
02249 }
02250 
02251 
02252 /*----------------------------------------------------------------------------*/
02269 /*----------------------------------------------------------------------------*/
02270 
02271 int
02272 uves_select_table_rows(cpl_table *t,  const char *column, 
02273                cpl_table_select_operator operator, double value)
02274 {
02275     int result = 0;
02276     cpl_type type;
02277     
02278     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
02279     assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT, 
02280         "No such column: %s", column);
02281 
02282     type = cpl_table_get_column_type(t, column);
02283 
02284     assure( type == CPL_TYPE_DOUBLE || type == CPL_TYPE_FLOAT ||
02285         type == CPL_TYPE_INT, CPL_ERROR_INVALID_TYPE,
02286         "Column '%s' must be double or int. %s found", column, 
02287         uves_tostring_cpl_type(type));
02288 
02289     check( cpl_table_select_all(t), "Error selecting rows");
02290     
02291     if      (type == CPL_TYPE_DOUBLE)
02292     {
02293         result = cpl_table_and_selected_double(t, column, operator, value);
02294     }
02295     else if (type == CPL_TYPE_FLOAT)
02296     {
02297         result = cpl_table_and_selected_float(t, column, operator, value);
02298     }
02299     else if (type == CPL_TYPE_INT)
02300     {
02301         result = cpl_table_and_selected_int(t, column, operator, 
02302                                                 uves_round_double(value));
02303     }
02304     else { /*impossible*/ passure(false, ""); }
02305     
02306   cleanup:
02307     return result;
02308 
02309 }
02310 
02311 /*----------------------------------------------------------------------------*/
02325 /*----------------------------------------------------------------------------*/
02326 int
02327 uves_extract_table_rows_local(cpl_table *t, const char *column,
02328                   cpl_table_select_operator operator, double value)
02329 {
02330     int result = 0;
02331     
02332     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
02333     assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT, 
02334         "No such column: %s", column);
02335 
02336     check( result = uves_select_table_rows(t, column, operator, value),
02337        "Error selecting rows");
02338 
02339     check( cpl_table_not_selected(t), "Error selecting rows");
02340 
02341     check( uves_table_erase_selected_dfs02356(t), "Error deleting rows");
02342 
02343   cleanup:
02344     return result;
02345 }
02346 
02347 /*----------------------------------------------------------------------------*/
02366 /*----------------------------------------------------------------------------*/
02367 int
02368 uves_erase_table_rows(cpl_table *t, const char *column,
02369               cpl_table_select_operator operator, double value)
02370 {
02371     int result = 0;
02372     
02373     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
02374     assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT, 
02375         "No such column: %s", column);
02376 
02377     check( result = uves_select_table_rows(t, column, operator, value),
02378        "Error selecting rows");
02379 
02380     check( uves_table_erase_selected_dfs02356(t), "Error deleting rows");
02381 
02382   cleanup:
02383     return result;
02384 }
02385 
02386 
02387 
02388 
02389 
02390 /*----------------------------------------------------------------------------*/
02399 /*----------------------------------------------------------------------------*/
02400 
02401 void uves_propertylist_append_property(uves_propertylist *plist, const cpl_property *p)
02402 {
02403     switch(cpl_property_get_type(p)) {
02404     case CPL_TYPE_CHAR:
02405         uves_propertylist_append_char(plist, cpl_property_get_name(p), cpl_property_get_char(p));
02406         break;
02407     case CPL_TYPE_BOOL:
02408         uves_propertylist_append_bool(plist, cpl_property_get_name(p), cpl_property_get_bool(p));
02409         break;
02410     case CPL_TYPE_INT:
02411         uves_propertylist_append_int(plist, cpl_property_get_name(p), cpl_property_get_int(p));
02412         break;
02413     case CPL_TYPE_LONG:
02414         uves_propertylist_append_long(plist, cpl_property_get_name(p), cpl_property_get_long(p));
02415         break;
02416     case CPL_TYPE_FLOAT:
02417         uves_propertylist_append_float(plist, cpl_property_get_name(p), cpl_property_get_float(p));
02418         break;
02419     case CPL_TYPE_DOUBLE:
02420         uves_propertylist_append_double(plist, cpl_property_get_name(p), cpl_property_get_double(p));
02421         break;
02422     case CPL_TYPE_STRING:
02423         uves_propertylist_append_string(plist, cpl_property_get_name(p), cpl_property_get_string(p));
02424         break;
02425     default:
02426         assure( false, CPL_ERROR_UNSUPPORTED_MODE,
02427                 "Type is %s", uves_tostring_cpl_type(cpl_property_get_type(p)));
02428         break;
02429     }
02430   cleanup:
02431     return;
02432 }
02433 
02434 /* This is really, really bad. If CPL realeased their bug-fixes, it wouldn't have been necessary.
02435    The following is duplicated from CPL and renamed cpl->xxx
02436 
02437    Did I mention that this is an ugly workaround. */
02438 
02439 typedef struct _xxx_table_ xxx_table;
02440 typedef int xxx_column_flag;
02441 typedef struct _xxx_column_ xxx_column;
02442 
02443 typedef union _xxx_column_values_ {
02444     int        *i;                          /* CPL_TYPE_INT    */
02445     float      *f;                          /* CPL_TYPE_FLOAT  */
02446     double     *d;                          /* CPL_TYPE_DOUBLE */
02447     char      **s;                          /* CPL_TYPE_STRING */
02448     cpl_array **array;                      /* Array types     */
02449 } xxx_column_values;
02450 
02451 struct _xxx_column_ {
02452     char              *name;
02453     char              *unit;
02454     char              *format;
02455     int                length;
02456     int                depth;
02457     cpl_type           type;
02458     xxx_column_values *values;
02459     xxx_column_flag   *null;       /* NULL flags buffer              */
02460     int                nullcount;  /* Number of NULLs in column      */
02461     cpl_array         *dimensions; /* Number of dimensions in column */
02462 };
02463 
02464 struct _xxx_table_ {
02465     int              nc;
02466     int              nr;
02467     xxx_column     **columns;
02468     xxx_column_flag *select;
02469     int              selectcount;
02470 };
02471 
02472 
02473 
02474 
02475 
02476 
02477 
02478 #define CPL_INT_SWAP(a,b) { register int t=(a);(a)=(b);(b)=t; }
02479 
02480 #define CPL_PIX_STACK_SIZE 50
02481 /*----------------------------------------------------------------------------*/
02492 /*----------------------------------------------------------------------------*/
02493 static cpl_error_code xxx_tools_sort_int(
02494         int     *   pix_arr,
02495         int         n)
02496 {
02497     int         i, ir, j, k, l;
02498     int         i_stack[CPL_PIX_STACK_SIZE] ;
02499     int         j_stack ;
02500     int         a ;
02501 
02502     /* Check entries */
02503     cpl_ensure(pix_arr, CPL_ERROR_NULL_INPUT,
02504             CPL_ERROR_NULL_INPUT) ;
02505 
02506     ir = n ;
02507     l = 1 ;
02508     j_stack = 0 ;
02509     for (;;) {
02510         if (ir-l < 7) {
02511             for (j=l+1 ; j<=ir ; j++) {
02512                 a = pix_arr[j-1];
02513                 for (i=j-1 ; i>=1 ; i--) {
02514                     if (pix_arr[i-1] <= a) break;
02515                     pix_arr[i] = pix_arr[i-1];
02516                 }
02517                 pix_arr[i] = a;
02518             }
02519             if (j_stack == 0) break;
02520             ir = i_stack[j_stack-- -1];
02521             l  = i_stack[j_stack-- -1];
02522         } else {
02523             k = (l+ir) >> 1;
02524             CPL_INT_SWAP(pix_arr[k-1], pix_arr[l])
02525             if (pix_arr[l] > pix_arr[ir-1]) {
02526                 CPL_INT_SWAP(pix_arr[l], pix_arr[ir-1])
02527             }
02528             if (pix_arr[l-1] > pix_arr[ir-1]) {
02529                 CPL_INT_SWAP(pix_arr[l-1], pix_arr[ir-1])
02530             }
02531             if (pix_arr[l] > pix_arr[l-1]) {
02532                 CPL_INT_SWAP(pix_arr[l], pix_arr[l-1])
02533             }
02534             i = l+1;
02535             j = ir;
02536             a = pix_arr[l-1];
02537             for (;;) {
02538                 do i++; while (pix_arr[i-1] < a);
02539                 do j--; while (pix_arr[j-1] > a);
02540                 if (j < i) break;
02541                 CPL_INT_SWAP(pix_arr[i-1], pix_arr[j-1]);
02542             }
02543             pix_arr[l-1] = pix_arr[j-1];
02544             pix_arr[j-1] = a;
02545             j_stack += 2;
02546             if (j_stack > CPL_PIX_STACK_SIZE) {
02547                 /* Should never reach here */
02548                 return CPL_ERROR_ILLEGAL_INPUT ;
02549             }
02550             if (ir-i+1 >= j-l) {
02551                 i_stack[j_stack-1] = ir;
02552                 i_stack[j_stack-2] = i;
02553                 ir = j-1;
02554             } else {
02555                 i_stack[j_stack-1] = j-1;
02556                 i_stack[j_stack-2] = l;
02557                 l = i;
02558             }
02559         }
02560     }
02561     return CPL_ERROR_NONE ;
02562 }
02563 #undef CPL_PIX_STACK_SIZE
02564 
02565 static cpl_error_code xxx_tools_sort_stable_pattern_int(const int *, 
02566                                                int, int, int, int *);
02567 static cpl_error_code xxx_tools_sort_stable_pattern_float(const float *, 
02568                                                  int, int, int, int *);
02569 static cpl_error_code xxx_tools_sort_stable_pattern_double(const double *, 
02570                                                   int, int, int, int *);
02571 static cpl_error_code xxx_tools_sort_stable_pattern_string(char * const *,
02572                                                   int, int, int, int *);
02573 
02574 
02575 #undef CONCAT
02576 #undef CONCAT2X
02577 #define CONCAT(a,b) a ## _ ## b
02578 #define CONCAT2X(a,b) CONCAT(a,b)
02579 
02580 #define CPL_TYPE int
02581 #define CPL_TYPE_NAME int
02582 #define CPL_TOOLS_SORT_LT(x,y) ((x) < (y))
02583 #include "uves_tools_body.c"
02584 #undef CPL_TYPE
02585 #undef CPL_TYPE_NAME
02586 #undef CPL_TOOLS_SORT_LT
02587 
02588 #define CPL_TYPE float
02589 #define CPL_TYPE_NAME float
02590 #define CPL_TOOLS_SORT_LT(x,y) ((x) < (y))
02591 #include "uves_tools_body.c"
02592 #undef CPL_TYPE
02593 #undef CPL_TYPE_NAME
02594 #undef CPL_TOOLS_SORT_LT
02595 
02596 #define CPL_TYPE double
02597 #define CPL_TYPE_NAME double
02598 #define CPL_TOOLS_SORT_LT(x,y) ((x) < (y))
02599 #include "uves_tools_body.c"
02600 #undef CPL_TYPE
02601 #undef CPL_TYPE_NAME
02602 #undef CPL_TOOLS_SORT_LT
02603 
02604 #define CPL_TYPE char *
02605 #define CPL_TYPE_NAME string
02606 #define CPL_TOOLS_SORT_LT(x,y) (((x) == NULL && (y) != NULL) ||  \
02607                                 ((x) != NULL && (y) != NULL &&   \
02608                                  strcmp((x), (y)) < 0))
02609 #include "uves_tools_body.c"
02610 #undef CPL_TYPE
02611 #undef CPL_TYPE_NAME
02612 #undef CPL_TOOLS_SORT_LT
02613 
02614 
02615 
02616 
02617 
02618 
02619 
02620 
02621 void xxx_column_dump_structure(xxx_column *column);
02622 void xxx_column_dump(xxx_column *column, int start, int count);
02623 
02624 /*
02625  * Constructors and destructors:
02626  */
02627 
02628 xxx_column *xxx_column_new_int(int length);
02629 xxx_column *xxx_column_new_float(int length);
02630 xxx_column *xxx_column_new_double(int length);
02631 xxx_column *xxx_column_new_string(int length);
02632 xxx_column *xxx_column_new_array(cpl_type, int, int);
02633 
02634 xxx_column *xxx_column_wrap_int(int *data, int length);
02635 xxx_column *xxx_column_wrap_float(float *data, int length);
02636 xxx_column *xxx_column_wrap_double(double *data, int length);
02637 xxx_column *xxx_column_wrap_string(char **data, int length);
02638 
02639 void *xxx_column_unwrap(xxx_column *);
02640 void xxx_column_delete_but_strings(xxx_column *);
02641 void xxx_column_delete_but_arrays(xxx_column *);
02642 
02643 cpl_error_code xxx_column_copy_data(xxx_column *column, 
02644                                     const double *data);
02645 cpl_error_code xxx_column_copy_data_int(xxx_column *column, 
02646                                     const int *data);
02647 cpl_error_code xxx_column_copy_data_float(xxx_column *column, 
02648                                     const float *data);
02649 cpl_error_code xxx_column_copy_data_double(xxx_column *column, 
02650                                     const double *data);
02651 cpl_error_code xxx_column_copy_data_string(xxx_column *column, 
02652                                     const char **data);
02653 
02654 void xxx_column_delete(xxx_column *);
02655 
02656 
02657 /*
02658  * Methods:
02659  */
02660 
02661 cpl_error_code xxx_column_set_name(xxx_column *, const char *);
02662 const char *xxx_column_get_name(xxx_column *);
02663 
02664 cpl_error_code xxx_column_set_unit(xxx_column *, const char *);
02665 const char *xxx_column_get_unit(xxx_column *);
02666 
02667 cpl_error_code xxx_column_set_format(xxx_column *, const char *);
02668 const char *xxx_column_get_format(xxx_column *);
02669 
02670 int xxx_column_get_depth(xxx_column *);
02671 int xxx_column_get_dimensions(xxx_column *);
02672 cpl_error_code xxx_column_set_dimensions(xxx_column *, cpl_array *);
02673 int xxx_column_get_dimension(xxx_column *, int);
02674 
02675 
02676 int *xxx_column_get_data_int(xxx_column *);
02677 float *xxx_column_get_data_float(xxx_column *);
02678 double *xxx_column_get_data_double(xxx_column *);
02679 char **xxx_column_get_data_string(xxx_column *);
02680 cpl_array **xxx_column_get_data_array(xxx_column *);
02681 xxx_column_flag *xxx_column_get_data_invalid(xxx_column *);
02682 cpl_error_code xxx_column_set_data_invalid(xxx_column *, 
02683                                            xxx_column_flag *, int);
02684 
02685 cpl_error_code xxx_column_set_size(xxx_column *, int);
02686 cpl_error_code xxx_column_set_depth(xxx_column *, int);
02687 
02688 double xxx_column_get(xxx_column *, int, int *null); 
02689 int xxx_column_get_int(xxx_column *, int, int *null); 
02690 float xxx_column_get_float(xxx_column *, int, int *null); 
02691 double xxx_column_get_double(xxx_column *, int, int *null); 
02692 const char *xxx_column_get_string(xxx_column *, int);
02693 const cpl_array *xxx_column_get_array(xxx_column *, int);
02694 
02695 cpl_error_code xxx_column_set(xxx_column *, int, double); 
02696 cpl_error_code xxx_column_set_int(xxx_column *, int, int); 
02697 cpl_error_code xxx_column_set_float(xxx_column *, int, float); 
02698 cpl_error_code xxx_column_set_double(xxx_column *, int, double); 
02699 cpl_error_code xxx_column_set_string(xxx_column *, int, const char *);
02700 cpl_error_code xxx_column_set_array(xxx_column *, int, const cpl_array *);
02701 
02702 cpl_error_code xxx_column_fill(xxx_column *, int, int, double); 
02703 cpl_error_code xxx_column_fill_int(xxx_column *, int, int, int); 
02704 cpl_error_code xxx_column_fill_float(xxx_column *, int, int, float); 
02705 cpl_error_code xxx_column_fill_double(xxx_column *, int, int, double);
02706 cpl_error_code xxx_column_fill_string(xxx_column *, int, int, const char *);
02707 cpl_error_code xxx_column_fill_array(xxx_column *, int, int, const cpl_array *);
02708 
02709 cpl_error_code xxx_column_copy_segment(xxx_column *, int, int, double *);
02710 cpl_error_code xxx_column_copy_segment_int(xxx_column *, int, int, int *);
02711 cpl_error_code xxx_column_copy_segment_float(xxx_column *, int, int, float *);
02712 cpl_error_code xxx_column_copy_segment_double(xxx_column *, int, int, double *);
02713 cpl_error_code xxx_column_copy_segment_string(xxx_column *, int, int, char **);
02714 cpl_error_code xxx_column_copy_segment_array(xxx_column *, int, int, 
02715                                              cpl_array **);
02716 
02717 cpl_error_code xxx_column_shift(xxx_column *, int);
02718 
02719 cpl_error_code xxx_column_set_invalid(xxx_column *, int);
02720 cpl_error_code xxx_column_fill_invalid(xxx_column *, int, int);
02721 int xxx_column_is_invalid(xxx_column *, int);
02722 int xxx_column_has_invalid(xxx_column *);
02723 int xxx_column_has_valid(xxx_column *);
02724 int xxx_column_count_invalid(xxx_column *);
02725 
02726 cpl_error_code xxx_column_fill_invalid_int(xxx_column *, int);
02727 cpl_error_code xxx_column_fill_invalid_float(xxx_column *, float);
02728 cpl_error_code xxx_column_fill_invalid_double(xxx_column *, double);
02729 
02730 cpl_error_code xxx_column_erase_segment(xxx_column *, int, int);
02731 cpl_error_code xxx_column_insert_segment(xxx_column *, int, int);
02732 
02733 xxx_column *xxx_column_duplicate(xxx_column *);
02734 
02735 xxx_column *xxx_column_extract(xxx_column *, int, int);
02736 
02737 xxx_column *xxx_column_cast_to_int(xxx_column *);
02738 xxx_column *xxx_column_cast_to_float(xxx_column *);
02739 xxx_column *xxx_column_cast_to_double(xxx_column *);
02740 
02741 cpl_error_code xxx_column_merge(xxx_column *, xxx_column *, int);
02742 
02743 cpl_error_code xxx_column_add(xxx_column *, xxx_column *);
02744 cpl_error_code xxx_column_subtract(xxx_column *, xxx_column *);
02745 cpl_error_code xxx_column_multiply(xxx_column *, xxx_column *);
02746 cpl_error_code xxx_column_divide(xxx_column *, xxx_column *);
02747 
02748 cpl_error_code xxx_column_add_scalar(xxx_column *, double);
02749 cpl_error_code xxx_column_subtract_scalar(xxx_column *, double);
02750 cpl_error_code xxx_column_multiply_scalar(xxx_column *, double);
02751 cpl_error_code xxx_column_divide_scalar(xxx_column *, double);
02752 cpl_error_code xxx_column_logarithm(xxx_column *, double);
02753 cpl_error_code xxx_column_power(xxx_column *, double);
02754 cpl_error_code xxx_column_exponential(xxx_column *, double);
02755 
02756 double xxx_column_get_mean(xxx_column *);
02757 double xxx_column_get_median(xxx_column *);
02758 double xxx_column_get_stdev(xxx_column *);
02759 
02760 double xxx_column_get_max(xxx_column *);
02761 double xxx_column_get_min(xxx_column *);
02762 cpl_error_code xxx_column_get_maxpos(xxx_column *, int *);
02763 cpl_error_code xxx_column_get_minpos(xxx_column *, int *);
02764 
02765 
02766 
02767 
02768 
02769 
02770 
02771 
02772 
02773 
02774 inline static int xxx_column_type_size(cpl_type type)
02775 {
02776 
02777     switch (type) {
02778     case CPL_TYPE_INT:
02779         return sizeof(int);
02780     case CPL_TYPE_FLOAT:
02781         return sizeof(float);
02782     case CPL_TYPE_DOUBLE:
02783         return sizeof(double);
02784     case CPL_TYPE_STRING:
02785         return sizeof(char *);
02786     case CPL_TYPE_INT | CPL_TYPE_POINTER:
02787     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
02788     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
02789     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
02790         return sizeof(cpl_array *);
02791     default:
02792         return 0;
02793     }
02794 
02795 }
02796 #define CPL_DOUBLE_SWAP(a,b) { register double t=(a);(a)=(b);(b)=t; }
02797 #define CPL_FLOAT_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; }
02798 #define CPL_PIX_SORT(a,b) { if ((a)>(b)) CPL_DOUBLE_SWAP((a),(b)); }
02799 
02800 
02801 static int xxx_column_get_size(xxx_column *column)
02802 {
02803 
02804     if (column)
02805         return column->length;
02806 
02807     cpl_error_set("xxx_column_get_size", CPL_ERROR_NULL_INPUT);
02808 
02809     return 0;
02810 
02811 }
02812 
02813 static cpl_type xxx_column_get_type(xxx_column *column)
02814 {
02815 
02816     if (column)
02817         return column->type;
02818 
02819     cpl_error_set("xxx_column_get_type", CPL_ERROR_NULL_INPUT);
02820 
02821     return CPL_TYPE_INVALID;
02822 
02823 }
02824 
02825 
02826 
02827 static cpl_error_code xxx_column_erase_pattern(xxx_column *column, 
02828                                         int *pattern)
02829 {
02830     
02831     const char     *fid        = "xxx_column_erase_pattern";
02832     cpl_type         type       = xxx_column_get_type(column);
02833     int              old_length = xxx_column_get_size(column);
02834     int              new_length;
02835     int              i;
02836     int              j;
02837     cpl_array      **ap;
02838     char           **sp;
02839     int             *ip;
02840     float           *fp;
02841     double          *dp;
02842 
02843 
02844     if (column == 0x0)
02845         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
02846 
02847     if (pattern == 0x0)
02848         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
02849 
02850     new_length = 0;
02851     for (i = 0; i < old_length; i++)
02852         if (!pattern[i]) 
02853             new_length++;
02854 
02855     if (type == CPL_TYPE_STRING) {
02856 
02857         /*
02858          *  If a column of character strings is shortened, we must
02859          *  free explicitly the extra strings.
02860          */
02861 
02862       for(i = 0; i < old_length; i++)
02863         if (pattern[i])
02864           if (column->values->s[i])
02865             cpl_free(column->values->s[i]);
02866 
02867     }
02868 
02869     if (type & CPL_TYPE_POINTER) {
02870 
02871         /*
02872          *  If a column of arrays is shortened, we must
02873          *  free explicitly the extra arrays.
02874          */
02875 
02876       for(i = 0; i < old_length; i++)
02877         if (pattern[i])
02878           if (column->values->array[i])
02879             cpl_array_delete(column->values->array[i]);
02880 
02881     }
02882 
02883 
02884     /*
02885      *  Shorten the invalid flags buffer, if present, 
02886      *  counting how many invalid elements will be lost.
02887      */
02888     
02889     if (column->null) {
02890         
02891         for (i = 0; i < old_length; i++)
02892             if (pattern[i])
02893                 if (column->null[i])
02894                     column->nullcount--;
02895 
02896         if (column->nullcount == 0 || column->nullcount == new_length) {
02897             
02898             /*
02899              *  Since either no invalid or just invalid elements are left, 
02900              *  the invalid flag buffer can be released.
02901              */
02902             
02903             if (column->null)
02904                 cpl_free(column->null);
02905             column->null = NULL;
02906             
02907         }
02908         else {
02909 
02910             /*
02911              *  Shift up NULL flags.
02912              */
02913             
02914             i = 0;
02915             for (j = 0; j < old_length; j++)
02916                 if (!pattern[j]) {
02917                     column->null[i] = column->null[j];
02918                     i++;
02919                 }
02920             
02921             /*
02922              *  Get rid of extra memory.
02923              */
02924             
02925             column->null = cpl_realloc(column->null,
02926                                        new_length * sizeof(xxx_column_flag));
02927             
02928         }
02929     }
02930     else {
02931 
02932         /*
02933          *  There is no invalid flag buffer, so either there are no 
02934          *  invalid elements or there are just invalid elements. If 
02935          *  there are no invalid elements, nullcount stays zero. If 
02936          *  there are just invalid elements, nullcount must be set 
02937          *  to the new column length.
02938          */
02939 
02940         if (column->nullcount == old_length)
02941             column->nullcount = new_length;
02942 
02943     }
02944 
02945 
02946     /*
02947      *  Now take care of data values
02948      */
02949 
02950     if ((type == CPL_TYPE_STRING) || (type & CPL_TYPE_POINTER))
02951         column->nullcount = 0;
02952 
02953     if (column->nullcount != new_length) {
02954 
02955         /*
02956          *  Column has not just invalid elements. In this case we have to
02957          *  shift also the data to fill the gaps.
02958          */
02959 
02960         ip = column->values->i;
02961         fp = column->values->f;
02962         dp = column->values->d;
02963         sp = column->values->s;
02964         ap = column->values->array;
02965  
02966         switch (type) {
02967         case CPL_TYPE_INT:
02968           i = 0;
02969           for(j = 0; j < old_length; j++)
02970             if (!pattern[j])
02971               ip[i++] = ip[j];
02972           break;
02973         case CPL_TYPE_FLOAT:
02974           i = 0;
02975           for(j = 0; j < old_length; j++)
02976             if (!pattern[j])
02977               fp[i++] = fp[j];
02978             break;
02979         case CPL_TYPE_DOUBLE:
02980           i = 0;
02981           for(j = 0; j < old_length; j++)
02982             if (!pattern[j])
02983               dp[i++] = dp[j];
02984             break;
02985         case CPL_TYPE_STRING:
02986           i = 0;
02987           for(j = 0; j < old_length; j++)
02988             if (!pattern[j])
02989               sp[i++] = sp[j];
02990             break;
02991         default:     /* Array columns */
02992           i = 0;
02993           for(j = 0; j < old_length; j++)
02994             if (!pattern[j])
02995               ap[i++] = ap[j];
02996           break;
02997         }
02998 
02999     }
03000 
03001 
03002     /*
03003      *  Finally, reallocate the data buffer.
03004      */
03005 
03006     column->values->i = cpl_realloc(column->values->i,
03007                         new_length * xxx_column_type_size(type));
03008 
03009     column->length = new_length;
03010 
03011     return 0;
03012 
03013 }
03014 
03015 /* Lots of unsafe casts here */
03016 static cpl_error_code xxx_table_erase_selected(xxx_table *table)
03017 {
03018 
03019     const char     *fid    = "xxx_table_erase_selected";
03020     int              length = cpl_table_get_nrow((cpl_table *)table);
03021     int              i, width;
03022 
03023     if (table == 0x0)
03024         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
03025 
03026     if (table->selectcount == 0)
03027         return cpl_table_select_all((cpl_table *)table);
03028 
03029     if (table->selectcount == length)
03030         return cpl_table_set_size((cpl_table *)table, 0);
03031 
03032     width = cpl_table_get_ncol((cpl_table *)table);
03033 
03034     for (i = 0; i < width; i++)
03035         if (xxx_column_erase_pattern(table->columns[i], table->select)) {
03036             cpl_error_set_where(fid);
03037             return cpl_error_get_code();
03038         }
03039 
03040     table->nr -= table->selectcount;
03041 
03042     return cpl_table_select_all((cpl_table *)table);
03043 }
03044 
03045 /*----------------------------------------------------------------------------*/
03053 /*----------------------------------------------------------------------------*/
03054 cpl_error_code uves_table_erase_selected_dfs02356(cpl_table *t)
03055 {
03056     xxx_table_erase_selected((xxx_table *)t);
03057 
03058     passure( cpl_table_count_selected(t) == cpl_table_get_nrow(t),
03059              "%d %d",
03060              cpl_table_count_selected(t), cpl_table_get_nrow(t) );
03061 
03062 //    cpl_table_erase_selected(t);
03063   cleanup:
03064     return cpl_error_get_code();
03065 }
03066 
03067 /* another major workaround here */
03068 static xxx_column *xxx_table_find_column(const xxx_table *table,
03069                                          const char *name)
03070 {
03071 
03072     xxx_column **column;
03073     const char  *column_name;
03074     int          i;
03075 
03076 
03077     column = table->columns;
03078 
03079     for (i = 0; i < table->nc; i++, column++) {
03080         column_name = xxx_column_get_name(*column);
03081         if (strcmp(name, column_name) == 0) {
03082             return *column;
03083         }
03084     }
03085 
03086     return NULL;
03087 
03088 }
03089 
03090 
03091 
03092 static double xxx_tools_get_kth_double(
03093         double  *   a,
03094         int         n,
03095         int         k)
03096 {
03097     register double x ;
03098     register int    i, j, l, m ;
03099 
03100     cpl_ensure(a, CPL_ERROR_NULL_INPUT, 0.00) ;
03101 
03102     l=0 ; m=n-1 ;
03103     while (l<m) {
03104         x=a[k] ;
03105         i=l ;
03106         j=m ;
03107         do {
03108             while (a[i]<x) i++ ;
03109             while (x<a[j]) j-- ;
03110             if (i<=j) {
03111                 CPL_DOUBLE_SWAP(a[i],a[j]) ;
03112                 i++ ; j-- ;
03113             }
03114         } while (i<=j) ;
03115         if (j<k) l=i ;
03116         if (k<i) m=j ;
03117     }
03118     return a[k] ;
03119 }
03120 
03121 /*----------------------------------------------------------------------------*/
03130 /*----------------------------------------------------------------------------*/
03131 static float xxx_tools_get_kth_float(
03132         float   *   a,
03133         int         n,
03134         int         k)
03135 {
03136     register float  x ;
03137     register int    i, j, l, m ;
03138 
03139     cpl_ensure(a, CPL_ERROR_NULL_INPUT, 0.00) ;
03140 
03141     l=0 ; m=n-1 ;
03142     while (l<m) {
03143         x=a[k] ;
03144         i=l ;
03145         j=m ;
03146         do {
03147             while (a[i]<x) i++ ;
03148             while (x<a[j]) j-- ;
03149             if (i<=j) {
03150                 CPL_FLOAT_SWAP(a[i],a[j]) ;
03151                 i++ ; j-- ;
03152             }
03153         } while (i<=j) ;
03154         if (j<k) l=i ;
03155         if (k<i) m=j ;
03156     }
03157     return a[k] ;
03158 }
03159 
03160 /*----------------------------------------------------------------------------*/
03169 /*----------------------------------------------------------------------------*/
03170 static int xxx_tools_get_kth_int(
03171         int     *   a,
03172         int         n,
03173         int         k)
03174 {
03175     register float  x ;
03176     register int    i, j, l, m ;
03177 
03178     cpl_ensure(a, CPL_ERROR_NULL_INPUT, 0) ;
03179 
03180     l=0 ; m=n-1 ;
03181     while (l<m) {
03182         x=a[k] ;
03183         i=l ;
03184         j=m ;
03185         do {
03186             while (a[i]<x) i++ ;
03187             while (x<a[j]) j-- ;
03188             if (i<=j) {
03189                 CPL_INT_SWAP(a[i],a[j]) ;
03190                 i++ ; j-- ;
03191             }
03192         } while (i<=j) ;
03193         if (j<k) l=i ;
03194         if (k<i) m=j ;
03195     }
03196     return a[k] ;
03197 }
03198 
03199 
03200 #define INT_FORM "% 7d"
03201 #define FLOAT_FORM "% 1.5e"
03202 #define DOUBLE_FORM "% 1.5e"
03203 #define STRING_FORM "%s"
03204 
03205 static cpl_error_code
03206 table_sort(xxx_table *table, const uves_propertylist *reflist, unsigned n,
03207            int *sort_pattern, int *sort_null_pattern)
03208 {
03209     const char     *fid = "table_sort";
03210     cpl_property *info;
03211     const char *name;
03212     int reverse;
03213     const int stable = 1;
03214     xxx_column *column;
03215     xxx_column *column_sorted_null;
03216     cpl_type type;
03217     int i, j;
03218 
03219     int nullcount;
03220     int             *idata;
03221     int             *sorted_idata;
03222     float           *fdata;
03223     float           *sorted_fdata;
03224     double          *ddata;
03225     double          *sorted_ddata;
03226     char           **sdata;
03227     char           **sorted_sdata;
03228     cpl_array      **adata;
03229     cpl_array      **sorted_adata;
03230     xxx_column_flag *ndata;
03231     xxx_column_flag *sorted_ndata;
03232 
03233 
03234     if (n == 0) {
03235         return CPL_ERROR_NONE;
03236     }
03237 
03238 
03239     /*
03240      * Sort after least significant column
03241      */
03242 
03243     info = uves_propertylist_get((uves_propertylist *)reflist, n - 1);
03244     name = cpl_property_get_name(info);
03245     if (cpl_property_get_type(info) == CPL_TYPE_BOOL) {
03246         reverse = cpl_property_get_bool(info);
03247     }
03248     else {
03249         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
03250     }
03251 
03252     if (name == NULL) {
03253         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
03254     }
03255     if ((column = xxx_table_find_column(table, name)) == NULL) {
03256         return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
03257     }
03258 
03259     type = xxx_column_get_type(column);
03260     if (type & CPL_TYPE_POINTER) {   /* Arrays not as reference */
03261         return cpl_error_set(fid, CPL_ERROR_UNSUPPORTED_MODE);
03262     }
03263 
03264 
03265     /*
03266      * Independent of the reverse flag, put rows with invalid values at the
03267      * beginning of the table
03268      */
03269 
03270     nullcount = xxx_column_count_invalid(column);
03271     ndata = xxx_column_get_data_invalid(column);
03272 
03273     j = 0;
03274     for (i = 0; i < table->nr; i++) {
03275         if (ndata != NULL && ndata[i]) {
03276             sort_null_pattern[j++] = i;
03277         }
03278     }
03279 
03280     assert( j == nullcount );
03281 
03282     for (i = 0; i < table->nr; i++) {
03283         if (!(ndata != NULL && ndata[i])) {
03284             sort_null_pattern[j++] = i;
03285         }
03286     }
03287 
03288     assert( j == table->nr );
03289 
03290 
03291     /*
03292      *  Apply NULL pattern
03293      */
03294 
03295     column_sorted_null = xxx_column_duplicate(column);
03296     for (i = 0; i < nullcount; i++) {
03297         xxx_column_set_invalid(column_sorted_null, i);
03298     }
03299     for (i = nullcount; i < table->nr; i++) {
03300         int isnull;
03301 
03302         switch (type) {
03303         case CPL_TYPE_INT:
03304             xxx_column_set_int(
03305                 column_sorted_null, i,
03306                 xxx_column_get_int(column, sort_null_pattern[i], &isnull));
03307             break;
03308         case CPL_TYPE_FLOAT:
03309             xxx_column_set_float(
03310                 column_sorted_null, i,
03311                 xxx_column_get_float(column, sort_null_pattern[i], &isnull));
03312             break;
03313         case CPL_TYPE_DOUBLE:
03314             xxx_column_set_double(
03315                 column_sorted_null, i,
03316                 xxx_column_get_double(column, sort_null_pattern[i], &isnull));
03317             break;
03318         case CPL_TYPE_STRING:
03319             xxx_column_set_string(
03320                 column_sorted_null, i,
03321                 xxx_column_get_string(column, sort_null_pattern[i]));
03322             break;
03323         default:
03324             assert( 0 );
03325             break;
03326         }
03327     }
03328 
03329     /*
03330      * Get remaining sort pattern
03331      */
03332 
03333     for (i = 0; i < nullcount; i++) {
03334         sort_pattern[i] = i;
03335     }
03336     switch (type) {
03337     case CPL_TYPE_INT:
03338         xxx_tools_sort_stable_pattern_int(
03339             xxx_column_get_data_int(column_sorted_null) + nullcount,
03340             table->nr - nullcount,
03341             reverse,
03342             stable,
03343             sort_pattern + nullcount);
03344         break;
03345     case CPL_TYPE_FLOAT:
03346         xxx_tools_sort_stable_pattern_float(
03347             xxx_column_get_data_float(column_sorted_null) + nullcount,
03348             table->nr - nullcount,
03349             reverse,
03350             stable,
03351             sort_pattern + nullcount);
03352         break;
03353     case CPL_TYPE_DOUBLE:
03354         xxx_tools_sort_stable_pattern_double(
03355             xxx_column_get_data_double(column_sorted_null) + nullcount,
03356             table->nr - nullcount,
03357             reverse,
03358             stable,
03359             sort_pattern + nullcount);
03360         break;
03361     case CPL_TYPE_STRING:
03362         xxx_tools_sort_stable_pattern_string(
03363             xxx_column_get_data_string(column_sorted_null) + nullcount,
03364             table->nr - nullcount,
03365             reverse,
03366             stable,
03367             sort_pattern + nullcount);
03368         break;
03369     default:
03370         assert( 0 );
03371         break;
03372     }
03373 
03374     xxx_column_delete(column_sorted_null);
03375 
03376 
03377     /*
03378      *  Transform sort pattern
03379      */
03380 
03381     for (i = nullcount; i < table->nr; i++) {
03382         sort_pattern[i] += nullcount;
03383     }
03384 
03385 
03386     /*
03387      * Now apply the combined sort pattern to each column in the table:
03388      */
03389 
03390     j = 0;
03391     while (j < table->nc) {
03392         xxx_column      *sorted_column;
03393 
03394         switch (xxx_column_get_type(table->columns[j])) {
03395 
03396         case CPL_TYPE_INT:
03397 
03398             sorted_column = xxx_column_new_int(table->nr);
03399 
03400             xxx_column_set_name(sorted_column,
03401                                 xxx_column_get_name(table->columns[j]));
03402 
03403             nullcount = xxx_column_count_invalid(table->columns[j]);
03404 
03405             if (nullcount != table->nr) {
03406 
03407                 /*
03408                  * This is just a trick to make the null column exist,
03409                  * with the right number of nulls:
03410                  */
03411 
03412                 xxx_column_fill_int(sorted_column, 0,
03413                                     table->nr - nullcount, 0);
03414 
03415                 ndata = xxx_column_get_data_invalid(table->columns[j]);
03416 
03417                 if (ndata) {
03418                     sorted_ndata = xxx_column_get_data_invalid(sorted_column);
03419 
03420                     for (i = 0; i < table->nr; i++)
03421                         sorted_ndata[i] = 
03422                         ndata[sort_null_pattern[sort_pattern[i]]];
03423 
03424                 }
03425 
03426             }
03427 
03428             sorted_idata = xxx_column_get_data_int(sorted_column);
03429             idata = xxx_column_get_data_int(table->columns[j]);
03430 
03431             for (i = 0; i < table->nr; i++)
03432                 sorted_idata[i] = idata[sort_null_pattern[sort_pattern[i]]];
03433 
03434             xxx_column_delete(table->columns[j]);
03435             table->columns[j] = sorted_column;
03436             break;
03437 
03438         case CPL_TYPE_FLOAT:
03439 
03440             sorted_column = xxx_column_new_float(table->nr);
03441 
03442             xxx_column_set_name(sorted_column,
03443                                 xxx_column_get_name(table->columns[j]));
03444 
03445             nullcount = xxx_column_count_invalid(table->columns[j]);
03446 
03447             if (nullcount != table->nr) {
03448 
03449                 /*
03450                  * This is just a trick to make the null column exist,
03451                  * with the right number of nulls:
03452                  */
03453 
03454                 xxx_column_fill_float(sorted_column, 0,
03455                                       table->nr - nullcount, 0.0);
03456 
03457                 ndata = xxx_column_get_data_invalid(table->columns[j]);
03458 
03459                 if (ndata) {
03460                     sorted_ndata = xxx_column_get_data_invalid(sorted_column);
03461 
03462                     for (i = 0; i < table->nr; i++)
03463                         sorted_ndata[i] = 
03464                         ndata[sort_null_pattern[sort_pattern[i]]];
03465 
03466                 }
03467 
03468             }
03469 
03470             sorted_fdata = xxx_column_get_data_float(sorted_column);
03471             fdata = xxx_column_get_data_float(table->columns[j]);
03472 
03473             for (i = 0; i < table->nr; i++)
03474                 sorted_fdata[i] = fdata[sort_null_pattern[sort_pattern[i]]];
03475 
03476 
03477             xxx_column_delete(table->columns[j]);
03478             table->columns[j] = sorted_column;
03479             break;
03480 
03481         case CPL_TYPE_DOUBLE:
03482 
03483             sorted_column = xxx_column_new_double(table->nr);
03484 
03485             xxx_column_set_name(sorted_column,
03486                                 xxx_column_get_name(table->columns[j]));
03487 
03488             nullcount = xxx_column_count_invalid(table->columns[j]);
03489 
03490             if (nullcount != table->nr) {
03491 
03492                 /*
03493                  * This is just a trick to make the null column exist,
03494                  * with the right number of nulls:
03495                  */
03496 
03497                 xxx_column_fill_double(sorted_column, 0,
03498                                        table->nr - nullcount, 0.0);
03499 
03500                 ndata = xxx_column_get_data_invalid(table->columns[j]);
03501 
03502                 if (ndata) {
03503                     sorted_ndata = xxx_column_get_data_invalid(sorted_column);
03504 
03505                     for (i = 0; i < table->nr; i++)
03506                         sorted_ndata[i] = 
03507                         ndata[sort_null_pattern[sort_pattern[i]]];
03508 
03509                 }
03510 
03511             }
03512 
03513             sorted_ddata = xxx_column_get_data_double(sorted_column);
03514             ddata = xxx_column_get_data_double(table->columns[j]);
03515 
03516             for (i = 0; i < table->nr; i++)
03517                 sorted_ddata[i] = ddata[sort_null_pattern[sort_pattern[i]]];
03518 
03519             xxx_column_delete(table->columns[j]);
03520             table->columns[j] = sorted_column;
03521             break;
03522 
03523         case CPL_TYPE_STRING:
03524 
03525             sorted_column = xxx_column_new_string(table->nr);
03526 
03527             xxx_column_set_name(sorted_column,
03528                                 xxx_column_get_name(table->columns[j]));
03529 
03530             sorted_sdata = xxx_column_get_data_string(sorted_column);
03531             sdata = xxx_column_get_data_string(table->columns[j]);
03532 
03533             for (i = 0; i < table->nr; i++)
03534                 sorted_sdata[i] = sdata[sort_null_pattern[sort_pattern[i]]];
03535 
03536             xxx_column_delete_but_strings(table->columns[j]);
03537             table->columns[j] = sorted_column;
03538             break;
03539 
03540         case CPL_TYPE_INT | CPL_TYPE_POINTER:
03541         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
03542         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
03543         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
03544 
03545             sorted_column =
03546             xxx_column_new_array(xxx_column_get_type(table->columns[j]),
03547                                  table->nr,
03548                                  xxx_column_get_depth(table->columns[j]));
03549 
03550             xxx_column_set_name(sorted_column,
03551                                 xxx_column_get_name(table->columns[j]));
03552 
03553             sorted_adata = xxx_column_get_data_array(sorted_column);
03554             adata = xxx_column_get_data_array(table->columns[j]);
03555 
03556             for (i = 0; i < table->nr; i++)
03557                 sorted_adata[i] = adata[sort_null_pattern[sort_pattern[i]]];
03558 
03559             xxx_column_delete_but_arrays(table->columns[j]);
03560             table->columns[j] = sorted_column;
03561             break;
03562 
03563         default:
03564 
03565             break;      /* Should never get here */
03566 
03567         }
03568 
03569         j++;
03570 
03571     }
03572 
03573 
03574     /*
03575      * Finished sorting after least significant column.
03576      * Sort after remaining columns
03577      */
03578 
03579     return table_sort(table, reflist, n - 1, sort_pattern, sort_null_pattern);
03580 }
03581 static 
03582 cpl_error_code xxx_table_sort(xxx_table *table, const uves_propertylist *reflist)
03583 {
03584     const char     *fid = "xxx_table_sort";
03585     int *sort_pattern, *sort_null_pattern;
03586     cpl_error_code ec;
03587 
03588     if (table == NULL || reflist == NULL)
03589         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
03590 
03591     if (uves_propertylist_get_size(reflist) == 0)
03592         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
03593 
03594     if (table->nr < 2)
03595         return CPL_ERROR_NONE;
03596 
03597     sort_pattern      = cpl_malloc(table->nr * sizeof(int));
03598     sort_null_pattern = cpl_malloc(table->nr * sizeof(int));
03599 
03600     ec = table_sort(table, reflist, uves_propertylist_get_size(reflist),
03601                     sort_pattern, sort_null_pattern);
03602 
03603     cpl_free(sort_pattern);
03604     cpl_free(sort_null_pattern);
03605 
03606     return ec;
03607 }
03608 
03609 
03610 
03611 
03612 
03613 
03614 
03615 /*
03616  * @brief
03617  *   Create a column values container (private).
03618  *
03619  * @return Pointer to column values container.
03620  *
03621  * This private function allocates and initializes a container of
03622  * column values.
03623  */
03624 
03625 static xxx_column_values *xxx_column_values_new(void)
03626 {
03627 
03628     xxx_column_values *value = cpl_calloc(1, sizeof(xxx_column_values));
03629 
03630 
03631     value->i = NULL;
03632 
03633     return value;
03634 
03635 }
03636 
03637 /*
03638  * @brief
03639  *   Returns the values container of a column (private).
03640  *
03641  * @return Pointer to column values container, or @em NULL.
03642  */
03643 
03644 static xxx_column_values *xxx_column_get_values(xxx_column *column)
03645 {
03646 
03647     if (column)
03648         return column->values;
03649 
03650     return NULL;
03651 
03652 }
03653 
03654 
03655 /*
03656  * @brief
03657  *   Destructor of the container of column values (private).
03658  *
03659  * @param values  Pointer to container of column values.
03660  * @param length  Column length.
03661  * @param type    Column type.
03662  *
03663  * @return Nothing.
03664  *
03665  * This is a private function used to free all the column data and their
03666  * container.
03667  */
03668 
03669 static void xxx_column_values_delete(xxx_column_values *values, 
03670                                      int length, cpl_type type)
03671 {
03672 
03673     int i;
03674 
03675 
03676     if (values) {
03677         switch (type) {
03678         case CPL_TYPE_INT | CPL_TYPE_POINTER:
03679         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
03680         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
03681         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
03682 
03683             for (i = 0; i < length; i++)
03684                 cpl_array_delete(values->array[i]);
03685 
03686             cpl_free((void *)values->array);
03687             cpl_free(values);
03688 
03689             break;
03690 
03691         case CPL_TYPE_STRING:
03692 
03693             for (i = 0; i < length; i++)
03694                 if (values->s[i])
03695                     cpl_free(values->s[i]);
03696 
03697         default:
03698 
03699             if (values->s)
03700                 cpl_free((void *)values->s);
03701 
03702             cpl_free(values);
03703 
03704             break;
03705 
03706         }
03707     }
03708 
03709 }
03710 
03711 
03712 /*
03713  * @brief
03714  *   Unset a NULL flag (private).
03715  *
03716  * @param column  Column to be accessed.
03717  * @param row     Position where to unset the NULL.
03718  *
03719  * @return 0 on success.
03720  *
03721  * This function is private: the only way for a user to unset a
03722  * null flag, is to write to the corresponding column element a
03723  * valid value. This function cannot be used for string or array 
03724  * columns.
03725  * Being this function private, all safety checks are removed to
03726  * make this function faster, assuming that all checks has been
03727  * already performed by the caller.
03728  */
03729 
03730 static int xxx_column_unset_null(xxx_column *column, int row)
03731 {
03732 
03733     int length;
03734 
03735 
03736     if (column->nullcount == 0)       /* There are no nulls to unset */
03737         return 0;
03738 
03739     if (!column->null)                /* There are just nulls        */
03740         column->null = cpl_malloc(column->length * sizeof(xxx_column_flag));
03741 
03742     length = column->length;
03743 
03744     if (column->nullcount == length)
03745         while (length--)
03746             column->null[length] = 1;
03747 
03748     if (column->null[row] == 1) {
03749         column->null[row] = 0;
03750         column->nullcount--;
03751     }
03752 
03753     if (column->nullcount == 0) {
03754         if (column->null)
03755             cpl_free(column->null);
03756         column->null = NULL;
03757     }
03758 
03759     return 0;
03760 
03761 }
03762 
03763 
03764 /*
03765  * @brief
03766  *   Unset an interval of NULL flags (private).
03767  *
03768  * @param column  Column to be accessed.
03769  * @param start   Position where to start unsetting NULLs.
03770  * @param count   Number of column elements to unset.
03771  *
03772  * @return 0 on success.
03773  *
03774  * This function is private: the only way for a user to unset a
03775  * null flag, is to write to the corresponding column element a
03776  * valid value. This function cannot be used for string or array columns.
03777  * Being this function private, all safety checks are removed to
03778  * make this function faster, assuming that all checks has been
03779  * already performed by the caller.
03780  */
03781 
03782 static int xxx_column_unset_null_segment(xxx_column *column, 
03783                                          int start, int count)
03784 {
03785 
03786     int length = xxx_column_get_size(column);
03787 
03788 
03789     if (start == 0 && count == length) {
03790         if (column->null)
03791             cpl_free(column->null);
03792         column->null = NULL;
03793         column->nullcount = 0;
03794     }
03795 
03796     if (column->nullcount == 0)
03797         return 0;
03798 
03799     if (!column->null)
03800         column->null = cpl_malloc(length * sizeof(xxx_column_flag));
03801 
03802     if (column->nullcount == length) {
03803         while (length--)
03804             column->null[length] = 1;
03805         memset(column->null + start, 0, count * sizeof(xxx_column_flag));
03806         column->nullcount -= count;
03807     }
03808     else {
03809         while (count--) {
03810             if (column->null[start] == 1) {
03811                 column->null[start] = 0;
03812                 column->nullcount--;
03813             }
03814             start++;
03815         }
03816     }
03817 
03818     if (column->nullcount == 0) {
03819         if (column->null)
03820             cpl_free(column->null);
03821         column->null = NULL;
03822     }
03823 
03824     return 0;
03825 
03826 }
03827 
03828 
03829 void xxx_column_dump_structure(xxx_column *column)
03830 {
03831 
03832     const char *name   = xxx_column_get_name(column);
03833     const char *unit   = xxx_column_get_unit(column);
03834     const char *format = xxx_column_get_format(column);
03835     cpl_type    type   = xxx_column_get_type(column);
03836     int         length = xxx_column_get_size(column);
03837 
03838 
03839     if (column) {
03840 
03841         printf("Column name   : ");
03842 
03843         if (name)
03844             printf("\"%s\"\n", name);
03845         else
03846             printf("NONE\n");
03847 
03848         printf("Column unit   : ");
03849 
03850         if (unit)
03851             printf("\"%s\"\n", unit);
03852         else
03853             printf("NONE\n");
03854 
03855         printf("Column format : ");
03856 
03857         if (format)
03858             printf("\"%s\"\n", format);
03859         else
03860             printf("NONE\n");
03861 
03862         printf("Column type   : ");
03863 
03864         switch (type) {
03865         case CPL_TYPE_INT:
03866             printf("int\n");
03867             break;
03868         case CPL_TYPE_FLOAT:
03869             printf("float\n");
03870             break;
03871         case CPL_TYPE_DOUBLE:
03872             printf("double\n");
03873             break;
03874         case CPL_TYPE_STRING:
03875             printf("string\n");
03876             break;
03877         default:
03878             printf("UNDEFINED\n");
03879         }
03880 
03881         printf("Column length : %d\n", length);
03882 
03883         printf("Column nulls  : %d\n", xxx_column_count_invalid(column));
03884         printf("                (the NULL column %sexists)\n", 
03885                       column->null ? "" : "does not ");
03886 
03887     }
03888     else {
03889         printf("Column is NULL\n");
03890         cpl_error_reset();
03891     }
03892         
03893 }
03894 
03895 
03896 void xxx_column_dump(xxx_column *column, int start, int count)
03897 {
03898 
03899     cpl_type type   = xxx_column_get_type(column);
03900     int      length = xxx_column_get_size(column);
03901     int      nulls  = xxx_column_count_invalid(column);
03902     int      i      = start;
03903 
03904 
03905     if (column) {
03906         if (start < length) {
03907 
03908             if (count > length - start)
03909                 count = length - start;
03910 
03911             switch (type) {
03912             case CPL_TYPE_INT:
03913                 if (nulls == 0) {
03914                     while (count--) {
03915                         printf("%d %d\n", i, column->values->i[i]);
03916                         i++;
03917                     }
03918                 }
03919                 else if (nulls == length) {
03920                     while (count--) {
03921                         printf("%d %d NULL\n", i, column->values->i[i]);
03922                         i++;
03923                     }
03924                 }
03925                 else {
03926                     while (count--) {
03927                         printf("%d %d %d\n", i, 
03928                         column->values->i[i], column->null[i]);
03929                         i++;
03930                     }
03931                 }
03932                 break;
03933             case CPL_TYPE_FLOAT:
03934                 if (nulls == 0) {
03935                     while (count--) {
03936                         printf("%d %f\n", i, column->values->f[i]);
03937                         i++;
03938                     }
03939                 }
03940                 else if (nulls == length) {
03941                     while (count--) {
03942                         printf("%d %f NULL\n", i, column->values->f[i]);
03943                         i++;
03944                     }
03945                 }
03946                 else {
03947                     while (count--) {
03948                         printf("%d %f %d\n", i, 
03949                         column->values->f[i], column->null[i]);
03950                         i++;
03951                     } 
03952                 } 
03953                 break;
03954             case CPL_TYPE_DOUBLE:
03955                 if (nulls == 0) {
03956                     while (count--) {
03957                         printf("%d %f\n", i, column->values->d[i]);
03958                         i++;
03959                     }
03960                 }
03961                 else if (nulls == length) {
03962                     while (count--) {
03963                         printf("%d %f NULL\n", i, column->values->d[i]);
03964                         i++;
03965                     }
03966                 }
03967                 else {
03968                     while (count--) {
03969                         printf("%d %f %d\n", i, 
03970                         column->values->d[i], column->null[i]);
03971                         i++;
03972                     } 
03973                 } 
03974                 break;
03975             case CPL_TYPE_STRING:
03976                 while (count--) {
03977                     printf("%d %s\n", i, 
03978                     column->values->s[i] ? column->values->s[i] : "NULL");
03979                     i++;
03980                 } 
03981                 break;
03982             default:
03983                 break;
03984             }
03985         }
03986     }
03987     else {
03988         printf("Column is NULL\n");
03989         cpl_error_reset();
03990     }
03991     
03992 }
03993 
03994 
03995 /*
03996  * @brief
03997  *   Create a new empty column (private).
03998  *
03999  * @param type    Column type.
04000  *
04001  * @return Pointer to the new column, or @c NULL.
04002  *
04003  * This private function allocates memory for a column, its type is 
04004  * assigned, and the container of column values is initialized together 
04005  * with all the other column properties.
04006  */
04007 
04008 static xxx_column *xxx_column_new(cpl_type type)
04009 {
04010 
04011     xxx_column *column = cpl_calloc(1, sizeof(xxx_column));
04012 
04013 
04014     column->values     = xxx_column_values_new();
04015     column->name       = NULL;
04016     column->unit       = NULL;
04017     column->format     = NULL;
04018     column->length     = 0;
04019     column->depth      = 0;
04020     column->type       = type;
04021     column->null       = NULL;
04022     column->nullcount  = 0;
04023     column->dimensions = NULL;
04024 
04025     return column;
04026 
04027 }
04028 
04029 
04030 /* 
04031  * @brief
04032  *   Create a new @em integer column.
04033  *
04034  * @param length    Number of elements in column.
04035  *
04036  * @return Pointer to the new column, or @c NULL in case of error.
04037  *
04038  * The function allocates memory for a column, its type is assigned,
04039  * and its number of elements is allocated. All column elements are 
04040  * flagged as invalid. If a negative length is specified, an error 
04041  * @c CPL_ERROR_ILLEGAL_INPUT is set. Zero length columns are allowed.
04042  */
04043 
04044 xxx_column *xxx_column_new_int(int length)
04045 {
04046 
04047     const char *fid = "xxx_column_new_int";
04048     xxx_column  *column;
04049 
04050 
04051     if (length < 0) {
04052         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04053         return NULL;
04054     }
04055 
04056     column = xxx_column_new(CPL_TYPE_INT);
04057 
04058     if (length)
04059         column->values->i = (int *)cpl_malloc(length * sizeof(int));
04060     else
04061         column->values->i = NULL;
04062 
04063     column->format    = cpl_strdup(INT_FORM);
04064     column->length    = length;
04065     column->nullcount = length;
04066 
04067     return column;
04068 
04069 }
04070 
04071 
04072 /* 
04073  * @brief
04074  *   Create a new @em float column.
04075  *
04076  * @param length    Number of elements in column.
04077  *
04078  * @return Pointer to the new column, or @c NULL in case of error.
04079  *
04080  * See documentation of @c xxx_column_new_int().
04081  */
04082 
04083 xxx_column *xxx_column_new_float(int length)
04084 {
04085 
04086     const char *fid = "xxx_column_new_float";
04087     xxx_column  *column;
04088 
04089 
04090     if (length < 0) {
04091         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04092         return NULL;
04093     }
04094 
04095     column = xxx_column_new(CPL_TYPE_FLOAT);
04096 
04097     if (length)
04098         column->values->f = (float *)cpl_malloc(length * sizeof(float));
04099     else
04100         column->values->f = NULL;
04101 
04102     column->format    = cpl_strdup(FLOAT_FORM);
04103     column->length    = length;
04104     column->nullcount = length;
04105 
04106     return column;
04107 
04108 }
04109 
04110 
04111 /* 
04112  * @brief
04113  *   Create a new @em double column.
04114  *
04115  * @param length    Number of elements in column.
04116  *
04117  * @return Pointer to the new column, or @c NULL in case of error.
04118  *
04119  * See documentation of @c xxx_column_new_int().
04120  */
04121 
04122 xxx_column *xxx_column_new_double(int length)
04123 {
04124 
04125     const char *fid = "xxx_column_new_double";
04126     xxx_column  *column;
04127 
04128 
04129     if (length < 0) {
04130         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04131         return NULL;
04132     }
04133 
04134     column = xxx_column_new(CPL_TYPE_DOUBLE);
04135 
04136     if (length)
04137         column->values->d = (double *)cpl_malloc(length * sizeof(double));
04138     else
04139         column->values->d = NULL;
04140 
04141     column->format    = cpl_strdup(DOUBLE_FORM);
04142     column->length    = length;
04143     column->nullcount = length;
04144 
04145     return column;
04146 
04147 }
04148 
04149 
04150 /* 
04151  * @brief
04152  *   Create a new string column.
04153  *
04154  * @param length    Number of elements in column.
04155  *
04156  * @return Pointer to the new column, or @c NULL in case of error.
04157  *
04158  * The function allocates memory for a column of pointers to @em char,
04159  * all initialized to @c NULL pointers. No memory is allocated for the 
04160  * single column elements. If a negative length is specified, an error 
04161  * @c CPL_ERROR_ILLEGAL_INPUT is set. Zero length columns are allowed. 
04162  * No memory is allocated for the single column elements.
04163  */
04164 
04165 xxx_column *xxx_column_new_string(int length)
04166 {
04167 
04168     const char *fid = "xxx_column_new_string";
04169     xxx_column  *column;
04170 
04171 
04172     if (length < 0) {
04173         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04174         return NULL;
04175     }
04176 
04177     column = xxx_column_new(CPL_TYPE_STRING);
04178 
04179     if (length)
04180         column->values->s = (char **)cpl_calloc(length, sizeof (char *));
04181     else
04182         column->values->s = NULL;
04183 
04184     column->format = cpl_strdup(STRING_FORM);
04185     column->length = length;
04186 
04187     return column;
04188 
04189 }
04190 
04191 
04192 /*
04193  * @brief
04194  *   Create a new @em integer array column.
04195  *
04196  * @param type      Column type
04197  * @param length    Number of arrays in column.
04198  * @param depth     Number of elements per array in column.
04199  *
04200  * @return Pointer to the new column, or @c NULL in case of error.
04201  *
04202  * The function allocates memory for a column, its type is assigned,
04203  * and its number of elements is allocated. All column elements are
04204  * flagged as invalid. If a negative length is specified, an error
04205  * @c CPL_ERROR_ILLEGAL_INPUT is set. Zero length columns are allowed.
04206  */
04207 
04208 xxx_column *xxx_column_new_array(cpl_type type, int length, int depth)
04209 {
04210 
04211     const char *fid = "xxx_column_new_array";
04212     xxx_column  *column;
04213 
04214 
04215     if (length < 0 || depth < 0) {
04216         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04217         return NULL;
04218     }
04219 
04220     column = xxx_column_new(type | CPL_TYPE_POINTER);
04221 
04222     if (length)
04223         column->values->array = cpl_calloc(length, sizeof (cpl_array *));
04224     else
04225         column->values->array = NULL;
04226 
04227     switch(type) {
04228     case CPL_TYPE_INT: 
04229     case CPL_TYPE_INT | CPL_TYPE_POINTER:
04230         column->format = cpl_strdup(INT_FORM);
04231         break;
04232     case CPL_TYPE_FLOAT:
04233     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
04234         column->format = cpl_strdup(FLOAT_FORM);
04235         break;
04236     case CPL_TYPE_DOUBLE: 
04237     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
04238         column->format = cpl_strdup(DOUBLE_FORM);
04239         break;
04240     case CPL_TYPE_STRING:
04241     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
04242         column->format = cpl_strdup(STRING_FORM);
04243         break;
04244     default:
04245         xxx_column_delete(column);
04246         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
04247         return NULL;
04248     }
04249 
04250     column->length = length;
04251     column->depth = depth;
04252 
04253     return column;
04254 
04255 }
04256 
04257 
04258 /*
04259  * @brief
04260  *   Create a new @em integer column from existing data.
04261  *
04262  * @param data      Existing data buffer.
04263  * @param length    Number of elements in column.
04264  *
04265  * @return Pointer to the new column, or @c NULL in case of error.
04266  *
04267  * This function creates a new @em integer column that will encapsulate 
04268  * the given data. Note that the size of the data array is not checked in
04269  * any way, and that the data values are all considered valid: invalid
04270  * values should be marked using the functions @c xxx_column_set_invalid()
04271  * and @c xxx_column_fill_invalid(). The data array is not copied,
04272  * so it should never be deallocated: to deallocate it, the function
04273  * @c xxx_column_delete() should be called instead. Alternatively, the
04274  * function @c xxx_column_unwrap() might be used, and the data array
04275  * deallocated afterwards. A zero or negative length is illegal, and
04276  * would cause an error @c CPL_ERROR_ILLEGAL_INPUT to be set. An input
04277  * @c NULL pointer would set an error @c CPL_ERROR_NULL_INPUT.
04278  *
04279  * @note
04280  *   Functions that handle columns assume that a column data array
04281  *   is dinamically allocated: with a statically allocated array
04282  *   any function implying memory handling (@c xxx_column_set_size(),
04283  *   @c xxx_column_delete(), etc.) would crash the program. This means
04284  *   that a static array should never be passed to this function if
04285  *   memory handling is planned. In case of a static array, only the
04286  *   @c xxx_column_unwrap() destructor can be used.
04287  */
04288 
04289 xxx_column *xxx_column_wrap_int(int *data, int length)
04290 {
04291 
04292     const char *fid = "xxx_column_wrap_int";
04293     xxx_column  *column;
04294 
04295 
04296     if (data == 0x0) {
04297         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04298         return NULL;
04299     }
04300 
04301     if (length <= 0) {
04302         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04303         return NULL;
04304     }
04305 
04306     column = xxx_column_new(CPL_TYPE_INT);
04307 
04308     column->format    = cpl_strdup(INT_FORM);
04309     column->length    = length;
04310     column->values->i = data;
04311 
04312     return column;
04313 
04314 }
04315 
04316 
04317 /* 
04318  * @brief
04319  *   Create a new @em float column from existing data.
04320  *
04321  * @param data      Existing data buffer.
04322  * @param length    Number of elements in column.
04323  *
04324  * @return Pointer to the new column, or @c NULL in case of error.
04325  *
04326  * See documentation of function @c xxx_column_wrap_int().
04327  */
04328 
04329 xxx_column *xxx_column_wrap_float(float *data, int length)
04330 {
04331 
04332     const char *fid = "xxx_column_wrap_float";
04333     xxx_column  *column;
04334 
04335 
04336     if (data == 0x0) {
04337         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04338         return NULL;
04339     }
04340 
04341     if (length <= 0) {
04342         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04343         return NULL;
04344     }
04345 
04346     column = xxx_column_new(CPL_TYPE_FLOAT);
04347 
04348     column->format    = cpl_strdup(FLOAT_FORM);
04349     column->length    = length;
04350     column->values->f = data;
04351 
04352     return column;
04353 
04354 }
04355 
04356 
04357 /* 
04358  * @brief
04359  *   Create a new @em double column from existing data.
04360  *
04361  * @param data      Existing data buffer.
04362  * @param length    Number of elements in column.
04363  *
04364  * @return Pointer to the new column, or @c NULL in case of error.
04365  *
04366  * See documentation of function @c xxx_column_wrap_int().
04367  */
04368 
04369 xxx_column *xxx_column_wrap_double(double *data, int length)
04370 {
04371 
04372     const char *fid = "xxx_column_wrap_double";
04373     xxx_column  *column;
04374 
04375 
04376     if (data == 0x0) {
04377         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04378         return NULL;
04379     }
04380 
04381     if (length <= 0) {
04382         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04383         return NULL;
04384     }
04385 
04386     column = xxx_column_new(CPL_TYPE_DOUBLE);
04387 
04388     column->format    = cpl_strdup(DOUBLE_FORM);
04389     column->length    = length;
04390     column->values->d = data;
04391 
04392     return column;
04393 
04394 }
04395 
04396 
04397 /* 
04398  * @brief
04399  *   Create a new character string column from existing data.
04400  *
04401  * @param data      Existing data buffer.
04402  * @param length    Number of elements in column.
04403  *
04404  * @return Pointer to the new column, or @c NULL in case of error.
04405  *
04406  * See documentation of function @c xxx_column_wrap_int().
04407  */
04408 
04409 xxx_column *xxx_column_wrap_string(char **data, int length)
04410 {
04411 
04412     const char *fid = "xxx_column_wrap_string";
04413     xxx_column  *column;
04414 
04415 
04416     if (data == 0x0) {
04417         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04418         return NULL;
04419     }
04420 
04421     if (length <= 0) {
04422         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04423         return NULL;
04424     }
04425 
04426     column = xxx_column_new(CPL_TYPE_STRING);
04427 
04428     column->format    = cpl_strdup(STRING_FORM);
04429     column->length    = length;
04430     column->values->s = data;
04431 
04432     return column;
04433 
04434 }
04435 
04436 
04437 /* 
04438  * @brief
04439  *   Copy array of numerical data to a numerical column.
04440  *
04441  * @param column    Existing column.
04442  * @param data      Existing data buffer.
04443  *
04444  * @return @c CPL_ERROR_NONE on success. If the column is not a numerical 
04445  *   column, a @c CPL_ERROR_INVALID_TYPE is returned. At any @c NULL input
04446  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04447  *
04448  * The input data are copied into the specified column. If the type of the
04449  * accessed column is not double, data values will be truncated according
04450  * to C casting rules. The size of the input array is not checked in any 
04451  * way, and the data values are all considered valid: invalid values 
04452  * should be marked using the functions @c xxx_column_set_invalid() and 
04453  * @c xxx_column_fill_invalid(). If @em N is the length of the column,
04454  * the first @em N values of the input data buffer would be copied to
04455  * the column buffer. If the column had length zero, no values would
04456  * be copied.
04457  */
04458 
04459 cpl_error_code xxx_column_copy_data(xxx_column *column, const double *data)
04460 {
04461 
04462     const char *fid = "xxx_column_copy_data";
04463     int       length = xxx_column_get_size(column);
04464     cpl_type  type   = xxx_column_get_type(column);
04465     int      *idata;
04466     float    *fdata;
04467 
04468 
04469     if (data == 0x0 || column == 0x0)
04470         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04471 
04472     if (length == 0)
04473         return CPL_ERROR_NONE;
04474 
04475 
04476     switch (type) {
04477     case CPL_TYPE_INT:
04478         idata = xxx_column_get_data_int(column);
04479         while (length--)
04480             *idata++ = *data++;
04481         break;
04482     case CPL_TYPE_FLOAT:
04483         fdata = xxx_column_get_data_float(column);
04484         while (length--)
04485             *fdata++ = *data++;
04486         break;
04487     case CPL_TYPE_DOUBLE:
04488         memcpy(column->values->d, data, column->length * sizeof(double));
04489         break;
04490     default:
04491         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
04492     }
04493 
04494     if (column->null)
04495         cpl_free(column->null);
04496     column->null = NULL;
04497     column->nullcount = 0;
04498 
04499     return CPL_ERROR_NONE;
04500 
04501 }
04502 
04503 
04504 /* 
04505  * @brief
04506  *   Copy existing data to an @em integer column.
04507  *
04508  * @param column    Existing column.
04509  * @param data      Existing data buffer.
04510  *
04511  * @return 0 on success. If the input column is not integer, a 
04512  *   @c CPL_ERROR_TYPE_MISMATCH is returned. At any @c NULL input
04513  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04514  *
04515  * The input data are copied into the specified column. The size of the 
04516  * input array is not checked in any way, and the data values are all 
04517  * considered valid: invalid values should be marked using the functions 
04518  * @c xxx_column_set_invalid() and @c xxx_column_fill_invalid(). If @em N 
04519  * is the length of the column, the first @em N values of the input data 
04520  * buffer would be copied to the column buffer. If the column had length 
04521  * zero, no values would be copied.
04522  */
04523 
04524 cpl_error_code xxx_column_copy_data_int(xxx_column *column, const int *data)
04525 {
04526 
04527     const char *fid  = "xxx_column_copy_data_int";
04528     cpl_type     type = xxx_column_get_type(column);
04529 
04530 
04531     if (data == 0x0 || column == 0x0)
04532         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04533 
04534     if (type != CPL_TYPE_INT)
04535         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
04536 
04537     if (column->length == 0)
04538         return CPL_ERROR_NONE;
04539 
04540     memcpy(column->values->i, data, column->length * sizeof(int));
04541 
04542     if (column->null)
04543         cpl_free(column->null);
04544     column->null = NULL;
04545     column->nullcount = 0;
04546 
04547     return CPL_ERROR_NONE;
04548 
04549 }
04550 
04551 
04552 /* 
04553  * @brief
04554  *   Copy existing data to a @em float column.
04555  *
04556  * @param column    Existing column.
04557  * @param data      Existing data buffer.
04558  *
04559  * @return 0 on success.  If the input column is not float, a
04560  *   @c CPL_ERROR_TYPE_MISMATCH is returned. At any @c NULL input
04561  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04562  *
04563  * See documentation of function @c xxx_column_copy_data_int().
04564  */
04565 
04566 cpl_error_code xxx_column_copy_data_float(xxx_column *column, 
04567                                           const float *data)
04568 {
04569 
04570     const char *fid  = "xxx_column_copy_data_float";
04571     cpl_type     type = xxx_column_get_type(column);
04572 
04573 
04574     if (data == 0x0 || column == 0x0)
04575         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04576 
04577     if (type != CPL_TYPE_FLOAT)
04578         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
04579 
04580     if (column->length == 0)
04581         return CPL_ERROR_NONE;
04582 
04583     memcpy(column->values->f, data, column->length * sizeof(float));
04584 
04585     if (column->null)
04586         cpl_free(column->null);
04587     column->null = NULL;
04588     column->nullcount = 0;
04589 
04590     return CPL_ERROR_NONE;
04591 
04592 }
04593 
04594 
04595 /* 
04596  * @brief
04597  *   Copy existing data to a @em double column.
04598  *
04599  * @param column    Existing column.
04600  * @param data      Existing data buffer.
04601  *   
04602  * @return 0 on success. If the input column is not double, a
04603  *   @c CPL_ERROR_TYPE_MISMATCH is returned. At any @c NULL input
04604  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04605  *
04606  * See documentation of function @c xxx_column_copy_data_int().
04607  */
04608 
04609 cpl_error_code xxx_column_copy_data_double(xxx_column *column, 
04610                                            const double *data)
04611 {
04612 
04613     const char *fid  = "xxx_column_copy_data_double";
04614     cpl_type     type = xxx_column_get_type(column); 
04615 
04616 
04617     if (data == 0x0 || column == 0x0)
04618         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04619 
04620     if (type != CPL_TYPE_DOUBLE)
04621         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
04622 
04623     if (column->length == 0)
04624         return CPL_ERROR_NONE;
04625 
04626     memcpy(column->values->d, data, column->length * sizeof(double));
04627 
04628     if (column->null)
04629         cpl_free(column->null);
04630     column->null = NULL;
04631     column->nullcount = 0;
04632 
04633     return CPL_ERROR_NONE;
04634 
04635 }
04636 
04637 
04638 /* 
04639  * @brief
04640  *   Copy existing data to a @em string column.
04641  *
04642  * @param column    Existing column.
04643  * @param data      Existing data buffer.
04644  *   
04645  * @return 0 on success. If the input column is not of type string, a
04646  *   @c CPL_ERROR_TYPE_MISMATCH is returned. At any @c NULL input
04647  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04648  *
04649  * See documentation of function @c xxx_column_copy_data_int().
04650  * 
04651  * The input data are copied into the specified column. The size of the
04652  * input array is not checked in any way. The strings pointed by the input
04653  * buffer are all duplicated, while the strings contained in the column 
04654  * are released before being overwritten. If @em N is the length of the 
04655  * column, the first @em N values of the input data buffer would be copied 
04656  * to the column buffer. If the column had length zero, no values would be 
04657  * copied.
04658  */
04659 
04660 cpl_error_code xxx_column_copy_data_string(xxx_column *column, 
04661                                            const char **data)
04662 {
04663 
04664     const char *fid    = "xxx_column_copy_data_string";
04665     cpl_type     type   = xxx_column_get_type(column); 
04666     int          length = xxx_column_get_size(column);
04667 
04668 
04669     if (data == 0x0 || column == 0x0)
04670         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04671 
04672     if (type != CPL_TYPE_STRING)
04673         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
04674 
04675 
04676     while (length--) {
04677         if (column->values->s[length])
04678             cpl_free(column->values->s[length]);
04679         if (data[length])
04680             column->values->s[length] = cpl_strdup((char *)data[length]);
04681         else
04682             column->values->s[length] = NULL;
04683     }
04684 
04685     return CPL_ERROR_NONE;
04686 
04687 }
04688 
04689 
04690 /* 
04691  * @brief
04692  *   Delete a column.
04693  *
04694  * @param column  Column to be deleted.
04695  *
04696  * @return Nothing.
04697  *
04698  * This function deletes a column. If the input column is @c NULL, 
04699  * nothing is done, and no error is set.
04700  */
04701 
04702 void xxx_column_delete(xxx_column *column)
04703 {
04704 
04705     cpl_type           type;
04706     xxx_column_values *values;
04707     int                length;
04708 
04709 
04710     if (column != NULL) {
04711         type   = xxx_column_get_type(column);
04712         values = xxx_column_get_values(column);
04713         length = xxx_column_get_size(column);
04714 
04715         xxx_column_values_delete(values, length, type);
04716         if (column->name)
04717             cpl_free(column->name);
04718         if (column->unit)
04719             cpl_free(column->unit);
04720         if (column->format)
04721             cpl_free(column->format);
04722         if (column->null)
04723             cpl_free(column->null);
04724         if (column->dimensions)
04725             cpl_array_delete(column->dimensions);
04726         cpl_free(column);
04727     }
04728 
04729 }
04730 
04731 
04732 /* 
04733  * @brief
04734  *   Delete a column, without losing the data.
04735  *
04736  * @param column  Column to be deleted.
04737  *
04738  * @return Pointer to the internal data buffer.
04739  *
04740  * This function deletes a column, but the data buffer is not destroyed.
04741  * Supposedly, the developer knows that the data are static, or the
04742  * developer holds the pointer to the data obtained with the functions
04743  * @c xxx_column_get_data_int(), @c xxx_column_get_data_float(), etc.
04744  * If the input column is @c NULL, nothing is done, and no error is set.
04745  */
04746 
04747 void *xxx_column_unwrap(xxx_column *column)
04748 {
04749  
04750     cpl_type           type;
04751     xxx_column_values *values;
04752     void              *d = NULL;
04753  
04754  
04755     if (column != NULL) {
04756         type = xxx_column_get_type(column);
04757         values = xxx_column_get_values(column);
04758         d = (void *)values->i;
04759         cpl_free(values);
04760         if (column->name)
04761             cpl_free(column->name);
04762         if (column->unit)
04763             cpl_free(column->unit);
04764         if (column->format)
04765             cpl_free(column->format);
04766         if (column->null)
04767             cpl_free(column->null);
04768         if (column->dimensions)
04769             cpl_array_delete(column->dimensions);
04770         cpl_free(column);
04771     }
04772 
04773     return d;
04774 
04775 }
04776 
04777 
04778 /* 
04779  * @brief
04780  *   Delete a string column, without losing the single strings.
04781  *
04782  * @param column  Column to be deleted.
04783  *
04784  * @return Nothing, but if the column is not of string type, a 
04785  * @c CPL_ERROR_INVALID_TYPE is set.
04786  *
04787  * This function deletes a string column, but the single strings pointed
04788  * by the data buffer are not destroyed. Supposedly, the developer knows
04789  * that the strings are static, or the developer holds the pointers to the
04790  * strings somewhere else. If the input column is @c NULL, or the input
04791  * column is not a string column, nothing is done.
04792  */
04793 
04794 void xxx_column_delete_but_strings(xxx_column *column)
04795 {
04796 
04797     cpl_type           type;
04798     xxx_column_values *values;
04799 
04800 
04801     if (column == NULL)
04802         return;
04803 
04804     type = xxx_column_get_type(column);
04805 
04806     if (type == CPL_TYPE_STRING) {
04807         values = xxx_column_get_values(column);
04808         if (values->s)
04809             cpl_free(values->s);
04810         if (values)
04811             cpl_free(values);
04812         if (column->name)
04813             cpl_free(column->name);
04814         if (column->unit)
04815             cpl_free(column->unit);
04816         if (column->format)
04817             cpl_free(column->format);
04818         if (column->null)
04819             cpl_free(column->null);
04820         cpl_free(column);
04821     }
04822     else
04823         cpl_error_set("xxx_column_delete_but_strings", CPL_ERROR_INVALID_TYPE);
04824 
04825 }
04826 
04827 
04828 /*
04829  * @brief
04830  *   Delete an array column, without losing the single arrays.
04831  *
04832  * @param column  Column to be deleted.
04833  *
04834  * @return Nothing, but if the column is not of array type, a
04835  * @c CPL_ERROR_INVALID_TYPE is set.
04836  *   
04837  * This function deletes an array column, but the single arrays pointed
04838  * by the data buffer are not destroyed. Supposedly, the developer knows
04839  * that the arrays are static, or the developer holds the pointers to the
04840  * arrays somewhere else. If the input column is @c NULL, or the input
04841  * column is not an array column, nothing is done.
04842  */
04843 
04844 void xxx_column_delete_but_arrays(xxx_column *column)
04845 {
04846 
04847     cpl_type           type;
04848     xxx_column_values *values;
04849 
04850 
04851     if (column == NULL)
04852         return;
04853 
04854     type = xxx_column_get_type(column);
04855 
04856     if (type & CPL_TYPE_POINTER) {
04857         values = xxx_column_get_values(column);
04858         if (values->array)
04859             cpl_free(values->array);
04860         if (values)
04861             cpl_free(values);
04862         if (column->name)
04863             cpl_free(column->name);
04864         if (column->unit)
04865             cpl_free(column->unit);
04866         if (column->format)
04867             cpl_free(column->format);
04868         if (column->null)
04869             cpl_free(column->null);
04870         if (column->dimensions)
04871             cpl_array_delete(column->dimensions);
04872         cpl_free(column);
04873     }
04874     else
04875         cpl_error_set("xxx_column_delete_but_arrays", CPL_ERROR_INVALID_TYPE);
04876 
04877 }
04878 
04879 
04880 /* 
04881  * @brief
04882  *   Give a new name to a column.
04883  *
04884  * @param column  Column to be named.
04885  * @param name    New column name.
04886  *
04887  * @return @c CPL_ERROR_NONE on success. If the input column is @c NULL,
04888  *   a @c CPL_ERROR_NULL_INPUT is returned.
04889  *
04890  * The input name is duplicated before being used as the column name. 
04891  * If the new name is a @c NULL pointer the column will be nameless.
04892  */
04893 
04894 cpl_error_code xxx_column_set_name(xxx_column *column, const char *name)
04895 {
04896 
04897     const char *fid = "xxx_column_set_name";
04898 
04899 
04900     if (column == 0x0)
04901         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04902 
04903     if (column->name)
04904         cpl_free(column->name);
04905 
04906     if (name)
04907         column->name = cpl_strdup((char *)name);
04908     else
04909         column->name = NULL;
04910 
04911     return CPL_ERROR_NONE;
04912 
04913 }
04914 
04915 
04916 /* 
04917  * @brief
04918  *   Get the name of a column.
04919  *
04920  * @param column  Column to get the name from.
04921  *
04922  * @return Name of column, or @em NULL if the column is nameless, or 
04923  *   if the input column is a @c NULL pointer. In the latter case, a 
04924  *   @c CPL_ERROR_NULL_INPUT is set.
04925  *
04926  * Return the name of a column, if present. Note that the returned 
04927  * string is a pointer to the column name, not its copy. Its manipulation
04928  * will directly affect the column name, while changing the column name
04929  * using @c xxx_column_set_name() will turn it into garbage. Therefore,
04930  * if a real copy of a column name is required, this function should be
04931  * called as an argument of the function @c cpl_strdup(). If the input column 
04932  * has no name, a @c NULL is returned.
04933  */
04934 
04935 const char *xxx_column_get_name(xxx_column *column)
04936 {
04937 
04938     if (column)
04939         return column->name;
04940 
04941     cpl_error_set("xxx_column_get_name", CPL_ERROR_NULL_INPUT);
04942 
04943     return NULL;
04944 
04945 }
04946 
04947 
04948 /* 
04949  * @brief
04950  *   Give a new unit to a column.
04951  * 
04952  * @param column  Column to access.
04953  * @param unit    New column unit.
04954  *
04955  * @return 0 on success. Currently this function always succeeds.
04956  * 
04957  * The input unit is duplicated before being used as the column unit.
04958  * If the new unit is a @c NULL pointer the column will be unitless. 
04959  * The unit string associated to a column has no effect on any operation 
04960  * performed on columns, and it must be considered just an optional 
04961  * description of the content of a column.
04962  */ 
04963 
04964 cpl_error_code xxx_column_set_unit(xxx_column *column, const char *unit)
04965 {
04966 
04967     if (column == 0x0)
04968         return cpl_error_set("xxx_column_set_unit", CPL_ERROR_NULL_INPUT);
04969 
04970     if (column->unit)
04971         cpl_free(column->unit);
04972 
04973     if (unit)
04974         column->unit = cpl_strdup((char *)unit);
04975     else
04976         column->unit = NULL;
04977 
04978     return CPL_ERROR_NONE;
04979 
04980 }
04981 
04982 
04983 /* 
04984  * @brief
04985  *   Get the unit of a column.
04986  *
04987  * @param column  Column to get the unit from.
04988  *
04989  * @return Unit of column, or @c NULL if the column is unitless, or if the
04990  * input column is a @c NULL. In the latter case, a @c CPL_ERROR_NULL_INPUT is
04991  * set.
04992  *
04993  * Return the unit of a column, if present. Note that the returned
04994  * string is a pointer to the column unit, not its copy. Its manipulation
04995  * will directly affect the column unit, while changing the column unit
04996  * using @c xxx_column_set_unit() will turn it into garbage. Therefore,
04997  * if a real copy of a column unit is required, this function should be
04998  * called as an argument of the function @c cpl_strdup(). If the input column
04999  * has no unit, a @c NULL is returned.
05000  */
05001 
05002 const char *xxx_column_get_unit(xxx_column *column)
05003 {
05004 
05005     if (column)
05006         return column->unit;
05007 
05008     cpl_error_set("xxx_column_get_unit", CPL_ERROR_NULL_INPUT);
05009 
05010     return NULL;
05011 
05012 }
05013 
05014 
05015 /* 
05016  * @brief
05017  *   Give a new format to a column.
05018  *
05019  * @param column  Column to access.
05020  * @param format  New column format.
05021  *
05022  * @return 0 on success. Currently this function always succeeds.
05023  *
05024  * The input format is duplicated before being used as the column format.
05025  * If a @c NULL @em format is given, "%s" will be used if the column is
05026  * of type string, "% 1.5e" if the column is of type float or double, and 
05027  * "% 7d" if it is of type integer. The format string associated to a column 
05028  * has no effect on any operation performed on columns, and it is used
05029  * just while printing a column. The given format string must conform to
05030  * the legal standard C formats.
05031  */
05032 
05033 cpl_error_code xxx_column_set_format(xxx_column *column, const char *format)
05034 {
05035 
05036     const char *fid = "xxx_column_set_format";
05037     cpl_type type;
05038 
05039 
05040     if (column == 0x0)
05041         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05042 
05043     type = xxx_column_get_type(column);
05044 
05045     if (column->format)
05046         cpl_free(column->format);
05047 
05048     if (format)
05049         column->format = cpl_strdup((char *)format);
05050     else
05051         switch (type) {
05052         case CPL_TYPE_INT:
05053         case CPL_TYPE_INT | CPL_TYPE_POINTER:
05054             column->format = cpl_strdup(INT_FORM);
05055             break;
05056         case CPL_TYPE_FLOAT:
05057         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
05058             column->format = cpl_strdup(FLOAT_FORM);
05059             break;
05060         case CPL_TYPE_DOUBLE:
05061         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
05062             column->format = cpl_strdup(DOUBLE_FORM);
05063             break;
05064         case CPL_TYPE_STRING:
05065         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
05066             column->format = cpl_strdup(STRING_FORM);
05067             break;
05068         default:
05069             return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
05070         }
05071 
05072     return CPL_ERROR_NONE;
05073     
05074 }
05075 
05076 
05077 /*  
05078  * @brief
05079  *   Get the format of a column.
05080  *  
05081  * @param column  Column to get the format from.
05082  *
05083  * @return Column format, or @c NULL. The latter case can occur only if a
05084  *   @c NULL column is passed to the function, and a @c CPL_ERROR_NULL_INPUT 
05085  *   is set.
05086  *
05087  * Return the format string of a column. Note that the returned string 
05088  * is a pointer to the column format, not its copy. Its manipulation
05089  * will directly affect the column format, while changing the column format
05090  * using @c xxx_column_set_format() will turn it into garbage. Therefore,
05091  * if a real copy of a column format is required, this function should be
05092  * called as an argument of the function @c cpl_strdup(). The function accepts 
05093  * also a @c NULL input column.
05094  */
05095 
05096 const char *xxx_column_get_format(xxx_column *column)
05097 {
05098 
05099     if (column)
05100         return column->format;
05101 
05102     cpl_error_set("xxx_column_get_format", CPL_ERROR_NULL_INPUT);
05103 
05104     return NULL;
05105 
05106 }
05107 /*
05108  * @brief
05109  *   Get the depth of a column.
05110  *
05111  * @param column  Column to get the depth from.
05112  *
05113  * @return Depth of column, or zero. The latter case can occur either
05114  * with a non-array column, or if a NULL column is passed to this
05115  * function, but in the latter case a @c CPL_ERROR_NULL_INPUT is set.
05116  *
05117  * If the column is @em NULL, zero is returned.
05118  */
05119 
05120 int xxx_column_get_depth(xxx_column *column)
05121 {
05122 
05123     if (column)
05124         return column->depth;
05125 
05126     cpl_error_set("xxx_column_get_depth", CPL_ERROR_NULL_INPUT);
05127 
05128     return 0;
05129 
05130 }
05131 
05132 
05133 /*
05134  * @brief
05135  *   Get the number of dimensions of a column.
05136  *
05137  * @param column  Column to get the number of dimensions from.
05138  *
05139  * @return Number of dimensions of column, or zero. The latter case can 
05140  * occur if a NULL column is passed to this function, and in that case
05141  * @c CPL_ERROR_NULL_INPUT is also set. If a column is not an array
05142  * column, or if it has no dimensions, 1 is returned.
05143  *
05144  * If the column is @em NULL, zero is returned. 
05145  */
05146 
05147 int xxx_column_get_dimensions(xxx_column *column)
05148 {
05149 
05150     if (column) {
05151         if (xxx_column_get_type(column) & CPL_TYPE_POINTER)
05152             if (column->dimensions)
05153                 return cpl_array_get_size(column->dimensions);
05154         return 1;
05155     }
05156 
05157     cpl_error_set("xxx_column_get_dimensions", CPL_ERROR_NULL_INPUT);
05158 
05159     return 0;
05160 
05161 }
05162 
05163 
05164 /*
05165  * @brief
05166  *   Set the dimensions of a column.
05167  *
05168  * @param column      Column to be assigned the dimensions.
05169  * @param dimensions  Integer array containing the sizes of the column
05170  *
05171  * @return The column must be of type array, and all of its elements
05172  * must be valid, or a @c CPL_ERROR_ILLEGAL_INPUT is returned. 
05173  * A @c CPL_ERROR_INCOMPATIBLE_INPUT is returned if the specified 
05174  * sizes are incompatible with the total number of elements in the column.
05175  * If the input array @em dimensions is not an integer array a
05176  * @c CPL_ERROR_TYPE_MISMATCH is returned. If this array has size less 
05177  * than 2, nothing is done and no error is returned. If a NULL column is 
05178  * passed to this function, a @c CPL_ERROR_NULL_INPUT is set. 
05179  *
05180  * Set the dimensions of a column. 
05181  */
05182 
05183 cpl_error_code xxx_column_set_dimensions(xxx_column *column, 
05184                                          cpl_array *dimensions)
05185 {
05186     const char *fid = "xxx_column_set_dimensions";
05187 
05188     cpl_type type;
05189     int      ndim;
05190     int      size = 1;
05191 
05192     if (column == NULL || dimensions == NULL)
05193         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05194 
05195     type = xxx_column_get_type(column);
05196 
05197     if (type & CPL_TYPE_POINTER) {
05198         type = cpl_array_get_type(dimensions);
05199 
05200         if (!(type & CPL_TYPE_INT))
05201             return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05202 
05203         ndim = cpl_array_get_size(dimensions);
05204 
05205         if (ndim < 2)
05206             return CPL_ERROR_NONE;
05207 
05208         if (cpl_array_has_invalid(dimensions))
05209             return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
05210 
05211         while (ndim--)
05212             size *= cpl_array_get(dimensions, ndim, NULL);
05213 
05214         if (size != column->depth)
05215             return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
05216 
05217         if (column->dimensions)
05218             cpl_array_delete(column->dimensions);
05219 
05220         column->dimensions = cpl_array_duplicate(dimensions);
05221     }
05222     else
05223         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
05224 
05225     return CPL_ERROR_NONE;
05226 
05227 }
05228 
05229 
05230 /*
05231  * @brief
05232  *   Get size of one dimension of the column.
05233  *
05234  * @param column  Column.
05235  * @param indx    Indicate dimension to query (0 = x, 1 = y, 2 = z, etc.)
05236  *
05237  * @return Size of queried dimension of the column, or zero in case of error.
05238  *
05239  * If the column is not of type array, a @c CPL_ERROR_UNSUPPORTED_MODE is set.
05240  * A @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set if the specified @em indx
05241  * is not compatible with the column dimensions. If the column has no
05242  * dimensions, 1 is returned.
05243  *
05244  * Get size of one dimension of the column.
05245  */
05246 
05247 int xxx_column_get_dimension(xxx_column *column, int indx)
05248 {
05249     const char *fid = "xxx_column_get_dimension";
05250     
05251     cpl_type type;
05252     int      ndim;
05253     
05254 
05255     if (column == NULL) {
05256         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05257         return 0;
05258     }
05259 
05260     if (indx < 0) {
05261         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
05262         return 0;
05263     }
05264 
05265     type = xxx_column_get_type(column);
05266 
05267     if (type & CPL_TYPE_POINTER) {
05268 
05269         if (column->dimensions)
05270             ndim = cpl_array_get_size(column->dimensions);
05271         else
05272             ndim = 1;
05273 
05274         if (indx >= ndim) {
05275             cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
05276             return 0;
05277         }
05278 
05279         if (ndim > 1)
05280             return cpl_array_get(column->dimensions, indx, NULL);
05281         else
05282             return column->depth;
05283 
05284     }
05285 
05286     return cpl_error_set(fid, CPL_ERROR_UNSUPPORTED_MODE);
05287 
05288 
05289 
05290 }
05291 
05292 
05293 /* 
05294  * @brief
05295  *   Check if a column element is invalid.
05296  *
05297  * @param column  Column to inquire.
05298  * @param indx    Column element to inquire.
05299  *
05300  * @return 1 if the column element is invalid, 0 if not, or in case
05301  *   of error.
05302  *
05303  * Check if a column element is invalid. Column elements are counted 
05304  * starting from zero. An out of range index would cause an error 
05305  * @c CPL_ERROR_ACCESS_OUT_OF_RANGE to be set. If the input column
05306  * has zero length, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE would always be
05307  * set. If the input column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT 
05308  * is set.
05309  */
05310 
05311 int xxx_column_is_invalid(xxx_column *column, int indx)
05312 {
05313 
05314     const char  *fid    = "xxx_column_is_invalid";
05315     cpl_type     type   = xxx_column_get_type(column);
05316     int          length = xxx_column_get_size(column);
05317 
05318 
05319     if (column == 0x0) {
05320         cpl_error_set_where(fid);
05321         return 0;
05322     }
05323 
05324     if (indx < 0 || indx >= length) {
05325         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
05326         return 0;
05327     }
05328 
05329     if (type == CPL_TYPE_STRING)
05330         return (column->values->s[indx] == NULL);
05331     if (type & CPL_TYPE_POINTER)
05332         return (column->values->array[indx] == NULL);
05333     if (column->nullcount == 0)
05334         return 0;
05335     if (column->nullcount == length)
05336         return 1;
05337 
05338     return column->null[indx];
05339 
05340 }
05341 
05342 
05343 /* 
05344  * @brief
05345  *   Check if a column contains at least one invalid element.
05346  *
05347  * @param column  Column to inquire.
05348  *
05349  * @return 1 if the column contains at least one invalid element, 0 if not,
05350  *   -1 in case of error.
05351  *
05352  * Check if there are invalid elements in a column. This function does
05353  * not report the presence of invalid elements within an array type
05354  * column, but in that case reports just if an array is allocated or
05355  * not (just like is done for strings). If the input column is a
05356  * @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is set.
05357  */
05358 
05359 int xxx_column_has_invalid(xxx_column *column)
05360 {
05361 
05362     cpl_type type   = xxx_column_get_type(column);
05363     int      length = xxx_column_get_size(column);
05364 
05365 
05366     if (column == 0x0) {
05367         cpl_error_set_where("xxx_column_has_invalid");
05368         return -1;
05369     }
05370 
05371     if (type == CPL_TYPE_STRING) {
05372         while (length--)
05373             if (column->values->s[length] == NULL)
05374                 return 1;
05375         return 0;
05376     }
05377     if (type & CPL_TYPE_POINTER) {
05378         while (length--)
05379             if (column->values->array[length] == NULL)
05380                 return 1;
05381         return 0;
05382     }
05383 
05384     return (column->nullcount > 0 ? 1 : 0);
05385 
05386 }
05387 
05388 
05389 /* 
05390  * @brief
05391  *   Check if a column contains at least one valid value.
05392  *
05393  * @param column  Column to inquire.
05394  *
05395  * @return 1 if the column contains at least one valid value, 0 if not
05396  *   -1 in case of error.
05397  *
05398  * Check if there are valid values in a column. If the input column is a
05399  * @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is set.
05400  */
05401 
05402 int xxx_column_has_valid(xxx_column *column)
05403 {
05404 
05405     const char *fid    = "xxx_column_has_valid";
05406     cpl_type     type   = xxx_column_get_type(column);
05407     int          length = xxx_column_get_size(column);
05408 
05409 
05410     if (column == 0x0) {
05411         cpl_error_set_where(fid);
05412         return -1;
05413     }
05414 
05415     if (type == CPL_TYPE_STRING) {
05416 
05417         while (length--)
05418             if (column->values->s[length])
05419                 return 1;
05420         return 0;
05421 
05422     }
05423     if (type & CPL_TYPE_POINTER) {
05424 
05425         while (length--)
05426             if (column->values->array[length])
05427                 return 1;
05428         return 0;
05429 
05430     }
05431 
05432     return (column->nullcount < length ? 1 : 0);
05433 
05434 }
05435 
05436 
05437 /* 
05438  * @brief
05439  *   Count number of invalid elements in a column.
05440  *
05441  * @param column  Column to inquire.
05442  *
05443  * @return Number of invalid elements in a column. -1 is always returned
05444  *   in case of error.
05445  *
05446  * Count number of invalid elements in a column. This function does
05447  * not report the presence of invalid elements within an array type
05448  * column, but in that case reports just if an array is allocated or
05449  * not (just like is done for strings). If the column itself is 
05450  * a @c NULL pointer, an error @c CPL_ERROR_NULL_INPUT is set.
05451  */
05452 
05453 int xxx_column_count_invalid(xxx_column *column)
05454 {
05455 
05456     cpl_type    type   = xxx_column_get_type(column);
05457     int         length = xxx_column_get_size(column);
05458     char      **p;
05459     cpl_array **a;
05460 
05461 
05462     if (column == 0x0) {
05463         cpl_error_set_where("xxx_column_count_invalid");
05464         return -1;
05465     }
05466 
05467     if (type == CPL_TYPE_STRING) {
05468 
05469         p = column->values->s;
05470 
05471         column->nullcount = 0;
05472         while (length--)
05473             if (*p++ == NULL)
05474                 column->nullcount++;
05475 
05476     }
05477 
05478     if (type & CPL_TYPE_POINTER) {
05479 
05480         a = column->values->array;
05481 
05482         column->nullcount = 0;
05483         while (length--)
05484             if (*a++ == NULL)
05485                 column->nullcount++;
05486  
05487     }
05488 
05489     return column->nullcount;
05490 
05491 }
05492 
05493 
05494 /*
05495  * @brief
05496  *   Get a pointer to @c integer column data. 
05497  *
05498  * @param column  Column to get the data from.
05499  *
05500  * @return Pointer to @c integer column data. If @em column contains no
05501  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05502  *   a @c NULL is returned, and an error is set.
05503  *
05504  * If the column is not of type @c CPL_TYPE_INT, a
05505  * @c CPL_ERROR_TYPE_MISMATCH is set.
05506  *
05507  * @note
05508  *   Use at your own risk: direct manipulation of column data rules 
05509  *   out any check performed by the column object interface, and may 
05510  *   introduce inconsistencies between the column information maintained 
05511  *   internally and the actual column data.
05512  */
05513 
05514 int *xxx_column_get_data_int(xxx_column *column)
05515 {
05516 
05517     const char *fid  = "xxx_column_get_data_int";
05518     cpl_type     type = xxx_column_get_type(column);
05519 
05520 
05521     if (column == 0x0) {
05522         cpl_error_set_where(fid);
05523         return NULL;
05524     }
05525 
05526     if (type == CPL_TYPE_INT)
05527         return column->values->i;
05528 
05529     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05530 
05531     return NULL;
05532 
05533 }
05534 
05535 
05536 /* 
05537  * @brief
05538  *   Get a pointer to @em float column data. 
05539  *
05540  * @param column  Column to get the data from.
05541  *
05542  * @return Pointer to @em float column data. If @em column contains no
05543  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05544  *   a @c NULL is returned, and an error is set.
05545  * 
05546  * If the column is not of type @c CPL_TYPE_FLOAT, a 
05547  * @c CPL_ERROR_TYPE_MISMATCH is set.
05548  *
05549  * See documentation of function xxx_column_get_data_int().
05550  */
05551 
05552 float *xxx_column_get_data_float(xxx_column *column)
05553 {
05554 
05555     const char *fid  = "xxx_column_get_data_float";
05556     cpl_type     type = xxx_column_get_type(column);
05557 
05558 
05559     if (column == 0x0) {
05560         cpl_error_set_where(fid);
05561         return NULL;
05562     }
05563 
05564     if (type == CPL_TYPE_FLOAT)
05565         return column->values->f;
05566 
05567     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05568 
05569     return NULL;
05570 
05571 }
05572 
05573 
05574 /* 
05575  * @brief
05576  *   Get a pointer to @em double column data. 
05577  *
05578  * @param column  Column to get the data from.
05579  *
05580  * @return Pointer to @em double column data. If @em column contains no
05581  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05582  *   a @c NULL is returned, and an error is set. 
05583  *
05584  * If the column is not of type @c CPL_TYPE_DOUBLE, 
05585  * a @c CPL_ERROR_TYPE_MISMATCH is set.
05586  *
05587  * See documentation of function xxx_column_get_data_int().
05588  */
05589 
05590 double *xxx_column_get_data_double(xxx_column *column)
05591 {
05592 
05593     const char *fid  = "xxx_column_get_data_double";
05594     cpl_type     type =  xxx_column_get_type(column);
05595 
05596 
05597     if (column == 0x0) {
05598         cpl_error_set_where(fid);
05599         return NULL;
05600     }
05601 
05602     if (type == CPL_TYPE_DOUBLE)
05603         return column->values->d;
05604 
05605     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05606 
05607     return NULL;
05608 
05609 }
05610 
05611 
05612 /* 
05613  * @brief
05614  *   Get a pointer to string column data. 
05615  *
05616  * @param column  Column to get the data from.
05617  *
05618  * @return Pointer to string column data.  If @em column contains no
05619  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05620  *   a @c NULL is returned, and an error is set. 
05621  *
05622  * If the column is not of type @c CPL_TYPE_STRING, 
05623  * a @c CPL_ERROR_TYPE_MISMATCH is set.
05624  *
05625  * See documentation of function xxx_column_get_data_int().
05626  */
05627 
05628 char **xxx_column_get_data_string(xxx_column *column)
05629 {
05630 
05631     const char *fid  = "xxx_column_get_data_string";
05632     cpl_type     type =  xxx_column_get_type(column);
05633 
05634 
05635     if (column == 0x0) {
05636         cpl_error_set_where(fid);
05637         return NULL;
05638     }
05639 
05640     if (type == CPL_TYPE_STRING)
05641         return column->values->s;
05642 
05643     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05644 
05645     return NULL;
05646 
05647 }
05648 
05649 
05650 /*
05651  * @brief
05652  *   Get a pointer to array column data.
05653  *
05654  * @param column  Column to get the data from.
05655  *
05656  * @return Pointer to array column data.  If @em column contains no
05657  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05658  *   a @c NULL is returned and an error is set.
05659  *
05660  * If the column is not an array type
05661  * a @c CPL_ERROR_TYPE_MISMATCH is set.
05662  *
05663  * See documentation of function xxx_column_get_data_int().
05664  */
05665 
05666 cpl_array **xxx_column_get_data_array(xxx_column *column)
05667 {
05668 
05669     const char *fid  = "xxx_column_get_data_array";
05670     cpl_type     type =  xxx_column_get_type(column);
05671 
05672 
05673     if (column == 0x0) {
05674         cpl_error_set_where(fid);
05675         return NULL;
05676     }
05677 
05678     if (type & CPL_TYPE_POINTER)
05679         return column->values->array;
05680 
05681     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05682 
05683     return NULL;
05684 
05685 }
05686 
05687 
05688 /* 
05689  * @brief
05690  *   Get a pointer to a column invalid flags buffer.
05691  *
05692  * @param column  Column from where to get the data.
05693  *
05694  * @return Pointer to the column buffer containing the flagging of the
05695  *   invalid elements, or @c NULL if it is missing.
05696  *
05697  * If all or no column elements are invalid, a @c NULL pointer is returned. 
05698  * A @c NULL is returned also if the column is of type @c CPL_TYPE_STRING 
05699  * or of type array (no buffer marking the invalid elements is present in 
05700  * this case).
05701  *
05702  * @note
05703  *   Use at your own risk: direct manipulation of column data rules out 
05704  *   any check performed by the column object interface, and may introduce 
05705  *   inconsistencies between the column information maintained internally
05706  *   and the actual column data.
05707  */
05708 
05709 xxx_column_flag *xxx_column_get_data_invalid(xxx_column *column)
05710 {
05711 
05712     if (column == 0x0) {
05713         cpl_error_set("xxx_column_get_data_invalid", CPL_ERROR_NULL_INPUT);
05714         return NULL;
05715     }
05716 
05717     return column->null;
05718 
05719 }
05720 
05721 
05722 /* 
05723  * @brief
05724  *   Plug a new invalid flag buffer into a numerical column.
05725  *
05726  * @param column      Column to access.
05727  * @param nulls       Array of null flags.
05728  * @param nullcount   Total number of nulls.
05729  *
05730  * @return CPL_ERROR_NONE on success. If the column type is not
05731  *   numerical, an invalid flag buffer is not used, and an attempt 
05732  *   to plug it in will cause a @c CPL_ERROR_INVALID_TYPE to be 
05733  *   returned. A @c CPL_ERROR_INCOMPATIBLE_INPUT is returned if 
05734  *   an impossible @em nullcount value is passed. If the input 
05735  *   @em nulls buffer does not contains just 1s or 0s, a 
05736  *   @c CPL_ERROR_ILLEGAL_INPUT is returned. A @c CPL_ERROR_NULL_INPUT
05737  *   is returned if a @c NULL column pointer is passed.
05738  *
05739  * This function is used to assign a new set of flags marking invalid
05740  * elements within a column. If a flag buffer already exists, this is 
05741  * deallocated before being replaced by the new one. If @em nullcount 
05742  * is either 0 or equal to the column length, the passed flag buffer 
05743  * is ignored, but the internal buffer is deallocated. If @em nullcount 
05744  * is negative, it will be evaluated internally, or set to zero if no 
05745  * flag buffer was passed. This function cannot be use either for array
05746  * columns or @c CPL_TYPE_STRING columns.
05747  *
05748  * @note
05749  *   Use at your own risk: direct manipulation of column data rules out 
05750  *   any check performed by the column object interface, and may introduce 
05751  *   inconsistencies between the column information maintained internally 
05752  *   and the actual column data.
05753  */
05754 
05755 cpl_error_code xxx_column_set_data_invalid(xxx_column *column, 
05756                              xxx_column_flag *nulls, int nullcount)
05757 {
05758 
05759     const char *fid    = "xxx_column_set_data_invalid";
05760     cpl_type     type   = xxx_column_get_type(column);
05761     int          length = xxx_column_get_size(column);
05762 
05763 
05764     if (column == 0x0)
05765         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05766 
05767     if (type == CPL_TYPE_STRING)
05768         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
05769 
05770     if (type & CPL_TYPE_POINTER)
05771         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
05772 
05773     if (nullcount > length)
05774         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
05775 
05776     if (nulls)
05777         while (length--)
05778             if (nulls[length] != 0)
05779                 if (nulls[length] != 1)
05780                     return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
05781 
05782     length = xxx_column_get_size(column);
05783 
05784     if (nullcount < 0) {
05785 
05786         /*
05787          *  The total number of NULLs must be evaluated internally. If a 
05788          *  null flag buffer was not passed, the total number of NULLs is
05789          *  assumed to be zero.
05790          */
05791 
05792         if (nulls) {
05793             nullcount = 0;
05794             while (length--)
05795                 nullcount += nulls[length];
05796         }
05797         else {
05798             nullcount = 0;
05799         }
05800     }
05801 
05802 
05803     /*
05804      *  If no null buffer was passed, and a wrong null count was specified,
05805      *  return a failure (wrong input).
05806      */
05807 
05808     if (!nulls)
05809         if (nullcount != length && nullcount != 0)
05810             return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
05811 
05812 
05813     /*
05814      *  Replace the old buffer with the new one if necessary.
05815      */
05816 
05817     if (nullcount == length || nullcount == 0)
05818         nulls = NULL;
05819 
05820     if (column->null)
05821         cpl_free(column->null);
05822 
05823     column->null = nulls;
05824     column->nullcount = nullcount;
05825 
05826     return 0;
05827 
05828 }
05829 
05830 
05831 /*
05832  * @brief
05833  *   Reallocate a column of arrays to a new depth.
05834  *
05835  * @param column  Column to be resized.
05836  * @param depth   New depth of column.
05837  *
05838  * @return @c CPL_ERROR_NONE on success. The new column depth must not 
05839  *   be negative, or a @c CPL_ERROR_ILLEGAL_INPUT is returned. The input
05840  *   column pointer should not be @c NULL, or a @c CPL_ERROR_NULL_INPUT
05841  *   is returned.
05842  *
05843  * Reallocate a column of arrays to a new depth. The contents of the
05844  * arrays data buffer will be unchanged up to the lesser of the new and
05845  * old sizes. If the column depth is increased, the new arrays elements
05846  * are flagged as invalid. The pointer to array data may change, therefore
05847  * pointers previously retrieved by calling @c xxx_column_get_data_array(),
05848  * @c xxx_column_get_data_string(), etc. should be discarded). Resizing
05849  * to zero is allowed, and would produce a zero-depth column. In case
05850  * of failure, the old data buffer is left intact. Changing column
05851  * depth implies removing any information about column dimensions.
05852  */
05853 
05854 
05855 /* 
05856  * @brief
05857  *   Reallocate a column to a new number of elements.
05858  *
05859  * @param column      Column to be resized.
05860  * @param new_length  New number of elements in column.
05861  *
05862  * @return @c CPL_ERROR_NONE on success. The new column size must not be
05863  *   negative, or a @c CPL_ERROR_ILLEGAL_INPUT is returned. The input
05864  *   column pointer should not be @c NULL, or a @c CPL_ERROR_NULL_INPUT
05865  *   is returned.
05866  *
05867  * Reallocate a column to a new number of elements. The contents of the 
05868  * column data buffer will be unchanged up to the lesser of the new and 
05869  * old sizes. If the column size is increased, the new column elements 
05870  * are flagged as invalid. The pointer to data may change, therefore 
05871  * pointers previously retrieved by calling @c xxx_column_get_data_int(), 
05872  * @c xxx_column_get_data_string(), etc. should be discarded). Resizing 
05873  * to zero is allowed, and would produce a zero-length column. In case 
05874  * of failure, the old data buffer is left intact.
05875  */
05876 
05877 cpl_error_code xxx_column_set_size(xxx_column *column, int new_length)
05878 {
05879 
05880     const char *fid          = "xxx_column_set_size";
05881     cpl_type     type         = xxx_column_get_type(column);
05882     int          old_length   = xxx_column_get_size(column);
05883     int          element_size = xxx_column_type_size(type);
05884     int          null_size    = old_length * sizeof(xxx_column_flag);
05885     int          new_size     = element_size * new_length;
05886     int          i            = 0;
05887 
05888     xxx_column_flag *np       = NULL;
05889     char           **sp;
05890     cpl_array      **ap;
05891 
05892 
05893     if (column == 0x0)
05894         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05895 
05896     if (new_length < 0)
05897         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
05898 
05899     if (new_length == old_length)     /* Resizing is unnecessary */
05900         return CPL_ERROR_NONE;
05901 
05902     if (new_length == 0) {            /* Resizing to zero        */
05903 
05904         switch (type) {
05905         case CPL_TYPE_INT | CPL_TYPE_POINTER:
05906         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
05907         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
05908         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
05909 
05910             for (i = 0; i < old_length; i++)
05911                 if (column->values->array[i])
05912                     cpl_array_delete(column->values->array[i]);
05913 
05914             cpl_free((void *)column->values->array);
05915 
05916             break;
05917 
05918         case CPL_TYPE_STRING:
05919 
05920             for (i = 0; i < old_length; i++)
05921                 if (column->values->s[i])
05922                     cpl_free(column->values->s[i]);
05923 
05924         default:
05925 
05926             if (column->values->s)
05927                 cpl_free((void *)column->values->s);
05928 
05929             break;
05930 
05931         }
05932 
05933         column->values->i = NULL;
05934         if (column->null)
05935             cpl_free(column->null);
05936         column->null = NULL;
05937         column->nullcount = 0;
05938         column->length = 0;
05939 
05940         return CPL_ERROR_NONE;
05941     }
05942 
05943     if (old_length == 0) {            /* Resizing from zero      */
05944 
05945         switch (type) {
05946         case CPL_TYPE_INT:
05947             column->values->i = cpl_malloc(new_length * sizeof(int));
05948             break;
05949         case CPL_TYPE_FLOAT:
05950             column->values->f = cpl_malloc(new_length * sizeof(float));
05951             break;
05952         case CPL_TYPE_DOUBLE:
05953             column->values->d = cpl_malloc(new_length * sizeof(double));
05954             break;
05955         case CPL_TYPE_STRING:
05956             column->values->s = cpl_calloc(new_length, sizeof(char *));
05957             break;
05958         case CPL_TYPE_INT | CPL_TYPE_POINTER:
05959         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
05960         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
05961         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
05962             column->values->array = cpl_calloc(new_length, sizeof(cpl_array *));
05963             break;
05964         default:
05965             return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
05966         }
05967 
05968         column->length = new_length;
05969 
05970         if (type != CPL_TYPE_STRING && !(type & CPL_TYPE_POINTER))
05971             column->nullcount = new_length;
05972 
05973         return CPL_ERROR_NONE;
05974     }
05975 
05976 
05977     /*
05978      * In the following the generic case is handled
05979      */
05980 
05981     if (column->null) {
05982 
05983         /*
05984          *  If the null flags buffer exists, it should be reallocated 
05985          *  first. 
05986          */
05987 
05988         null_size = new_length * sizeof(xxx_column_flag);
05989         column->null = cpl_realloc((void *)column->null, null_size);
05990 
05991         if (new_length < old_length) {
05992 
05993             /*
05994              *  If the column was shortened, check whether some 
05995              *  NULLs are still present in column. If no NULL is 
05996              *  found, then the null flags buffer can be deallocated.
05997              */
05998 
05999             column->nullcount = 0;
06000             np = column->null;
06001             for (i = 0; i < new_length; i++)
06002                 if (*np++)
06003                     column->nullcount++;
06004 
06005             if (column->nullcount == new_length || 
06006                 column->nullcount == 0) {
06007                 if (column->null)
06008                     cpl_free(column->null);
06009                 column->null = NULL;
06010             }
06011         }
06012         else {
06013 
06014             /*
06015              *  Pad with 1s the extra space (by definition, extra space
06016              *  in the column data buffer is not initialized, therefore
06017              *  it is a NULL value; the case of string columns doesn't 
06018              *  need to be treated, since in that case the null flags 
06019              *  are not used).
06020              */
06021 
06022             np = column->null + old_length;
06023             for (i = old_length; i < new_length; i++)
06024                 *np++ = 1;
06025 
06026             column->nullcount += new_length - old_length;
06027 
06028         }
06029     }
06030     else {
06031 
06032         /*
06033          *  We don't need to take care of string columns here, because
06034          *  they take automatically care of their own NULLs.
06035          */
06036 
06037         if (type != CPL_TYPE_STRING) {
06038 
06039             if (new_length > old_length) {
06040 
06041                 /*
06042                  *  If the null flags buffer doesn't exist, it is 
06043                  *  either because there were no NULLs, or there 
06044                  *  were just NULLs. In the latter case we do not 
06045                  *  need to allocate any new buffer, because the
06046                  *  expansion just added extra NULLs. In the former 
06047                  *  case, we have to allocate a null flags column 
06048                  *  buffer in case the column is expanded, because 
06049                  *  the expanded part contains NULLs:
06050                  */
06051 
06052                 if (column->nullcount == 0) {
06053 
06054                     column->null = cpl_calloc(new_length, 
06055                                               sizeof(xxx_column_flag));
06056 
06057                     np = column->null + old_length;
06058                     for (i = old_length; i < new_length; i++)
06059                         *np++ = 1;
06060 
06061                     column->nullcount = new_length - old_length;
06062                 }
06063                 else                       /* There were just nulls     */
06064                     column->nullcount = new_length;
06065             }
06066             else if (column->nullcount)    /* Column of nulls shortened */
06067                 column->nullcount = new_length;
06068 
06069         }
06070     }
06071 
06072     /*
06073      *  If a column of character strings or of arrays is shortened,
06074      *  we must explicitly free the extra strings.
06075      */
06076 
06077     if (type == CPL_TYPE_STRING)
06078         for (i = new_length; i < old_length; i++)
06079             if (column->values->s[i])
06080                 cpl_free(column->values->s[i]);
06081 
06082     if (type & CPL_TYPE_POINTER)
06083         for (i = new_length; i < old_length; i++)
06084             if (column->values->array[i])
06085                 cpl_array_delete(column->values->array[i]);
06086 
06087     /*
06088      *  Finally, we realloc the column data buffer:
06089      */
06090 
06091     column->values->i = cpl_realloc((void *)column->values->i, new_size);
06092     column->length = new_length;
06093 
06094     /*
06095      *  We don't initialize the extra memory, since it is NULL flagged,
06096      *  with the exception of string and array columns:
06097      */
06098 
06099     if (type == CPL_TYPE_STRING) {
06100         sp = column->values->s + old_length;
06101         for (i = old_length; i < new_length; i++)
06102             *sp++ = 0x0;
06103     }
06104 
06105     if (type & CPL_TYPE_POINTER) {
06106         ap = column->values->array + old_length;
06107         for (i = old_length; i < new_length; i++)
06108             *ap++ = 0x0;
06109     }
06110 
06111     return CPL_ERROR_NONE;
06112 
06113 }
06114 
06115 
06116 /* 
06117  * @brief
06118  *   Read a value from a numerical column.
06119  *
06120  * @param column  Column to be accessed.
06121  * @param indx    Position of element to be read.
06122  * @param null    Flag indicating null values, or error condition.
06123  *
06124  * @return Value read. In case of an invalid column element, or in
06125  *   case of error, 0.0 is always returned. 
06126  *
06127  * Read a value from a numerical column. A @c CPL_ERROR_NULL_INPUT is set in
06128  * case @em column is a @c NULL pointer. A @c CPL_ERROR_INVALID_TYPE is set 
06129  * in case a non-numerical column is accessed. @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06130  * is set if the @em indx is outside the column range. Indexes are 
06131  * counted starting from 0. If the input column has length zero, 
06132  * @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set. The @em null 
06133  * flag is used to indicate whether the accessed column element is 
06134  * valid (0) or invalid (1). The null flag also signals an error 
06135  * condition (-1). The @em null argument can be left to @c NULL.
06136  * This function cannot be used for the access of array elements in
06137  * array columns.
06138  */
06139 
06140 double xxx_column_get(xxx_column *column, int indx, int *null)
06141 {
06142 
06143     const char *fid  = "xxx_column_get";
06144     cpl_type     type = xxx_column_get_type(column);
06145 
06146 
06147     if (null)
06148         *null = -1;
06149 
06150     switch (type) {
06151     case CPL_TYPE_INT:
06152         return (double)xxx_column_get_int(column, indx, null);
06153     case CPL_TYPE_FLOAT:
06154         return (double)xxx_column_get_float(column, indx, null);
06155     case CPL_TYPE_DOUBLE:
06156         return xxx_column_get_double(column, indx, null);
06157     case CPL_TYPE_INT | CPL_TYPE_POINTER:
06158     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
06159     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
06160     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
06161     case CPL_TYPE_STRING:
06162         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
06163         break;
06164     default:
06165         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06166     }
06167 
06168     return 0.0;
06169 
06170 }
06171 
06172 
06173 /* 
06174  * @brief
06175  *   Read a value from an @em integer column.
06176  *
06177  * @param column  Column to be accessed.
06178  * @param indx    Position of element to be read.
06179  * @param null    Flag indicating null values, or error condition.
06180  *
06181  * @return Integer value read. In case of an invalid column element, or in
06182  *   case of error, 0 is always returned.
06183  *
06184  * Read a value from a column of type @c CPL_TYPE_INT. If @em column is a
06185  * @c NULL pointer a @c CPL_ERROR_NULL_INPUT is set. If the column is not
06186  * of the expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx 
06187  * is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set. 
06188  * Indexes are counted starting from 0. If the input column has length zero, 
06189  * the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set. If the @em null 
06190  * flag is a valid pointer, it is used to indicate whether the accessed 
06191  * column element is valid (0) or invalid (1). The null flag also signals 
06192  * an error condition (-1).
06193  */
06194 
06195 int xxx_column_get_int(xxx_column *column, int indx, int *null)
06196 {
06197 
06198     const char *fid    = "xxx_column_get_int";
06199     int          isnull = xxx_column_is_invalid(column, indx);
06200     int          length = xxx_column_get_size(column);
06201     cpl_type     type   = xxx_column_get_type(column);
06202 
06203 
06204     if (null)
06205         *null = -1;
06206 
06207     if (column == 0x0) {
06208         cpl_error_set_where(fid);
06209         return 0;
06210     }
06211 
06212     if (indx < 0 || indx >= length) {
06213         cpl_error_set_where(fid);
06214         return 0;
06215     }
06216 
06217     if (type != CPL_TYPE_INT) {
06218         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06219         return 0;
06220     }
06221 
06222     if (null)
06223         *null = isnull;
06224 
06225     if (isnull)
06226         return 0;
06227 
06228     return column->values->i[indx];
06229 
06230 }
06231 
06232 
06233 /* 
06234  * @brief
06235  *   Read a value from a @em float column.
06236  *
06237  * @param column  Column to be accessed.
06238  * @param indx    Position of element to be read.
06239  * @param null    Flag indicating null values, or error condition.
06240  *
06241  * @return Float value read. In case of an invalid column element, or in
06242  *   case of error, 0.0 is always returned.
06243  *
06244  * Read a value from a column of type @c CPL_TYPE_FLOAT. See the
06245  * documentation of the function xxx_column_get_int().
06246  */
06247 
06248 float xxx_column_get_float(xxx_column *column, int indx, int *null)
06249 {
06250 
06251     const char *fid    = "xxx_column_get_float";
06252     int          isnull = xxx_column_is_invalid(column, indx);
06253     int          length = xxx_column_get_size(column);
06254     cpl_type     type   = xxx_column_get_type(column);
06255 
06256 
06257     if (null)
06258         *null = -1;
06259 
06260     if (column == 0x0) {
06261         cpl_error_set_where(fid);
06262         return 0; 
06263     }
06264 
06265     if (indx < 0 || indx >= length) {
06266         cpl_error_set_where(fid);
06267         return 0; 
06268     }
06269 
06270     if (type != CPL_TYPE_FLOAT) {
06271         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06272         return 0;
06273     }
06274     
06275     if (null)
06276         *null = isnull;
06277 
06278     if (isnull)
06279         return 0;
06280 
06281     return column->values->f[indx];
06282 
06283 }
06284 
06285 
06286 
06287 /* 
06288  * @brief
06289  *   Read a value from a @em double column.
06290  *
06291  * @param column  Column to be accessed.
06292  * @param indx    Position of element to be read.
06293  * @param null    Flag indicating null values, or error condition.
06294  *
06295  * @return Double value read. In case of an invalid column element, or in
06296  *   case of error, 0.0 is always returned.
06297  *
06298  * Read a value from a column of type @c CPL_TYPE_DOUBLE. See the
06299  * documentation of the function xxx_column_get_int().
06300  */
06301 
06302 double xxx_column_get_double(xxx_column *column, int indx, int *null)
06303 {
06304 
06305     const char *fid    = "xxx_column_get_double";
06306     int          isnull = xxx_column_is_invalid(column, indx);
06307     int          length = xxx_column_get_size(column);
06308     cpl_type     type   = xxx_column_get_type(column);
06309 
06310 
06311     if (null)
06312         *null = -1;
06313 
06314     if (column == 0x0) {
06315         cpl_error_set_where(fid);
06316         return 0; 
06317     }
06318 
06319     if (indx < 0 || indx >= length) {
06320         cpl_error_set_where(fid);
06321         return 0; 
06322     }
06323 
06324     if (type != CPL_TYPE_DOUBLE) {
06325         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06326         return 0;
06327     }
06328     
06329     if (null)
06330         *null = isnull;
06331 
06332     if (isnull)
06333         return 0;
06334 
06335     return column->values->d[indx];
06336 
06337 }
06338 
06339 
06340 /* 
06341  * @brief
06342  *   Read a value from a string column.
06343  *
06344  * @param column  Column to be accessed.
06345  * @param indx    Position of element to be read.
06346  *
06347  * @return Character string read. In case of an invalid column element,
06348  *   or in case of error, a @c NULL pointer is always returned.
06349  *
06350  * Read a value from a column of type @c CPL_TYPE_STRING. If @em column is a
06351  * @c NULL pointer a @c CPL_ERROR_NULL_INPUT is set. If the column is not
06352  * of the expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx
06353  * is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set.
06354  * Indexes are counted starting from 0. If the input column has length zero,
06355  * the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set.
06356  * 
06357  * @note
06358  *   The returned string is a pointer to a column element, not its 
06359  *   copy. Its manipulation will directly affect that column element, 
06360  *   while changing that column element using @c xxx_column_set_string() 
06361  *   will turn it into garbage. Therefore, if a real copy of a string 
06362  *   column element is required, this function should be called as an 
06363  *   argument of the function @c cpl_strdup().
06364  */
06365 
06366 const char *xxx_column_get_string(xxx_column *column, int indx)
06367 {
06368 
06369     const char *fid    = "xxx_column_get_string";
06370     int          length = xxx_column_get_size(column);
06371     cpl_type     type   = xxx_column_get_type(column);
06372 
06373 
06374     if (column == 0x0) {
06375         cpl_error_set_where(fid);
06376         return NULL; 
06377     }
06378 
06379     if (indx < 0 || indx >= length) {
06380         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06381         return NULL; 
06382     }
06383 
06384     if (type != CPL_TYPE_STRING) {
06385         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06386         return NULL;
06387     }
06388     
06389     return column->values->s[indx];
06390 
06391 }
06392 
06393 
06394 /*
06395  * @brief
06396  *   Read an array from an array column.
06397  *
06398  * @param column  Column to be accessed.
06399  * @param indx    Position of array to be read.
06400  *
06401  * @return CPL array read. In case of an invalid column element,
06402  *   or in case of error, a @c NULL pointer is always returned.
06403  *
06404  * Read an array from a column of type array. If @em column is a
06405  * @c NULL pointer a @c CPL_ERROR_NULL_INPUT is set. If the column is not
06406  * of the expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx
06407  * is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set.
06408  * Indexes are counted starting from 0. If the input column has length zero,
06409  * the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set.
06410  *
06411  * @note
06412  *   The returned array is a pointer to a column element, not its
06413  *   copy. Its manipulation will directly affect that column element,
06414  *   while changing that column element using @c xxx_column_set_array()
06415  *   will turn it into garbage. Therefore, if a real copy of an array
06416  *   column element is required, this function should be called as an
06417  *   argument of the function @c cpl_array_duplicate().
06418  */
06419 
06420 const cpl_array *xxx_column_get_array(xxx_column *column, int indx)
06421 {
06422 
06423     const char *fid    = "xxx_column_get_array";
06424     int          length = xxx_column_get_size(column);
06425     cpl_type     type   = xxx_column_get_type(column);
06426 
06427 
06428     if (column == 0x0) {
06429         cpl_error_set_where(fid);
06430         return NULL;
06431     }
06432 
06433     if (indx < 0 || indx >= length) {
06434         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06435         return NULL;
06436     }
06437 
06438     if (!(type & CPL_TYPE_POINTER)) {
06439         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06440         return NULL;
06441     }
06442 
06443     return column->values->array[indx];
06444 
06445 }
06446 
06447 
06448 /* 
06449  * @brief
06450  *   Write a value to a numerical column element.
06451  *
06452  * @param column  Column to be accessed.
06453  * @param indx    Position where to write value.
06454  * @param value   Value to write.
06455  *
06456  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer 
06457  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of numerical 
06458  *   type, a @c CPL_ERROR_INVALID_TYPE is returned. If @em indx is outside 
06459  *   the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If 
06460  *   the input column has length zero, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
06461  *   is always returned.
06462  *
06463  * Write a value to a numerical column element. The value is cast to the
06464  * accessed column type. The written value is automatically flagged as
06465  * valid. To invalidate a column value use @c xxx_column_set_invalid().
06466  * Column elements are counted starting from 0. This function cannot
06467  * be used on array columns.
06468  */
06469 
06470 cpl_error_code xxx_column_set(xxx_column *column, int indx, double value)
06471 {
06472 
06473     const char *fid  = "xxx_column_set";
06474     cpl_type     type = xxx_column_get_type(column);
06475 
06476 
06477     switch (type) {
06478     case CPL_TYPE_INT:
06479         return xxx_column_set_int(column, indx, value);
06480     case CPL_TYPE_FLOAT:
06481         return xxx_column_set_float(column, indx, value);
06482     case CPL_TYPE_DOUBLE:
06483         return xxx_column_set_double(column, indx, value);
06484     case CPL_TYPE_INT | CPL_TYPE_POINTER:
06485     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
06486     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
06487     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
06488     case CPL_TYPE_STRING:
06489         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
06490     default:
06491         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06492     }
06493 
06494 }
06495 
06496 
06497 /* 
06498  * @brief
06499  *   Write a value to an @em integer column element.
06500  *
06501  * @param column  Column to be accessed.
06502  * @param indx    Position where to write value.
06503  * @param value   Value to write.
06504  *
06505  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer 
06506  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the 
06507  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx is 
06508  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned.
06509  *   If the input column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
06510  *   is always returned.
06511  *
06512  * Write a value to an @em integer column element. The written value 
06513  * is automatically flagged as valid. To invalidate a column value use 
06514  * @c xxx_column_set_invalid(). Column elements are counted starting 
06515  * from 0.
06516  */
06517 
06518 cpl_error_code xxx_column_set_int(xxx_column *column, int indx, int value)
06519 {
06520 
06521     const char *fid    = "xxx_column_set_int";
06522     int          length = xxx_column_get_size(column);
06523     cpl_type     type   = xxx_column_get_type(column);
06524 
06525 
06526     if (column == 0x0)
06527         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06528     
06529     if (indx < 0 || indx >= length)
06530         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06531 
06532     if (type != CPL_TYPE_INT)
06533         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06534 
06535     column->values->i[indx] = value;
06536     xxx_column_unset_null(column, indx);
06537 
06538     return CPL_ERROR_NONE;
06539 
06540 }
06541 
06542 
06543 /* 
06544  * @brief
06545  *   Write a value to a @em float column element.
06546  *
06547  * @param column  Column to be accessed.
06548  * @param indx    Position where to write value.
06549  * @param value   Value to write.
06550  *
06551  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06552  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06553  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx is
06554  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned.
06555  *   If the input column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06556  *   is always returned.
06557  *
06558  * Write a value to a @em float column element. The written value
06559  * is automatically flagged as valid. To invalidate a column value use
06560  * @c xxx_column_set_invalid(). Column elements are counted starting
06561  * from 0.
06562  */
06563 
06564 cpl_error_code xxx_column_set_float(xxx_column *column, int indx, float value)
06565 {
06566 
06567     const char *fid    = "xxx_column_set_float";
06568     int          length = xxx_column_get_size(column);
06569     cpl_type     type   = xxx_column_get_type(column);
06570 
06571 
06572     if (column == 0x0)
06573         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06574 
06575     if (indx < 0 || indx >= length)
06576         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06577 
06578     if (type != CPL_TYPE_FLOAT)
06579         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06580 
06581     column->values->f[indx] = value;
06582     xxx_column_unset_null(column, indx);
06583 
06584     return CPL_ERROR_NONE;
06585 
06586 }
06587 
06588 
06589 /* 
06590  * @brief
06591  *   Write a value to a @em double column element.
06592  *
06593  * @param column  Column to be accessed.
06594  * @param indx    Position where to write value.
06595  * @param value   Value to write.
06596  *
06597  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06598  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06599  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx is
06600  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned.
06601  *   If the input column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06602  *   is always returned.
06603  *
06604  * Write a value to a @em double column element. The written value
06605  * is automatically flagged as valid. To invalidate a column value use
06606  * @c xxx_column_set_invalid(). Column elements are counted starting
06607  * from 0.
06608  */
06609 
06610 cpl_error_code xxx_column_set_double(xxx_column *column, int indx, 
06611                                      double value)
06612 {
06613 
06614     const char *fid    = "xxx_column_set_double";
06615     int          length = xxx_column_get_size(column);
06616     cpl_type     type   = xxx_column_get_type(column);
06617 
06618 
06619     if (column == 0x0)
06620         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06621 
06622     if (indx < 0 || indx >= length)
06623         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06624 
06625     if (type != CPL_TYPE_DOUBLE)
06626         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06627 
06628     column->values->d[indx] = value;
06629     xxx_column_unset_null(column, indx);
06630 
06631     return CPL_ERROR_NONE;
06632 
06633 }
06634 
06635 
06636 /* 
06637  * @brief
06638  *   Write a character string to a string column element.
06639  *
06640  * @param column  Column to be accessed.
06641  * @param indx    Position where to write character string.
06642  * @param string  Character string to write.
06643  *
06644  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06645  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06646  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em indx is
06647  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned.
06648  *   If the input column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06649  *   is always returned.
06650  *
06651  * Copy a character string to a @em string column element. The written 
06652  * value can also be a @c NULL pointer. Note that the input character 
06653  * string is copied, therefore the original can be modified without 
06654  * affecting the column content. To "plug" a character string directly 
06655  * into a column element, use the function @c xxx_column_get_data_string(). 
06656  * Column elements are counted starting from zero.
06657  */
06658 
06659 cpl_error_code xxx_column_set_string(xxx_column *column, 
06660                                      int indx, const char *string)
06661 {
06662 
06663     const char *fid    = "xxx_column_set_string";
06664     int          length = xxx_column_get_size(column);
06665     cpl_type     type   = xxx_column_get_type(column);
06666 
06667 
06668     if (column == 0x0)
06669         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06670 
06671     if (indx < 0 || indx >= length)
06672         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06673 
06674     if (type != CPL_TYPE_STRING)
06675         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06676 
06677     if (column->values->s[indx])
06678         cpl_free(column->values->s[indx]);
06679 
06680     if (string)
06681         column->values->s[indx] = cpl_strdup((char *)string);
06682     else
06683         column->values->s[indx] = NULL;
06684 
06685     return CPL_ERROR_NONE;
06686 
06687 }
06688 
06689 
06690 /*
06691  * @brief
06692  *   Write an array to an array column element.
06693  *
06694  * @param column  Column to be accessed.
06695  * @param indx    Position where to write array.
06696  * @param array   CPL array to write.
06697  *
06698  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL 
06699  *   pointer a @c CPL_ERROR_NULL_INPUT is returned. If the column 
06700  *   does not match the type of the input @em array, or if the column 
06701  *   is not made of arrays, a @c CPL_ERROR_TYPE_MISMATCH is returned. 
06702  *   If the input @em array size is different from the column depth, 
06703  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned. If @em indx is 
06704  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is 
06705  *   returned.
06706  *
06707  * Copy a CPL array to an array column element. The written value 
06708  * can also be a @c NULL pointer. Note that the input array
06709  * is copied, therefore the original can be modified without
06710  * affecting the column content. To "plug" an array directly
06711  * into a column element, use the function @c xxx_column_get_data_array().
06712  * Column elements are counted starting from zero.
06713  */
06714 
06715 cpl_error_code xxx_column_set_array(xxx_column *column,
06716                                     int indx, const cpl_array *array)
06717 {
06718 
06719     const char *fid    = "xxx_column_set_array";
06720     int          length = xxx_column_get_size(column);
06721     cpl_type     type   = xxx_column_get_type(column);
06722     cpl_type     atype;
06723 
06724 
06725     if (column == 0x0)
06726         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06727 
06728     if (indx < 0 || indx >= length)
06729         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06730 
06731     if (!(type & CPL_TYPE_POINTER))
06732         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06733 
06734     if (array) {
06735         atype = cpl_array_get_type(array);
06736         if (type != (atype | CPL_TYPE_POINTER))
06737             return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06738         if (xxx_column_get_depth(column) != cpl_array_get_size(array))
06739             return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
06740     }
06741 
06742     if (column->values->array[indx])
06743         cpl_array_delete(column->values->array[indx]);
06744 
06745     if (array)
06746         column->values->array[indx] = cpl_array_duplicate((cpl_array *)array);
06747     else
06748         column->values->array[indx] = NULL;
06749 
06750     return CPL_ERROR_NONE;
06751 
06752 }
06753 
06754 
06755 /* 
06756  * @brief
06757  *   Set a column element to NULL;
06758  *
06759  * @param column  Column to be accessed.
06760  * @param indx    Position where to write a NULL.
06761  *
06762  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06763  *   a @c CPL_ERROR_NULL_INPUT is returned. If @em indx is outside the 
06764  *   column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set. If the input 
06765  *   column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set.
06766  *
06767  * In the case of a string or array column, the string or array is set free 
06768  * and its pointer is set to @c NULL; for other data types, the corresponding
06769  * element of the null flags buffer is flagged. Column elements are counted 
06770  * starting from zero.
06771  */
06772 
06773 cpl_error_code xxx_column_set_invalid(xxx_column *column, int indx)
06774 {
06775 
06776     const char *fid    = "xxx_column_set_invalid";
06777     int          length = xxx_column_get_size(column);
06778     cpl_type     type   = xxx_column_get_type(column);
06779 
06780 
06781     if (column == 0x0)
06782         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06783 
06784     if (indx < 0 || indx >= length)
06785         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06786 
06787 
06788     if (type == CPL_TYPE_STRING) {
06789         if (column->values->s[indx]) {
06790             cpl_free(column->values->s[indx]);
06791             column->values->s[indx] = NULL;
06792         }
06793         return CPL_ERROR_NONE;
06794     }
06795 
06796     if (type & CPL_TYPE_POINTER) {
06797         if (column->values->array[indx]) {
06798             cpl_array_delete(column->values->array[indx]);
06799             column->values->array[indx] = NULL;
06800         }
06801         return CPL_ERROR_NONE;
06802     }
06803 
06804     if (column->nullcount == column->length)
06805         return CPL_ERROR_NONE;
06806 
06807     if (!column->null)
06808         column->null = cpl_calloc(column->length, sizeof(xxx_column_flag));
06809 
06810     if (column->null[indx] == 0) {
06811 
06812         column->null[indx] = 1;
06813         column->nullcount++;
06814 
06815         if (column->nullcount == column->length) {
06816             if (column->null)
06817                 cpl_free(column->null);
06818             column->null = NULL;
06819         }
06820 
06821     }
06822 
06823     return CPL_ERROR_NONE;
06824 
06825 }
06826 
06827 
06828 /*
06829  * @brief
06830  *   Write the same a value within a numerical column segment.
06831  *
06832  * @param column  Column to be accessed.
06833  * @param start   Position where to begin write value.
06834  * @param count   Number of values to write.
06835  * @param value   Value to write.
06836  *
06837  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06838  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of numerical
06839  *   type, a @c CPL_ERROR_INVALID_TYPE is returned. If @em start is outside
06840  *   the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If
06841  *   the input column has length zero, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06842  *   is always returned.
06843  *
06844  * Write the same value to a numerical column segment. The value is cast to
06845  * the accessed column type. The written values are automatically flagged as
06846  * valid. To invalidate a column interval use @c xxx_column_fill_invalid().
06847  */
06848 
06849 cpl_error_code xxx_column_fill(xxx_column *column, 
06850                                int start, int count, double value)
06851 {
06852 
06853     const char *fid  = "xxx_column_fill";
06854     cpl_type     type = xxx_column_get_type(column);
06855 
06856 
06857     switch (type) {
06858     case CPL_TYPE_INT:
06859         return xxx_column_fill_int(column, start, count, value);
06860     case CPL_TYPE_FLOAT:
06861         return xxx_column_fill_float(column, start, count, value);
06862     case CPL_TYPE_DOUBLE:
06863         return xxx_column_fill_double(column, start, count, value);
06864     case CPL_TYPE_INT | CPL_TYPE_POINTER:
06865     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
06866     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
06867     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
06868     case CPL_TYPE_STRING:
06869         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
06870     default:
06871         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06872     }
06873 
06874 }
06875 
06876 
06877 /* 
06878  * @brief
06879  *   Write the same value within an @em integer column segment.
06880  *
06881  * @param column  Column to be accessed.
06882  * @param start   Position where to begin write value.
06883  * @param count   Number of values to write.
06884  * @param value   Value to write.
06885  *
06886  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06887  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06888  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start 
06889  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
06890  *   is returned. If the input column has length zero, the error 
06891  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
06892  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
06893  *
06894  * Write the same value to an @em integer column segment. The written 
06895  * values are automatically flagged as valid. To invalidate a column 
06896  * interval use @c xxx_column_fill_invalid(). The @em count argument
06897  * can go beyond the column end, and in that case the specified @em value
06898  * will be written just up to the end of the column. If @em count is zero,
06899  * the column is not modified and no error is set.
06900  */
06901 
06902 cpl_error_code xxx_column_fill_int(xxx_column *column, 
06903                                    int start, int count, int value)
06904 {
06905 
06906     const char *fid    = "xxx_column_fill_int";
06907     int          length = xxx_column_get_size(column);
06908     cpl_type     type   = xxx_column_get_type(column);
06909     int         *ip;
06910 
06911 
06912     if (column == 0x0)
06913         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06914 
06915     if (start < 0 || start >= length)
06916         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06917 
06918     if (count < 0)
06919         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
06920 
06921     if (type != CPL_TYPE_INT)
06922         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06923 
06924     if (count == 0)
06925         return CPL_ERROR_NONE;
06926 
06927     if (count > length - start)
06928         count = length - start;
06929 
06930     xxx_column_unset_null_segment(column, start, count);
06931 
06932     ip = column->values->i + start;
06933 
06934     while (count--)
06935         *ip++ = value;
06936 
06937     return CPL_ERROR_NONE;
06938 
06939 }
06940 
06941 
06942 /* 
06943  * @brief
06944  *   Write a value to a @em float column segment.
06945  *
06946  * @param column  Column to be accessed.
06947  * @param start   Position where to begin write value.
06948  * @param count   Number of values to write.
06949  * @param value   Value to write.
06950  *
06951  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06952  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06953  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
06954  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06955  *   is returned. If the input column has length zero, the error
06956  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
06957  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
06958  *
06959  * Write the same value to a @em float column segment. The written
06960  * values are automatically flagged as valid. To invalidate a column
06961  * interval use @c xxx_column_fill_invalid(). The @em count argument
06962  * can go beyond the column end, and in that case the specified @em value
06963  * will be written just up to the end of the column. If @em count is zero,
06964  * the column is not modified and no error is set.
06965  */
06966 
06967 cpl_error_code xxx_column_fill_float(xxx_column *column, int start, 
06968                                      int count, float value)
06969 {
06970 
06971     const char *fid    = "xxx_column_fill_float";
06972     int          length = xxx_column_get_size(column);
06973     cpl_type     type   = xxx_column_get_type(column);
06974     float       *fp;
06975 
06976 
06977     if (column == 0x0)
06978         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06979 
06980     if (start < 0 || start >= length)
06981         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06982 
06983     if (count < 0)
06984         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
06985 
06986     if (type != CPL_TYPE_FLOAT)
06987         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06988 
06989     if (count == 0)
06990         return CPL_ERROR_NONE;
06991 
06992     if (count > length - start)
06993         count = length - start;
06994 
06995     xxx_column_unset_null_segment(column, start, count);
06996 
06997     fp = column->values->f + start;
06998 
06999     while (count--)
07000         *fp++ = value;
07001 
07002     return CPL_ERROR_NONE;
07003 
07004 }
07005 
07006 
07007 /* 
07008  * @brief
07009  *   Write a value to a @em double column segment.
07010  *
07011  * @param column  Column to be accessed.
07012  * @param start   Position where to begin write value.
07013  * @param count   Number of values to write.
07014  * @param value   Value to write.
07015  *
07016  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07017  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07018  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07019  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07020  *   is returned. If the input column has length zero, the error
07021  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07022  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07023  *
07024  * Write the same value to a @em double column segment. The written
07025  * values are automatically flagged as valid. To invalidate a column
07026  * interval use @c xxx_column_fill_invalid(). The @em count argument
07027  * can go beyond the column end, and in that case the specified @em value
07028  * will be written just up to the end of the column. If @em count is zero,
07029  * the column is not modified and no error is set.
07030  */
07031 
07032 cpl_error_code xxx_column_fill_double(xxx_column *column, int start, 
07033                                       int count, double value)
07034 {
07035 
07036     const char *fid    = "xxx_column_fill_double";
07037     int          length = xxx_column_get_size(column);
07038     cpl_type     type   = xxx_column_get_type(column);
07039     double      *dp;
07040 
07041 
07042     if (column == 0x0)
07043         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07044 
07045     if (start < 0 || start >= length)
07046         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07047 
07048     if (count < 0)
07049         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07050 
07051     if (type != CPL_TYPE_DOUBLE)
07052         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07053 
07054     if (count == 0)
07055         return CPL_ERROR_NONE;
07056 
07057     if (count > length - start)
07058         count = length - start;
07059 
07060     xxx_column_unset_null_segment(column, start, count);
07061 
07062     dp = column->values->d + start;
07063 
07064     while (count--)
07065         *dp++ = value;
07066 
07067     return CPL_ERROR_NONE;
07068 
07069 }
07070 
07071 
07072 /* 
07073  * @brief
07074  *   Write a string to a string column segment.
07075  *
07076  * @param column  Column to be accessed.
07077  * @param start   Position where to begin write value.
07078  * @param count   Number of values to write.
07079  * @param value   Value to write.
07080  *
07081  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07082  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07083  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07084  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07085  *   is returned. If the input column has length zero, the error
07086  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07087  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07088  *
07089  * Copy the same string to a string column segment. If the input string 
07090  * is not a @c NULL pointer, it is duplicated for each accessed column 
07091  * element. If the input string is @c NULL, this call is equivalent to 
07092  * @c xxx_column_fill_invalid(). The @em count argument can go beyond 
07093  * the column end, and in that case the specified @em value will be 
07094  * copied just up to the end of the column. If @em count is zero,
07095  * the column is not modified and no error is set.
07096  */
07097 
07098 cpl_error_code xxx_column_fill_string(xxx_column *column, int start,
07099                                       int count, const char *value)
07100 {
07101 
07102     const char *fid    = "xxx_column_fill_string";
07103     int          length = xxx_column_get_size(column);
07104     cpl_type     type   = xxx_column_get_type(column);
07105     char       **sp;
07106 
07107 
07108     if (column == 0x0)
07109         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07110 
07111     if (start < 0 || start >= length)
07112         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07113 
07114     if (count < 0)
07115         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07116 
07117     if (type != CPL_TYPE_STRING)
07118         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07119 
07120     if (count == 0)
07121         return CPL_ERROR_NONE;
07122 
07123     if (count > length - start)
07124         count = length - start;
07125 
07126     if (value == NULL)
07127         return xxx_column_fill_invalid(column, start, count);
07128 
07129     sp = column->values->s + start;
07130     while (count--) {
07131         if (*sp)
07132             cpl_free(*sp);
07133         *sp++ = cpl_strdup((char *)value);
07134     }
07135 
07136     return CPL_ERROR_NONE;
07137 
07138 }
07139 
07140 
07141 /*
07142  * @brief
07143  *   Write the same array to an array column segment.
07144  *   
07145  * @param column  Column to be accessed.
07146  * @param start   Position where to begin write value.
07147  * @param count   Number of values to write.
07148  * @param array   Array to write.
07149  * 
07150  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL
07151  *   pointer a @c CPL_ERROR_NULL_INPUT is returned. If the column
07152  *   does not match the type of the input @em array, or if the column
07153  *   is not made of arrays, a @c CPL_ERROR_TYPE_MISMATCH is returned.
07154  *   If the input @em array size is different from the column depth,
07155  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned. If @em start
07156  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
07157  *   is returned. If the input column has length zero, the error
07158  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07159  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07160  *   
07161  * Copy the same array to an array column segment. If the input array
07162  * is not a @c NULL pointer, it is duplicated for each accessed column 
07163  * element. If the input array is @c NULL, this call is equivalent to
07164  * @c xxx_column_fill_invalid(). The @em count argument can go beyond 
07165  * the column end, and in that case the specified @em value will be 
07166  * copied just up to the end of the column. If @em count is zero,
07167  * the column is not modified and no error is set. 
07168  */
07169 
07170 cpl_error_code xxx_column_fill_array(xxx_column *column, int start,
07171                                      int count, const cpl_array *array)
07172 {
07173 
07174     const char *fid    = "xxx_column_fill_array";
07175     int          length = xxx_column_get_size(column);
07176     cpl_type     type   = xxx_column_get_type(column);
07177     cpl_type     atype;
07178     cpl_array  **ap;
07179     
07180 
07181     if (column == 0x0)
07182         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07183 
07184     if (start < 0 || start >= length)
07185         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07186 
07187     if (count < 0)
07188         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07189 
07190     if (!(type & CPL_TYPE_POINTER))
07191         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07192 
07193     if (array) {
07194         atype = cpl_array_get_type(array);
07195         if (type != (atype | CPL_TYPE_POINTER))
07196             return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07197         if (xxx_column_get_depth(column) != cpl_array_get_size(array))
07198             return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
07199     }
07200 
07201     if (count == 0)
07202         return CPL_ERROR_NONE;
07203 
07204     if (count > length - start)
07205         count = length - start;
07206 
07207     if (array == NULL)
07208         return xxx_column_fill_invalid(column, start, count);
07209 
07210     ap = column->values->array + start;
07211     while (count--) {
07212         if (*ap)
07213             cpl_array_delete(*ap);
07214         *ap++ = cpl_array_duplicate(array);
07215     }
07216 
07217     return CPL_ERROR_NONE;
07218 
07219 }
07220 
07221 
07222 /*
07223  * @brief
07224  *   Set a column segment to NULL.
07225  *
07226  * @param column  Column to be accessed.
07227  * @param start   Position where to start writing NULLs.
07228  * @param count   Number of column elements to set to NULL.
07229  *
07230  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07231  *   a @c CPL_ERROR_NULL_INPUT is returned. If @em start is outside the 
07232  *   column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If the 
07233  *   input column has length zero, the error @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
07234  *   is always returned. If @em count is negative, a @c CPL_ERROR_ILLEGAL_INPUT 
07235  *   is returned.
07236  *
07237  * Invalidate values contained in a column segment. The @em count argument 
07238  * can go beyond the column end, and in that case the values will be
07239  * invalidated up to the end of the column. If @em count is zero, the 
07240  * column is not modified and no error is set. In the case of a @em string 
07241  * or @em array column, the invalidated strings or arrays are set free and 
07242  * their pointers are set to @c NULL; for other data types, the corresponding 
07243  * elements are flagged as invalid.
07244  */
07245 
07246 cpl_error_code xxx_column_fill_invalid(xxx_column *column, int start, int count)
07247 {
07248 
07249     const char *fid    = "xxx_column_fill_invalid";
07250     cpl_type     type   = xxx_column_get_type(column);
07251     int          length = xxx_column_get_size(column);
07252     int          c;
07253     int         *np;
07254     char       **sp;
07255     cpl_array  **ap;
07256 
07257 
07258     if (column == 0x0)
07259         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07260 
07261     if (start < 0 || start >= length)
07262         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07263 
07264     if (count < 0) 
07265         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07266 
07267     if (count == 0)
07268         return CPL_ERROR_NONE;
07269 
07270     if (count > length - start)
07271         count = length - start;
07272 
07273     if (count == length) {
07274         if (type != CPL_TYPE_STRING && !(type & CPL_TYPE_POINTER)) {
07275             if (column->null)
07276                 cpl_free(column->null);
07277             column->null = NULL;
07278             column->nullcount = length;
07279             return CPL_ERROR_NONE;
07280         }
07281     }
07282 
07283     c = count;
07284 
07285     if (type == CPL_TYPE_STRING) {
07286 
07287         sp = column->values->s + start;
07288 
07289         while (c--) {
07290             if (*sp)
07291                 cpl_free(*sp);
07292             sp++;
07293         }
07294 
07295         memset(column->values->s + start, 0, count * sizeof(char *));
07296 
07297         return CPL_ERROR_NONE;
07298     }
07299 
07300     if (type & CPL_TYPE_POINTER) {
07301  
07302         ap = column->values->array + start;
07303  
07304         while (c--) { 
07305             if (*ap)
07306                 cpl_array_delete(*ap);
07307             ap++;
07308         }
07309 
07310         memset(column->values->array + start, 0, count * sizeof(cpl_array *));
07311 
07312         return CPL_ERROR_NONE;
07313     }
07314 
07315     if (column->nullcount == length)
07316         return CPL_ERROR_NONE;
07317 
07318     if (!column->null)
07319         column->null = cpl_calloc(length, sizeof(xxx_column_flag));
07320 
07321     np = column->null + start;
07322 
07323     if (column->nullcount == 0) {
07324         column->nullcount = count;
07325         while (c--)
07326             *np++ = 1;
07327     }
07328     else {
07329         while (c--) {
07330             if (*np == 0) {
07331                 *np = 1;
07332                 column->nullcount++;
07333             }
07334             np++;
07335         }
07336 
07337         if (column->nullcount == length) {
07338             if (column->null)
07339                 cpl_free(column->null);
07340             column->null = NULL;
07341         }
07342     }
07343 
07344     return CPL_ERROR_NONE;
07345     
07346 }
07347 
07348 
07349 /*
07350  * @brief
07351  *   Copy an array of values to a numerical column segment.
07352  *
07353  * @param column  Column to be accessed.
07354  * @param start   Position where to begin write values.
07355  * @param count   Number of values to write.
07356  * @param values  Values to write.
07357  *
07358  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07359  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of numerical
07360  *   type, a @c CPL_ERROR_INVALID_TYPE is returned. If @em start is outside
07361  *   the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If
07362  *   the input column has length zero, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07363  *   is always returned. If @em count is not greater than zero, a 
07364  *   @c CPL_ERROR_ILLEGAL_INPUT is returned.
07365  *
07366  * Write the values to a numerical column segment. The values are cast to
07367  * the accessed column type. The written values are automatically flagged 
07368  * as valid. The @em count argument can go beyond the column end, and in 
07369  * that case values will be transferred just up to the end of the column.
07370  * This function doesn't apply to array column types.
07371  */
07372 
07373 cpl_error_code xxx_column_copy_segment(xxx_column *column, 
07374                                        int start, int count, double *values)
07375 {
07376 
07377     const char *fid    = "xxx_column_copy_segment";
07378     int          length = xxx_column_get_size(column);
07379     cpl_type     type   = xxx_column_get_type(column);
07380     int         *idata;
07381     float       *fdata;
07382 
07383 
07384     if (column == 0x0)
07385         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07386 
07387     if (start < 0 || start >= length)
07388         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07389 
07390     if (count <= 0)
07391         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07392 
07393     if (count > length - start)
07394         count = length - start;
07395 
07396     xxx_column_unset_null_segment(column, start, count);
07397 
07398     switch (type) {
07399     case CPL_TYPE_INT:
07400         idata = xxx_column_get_data_int(column);
07401         idata += start;
07402         while (count--)
07403             *idata++ = *values++;
07404         break;
07405     case CPL_TYPE_FLOAT:
07406         fdata = xxx_column_get_data_float(column);
07407         fdata += start;
07408         while (count--)
07409             *fdata++ = *values++;
07410         break;
07411     case CPL_TYPE_DOUBLE:
07412         memcpy(column->values->d + start, values, count * sizeof(double));
07413         break;
07414     default:
07415         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
07416     }
07417 
07418     return CPL_ERROR_NONE;
07419 
07420 }
07421 static double xxx_tools_get_median_9double(double * p)
07422 {
07423     cpl_ensure(p, CPL_ERROR_NULL_INPUT, 0.00) ;
07424 
07425     CPL_PIX_SORT(p[1], p[2]); CPL_PIX_SORT(p[4], p[5]); CPL_PIX_SORT(p[7],p[8]);
07426     CPL_PIX_SORT(p[0], p[1]); CPL_PIX_SORT(p[3], p[4]); CPL_PIX_SORT(p[6],p[7]);
07427     CPL_PIX_SORT(p[1], p[2]); CPL_PIX_SORT(p[4], p[5]); CPL_PIX_SORT(p[7],p[8]);
07428     CPL_PIX_SORT(p[0], p[3]); CPL_PIX_SORT(p[5], p[8]); CPL_PIX_SORT(p[4],p[7]);
07429     CPL_PIX_SORT(p[3], p[6]); CPL_PIX_SORT(p[1], p[4]); CPL_PIX_SORT(p[2],p[5]);
07430     CPL_PIX_SORT(p[4], p[7]); CPL_PIX_SORT(p[4], p[2]); CPL_PIX_SORT(p[6],p[4]);
07431     CPL_PIX_SORT(p[4], p[2]); return(p[4]) ;
07432 }
07433 static double xxx_tools_get_median_double(
07434         double  *   a,
07435         int         n)
07436 {
07437     if (n==9) return xxx_tools_get_median_9double(a) ;
07438     return xxx_tools_get_kth_double(a,n,(((n)&1)?((n)/2):(((n)/2)-1))) ;
07439 }
07440 
07441 
07442 /*----------------------------------------------------------------------------*/
07450 /*----------------------------------------------------------------------------*/
07451 static float xxx_tools_get_median_float(
07452         float   *   a,
07453         int         n)
07454 {
07455     return xxx_tools_get_kth_float(a,n,(((n)&1)?((n)/2):(((n)/2)-1))) ;
07456 }
07457 
07458 /*----------------------------------------------------------------------------*/
07466 /*----------------------------------------------------------------------------*/
07467 static int xxx_tools_get_median_int(
07468         int     *   a,
07469         int         n)
07470 {
07471     return xxx_tools_get_kth_int(a,n,(((n)&1)?((n)/2):(((n)/2)-1))) ;
07472 }
07473 
07474 static double xxx_tools_ipow(double x, int y)
07475 {
07476 
07477     double result;
07478     double pow2 = x;
07479     int p = abs(y);
07480 
07481     /* Compute the result as a product of powers of 2 of x.
07482        - this method may produce (slightly) different results than pow(x,y) */
07483 
07484     /* Handle least significant bit in p here in order to avoid an unnecessary
07485        multiplication of pow2 - which could cause an over- or underflow */
07486     /* Also, 0^0 is 1, while any other power of 0 is 0 */
07487     result = p & 1 ? x : 1.0;
07488 
07489     while (p >>= 1) {
07490         pow2 *= pow2;
07491         /* Process least significant bit in p */
07492         if (p & 1) result *= pow2;
07493     }
07494 
07495     /* It is left to the caller to ensure that no division by zero occurs */
07496     return y < 0 ? 1.0/result : result;
07497 }
07498 
07499 
07500 /* 
07501  * @brief
07502  *   Copy a list of integer values to an @em integer column segment.
07503  *
07504  * @param column  Column to be accessed.
07505  * @param start   Position where to begin write values.
07506  * @param count   Number of values to write.
07507  * @param values  Values to write.
07508  *
07509  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07510  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the 
07511  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start 
07512  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
07513  *   is returned. If the input column has length zero, the 
07514  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count 
07515  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07516  *
07517  * Write a list of integer values to an @em integer column segment. 
07518  * The written values are automatically flagged as valid. The @em count 
07519  * argument can go beyond the column end, and in that case values will 
07520  * be transferred just up to the end of the column.
07521  */
07522 
07523 cpl_error_code xxx_column_copy_segment_int(xxx_column *column, 
07524                                            int start, int count, int *values)
07525 {
07526 
07527     const char *fid    = "xxx_column_copy_segment_int";
07528     int          length = xxx_column_get_size(column);
07529     cpl_type     type   = xxx_column_get_type(column);
07530 
07531 
07532     if (column == 0x0)
07533         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07534 
07535     if (start < 0 || start >= length)
07536         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07537 
07538     if (count <= 0)
07539         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07540 
07541     if (type != CPL_TYPE_INT)
07542         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07543 
07544     if (count > length - start)
07545         count = length - start;
07546 
07547     memcpy(column->values->i + start, values, count * sizeof(int));
07548 
07549     xxx_column_unset_null_segment(column, start, count);
07550 
07551     return CPL_ERROR_NONE;
07552 
07553 }
07554 
07555 
07556 /* 
07557  * @brief
07558  *   Copy a list of float values to a @em float column segment.
07559  *
07560  * @param column  Column to be accessed.
07561  * @param start   Position where to begin write values.
07562  * @param count   Number of values to write.
07563  * @param values  Values to write.
07564  *
07565  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07566  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07567  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07568  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07569  *   is returned. If the input column has length zero, the
07570  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07571  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07572  *
07573  * Write a list of float values to a @em float column segment.
07574  * The written values are automatically flagged as valid. The @em count 
07575  * argument can go beyond the column end, and in that case values will 
07576  * be transferred just up to the end of the column.
07577  */
07578 
07579 cpl_error_code xxx_column_copy_segment_float(xxx_column *column, int start,
07580                                              int count, float *values)
07581 {
07582 
07583     const char *fid    = "xxx_column_copy_segment_float";
07584     int          length = xxx_column_get_size(column);
07585     cpl_type     type   = xxx_column_get_type(column);
07586 
07587 
07588     if (column == 0x0)
07589         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07590 
07591     if (start < 0 || start >= length)
07592         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07593 
07594     if (count <= 0)
07595         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07596 
07597     if (type != CPL_TYPE_FLOAT)
07598         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07599 
07600     if (count > length - start)
07601         count = length - start;
07602 
07603     memcpy(column->values->f + start, values, count * sizeof(float));
07604 
07605     xxx_column_unset_null_segment(column, start, count);
07606 
07607     return CPL_ERROR_NONE;
07608 
07609 }
07610 
07611 
07612 /* 
07613  * @brief
07614  *   Copy a list of @em double values to a @em double column segment.
07615  *
07616  * @param column  Column to be accessed.
07617  * @param start   Position where to begin write values.
07618  * @param count   Number of values to write.
07619  * @param values  Values to write.
07620  *
07621  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07622  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07623  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07624  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07625  *   is returned. If the input column has length zero, the
07626  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07627  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07628  *
07629  * Write a list of double values to a @em double column segment.
07630  * The written values are automatically flagged as valid. The @em count 
07631  * argument can go beyond the column end, and in that case values will 
07632  * be transferred just up to the end of the column.
07633  */
07634 
07635 cpl_error_code xxx_column_copy_segment_double(xxx_column *column, int start,
07636                                               int count, double *values)
07637 {
07638 
07639     const char *fid    = "xxx_column_copy_segment_double";
07640     int          length = xxx_column_get_size(column);
07641     cpl_type     type   = xxx_column_get_type(column);
07642 
07643 
07644     if (column == 0x0)
07645         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07646 
07647     if (start < 0 || start >= length)
07648         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07649 
07650     if (count <= 0)
07651         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07652 
07653     if (type != CPL_TYPE_DOUBLE)
07654         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07655 
07656     if (count > length - start)
07657         count = length - start;
07658 
07659     memcpy(column->values->d + start, values, count * sizeof(double));
07660  
07661     xxx_column_unset_null_segment(column, start, count);
07662  
07663     return CPL_ERROR_NONE;
07664 
07665 }
07666 
07667 
07668 /* 
07669  * @brief
07670  *   Copy a list of strings to a @em string column segment.
07671  *
07672  * @param column  Column to be accessed.
07673  * @param start   Position where to begin write strings.
07674  * @param count   Number of strings to write.
07675  * @param strings Strings to write.
07676  *
07677  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07678  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07679  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07680  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07681  *   is returned. If the input column has length zero, the
07682  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07683  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07684  *
07685  * Write a list of strings to a @em string column segment. The written 
07686  * values are automatically flagged as valid. The input strings are
07687  * duplicated before being assigned to the corresponding column elements.
07688  * The @em count argument can go beyond the column end, and in that case 
07689  * values will be transferred just up to the end of the column.
07690  */
07691 
07692 cpl_error_code xxx_column_copy_segment_string(xxx_column *column, int start,
07693                                               int count, char **strings)
07694 {
07695 
07696     const char *fid    = "xxx_column_copy_segment_string";
07697     cpl_type     type   = xxx_column_get_type(column);
07698     int          length = xxx_column_get_size(column);
07699     int          i;
07700     char       **sp;
07701 
07702 
07703     if (column == 0x0)
07704         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07705 
07706     if (start < 0 || start >= length)
07707         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07708 
07709     if (count <= 0)
07710         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07711 
07712     if (type != CPL_TYPE_STRING)
07713         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07714 
07715     if (count > length - start)
07716         count = length - start;
07717 
07718     sp = column->values->s + start;
07719 
07720     if (strings) {
07721         for (i = 0; i < count; i++) {
07722             if (*sp)
07723                 cpl_free(*sp);
07724             if (*strings)
07725                 *sp++ = cpl_strdup(*strings++);
07726             else
07727                 *sp++ = NULL;
07728         }
07729     }
07730     else {
07731         for (i = 0; i < count; i++) {
07732             if (*sp)
07733                 cpl_free(*sp);
07734             *sp++ = NULL;
07735         }
07736     }
07737 
07738     return CPL_ERROR_NONE;
07739 
07740 }
07741 
07742 
07743 /*
07744  * @brief
07745  *   Copy a list of CPL arrays to an @em array column segment.
07746  *
07747  * @param column  Column to be accessed.
07748  * @param start   Position where to begin write strings.
07749  * @param count   Number of strings to write.
07750  * @param arrays  Arrays to write.
07751  *
07752  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL 
07753  *   pointer a @c CPL_ERROR_NULL_INPUT is returned. If the column
07754  *   does not match the type of any of the input arrays, or if the column
07755  *   is not made of arrays, a @c CPL_ERROR_TYPE_MISMATCH is returned.
07756  *   If the size of any of the input arrays is different from the column 
07757  *   depth a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned. If @em start
07758  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07759  *   is returned. If the input column has length zero, the
07760  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07761  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07762  *
07763  * Write a list of arrays to an @em array column segment. The written
07764  * values are automatically flagged as valid. The input arrays are
07765  * duplicated before being assigned to the corresponding column elements.
07766  * The @em count argument can go beyond the column end, and in that case
07767  * values will be transferred just up to the end of the column.
07768  */
07769 
07770 cpl_error_code xxx_column_copy_segment_array(xxx_column *column, int start,
07771                                              int count, cpl_array **arrays)
07772 {
07773 
07774     const char *fid    = "xxx_column_copy_segment_array";
07775     cpl_type     type   = xxx_column_get_type(column);
07776     cpl_type     atype;
07777     int          length = xxx_column_get_size(column);
07778     int          i;
07779     cpl_array  **ap;
07780     cpl_array  **keep;
07781     
07782 
07783     if (column == 0x0)
07784         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07785 
07786     if (start < 0 || start >= length)
07787         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07788 
07789     if (count <= 0)
07790         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07791 
07792     if (!(type & CPL_TYPE_POINTER))
07793         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07794 
07795     if (count > length - start)
07796         count = length - start;
07797 
07798     ap = column->values->array + start;
07799 
07800     if (arrays) {
07801 
07802         /*
07803          * Check the compatibility of all the input arrays first
07804          */
07805 
07806         keep = arrays;
07807 
07808         for (i = 0; i < count; i++) {
07809             if (*arrays) {
07810                 atype = cpl_array_get_type(*arrays);
07811                 if (type != (atype | CPL_TYPE_POINTER))
07812                     return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07813                 if (xxx_column_get_depth(column) != cpl_array_get_size(*arrays))
07814                     return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
07815                 arrays++;
07816             }
07817         }
07818 
07819         arrays = keep;
07820 
07821         for (i = 0; i < count; i++) {
07822             if (*ap)
07823                 cpl_array_delete(*ap);
07824             if (*arrays)
07825                 *ap++ = cpl_array_duplicate(*arrays++);
07826             else
07827                 *ap++ = NULL;
07828         }
07829     }
07830     else {
07831         for (i = 0; i < count; i++) {
07832             if (*ap)
07833                 cpl_array_delete(*ap);
07834             *ap++ = NULL;
07835         }
07836     }
07837 
07838     return CPL_ERROR_NONE;
07839 
07840 }
07841 
07842 /*************** TODO ******************/
07843 /*  
07844  * @brief
07845  *   Copy a segment of a column into another column.
07846  *
07847  * @param to_column   Column to be modified.
07848  * @param to_start    Position where to begin write values.
07849  * @param from_column Source column.
07850  * @param from_start  Position where to begin copy values.
07851  * @param count       Number of values to copy.
07852  *
07853  * @return 0 on success.
07854  *
07855  * Both columns must be of the same type.
07856  */
07857 
07858 /*************** TODO ******************
07859 
07860 cpl_error_code xxx_column_extract_from_column(xxx_column *to_column, 
07861                                               size_t to_start,
07862                                               xxx_column *from_column, 
07863                                               size_t from_start, 
07864                                               size_t count)
07865 {
07866 
07867     size_t   i           = 0;
07868     size_t   nullcount   = 0;
07869     size_t   to_length   = xxx_column_get_size(to_column);
07870     size_t   from_length = xxx_column_get_size(from_column);
07871     cpl_type to_type     = xxx_column_get_type(to_column);
07872     cpl_type from_type   = xxx_column_get_type(from_column);
07873 
07874 
07875     assert(to_column != 0x0);
07876     assert(from_column != 0x0);
07877 
07878 
07879     if (to_type != from_type)
07880         return 1;
07881 
07882     if (to_start > to_length || from_start > from_length)
07883         return 1;
07884 
07885     if (to_start + count > to_length || from_start + count > from_length)
07886         return 1;
07887 
07888     if (from_column->nullcount == from_length)
07889         return xxx_column_fill_invalid(to_column, to_start, count);
07890 
07891     if (from_column->nullcount) {
07892         while (i < count) {
07893             nullcount += from_column->null[from_start + i];
07894             i++;
07895         }
07896     }
07897 
07898     if (nullcount == count)
07899         return xxx_column_fill_invalid(to_column, to_start, count);
07900 
07901     if (nullcount) {
07902         if (to_column->nullcount == to_length) {
07903             to_column->null = cpl_malloc(to_length * sizeof(xxx_column_flag));
07904         }
07905     }
07906 
07907     switch (to_type) {
07908 
07909     case CPL_TYPE_INT:
07910         memcpy(to_column->values->i + to_start, 
07911                from_column->values->i + from_start, count * sizeof(int));
07912     case CPL_TYPE_FLOAT:
07913     case CPL_TYPE_DOUBLE:
07914     case CPL_TYPE_STRING:
07915     default:
07916 
07917     }
07918 
07919     if (start < length) {
07920 
07921         if (count > length - start)
07922             count = length - start;
07923 
07924         if (type == CPL_TYPE_INT) {
07925 
07926             memcpy(column->values->i + start, 
07927                    values, count * sizeof(int));
07928 
07929             return xxx_column_unset_null_segment(column, start, count);
07930 
07931         }
07932     }
07933 
07934 }
07935 
07936 **********************************/
07937 
07938 
07939 /* 
07940  * @brief
07941  *   Delete a column segment.
07942  *
07943  * @param column  Column to be accessed.
07944  * @param start   Position of first column element to delete.
07945  * @param count   Number of column elements to delete.
07946  *
07947  * @return @c CPL_ERROR_NONE on success. If @em start is outside the 
07948  *   column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If the 
07949  *   input column has length zero, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is
07950  *   always returned. If @em count is negative, a @c CPL_ERROR_ILLEGAL_INPUT 
07951  *   is returned.
07952  *
07953  * Delete a column segment. This is different from invalidating a column 
07954  * segment, as done by @c xxx_column_fill_invalid(): here a portion of 
07955  * the data is physically removed, and the column data buffer shortened 
07956  * proportionally. The pointer to data may change (therefore pointers 
07957  * previously retrieved by calling @c xxx_column_get_data_int(), 
07958  * @c xxx_column_get_data_string(), etc., should be discarded). The 
07959  * specified segment can go beyond the end of the column, and even all 
07960  * of the column data elements can be removed.
07961  */
07962 
07963 cpl_error_code xxx_column_erase_segment(xxx_column *column, 
07964                                         int start, int count)
07965 {
07966 
07967     const char     *fid        = "xxx_column_erase_segment";
07968     cpl_type         type       = xxx_column_get_type(column);
07969     int              old_length = xxx_column_get_size(column);
07970     int              new_length;
07971     int              end;
07972     int              i;
07973     int              j;
07974     cpl_array      **ap1;
07975     cpl_array      **ap2;
07976     char           **sp1;
07977     char           **sp2;
07978     int             *ip1;
07979     int             *ip2;
07980     float           *fp1;
07981     float           *fp2;
07982     double          *dp1;
07983     double          *dp2;
07984 
07985 
07986     if (column == 0x0)
07987         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07988 
07989     if (start < 0 || start >= old_length)
07990         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07991 
07992     if (count < 0)
07993         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07994 
07995     if (count == 0)
07996         return CPL_ERROR_NONE;
07997 
07998     if (count > old_length - start)
07999         count = old_length - start;
08000 
08001     new_length = old_length - count; 
08002     end = start + count;
08003 
08004     if (end == old_length)
08005         return xxx_column_set_size(column, start);
08006 
08007     if (type == CPL_TYPE_STRING) {
08008 
08009         /*
08010          *  If a column of character strings is shortened, we must
08011          *  free explicitly the extra strings.
08012          */
08013 
08014         sp1 = column->values->s + start;
08015 
08016         for (i = start; i < end; i++, sp1++)
08017             if (*sp1)
08018                 cpl_free(*sp1);
08019     }
08020 
08021     if (type & CPL_TYPE_POINTER) {
08022 
08023         /*
08024          *  If a column of arrays is shortened, we must
08025          *  free explicitly the extra arrays.
08026          */
08027 
08028         ap1 = column->values->array + start;
08029 
08030         for (i = start; i < end; i++, ap1++)
08031             if (*ap1)
08032                 cpl_array_delete(*ap1);
08033     }
08034 
08035 
08036     /*
08037      *  Cut the slice from the invalid flags buffer, if present, 
08038      *  counting how many invalid elements will be lost.
08039      */
08040 
08041     if (column->null) {
08042 
08043         i = start;
08044         while (i < end) {
08045             if (column->null[i])
08046                 column->nullcount--;
08047             i++;
08048         }
08049 
08050         if (column->nullcount == 0 || column->nullcount == new_length) {
08051 
08052             /*
08053              *  Since either no invalid or just invalid elements are left, 
08054              *  the invalid flag buffer can be released.
08055              */
08056 
08057             if (column->null)
08058                 cpl_free(column->null);
08059             column->null = NULL;
08060 
08061         }
08062         else {
08063 
08064             /*
08065              *  Shift up NULL flags that are after the slice.
08066              */
08067 
08068             i = start;
08069             j = end;
08070             while (j < old_length) {
08071                 column->null[i] = column->null[j];
08072                 i++;
08073                 j++;
08074             }
08075 
08076             /*
08077              *  Get rid of extra memory.
08078              */
08079 
08080             column->null = cpl_realloc(column->null,
08081                            new_length * sizeof(xxx_column_flag));
08082 
08083         }
08084     }
08085     else {
08086 
08087         /*
08088          *  There is no invalid flag buffer, so either there are no 
08089          *  invalid elements or there are just invalid elements. If 
08090          *  there are no invalid elements, nullcount stays zero. If 
08091          *  there are just invalid elements, nullcount must be set 
08092          *  to the new column length.
08093          */
08094 
08095         if (column->nullcount == old_length)
08096             column->nullcount = new_length;
08097 
08098     }
08099 
08100 
08101     /*
08102      *  Now take care of data values
08103      */
08104 
08105     if ((type == CPL_TYPE_STRING) || (type & CPL_TYPE_POINTER))
08106         column->nullcount = 0;
08107 
08108     if (column->nullcount != new_length) {
08109 
08110         /*
08111          *  Column has not just invalid elements. In this case we have to
08112          *  shift also the data to fill the gap.
08113          */
08114 
08115         ip1 = column->values->i + start;
08116         ip2 = column->values->i + end;
08117         fp1 = column->values->f + start;
08118         fp2 = column->values->f + end;
08119         dp1 = column->values->d + start;
08120         dp2 = column->values->d + end;
08121         sp1 = column->values->s + start;
08122         sp2 = column->values->s + end;
08123         ap1 = column->values->array + start;
08124         ap2 = column->values->array + end;
08125 
08126         switch (type) {
08127         case CPL_TYPE_INT:
08128             for (j = end; j < old_length; j++)
08129                 *ip1++ = *ip2++;
08130             break;
08131         case CPL_TYPE_FLOAT:
08132             for (j = end; j < old_length; j++)
08133                 *fp1++ = *fp2++;
08134             break;
08135         case CPL_TYPE_DOUBLE:
08136             for (j = end; j < old_length; j++)
08137                 *dp1++ = *dp2++;
08138             break;
08139         case CPL_TYPE_STRING:
08140             for (j = end; j < old_length; j++)
08141                 *sp1++ = *sp2++;
08142             break;
08143         default:     /* Array columns */
08144             for (j = end; j < old_length; j++)
08145                 *ap1++ = *ap2++;
08146             break;
08147         }
08148 
08149     }
08150 
08151 
08152     /*
08153      *  Finally, reallocate the data buffer.
08154      */
08155 
08156     column->values->i = cpl_realloc(column->values->i,
08157                         new_length * xxx_column_type_size(type));
08158 
08159     column->length = new_length;
08160 
08161     return 0;
08162 
08163 }
08164 
08165 
08166 
08167 /*
08168  * @brief
08169  *   Insert a segment into column data.
08170  *
08171  * @param column  Column to be accessed.
08172  * @param start   Column element where to insert the segment.
08173  * @param count   Length of segment.
08174  *
08175  * @return @c CPL_ERROR_NONE on success. If @em start is negative,
08176  *   a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If @em count 
08177  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
08178  *
08179  * Insert a segment of new values in the column data buffer. The
08180  * new segment consists of a sequence of invalid (not initialised)
08181  * column elements. This is different from invalidating a column data 
08182  * segment, as done by @c xxx_column_fill_invalid(): here a portion 
08183  * of new data is physically inserted, and the column data buffer 
08184  * is made proportionally longer. Setting @em start to a number 
08185  * not less than the column length is legal, and has the effect of 
08186  * appending at the end of the column as many invalid elements as 
08187  * specified by the @em count argument (this is equivalent to expanding 
08188  * a column using @c xxx_column_set_size() ). The input @em column may
08189  * also have zero length. The pointer to data may change, therefore 
08190  * pointers previously retrieved by calling @c xxx_column_get_data_int(), 
08191  * @c xxx_column_get_data_string(), etc., should be discarded.
08192  */
08193 
08194 cpl_error_code xxx_column_insert_segment(xxx_column *column, 
08195                                          int start, int count)
08196 {
08197 
08198     const char *fid        = "xxx_column_insert_segment";
08199     cpl_type     type       = xxx_column_get_type(column);
08200     int          old_length = xxx_column_get_size(column);
08201     int          new_length = old_length + count;
08202     int          i;
08203     cpl_array  **ap1;
08204     cpl_array  **ap2;
08205     char       **sp1;
08206     char       **sp2;
08207     int         *ip1;
08208     int         *ip2;
08209     float       *fp1;
08210     float       *fp2;
08211     double      *dp1;
08212     double      *dp2;
08213     int         *np1;
08214     int         *np2;
08215 
08216 
08217     if (column == 0x0)
08218         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
08219 
08220     if (start < 0)
08221         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
08222 
08223     if (count < 0)
08224         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
08225 
08226     if (count == 0)
08227         return CPL_ERROR_NONE;
08228 
08229     if (xxx_column_set_size(column, new_length)) {
08230         cpl_error_set_where(fid);
08231         return cpl_error_get_code();
08232     }
08233 
08234     if (start > old_length)
08235         return CPL_ERROR_NONE;
08236 
08237     ip1 = column->values->i + new_length;
08238     ip2 = column->values->i + old_length;
08239     fp1 = column->values->f + new_length;
08240     fp2 = column->values->f + old_length;
08241     dp1 = column->values->d + new_length;
08242     dp2 = column->values->d + old_length;
08243     sp1 = column->values->s + new_length;
08244     sp2 = column->values->s + old_length;
08245     ap1 = column->values->array + new_length;
08246     ap2 = column->values->array + old_length;
08247 
08248     switch (type) {
08249     case CPL_TYPE_INT:
08250         for (i = old_length; i > start; i--) {
08251             *--ip1 = *--ip2;
08252             *ip2 = 0;
08253         }
08254         break;
08255 
08256     case CPL_TYPE_FLOAT:
08257         for (i = old_length; i > start; i--) {
08258             *--fp1 = *--fp2;
08259             *fp2 = 0.0;
08260         }
08261         break;
08262 
08263     case CPL_TYPE_DOUBLE:
08264         for (i = old_length; i > start; i--) {
08265             *--dp1 = *--dp2;
08266             *dp2 = 0.0;
08267         }
08268         break;
08269 
08270     case CPL_TYPE_STRING:
08271         for (i = old_length; i > start; i--) {
08272             *--sp1 = *--sp2;
08273             *sp2 = 0x0;
08274         }
08275         break;
08276 
08277     default:                   /* Array columns */
08278         for (i = old_length; i > start; i--) {
08279             *--ap1 = *--ap2;
08280             *ap2 = 0x0;
08281         }
08282         break;
08283     }
08284 
08285 
08286     /*
08287      *  Handling the invalid flags it's simple: all the hard work
08288      *  was actually done by xxx_column_set_size(). If the invalid
08289      *  flags buffer exists, we have just to shift the flags to
08290      *  the proper place.
08291      */
08292 
08293     if (column->null) {
08294 
08295         np1 = column->null + new_length;
08296         np2 = column->null + old_length;
08297 
08298         for (i = old_length; i > start; i--) {
08299             *--np1 = *--np2;
08300             *np2 = 1;
08301         }
08302 
08303     }
08304 
08305     return CPL_ERROR_NONE;
08306 
08307 }
08308 
08309 
08310 /*
08311  * @brief
08312  *   Make a copy of a column.
08313  *
08314  * @param column  Column to be duplicated.
08315  *
08316  * @return Pointer to the new column, or @c NULL in case of error.
08317  *
08318  * If the input @em column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT
08319  * is returned. Copy is "in depth": in the case of a @em string column, 
08320  * also the string elements are duplicated.
08321  */
08322 
08323 xxx_column *xxx_column_duplicate(xxx_column *column)
08324 {
08325 
08326     const char *fid        = "xxx_column_duplicate";
08327     cpl_type     type       = xxx_column_get_type(column);
08328     int          length     = xxx_column_get_size(column);
08329     int          depth      = xxx_column_get_depth(column);
08330     xxx_column  *new_column = NULL;
08331 
08332 
08333     if (column == 0x0) {
08334         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
08335         return NULL;
08336     }
08337 
08338     switch (type) {
08339     case CPL_TYPE_INT:
08340         new_column = xxx_column_new_int(length);
08341         break;
08342     case CPL_TYPE_FLOAT:
08343         new_column = xxx_column_new_float(length);
08344         break;
08345     case CPL_TYPE_DOUBLE:
08346         new_column = xxx_column_new_double(length);
08347         break;
08348     case CPL_TYPE_STRING:
08349         new_column = xxx_column_new_string(length);
08350         break;
08351     case CPL_TYPE_INT | CPL_TYPE_POINTER:
08352     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
08353     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
08354     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
08355         new_column = xxx_column_new_array(type, length, depth);
08356         break;
08357     default:
08358         cpl_error_set(fid, CPL_ERROR_UNSPECIFIED);
08359         return NULL;
08360     }
08361 
08362     xxx_column_set_name(new_column, xxx_column_get_name(column));
08363     xxx_column_set_unit(new_column, xxx_column_get_unit(column));
08364     xxx_column_set_format(new_column, xxx_column_get_format(column));
08365 
08366     if (length == 0)
08367         return new_column;
08368 
08369     if (type == CPL_TYPE_STRING) {
08370         while (length--) {
08371             if (column->values->s[length]) {
08372                 new_column->values->s[length] = 
08373                                    cpl_strdup(column->values->s[length]);
08374             }
08375             else {
08376                 new_column->values->s[length] = NULL;
08377             }
08378         }
08379         return new_column;
08380     }
08381 
08382     if (type & CPL_TYPE_POINTER) {
08383         while (length--) {
08384             if (column->values->array[length]) {
08385                 new_column->values->array[length] =
08386                     cpl_array_duplicate(column->values->array[length]);
08387             }
08388             else {
08389                 new_column->values->array[length] = NULL;
08390             }
08391         }
08392 
08393         if (column->dimensions)
08394             new_column->dimensions = cpl_array_duplicate(column->dimensions);
08395 
08396         return new_column;
08397     }
08398 
08399     memcpy(new_column->values->i, column->values->i, 
08400            length * xxx_column_type_size(type));
08401 
08402     new_column->nullcount = column->nullcount;
08403 
08404     if (column->null) {
08405         new_column->null = cpl_malloc(length * sizeof(xxx_column_flag));
08406         memcpy(new_column->null, column->null, 
08407                length * sizeof(xxx_column_flag));
08408     }
08409 
08410     return new_column;
08411 
08412 }
08413 
08414 
08415 /*
08416  * @brief
08417  *   Cast a numerical column to a new @em integer column.
08418  *
08419  * @param column  Column to be cast.
08420  *
08421  * @return Pointer to the new columnm, or @em NULL in case of error.
08422  *
08423  * If the accessed column is of type either string or array of strings, 
08424  * a @c CPL_ERROR_INVALID_TYPE is set. If the input is a @c NULL pointer, 
08425  * a @c CPL_ERROR_NULL_INPUT is set. The output column is nameless, 
08426  * and with the default format for its type (see function 
08427  * @c xxx_column_set_format() ). However, if the input column is 
08428  * also @em integer, a simple copy is made and the column format 
08429  * is inherited. The input column units are always preserved in the
08430  * output column. Note that a column of arrays is always cast to 
08431  * another column of @em integer arrays. It is not allowed to cast 
08432  * a column of arrays into a column of plain integers.
08433  */
08434 
08435 
08436 
08437 /*
08438  * @brief
08439  *   Cast a numeric column to a new @em float column.
08440  *
08441  * @param column  Column to be cast.
08442  *
08443  * @return Pointer to the new columnm, or @em NULL in case of error. 
08444  *
08445  * If the accessed column is of type either string or array of strings,
08446  * a @c CPL_ERROR_INVALID_TYPE is set. If the input is a @c NULL 
08447  * pointer, a @c CPL_ERROR_NULL_INPUT is set. The output column is 
08448  * nameless, and with the default format for its type (see function
08449  * @c xxx_column_set_format() ). However, if the input column is
08450  * also @em float, a simple copy is made and the column format
08451  * is inherited. The input column units are always preserved in the
08452  * output column. Note that a column of arrays is always cast to
08453  * another column of @em float arrays. It is not allowed to cast
08454  * a column of arrays into a column of plain floats.
08455  */
08456 
08457 
08458 
08459 /* 
08460  * @brief
08461  *   Create a column from an interval of another column.
08462  *
08463  * @param column  Input column.
08464  * @param start   First element to be copied to new column.
08465  * @param count   Number of elements to be copied.
08466  *
08467  * @return Pointer to the new column, or @c NULL in case of error.
08468  *
08469  * If the input column is @c NULL, @c CPL_ERROR_NULL_INPUT is set. If 
08470  * @em start is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
08471  * is set. If the input column has length zero, this error is always 
08472  * set. If @em count is negative, a @c CPL_ERROR_ILLEGAL_INPUT is set. 
08473  * If @em count is zero, a zero-length column is created. 
08474  * If @em start + @em count goes beyond the end of the input column, 
08475  * elements are always copied up to the end. The new column is nameless, 
08476  * but it inherits the unit and the format of the source column. Existing 
08477  * invalid element flags are also transferred to the new column.
08478  */
08479 
08480 xxx_column *xxx_column_extract(xxx_column *column, int start, int count)
08481 {
08482 
08483     const char *fid        = "xxx_column_extract";
08484     xxx_column  *new_column = NULL;
08485     cpl_type     type       = xxx_column_get_type(column);
08486     int          length     = xxx_column_get_size(column);
08487     int          depth      = xxx_column_get_depth(column);
08488     int          byte_count;
08489     int          i;
08490     int          j;
08491 
08492 
08493     if (column == 0x0) {
08494         cpl_error_set_where(fid);
08495         return NULL;
08496     }
08497 
08498     if (start < 0 || start >= length) {
08499         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
08500         return NULL;
08501     }
08502 
08503     if (count < 0) {
08504         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
08505         return NULL;
08506     }
08507 
08508     if (count > length - start)
08509         count = length - start;
08510 
08511     byte_count  = count * xxx_column_type_size(type);
08512 
08513     switch (type) {
08514 
08515     case CPL_TYPE_INT:
08516         new_column = xxx_column_new_int(count);
08517         if (count)
08518             memcpy(new_column->values->i, 
08519                    column->values->i + start, byte_count);
08520         break;
08521 
08522     case CPL_TYPE_FLOAT:
08523         new_column = xxx_column_new_float(count);
08524         if (count)
08525             memcpy(new_column->values->f, 
08526                    column->values->f + start, byte_count);
08527         break;
08528 
08529     case CPL_TYPE_DOUBLE:
08530         new_column = xxx_column_new_double(count);
08531         if (count)
08532             memcpy(new_column->values->d, 
08533                    column->values->d + start, byte_count);
08534         break;
08535 
08536     case CPL_TYPE_STRING:
08537         new_column = xxx_column_new_string(count);
08538         for (i = 0, j = start; i < count; i++, j++)
08539             if (column->values->s[j])
08540                 new_column->values->s[i] = cpl_strdup(column->values->s[j]);
08541             else
08542                 new_column->values->s[i] = NULL;
08543         break;
08544 
08545     case CPL_TYPE_INT | CPL_TYPE_POINTER:
08546     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
08547     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
08548     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
08549 
08550         new_column = xxx_column_new_array(type, count, depth);
08551         for (i = 0, j = start; i < count; i++, j++) {
08552             if (column->values->array[j])
08553                 new_column->values->array[i] = 
08554                       cpl_array_duplicate(column->values->array[j]);
08555             else
08556                 new_column->values->array[i] = NULL;
08557         }
08558 
08559         if (column->dimensions)
08560             new_column->dimensions = cpl_array_duplicate(column->dimensions);
08561 
08562         break;
08563 
08564     default:
08565         cpl_error_set(fid, CPL_ERROR_UNSPECIFIED);
08566         return NULL;
08567         break;
08568     }
08569 
08570     xxx_column_set_unit(new_column, xxx_column_get_unit(column));
08571     xxx_column_set_format(new_column, xxx_column_get_format(column));
08572 
08573     if (column->null) {
08574 
08575         /*
08576          *  If an invalid flags buffer exists in the original column,
08577          *  we have to take care of the (possible) duplication of
08578          *  the appropriate segment.
08579          */
08580 
08581         new_column->nullcount = 0;
08582         for (i = 0, j = start; i < count; i++, j++)
08583             if (column->null[j])
08584                 new_column->nullcount++;
08585 
08586         if (new_column->nullcount != 0 && 
08587             new_column->nullcount != count) {
08588             new_column->null = cpl_calloc(count, sizeof(xxx_column_flag));
08589             for (i = 0, j = start; i < count; i++, j++)
08590                 if (column->null[j])
08591                     new_column->null[i] = 1;
08592         }
08593 
08594     }
08595     else {
08596 
08597       /* 
08598        *  An invalid flag buffer doesn't exist in the original column,
08599        *  and this means no invalid elements, or all elements are invalid, 
08600        *  also for the subcolumn.
08601        */
08602 
08603       if (column->nullcount == 0)
08604           new_column->nullcount = 0;
08605       else
08606           new_column->nullcount = xxx_column_get_size(new_column);
08607           
08608     }
08609 
08610     return new_column;
08611 
08612 }
08613 
08614   
08615 /*
08616  * @brief
08617  *   Insert a column into another column of the same type.
08618  *
08619  * @param target_column Target column.
08620  * @param insert_column Column to be inserted in target column.
08621  * @param position      Position of target where to insert.
08622  *
08623  * @return @c CPL_ERROR_NONE on success. If any input column is a @c NULL 
08624  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the columns are 
08625  *   not of the same type, a @c CPL_ERROR_TYPE_MISMATCH is returned.
08626  *   If @em position is negative, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
08627  *   is returned.
08628  *
08629  * The first element of the column to be inserted will be at the 
08630  * specified @em position. If the specified @em position is not 
08631  * less than the target column length, the second column will be 
08632  * appended to the target column. The output column is expanded 
08633  * to host the values copied from the input column, that is left 
08634  * untouched. In the @em target column the pointer to target data 
08635  * may change, therefore pointers previously retrieved by calling 
08636  * @c xxx_column_get_data_int(), @c xxx_column_get_data_string(), 
08637  * etc., should be discarded). Information about columns dimensions 
08638  * (in case of array columns) is ignored.
08639  */
08640 
08641 cpl_error_code xxx_column_merge(xxx_column *target_column, 
08642                                 xxx_column *insert_column, int position)
08643 {
08644 
08645     const char *fid      = "xxx_column_merge";
08646     int          t_length = xxx_column_get_size(target_column);
08647     int          i_length = xxx_column_get_size(insert_column);
08648     cpl_type     t_type   = xxx_column_get_type(target_column);
08649     cpl_type     i_type   = xxx_column_get_type(insert_column);
08650     int          i_size   = i_length * xxx_column_type_size(i_type);
08651     int          i;
08652     int          j;
08653 
08654 
08655     if (target_column == 0x0 || insert_column == 0x0)
08656         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
08657 
08658     if (position < 0) 
08659         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
08660 
08661     if (t_type != i_type)
08662         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
08663 
08664     if (i_length == 0)
08665         return CPL_ERROR_NONE;
08666 
08667     if (position > t_length)
08668         position = t_length;
08669 
08670 
08671     /*
08672      *  First of all, a segment of invalid elements is inserted at the
08673      *  right position.
08674      */
08675 
08676     xxx_column_insert_segment(target_column, position, i_length);
08677 
08678 
08679     /*
08680      *  If the column to be inserted just consists of invalid elements, 
08681      *  the job is already completed.
08682      */
08683 
08684     if (xxx_column_count_invalid(insert_column) == i_length)
08685         return CPL_ERROR_NONE;
08686 
08687 
08688     /*
08689      *  Transferring the data from the column to be inserted,
08690      *  to the expanded part of the target column:
08691      */
08692 
08693     t_length = xxx_column_get_size(target_column);     /* It got longer */
08694 
08695     switch (i_type) {
08696 
08697     case CPL_TYPE_INT:
08698         memcpy(target_column->values->i + position, 
08699                insert_column->values->i, i_size);
08700         break;
08701 
08702     case CPL_TYPE_FLOAT:
08703         memcpy(target_column->values->f + position, 
08704                insert_column->values->f, i_size);
08705         break;
08706 
08707     case CPL_TYPE_DOUBLE:
08708         memcpy(target_column->values->d + position, 
08709                insert_column->values->d, i_size);
08710         break;
08711 
08712     case CPL_TYPE_STRING:
08713         for (i = 0, j = position; i < i_length; i++, j++)
08714             if (insert_column->values->s[i])
08715                 target_column->values->s[j] = 
08716                                        cpl_strdup(insert_column->values->s[i]);
08717         break;
08718 
08719     case CPL_TYPE_INT | CPL_TYPE_POINTER:
08720     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
08721     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
08722     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
08723         for (i = 0, j = position; i < i_length; i++, j++)
08724             if (insert_column->values->array[i])
08725                 target_column->values->array[j] =
08726                     cpl_array_duplicate(insert_column->values->array[i]);
08727         break;
08728 
08729     default:
08730         return cpl_error_set(fid, CPL_ERROR_UNSPECIFIED);
08731 
08732     }
08733 
08734     if ((i_type == CPL_TYPE_STRING) || (i_type & CPL_TYPE_POINTER))
08735         return CPL_ERROR_NONE;
08736 
08737 
08738     /*
08739      *  Now also the null flags buffer must be upgraded.
08740      */
08741 
08742     if (target_column->null) {
08743 
08744         if (insert_column->null) {
08745 
08746             /*
08747              *  Both null flags buffers exist. The expanded part of
08748              *  the target column already consists of invalid elements, 
08749              *  so just overwrite valid elements from the first column:
08750              */
08751 
08752             for (i = 0, j = position; i < i_length; i++, j++) {
08753                 if (!insert_column->null[i]) {
08754                     target_column->null[j] = 0;
08755                     target_column->nullcount--;
08756                 } 
08757             } 
08758         }
08759         else {
08760 
08761 
08762             /*
08763              *  Just the target column has the invalid flag buffer. This
08764              *  means necessarily that the column to insert has no invalid
08765              *  elements (the other possibility, that the column to insert
08766              *  just consists of invalid elements, was already handled at
08767              *  the beginning). Then we must turn all the invalid elements
08768              *  of the target expanded interval of the null flag buffer 
08769              *  into valid.
08770              */
08771 
08772             if (target_column->nullcount > i_length) {
08773 
08774 
08775                 /*
08776                  *  Surely target_column->nullcount is at least i_length,
08777                  *  i.e., the number of invalid elements added by the
08778                  *  expansion. If target_column->nullcount is equal to 
08779                  *  i_length, then these are the only invalid elements 
08780                  *  existing, and they would be all unset, therefore it 
08781                  *  would be enough to free the null flags buffer skipping 
08782                  *  this loop.
08783                  */
08784 
08785                 for (i = 0, j = position; i < i_length; i++, j++)
08786                     target_column->null[j] = 0;
08787             }
08788 
08789             target_column->nullcount -= i_length;
08790 
08791         }
08792     }
08793     else {
08794 
08795         /*
08796          *  The target column invalid flags buffer doesn't exist. 
08797          *  Excluding the case of array or string columns, this is
08798          *  necessarily because it just contains invalid elements, 
08799          *  since to expand it means just to add extra invalid elements. 
08800          *  The inserted column instead has some valid elements, that 
08801          *  must be transferred - therefore the target column invalid 
08802          *  flag buffer must be allocated.
08803          */
08804 
08805         target_column->null = cpl_malloc(t_length * sizeof(xxx_column_flag));
08806 
08807         i = t_length;
08808         while (i--)
08809             target_column->null[i] = 1;
08810 
08811         if (insert_column->null) {
08812 
08813            /*
08814             *  Some invalid elements:
08815             */
08816 
08817             for (i = 0, j = position; i < i_length; i++, j++) {
08818                 if (!insert_column->null[i]) {
08819                     target_column->null[j] = 0;
08820                     target_column->nullcount--;
08821                 }
08822             }
08823 
08824         }
08825         else {
08826 
08827             /*
08828              *  No invalid elements:
08829              */
08830 
08831             for (i = 0, j = position; i < i_length; i++, j++)
08832                 target_column->null[j] = 0;
08833 
08834             target_column->nullcount -= i_length;
08835         }
08836     }
08837 
08838 
08839     /*
08840      *  If no invalid elements are left, free the invalid flags buffer
08841      */
08842 
08843     if (target_column->nullcount == 0) {
08844         if (target_column->null)
08845             cpl_free(target_column->null);
08846         target_column->null = NULL;
08847     }
08848 
08849     return 0;
08850 
08851 }
08852 
08853 
08854 /*
08855  * @brief
08856  *   Add two numerical columns.
08857  *
08858  * @param to_column   Target column.
08859  * @param from_column Column to be summed to target column.
08860  * 
08861  * @return @c CPL_ERROR_NONE on success. If any of the input columns
08862  *   is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If 
08863  *   any of the input columns is of type string, a @c CPL_ERROR_INVALID_TYPE
08864  *   is returned. If the input columns do not have the same length, 
08865  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned. 
08866  *
08867  * The result of the sum is stored in the target colum. The type of the
08868  * columns may differ, and in that case the operation would be performed 
08869  * according to the C upcasting rules, with a final cast of the result to
08870  * the target column type. Invalid elements are propagated consistently: 
08871  * if either or both members of the sum are invalid, the result will be
08872  * invalid too. Underflows and overflows are ignored. This function is
08873  * not applicable to array columns.
08874  */
08875 
08876 cpl_error_code xxx_column_add(xxx_column *to_column, xxx_column *from_column)
08877 {
08878 
08879     const char *fid         = "xxx_column_add";
08880     int          i;
08881     int          to_length   = xxx_column_get_size(to_column);
08882     int          from_length = xxx_column_get_size(from_column);
08883     cpl_type     to_type     = xxx_column_get_type(to_column);
08884     cpl_type     from_type   = xxx_column_get_type(from_column);
08885 
08886     int         *fip;
08887     float       *ffp;
08888     double      *fdp;
08889     int         *tip;
08890     float       *tfp;
08891     double      *tdp;
08892     int         *tnp;
08893 
08894 
08895     if (to_column == 0x0 || from_column == 0x0)
08896         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
08897 
08898     if ((to_type == CPL_TYPE_STRING) || (from_type == CPL_TYPE_STRING) ||
08899         (to_type & CPL_TYPE_POINTER) || (from_type & CPL_TYPE_POINTER))
08900         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
08901 
08902     if (to_length != from_length)
08903         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
08904 
08905     if (to_length == 0)
08906         return CPL_ERROR_NONE;
08907 
08908     if (to_column->nullcount == to_length)
08909         return CPL_ERROR_NONE;
08910 
08911     if (from_column->nullcount == from_length)
08912         return xxx_column_fill_invalid(to_column, 0, to_length);
08913 
08914 
08915     fip = from_column->values->i;
08916     ffp = from_column->values->f;
08917     fdp = from_column->values->d;
08918     tip = to_column->values->i;
08919     tfp = to_column->values->f;
08920     tdp = to_column->values->d;
08921 
08922     if (to_column->nullcount == 0 && from_column->nullcount == 0) {
08923 
08924         /*
08925          * If there are no invalid elements in both columns, the operation 
08926          * can be performed without any check:
08927          */
08928 
08929         switch (to_type) {
08930 
08931         case CPL_TYPE_INT:
08932 
08933             switch (from_type) {
08934 
08935             case CPL_TYPE_INT:
08936                 while (to_length--)
08937                     *tip++ += *fip++;
08938                 break;
08939 
08940             case CPL_TYPE_FLOAT:
08941                 while (to_length--)
08942                     *tip++ += *ffp++;
08943                 break;
08944 
08945             case CPL_TYPE_DOUBLE:
08946                 while (to_length--)
08947                     *tip++ += *fdp++;
08948                 break;
08949 
08950             default:
08951                 break;
08952             }
08953             break;
08954 
08955         case CPL_TYPE_FLOAT:
08956 
08957             switch (from_type) {
08958 
08959             case CPL_TYPE_INT:
08960                 while (to_length--)
08961                     *tfp++ += (double)*fip++;
08962                 break;
08963 
08964             case CPL_TYPE_FLOAT:
08965                 while (to_length--)
08966                     *tfp++ += (double)*ffp++;
08967                 break;
08968 
08969             case CPL_TYPE_DOUBLE:
08970                 while (to_length--)
08971                     *tfp++ += *fdp++;
08972                 break;
08973             
08974             default:
08975                 break;
08976             }
08977             break;
08978 
08979         case CPL_TYPE_DOUBLE:
08980 
08981             switch (from_type) {
08982 
08983             case CPL_TYPE_INT:
08984                 while (to_length--)
08985                     *tdp++ += *fip++;
08986                 break;
08987 
08988             case CPL_TYPE_FLOAT:
08989                 while (to_length--)
08990                     *tdp++ += *ffp++;
08991                 break;
08992 
08993             case CPL_TYPE_DOUBLE:
08994                 while (to_length--)
08995                     *tdp++ += *fdp++;
08996                 break;
08997             
08998             default:
08999                 break;
09000             }
09001             break;
09002 
09003         default:
09004             break;
09005         }
09006     }
09007     else {
09008 
09009         /*
09010          * Here there are some invalid elements, so the operation needs to be
09011          * performed with some checks. As a first thing, take care of the
09012          * invalid elements in the target column:
09013          */
09014 
09015         if (to_column->nullcount == 0 || from_column->nullcount == 0) {
09016 
09017             /*
09018              * Here there are some invalid elements in just one of the two 
09019              * columns. If they are just in the column to add, an identical 
09020              * invalid flags buffer must be created for the target column.
09021              */
09022 
09023             if (from_column->nullcount) {
09024                 to_column->null = cpl_calloc(to_length, 
09025                                              sizeof(xxx_column_flag));
09026 
09027                 i = to_length;
09028                 while (i--)
09029                     if (from_column->null[i])
09030                         to_column->null[i] = 1;
09031 
09032                 to_column->nullcount = from_column->nullcount;
09033 
09034             }
09035         }
09036         else {
09037 
09038             /*
09039              *  Here there are some invalid elements in both columns.
09040              */
09041 
09042             i = to_length;
09043             while (i--) {
09044                 if (from_column->null[i]) {
09045                     if (!to_column->null[i]) {
09046                         to_column->null[i] = 1;
09047                         to_column->nullcount++;
09048                     }
09049                 }
09050             }
09051 
09052             if (to_column->nullcount == to_length) {
09053 
09054                 /*
09055                  * Just invalid elements in the result: no need to perform 
09056                  * any further operation, and the invalid flag buffer of the 
09057                  * target column can be disabled.
09058                  */
09059 
09060                 if (to_column->null)
09061                     cpl_free(to_column->null);
09062                 to_column->null = NULL;
09063                 return 0;
09064             }
09065 
09066         }
09067 
09068         /*
09069          * The operation can be performed while checking the already
09070          * computed result invalid flags buffer of the target column.
09071          */
09072 
09073         tnp = to_column->null;
09074 
09075         switch (to_type) {
09076 
09077         case CPL_TYPE_INT:
09078 
09079             switch (from_type) {
09080 
09081             case CPL_TYPE_INT:
09082                 while (to_length--) {
09083                     if (*tnp++ == 0)
09084                         *tip += *fip;
09085                     tip++;
09086                     fip++;
09087                 }
09088                 break;
09089 
09090             case CPL_TYPE_FLOAT:
09091                 while (to_length--) {
09092                     if (*tnp++ == 0)
09093                         *tip += *ffp;
09094                     tip++;
09095                     ffp++;
09096                 }
09097                 break;
09098 
09099             case CPL_TYPE_DOUBLE:
09100                 while (to_length--) {
09101                     if (*tnp++ == 0)
09102                         *tip += *fdp;
09103                     tip++;
09104                     fdp++;
09105                 }
09106                 break;
09107 
09108             default:
09109                 break;
09110             }
09111             break;
09112 
09113         case CPL_TYPE_FLOAT:
09114 
09115             switch (from_type) {
09116 
09117             case CPL_TYPE_INT:
09118                 while (to_length--) {
09119                     if (*tnp++ == 0)
09120                         *tfp += (double)*fip;
09121                     tfp++;
09122                     fip++;
09123                 }
09124                 break;
09125 
09126             case CPL_TYPE_FLOAT:
09127                 while (to_length--) {
09128                     if (*tnp++ == 0)
09129                         *tfp += (double)*ffp;
09130                     tfp++;
09131                     ffp++;
09132                 }
09133                 break;
09134 
09135             case CPL_TYPE_DOUBLE:
09136                 while (to_length--) {
09137                     if (*tnp++ == 0)
09138                         *tfp += *fdp;
09139                     tfp++;
09140                     fdp++;
09141                 }
09142                 break;
09143             
09144             default:
09145                 break;
09146             }
09147             break;
09148 
09149         case CPL_TYPE_DOUBLE:
09150 
09151             switch (from_type) {
09152 
09153             case CPL_TYPE_INT:
09154                 while (to_length--) {
09155                     if (*tnp++ == 0)
09156                         *tdp += *fip;
09157                     tdp++;
09158                     fip++;
09159                 }
09160                 break;
09161 
09162             case CPL_TYPE_FLOAT:
09163                 while (to_length--) {
09164                     if (*tnp++ == 0)
09165                         *tdp += *ffp;
09166                     tdp++;
09167                     ffp++;
09168                 }
09169                 break;
09170 
09171             case CPL_TYPE_DOUBLE:
09172                 while (to_length--) {
09173                     if (*tnp++ == 0)
09174                         *tdp += *fdp;
09175                     tdp++;
09176                     fdp++;
09177                 }
09178                 break;
09179             
09180             default:
09181                 break;
09182             }
09183             break;
09184 
09185         default:
09186             break;
09187         }
09188     }
09189 
09190     return CPL_ERROR_NONE;
09191 
09192 }
09193 
09194 
09195 /* 
09196  * @brief
09197  *   Subtract two numeric columns.
09198  *
09199  * @param to_column   Target column.
09200  * @param from_column Column to subtract from target column.
09201  *
09202  * @return @c CPL_ERROR_NONE on success. If any of the input columns
09203  *   is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If
09204  *   any of the input columns is of type string, a @c CPL_ERROR_INVALID_TYPE
09205  *   is returned. If the input columns do not have the same length,
09206  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned.
09207  *
09208  * The result of the subtraction is stored in the target colum. The type of 
09209  * the columns may differ, and in that case the operation would be performed 
09210  * according to the C upcasting rules, with a final cast of the result to
09211  * the target column type. Invalid elements are propagated consistently: 
09212  * if either or both members of the subtraction are invalid, the result 
09213  * will be invalid too. Underflows and overflows are ignored. This function
09214  * is not applicable to array columns.
09215  */
09216 
09217 cpl_error_code xxx_column_subtract(xxx_column *to_column, 
09218                                    xxx_column *from_column)
09219 {
09220 
09221     const char *fid         = "xxx_column_subtract";
09222     int          i;
09223     int          to_length   = xxx_column_get_size(to_column);
09224     int          from_length = xxx_column_get_size(from_column);
09225     cpl_type     to_type     = xxx_column_get_type(to_column);
09226     cpl_type     from_type   = xxx_column_get_type(from_column);
09227 
09228     int         *fip;
09229     float       *ffp;
09230     double      *fdp;
09231     int         *tip;
09232     float       *tfp;
09233     double      *tdp;
09234     int         *tnp;
09235 
09236 
09237     if (to_column == 0x0 || from_column == 0x0)
09238         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
09239 
09240     if ((to_type == CPL_TYPE_STRING) || (from_type == CPL_TYPE_STRING) ||
09241         (to_type & CPL_TYPE_POINTER) || (from_type & CPL_TYPE_POINTER))
09242         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
09243 
09244     if (to_length != from_length)
09245         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
09246 
09247     if (to_length == 0)
09248         return CPL_ERROR_NONE;
09249 
09250     if (to_column->nullcount == to_length)
09251         return CPL_ERROR_NONE;
09252 
09253     if (from_column->nullcount == from_length)
09254         return xxx_column_fill_invalid(to_column, 0, to_length);
09255 
09256 
09257     fip = from_column->values->i;
09258     ffp = from_column->values->f;
09259     fdp = from_column->values->d;
09260     tip = to_column->values->i;
09261     tfp = to_column->values->f;
09262     tdp = to_column->values->d;
09263 
09264     if (to_column->nullcount == 0 && from_column->nullcount == 0) {
09265 
09266         /*
09267          * If there are no invalid elements in both columns, the operation 
09268          * can be performed without any check:
09269          */
09270 
09271         switch (to_type) {
09272 
09273         case CPL_TYPE_INT:
09274 
09275             switch (from_type) {
09276 
09277             case CPL_TYPE_INT:
09278                 while (to_length--)
09279                     *tip++ -= *fip++;
09280                 break;
09281 
09282             case CPL_TYPE_FLOAT:
09283                 while (to_length--)
09284                     *tip++ -= *ffp++;
09285                 break;
09286 
09287             case CPL_TYPE_DOUBLE:
09288                 while (to_length--)
09289                     *tip++ -= *fdp++;
09290                 break;
09291 
09292             default:
09293                 break;
09294             }
09295             break;
09296 
09297         case CPL_TYPE_FLOAT:
09298 
09299             switch (from_type) {
09300 
09301             case CPL_TYPE_INT:
09302                 while (to_length--)
09303                     *tfp++ -= (double)*fip++;
09304                 break;
09305 
09306             case CPL_TYPE_FLOAT:
09307                 while (to_length--)
09308                     *tfp++ -= (double)*ffp++;
09309                 break;
09310 
09311             case CPL_TYPE_DOUBLE:
09312                 while (to_length--)
09313                     *tfp++ -= *fdp++;
09314                 break;
09315             
09316             default:
09317                 break;
09318             }
09319             break;
09320 
09321         case CPL_TYPE_DOUBLE:
09322 
09323             switch (from_type) {
09324 
09325             case CPL_TYPE_INT:
09326                 while (to_length--)
09327                     *tdp++ -= *fip++;
09328                 break;
09329 
09330             case CPL_TYPE_FLOAT:
09331                 while (to_length--)
09332                     *tdp++ -= *ffp++;
09333                 break;
09334 
09335             case CPL_TYPE_DOUBLE:
09336                 while (to_length--)
09337                     *tdp++ -= *fdp++;
09338                 break;
09339             
09340             default:
09341                 break;
09342             }
09343             break;
09344 
09345         default:
09346             break;
09347         }
09348     }
09349     else {
09350 
09351         /*
09352          * Here there are some invalid elements, so the operation needs to be
09353          * performed with some checks. As a first thing, take care of the
09354          * invalid elements in the target column:
09355          */
09356 
09357         if (to_column->nullcount == 0 || from_column->nullcount == 0) {
09358 
09359             /*
09360              * Here there are some invalids in just one of the two columns.
09361              * If they are just in the column to add, an identical invalid
09362              * flags buffer must be created for the target column.
09363              */
09364 
09365             if (from_column->nullcount) {
09366                 to_column->null = cpl_calloc(to_length, sizeof(xxx_column_flag));
09367 
09368                 i = to_length;
09369                 while (i--)
09370                     if (from_column->null[i])
09371                         to_column->null[i] = 1;
09372 
09373                 to_column->nullcount = from_column->nullcount;
09374 
09375             }
09376         }
09377         else {
09378 
09379             /*
09380              *  Here there are some invalids in both columns.
09381              */
09382 
09383             i = to_length;
09384             while (i--) {
09385                 if (from_column->null[i]) {
09386                     if (!to_column->null[i]) {
09387                         to_column->null[i] = 1;
09388                         to_column->nullcount++;
09389                     }
09390                 }
09391             }
09392 
09393             if (to_column->nullcount == to_length) {
09394 
09395                 /*
09396                  * Just invalids in the result: no need to perform any further
09397                  * operation, and the invalid buffer of the target column can
09398                  * be disabled.
09399                  */
09400 
09401                 if (to_column->null)
09402                     cpl_free(to_column->null);
09403                 to_column->null = NULL;
09404                 return 0;
09405             }
09406 
09407         }
09408 
09409         /*
09410          * The operation can be performed while checking the already
09411          * computed result invalid flags buffer of the target column.
09412          */
09413 
09414         tnp = to_column->null;
09415 
09416         switch (to_type) {
09417 
09418         case CPL_TYPE_INT:
09419 
09420             switch (from_type) {
09421 
09422             case CPL_TYPE_INT:
09423                 while (to_length--) {
09424                     if (*tnp++ == 0)
09425                         *tip -= *fip;
09426                     tip++;
09427                     fip++;
09428                 }
09429                 break;
09430 
09431             case CPL_TYPE_FLOAT:
09432                 while (to_length--) {
09433                     if (*tnp++ == 0)
09434                         *tip -= *ffp;
09435                     tip++;
09436                     ffp++;
09437                 }
09438                 break;
09439 
09440             case CPL_TYPE_DOUBLE:
09441                 while (to_length--) {
09442                     if (*tnp++ == 0)
09443                         *tip -= *fdp;
09444                     tip++;
09445                     fdp++;
09446                 }
09447                 break;
09448 
09449             default:
09450                 break;
09451             }
09452             break;
09453 
09454         case CPL_TYPE_FLOAT:
09455 
09456             switch (from_type) {
09457 
09458             case CPL_TYPE_INT:
09459                 while (to_length--) {
09460                     if (*tnp++ == 0)
09461                         *tfp -= (double)*fip;
09462                     tfp++;
09463                     fip++;
09464                 }
09465                 break;
09466 
09467             case CPL_TYPE_FLOAT:
09468                 while (to_length--) {
09469                     if (*tnp++ == 0)
09470                         *tfp -= (double)*ffp;
09471                     tfp++;
09472                     ffp++;
09473                 }
09474                 break;
09475 
09476             case CPL_TYPE_DOUBLE:
09477                 while (to_length--) {
09478                     if (*tnp++ == 0)
09479                         *tfp -= *fdp;
09480                     tfp++;
09481                     fdp++;
09482                 }
09483                 break;
09484             
09485             default:
09486                 break;
09487             }
09488             break;
09489 
09490         case CPL_TYPE_DOUBLE:
09491 
09492             switch (from_type) {
09493 
09494             case CPL_TYPE_INT:
09495                 while (to_length--) {
09496                     if (*tnp++ == 0)
09497                         *tdp -= *fip;
09498                     tdp++;
09499                     fip++;
09500                 }
09501                 break;
09502 
09503             case CPL_TYPE_FLOAT:
09504                 while (to_length--) {
09505                     if (*tnp++ == 0)
09506                         *tdp -= *ffp;
09507                     tdp++;
09508                     ffp++;
09509                 }
09510                 break;
09511 
09512             case CPL_TYPE_DOUBLE:
09513                 while (to_length--) {
09514                     if (*tnp++ == 0)
09515                         *tdp -= *fdp;
09516                     tdp++;
09517                     fdp++;
09518                 }
09519                 break;
09520             
09521             default:
09522                 break;
09523             }
09524             break;
09525 
09526         default:
09527             break;
09528         }
09529     }
09530 
09531     return CPL_ERROR_NONE;
09532 
09533 }
09534 
09535 
09536 /*
09537  * @brief
09538  *   Multiply two numeric columns.
09539  *
09540  * @param to_column   Target column.
09541  * @param from_column Multiplier column.
09542  *
09543  * @return @c CPL_ERROR_NONE on success. If any of the input columns
09544  *   is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If
09545  *   any of the input columns is of type string, a @c CPL_ERROR_INVALID_TYPE
09546  *   is returned. If the input columns do not have the same length,
09547  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned.
09548  *
09549  * The result of the multiplication is stored in the target colum. The type of
09550  * the columns may differ, and in that case the operation would be performed
09551  * according to the C upcasting rules, with a final cast of the result to
09552  * the target column type. Invalid elements are propagated consistently:
09553  * if either or both members of the multiplication are invalid, the result
09554  * will be invalid too. Underflows and overflows are ignored. This function
09555  * is not applicable to array columns.
09556  */
09557 
09558 cpl_error_code xxx_column_multiply(xxx_column *to_column, 
09559                                    xxx_column *from_column)
09560 {
09561 
09562     const char *fid         = "xxx_column_multiply";
09563     int          i;
09564     int          to_length   = xxx_column_get_size(to_column);
09565     int          from_length = xxx_column_get_size(from_column);
09566     cpl_type     to_type     = xxx_column_get_type(to_column);
09567     cpl_type     from_type   = xxx_column_get_type(from_column);
09568 
09569     int         *fip;
09570     float       *ffp;
09571     double      *fdp;
09572     int         *tip;
09573     float       *tfp;
09574     double      *tdp;
09575     int         *tnp;
09576 
09577 
09578     if (to_column == 0x0 || from_column == 0x0)
09579         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
09580 
09581     if ((to_type == CPL_TYPE_STRING) || (from_type == CPL_TYPE_STRING) ||
09582         (to_type & CPL_TYPE_POINTER) || (from_type & CPL_TYPE_POINTER))
09583         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
09584 
09585     if (to_length != from_length)
09586         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
09587 
09588     if (to_length == 0)
09589         return CPL_ERROR_NONE;
09590 
09591     if (to_column->nullcount == to_length)
09592         return CPL_ERROR_NONE;
09593 
09594     if (from_column->nullcount == from_length)
09595         return xxx_column_fill_invalid(to_column, 0, to_length);
09596 
09597 
09598     fip = from_column->values->i;
09599     ffp = from_column->values->f;
09600     fdp = from_column->values->d;
09601     tip = to_column->values->i;
09602     tfp = to_column->values->f;
09603     tdp = to_column->values->d;
09604 
09605     if (to_column->nullcount == 0 && from_column->nullcount == 0) {
09606 
09607         /*
09608          * If there are no invalids in both columns, the operation can
09609          * be performed without any check:
09610          */
09611 
09612         switch (to_type) {
09613 
09614         case CPL_TYPE_INT:
09615 
09616             switch (from_type) {
09617 
09618             case CPL_TYPE_INT:
09619                 while (to_length--)
09620                     *tip++ *= *fip++;
09621                 break;
09622 
09623             case CPL_TYPE_FLOAT:
09624                 while (to_length--)
09625                     *tip++ *= *ffp++;
09626                 break;
09627 
09628             case CPL_TYPE_DOUBLE:
09629                 while (to_length--)
09630                     *tip++ *= *fdp++;
09631                 break;
09632 
09633             default:
09634                 break;
09635             }
09636             break;
09637 
09638         case CPL_TYPE_FLOAT:
09639 
09640             switch (from_type) {
09641 
09642             case CPL_TYPE_INT:
09643                 while (to_length--)
09644                     *tfp++ *= (double)*fip++;
09645                 break;
09646 
09647             case CPL_TYPE_FLOAT:
09648                 while (to_length--)
09649                     *tfp++ *= (double)*ffp++;
09650                 break;
09651 
09652             case CPL_TYPE_DOUBLE:
09653                 while (to_length--)
09654                     *tfp++ *= *fdp++;
09655                 break;
09656             
09657             default:
09658                 break;
09659             }
09660             break;
09661 
09662         case CPL_TYPE_DOUBLE:
09663 
09664             switch (from_type) {
09665 
09666             case CPL_TYPE_INT:
09667                 while (to_length--)
09668                     *tdp++ *= *fip++;
09669                 break;
09670 
09671             case CPL_TYPE_FLOAT:
09672                 while (to_length--)
09673                     *tdp++ *= *ffp++;
09674                 break;
09675 
09676             case CPL_TYPE_DOUBLE:
09677                 while (to_length--)
09678                     *tdp++ *= *fdp++;
09679                 break;
09680             
09681             default:
09682                 break;
09683             }
09684             break;
09685 
09686         default:
09687             break;
09688         }
09689     }
09690     else {
09691 
09692         /*
09693          * Here there are some invalids around, so the operation needs to be
09694          * performed with some checks. As a first thing, take care of the
09695          * invalids pattern in the target column:
09696          */
09697 
09698         if (to_column->nullcount == 0 || from_column->nullcount == 0) {
09699 
09700             /*
09701              * Here there are some invalids in just one of the two columns.
09702              * If they are just in the column to add, an identical invalid
09703              * flags buffer must be created for the target column.
09704              */
09705 
09706             if (from_column->nullcount) {
09707                 to_column->null = cpl_calloc(to_length, sizeof(xxx_column_flag));
09708 
09709                 i = to_length;
09710                 while (i--)
09711                     if (from_column->null[i])
09712                         to_column->null[i] = 1;
09713 
09714                 to_column->nullcount = from_column->nullcount;
09715 
09716             }
09717         }
09718         else {
09719 
09720             /*
09721              *  Here there are some invalids in both columns.
09722              */
09723 
09724             i = to_length;
09725             while (i--) {
09726                 if (from_column->null[i]) {
09727                     if (!to_column->null[i]) {
09728                         to_column->null[i] = 1;
09729                         to_column->nullcount++;
09730                     }
09731                 }
09732             }
09733 
09734             if (to_column->nullcount == to_length) {
09735 
09736                 /*
09737                  * Just invalids in the result: no need to perform any further
09738                  * operation, and the invalid buffer of the target column can
09739                  * be disabled.
09740                  */
09741 
09742                 if (to_column->null)
09743                     cpl_free(to_column->null);
09744                 to_column->null = NULL;
09745                 return 0;
09746             }
09747 
09748         }
09749 
09750         /*
09751          * The operation can be performed while checking the already
09752          * computed result invalid flags buffer of the target column.
09753          */
09754 
09755         tnp = to_column->null;
09756 
09757         switch (to_type) {
09758 
09759         case CPL_TYPE_INT:
09760 
09761             switch (from_type) {
09762 
09763             case CPL_TYPE_INT:
09764                 while (to_length--) {
09765                     if (*tnp++ == 0)
09766                         *tip *= *fip;
09767                     tip++;
09768                     fip++;
09769                 }
09770                 break;
09771 
09772             case CPL_TYPE_FLOAT:
09773                 while (to_length--) {
09774                     if (*tnp++ == 0)
09775                         *tip *= *ffp;
09776                     tip++;
09777                     ffp++;
09778                 }
09779                 break;
09780 
09781             case CPL_TYPE_DOUBLE:
09782                 while (to_length--) {
09783                     if (*tnp++ == 0)
09784                         *tip *= *fdp;
09785                     tip++;
09786                     fdp++;
09787                 }
09788                 break;
09789 
09790             default:
09791                 break;
09792             }
09793             break;
09794 
09795         case CPL_TYPE_FLOAT:
09796 
09797             switch (from_type) {
09798 
09799             case CPL_TYPE_INT:
09800                 while (to_length--) {
09801                     if (*tnp++ == 0)
09802                         *tfp *= (double)*fip;
09803                     tfp++;
09804                     fip++;
09805                 }
09806                 break;
09807 
09808             case CPL_TYPE_FLOAT:
09809                 while (to_length--) {
09810                     if (*tnp++ == 0)
09811                         *tfp *= (double)*ffp;
09812                     tfp++;
09813                     ffp++;
09814                 }
09815                 break;
09816 
09817             case CPL_TYPE_DOUBLE:
09818                 while (to_length--) {
09819                     if (*tnp++ == 0)
09820                         *tfp *= *fdp;
09821                     tfp++;
09822                     fdp++;
09823                 }
09824                 break;
09825             
09826             default:
09827                 break;
09828             }
09829             break;
09830 
09831         case CPL_TYPE_DOUBLE:
09832 
09833             switch (from_type) {
09834 
09835             case CPL_TYPE_INT:
09836                 while (to_length--) {
09837                     if (*tnp++ == 0)
09838                         *tdp *= *fip;
09839                     tdp++;
09840                     fip++;
09841                 }
09842                 break;
09843 
09844             case CPL_TYPE_FLOAT:
09845                 while (to_length--) {
09846                     if (*tnp++ == 0)
09847                         *tdp *= *ffp;
09848                     tdp++;
09849                     ffp++;
09850                 }
09851                 break;
09852 
09853             case CPL_TYPE_DOUBLE:
09854                 while (to_length--) {
09855                     if (*tnp++ == 0)
09856                         *tdp *= *fdp;
09857                     tdp++;
09858                     fdp++;
09859                 }
09860                 break;
09861             
09862             default:
09863                 break;
09864             }
09865             break;
09866 
09867         default:
09868             break;
09869         }
09870     }
09871 
09872     return CPL_ERROR_NONE;
09873 
09874 }
09875 
09876 
09877 /*
09878  * @brief
09879  *   Divide two numeric columns.
09880  *
09881  * @param to_column   Target column.
09882  * @param from_column Divisor column.
09883  *
09884  * @return @c CPL_ERROR_NONE on success. If any of the input columns
09885  *   is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If
09886  *   any of the input columns is of type string, a @c CPL_ERROR_INVALID_TYPE
09887  *   is returned. If the input columns do not have the same length,
09888  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned.
09889  *
09890  * The result of the multiplication is stored in the target colum. The type of
09891  * the columns may differ, and in that case the operation would be performed
09892  * according to the C upcasting rules, with a final cast of the result to
09893  * the target column type. Invalid elements are propagated consistently:
09894  * if either or both members of the multiplication are invalid, the result
09895  * will be invalid too. Underflows and overflows are ignored, but a division 
09896  * by zero is producing an invalid element in the target column. This function
09897  * is not applicable to array columns.
09898  */
09899 
09900 cpl_error_code xxx_column_divide(xxx_column *to_column, 
09901                                  xxx_column *from_column)
09902 {
09903 
09904     const char *fid         = "xxx_column_divide";
09905     int          i;
09906     int          to_length   = xxx_column_get_size(to_column);
09907     int          from_length = xxx_column_get_size(from_column);
09908     cpl_type     to_type     = xxx_column_get_type(to_column);
09909     cpl_type     from_type   = xxx_column_get_type(from_column);
09910 
09911     int         *fip;
09912     float       *ffp;
09913     double      *fdp;
09914     int         *tip;
09915     float       *tfp;
09916     double      *tdp;
09917     int         *fnp;
09918     int         *tnp;
09919 
09920 
09921     if (to_column == 0x0 || from_column == 0x0)
09922         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
09923 
09924     if ((to_type == CPL_TYPE_STRING) || (from_type == CPL_TYPE_STRING) ||
09925         (to_type & CPL_TYPE_POINTER) || (from_type & CPL_TYPE_POINTER))
09926         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
09927 
09928     if (to_length != from_length)
09929         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
09930 
09931     if (to_length == 0)
09932         return CPL_ERROR_NONE;
09933 
09934     if (from_column->nullcount == from_length)
09935         return xxx_column_fill_invalid(to_column, 0, to_length);
09936 
09937 
09938     /*
09939      *  Look for zeroes in the divisor column, and mark them as
09940      *  invalid in the target column in advance.
09941      */
09942 
09943     if (from_column->nullcount == 0) {
09944 
09945         switch (from_type) {
09946 
09947         case CPL_TYPE_INT:
09948             fip = from_column->values->i;
09949             for (i = 0; i < to_length; i++)
09950                 if (*fip++ == 0)
09951                     xxx_column_set_invalid(to_column, i);
09952             break;
09953     
09954         case CPL_TYPE_FLOAT:
09955             ffp = from_column->values->f;
09956             for (i = 0; i < to_length; i++)
09957                 if (*ffp++ == 0.0)
09958                     xxx_column_set_invalid(to_column, i);
09959             break;
09960     
09961         case CPL_TYPE_DOUBLE:
09962             fdp = from_column->values->d;
09963             for (i = 0; i < to_length; i++)
09964                 if (*fdp++ == 0.0)
09965                     xxx_column_set_invalid(to_column, i);
09966             break;
09967     
09968         default:
09969             break;
09970     
09971         }
09972     }
09973     else {
09974 
09975         fnp = from_column->null;
09976 
09977         switch (from_type) {
09978 
09979         case CPL_TYPE_INT:
09980             fip = from_column->values->i;
09981             for (i = 0; i < to_length; i++, fip++)
09982                 if (*fnp++ == 0)
09983                     if (*fip == 0)
09984                         xxx_column_set_invalid(to_column, i);
09985             break;
09986 
09987         case CPL_TYPE_FLOAT:
09988             ffp = from_column->values->f;
09989             for (i = 0; i < to_length; i++, ffp++)
09990                 if (*fnp++ == 0)
09991                     if (*ffp == 0.0)
09992                         xxx_column_set_invalid(to_column, i);
09993             break;
09994 
09995         case CPL_TYPE_DOUBLE:
09996             fdp = from_column->values->d;
09997             for (i = 0; i < to_length; i++, fdp++)
09998                 if (*fnp++ == 0)
09999                     if (*fdp == 0.0)
10000                         xxx_column_set_invalid(to_column, i);
10001             break;
10002 
10003         default:
10004             break;
10005 
10006         }
10007 
10008     }
10009 
10010 
10011    /*
10012     * If there are just NULLs in the target column, no need to
10013     * perform any further operation:
10014     */
10015 
10016     if (to_column->nullcount == to_length)
10017         return CPL_ERROR_NONE;
10018 
10019 
10020     fip = from_column->values->i;
10021     ffp = from_column->values->f;
10022     fdp = from_column->values->d;
10023     tip = to_column->values->i;
10024     tfp = to_column->values->f;
10025     tdp = to_column->values->d;
10026 
10027     if (to_column->nullcount == 0 && from_column->nullcount == 0) {
10028 
10029         /*
10030          * If there are no invalids in both columns, the operation can
10031          * be performed without any check:
10032          */
10033 
10034         switch (to_type) {
10035 
10036         case CPL_TYPE_INT:
10037 
10038             switch (from_type) {
10039 
10040             case CPL_TYPE_INT:
10041                 while (to_length--)
10042                     *tip++ /= *fip++;
10043                 break;
10044 
10045             case CPL_TYPE_FLOAT:
10046                 while (to_length--)
10047                     *tip++ /= *ffp++;
10048                 break;
10049 
10050             case CPL_TYPE_DOUBLE:
10051                 while (to_length--)
10052                     *tip++ /= *fdp++;
10053                 break;
10054 
10055             default:
10056                 break;
10057             }
10058             break;
10059 
10060         case CPL_TYPE_FLOAT:
10061 
10062             switch (from_type) {
10063 
10064             case CPL_TYPE_INT:
10065                 while (to_length--)
10066                     *tfp++ /= (double)*fip++;
10067                 break;
10068 
10069             case CPL_TYPE_FLOAT:
10070                 while (to_length--)
10071                     *tfp++ /= (double)*ffp++;
10072                 break;
10073 
10074             case CPL_TYPE_DOUBLE:
10075                 while (to_length--)
10076                     *tfp++ /= *fdp++;
10077                 break;
10078             
10079             default:
10080                 break;
10081             }
10082             break;
10083 
10084         case CPL_TYPE_DOUBLE:
10085 
10086             switch (from_type) {
10087 
10088             case CPL_TYPE_INT:
10089                 while (to_length--)
10090                     *tdp++ /= *fip++;
10091                 break;
10092 
10093             case CPL_TYPE_FLOAT:
10094                 while (to_length--)
10095                     *tdp++ /= *ffp++;
10096                 break;
10097 
10098             case CPL_TYPE_DOUBLE:
10099                 while (to_length--)
10100                     *tdp++ /= *fdp++;
10101                 break;
10102             
10103             default:
10104                 break;
10105             }
10106             break;
10107 
10108         default:
10109             break;
10110         }
10111     }
10112     else {
10113 
10114         /*
10115          * Here there are some invalids around, so the operation needs to be
10116          * performed with some checks. As a first thing, take care of the
10117          * invalids pattern in the target column:
10118          */
10119 
10120         if (to_column->nullcount == 0 || from_column->nullcount == 0) {
10121 
10122             /*
10123              * Here there are some invalids in just one of the two columns.
10124              * If they are just in the column to subtract, an identical
10125              * invalid flags buffer must be created for the target column.
10126              */
10127 
10128             if (from_column->nullcount) {
10129                 to_column->null = cpl_calloc(to_length, 
10130                                              sizeof(xxx_column_flag));
10131 
10132                 i = to_length;
10133                 while (i--)
10134                     if (from_column->null[i])
10135                         to_column->null[i] = 1;
10136 
10137                 to_column->nullcount = from_column->nullcount;
10138 
10139             }
10140         }
10141         else {
10142 
10143             /*
10144              *  Here there are some invalids in both columns.
10145              */
10146 
10147             i = to_length;
10148             while (i--) {
10149                 if (from_column->null[i]) {
10150                     if (!to_column->null[i]) {
10151                         to_column->null[i] = 1;
10152                         to_column->nullcount++;
10153                     }
10154                 }
10155             }
10156 
10157             if (to_column->nullcount == to_length) {
10158 
10159                 /*
10160                  * Just invalids in the result: no need to perform any further
10161                  * operation, and the invalid buffer of the target column can
10162                  * be disabled.
10163                  */
10164 
10165                 if (to_column->null)
10166                     cpl_free(to_column->null);
10167                 to_column->null = NULL;
10168                 return 0;
10169             }
10170 
10171         }
10172 
10173 
10174         /*
10175          * The operation can be performed while checking the already
10176          * computed result invalid flags buffer of the target column.
10177          */
10178 
10179         tnp = to_column->null;
10180 
10181         switch (to_type) {
10182 
10183         case CPL_TYPE_INT:
10184 
10185             switch (from_type) {
10186 
10187             case CPL_TYPE_INT:
10188                 for (i = 0; i < to_length; i++, tip++, fip++, tnp++)
10189                     if (*tnp == 0)
10190                         *tip /= *fip;
10191                 break;
10192 
10193             case CPL_TYPE_FLOAT:
10194                 for (i = 0; i < to_length; i++, tip++, ffp++, tnp++)
10195                     if (*tnp == 0)
10196                         *tip /= *ffp;
10197                 break;
10198 
10199             case CPL_TYPE_DOUBLE:
10200                 for (i = 0; i < to_length; i++, tip++, fdp++, tnp++)
10201                     if (*tnp == 0)
10202                         *tip /= *fdp;
10203                 break;
10204 
10205             default:
10206                 break;
10207             }
10208             break;
10209 
10210         case CPL_TYPE_FLOAT:
10211 
10212             switch (from_type) {
10213 
10214             case CPL_TYPE_INT:
10215                 for (i = 0; i < to_length; i++, tfp++, fip++, tnp++)
10216                     if (*tnp == 0)
10217                         *tfp /= (double)*fip;
10218                 break;
10219 
10220             case CPL_TYPE_FLOAT:
10221                 for (i = 0; i < to_length; i++, tfp++, ffp++, tnp++)
10222                     if (*tnp == 0)
10223                         *tfp /= (double)*ffp;
10224                 break;
10225 
10226             case CPL_TYPE_DOUBLE:
10227                 for (i = 0; i < to_length; i++, tfp++, fdp++, tnp++)
10228                     if (*tnp == 0)
10229                         *tfp /= *fdp;
10230                 break;
10231             
10232             default:
10233                 break;
10234             }
10235             break;
10236 
10237         case CPL_TYPE_DOUBLE:
10238 
10239             switch (from_type) {
10240 
10241             case CPL_TYPE_INT:
10242                 for (i = 0; i < to_length; i++, tdp++, fip++, tnp++)
10243                     if (*tnp == 0)
10244                         *tdp /= *fip;
10245                 break;
10246 
10247             case CPL_TYPE_FLOAT:
10248                 for (i = 0; i < to_length; i++, tdp++, ffp++, tnp++)
10249                     if (*tnp == 0)
10250                         *tdp /= *ffp;
10251                 break;
10252 
10253             case CPL_TYPE_DOUBLE:
10254                 for (i = 0; i < to_length; i++, tdp++, fdp++, tnp++)
10255                     if (*tnp == 0)
10256                         *tdp /= *fdp;
10257                 break;
10258             
10259             default:
10260                 break;
10261             }
10262             break;
10263 
10264         default:
10265             break;
10266         }
10267     }
10268 
10269     return CPL_ERROR_NONE;
10270 
10271 }
10272 
10273 
10274 /*
10275  * @brief
10276  *   Private function to make the exponential of an integer column.
10277  *
10278  * @param column  Target column.
10279  * @param base    Constant base.
10280  *
10281  * @return Nothing
10282  *
10283  * This private function is just a way to compact the code of other
10284  * higher level functions. No check is performed on input, assuming
10285  * that this was done elsewhere.
10286  */
10287 
10288 static void xxx_column_exp_int(xxx_column *column, double base)
10289 {
10290 
10291     int    nullcount = xxx_column_count_invalid(column);
10292     int    length    = xxx_column_get_size(column);
10293     int   *ip        = xxx_column_get_data_int(column);
10294     int   *np        = xxx_column_get_data_invalid(column);
10295     int    i;
10296 
10297 
10298     if (nullcount == length)
10299         return;
10300 
10301     if (nullcount == 0) {
10302         for (i = 0; i < length; i++, ip++)
10303             *ip = xxx_tools_ipow(base, *ip);
10304     }
10305     else {
10306         for (i = 0; i < length; i++, ip++, np++)
10307             if (*np == 0)
10308                 *ip = xxx_tools_ipow(base, *ip);
10309     }
10310 
10311 }
10312 
10313 
10314 /*
10315  * @brief
10316  *   Private function to make the exponential of a float column.
10317  *
10318  * @param column  Target column.
10319  * @param base    Constant base.
10320  *
10321  * @return Nothing
10322  *
10323  * This private function is just a way to compact the code of other
10324  * higher level functions. No check is performed on input, assuming
10325  * that this was done elsewhere.
10326  */
10327 
10328 static void xxx_column_exp_float(xxx_column *column, double base)
10329 {
10330 
10331     int    nullcount = xxx_column_count_invalid(column);
10332     int    length    = xxx_column_get_size(column);
10333     float *fp        = xxx_column_get_data_float(column);
10334     int   *np        = xxx_column_get_data_invalid(column);
10335     int    i;
10336 
10337 
10338     if (nullcount == length)
10339         return;
10340 
10341     if (nullcount == 0) {
10342         for (i = 0; i < length; i++, fp++)
10343             *fp = pow(base, *fp);
10344     }
10345     else {
10346         for (i = 0; i < length; i++, fp++, np++)
10347             if (*np == 0)
10348                 *fp = pow(base, *fp);
10349     }
10350 
10351 }
10352 
10353 
10354 /*
10355  * @brief
10356  *   Private function to make the exponential of a double column.
10357  *
10358  * @param column  Target column.
10359  * @param base    Constant base.
10360  *
10361  * @return Nothing
10362  *
10363  * This private function is just a way to compact the code of other
10364  * higher level functions. No check is performed on input, assuming
10365  * that this was done elsewhere.
10366  */
10367 
10368 static void xxx_column_exp_double(xxx_column *column, double base)
10369 {
10370 
10371     int     nullcount = xxx_column_count_invalid(column);
10372     int     length    = xxx_column_get_size(column);
10373     double *dp        = xxx_column_get_data_double(column);
10374     int    *np        = xxx_column_get_data_invalid(column);
10375     int     i;
10376 
10377 
10378     if (nullcount == length)
10379         return;
10380 
10381     if (nullcount == 0) {
10382         for (i = 0; i < length; i++, dp++)
10383             *dp = pow(base, *dp);
10384     }
10385     else {
10386         for (i = 0; i < length; i++, dp++, np++)
10387             if (*np == 0)
10388                 *dp = pow(base, *dp);
10389     }
10390 
10391 }
10392 
10393 
10394 /*
10395  * @brief
10396  *   Private function to make the power of an integer column.
10397  *
10398  * @param column   Target column.
10399  * @param exponent Constant exponent.
10400  *
10401  * @return Nothing
10402  *
10403  * This private function is just a way to compact the code of other
10404  * higher level functions. No check is performed on input, assuming
10405  * that this was done elsewhere.
10406  */
10407 
10408 static void xxx_column_pow_int(xxx_column *column, double exponent)
10409 {
10410 
10411     int    nullcount = xxx_column_count_invalid(column);
10412     int    length    = xxx_column_get_size(column);
10413     int   *ip        = xxx_column_get_data_int(column);
10414     int   *np        = xxx_column_get_data_invalid(column);
10415     int    negative  = exponent < 0.0;
10416     int    i;
10417 
10418 
10419     if (nullcount == length)
10420         return;
10421 
10422     if (negative)
10423         exponent = -exponent;
10424 
10425     if (exponent != 1.0) {
10426         if (nullcount == 0) {
10427             if (negative) {
10428                 for (i = 0; i < length; i++, ip++) {
10429                     if (*ip > 0)
10430                         *ip = floor(1 / pow(*ip, exponent) + 0.5);
10431                     else
10432                         xxx_column_set_invalid(column, i);
10433                 }
10434             }
10435             else {
10436                 for (i = 0; i < length; i++, ip++) {
10437                     if (*ip >= 0)
10438                         *ip = floor(pow(*ip, exponent) + 0.5);
10439                     else
10440                         xxx_column_set_invalid(column, i);
10441                 }
10442             }
10443         }
10444         else {
10445             for (i = 0; i < length; i++, ip++, np++) {
10446                 if (negative) {
10447                     if (*np == 0) {
10448                         if (*ip > 0)
10449                             *ip = floor(1 / pow(*ip, exponent) + 0.5);
10450                         else
10451                             xxx_column_set_invalid(column, i);
10452                     }
10453                 }
10454                 else {
10455                     if (*np == 0) {
10456                         if (*ip >= 0)
10457                             *ip = floor(pow(*ip, exponent) + 0.5);
10458                         else
10459                             xxx_column_set_invalid(column, i);
10460                     }
10461                 }
10462             }
10463         }
10464     }
10465 }
10466 
10467 
10468 /*
10469  * @brief
10470  *   Private function to make the power of a float column.
10471  *
10472  * @param column   Target column.
10473  * @param exponent Constant exponent.
10474  *
10475  * @return Nothing
10476  *
10477  * This private function is just a way to compact the code of other
10478  * higher level functions. No check is performed on input, assuming
10479  * that this was done elsewhere.
10480  */
10481 
10482 static void xxx_column_pow_float(xxx_column *column, double exponent)
10483 {
10484 
10485     int    nullcount = xxx_column_count_invalid(column);
10486     int    length    = xxx_column_get_size(column);
10487     float *fp        = xxx_column_get_data_float(column);
10488     int   *np        = xxx_column_get_data_invalid(column);
10489     int    negative  = exponent < 0.0;
10490     int    i;
10491 
10492 
10493     if (nullcount == length)
10494         return;
10495 
10496     if (negative)
10497         exponent = -exponent;
10498 
10499     if (exponent != 1.0) {
10500         if (nullcount == 0) {
10501             if (negative) {
10502                 for (i = 0; i < length; i++, fp++) {
10503                     if (*fp > 0.0)
10504                         *fp = 1 / pow(*fp, exponent);
10505                     else
10506                         xxx_column_set_invalid(column, i);
10507                 }
10508             }
10509             else {
10510                 for (i = 0; i < length; i++, fp++) {
10511                     if (*fp >= 0.0)
10512                         *fp = pow(*fp, exponent);
10513                     else
10514                         xxx_column_set_invalid(column, i);
10515                 }
10516             }
10517         }
10518         else {
10519             for (i = 0; i < length; i++, fp++, np++) {
10520                 if (negative) {
10521                     if (*np == 0) {
10522                         if (*fp > 0.0)
10523                             *fp = 1 / pow(*fp, exponent);
10524                         else
10525                             xxx_column_set_invalid(column, i);
10526                     }
10527                 }
10528                 else {
10529                     if (*np == 0) {
10530                         if (*fp >= 0.0)
10531                             *fp = pow(*fp, exponent);
10532                         else
10533                             xxx_column_set_invalid(column, i);
10534                     }
10535                 }
10536             }
10537         }
10538     }
10539 }
10540 
10541 
10542 /*
10543  * @brief
10544  *   Private function to make the power of a double column.
10545  *
10546  * @param column   Target column.
10547  * @param exponent Constant exponent.
10548  *
10549  * @return Nothing
10550  *
10551  * This private function is just a way to compact the code of other
10552  * higher level functions. No check is performed on input, assuming
10553  * that this was done elsewhere.
10554  */
10555 
10556 static void xxx_column_pow_double(xxx_column *column, double exponent)
10557 {
10558 
10559     int     nullcount = xxx_column_count_invalid(column);
10560     int     length    = xxx_column_get_size(column);
10561     double *dp        = xxx_column_get_data_double(column);
10562     int    *np        = xxx_column_get_data_invalid(column);
10563     int     negative  = exponent < 0.0;
10564     int     i;
10565 
10566 
10567     if (nullcount == length)
10568         return; 
10569 
10570     if (negative)
10571         exponent = -exponent;
10572 
10573     if (nullcount == 0) {
10574         if (negative) {
10575             for (i = 0; i < length; i++, dp++) {
10576                 if (*dp > 0.0)
10577                     *dp = 1 / pow(*dp, exponent);
10578                 else
10579                     xxx_column_set_invalid(column, i);
10580             }
10581         }
10582         else {
10583             for (i = 0; i < length; i++, dp++) {
10584                 if (*dp >= 0.0)
10585                     *dp = pow(*dp, exponent);
10586                 else
10587                     xxx_column_set_invalid(column, i);
10588             }
10589         }
10590     }
10591     else {
10592         for (i = 0; i < length; i++, dp++, np++) {
10593             if (negative) {
10594                 if (*np == 0) {
10595                     if (*dp > 0.0)
10596                         *dp = 1 / pow(*dp, exponent);
10597                     else
10598                         xxx_column_set_invalid(column, i);
10599                 }
10600             }
10601             else {
10602                 if (*np == 0) {
10603                     if (*dp >= 0.0)
10604                         *dp = pow(*dp, exponent);
10605                     else
10606                         xxx_column_set_invalid(column, i);
10607                 }
10608             }
10609         }
10610     }
10611 }
10612 
10613 
10614 /*
10615  * @brief
10616  *   Private function to make the log of an integer column.
10617  *
10618  * @param column   Target column.
10619  * @param base     Logarithm base.
10620  *
10621  * @return Nothing
10622  *
10623  * This private function is just a way to compact the code of other
10624  * higher level functions. No check is performed on input, assuming
10625  * that this was done elsewhere.
10626  */
10627 
10628 static void xxx_column_log_int(xxx_column *column, double base)
10629 {
10630 
10631     int    nullcount = xxx_column_count_invalid(column);
10632     int    length    = xxx_column_get_size(column);
10633     int   *ip        = xxx_column_get_data_int(column);
10634     int   *np        = xxx_column_get_data_invalid(column);
10635     int    i;
10636     double invlog    = 1 / log(base);
10637 
10638 
10639     if (nullcount == length)
10640         return;
10641 
10642     if (nullcount == 0) {
10643         for (i = 0; i < length; i++, ip++) {
10644             if (*ip > 0)
10645                 *ip = floor(log(*ip) * invlog + 0.5);
10646             else 
10647                 xxx_column_set_invalid(column, i);
10648         }
10649     }
10650     else {
10651         for (i = 0; i < length; i++, ip++, np++) {
10652             if (*np == 0) {
10653                 if (*ip > 0)
10654                     *ip = floor(log(*ip) * invlog + 0.5);
10655                 else
10656                     xxx_column_set_invalid(column, i);
10657             }
10658         }
10659     }
10660 }
10661 
10662 
10663 /*
10664  * @brief
10665  *   Private function to make the log of a float column.
10666  *
10667  * @param column   Target column.
10668  * @param base     Logarithm base.
10669  *
10670  * @return Nothing
10671  *
10672  * This private function is just a way to compact the code of other
10673  * higher level functions. No check is performed on input, assuming
10674  * that this was done elsewhere.
10675  */
10676 
10677 static void xxx_column_log_float(xxx_column *column, double base)
10678 {
10679 
10680     int    nullcount = xxx_column_count_invalid(column);
10681     int    length    = xxx_column_get_size(column);
10682     float *fp        = xxx_column_get_data_float(column);
10683     int   *np        = xxx_column_get_data_invalid(column);
10684     int    i;
10685     double invlog    = 1 / log(base);
10686 
10687 
10688     if (nullcount == length)
10689         return;
10690 
10691     if (nullcount == 0) {
10692         for (i = 0; i < length; i++, fp++) {
10693             if (*fp > 0.0)
10694                 *fp = log(*fp) * invlog;
10695             else
10696                 xxx_column_set_invalid(column, i);
10697         }
10698     }
10699     else {
10700         for (i = 0; i < length; i++, fp++, np++) {
10701             if (*np == 0) {
10702                 if (*fp > 0.0)
10703                     *fp = log(*fp) * invlog;
10704                 else
10705                     xxx_column_set_invalid(column, i);
10706             }
10707         }
10708     }
10709 }
10710 
10711 
10712 /*
10713  * @brief
10714  *   Private function to make the log of a double column.
10715  *
10716  * @param column   Target column.
10717  * @param base     Logarithm base.
10718  *
10719  * @return Nothing
10720  *
10721  * This private function is just a way to compact the code of other
10722  * higher level functions. No check is performed on input, assuming
10723  * that this was done elsewhere.
10724  */
10725 
10726 static void xxx_column_log_double(xxx_column *column, double base)
10727 {
10728 
10729     int     nullcount = xxx_column_count_invalid(column);
10730     int     length    = xxx_column_get_size(column);
10731     double *dp        = xxx_column_get_data_double(column);
10732     int    *np        = xxx_column_get_data_invalid(column);
10733     int     i;
10734     double  invlog    = 1 / log(base);
10735 
10736 
10737     if (nullcount == length)
10738         return;
10739 
10740     if (nullcount == 0) {
10741         for (i = 0; i < length; i++, dp++) {
10742             if (*dp > 0.0)
10743                 *dp = log(*dp) * invlog;
10744             else
10745                 xxx_column_set_invalid(column, i);
10746         }
10747     }
10748     else {
10749         for (i = 0; i < length; i++, dp++, np++) {
10750             if (*np == 0) {
10751                 if (*dp > 0.0)
10752                     *dp = log(*dp) * invlog;
10753                 else
10754                     xxx_column_set_invalid(column, i);
10755             }
10756         }
10757     }
10758 }
10759 
10760 
10761 /*
10762  * @brief
10763  *   Private function to add an @em integer constant to an @em integer column.
10764  *
10765  * @param column   Target column.
10766  * @param value    Value to add.
10767  *
10768  * @return Nothing
10769  *
10770  * This private function is just a way to compact the code of other
10771  * higher level functions. No check is performed on input, assuming
10772  * that this was done elsewhere.
10773  */
10774 
10775 static void xxx_column_add_to_int(xxx_column *column, int value)
10776 {
10777 
10778     int  nullcount = xxx_column_count_invalid(column);
10779     int  length    = xxx_column_get_size(column);
10780     int *ip        = xxx_column_get_data_int(column);
10781     int *np        = xxx_column_get_data_invalid(column);
10782     int  i;
10783 
10784 
10785     if (value == 0)
10786         return;
10787 
10788     if (nullcount == length)
10789         return;
10790 
10791     if (nullcount == 0)
10792         for (i = 0; i < length; i++)
10793             *ip++ += value;
10794     else
10795         for (i = 0; i < length; i++, ip++, np++)
10796             if (*np == 0)
10797                 *ip += value;
10798 
10799 }
10800 
10801 
10802 /*
10803  * @brief
10804  *   Private function to add a @em float constant to a @em float column.
10805  *
10806  * @param column   Target column.
10807  * @param value    Value to add.
10808  *
10809  * @return Nothing
10810  *
10811  * This private function is just a way to compact the code of other
10812  * higher level functions. No check is performed on input, assuming
10813  * that this was done elsewhere.
10814  */ 
10815 
10816 static void xxx_column_add_to_float(xxx_column *column, double value)
10817 {
10818 
10819     int    nullcount = xxx_column_count_invalid(column);
10820     int    length    = xxx_column_get_size(column);
10821     float *fp        = xxx_column_get_data_float(column);
10822     int   *np        = xxx_column_get_data_invalid(column);
10823     int    i;
10824 
10825 
10826     if (value == 0.0)
10827         return;
10828 
10829     if (nullcount == length)
10830         return;
10831 
10832     if (nullcount == 0) 
10833         for (i = 0; i < length; i++)
10834             *fp++ += value;
10835     else
10836         for (i = 0; i < length; i++, fp++, np++)
10837             if (*np == 0)
10838                 *fp += value;
10839 
10840 }
10841 
10842 
10843 /*
10844  * @brief
10845  *   Private function to add a @em double constant to a @em double column.
10846  *
10847  * @param column   Target column.
10848  * @param value    Value to add.
10849  *
10850  * @return Nothing
10851  *
10852  * This private function is just a way to compact the code of other
10853  * higher level functions. No check is performed on input, assuming
10854  * that this was done elsewhere.
10855  */
10856 
10857 static void xxx_column_add_to_double(xxx_column *column, double value)
10858 {
10859 
10860     int     nullcount = xxx_column_count_invalid(column);
10861     int     length    = xxx_column_get_size(column);
10862     double *dp        = xxx_column_get_data_double(column);
10863     int    *np        = xxx_column_get_data_invalid(column);
10864     int     i;
10865 
10866 
10867     if (value == 0.0)
10868         return;
10869 
10870     if (nullcount == length)
10871         return;
10872 
10873     if (nullcount == 0) 
10874         for (i = 0; i < length; i++)
10875             *dp++ += value;
10876     else
10877         for (i = 0; i < length; i++, dp++, np++)
10878             if (*np == 0)
10879                 *dp += value;
10880 
10881 }
10882 
10883 
10884 /*
10885  * @brief
10886  *   Private function to multiply a @em double column by a @em double constant.
10887  *
10888  * @param column   Target column.
10889  * @param value    Value to add.
10890  *
10891  * @return Nothing
10892  *
10893  * This private function is just a way to compact the code of other
10894  * higher level functions. No check is performed on input, assuming
10895  * that this was done elsewhere.
10896  */
10897 
10898 static void xxx_column_mul_to_double(xxx_column *column, double value)
10899 {
10900 
10901     int     nullcount = xxx_column_count_invalid(column);
10902     int     length    = xxx_column_get_size(column);
10903     double *dp        = xxx_column_get_data_double(column);
10904     int    *np        = xxx_column_get_data_invalid(column);
10905     int     i;
10906 
10907 
10908     if (value == 1.0)
10909         return;
10910 
10911     if (nullcount == length)
10912         return;
10913 
10914     if (nullcount == 0)
10915         for (i = 0; i < length; i++)
10916             *dp++ *= value;
10917     else
10918         for (i = 0; i < length; i++, dp++, np++)
10919             if (*np == 0)
10920                 *dp *= value;
10921 
10922 }
10923 
10924 
10925 /*
10926  * @brief
10927  *   Private function to multiply a @em integer column by a @em double constant.
10928  *
10929  * @param column   Target column.
10930  * @param value    Value to add.
10931  *
10932  * @return Nothing.
10933  *
10934  * This private function is just a way to compact the code of other
10935  * higher level functions. No check is performed on input, assuming
10936  * that this was done elsewhere.
10937  */
10938 
10939 static void xxx_column_mul_double_to_int(xxx_column *column, double value)
10940 {
10941 
10942     int  nullcount = xxx_column_count_invalid(column);
10943     int  length    = xxx_column_get_size(column);
10944     int *ip        = xxx_column_get_data_int(column);
10945     int *np        = xxx_column_get_data_invalid(column);
10946     int  i;
10947 
10948 
10949     if (value == 1.0)
10950         return;
10951 
10952     if (nullcount == length)
10953         return;
10954 
10955     if (nullcount == 0)
10956         for (i = 0; i < length; i++)
10957             *ip++ *= value;
10958     else
10959         for (i = 0; i < length; i++, ip++, np++)
10960             if (*np == 0)
10961                 *ip *= value;
10962 
10963 }
10964 
10965 
10966 /*
10967  * @brief
10968  *   Private function to multiply a @em float column by a @em double constant.
10969  *
10970  * @param column   Target column.
10971  * @param value    Value to add.
10972  *
10973  * @return Nothing.
10974  *
10975  * This private function is just a way to compact the code of other
10976  * higher level functions. No check is performed on input, assuming
10977  * that this was done elsewhere.
10978  */
10979 
10980 static void xxx_column_mul_double_to_float(xxx_column *column, double value)
10981 {
10982 
10983     int    nullcount = xxx_column_count_invalid(column);
10984     int    length    = xxx_column_get_size(column);
10985     float *fp        = xxx_column_get_data_float(column);
10986     int   *np        = xxx_column_get_data_invalid(column);
10987     int    i;
10988 
10989 
10990     if (value == 1.0)
10991         return;
10992 
10993     if (nullcount == length)
10994         return;
10995 
10996     if (nullcount == 0)
10997         for (i = 0; i < length; i++)
10998             *fp++ *= value;
10999     else
11000         for (i = 0; i < length; i++, fp++, np++)
11001             if (*np == 0)
11002                 *fp *= value;
11003 
11004 }
11005 
11006 
11007 /* 
11008  * @brief
11009  *   Compute the logarithm of column values.
11010  *
11011  * @param column   Target column.
11012  * @param base     Logarithm base.
11013  *
11014  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL 
11015  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column 
11016  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned. If the
11017  *   @em base is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is
11018  *   returned.
11019  *
11020  * The operation is always performed in double precision, with a final
11021  * cast of the result to the target column type. Non-positive column
11022  * values will be marked as invalid. Columns of strings or arrays are
11023  * not allowed.
11024  */
11025 
11026 cpl_error_code xxx_column_logarithm(xxx_column *column, double base)
11027 {
11028 
11029     const char *fid  = "xxx_column_logarithm";
11030     cpl_type     type = xxx_column_get_type(column);
11031 
11032 
11033     if (column == 0x0)
11034         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11035 
11036     if (base <= 0.0)
11037         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
11038 
11039 
11040     switch (type) {
11041 
11042     case CPL_TYPE_INT:
11043         xxx_column_log_int(column, base);
11044         break;
11045     case CPL_TYPE_FLOAT:
11046         xxx_column_log_float(column, base);
11047         break;
11048     case CPL_TYPE_DOUBLE:
11049         xxx_column_log_double(column, base);
11050         break;
11051     default:
11052         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11053 
11054     }
11055 
11056     return CPL_ERROR_NONE;
11057 
11058 }
11059 
11060 
11061 /* 
11062  * @brief
11063  *   Compute the exponential of column values.
11064  *
11065  * @param column   Target column.
11066  * @param base     Exponential base.
11067  *
11068  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11069  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11070  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned. If the
11071  *   @em base is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is
11072  *   returned.
11073  *
11074  * The operation is always performed in double precision, with a final
11075  * cast of the result to the target column type. Columns of strings or 
11076  * arrays are not allowed.
11077  */
11078 
11079 cpl_error_code xxx_column_exponential(xxx_column *column, double base)
11080 {
11081 
11082     const char *fid  = "xxx_column_exponential";
11083     cpl_type     type = xxx_column_get_type(column);
11084 
11085 
11086     if (column == 0x0)
11087         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11088 
11089     if (base <= 0.0)
11090         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
11091 
11092 
11093     switch (type) {
11094 
11095     case CPL_TYPE_INT:
11096         xxx_column_exp_int(column, base);
11097         break;
11098     case CPL_TYPE_FLOAT:
11099         xxx_column_exp_float(column, base);
11100         break;
11101     case CPL_TYPE_DOUBLE:
11102         xxx_column_exp_double(column, base);
11103         break;
11104     default:
11105         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11106 
11107     }
11108 
11109     return CPL_ERROR_NONE;
11110 
11111 }
11112 
11113 
11114 /* 
11115  * @brief
11116  *   Compute a power of column values.
11117  *
11118  * @param column   Target column.
11119  * @param exponent Constant exponent.
11120  *
11121  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11122  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11123  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned.
11124  *
11125  * The operation is always performed in double precision, with a final
11126  * cast of the result to the target column type. Non-positive column
11127  * values will be marked as invalid. Columns of strings or arrays are 
11128  * not allowed.
11129  */
11130 
11131 cpl_error_code xxx_column_power(xxx_column *column, double exponent)
11132 {
11133 
11134     const char *fid  = "xxx_column_power";
11135     cpl_type     type = xxx_column_get_type(column);
11136 
11137 
11138     if (column == 0x0)
11139         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11140 
11141 
11142     switch (type) {
11143 
11144     case CPL_TYPE_INT:  
11145         xxx_column_pow_int(column, exponent);
11146         break;
11147     case CPL_TYPE_FLOAT:
11148         xxx_column_pow_float(column, exponent);
11149         break;
11150     case CPL_TYPE_DOUBLE:
11151         xxx_column_pow_double(column, exponent);
11152         break;
11153     default:
11154         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11155 
11156     }
11157 
11158     return CPL_ERROR_NONE;
11159 
11160 }
11161 
11162 
11163 /* 
11164  * @brief
11165  *   Add a constant value to a numerical column.
11166  *
11167  * @param column   Target column.
11168  * @param value    Value to add.
11169  * 
11170  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11171  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11172  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned.
11173  * 
11174  * The operation is always performed in double precision, with a final   
11175  * cast of the result to the target column type. Invalid flags are not
11176  * modified by this operation. Columns of strings or arrays are not allowed.
11177  */
11178 
11179 cpl_error_code xxx_column_add_scalar(xxx_column *column, double value)
11180 {
11181 
11182     const char *fid  = "xxx_column_add_scalar";
11183     cpl_type     type = xxx_column_get_type(column);
11184 
11185 
11186     if (column == 0x0)
11187         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11188 
11189 
11190     switch (type) {
11191 
11192     case CPL_TYPE_INT:
11193         xxx_column_add_to_int(column, value);
11194         break;
11195     case CPL_TYPE_FLOAT:
11196         xxx_column_add_to_float(column, value);
11197         break;
11198     case CPL_TYPE_DOUBLE:
11199         xxx_column_add_to_double(column, value);
11200         break;
11201     default:
11202         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11203 
11204     }
11205 
11206     return CPL_ERROR_NONE;
11207 
11208 }
11209 
11210 
11211 /* 
11212  * @brief
11213  *   Subtract a constant value from a numerical column.
11214  *
11215  * @param column   Target column.
11216  * @param value    Value to subtract.
11217  *
11218  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11219  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11220  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned.
11221  *
11222  * The operation is always performed in double precision, with a final
11223  * cast of the result to the target column type. Invalid flags are not
11224  * modified by this operation. Columns of strings or arrays are not allowed.
11225  */
11226 
11227 cpl_error_code xxx_column_subtract_scalar(xxx_column *column, double value)
11228 {
11229 
11230     return xxx_column_add_scalar(column, -value);
11231 
11232 }
11233 
11234 
11235 /* 
11236  * @brief
11237  *   Multiply by a constant a numerical column.
11238  *
11239  * @param column   Target column.
11240  * @param value    Multiplier.
11241  *
11242  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11243  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11244  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned.
11245  *
11246  * The operation is always performed in double precision, with a final
11247  * cast of the result to the target column type. Invalid flags are not
11248  * modified by this operation. Columns of strings or arrays are not allowed.
11249  */
11250 
11251 cpl_error_code xxx_column_multiply_scalar(xxx_column *column, double value)
11252 {
11253 
11254     const char *fid  = "xxx_column_multiply_scalar";
11255     cpl_type     type = xxx_column_get_type(column);
11256 
11257 
11258     if (column == 0x0)
11259         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11260 
11261 
11262     switch (type) {
11263 
11264     case CPL_TYPE_INT:
11265         xxx_column_mul_double_to_int(column, value);
11266         break;
11267     case CPL_TYPE_FLOAT:
11268         xxx_column_mul_double_to_float(column, value);
11269         break;
11270     case CPL_TYPE_DOUBLE:
11271         xxx_column_mul_to_double(column, value);
11272         break;
11273     default:
11274         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11275 
11276     }
11277 
11278     return CPL_ERROR_NONE;
11279 
11280 }
11281 
11282 
11283 /* 
11284  * @brief
11285  *   Divide by a constant a numerical column.
11286  *
11287  * @param column   Target column.
11288  * @param value    Divisor.
11289  *
11290  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11291  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11292  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned. If the input 
11293  *   @em value is zero, a @c CPL_ERROR_DIVISION_BY_ZERO is returned.
11294  *
11295  * The operation is always performed in double precision, with a final
11296  * cast of the result to the target column type. Invalid flags are not
11297  * modified by this operation. Columns of strings or arrays are not allowed.
11298  */
11299 
11300 cpl_error_code xxx_column_divide_scalar(xxx_column *column, double value)
11301 {
11302 
11303     const char *fid  = "xxx_column_divide_scalar";
11304     cpl_type     type = xxx_column_get_type(column);
11305 
11306     
11307     if (column == 0x0)
11308         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11309 
11310 
11311     if (value == 0.0)
11312         return cpl_error_set(fid, CPL_ERROR_DIVISION_BY_ZERO);
11313 
11314     value = 1 / value;
11315 
11316     switch (type) {
11317 
11318     case CPL_TYPE_INT:
11319         xxx_column_mul_double_to_int(column, value);
11320         break;
11321     case CPL_TYPE_FLOAT:
11322         xxx_column_mul_double_to_float(column, value);
11323         break;
11324     case CPL_TYPE_DOUBLE:
11325         xxx_column_mul_to_double(column, value);
11326         break;
11327     default:
11328         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11329 
11330     }
11331 
11332     return CPL_ERROR_NONE;
11333 
11334 }
11335 
11336 
11337 /* 
11338  * @brief
11339  *   Compute the mean value of a numeric column.
11340  *
11341  * @param column   Input column.
11342  *
11343  * @return Mean value. In case of error, this is set to 0.0.
11344  * 
11345  * If the input @em column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is
11346  * set. If the accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE 
11347  * is set. If the input column elements are all invalid, or the column has
11348  * zero length, a @c CPL_ERROR_DATA_NOT_FOUND is set.
11349  *
11350  * Column values marked as invalid are excluded from the computation. 
11351  * The column must contain at least one valid value. Columns of strings or
11352  * arrays are not allowed.
11353  */
11354 
11355 double xxx_column_get_mean(xxx_column *column)
11356 {
11357 
11358     const char *fid       = "xxx_column_get_mean";
11359     int          length    = xxx_column_get_size(column);
11360     int          nullcount = xxx_column_count_invalid(column);
11361     cpl_type     type      = xxx_column_get_type(column);
11362     double       mean      = 0.0;
11363     int          count     = length - nullcount;
11364     int          i;
11365 
11366     int         *np;
11367     int         *ip;
11368     float       *fp;
11369     double      *dp;
11370 
11371     
11372     if (column == 0x0) {
11373         cpl_error_set_where(fid);
11374         return 0.0;
11375     }
11376 
11377 
11378     if (nullcount == length || length == 0) {
11379         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11380         return 0.0;
11381     }
11382 
11383     np = column->null;
11384 
11385     switch (type) {
11386 
11387     case CPL_TYPE_INT:
11388         ip = column->values->i;
11389         if (nullcount == 0)
11390             for (i = 0; i < length; i++)
11391                 mean += *ip++;
11392         else
11393             for (i = 0; i < length; i++, ip++, np++)
11394                 if (*np == 0)
11395                     mean += *ip;
11396         break;
11397 
11398     case CPL_TYPE_FLOAT:
11399         fp = column->values->f;
11400         if (nullcount == 0)
11401             for (i = 0; i < length; i++)
11402                 mean += *fp++;
11403         else
11404             for (i = 0; i < length; i++, fp++, np++)
11405                 if (*np == 0)
11406                     mean += *fp;
11407         break;
11408 
11409     case CPL_TYPE_DOUBLE:
11410         dp = column->values->d;
11411         if (nullcount == 0)
11412             for (i = 0; i < length; i++)
11413                 mean += *dp++;
11414         else
11415             for (i = 0; i < length; i++, dp++, np++)
11416                 if (*np == 0)
11417                     mean += *dp;
11418         break;
11419 
11420     default:
11421         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11422 
11423     }
11424 
11425     return (mean / count);
11426 
11427 }
11428 
11429 
11430 double xxx_column_get_stdev(xxx_column *column)
11431 {
11432 
11433     const char *fid       = "xxx_column_get_stdev";
11434     int          length    = xxx_column_get_size(column);
11435     int          nullcount = xxx_column_count_invalid(column);
11436     cpl_type     type      = xxx_column_get_type(column);
11437     double       stdev     = 0.0;
11438     double       mean;
11439     int          count     = length - nullcount;
11440     int          i;
11441 
11442     int         *np;
11443     int         *ip;
11444     float       *fp;
11445     double      *dp;
11446 
11447 
11448     if (column == 0x0) {
11449         cpl_error_set_where(fid);
11450         return 0.0;
11451     }
11452 
11453 
11454     if (nullcount == length || length == 0) {
11455         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11456         return 0.0;
11457     }
11458 
11459     if (count == 1)
11460       return 0.0;
11461 
11462     mean = xxx_column_get_mean(column);
11463 
11464     np = column->null;
11465 
11466     switch (type) {
11467 
11468     case CPL_TYPE_INT:
11469         ip = column->values->i;
11470         if (nullcount == 0)
11471             for (i = 0; i < length; i++, ip++)
11472                 stdev += (*ip - mean) * (*ip - mean);
11473         else
11474             for (i = 0; i < length; i++, ip++, np++)
11475                 if (*np == 0)
11476                     stdev += (*ip - mean) * (*ip - mean);
11477         break;
11478 
11479     case CPL_TYPE_FLOAT:
11480         fp = column->values->f;
11481         if (nullcount == 0)
11482             for (i = 0; i < length; i++, fp++)
11483                 stdev += (*fp - mean) * (*fp - mean);
11484         else
11485             for (i = 0; i < length; i++, fp++, np++)
11486                 if (*np == 0)
11487                     stdev += (*fp - mean) * (*fp - mean);
11488         break;
11489 
11490     case CPL_TYPE_DOUBLE:
11491         dp = column->values->d;
11492         if (nullcount == 0)
11493             for (i = 0; i < length; i++, dp++)
11494                 stdev += (*dp - mean) * (*dp - mean);
11495         else
11496             for (i = 0; i < length; i++, dp++, np++)
11497                 if (*np == 0)
11498                     stdev += (*dp - mean) * (*dp - mean);
11499         break;
11500 
11501     default:
11502         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11503 
11504     }
11505 
11506     return sqrt(stdev / (count - 1));
11507 
11508 }
11509 
11510 
11511 /* 
11512  * @brief
11513  *   Get maximum value in a numerical column.
11514  *
11515  * @param column   Input column.
11516  *
11517  * @return Maximum value. In case of error, this is set to 0.0.
11518  *
11519  * If the input @em column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is
11520  * set. If the accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
11521  * is set. If the input column elements are all invalid, or the column has
11522  * zero length, a @c CPL_ERROR_DATA_NOT_FOUND is set.
11523  *
11524  * Column values marked as invalid are excluded from the search. 
11525  * The column must contain at least one valid value. Columns of strings or
11526  * arrays are not allowed.
11527  */
11528 
11529 double xxx_column_get_max(xxx_column *column)
11530 {
11531 
11532     const char *fid       = "xxx_column_get_max";
11533     int          length    = xxx_column_get_size(column);
11534     int          nullcount = xxx_column_count_invalid(column);
11535     cpl_type     type      = xxx_column_get_type(column);
11536     int          first     = 1;
11537     int         *ip;
11538     float       *fp;
11539     double      *dp;
11540     int         *np;
11541     double       maximum = 0;
11542     int          i;
11543 
11544 
11545     if (column == 0x0) {
11546         cpl_error_set_where(fid);
11547         return 0.0;
11548     }
11549 
11550     if (nullcount == length || length == 0) {
11551         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11552         return 0.0;
11553     }
11554 
11555     np = column->null;
11556 
11557     switch (type) {
11558     case CPL_TYPE_INT:
11559         ip = column->values->i;
11560         if (length == 1)
11561             return *ip;
11562         if (nullcount == 0) {
11563             maximum = *ip++;
11564             for (i = 1; i < length; i++, ip++)
11565                 if (maximum < *ip)
11566                     maximum = *ip;
11567         }
11568         else {
11569             for (i = 0; i < length; i++, ip++, np++) {
11570                 if (*np == 0) {
11571                     if (first) {
11572                         first = 0;
11573                         maximum = *ip;
11574                     }
11575                     else
11576                         if (maximum < *ip)
11577                             maximum = *ip;
11578                 }
11579             }
11580         }
11581         break;
11582     case CPL_TYPE_FLOAT:
11583         fp = column->values->f;
11584         if (length == 1)
11585             return *fp;
11586         if (nullcount == 0) {
11587             maximum = *fp++;
11588             for (i = 1; i < length; i++, fp++)
11589                 if (maximum < *fp)
11590                     maximum = *fp;
11591         }
11592         else {
11593             for (i = 0; i < length; i++, fp++, np++) {
11594                 if (*np == 0) {
11595                     if (first) {
11596                         first = 0;
11597                         maximum = *fp;
11598                     }
11599                     else
11600                         if (maximum < *fp)
11601                             maximum = *fp;
11602                 }
11603             }
11604         }
11605         break;
11606     case CPL_TYPE_DOUBLE:
11607         dp = column->values->d;
11608         if (length == 1)
11609             return *dp;
11610         if (nullcount == 0) {
11611             maximum = *dp++;
11612             for (i = 1; i < length; i++, dp++) 
11613                 if (maximum < *dp) 
11614                     maximum = *dp;
11615         }
11616         else {
11617             for (i = 0; i < length; i++, dp++, np++) {
11618                 if (*np == 0) {
11619                     if (first) {
11620                         first = 0;
11621                         maximum = *dp;
11622                     }
11623                     else 
11624                         if (maximum < *dp) 
11625                             maximum = *dp;
11626                 }
11627             }
11628         }
11629         break;
11630     default:
11631         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11632         return 0.0;
11633     }
11634 
11635     return maximum;
11636 
11637 }
11638 
11639 
11640 /* 
11641  * @brief
11642  *   Get minimum value in a numerical column.
11643  *
11644  * @param column   Input column.
11645  *
11646  * @return Minimum value. In case of error, this is set to 0.0.
11647  *
11648  * If the input @em column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is
11649  * set. If the accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
11650  * is set. If the input column elements are all invalid, or the column has
11651  * zero length, a @c CPL_ERROR_DATA_NOT_FOUND is set.
11652  *
11653  * Column values marked as invalid are excluded from the search.
11654  * The column must contain at least one valid value. Columns of strings or
11655  * arrays are not allowed.
11656  */ 
11657 
11658 double xxx_column_get_min(xxx_column *column)
11659 {
11660 
11661     const char *fid       = "xxx_column_get_min";
11662     int          length    = xxx_column_get_size(column);
11663     int          nullcount = xxx_column_count_invalid(column);
11664     cpl_type     type      = xxx_column_get_type(column);
11665     int          first     = 1;
11666     int         *ip;
11667     float       *fp;
11668     double      *dp;
11669     int         *np;
11670     double       minimum= 0;
11671     int          i;
11672 
11673 
11674     if (column == 0x0) {
11675         cpl_error_set_where(fid);
11676         return 0.0;
11677     }
11678 
11679     if (nullcount == length || length == 0) {
11680         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11681         return 0.0;
11682     }
11683 
11684     np = column->null;
11685 
11686     switch (type) {
11687     case CPL_TYPE_INT:
11688         ip = column->values->i;
11689         if (length == 1)
11690             return *ip;
11691         if (nullcount == 0) {
11692             minimum = *ip++;
11693             for (i = 1; i < length; i++, ip++) 
11694                 if (minimum > *ip) 
11695                     minimum = *ip;
11696         }
11697         else {
11698             for (i = 0; i < length; i++, ip++, np++) {
11699                 if (*np == 0) {
11700                     if (first) {
11701                         first = 0;
11702                         minimum = *ip;
11703                     }
11704                     else 
11705                         if (minimum > *ip) 
11706                             minimum = *ip;
11707                 }
11708             }
11709         }
11710         break;
11711     case CPL_TYPE_FLOAT:
11712         fp = column->values->f;
11713         if (length == 1)
11714             return *fp;
11715         if (nullcount == 0) {
11716             minimum = *fp++;
11717             for (i = 1; i < length; i++, fp++) 
11718                 if (minimum > *fp) 
11719                     minimum = *fp;
11720         }
11721         else {
11722             for (i = 0; i < length; i++, fp++, np++) {
11723                 if (*np == 0) {
11724                     if (first) {
11725                         first = 0;
11726                         minimum = *fp;
11727                     }
11728                     else 
11729                         if (minimum > *fp) 
11730                             minimum = *fp;
11731                 }
11732             }
11733         }
11734         break;
11735     case CPL_TYPE_DOUBLE:
11736         dp = column->values->d;
11737         if (length == 1)
11738             return *dp;
11739         if (nullcount == 0) {
11740             minimum = *dp++;
11741             for (i = 1; i < length; i++, dp++) 
11742                 if (minimum > *dp) 
11743                     minimum = *dp;
11744         }
11745         else {
11746             for (i = 0; i < length; i++, dp++, np++) {
11747                 if (*np == 0) {
11748                     if (first) {
11749                         first = 0;
11750                         minimum = *dp;
11751                     }
11752                     else 
11753                         if (minimum > *dp) 
11754                             minimum = *dp;
11755                 }
11756             }
11757         }
11758         break;
11759     default:
11760         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11761         return 0.0;
11762     }
11763 
11764     return minimum;
11765 
11766 }
11767 
11768 
11769 /* 
11770  * @brief
11771  *   Get position of maximum in a numerical column.
11772  *
11773  * @param column   Input column.
11774  * @param indx     Returned position of maximum value.
11775  *
11776  * @return @c CPL_ERROR_NONE on success. If any input argument is a 
11777  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the 
11778  *   accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
11779  *   is returned. If the input column elements are all invalid, or 
11780  *   the column has zero length, a @c CPL_ERROR_DATA_NOT_FOUND is 
11781  *   returned.
11782  *
11783  * Column values marked as invalid are excluded from the search.
11784  * The @em indx argument will be assigned the position of the maximum 
11785  * value. Indexes are counted starting from 0. If more than one column 
11786  * element correspond to the max value, the position with the lowest 
11787  * indx is returned. In case of error, @em indx is set to zero. 
11788  * Columns of strings or arrays are not allowed.
11789  */ 
11790     
11791 cpl_error_code xxx_column_get_maxpos(xxx_column *column, int *indx)
11792 {
11793 
11794     const char *fid       = "xxx_column_get_maxpos";
11795     int          length    = xxx_column_get_size(column);
11796     int          nullcount = xxx_column_count_invalid(column);
11797     cpl_type     type      = xxx_column_get_type(column);
11798     int          first     = 1;
11799     int         *ip;
11800     float       *fp;
11801     double      *dp;
11802     int         *np;
11803     double       maximum=0;
11804     int          i;
11805 
11806 
11807     if (column == 0x0 || indx == 0x0)
11808         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11809 
11810     if (nullcount == length || length == 0)
11811         return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11812 
11813     *indx = 0;
11814 
11815     if (length == 1)
11816         return CPL_ERROR_NONE;
11817 
11818     np = column->null;
11819 
11820     switch (type) {
11821     case CPL_TYPE_INT:
11822         ip = column->values->i;
11823         if (nullcount == 0) {
11824             maximum = *ip++;
11825             for (i = 1; i < length; i++, ip++) {
11826                 if (maximum < *ip) {
11827                     maximum = *ip;
11828                     *indx = i;
11829                 }
11830             }
11831         }
11832         else {
11833             for (i = 0; i < length; i++, ip++, np++) {
11834                 if (*np == 0) {
11835                     if (first) {
11836                         first = 0;
11837                         maximum = *ip;
11838                         *indx = i;
11839                     }
11840                     else {
11841                         if (maximum < *ip) {
11842                             maximum = *ip;
11843                             *indx = i;
11844                         }
11845                     }
11846                 }
11847             }
11848         }
11849         break;
11850     case CPL_TYPE_FLOAT:
11851         fp = column->values->f;
11852         if (nullcount == 0) {
11853             maximum = *fp++;
11854             for (i = 1; i < length; i++, fp++) {
11855                 if (maximum < *fp) {
11856                     maximum = *fp;
11857                     *indx = i;
11858                 }
11859             }
11860         }
11861         else {
11862             for (i = 0; i < length; i++, fp++, np++) {
11863                 if (*np == 0) {
11864                     if (first) {
11865                         first = 0;
11866                         maximum = *fp;
11867                         *indx = i;
11868                     }
11869                     else {
11870                         if (maximum < *fp) {
11871                             maximum = *fp;
11872                             *indx = i;
11873                         }
11874                     }
11875                 }
11876             }
11877         }
11878         break;
11879     case CPL_TYPE_DOUBLE:
11880         dp = column->values->d;
11881         if (nullcount == 0) {
11882             maximum = *dp++;
11883             for (i = 1; i < length; i++, dp++) {
11884                 if (maximum < *dp) {
11885                     maximum = *dp;
11886                     *indx = i;
11887                 }
11888             }
11889         }
11890         else {
11891             for (i = 0; i < length; i++, dp++, np++) {
11892                 if (*np == 0) {
11893                     if (first) {
11894                         first = 0;
11895                         maximum = *dp;
11896                         *indx = i;
11897                     }
11898                     else {
11899                         if (maximum < *dp) {
11900                             maximum = *dp;
11901                             *indx = i;
11902                         }
11903                     }
11904                 }
11905             }
11906         }
11907         break;
11908     default:
11909         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11910     }
11911 
11912     return CPL_ERROR_NONE;
11913 
11914 }
11915 
11916 
11917 /* 
11918  * @brief
11919  *   Get position of minimum in a numerical column.
11920  *
11921  * @param column   Input column.
11922  * @param indx     Returned position of minimum value.
11923  *
11924  * @return @c CPL_ERROR_NONE on success. If any input argument is a
11925  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
11926  *   accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
11927  *   is returned. If the input column elements are all invalid, or
11928  *   the column has zero length, a @c CPL_ERROR_DATA_NOT_FOUND is
11929  *   returned.
11930  *
11931  * Column values marked as invalid are excluded from the search.
11932  * The @em indx argument will be assigned the position of the minimum
11933  * value. Indexes are counted starting from 0. If more than one column
11934  * element correspond to the min value, the position with the lowest
11935  * index is returned. In case of error, @em indx is set to zero.
11936  * Columns of strings or arrays are not allowed.
11937  */
11938 
11939 cpl_error_code xxx_column_get_minpos(xxx_column *column, int *indx)
11940 {
11941 
11942     const char *fid       = "xxx_column_get_minpos";
11943     int          length    = xxx_column_get_size(column);
11944     int          nullcount = xxx_column_count_invalid(column);
11945     cpl_type     type      = xxx_column_get_type(column);
11946     int          first     = 1;
11947     int         *ip;
11948     float       *fp;
11949     double      *dp;
11950     int         *np;
11951     double       minimum=0;
11952     int          i;
11953 
11954 
11955     if (column == 0x0 || indx == 0x0)
11956         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11957 
11958     if (nullcount == length || length == 0)
11959         return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11960 
11961     *indx = 0;
11962 
11963     if (length == 1)
11964         return CPL_ERROR_NONE;
11965 
11966     np = column->null;
11967 
11968     switch (type) {
11969     case CPL_TYPE_INT:
11970         ip = column->values->i;
11971         if (nullcount == 0) {
11972             minimum = *ip++;
11973             for (i = 1; i < length; i++, ip++) {
11974                 if (minimum > *ip) {
11975                     minimum = *ip;
11976                     *indx = i;
11977                 }
11978             }
11979         }
11980         else {
11981             for (i = 0; i < length; i++, ip++, np++) {
11982                 if (*np == 0) {
11983                     if (first) {
11984                         first = 0;
11985                         minimum = *ip;
11986                         *indx = i;
11987                     }
11988                     else {
11989                         if (minimum > *ip) {
11990                             minimum = *ip;
11991                             *indx = i;
11992                         }
11993                     }
11994                 }
11995             }
11996         }
11997         break;
11998     case CPL_TYPE_FLOAT:
11999         fp = column->values->f;
12000         if (nullcount == 0) {
12001             minimum = *fp++;
12002             for (i = 1; i < length; i++, fp++) {
12003                 if (minimum > *fp) {
12004                     minimum = *fp;
12005                     *indx = i;
12006                 }
12007             }
12008         }
12009         else {
12010             for (i = 0; i < length; i++, fp++, np++) {
12011                 if (*np == 0) {
12012                     if (first) {
12013                         first = 0;
12014                         minimum = *fp;
12015                         *indx = i;
12016                     }
12017                     else {
12018                         if (minimum > *fp) {
12019                             minimum = *fp;
12020                             *indx = i;
12021                         }
12022                     }
12023                 }
12024             }
12025         }
12026         break;
12027     case CPL_TYPE_DOUBLE:
12028         dp = column->values->d;
12029         if (nullcount == 0) {
12030             minimum = *dp++;
12031             for (i = 1; i < length; i++, dp++) {
12032                 if (minimum > *dp) {
12033                     minimum = *dp;
12034                     *indx = i;
12035                 }
12036             }
12037         }
12038         else {
12039             for (i = 0; i < length; i++, dp++, np++) {
12040                 if (*np == 0) {
12041                     if (first) {
12042                         first = 0;
12043                         minimum = *dp;
12044                         *indx = i;
12045                     }
12046                     else {
12047                         if (minimum > *dp) {
12048                             minimum = *dp;
12049                             *indx = i;
12050                         }
12051                     }
12052                 }
12053             }
12054         }
12055         break;
12056     default:
12057         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
12058     }
12059 
12060     return CPL_ERROR_NONE;
12061 
12062 }
12063 
12064 
12065 /*
12066  * @brief
12067  *   Find the median of an integer column.
12068  *
12069  * @param column   Input column.
12070  *
12071  * @return Median.
12072  *
12073  * Invalid column values are excluded from the search. 
12074  * The column must contain at least one valid value.
12075  * In case of failure, zero is returned. Columns of strings or
12076  * arrays are not allowed.
12077  */
12078 
12079 static int xxx_column_median_int(xxx_column *column)
12080 {
12081 
12082     int          length    = xxx_column_get_size(column);
12083     int          nullcount = xxx_column_count_invalid(column);
12084     int          median    = 0;
12085     int          i, n;
12086     int         *np;
12087     int         *ip;
12088     int         *cip;
12089     int         *copybuf;
12090 
12091 
12092     n = length - nullcount;
12093     cip = copybuf = cpl_malloc(n * sizeof(int));
12094     ip = column->values->i;
12095     np = column->null;
12096 
12097     if (nullcount) {
12098         for (i = 0; i < length; i++, np++, ip++) {
12099             if (*np == 0) {
12100                 *cip = *ip;
12101                 cip++;
12102             }
12103         }
12104     }
12105     else
12106         memcpy(copybuf, ip, length * sizeof(int));
12107 
12108     median = xxx_tools_get_median_int(copybuf, n);
12109     cpl_free(copybuf);
12110 
12111     return median;
12112 
12113 }
12114 
12115 
12116 /*
12117  * @brief
12118  *   Find the median of a float column.
12119  *
12120  * @param column   Input column.
12121  *
12122  * @return Median.
12123  *
12124  * Column values flagged as NULLs are excluded from the search. 
12125  * The column must contain at least one non-NULL value.
12126  * In case of failure, zero is returned. Columns of strings or
12127  * arrays are not allowed.
12128  */
12129 
12130 static float xxx_column_median_float(xxx_column *column)
12131 {
12132 
12133     int             length    = xxx_column_get_size(column);
12134     int             nullcount = xxx_column_count_invalid(column);
12135     float           median    = 0;
12136     int             i, n;
12137     int            *np;
12138     float          *fp;
12139     float          *cfp;
12140     float          *copybuf;
12141 
12142 
12143     n = length - nullcount;
12144     cfp = copybuf = cpl_malloc(n * sizeof(float));
12145     fp = column->values->f;
12146     np = column->null;
12147 
12148     if (nullcount) {
12149         for (i = 0; i < length; i++, np++, fp++) {
12150             if (*np == 0) {
12151                 *cfp = *fp;
12152                 cfp++;
12153             }
12154         }
12155     }
12156     else
12157         memcpy(copybuf, fp, length * sizeof(float));
12158 
12159     median = xxx_tools_get_median_float(copybuf, n);
12160     cpl_free(copybuf);
12161 
12162     return median;
12163 
12164 }
12165 
12166 
12167 /*
12168  * @brief
12169  *   Find the median of a double column.
12170  *
12171  * @param column   Input column.
12172  *
12173  * @return Median.
12174  *
12175  * Column values flagged as NULLs are excluded from the search. 
12176  * The column must contain at least one non-NULL value.
12177  * In case of failure, zero is returned.
12178  */
12179 
12180 static double xxx_column_median_double(xxx_column *column)
12181 {
12182 
12183     int             length    = xxx_column_get_size(column);
12184     int             nullcount = xxx_column_count_invalid(column);
12185     double          median    = 0;
12186     int             i, n;
12187     int            *np;
12188     double         *dp;
12189     double         *cdp;
12190     double         *copybuf;
12191 
12192 
12193     n = length - nullcount;
12194     cdp = copybuf = cpl_malloc(n * sizeof(double));
12195     dp = column->values->d;
12196     np = column->null;
12197 
12198     if (nullcount) {
12199         for (i = 0; i < length; i++, np++, dp++) {
12200             if (*np == 0) {
12201                 *cdp = *dp;
12202                 cdp++;
12203             }
12204         }
12205     }
12206     else
12207         memcpy(copybuf, dp, length * sizeof(double));
12208 
12209     median = xxx_tools_get_median_double(copybuf, n);
12210     cpl_free(copybuf);
12211 
12212     return median;
12213 
12214 }
12215 
12216 
12217 /* 
12218  * @brief
12219  *   Find the median of a numerical column.
12220  *
12221  * @param column   Input column.
12222  *
12223  * @return Median. In case of error, 0.0 is always returned.
12224  *
12225  * If the input column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is set.
12226  * If the accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE is 
12227  * set. If the input column elements are all invalid, or the column has zero 
12228  * length, a @c CPL_ERROR_DATA_NOT_FOUND is returned. Invalid column elements 
12229  * are excluded from the computation. The column must contain at least one 
12230  * valid elements. Columns of strings or arrays are not allowed.
12231  */
12232 
12233 double xxx_column_get_median(xxx_column *column)
12234 {
12235 
12236     const char *fid       = "xxx_column_get_median";
12237     cpl_type     type      = xxx_column_get_type(column);
12238     int          length    = xxx_column_get_size(column);
12239     int          nullcount = xxx_column_count_invalid(column);
12240 
12241 
12242     if (column == 0x0) {
12243         cpl_error_set_where(fid);
12244         return 0.0;
12245     }
12246 
12247     if (nullcount == length || length == 0) {
12248         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
12249         return 0.0;
12250     }
12251 
12252     switch (type) {
12253     case CPL_TYPE_INT:
12254         return (double)xxx_column_median_int(column);
12255     case CPL_TYPE_FLOAT:
12256         return (double)xxx_column_median_float(column);
12257     case CPL_TYPE_DOUBLE:
12258         return xxx_column_median_double(column);
12259     default:
12260         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
12261     }
12262 
12263     return 0.0;
12264 
12265 }
12266 
12267 
12268 /*
12269  * @brief
12270  *   Shift numeric column elements.
12271  *
12272  * @param column   Input column.
12273  * @param shift    Shift column values by so many elements.
12274  *
12275  * @return @c CPL_ERROR_NONE on success. If the input @em column is a
12276  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
12277  *   accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
12278  *   is returned. The specified shift must be in module less than 
12279  *   the column length, or a @c CPL_ERROR_ILLEGAL_INPUT is returned.
12280  *
12281  * All column elements are shifted by the specified amount. If @em shift 
12282  * is positive, all elements will be moved toward the bottom of the column, 
12283  * otherwise toward its top. The column elements that are left undefined 
12284  * at either end of the column are marked as invalid. Columns of strings or
12285  * arrays are not allowed.
12286  */
12287 
12288 cpl_error_code xxx_column_shift(xxx_column *column, int shift)
12289 {
12290     
12291     const char *fid    = "xxx_column_shift";
12292     cpl_type     type   = xxx_column_get_type(column);
12293     int          length = xxx_column_get_size(column);
12294     int          j;
12295     int          status;
12296     int         *np1;
12297     int         *np2;
12298     int         *ip1;
12299     int         *ip2;
12300     float       *fp1;
12301     float       *fp2;
12302     double      *dp1;
12303     double      *dp2;
12304 
12305 
12306     if (column == 0x0)
12307         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
12308 
12309 
12310     /*
12311      *  Allowed column types:
12312      */
12313 
12314     switch (type) {
12315     case CPL_TYPE_INT:
12316     case CPL_TYPE_FLOAT:
12317     case CPL_TYPE_DOUBLE:
12318         break;
12319     default:
12320         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
12321     }
12322 
12323     if (abs(shift) >= length)
12324         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
12325 
12326     if (shift == 0)
12327         return CPL_ERROR_NONE;
12328 
12329     if (column->nullcount == length)
12330         return CPL_ERROR_NONE;
12331 
12332 
12333     /*
12334      *  Invalid flags buffer handling first (because it may fail...)
12335      */
12336 
12337     if (column->nullcount) {
12338         if (shift > 0) {
12339             j = length - shift;
12340             np1 = column->null + length;
12341             np2 = np1 - shift;
12342             while (j--)
12343                 *--np1 = *--np2;
12344         }
12345         else {
12346             j = -shift;
12347             np1 = column->null;
12348             np2 = np1 - shift;
12349             while(j++ < length)
12350                 *np1++ = *np2++;
12351         }
12352 
12353     }
12354 
12355 
12356    /*
12357     *  Invalidate the leftovers
12358     */
12359 
12360     if (shift > 0)
12361         status = xxx_column_fill_invalid(column, 0, shift);
12362     else
12363         status = xxx_column_fill_invalid(column, length + shift, -shift);
12364 
12365     if (status)
12366         return status;
12367 
12368 
12369    /*
12370     *  Now shift the data.
12371     */
12372 
12373     switch (type) {
12374 
12375     case CPL_TYPE_INT:
12376         if (shift > 0) {
12377             j = length - shift;
12378             ip1 = column->values->i + length;
12379             ip2 = ip1 - shift;
12380             while (j--)
12381                 *--ip1 = *--ip2;
12382         }
12383         else {
12384             j = -shift;
12385             ip1 = column->values->i;
12386             ip2 = ip1 - shift;
12387             while(j++ < length)
12388                 *ip1++ = *ip2++;
12389         }
12390         break;
12391 
12392     case CPL_TYPE_FLOAT:
12393         if (shift > 0) {
12394             j = length - shift;
12395             fp1 = column->values->f + length;
12396             fp2 = fp1 - shift;
12397             while (j--)
12398                 *--fp1 = *--fp2;
12399         }
12400         else {  
12401             j = -shift;
12402             fp1 = column->values->f;
12403             fp2 = fp1 - shift;
12404             while(j++ < length)
12405                 *fp1++ = *fp2++;
12406         }
12407         break;
12408 
12409     case CPL_TYPE_DOUBLE:
12410         if (shift > 0) {
12411             j = length - shift;
12412             dp1 = column->values->d + length;
12413             dp2 = dp1 - shift;
12414             while (j--)
12415                 *--dp1 = *--dp2;
12416         }
12417         else {  
12418             j = -shift;
12419             dp1 = column->values->d;
12420             dp2 = dp1 - shift;
12421             while(j++ < length)
12422                 *dp1++ = *dp2++;
12423         }
12424         break;
12425 
12426     default:
12427         break;
12428     }
12429 
12430     return CPL_ERROR_NONE;
12431 
12432 }
12433 
12434 
12435 /* 
12436  * @brief
12437  *   Assign to invalid @em integer column elements a numeric code.
12438  *
12439  * @param column   Input column.
12440  * @param code     Code to write at invalid column elements.
12441  *
12442  * @return @c CPL_ERROR_NONE on success.  If the input @em column is a
12443  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
12444  *   accessed column is not @em integer or arrays of integers, 
12445  *   a @c CPL_ERROR_TYPE_MISMATCH is returned.
12446  *
12447  * In general the column elements that are marked as invalid
12448  * may contain any value, that should not be given any meaning
12449  * whatsoever. In order to export the column data (using a call
12450  * to @c xxx_column_get_data_int() ) to procedures that are external
12451  * to the CPL column system, it may turn out to be appropriate
12452  * assigning to all the invalid elements a special code value.
12453  * This code value will supposedly be recognized and handled
12454  * properly by the foreign method. Note that only existing invalid
12455  * elements will be coded as indicated: new invalid column elements 
12456  * would still have their actual values undefined. Also, any further 
12457  * processing of the column would not take care of maintaining the 
12458  * assigned code to a given invalid column element: therefore the 
12459  * code should be set just before it is actually needed.
12460  *
12461  * @note
12462  *   Assigning a code to an invalid element doesn't make it valid.
12463  */
12464 
12465 
12466 /* 
12467  * @brief
12468  *   Assign to invalid @em float column elements a numeric code.
12469  *
12470  * @param column   Input column.
12471  * @param code     Code to write at invalid column elements.
12472  *
12473  * @return @c CPL_ERROR_NONE on success.  If the input @em column is a
12474  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
12475  *   accessed column is not @em float or array of floats, 
12476  *   a @c CPL_ERROR_TYPE_MISMATCH is returned.
12477  *
12478  * In general the column elements that are marked as invalid
12479  * may contain any value, that should not be given any meaning
12480  * whatsoever. In order to export the column data (using a call
12481  * to @c xxx_column_get_data_float() ) to procedures that are external
12482  * to the CPL column system, it may turn out to be appropriate
12483  * assigning to all the invalid elements a special code value.
12484  * This code value will supposedly be recognized and handled
12485  * properly by the foreign method. Note that only existing invalid
12486  * elements will be coded as indicated: new invalid column elements
12487  * would still have their actual values undefined. Also, any further
12488  * processing of the column would not take care of maintaining the
12489  * assigned code to a given invalid column element: therefore the
12490  * code should be set just before it is actually needed.
12491  *
12492  * @note
12493  *   Assigning a code to an invalid element doesn't make it valid.
12494  */
12495 
12496 
12497 
12498 /* 
12499  * @brief
12500  *   Assign to invalid @em double column elements a numeric code.
12501  *
12502  * @param column   Input column.
12503  * @param code     Code to write at invalid column elements.
12504  *
12505  * @return @c CPL_ERROR_NONE on success.  If the input @em column is a
12506  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
12507  *   accessed column is not @em doubleor array of doubles, 
12508  *   a @c CPL_ERROR_TYPE_MISMATCH is returned.
12509  *
12510  * In general the column elements that are marked as invalid
12511  * may contain any value, that should not be given any meaning
12512  * whatsoever. In order to export the column data (using a call
12513  * to @c xxx_column_get_data_double() ) to procedures that are external
12514  * to the CPL column system, it may turn out to be appropriate
12515  * assigning to all the invalid elements a special code value.
12516  * This code value will supposedly be recognized and handled
12517  * properly by the foreign method. Note that only existing invalid
12518  * elements will be coded as indicated: new invalid column elements
12519  * would still have their actual values undefined. Also, any further
12520  * processing of the column would not take care of maintaining the
12521  * assigned code to a given invalid column element: therefore the
12522  * code should be set just before it is actually needed.
12523  *
12524  * @note
12525  *   Assigning a code to an invalid element doesn't make it valid.
12526  */
12527 
12528 
12529 
12530 
12531 
12532 
12533 
12534 
12535 
12536 
12537 
12538 
12539 
12540 
12541 
12542 
12543 
12544 
12545 
12546 
12547 
12548 
12549 
12550 
12551 
12552 
12553 
12554 cpl_error_code
12555 uves_table_sort_dfsxxxx(cpl_table *table, const uves_propertylist *reflist)
12556 {
12557     return xxx_table_sort((xxx_table *)table, reflist);
12558 }
12559 
12560 
12561 
12562 
12563 
12564 /*----------------------------------------------------------------------------*/
12570 /*----------------------------------------------------------------------------*/
12571 int
12572 uves_table_and_selected_invalid(cpl_table *t, const char *column)
12573 {
12574     if (cpl_table_get_column_type(t, column) != CPL_TYPE_STRING)
12575         {
12576             return cpl_table_and_selected_invalid(t, column);
12577         }
12578     else
12579         {
12580             int i = 0;
12581             for (i = 0; i < cpl_table_get_nrow(t); i++)
12582                 {
12583                     if (cpl_table_is_selected(t, i))
12584                         {
12585                             if (cpl_table_is_valid(t, column, i))
12586                                 {
12587                                     cpl_table_unselect_row(t, i);
12588                                 }
12589                             /* else keep it selected */
12590                         }
12591                     /* else unselected, don't change */
12592                 }
12593 
12594             return cpl_table_count_selected(t);
12595         }
12596 }
12597 
12598     
12599 /*----------------------------------------------------------------------------*/
12616 /*----------------------------------------------------------------------------*/
12617 int
12618 uves_erase_invalid_table_rows(cpl_table *t, const char *column)
12619 {
12620     int result = 0;
12621 
12622     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12623 
12624     if (column == NULL)
12625     /* Loop through all columns */
12626     {
12627         const char *name;
12628         cpl_table *argument = t;
12629         result = 0;
12630         while ( (name = cpl_table_get_column_name(argument)) != NULL)
12631         {
12632             int n_deleted_rows;
12633 
12634             argument = NULL;
12635             n_deleted_rows = uves_erase_invalid_table_rows(t, name);
12636 
12637             if (n_deleted_rows > 0) 
12638             {
12639                 uves_msg_low("%d rows with invalid '%s' removed", 
12640                      n_deleted_rows, name);
12641             }
12642             result += n_deleted_rows;
12643         }
12644     }
12645     else
12646     {
12647         assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT,
12648             "No such column: %s", column);
12649         
12650         check(( cpl_table_select_all(t),
12651             result = uves_table_and_selected_invalid(t, column), /* workaround here */
12652             uves_table_erase_selected_dfs02356(t)),              /* and here */
12653                   "Error deleting rows");
12654     }
12655     
12656   cleanup:
12657     return result;
12658 }
12659 
12660 /*----------------------------------------------------------------------------*/
12677 /*----------------------------------------------------------------------------*/
12678 cpl_table *
12679 uves_extract_table_rows(const cpl_table *t, const char *column,
12680             cpl_table_select_operator operator, double value)
12681 {
12682     cpl_table *result = NULL;
12683     
12684     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12685     assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT,
12686         "No such column: %s", column);
12687     
12688     /* 1. Extract (duplicate) the entire table
12689        2. remove rows *not* satisfying the criterion */
12690     check(( result = cpl_table_duplicate(t),
12691 
12692         uves_select_table_rows(result, column, operator, value),
12693         cpl_table_not_selected(result),  /* Inverses selection */
12694         
12695         uves_table_erase_selected_dfs02356(result)),
12696        
12697        "Error extracting rows");
12698 
12699     passure( cpl_table_count_selected(result) == cpl_table_get_nrow(result),
12700              "%d %d",
12701              cpl_table_count_selected(result), cpl_table_get_nrow(result) );
12702     
12703   cleanup:
12704     if (cpl_error_get_code() != CPL_ERROR_NONE)
12705     {
12706         uves_free_table(&result);
12707     }
12708     return result;
12709 }
12710 
12711 /*----------------------------------------------------------------------------*/
12723 /*----------------------------------------------------------------------------*/
12724 void
12725 uves_sort_table_1(cpl_table *t, const char *column, bool reverse)
12726 {
12727     uves_propertylist *plist = NULL;
12728     
12729     assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12730     assure(cpl_table_has_column(t, column), CPL_ERROR_ILLEGAL_INPUT, 
12731        "No column '%s'", column);
12732 
12733     check(( plist = uves_propertylist_new(),
12734         uves_propertylist_append_bool(plist, column, reverse)),
12735        "Could not create property list for sorting");
12736 
12737     check( uves_table_sort(t, plist), "Could not sort table");
12738 
12739   cleanup:
12740     uves_free_propertylist(&plist);
12741     return;
12742 }
12743 
12744 /*----------------------------------------------------------------------------*/
12760 /*----------------------------------------------------------------------------*/
12761 void
12762 uves_sort_table_2(cpl_table *t, const char *column1, const char *column2, 
12763           bool reverse1, bool reverse2)
12764 {
12765     uves_propertylist *plist = NULL;
12766     
12767     assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12768     assure(cpl_table_has_column(t, column1), CPL_ERROR_ILLEGAL_INPUT, 
12769        "No column '%s'", column1);
12770     assure(cpl_table_has_column(t, column2), CPL_ERROR_ILLEGAL_INPUT,
12771        "No column '%s'", column2);
12772 
12773     check(( plist = uves_propertylist_new(),
12774         uves_propertylist_append_bool(plist, column1, reverse1),
12775         uves_propertylist_append_bool(plist, column2, reverse2)),
12776        "Could not create property list for sorting");
12777     check( uves_table_sort(t, plist), "Could not sort table");
12778     
12779   cleanup:
12780     uves_free_propertylist(&plist);
12781     return;
12782 }
12783 /*----------------------------------------------------------------------------*/
12798 /*----------------------------------------------------------------------------*/
12799 void
12800 uves_sort_table_3(cpl_table *t, const char *column1, const char *column2, 
12801                   const char *column3,
12802           bool reverse1, bool reverse2, bool reverse3)
12803 {
12804     uves_propertylist *plist = NULL;
12805     
12806     assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12807     assure(cpl_table_has_column(t, column1), CPL_ERROR_ILLEGAL_INPUT, 
12808        "No column '%s'", column1);
12809     assure(cpl_table_has_column(t, column2), CPL_ERROR_ILLEGAL_INPUT,
12810        "No column '%s'", column2);
12811     assure(cpl_table_has_column(t, column3), CPL_ERROR_ILLEGAL_INPUT,
12812        "No column '%s'", column3);
12813 
12814     check(( plist = uves_propertylist_new(),
12815         uves_propertylist_append_bool(plist, column1, reverse1),
12816         uves_propertylist_append_bool(plist, column2, reverse2),
12817             uves_propertylist_append_bool(plist, column3, reverse3)),
12818         "Could not create property list for sorting");
12819     check( uves_table_sort(t, plist), "Could not sort table");
12820     
12821   cleanup:
12822     uves_free_propertylist(&plist);
12823     return;
12824 }
12825 
12826 /*----------------------------------------------------------------------------*/
12831 /*----------------------------------------------------------------------------*/
12832 void uves_free_image(cpl_image **i) 
12833 {if(i){cpl_image_delete(*i); *i = NULL;}}
12834 /*----------------------------------------------------------------------------*/
12839 /*----------------------------------------------------------------------------*/
12840 void uves_free_mask(cpl_mask **m)
12841 {if(m){cpl_mask_delete(*m); *m = NULL;}}
12842 /*----------------------------------------------------------------------------*/
12847 /*----------------------------------------------------------------------------*/
12848 void uves_free_imagelist(cpl_imagelist **i)
12849 {if(i){cpl_imagelist_delete(*i);        *i = NULL;}}
12850 
12851 /*----------------------------------------------------------------------------*/
12856 /*----------------------------------------------------------------------------*/
12857 void uves_free_table(cpl_table **t)
12858 {if(t){cpl_table_delete(*t);            *t = NULL;}}
12859 
12860 /*----------------------------------------------------------------------------*/
12865 /*----------------------------------------------------------------------------*/
12866 void uves_free_table_const(const cpl_table **t)
12867 {if(t){irplib_table_delete(*t);            *t = NULL;}}
12868 
12869 /*----------------------------------------------------------------------------*/
12874 /*----------------------------------------------------------------------------*/
12875 void uves_free_propertylist(uves_propertylist **p)
12876 {if(p){uves_propertylist_delete(*p);     *p = NULL;}}
12877 
12878 /*----------------------------------------------------------------------------*/
12883 /*----------------------------------------------------------------------------*/
12884 void uves_free_propertylist_const(const uves_propertylist **p)
12885 {if(p){uves_propertylist_delete(*p);     *p = NULL;}}
12886 
12887 /*----------------------------------------------------------------------------*/
12892 /*----------------------------------------------------------------------------*/
12893 void uves_free_property(cpl_property **p)
12894 {if(p){cpl_property_delete(*p);     *p = NULL;}}
12895 /*----------------------------------------------------------------------------*/
12900 /*----------------------------------------------------------------------------*/
12901 void uves_free_polynomial(cpl_polynomial **p)
12902 {if(p){cpl_polynomial_delete(*p);       *p = NULL;}}
12903 /*----------------------------------------------------------------------------*/
12908 /*----------------------------------------------------------------------------*/
12909 void uves_free_matrix(cpl_matrix **m)
12910 {if(m){cpl_matrix_delete(*m);           *m = NULL;}}
12911 /*----------------------------------------------------------------------------*/
12916 /*----------------------------------------------------------------------------*/
12917 void uves_free_parameterlist(cpl_parameterlist **p)
12918 {if(p){cpl_parameterlist_delete(*p);    *p = NULL;}}
12919 /*----------------------------------------------------------------------------*/
12924 /*----------------------------------------------------------------------------*/
12925 void uves_free_frameset(cpl_frameset **f)
12926 {if(f){cpl_frameset_delete(*f);    *f = NULL;}}
12927 /*----------------------------------------------------------------------------*/
12932 /*----------------------------------------------------------------------------*/
12933 void uves_free_frame(cpl_frame **f)
12934 {if(f){cpl_frame_delete(*f);    *f = NULL;}}
12935 /*----------------------------------------------------------------------------*/
12940 /*----------------------------------------------------------------------------*/
12941 void uves_free_bivector(cpl_bivector **b)
12942 {if(b){cpl_bivector_delete(*b);           *b = NULL;}}
12943 /*----------------------------------------------------------------------------*/
12948 /*----------------------------------------------------------------------------*/
12949 void uves_free_vector(cpl_vector **v)
12950 {if(v){cpl_vector_delete(*v);           *v = NULL;}}
12951 /*----------------------------------------------------------------------------*/
12956 /*----------------------------------------------------------------------------*/
12957 void uves_free_stats(cpl_stats **s)
12958 {if(s){cpl_stats_delete(*s);            *s = NULL;}}
12959 /*----------------------------------------------------------------------------*/
12964 /*----------------------------------------------------------------------------*/
12965 void uves_unwrap_vector(cpl_vector **v)
12966 {if(v){cpl_vector_unwrap(*v);           *v = NULL;}}
12967 /*----------------------------------------------------------------------------*/
12972 /*----------------------------------------------------------------------------*/
12973 void uves_unwrap_vector_const(const cpl_vector **v)
12974 {if(v){irplib_vector_unwrap_const(*v);           *v = NULL;}}
12975 /*----------------------------------------------------------------------------*/
12980 /*----------------------------------------------------------------------------*/
12981 void uves_unwrap_bivector_vectors(cpl_bivector **b)
12982 {if(b){cpl_bivector_unwrap_vectors(*b); *b = NULL;}}
12983 /*----------------------------------------------------------------------------*/
12988 /*----------------------------------------------------------------------------*/
12989 void uves_free_array(cpl_array **a)
12990 {if(a){cpl_array_delete(*a);           *a = NULL;}}
12991 
12992 /*----------------------------------------------------------------------------*/
12997 /*----------------------------------------------------------------------------*/
12998 void uves_free_int(int **i)
12999 {if(i){cpl_free(*i);           *i = NULL;}}
13000 
13001 /*----------------------------------------------------------------------------*/
13006 /*----------------------------------------------------------------------------*/
13007 void uves_free_int_const(const int **i)
13008 {if(i){irplib_free(*i);           *i = NULL;}}
13009 /*----------------------------------------------------------------------------*/
13014 /*----------------------------------------------------------------------------*/
13015 void uves_free_float(float **f)
13016 {if(f){cpl_free(*f);           *f = NULL;}}
13017 
13018 /*----------------------------------------------------------------------------*/
13023 /*----------------------------------------------------------------------------*/
13024 void uves_free_double(double **d)
13025 {if(d){cpl_free(*d);           *d = NULL;}}
13026 
13027 /*----------------------------------------------------------------------------*/
13032 /*----------------------------------------------------------------------------*/
13033 void uves_free_string(char **s)
13034 {if(s){cpl_free(*s);           *s = NULL;}}
13035 /*----------------------------------------------------------------------------*/
13040 /*----------------------------------------------------------------------------*/
13041 void uves_free_string_const(const char **s)
13042 {if(s){irplib_free(*s);           *s = NULL;}}
13043 
13044 /*----------------------------------------------------------------------------*/
13065 /*----------------------------------------------------------------------------*/
13066 
13067 static double
13068 get_chisq(int N, int D,
13069       int (*f)(const double x[], const double a[], double *result),
13070       const double *a,
13071       const double *x,
13072       const double *y,
13073       const double *sigma)
13074 {
13075     double chi_sq;     /* Result */
13076     int i = 0;
13077 
13078     /* For efficiency, don't check input in this static function */
13079 
13080     chi_sq = 0.0;
13081     for (i = 0; i < N; i++)
13082     {
13083         double fx_i;
13084         double residual;                 /* Residual in units of uncertainty */
13085         const double *x_i = &(x[0+i*D]);
13086 
13087         /* Evaluate */
13088         cpl_ensure( f(x_i,
13089               a,
13090               &fx_i) == 0, CPL_ERROR_ILLEGAL_INPUT, -1.0);
13091 
13092         /* Accumulate */
13093         if (sigma == NULL)
13094         {
13095             residual = (fx_i - y[i]);
13096         }
13097         else
13098         {
13099             residual = (fx_i - y[i]) / sigma[i];
13100         }
13101 
13102         chi_sq += residual*residual;
13103        
13104     }
13105 
13106     return chi_sq;
13107 }
13108 /*----------------------------------------------------------------------------*/
13142 /*----------------------------------------------------------------------------*/
13143 static int
13144 get_candidate(const double *a, const int ia[],
13145           int M, int N, int D,
13146           double lambda,
13147           int    (*f)(const double x[], const double a[], double *result),
13148           int (*dfda)(const double x[], const double a[], double result[]),
13149           const double *x,
13150           const double *y,
13151           const double *sigma,
13152           double *partials,
13153           cpl_matrix *alpha,
13154           cpl_matrix *beta,
13155           double *a_da)
13156 {
13157     int Mfit = 0;         /* Number of non-constant fit parameters */
13158     cpl_matrix *da;       /* Solution of   alpha * da = beta */
13159     double *alpha_data;
13160     double *beta_data;
13161     double *da_data;
13162     int i, imfit = 0;
13163     int j, jmfit = 0;
13164     int k = 0;
13165 
13166     /* For efficiency, don't check input in this static function */
13167 
13168     Mfit = cpl_matrix_get_nrow(alpha);
13169 
13170     alpha_data    = irplib_matrix_get_data(alpha);
13171     beta_data     = irplib_matrix_get_data(beta);
13172    
13173     /* Build alpha, beta:
13174      *
13175      *  alpha[i,j] = sum_{k=1,N} (sigma_k)^-2 * df/da_i * df/da_j  *
13176      *                           (1 + delta_ij lambda) ,
13177      *
13178      *   beta[i]   = sum_{k=1,N} (sigma_k)^-2 * ( y_k - f(x_k) ) * df/da_i
13179      *
13180      * where (i,j) loop over the non-constant parameters (0 to Mfit-1),
13181      * delta is Kronecker's delta, and all df/da are evaluated in x_k
13182      */
13183 
13184     cpl_matrix_fill(alpha, 0.0);
13185     cpl_matrix_fill(beta , 0.0);
13186 
13187     for (k = 0; k < N; k++)
13188     {
13189         double sm2 = 0.0;                /* (sigma_k)^-2 */
13190         double fx_k = 0.0;               /* f(x_k)       */
13191         const double *x_k = &(x[0+k*D]); /* x_k          */
13192 
13193         if (sigma == NULL)
13194         {
13195             sm2 = 1.0;
13196         }
13197         else
13198         {
13199             sm2 = 1.0 / (sigma[k] * sigma[k]);
13200         }
13201         
13202         /* Evaluate f(x_k) */
13203         cpl_ensure( f(x_k, a, &fx_k) == 0, CPL_ERROR_ILLEGAL_INPUT, -1);
13204 
13205         /* Evaluate (all) df/da (x_k) */
13206         cpl_ensure( dfda(x_k, a, partials) == 0, 
13207             CPL_ERROR_ILLEGAL_INPUT, -1);
13208 
13209         for (i = 0, imfit = 0; i < M; i++)
13210         {
13211             if (ia[i] != 0)
13212             {
13213                 /* Beta */
13214                 beta_data[imfit] +=
13215                 sm2 * (y[k] - fx_k) * partials[i];
13216                 
13217                 /* Alpha is symmetrical, so compute
13218                    only lower-left part */
13219                 for (j = 0, jmfit = 0; j < i; j++)
13220                 {
13221                     if (ia[j] != 0)
13222                     {
13223                         alpha_data[jmfit + imfit*Mfit] +=
13224                         sm2 * partials[i] * 
13225                         partials[j];
13226                         
13227                         jmfit += 1;
13228                     }
13229                 }
13230                 
13231                 /* Alpha, diagonal terms */
13232                 j = i;
13233                 jmfit = imfit;
13234                 
13235                 alpha_data[jmfit + imfit*Mfit] += 
13236                 sm2 * partials[i] *
13237                 partials[j] * (1 + lambda);
13238                 
13239                 imfit += 1;
13240             }
13241         }
13242 
13243         assert( imfit == Mfit );
13244     }
13245 
13246     /* Create upper-right part of alpha */
13247     for (i = 0, imfit = 0; i < M; i++)
13248     {
13249         if (ia[i] != 0)
13250         {
13251             for (j = i+1, jmfit = imfit+1; j < M; j++)
13252             {
13253                 if (ia[j] != 0)
13254                 {
13255                     alpha_data[jmfit + imfit*Mfit] = 
13256                     alpha_data[imfit + jmfit*Mfit];
13257                     
13258                     jmfit += 1;
13259                 }
13260             }
13261             assert( jmfit == Mfit );
13262 
13263             imfit += 1;
13264         }
13265     }
13266     assert( imfit == Mfit );
13267     
13268     da = cpl_matrix_solve(alpha, beta);
13269 
13270     cpl_ensure(da != NULL, cpl_error_get_code(), -1);
13271 
13272     /* Create a+da vector by adding a and da */
13273     da_data   = irplib_matrix_get_data(da);
13274 
13275     for (i = 0, imfit = 0; i < M; i++)
13276     {
13277         if (ia[i] != 0)
13278         {
13279             a_da[i] = a[i] + da_data[0 + imfit*1];
13280             
13281             imfit += 1;
13282         }
13283         else
13284         {
13285             a_da[i] = a[i];
13286         }
13287     }
13288     
13289     assert( imfit == Mfit );
13290 
13291     cpl_matrix_delete(da);
13292 
13293     return 0;
13294 }
13295 

Generated on Tue Jun 19 14:39:20 2007 for UVES Pipeline Reference Manual by  doxygen 1.4.6