core/ocl: move opencl dynamic runtime from ocl module

This commit is contained in:
Alexander Alekhin
2013-11-21 12:17:16 +04:00
parent b5cdc03b81
commit 381d7851b7
21 changed files with 0 additions and 3505 deletions

View File

@@ -0,0 +1,222 @@
import sys, os, re
#
# Parser helpers
#
def remove_comments(s):
def replacer(match):
s = match.group(0)
if s.startswith('/'):
return ""
else:
return s
pattern = re.compile(
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
re.DOTALL | re.MULTILINE
)
return re.sub(pattern, replacer, s)
def getTokens(s):
return re.findall(r'[a-z_A-Z0-9_]+|[^[a-z_A-Z0-9_ \n\r\t]', s)
def getParameter(pos, tokens):
deep = 0
p = []
while True:
if pos >= len(tokens):
break
if (tokens[pos] == ')' or tokens[pos] == ',') and deep == 0:
if tokens[pos] == ')':
pos = len(tokens)
else:
pos += 1
break
if tokens[pos] == '(':
deep += 1
if tokens[pos] == ')':
deep -= 1
p.append(tokens[pos])
pos += 1
return (' '.join(p), pos)
def getParameters(i, tokens):
assert tokens[i] == '('
i += 1
params = []
while True:
if i >= len(tokens) or tokens[i] == ')':
break
(param, i) = getParameter(i, tokens)
if len(param) > 0:
params.append(param)
else:
assert False
break
if len(params) > 0 and params[0] == 'void':
del params[0]
return params
def postProcessParameters(fns):
for fn in fns:
fn['params_full'] = list(fn['params'])
for i in range(len(fn['params'])):
p = fn['params'][i]
if p.find('(') != -1:
p = re.sub(r'\* *([a-zA-Z0-9_]*) ?\)', '*)', p, 1)
fn['params'][i] = p
continue
parts = re.findall(r'[a-z_A-Z0-9]+|\*', p)
if len(parts) > 1:
if parts[-1].find('*') == -1:
del parts[-1]
fn['params'][i] = ' '.join(parts)
#
# Generator helpers
#
def outputToString(f):
def wrapped(*args, **kwargs):
from cStringIO import StringIO
old_stdout = sys.stdout
sys.stdout = str_stdout = StringIO()
res = f(*args, **kwargs)
assert res is None
sys.stdout = old_stdout
result = str_stdout.getvalue()
result = re.sub(r'([^\n ]) [ ]+', r'\1 ', result) # don't remove spaces at start of line
result = re.sub(r' ,', ',', result)
result = re.sub(r' \*', '*', result)
result = re.sub(r'\( ', '(', result)
result = re.sub(r' \)', ')', result)
return result
return wrapped
@outputToString
def generateEnums(fns, prefix='OPENCL_FN'):
print '// generated by %s' % os.path.basename(sys.argv[0])
print 'enum %s_ID {' % prefix
first = True
for fn in fns:
print ' %s_%s%s,' % (prefix, fn['name'], ' = 0' if first else '')
first = False
print '};'
@outputToString
def generateNames(fns, prefix='opencl_fn'):
print '// generated by %s' % os.path.basename(sys.argv[0])
print 'const char* %s_names[] = {' % prefix
for fn in fns:
print ' "%s",' % (fn['name'])
print '};'
@outputToString
def generatePtrs(fns, prefix='opencl_fn'):
print '// generated by %s' % os.path.basename(sys.argv[0])
print 'void* %s_ptrs[] = {' % prefix
for fn in fns:
print ' &%s,' % (fn['name'])
print '};'
@outputToString
def generateRemapOrigin(fns):
print '// generated by %s' % os.path.basename(sys.argv[0])
for fn in fns:
print '#define %s %s_' % (fn['name'], fn['name'])
@outputToString
def generateRemapDynamic(fns):
print '// generated by %s' % os.path.basename(sys.argv[0])
for fn in fns:
print '#undef %s' % (fn['name'])
print '#define %s %s_pfn' % (fn['name'], fn['name'])
@outputToString
def generateParamsCfg(fns):
for fn in fns:
print '%s %d' % (fn['name'], len(fn['params']))
@outputToString
def generateFnDeclaration(fns):
print '// generated by %s' % os.path.basename(sys.argv[0])
for fn in fns:
print 'extern CL_RUNTIME_EXPORT %s %s (%s *%s)(%s);' % (' '.join(fn['modifiers']), ' '.join(fn['ret']), ' '.join(fn['calling']),
fn['name'], ', '.join(fn['params'] if not fn.has_key('params_full') else fn['params_full']))
@outputToString
def generateFnDefinition(fns, lprefix='opencl_fn', uprefix='OPENCL_FN'):
print '// generated by %s' % os.path.basename(sys.argv[0])
for fn in fns:
print '%s%s (%s *%s)(%s) = %s%d<%s_%s, %s%s>::switch_fn;' % \
((' '.join(fn['modifiers'] + ' ') if len(fn['modifiers']) > 0 else ''),
' '.join(fn['ret']), ' '.join(fn['calling']), fn['name'], ', '.join(fn['params']), \
lprefix, len(fn['params']), uprefix, fn['name'], ' '.join(fn['ret']), ('' if len(fn['params']) == 0 else ', ' + ', '.join(fn['params'])))
@outputToString
def generateTemplates(sz, lprefix, switch_name, calling_convention=''):
print '// generated by %s' % os.path.basename(sys.argv[0])
for sz in range(sz):
template_params = ['int ID', 'typename _R']
types = []
types_with_params = []
params = []
for i in range(1, sz + 1):
template_params.append('typename _T%d' % i)
types.append('_T%d' % i)
types_with_params.append('_T%d p%d' % (i, i))
params.append('p%d' % i)
print 'template <%s>' % ', '.join(template_params)
print 'struct %s%d' % (lprefix, sz)
print '{'
print ' typedef _R (%s *FN)(%s);' % (calling_convention, ', '.join(types))
print ' static _R %s switch_fn(%s)' % (calling_convention, ', '.join(types_with_params))
print ' { return ((FN)%s(ID))(%s); }' % (switch_name, ', '.join(params))
print '};'
print ''
@outputToString
def generateInlineWrappers(fns):
print '// generated by %s' % os.path.basename(sys.argv[0])
for fn in fns:
print '#undef %s' % (fn['name'])
print '#define %s %s_fn' % (fn['name'], fn['name'])
params = []
call_params = []
for i in range(0, len(fn['params'])):
t = fn['params'][i]
if t.find('*)') >= 0:
p = re.sub(r'\*\)', (' *p%d)' % i), t, 1)
params.append(p)
else:
params.append('%s p%d' % (t, i))
call_params.append('p%d' % (i))
if len(fn['ret']) == 1 and fn['ret'][0] == 'void':
print 'inline void %s(%s) { %s_pfn(%s); }' \
% (fn['name'], ', '.join(params), fn['name'], ', '.join(call_params))
else:
print 'inline %s %s(%s) { return %s_pfn(%s); }' \
% (' '.join(fn['ret']), fn['name'], ', '.join(params), fn['name'], ', '.join(call_params))
def ProcessTemplate(inputFile, ctx, noteLine='//\n// AUTOGENERATED, DO NOT EDIT\n//'):
f = open(inputFile, "r")
if noteLine:
print noteLine
for line in f:
if line.startswith('@'):
assert line[-1] == '\n'
line = line[:-1] # remove '\n'
assert line[-1] == '@'
name = line[1:-1]
assert ctx.has_key(name), name
line = ctx[name]
print line,
f.close()

View File

@@ -0,0 +1,6 @@
#!/bin/bash -e
echo "Generate files for CL runtime..."
cat sources/cl.h | python parser_cl.py cl_runtime_opencl
cat sources/clAmdBlas.h | python parser_clamdblas.py
cat sources/clAmdFft.h | python parser_clamdfft.py
echo "Generate files for CL runtime... Done"

View File

@@ -0,0 +1,118 @@
#!/bin/python
# usage:
# cat opencl11/cl.h | $0 cl_runtime_opencl11
# cat opencl12/cl.h | $0 cl_runtime_opencl12
import sys, re;
from common import remove_comments, getTokens, getParameters, postProcessParameters
try:
if len(sys.argv) > 1:
outfile = open('../../../include/opencv2/ocl/cl_runtime/' + sys.argv[1] + '.hpp', "w")
outfile_impl = open('../' + sys.argv[1] + '_impl.hpp', "w")
outfile_wrappers = open('../../../include/opencv2/ocl/cl_runtime/' + sys.argv[1] + '_wrappers.hpp', "w")
if len(sys.argv) > 2:
f = open(sys.argv[2], "r")
else:
f = sys.stdin
else:
sys.exit("ERROR. Specify output file")
except:
sys.exit("ERROR. Can't open input/output file, check parameters")
fns = []
while True:
line = f.readline()
if len(line) == 0:
break
assert isinstance(line, str)
parts = line.split();
if line.startswith('extern') and line.find('CL_API_CALL') != -1:
# read block of lines
while True:
nl = f.readline()
nl = nl.strip()
nl = re.sub(r'\n', r'', nl)
if len(nl) == 0:
break;
line += ' ' + nl
line = remove_comments(line)
parts = getTokens(line)
fn = {}
modifiers = []
ret = []
calling = []
i = 1
while (i < len(parts)):
if parts[i].startswith('CL_'):
modifiers.append(parts[i])
else:
break
i += 1
while (i < len(parts)):
if not parts[i].startswith('CL_'):
ret.append(parts[i])
else:
break
i += 1
while (i < len(parts)):
calling.append(parts[i])
i += 1
if parts[i - 1] == 'CL_API_CALL':
break
fn['modifiers'] = [] # modifiers
fn['ret'] = ret
fn['calling'] = calling
# print 'modifiers='+' '.join(modifiers)
# print 'ret='+' '.join(type)
# print 'calling='+' '.join(calling)
name = parts[i]; i += 1;
fn['name'] = name
print 'name=' + name
params = getParameters(i, parts)
fn['params'] = params
# print 'params="'+','.join(params)+'"'
fns.append(fn)
f.close()
print 'Found %d functions' % len(fns)
postProcessParameters(fns)
from pprint import pprint
pprint(fns)
from common import *
ctx = {}
ctx['CL_REMAP_ORIGIN'] = generateRemapOrigin(fns)
ctx['CL_REMAP_DYNAMIC'] = generateRemapDynamic(fns)
ctx['CL_FN_DECLARATIONS'] = generateFnDeclaration(fns)
sys.stdout = outfile
ProcessTemplate('template/cl_runtime_opencl.hpp.in', ctx)
ctx['CL_FN_INLINE_WRAPPERS'] = generateInlineWrappers(fns)
sys.stdout = outfile_wrappers
ProcessTemplate('template/cl_runtime_opencl_wrappers.hpp.in', ctx)
ctx['CL_FN_ENUMS'] = generateEnums(fns)
ctx['CL_FN_NAMES'] = generateNames(fns)
ctx['CL_FN_DEFINITIONS'] = generateFnDefinition(fns)
ctx['CL_FN_PTRS'] = generatePtrs(fns)
ctx['CL_FN_SWITCH'] = generateTemplates(15, 'opencl_fn', 'opencl_check_fn', 'CL_API_CALL')
sys.stdout = outfile_impl
ProcessTemplate('template/cl_runtime_impl_opencl.hpp.in', ctx)

View File

@@ -0,0 +1,107 @@
#!/bin/python
# usage:
# cat clAmdBlas.h | $0
import sys, re;
from common import remove_comments, getTokens, getParameters, postProcessParameters
try:
if len(sys.argv) > 1:
f = open(sys.argv[1], "r")
else:
f = sys.stdin
except:
sys.exit("ERROR. Can't open input file")
fns = []
while True:
line = f.readline()
if len(line) == 0:
break
assert isinstance(line, str)
line = line.strip()
parts = line.split();
if (line.startswith('clAmd') or line.startswith('cl_') or line == 'void') and len(line.split()) == 1 and line.find('(') == -1:
fn = {}
modifiers = []
ret = []
calling = []
i = 0
while (i < len(parts)):
if parts[i].startswith('CL_'):
modifiers.append(parts[i])
else:
break
i += 1
while (i < len(parts)):
if not parts[i].startswith('CL_'):
ret.append(parts[i])
else:
break
i += 1
while (i < len(parts)):
calling.append(parts[i])
i += 1
fn['modifiers'] = [] # modifiers
fn['ret'] = ret
fn['calling'] = calling
# print 'modifiers='+' '.join(modifiers)
# print 'ret='+' '.join(type)
# print 'calling='+' '.join(calling)
# read block of lines
line = f.readline()
while True:
nl = f.readline()
nl = nl.strip()
nl = re.sub(r'\n', r'', nl)
if len(nl) == 0:
break;
line += ' ' + nl
line = remove_comments(line)
parts = getTokens(line)
i = 0;
name = parts[i]; i += 1;
fn['name'] = name
print 'name=' + name
params = getParameters(i, parts)
fn['params'] = params
# print 'params="'+','.join(params)+'"'
fns.append(fn)
f.close()
print 'Found %d functions' % len(fns)
postProcessParameters(fns)
from pprint import pprint
pprint(fns)
from common import *
ctx = {}
ctx['CLAMDBLAS_REMAP_ORIGIN'] = generateRemapOrigin(fns)
ctx['CLAMDBLAS_REMAP_DYNAMIC'] = generateRemapDynamic(fns)
ctx['CLAMDBLAS_FN_DECLARATIONS'] = generateFnDeclaration(fns)
sys.stdout = open('../../../include/opencv2/ocl/cl_runtime/clamdblas_runtime.hpp', 'w')
ProcessTemplate('template/clamdblas_runtime.hpp.in', ctx)
ctx['CL_FN_ENUMS'] = generateEnums(fns, 'OPENCLAMDBLAS_FN')
ctx['CL_FN_NAMES'] = generateNames(fns, 'openclamdblas_fn')
ctx['CL_FN_DEFINITIONS'] = generateFnDefinition(fns, 'openclamdblas_fn', 'OPENCLAMDBLAS_FN')
ctx['CL_FN_PTRS'] = generatePtrs(fns, 'openclamdblas_fn')
ctx['CL_FN_SWITCH'] = generateTemplates(23, 'openclamdblas_fn', 'openclamdblas_check_fn', '')
sys.stdout = open('../clamdblas_runtime.cpp', 'w')
ProcessTemplate('template/clamdblas_runtime.cpp.in', ctx)

View File

@@ -0,0 +1,104 @@
#!/bin/python
# usage:
# cat clAmdFft.h | $0
import sys, re;
from common import remove_comments, getTokens, getParameters, postProcessParameters
try:
if len(sys.argv) > 1:
f = open(sys.argv[1], "r")
else:
f = sys.stdin
except:
sys.exit("ERROR. Can't open input file")
fns = []
while True:
line = f.readline()
if len(line) == 0:
break
assert isinstance(line, str)
line = line.strip()
if line.startswith('CLAMDFFTAPI'):
line = re.sub(r'\n', r'', line)
while True:
nl = f.readline()
nl = nl.strip()
nl = re.sub(r'\n', r'', nl)
if len(nl) == 0:
break;
line += ' ' + nl
line = remove_comments(line)
parts = getTokens(line)
fn = {}
modifiers = []
ret = []
calling = []
i = 0
while True:
if parts[i] == "CLAMDFFTAPI":
modifiers.append(parts[i])
else:
break
i += 1
while (i < len(parts)):
if not parts[i] == '(':
ret.append(parts[i])
else:
del ret[-1]
i -= 1
break
i += 1
fn['modifiers'] = [] # modifiers
fn['ret'] = ret
fn['calling'] = calling
name = parts[i]; i += 1;
fn['name'] = name
print 'name=' + name
params = getParameters(i, parts)
if len(params) > 0 and params[0] == 'void':
del params[0]
fn['params'] = params
# print 'params="'+','.join(params)+'"'
fns.append(fn)
f.close()
print 'Found %d functions' % len(fns)
postProcessParameters(fns)
from pprint import pprint
pprint(fns)
from common import *
ctx = {}
ctx['CLAMDFFT_REMAP_ORIGIN'] = generateRemapOrigin(fns)
ctx['CLAMDFFT_REMAP_DYNAMIC'] = generateRemapDynamic(fns)
ctx['CLAMDFFT_FN_DECLARATIONS'] = generateFnDeclaration(fns)
sys.stdout = open('../../../include/opencv2/ocl/cl_runtime/clamdfft_runtime.hpp', 'w')
ProcessTemplate('template/clamdfft_runtime.hpp.in', ctx)
ctx['CL_FN_ENUMS'] = generateEnums(fns, 'OPENCLAMDFFT_FN')
ctx['CL_FN_NAMES'] = generateNames(fns, 'openclamdfft_fn')
ctx['CL_FN_DEFINITIONS'] = generateFnDefinition(fns, 'openclamdfft_fn', 'OPENCLAMDFFT_FN')
ctx['CL_FN_PTRS'] = generatePtrs(fns, 'openclamdfft_fn')
ctx['CL_FN_SWITCH'] = generateTemplates(23, 'openclamdfft_fn', 'openclamdfft_check_fn', '')
sys.stdout = open('../clamdfft_runtime.cpp', 'w')
ProcessTemplate('template/clamdfft_runtime.cpp.in', ctx)

View File

@@ -0,0 +1,75 @@
#include "precomp.hpp"
#ifdef HAVE_CLAMDBLAS
#include "opencv2/ocl/cl_runtime/cl_runtime.hpp"
#include "opencv2/ocl/cl_runtime/clamdblas_runtime.hpp"
#if defined(_WIN32)
static void* WinGetProcAddress(const char* name)
{
static HMODULE opencl_module = NULL;
if (!opencl_module)
{
opencl_module = GetModuleHandleA("clAmdBlas.dll");
if (!opencl_module)
{
opencl_module = LoadLibraryA("clAmdBlas.dll");
if (!opencl_module)
return NULL;
}
}
return (void*)GetProcAddress(opencl_module, name);
}
#define CV_CL_GET_PROC_ADDRESS(name) WinGetProcAddress(name)
#endif // _WIN32
#if defined(linux)
#include <dlfcn.h>
#include <stdio.h>
static void* GetProcAddress (const char* name)
{
static void* h = NULL;
if (!h)
{
h = dlopen("libclAmdBlas.so", RTLD_LAZY | RTLD_GLOBAL);
if (!h)
return NULL;
}
return dlsym(h, name);
}
#define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name)
#endif
#ifndef CV_CL_GET_PROC_ADDRESS
#define CV_CL_GET_PROC_ADDRESS(name) NULL
#endif
@CL_FN_ENUMS@
@CL_FN_NAMES@
static void* openclamdblas_check_fn(int ID)
{
void* func = CV_CL_GET_PROC_ADDRESS(openclamdblas_fn_names[ID]);
if (!func)
{
std::ostringstream msg;
msg << "OpenCL AMD BLAS function is not available: [" << openclamdblas_fn_names[ID] << "]";
CV_Error(CV_StsBadFunc, msg.str());
}
extern void* openclamdblas_fn_ptrs[];
*(void**)(openclamdblas_fn_ptrs[ID]) = func;
return func;
}
namespace {
@CL_FN_SWITCH@
}
@CL_FN_DEFINITIONS@
@CL_FN_PTRS@
#endif

View File

@@ -0,0 +1,25 @@
#ifndef __OPENCV_OCL_CLAMDBLAS_RUNTIME_HPP__
#define __OPENCV_OCL_CLAMDBLAS_RUNTIME_HPP__
#ifdef HAVE_CLAMDBLAS
@CLAMDBLAS_REMAP_ORIGIN@
#include <clAmdBlas.h>
@CLAMDBLAS_REMAP_DYNAMIC@
#ifndef CL_RUNTIME_EXPORT
#if (defined(BUILD_SHARED_LIBS) || defined(OPENCV_OCL_SHARED)) && (defined WIN32 || defined _WIN32 || defined WINCE)
#define CL_RUNTIME_EXPORT __declspec(dllimport)
#else
#define CL_RUNTIME_EXPORT
#endif
#endif
@CLAMDBLAS_FN_DECLARATIONS@
#endif
#endif // __OPENCV_OCL_CLAMDBLAS_RUNTIME_HPP__

View File

@@ -0,0 +1,75 @@
#include "precomp.hpp"
#ifdef HAVE_CLAMDFFT
#include "opencv2/ocl/cl_runtime/cl_runtime.hpp"
#include "opencv2/ocl/cl_runtime/clamdfft_runtime.hpp"
#if defined(_WIN32)
static void* WinGetProcAddress(const char* name)
{
static HMODULE opencl_module = NULL;
if (!opencl_module)
{
opencl_module = GetModuleHandleA("clAmdFft.Runtime.dll");
if (!opencl_module)
{
opencl_module = LoadLibraryA("clAmdFft.Runtime.dll");
if (!opencl_module)
return NULL;
}
}
return (void*)GetProcAddress(opencl_module, name);
}
#define CV_CL_GET_PROC_ADDRESS(name) WinGetProcAddress(name)
#endif // _WIN32
#if defined(linux)
#include <dlfcn.h>
#include <stdio.h>
static void* GetProcAddress (const char* name)
{
static void* h = NULL;
if (!h)
{
h = dlopen("libclAmdFft.Runtime.so", RTLD_LAZY | RTLD_GLOBAL);
if (!h)
return NULL;
}
return dlsym(h, name);
}
#define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name)
#endif
#ifndef CV_CL_GET_PROC_ADDRESS
#define CV_CL_GET_PROC_ADDRESS(name) NULL
#endif
@CL_FN_ENUMS@
@CL_FN_NAMES@
static void* openclamdfft_check_fn(int ID)
{
void* func = CV_CL_GET_PROC_ADDRESS(openclamdfft_fn_names[ID]);
if (!func)
{
std::ostringstream msg;
msg << "OpenCL AMD FFT function is not available: [" << openclamdfft_fn_names[ID] << "]";
CV_Error(CV_StsBadFunc, msg.str());
}
extern void* openclamdfft_fn_ptrs[];
*(void**)(openclamdfft_fn_ptrs[ID]) = func;
return func;
}
namespace {
@CL_FN_SWITCH@
}
@CL_FN_DEFINITIONS@
@CL_FN_PTRS@
#endif

View File

@@ -0,0 +1,25 @@
#ifndef __OPENCV_OCL_CLAMDFFT_RUNTIME_HPP__
#define __OPENCV_OCL_CLAMDFFT_RUNTIME_HPP__
#ifdef HAVE_CLAMDFFT
@CLAMDFFT_REMAP_ORIGIN@
#include <clAmdFft.h>
@CLAMDFFT_REMAP_DYNAMIC@
#ifndef CL_RUNTIME_EXPORT
#if (defined(BUILD_SHARED_LIBS) || defined(OPENCV_OCL_SHARED)) && (defined WIN32 || defined _WIN32 || defined WINCE)
#define CL_RUNTIME_EXPORT __declspec(dllimport)
#else
#define CL_RUNTIME_EXPORT
#endif
#endif
@CLAMDFFT_FN_DECLARATIONS@
#endif
#endif // __OPENCV_OCL_CLAMDFFT_RUNTIME_HPP__

View File

@@ -0,0 +1,10 @@
@CL_FN_ENUMS@
@CL_FN_NAMES@
namespace {
@CL_FN_SWITCH@
}
@CL_FN_DEFINITIONS@
@CL_FN_PTRS@

View File

@@ -0,0 +1,24 @@
#ifndef __OPENCV_OCL_CL_RUNTIME_OPENCL_HPP__
#define __OPENCV_OCL_CL_RUNTIME_OPENCL_HPP__
@CL_REMAP_ORIGIN@
#if defined __APPLE__
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif
@CL_REMAP_DYNAMIC@
#ifndef CL_RUNTIME_EXPORT
#if (defined(BUILD_SHARED_LIBS) || defined(OPENCV_OCL_SHARED)) && (defined WIN32 || defined _WIN32 || defined WINCE)
#define CL_RUNTIME_EXPORT __declspec(dllimport)
#else
#define CL_RUNTIME_EXPORT
#endif
#endif
@CL_FN_DECLARATIONS@
#endif // __OPENCV_OCL_CL_RUNTIME_OPENCL_HPP__

View File

@@ -0,0 +1,6 @@
#ifndef __OPENCV_OCL_CL_RUNTIME_OPENCL_WRAPPERS_HPP__
#define __OPENCV_OCL_CL_RUNTIME_OPENCL_WRAPPERS_HPP__
@CL_FN_INLINE_WRAPPERS@
#endif // __OPENCV_OCL_CL_RUNTIME_OPENCL_WRAPPERS_HPP__