I wonder how this code works. ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)]) - ctype

#ifndef _CTYPE_H_
#define _CTYPE_H_
#include "_ansi.h"
_BEGIN_STD_C
int _EXFUN(isalnum, (int __c));
int _EXFUN(isalpha, (int __c));
int _EXFUN(iscntrl, (int __c));
int _EXFUN(isdigit, (int __c));
int _EXFUN(isgraph, (int __c));
int _EXFUN(islower, (int __c));
int _EXFUN(isprint, (int __c));
int _EXFUN(ispunct, (int __c));
int _EXFUN(isspace, (int __c));
int _EXFUN(isupper, (int __c));
int _EXFUN(isxdigit,(int __c));
int _EXFUN(tolower, (int __c));
int _EXFUN(toupper, (int __c));
#if !defined(__STRICT_ANSI__) || defined(__cplusplus) || __STDC_VERSION__ >= 199901L
int _EXFUN(isblank, (int __c));
#endif
#ifndef __STRICT_ANSI__
int _EXFUN(isascii, (int __c));
int _EXFUN(toascii, (int __c));
#define _tolower(__c) ((unsigned char)(__c) - 'A' + 'a')
#define _toupper(__c) ((unsigned char)(__c) - 'a' + 'A')
#endif
#define _U 01
#define _L 02
#define _N 04
#define _S 010
#define _P 020
#define _C 040
#define _X 0100
#define _B 0200
#ifndef _MB_CAPABLE
_CONST
#endif
extern __IMPORT char *__ctype_ptr__;
#ifndef __cplusplus
/* These macros are intentionally written in a manner that will trigger
a gcc -Wall warning if the user mistakenly passes a 'char' instead
of an int containing an 'unsigned char'. Note that the sizeof will
always be 1, which is what we want for mapping EOF to __ctype_ptr__[0];
the use of a raw index inside the sizeof triggers the gcc warning if
__c was of type char, and sizeof masks side effects of the extra __c.
Meanwhile, the real index to __ctype_ptr__+1 must be cast to int,
since isalpha(0x100000001LL) must equal isalpha(1), rather than being
an out-of-bounds reference on a 64-bit machine. */
#define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)])
#define isalpha(__c) (__ctype_lookup(__c)&(_U|_L))
#define isupper(__c) ((__ctype_lookup(__c)&(_U|_L))==_U)
#define islower(__c) ((__ctype_lookup(__c)&(_U|_L))==_L)
#define isdigit(__c) (__ctype_lookup(__c)&_N)
#define isxdigit(__c) (__ctype_lookup(__c)&(_X|_N))
#define isspace(__c) (__ctype_lookup(__c)&_S)
#define ispunct(__c) (__ctype_lookup(__c)&_P)
#define isalnum(__c) (__ctype_lookup(__c)&(_U|_L|_N))
#define isprint(__c) (__ctype_lookup(__c)&(_P|_U|_L|_N|_B))
#define isgraph(__c) (__ctype_lookup(__c)&(_P|_U|_L|_N))
#define iscntrl(__c) (__ctype_lookup(__c)&_C)
#if defined(__GNUC__) && \
(!defined(__STRICT_ANSI__) || __STDC_VERSION__ >= 199901L)
#define isblank(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
(__ctype_lookup(__x)&_B) || (int) (__x) == '\t';})
#endif
/* Non-gcc versions will get the library versions, and will be
slightly slower. These macros are not NLS-aware so they are
disabled if the system supports the extended character sets. */
# if defined(__GNUC__)
# if !defined (_MB_EXTENDED_CHARSETS_ISO) && !defined (_MB_EXTENDED_CHARSETS_WINDOWS)
# define toupper(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
islower (__x) ? (int) __x - 'a' + 'A' : (int) __x;})
# define tolower(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
isupper (__x) ? (int) __x - 'A' + 'a' : (int) __x;})
# else /* _MB_EXTENDED_CHARSETS* */
/* Allow a gcc warning if the user passed 'char', but defer to the
function. */
# define toupper(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
(void) __ctype_ptr__[__x]; (toupper) (__x);})
# define tolower(__c) \
__extension__ ({ __typeof__ (__c) __x = (__c); \
(void) __ctype_ptr__[__x]; (tolower) (__x);})
# endif /* _MB_EXTENDED_CHARSETS* */
# endif /* __GNUC__ */
#endif /* !__cplusplus */
#ifndef __STRICT_ANSI__
#define isascii(__c) ((unsigned)(__c)<=0177)
#define toascii(__c) ((__c)&0177)
#endif
/* For C++ backward-compatibility only. */
extern __IMPORT _CONST char _ctype_[];
_END_STD_C
#endif /* _CTYPE_H_ */
This code is from the standard library ctype.h.
I was impressed by the following code:
#define isalpha(__c) (__ctype_lookup(__c)&(_U|_L))
But how? How is the alphabet checked by just that operation? I think I should know what __ctype_lookup is.
However, __ctype_lookup was more odd.
#define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)])
Fortunately, there was a comment right above the code, but unfortunately I could not understand it.
/* These macros are intentionally written in a manner that will trigger
a gcc -Wall warning if the user mistakenly passes a 'char' instead
of an int containing an 'unsigned char'. Note that the sizeof will
always be 1, which is what we want for mapping EOF to __ctype_ptr__[0];
the use of a raw index inside the sizeof triggers the gcc warning if
__c was of type char, and sizeof masks side effects of the extra __c.
Meanwhile, the real index to __ctype_ptr__+1 must be cast to int,
since isalpha(0x100000001LL) must equal isalpha(1), rather than being
an out-of-bounds reference on a 64-bit machine. */
Somebody help me!
And the __IMPORT in the following code was just defined somewhere. If it is important, I will find it.
extern __IMPORT char *__ctype_ptr__;

With reference to the chromium implementation of ctype.c (as hopefully it is representative):
__ctype_ptr__ is a pointer to the start of the _ctype_ array:
char *__ctype_ptr__ = (char *) _ctype_;
The _ctype_ array is an array of const chars:
_CONST char _ctype_[1 + 256] = {
0,
_CTYPE_DATA_0_127,
_CTYPE_DATA_128_255
};
And finally the _CTYPE_DATA_0_127 and _CTYPE_DATA_128_255 entries are actually
defines containing several chars, each of which is a bitfield:
#define _CTYPE_DATA_0_127 \
_C, _C, _C, _C, _C, _C, _C, _C, \
_C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, \
_C, _C, _C, _C, _C, _C, _C, _C, \
_C, _C, _C, _C, _C, _C, _C, _C, \
_S|_B, _P, _P, _P, _P, _P, _P, _P, \
_P, _P, _P, _P, _P, _P, _P, _P, \
_N, _N, _N, _N, _N, _N, _N, _N, \
_N, _N, _P, _P, _P, _P, _P, _P, \
_P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, \
_U, _U, _U, _U, _U, _U, _U, _U, \
_U, _U, _U, _U, _U, _U, _U, _U, \
_U, _U, _U, _P, _P, _P, _P, _P, \
_P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, \
_L, _L, _L, _L, _L, _L, _L, _L, \
_L, _L, _L, _L, _L, _L, _L, _L, \
_L, _L, _L, _P, _P, _P, _P, _C
where each _U, _P etc is a different bit:
#define _U 01
#define _L 02
#define _N 04
#define _S 010
#define _P 020
#define _C 040
#define _X 0100
#define _B 0200
So, the line:
#define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)])1
Is just a lookup into that _ctype_ array, and then
#define isalpha(__c) (__ctype_lookup(__c)&(_U|_L))
is a bitwise mask of that lookup with the appropriate bitmask (in this case, and OR of uppercase and lowercase).
1: Honestly not sure what sizeof(""[__c]) achieves, I'm guessing it's something to do with support for different compilers/architectures or something. It skips over the first '0' in the _ctype_ array

Related

Elegant initialization of static (member) array with a sequence

I would like to initialize a big static (and possibly constant) array with a predetermined sequence.
In this particular case it would be a sinetable, containing a digitized sine-wave.
Now, I know you can initialize arrays with:
#define TABLE_SIZE 2000
static float table[TABLE_SIZE] = { 0 , 0.124 , 0.245 , ... }
and all I need to do is generate all the sine values and paste them inside, but in my opinion this is incredibly ugly.
Is there a preprocessor directive or a lambda function or something for this?
Failing that, just a solution to calculating all the values at the start of the program and assigning them to the static array?
EDIT:
Thanks to TemplateRex's answer from c++11: Create 0 to N constexpr array in c++
, I have a working solution:
#define TABLE_SIZE 2000
template<class Function, std::size_t... Indices>
constexpr auto make_array_helper(Function f, std::index_sequence<Indices...>)
-> std::array<typename std::result_of<Function(std::size_t)>::type, sizeof...(Indices)>
{
return {{ f(Indices)... }};
}
template<int N, class Function>
constexpr auto make_array(Function f)
-> std::array<typename std::result_of<Function(std::size_t)>::type, N>
{
return make_array_helper(f, std::make_index_sequence<N>{});
}
constexpr float fun(double x) { return (float)sin(((double)x / (double)TABLE_SIZE) * M_PI * 2.0); }
static constexpr auto sinetable = make_array<TABLE_SIZE>(fun);
Unfortunately I am having difficulties integrating this into a class.
Getting error : sinetable::make_array is used before its definition, I'm guessing because static members are defined before static methods. Or maybe it has to do with constexpr being inline.
What you're looking for is C++11's constexpr but you'd need either recursion of templates.
c++11: Create 0 to N constexpr array in c++
http://fendrich.se/blog/2012/11/22/compile-time-loops-in-c-plus-plus-11-with-trampolines-and-exponential-recursion/
However, C++'s standard math functions are non constexpr so you wouldn't be able to use them anyways so you're probably better off just initializing it conventionally somewhere.
If you can't manage to achieve the initialization with template techniques that I don't know about, here is alternative, uglier approach:
You just define 2001 macros:
#include <cmath>
#define TABLE_SIZE 2000
#define SINE0 0.0f
#define SINE1 SINE0 ,std::sin( 1.0f * M_PI / ( 2 * TABLE_SIZE) )
#define SINE2 SINE1 ,std::sin( 2.0f * M_PI / ( 2 * TABLE_SIZE) )
#define SINE3 SINE2 ,std::sin( 3.0f * M_PI / ( 2 * TABLE_SIZE) )
//...
//...
#define SINE1998 SINE1997 ,std::sin( 1998.0f * M_PI / ( 2 * TABLE_SIZE) )
#define SINE1999 SINE1998 ,std::sin( 1999.0f * M_PI / ( 2 * TABLE_SIZE) )
#define SINE2000 SINE1999 ,std::sin( 2000.0f * M_PI / ( 2 * TABLE_SIZE) )
#define ALL_2001_SINES SINE2000
And just use it this way:
#include <iostream>
#include "file_with_macros.hpp" // contains above macros and includes <cmath>
static float const table[TABLE_SIZE+1] = {ALL_2001_SINES}; // + 1 because of inclusion of
// both borders 0.0f and M_PI/2
int main()
{
for(int i=0; i<TABLE_SIZE+1; ++i)
std::cout << table[i] << ", ";
}
Demo
If you want only 91 values (of every degree), then you can change TABLE_SIZE to 90, and remove macros SINE91 to SINE2000, and define macro ALL_91_SINES as SINE_90.

Macro for defining a template struct with template parameters exposed

Is is possible to create a macro that will reduce the boilerplate for definitions of template structs which merely expose all their template parameters?
template <
typename TPar1,
int TPar2,
...
bool TParN
>
struct MyStruct {
using Par1 = TPar1;
static int const Par2 = TPar2;
...
static bool const ParN = TParN;
};
Note the irregular mapping of template parameter types (typename->using, TYPE->static TYPE const). I will also be somehow satisfied with a solution that cannot map these types automatically, but for example only supports typename or requires a hint whether it's a typename or a type.
I have found a solution.
Some credit goes to this answer for figuring out the number of parameters passed.
#define GET_1(p1, ...) p1
#define GET_2(p1, p2, ...) p2
#define GET_3(p1, p2, p3, ...) p3
#define GET_4(p1, p2, p3, p4, ...) p4
#define GET_5(p1, p2, p3, p4, p5, ...) p5
#define GET_6(p1, p2, p3, p4, p5, p6, ...) p6
#define GET_7(p1, p2, p3, p4, p5, p6, p7, ...) p7
#define GET_8(p1, p2, p3, p4, p5, p6, p7, p8, ...) p8
#define GET_9(p1, p2, p3, p4, p5, p6, p7, p8, p9, ...) p9
#define GET_10(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, ...) p10
#define GET_11(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, ...) p11
#define GET_12(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, ...) p12
#define MAP_1(f, del, pars) f( GET_1 pars)
#define MAP_2(f, del, pars) MAP_1(f, del, pars) del(dummy) f( GET_2 pars)
#define MAP_3(f, del, pars) MAP_2(f, del, pars) del(dummy) f( GET_3 pars)
#define MAP_4(f, del, pars) MAP_3(f, del, pars) del(dummy) f( GET_4 pars)
#define MAP_5(f, del, pars) MAP_4(f, del, pars) del(dummy) f( GET_5 pars)
#define MAP_6(f, del, pars) MAP_5(f, del, pars) del(dummy) f( GET_6 pars)
#define MAP_7(f, del, pars) MAP_6(f, del, pars) del(dummy) f( GET_7 pars)
#define MAP_8(f, del, pars) MAP_7(f, del, pars) del(dummy) f( GET_8 pars)
#define MAP_9(f, del, pars) MAP_8(f, del, pars) del(dummy) f( GET_9 pars)
#define MAP_10(f, del, pars) MAP_9(f, del, pars) del(dummy) f(GET_10 pars)
#define MAP_11(f, del, pars) MAP_10(f, del, pars) del(dummy) f(GET_11 pars)
#define MAP_12(f, del, pars) MAP_11(f, del, pars) del(dummy) f(GET_12 pars)
#define CONCAT_HELPER(x, y) x##y
#define CONCAT(x, y) CONCAT_HELPER(x, y)
#define MAP(f, del, pars) CONCAT(MAP_, NUM_TUPLE_ARGS(pars))(f, del, pars)
#define NUM_MACRO_ARGS(...) NUM_MACRO_ARGS_HELPER1(__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define NUM_MACRO_ARGS_HELPER1(...) NUM_MACRO_ARGS_HELPER2(__VA_ARGS__)
#define NUM_MACRO_ARGS_HELPER2(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
#define NUM_TUPLE_ARGS(tuple) NUM_MACRO_ARGS tuple
#define GET_ARG_PAR_NAME(par_type, decl_type, name) T##name
#define MAKE_TEMPLATE_PART_VA(...) GET_1(__VA_ARGS__) GET_ARG_PAR_NAME(__VA_ARGS__)
#define MAKE_TEMPLATE_PART(param_def) MAKE_TEMPLATE_PART_VA param_def
#define MAKE_STRUCT_PART_VA(...) GET_2(__VA_ARGS__) GET_3(__VA_ARGS__) = GET_ARG_PAR_NAME(__VA_ARGS__);
#define MAKE_STRUCT_PART(param_def) MAKE_STRUCT_PART_VA param_def
#define TYPE_ARG(name) (typename, using, name)
#define VALUE_ARG(type, name) (type, static type const, name)
#define DELIMITER_TEMPLATE_PART(dummy) ,
#define DELIMITER_STRUCT_PART(dummy)
#define DEFINE_ALIAS_STRUCT(name, pars) template < MAP(MAKE_TEMPLATE_PART, DELIMITER_TEMPLATE_PART, pars) > struct name { MAP(MAKE_STRUCT_PART, DELIMITER_STRUCT_PART, pars) };
DEFINE_ALIAS_STRUCT(MyStruct3, (
TYPE_ARG(Par1),
VALUE_ARG(bool, Par2),
TYPE_ARG(Par3),
TYPE_ARG(Par4),
TYPE_ARG(Par5),
TYPE_ARG(Par6),
TYPE_ARG(Par7),
TYPE_ARG(Par8),
TYPE_ARG(Par9)
))
This example expands to:
template <
typename TPar1,
bool TPar2,
typename TPar3,
typename TPar4,
typename TPar5,
typename TPar6,
typename TPar7,
typename TPar8,
typename TPar9
>
struct MyStruct3 {
using Par1 = TPar1;
static bool const Par2 = TPar2;
using Par3 = TPar3;
using Par4 = TPar4;
using Par5 = TPar5;
using Par6 = TPar6;
using Par7 = TPar7;
using Par8 = TPar8;
using Par9 = TPar9;
};

How to compile including a .h file using mex in MATLAB?

I'm trying to compile a piece of code I download from website.
But there are some issues when I compile with the mex function
I'm using mex -I./ -L/lib convolve.cpp
(.h and .cpp file are in the same folder,my current folder)
I don't know it's correct or not.
But this is what MATLAB says
Error using mex
/tmp/mex_100625252862836_11288/convolve.o: In function
`internal_reduce(double*, int, int, double*, double*, int,
int, int, int, int, int, int, int, double*, char*)':
convolve.cpp:(.text+0xa2): undefined reference to
`edge_function(char*)'
/tmp/mex_100625252862836_11288/convolve.o: In function
`internal_expand(double*, double*, double*, int, int, int,
int, int, int, int, int, double*, int, int, char*)':
convolve.cpp:(.text+0xae4): undefined reference to
`edge_function(char*)'
collect2: error: ld returned 1 exit status
This is the .h file
/*
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; File: convolve.h
;;; Author: Simoncelli
;;; Description: Header file for convolve.c
;;; Creation Date:
;;; ----------------------------------------------------------------
;;; Object-Based Vision and Image Understanding System (OBVIUS),
;;; Copyright 1988, Vision Science Group, Media Laboratory,
;;; Massachusetts Institute of Technology.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
*/
#include <stdio.h>
#include <stdlib.h>
#define ABS(x) (((x)>=0) ? (x) : (-(x)))
#define ROOT2 1.4142135623730951
#define REDUCE 0
#define EXPAND 1
#define IS ==
#define ISNT !=
#define AND &&
#define OR ||
typedef int (*fptr)(register double *,register int ,int ,int ,int ,register double *,int);
typedef struct
{
char *name;
fptr func;
} EDGE_HANDLER;
fptr edge_function(char *edges);
int internal_reduce(register double *image,register int x_dim,int y_dim, double *filt, register double *temp,register int x_fdim,int y_fdim,
int x_start,register int x_step, int x_stop, int y_start,register int y_step,int y_stop,
register double *result, char *edges);
int internal_expand(register double *image,double *filt,register double *temp,register int x_fdim,int y_fdim,
int x_start,register int x_step,int x_stop,int y_start,register int y_step,int y_stop,
register double *result,register int x_dim,int y_dim,char *edges);
int internal_wrap_reduce(double *image,register int x_dim,register int y_dim, register double *filt,register int x_fdim,register int y_fdim,
int x_start,int x_step,int x_stop,int y_start,int y_step,int y_stop,
register double *result);
int internal_wrap_expand(double *image, register double *filt,register int x_fdim,register int y_fdim,
int x_start,int x_step,int x_stop,int y_start,int y_step,int y_stop,
register double *result,register int x_dim,register int y_dim);
And This is the .cpp file
/*
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; File: convolve.c
;;; Author: Eero Simoncelli
;;; Description: General convolution code for 2D images
;;; Creation Date: Spring, 1987.
;;; MODIFICATIONS:
;;; 10/89: approximately optimized the choice of register vars on SPARCS.
;;; 6/96: Switched array types to double float.
;;; 2/97: made more robust and readable. Added STOP arguments.
;;; 8/97: Bug: when calling internal_reduce with edges in {reflect1,repeat,
;;; extend} and an even filter dimension. Solution: embed the filter
;;; in the upper-left corner of a filter with odd Y and X dimensions.
;;; ----------------------------------------------------------------
;;; Object-Based Vision and Image Understanding System (OBVIUS),
;;; Copyright 1988, Vision Science Group, Media Laboratory,
;;; Massachusetts Institute of Technology.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
*/
#include <stdio.h>
#include <math.h>
#include "convolve.h"
/*
--------------------------------------------------------------------
Correlate FILT with IMAGE, subsampling according to START, STEP, and
STOP parameters, with values placed into RESULT array. RESULT
dimensions should be ceil((stop-start)/step). TEMP should be a
pointer to a temporary double array the size of the filter.
EDGES is a string specifying how to handle boundaries -- see edges.c.
The convolution is done in 9 sections, where the border sections use
specially computed edge-handling filters (see edges.c). The origin
of the filter is assumed to be (floor(x_fdim/2), floor(y_fdim/2)).
------------------------------------------------------------------------ */
/* abstract out the inner product computation */
#define INPROD(XCNR,YCNR) \
{ \
sum=0.0; \
for (im_pos=YCNR*x_dim+XCNR, filt_pos=0, x_filt_stop=x_fdim; \
x_filt_stop<=filt_size; \
im_pos+=(x_dim-x_fdim), x_filt_stop+=x_fdim) \
for (; \
filt_pos<x_filt_stop; \
filt_pos++, im_pos++) \
sum+= image[im_pos]*temp[filt_pos]; \
result[res_pos] = sum; \
}
int internal_reduce(register double *image,register int x_dim,int y_dim, double *filt, register double *temp,register int x_fdim,int y_fdim,
int x_start,register int x_step, int x_stop, int y_start,register int y_step,int y_stop,
register double *result, char *edges)
/*register double *image, *temp;
register int x_fdim, x_dim;
register double *result;
register int x_step, y_step;
int x_start, y_start;
int x_stop, y_stop;
double *filt;
int y_dim, y_fdim;
char *edges;*/
{
register double sum;
register int filt_pos, im_pos, x_filt_stop;
register int x_pos, filt_size = x_fdim*y_fdim;
register int y_pos, res_pos;
register int y_ctr_stop = y_dim - ((y_fdim==1)?0:y_fdim);
register int x_ctr_stop = x_dim - ((x_fdim==1)?0:x_fdim);
register int x_res_dim = (x_stop-x_start+x_step-1)/x_step;
int x_ctr_start = ((x_fdim==1)?0:1);
int y_ctr_start = ((y_fdim==1)?0:1);
int x_fmid = x_fdim/2;
int y_fmid = y_fdim/2;
int base_res_pos;
fptr reflect = edge_function(edges); /* look up edge-handling function */
if (!reflect) return(-1);
/* shift start/stop coords to filter upper left hand corner */
x_start -= x_fmid; y_start -= y_fmid;
x_stop -= x_fmid; y_stop -= y_fmid;
if (x_stop < x_ctr_stop) x_ctr_stop = x_stop;
if (y_stop < y_ctr_stop) y_ctr_stop = y_stop;
for (res_pos=0, y_pos=y_start; /* TOP ROWS */
y_pos<y_ctr_start;
y_pos+=y_step)
{
for (x_pos=x_start; /* TOP-LEFT CORNER */
x_pos<x_ctr_start;
x_pos+=x_step, res_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-1,temp,REDUCE);
INPROD(0,0)
}
(*reflect)(filt,x_fdim,y_fdim,0,y_pos-1,temp,REDUCE);
for (; /* TOP EDGE */
x_pos<x_ctr_stop;
x_pos+=x_step, res_pos++)
INPROD(x_pos,0)
for (; /* TOP-RIGHT CORNER */
x_pos<x_stop;
x_pos+=x_step, res_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-1,temp,REDUCE);
INPROD(x_ctr_stop,0)
}
} /* end TOP ROWS */
y_ctr_start = y_pos; /* hold location of top */
for (base_res_pos=res_pos, x_pos=x_start; /* LEFT EDGE */
x_pos<x_ctr_start;
x_pos+=x_step, base_res_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-1,0,temp,REDUCE);
for (y_pos=y_ctr_start, res_pos=base_res_pos;
y_pos<y_ctr_stop;
y_pos+=y_step, res_pos+=x_res_dim)
INPROD(0,y_pos)
}
(*reflect)(filt,x_fdim,y_fdim,0,0,temp,REDUCE);
for (; /* CENTER */
x_pos<x_ctr_stop;
x_pos+=x_step, base_res_pos++)
for (y_pos=y_ctr_start, res_pos=base_res_pos;
y_pos<y_ctr_stop;
y_pos+=y_step, res_pos+=x_res_dim)
INPROD(x_pos,y_pos)
for (; /* RIGHT EDGE */
x_pos<x_stop;
x_pos+=x_step, base_res_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,0,temp,REDUCE);
for (y_pos=y_ctr_start, res_pos=base_res_pos;
y_pos<y_ctr_stop;
y_pos+=y_step, res_pos+=x_res_dim)
INPROD(x_ctr_stop,y_pos)
}
for (res_pos-=(x_res_dim-1);
y_pos<y_stop; /* BOTTOM ROWS */
y_pos+=y_step)
{
for (x_pos=x_start; /* BOTTOM-LEFT CORNER */
x_pos<x_ctr_start;
x_pos+=x_step, res_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-y_ctr_stop+1,temp,REDUCE);
INPROD(0,y_ctr_stop)
}
(*reflect)(filt,x_fdim,y_fdim,0,y_pos-y_ctr_stop+1,temp,REDUCE);
for (; /* BOTTOM EDGE */
x_pos<x_ctr_stop;
x_pos+=x_step, res_pos++)
INPROD(x_pos,y_ctr_stop)
for (; /* BOTTOM-RIGHT CORNER */
x_pos<x_stop;
x_pos+=x_step, res_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-y_ctr_stop+1,temp,REDUCE);
INPROD(x_ctr_stop,y_ctr_stop)
}
} /* end BOTTOM */
return(0);
} /* end of internal_reduce */
/*
--------------------------------------------------------------------
Upsample IMAGE according to START,STEP, and STOP parameters and then
convolve with FILT, adding values into RESULT array. IMAGE
dimensions should be ceil((stop-start)/step). See
description of internal_reduce (above).
WARNING: this subroutine destructively modifies the RESULT array!
------------------------------------------------------------------------ */
/* abstract out the inner product computation */
#define INPROD2(XCNR,YCNR) \
{ \
val = image[im_pos]; \
for (res_pos=YCNR*x_dim+XCNR, filt_pos=0, x_filt_stop=x_fdim; \
x_filt_stop<=filt_size; \
res_pos+=(x_dim-x_fdim), x_filt_stop+=x_fdim) \
for (; \
filt_pos<x_filt_stop; \
filt_pos++, res_pos++) \
result[res_pos] += val*temp[filt_pos]; \
}
int internal_expand(register double *image,double *filt,register double *temp,register int x_fdim,int y_fdim,
int x_start,register int x_step,int x_stop,int y_start,register int y_step,int y_stop,
register double *result,register int x_dim,int y_dim,char *edges)
/*register double *result, *temp;
register int x_fdim, x_dim;
register int x_step, y_step;
register double *image;
int x_start, y_start;
double *filt;
int y_fdim, y_dim;
char *edges;*/
{
register double val;
register int filt_pos, res_pos, x_filt_stop;
register int x_pos, filt_size = x_fdim*y_fdim;
register int y_pos, im_pos;
register int x_ctr_stop = x_dim - ((x_fdim==1)?0:x_fdim);
int y_ctr_stop = (y_dim - ((y_fdim==1)?0:y_fdim));
int x_ctr_start = ((x_fdim==1)?0:1);
int y_ctr_start = ((y_fdim==1)?0:1);
int x_fmid = x_fdim/2;
int y_fmid = y_fdim/2;
int base_im_pos, x_im_dim = (x_stop-x_start+x_step-1)/x_step;
fptr reflect = edge_function(edges); /* look up edge-handling function */
if (!reflect) return(-1);
/* shift start/stop coords to filter upper left hand corner */
x_start -= x_fmid; y_start -= y_fmid;
x_stop -= x_fmid; y_stop -= y_fmid;
if (x_stop < x_ctr_stop) x_ctr_stop = x_stop;
if (y_stop < y_ctr_stop) y_ctr_stop = y_stop;
for (im_pos=0, y_pos=y_start; /* TOP ROWS */
y_pos<y_ctr_start;
y_pos+=y_step)
{
for (x_pos=x_start; /* TOP-LEFT CORNER */
x_pos<x_ctr_start;
x_pos+=x_step, im_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-1,temp,EXPAND);
INPROD2(0,0)
}
(*reflect)(filt,x_fdim,y_fdim,0,y_pos-1,temp,EXPAND);
for (; /* TOP EDGE */
x_pos<x_ctr_stop;
x_pos+=x_step, im_pos++)
INPROD2(x_pos,0)
for (; /* TOP-RIGHT CORNER */
x_pos<x_stop;
x_pos+=x_step, im_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-1,temp,EXPAND);
INPROD2(x_ctr_stop,0)
}
} /* end TOP ROWS */
y_ctr_start = y_pos; /* hold location of top */
for (base_im_pos=im_pos, x_pos=x_start; /* LEFT EDGE */
x_pos<x_ctr_start;
x_pos+=x_step, base_im_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-1,0,temp,EXPAND);
for (y_pos=y_ctr_start, im_pos=base_im_pos;
y_pos<y_ctr_stop;
y_pos+=y_step, im_pos+=x_im_dim)
INPROD2(0,y_pos)
}
(*reflect)(filt,x_fdim,y_fdim,0,0,temp,EXPAND);
for (; /* CENTER */
x_pos<x_ctr_stop;
x_pos+=x_step, base_im_pos++)
for (y_pos=y_ctr_start, im_pos=base_im_pos;
y_pos<y_ctr_stop;
y_pos+=y_step, im_pos+=x_im_dim)
INPROD2(x_pos,y_pos)
for (; /* RIGHT EDGE */
x_pos<x_stop;
x_pos+=x_step, base_im_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,0,temp,EXPAND);
for (y_pos=y_ctr_start, im_pos=base_im_pos;
y_pos<y_ctr_stop;
y_pos+=y_step, im_pos+=x_im_dim)
INPROD2(x_ctr_stop,y_pos)
}
for (im_pos-=(x_im_dim-1);
y_pos<y_stop; /* BOTTOM ROWS */
y_pos+=y_step)
{
for (x_pos=x_start; /* BOTTOM-LEFT CORNER */
x_pos<x_ctr_start;
x_pos+=x_step, im_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-1,y_pos-y_ctr_stop+1,temp,EXPAND);
INPROD2(0,y_ctr_stop)
}
(*reflect)(filt,x_fdim,y_fdim,0,y_pos-y_ctr_stop+1,temp,EXPAND);
for (; /* BOTTOM EDGE */
x_pos<x_ctr_stop;
x_pos+=x_step, im_pos++)
INPROD2(x_pos,y_ctr_stop)
for (; /* BOTTOM-RIGHT CORNER */
x_pos<x_stop;
x_pos+=x_step, im_pos++)
{
(*reflect)(filt,x_fdim,y_fdim,x_pos-x_ctr_stop+1,y_pos-y_ctr_stop+1,temp,EXPAND);
INPROD2(x_ctr_stop,y_ctr_stop)
}
} /* end BOTTOM */
return(0);
} /* end of internal_expand */
/* Local Variables: */
/* buffer-read-only: t */
/* End: */
A lot thanks if anyone could help me.
(I'm using g++ for c++ language compilation)
Ubuntu14.04,MATLAB 2015a
This is the 'edges.cpp' file where 'edge_function' are implemented.
/*
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; File: edges.c
;;; Author: Eero Simoncelli
;;; Description: Boundary handling routines for use with convolve.c
;;; Creation Date: Spring 1987.
;;; MODIFIED, 6/96, to operate on double float arrays.
;;; MODIFIED by dgp, 4/1/97, to support THINK C.
;;; MODIFIED, 8/97: reflect1, reflect2, repeat, extend upgraded to
;;; work properly for non-symmetric filters. Added qreflect2 to handle
;;; even-length QMF's which broke under the reflect2 modification.
;;; ----------------------------------------------------------------
;;; Object-Based Vision and Image Understanding System (OBVIUS),
;;; Copyright 1988, Vision Science Group, Media Laboratory,
;;; Massachusetts Institute of Technology.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
*/
/* This file contains functions which determine how edges are to be
handled when performing convolutions of images with linear filters.
Any edge handling function which is local and linear may be defined,
except (unfortunately) constants cannot be added. So to treat the
edges as if the image is surrounded by a gray field, you must paste it
into a gray image, convolve, and crop it out... The main convolution
functions are called internal_reduce and internal_expand and are
defined in the file convolve.c. The idea is that the convolution
function calls the edge handling function which computes a new filter
based on the old filter and the distance to the edge of the image.
For example, reflection is done by reflecting the filter through the
appropriate axis and summing. Currently defined functions are listed
below.
*/
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "convolve.h"
#define sgn(a) ( ((a)>0)?1:(((a)<0)?-1:0) )
#define clip(a,mn,mx) ( ((a)<(mn))?(mn):(((a)>=(mx))?(mx-1):(a)) )
int nocompute(register double *filt,register int x_dim,int y_dim,int x_pos,int y_pos,register double *result,int r_or_e);
int reflect1(register double *filt,register int x_dim,int y_dim,int x_pos,int y_pos,register double *result,int r_or_e);
int reflect2(register double *filt,register int x_dim,int y_dim,int x_pos,int y_pos,register double *result,int r_or_e);
int repeat(register double *filt,register int x_dim,int y_dim,int x_pos,int y_pos,register double *result,int r_or_e);
int zero(register double *filt,register int x_dim,int y_dim,int x_pos,int y_pos,register double *result,int r_or_e);
int Extend(register double *filt,register int x_dim,int y_dim,int x_pos,int y_pos,register double *result,int r_or_e);
int ereflect(register double *filt,register int x_dim,int y_dim,int x_pos,int y_pos,register double *result,int r_or_e);
int predict(register double *filt,register int x_dim,int y_dim,int x_pos,int y_pos,register double *result,int r_or_e);
int qreflect2(double *filt,int x_dim,int y_dim,int x_pos,int y_pos,double *result,int r_or_e);
/* Lookup table matching a descriptive string to the edge-handling function */
#if !THINK_C
static EDGE_HANDLER edge_foos[] =
{
{ "dont-compute", nocompute }, /* zero output for filter touching edge */
{ "zero", zero }, /* zero outside of image */
{ "repeat", repeat }, /* repeat edge pixel */
{ "reflect1", reflect1 }, /* reflect about edge pixels */
{ "reflect2", reflect2 }, /* reflect image, including edge pixels */
{ "qreflect2", qreflect2 }, /* reflect image, including edge pixels
for even-length QMF decompositions */
{ "extend", Extend }, /* extend (reflect & invert) */
{ "ereflect", ereflect }, /* orthogonal QMF reflection */
};
#else
/*
This is really stupid, but THINK C won't allow initialization of static variables in
a code resource with string addresses. So we do it this way.
The 68K code for a MATLAB 4 MEX file can only be created by THINK C.
However, for MATLAB 5, we'll be able to use Metrowerks CodeWarrior for both 68K and PPC, so this
cludge can be dropped when we drop support for MATLAB 4.
Denis Pelli, 4/1/97.
*/
static EDGE_HANDLER edge_foos[8];
void InitializeTable(EDGE_HANDLER edge_foos[])
{
static int i=0;
if(i>0) return;
edge_foos[i].name="dont-compute";
edge_foos[i++].func=nocompute;
edge_foos[i].name="zero";
edge_foos[i++].func=zero;
edge_foos[i].name="repeat";
edge_foos[i++].func=repeat;
edge_foos[i].name="reflect1";
edge_foos[i++].func=reflect1;
edge_foos[i].name="reflect2";
edge_foos[i++].func=reflect2;
edge_foos[i].name="qreflect2";
edge_foos[i++].func=qreflect2;
edge_foos[i].name="extend";
edge_foos[i++].func=Extend;
edge_foos[i].name="ereflect";
edge_foos[i++].func=ereflect;
}
#endif
/*
Function looks up an edge handler id string in the structure above, and
returns the associated function
*/
fptr edge_function(char *edges)
{
int i;
#if THINK_C
InitializeTable(edge_foos);
#endif
for (i = 0; i<sizeof(edge_foos)/sizeof(EDGE_HANDLER); i++)
if (strcmp(edges,edge_foos[i].name) IS 0)
return(edge_foos[i].func);
printf("Error: '%s' is not the name of a valid edge-handler!\n",edges);
for (i=0; i<sizeof(edge_foos)/sizeof(EDGE_HANDLER); i++)
{
if (i IS 0) printf(" Options are: ");
else printf(", ");
printf("%s",edge_foos[i].name);
}
printf("\n");
return(0);
}
You are missing a function definition (edge_function actually) which is either part of an external library or defined in a separate .cpp/.c file.

CUDA erosion algorithm

I'm new to CUDA and I'm trying to develop simple (naive) erosion algorithm with structural element 3x3. As for now, I have developed a code (it's based on nVidia presentation):
#define bx (blockIdx.x)
#define by (blockIdx.y)
#define bdx (blockDim.x)
#define bdy (blockDim.y)
#define tx (threadIdx.x)
#define ty (threadIdx.y)
#define max( a, b ) ( ((a) > (b)) ? (a) : (b) )
#define min( a, b ) ( ((a) < (b)) ? (a) : (b) )
#define TILE_H 16
#define TILE_W 16
#define D 3 //structural element diameter
#define R 1 //structural element radius
#define BLOCK_W (TILE_W+D-1)
#define BLOCK_H (TILE_H+D-1)
__global__ void erosion(int *picture, unsigned int width, unsigned int height)
{
__shared__ int pixels[BLOCK_W*BLOCK_H];
int x = bx*TILE_W + tx - R;
int y = by*TILE_H + ty - R;
x = max(0, x);
x = min(x, (int)width-1);
y = max(y,0);
y = min(y, (int)height-1);
unsigned int idx = y*width + x;
unsigned int bidx = ty*bdy+tx;
pixels[bidx] = picture[idx];
__syncthreads();
//compute pixels inside apron
if (tx>=R && tx<BLOCK_W-R && ty>=R && ty < BLOCK_H-R)
{
//erode
if (pixels[bidx] == 1)
picture[idx] = pixels[ty*bdy+(tx+1)] & pixels[ty*bdy+(tx-1)] & pixels[(ty+1)*bdy+tx] & pixels[(ty-1)*bdy+tx];
}
}
And main() function:
int main()
{
//...
int *pixels;
int img_width=M; int img_height=N;
cudaMemcpy(dev_pixels, pixels, M*N*sizeof(int), cudaMemcpyHostToDevice);
dim3 blocks(img_width/BLOCK_W, img_height/BLOCK_H);
erosion<<<blocks, D*D>>>(dev_pixels, img_width, img_height);
cudaMemcpy(output, dev_pixels, M*N*sizeof(int), cudaMemcpyDeviceToHost);
}
My problem is: it seems, that erosion() never reaches the if statement, where I want to compute pixels inside the apron. Do You happen to have any idea why is that so? I already ruled out img_widht/BLOCK_W division (it could return 0 value, but currently I fixed img_widht=54 and img_height=36).
You are launching a kernel whose grid consists of a 2D array of blocks, each of which has a 1D array of threads:
dim3 blocks(img_width/BLOCK_W, img_height/BLOCK_H); // creates 2D blocks variable
erosion<<<blocks, D*D>>>(dev_pixels, img_width, img_height);
^ ^
| |
| 1D array of threads
2D array of blocks
Since your threadblock is a 1D array of threads, threadIdx.y is always zero (for every thread in every block). Therefore ty is always zero, and this if-test always fails:
if (tx>=R && tx<BLOCK_W-R && ty>=R && ty < BLOCK_H-R)
since ty(==0) is never greater than or equal to R(==1)
You can launch a 2D array of threads in each block by defining an appropriate dim3 quantity:
dim3 threads(D,D);
and passing that in your kernel config:
erosion<<<blocks, threads>>>(dev_pixels, img_width, img_height);
I can't say whether this is sensible for the rest of your code, but with that modification I can say that the interior (body) of your if-statement in question will be reached.

I have 3 errors:expected a ")" , expected an expression, argument of type long is incompatible with parameter of type U32

/*******************************************************************/
#define cdisp(a, src, col);
#define FL_wpset_U8 256;
/*******************************************************************/
void main(void)
{
int posx= 100, posy=100, dx=300, dy=300;
long length=5000;
int threshold=125;
int lx, x0=0, y0=0;
int res1=0,res2=0, *rlc, *input, i;
long dest1,dest2,desttemp, addr;
char c;
image Area, Ovl;
ScrSetLogPage((int)ScrGetPhysPage);
OvlSetLogPage((int)OvlGetPhysPage);
OvlClearAll;
set_ovlmask(255);
ImageAssign(&Area,ScrByteAddr(posx,posy), dx, dy, ScrGetPitch);
ImageAssign(&Ovl,OvlBitAddr(posx,posy), dx, dy, OvlGetPitch);
frameo(&Ovl);
vmode(vmOvlLive);
/* follow contour */
dest1=DRAMWordMalloc((long)length);
dest2=DRAMWordMalloc((long)length);
The 2 errors are in the line frameo(&Ovl) (expected a ")" , expected an expression).
desttemp = dest1;
res1 = contour8(&Area,x0,y0,~2,threshold,length,&desttemp);
The last error is in the last line (argument of type long is incompatible with parameter of type U32). The function signature of contour8 is I32 contour8(image *a, I32 x0, I32 y0, I32 dir, I32 thr, U32 lng, U32 **dst).
I don't know how to solve it ,thanks in advance.
You almost certainly don't want those semicolons at the end of your #define lines.
Using them will most likely inject the statement separator into the middle of expressions.
You should remove the ; from defines.