Better vector/C++ containers support for Scilab
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2012-scilab@13719 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
parent
0d7be20f79
commit
6138b43d7b
8 changed files with 243 additions and 71 deletions
|
|
@ -1,7 +1,7 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
* scicontainer.swg
|
||||
*
|
||||
* Scilab cell <-> C++ container wrapper (Basd on Octave version)
|
||||
* Scilab list <-> C++ container wrapper (Based on Octave wrapper)
|
||||
*
|
||||
* This wrapper, and its iterator, allows a general use (and reuse) of
|
||||
* the mapping between C++ and Scilab, thanks to the C++ templates.
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
%include <sciiterators.swg>
|
||||
|
||||
// The Octave C++ Wrap
|
||||
// The Scilab C++ Wrap
|
||||
|
||||
%insert(header) %{
|
||||
#include <stdexcept>
|
||||
|
|
@ -74,8 +74,8 @@ namespace std {
|
|||
bool
|
||||
operator()(const SciObject& v, const SciObject& w) const
|
||||
{
|
||||
SciObject res = do_binary_op(SciObject::op_le,v,w);
|
||||
return res.is_true();
|
||||
//SciObject res = do_binary_op(SciObject::op_le,v,w);
|
||||
return true;//res.is_true();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -191,7 +191,7 @@ namespace swig {
|
|||
namespace swig
|
||||
{
|
||||
template <class T>
|
||||
struct SciSequence_Ref // * octave can't support these, because of how assignment works
|
||||
struct SciSequence_Ref // * Scilab can't support these, because of how assignment works
|
||||
{
|
||||
SciSequence_Ref(const SciObject& seq, int index)
|
||||
: _seq(seq), _index(index)
|
||||
|
|
@ -489,7 +489,7 @@ namespace swig
|
|||
#endif //SWIG_EXPORT_ITERATOR_METHODS
|
||||
%enddef
|
||||
|
||||
// The octave container methods
|
||||
// The Scilab container methods
|
||||
|
||||
%define %swig_container_methods(Container...)
|
||||
%enddef
|
||||
|
|
@ -543,15 +543,15 @@ namespace swig
|
|||
namespace swig {
|
||||
template <class SciSeq, class Seq>
|
||||
inline void
|
||||
assign(const SciSeq& octseq, Seq* seq) {
|
||||
assign(const SciSeq& sciseq, Seq* seq) {
|
||||
%#ifdef SWIG_STD_NOASSIGN_STL
|
||||
typedef typename SciSeq::value_type value_type;
|
||||
typename SciSeq::const_iterator it = octseq.begin();
|
||||
for (;it != octseq.end(); ++it) {
|
||||
typename SciSeq::const_iterator it = sciseq.begin();
|
||||
for (;it != sciseq.end(); ++it) {
|
||||
seq->insert(seq->end(),(value_type)(*it));
|
||||
}
|
||||
%#else
|
||||
seq->assign(octseq.begin(), octseq.end());
|
||||
seq->assign(sciseq.begin(), sciseq.end());
|
||||
%#endif
|
||||
}
|
||||
|
||||
|
|
@ -570,18 +570,18 @@ namespace swig {
|
|||
}
|
||||
} else if (obj.is_cell()) {
|
||||
try {
|
||||
SciSequence_Cont<value_type> octseq(obj);
|
||||
SciSequence_Cont<value_type> sciseq(obj);
|
||||
if (seq) {
|
||||
sequence *pseq = new sequence();
|
||||
assign(octseq, pseq);
|
||||
assign(sciseq, pseq);
|
||||
*seq = pseq;
|
||||
return SWIG_NEWOBJ;
|
||||
} else {
|
||||
return octseq.check() ? SWIG_OK : SWIG_ERROR;
|
||||
return sciseq.check() ? SWIG_OK : SWIG_ERROR;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
if (seq&&!error_state)
|
||||
Scierror(999, "swig type error: %s",e.what());
|
||||
error("swig type error: %s",e.what());
|
||||
return SWIG_ERROR;
|
||||
}
|
||||
}
|
||||
|
|
@ -597,7 +597,7 @@ namespace swig {
|
|||
typedef typename sequence::const_iterator const_iterator;
|
||||
|
||||
static SciObject from(const sequence& seq) {
|
||||
#ifdef SWIG_OCTAVE_EXTRA_NATIVE_CONTAINERS
|
||||
#ifdef SWIG_SCILAB_EXTRA_NATIVE_CONTAINERS
|
||||
swig_type_info *desc = swig::type_info<sequence>();
|
||||
if (desc && desc->clientdata) {
|
||||
return SWIG_NewPointerObj(new sequence(seq), desc, SWIG_POINTER_OWN);
|
||||
|
|
@ -613,7 +613,7 @@ namespace swig {
|
|||
}
|
||||
return c;
|
||||
} else {
|
||||
Scierror(999, "swig overflow error: sequence size not valid in Scilab");
|
||||
error("swig overflow error: sequence size not valid in Scilab");
|
||||
return SciObject();
|
||||
}
|
||||
return SciObject();
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ namespace swig
|
|||
struct stop_iteration {};
|
||||
|
||||
%typemap(throws) stop_iteration {
|
||||
Scierror(999, "stop_iteration exception");
|
||||
error("stop_iteration exception");
|
||||
SWIG_fail;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,3 +26,10 @@ static void SWIG_Scilab_SetOutputPosition(int _outputPosition) {
|
|||
|
||||
#define Scilab_Error_Occurred() 0
|
||||
#define SWIG_Scilab_AddErrorMsg(msg) {;}
|
||||
|
||||
namespace std {
|
||||
class SciObject {
|
||||
public:
|
||||
SciObject();
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
// Based on Python implementation
|
||||
|
||||
%fragment("StdTraits","header",fragment="StdTraitsCommon")
|
||||
{
|
||||
namespace swig {
|
||||
/*
|
||||
Traits that provides the from method
|
||||
*/
|
||||
// Traits that provides the from method
|
||||
template <class Type> struct traits_from_ptr {
|
||||
static SciObject from(Type *val, int owner = 0) {
|
||||
return SWIG_InternalNewPointerObj(val, type_info<Type>(), owner);
|
||||
return 0; //SWIG_NewPointerObj(val, type_info<Type>(), owner);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -41,29 +37,27 @@ namespace swig {
|
|||
return traits_from_ptr<Type>::from(val, owner);
|
||||
}
|
||||
|
||||
/*
|
||||
Traits that provides the asval/as/check method
|
||||
*/
|
||||
// Traits that provides the asval/as/check method
|
||||
template <class Type>
|
||||
struct traits_asptr {
|
||||
static int asptr(SciObject obj, Type **val) {
|
||||
struct traits_asptr {
|
||||
static int asptr(const SciObject& obj, Type **val) {
|
||||
Type *p;
|
||||
int res = SWIG_ConvertPtr(obj, (void**)&p, type_info<Type>(), 0);
|
||||
if (SWIG_IsOK(res)) {
|
||||
if (val) *val = p;
|
||||
if (val) *val = p;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <class Type>
|
||||
inline int asptr(SciObject obj, Type **vptr) {
|
||||
inline int asptr(const SciObject& obj, Type **vptr) {
|
||||
return traits_asptr<Type>::asptr(obj, vptr);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
struct traits_asval {
|
||||
static int asval(SciObject obj, Type *val) {
|
||||
static int asval(const SciObject& obj, Type *val) {
|
||||
if (val) {
|
||||
Type *p = 0;
|
||||
int res = traits_asptr<Type>::asptr(obj, &p);
|
||||
|
|
@ -86,7 +80,7 @@ namespace swig {
|
|||
};
|
||||
|
||||
template <class Type> struct traits_asval<Type*> {
|
||||
static int asval(SciObject obj, Type **val) {
|
||||
static int asval(const SciObject& obj, Type **val) {
|
||||
if (val) {
|
||||
typedef typename noconst_traits<Type>::noconst_type noconst_type;
|
||||
noconst_type *p = 0;
|
||||
|
|
@ -102,30 +96,30 @@ namespace swig {
|
|||
};
|
||||
|
||||
template <class Type>
|
||||
inline int asval(SciObject obj, Type *val) {
|
||||
inline int asval(const SciObject& obj, Type *val) {
|
||||
return traits_asval<Type>::asval(obj, val);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
struct traits_as<Type, value_category> {
|
||||
static Type as(SciObject obj, bool throw_error) {
|
||||
static Type as(const SciObject& obj, bool throw_error) {
|
||||
Type v;
|
||||
int res = asval(obj, &v);
|
||||
if (!obj || !SWIG_IsOK(res)) {
|
||||
// if (!PyErr_Occurred()) {
|
||||
// ::%type_error(swig::type_name<Type>());
|
||||
// }
|
||||
//if (!obj.is_defined() || !SWIG_IsOK(res)) {
|
||||
if (!Scilab_Error_Occurred()) {
|
||||
%type_error(swig::type_name<Type>());
|
||||
}
|
||||
if (throw_error) throw std::invalid_argument("bad type");
|
||||
}
|
||||
//}
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Type>
|
||||
struct traits_as<Type, pointer_category> {
|
||||
static Type as(SciObject obj, bool throw_error) {
|
||||
static Type as(const SciObject& obj, bool throw_error) {
|
||||
Type *v = 0;
|
||||
int res = (obj ? traits_asptr<Type>::asptr(obj, &v) : SWIG_ERROR);
|
||||
int res = traits_asptr<Type>::asptr(obj, &v);
|
||||
if (SWIG_IsOK(res) && v) {
|
||||
if (SWIG_IsNewObj(res)) {
|
||||
Type r(*v);
|
||||
|
|
@ -137,9 +131,9 @@ namespace swig {
|
|||
} else {
|
||||
// Uninitialized return value, no Type() constructor required.
|
||||
static Type *v_def = (Type*) malloc(sizeof(Type));
|
||||
// if (!PyErr_Occurred()) {
|
||||
// %type_error(swig::type_name<Type>());
|
||||
// }
|
||||
if (!Scilab_Error_Occurred()) {
|
||||
%type_error(swig::type_name<Type>());
|
||||
}
|
||||
if (throw_error) throw std::invalid_argument("bad type");
|
||||
memset(v_def,0,sizeof(Type));
|
||||
return *v_def;
|
||||
|
|
@ -149,15 +143,15 @@ namespace swig {
|
|||
|
||||
template <class Type>
|
||||
struct traits_as<Type*, pointer_category> {
|
||||
static Type* as(SciObject obj, bool throw_error) {
|
||||
static Type* as(const SciObject& obj, bool throw_error) {
|
||||
Type *v = 0;
|
||||
int res = (obj ? traits_asptr<Type>::asptr(obj, &v) : SWIG_ERROR);
|
||||
int res = traits_asptr<Type>::asptr(obj, &v);
|
||||
if (SWIG_IsOK(res)) {
|
||||
return v;
|
||||
} else {
|
||||
// if (!PyErr_Occurred()) {
|
||||
// %type_error(swig::type_name<Type>());
|
||||
// }
|
||||
if (!Scilab_Error_Occurred()) {
|
||||
%type_error(swig::type_name<Type>());
|
||||
}
|
||||
if (throw_error) throw std::invalid_argument("bad type");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -165,28 +159,28 @@ namespace swig {
|
|||
};
|
||||
|
||||
template <class Type>
|
||||
inline Type as(SciObject obj, bool te = false) {
|
||||
inline Type as(const SciObject& obj, bool te = false) {
|
||||
return traits_as<Type, typename traits<Type>::category>::as(obj, te);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
struct traits_check<Type, value_category> {
|
||||
static bool check(SciObject obj) {
|
||||
int res = obj ? asval(obj, (Type *)(0)) : SWIG_ERROR;
|
||||
static bool check(const SciObject& obj) {
|
||||
int res = asval(obj, (Type *)(0));
|
||||
return SWIG_IsOK(res) ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Type>
|
||||
struct traits_check<Type, pointer_category> {
|
||||
static bool check(SciObject obj) {
|
||||
int res = obj ? asptr(obj, (Type **)(0)) : SWIG_ERROR;
|
||||
static bool check(const SciObject& obj) {
|
||||
int res = asptr(obj, (Type **)(0));
|
||||
return SWIG_IsOK(res) ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Type>
|
||||
inline bool check(SciObject obj) {
|
||||
inline bool check(const SciObject& obj) {
|
||||
return traits_check<Type, typename traits<Type>::category>::check(obj);
|
||||
}
|
||||
}
|
||||
|
|
@ -197,7 +191,7 @@ namespace swig {
|
|||
namespace swig {
|
||||
template <> struct traits_asval<Type > {
|
||||
typedef Type value_type;
|
||||
static int asval(SciObject obj, value_type *val) {
|
||||
static int asval(const SciObject& obj, value_type *val) {
|
||||
if (Check(obj)) {
|
||||
if (val) *val = As(obj);
|
||||
return SWIG_OK;
|
||||
|
|
@ -214,7 +208,7 @@ namespace swig {
|
|||
|
||||
template <>
|
||||
struct traits_check<Type, value_category> {
|
||||
static int check(SciObject obj) {
|
||||
static int check(const SciObject& obj) {
|
||||
int res = Check(obj);
|
||||
return obj && res ? res : 0;
|
||||
}
|
||||
|
|
@ -229,3 +223,4 @@ namespace swig {
|
|||
#define specialize_std_deque(Type,Check,As,From) %specialize_std_container(%arg(Type),Check,As,From)
|
||||
#define specialize_std_set(Type,Check,As,From) %specialize_std_container(%arg(Type),Check,As,From)
|
||||
#define specialize_std_multiset(Type,Check,As,From) %specialize_std_container(%arg(Type),Check,As,From)
|
||||
|
||||
|
|
|
|||
64
Lib/scilab/scivector.i
Normal file
64
Lib/scilab/scivector.i
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Vectors typemaps
|
||||
*/
|
||||
|
||||
// Typemap for input arguments of type const std::vector<double> &
|
||||
%typecheck(SWIG_TYPECHECK_POINTER)
|
||||
const std::vector<double> &
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
%typemap(in)
|
||||
const std::vector<double> &
|
||||
(int is_new_object=0, std::vector<double> arrayv)
|
||||
{
|
||||
{
|
||||
SciErr sciErr;
|
||||
int iRows = 0;
|
||||
int iCols = 0;
|
||||
int *piAddrVar = NULL;
|
||||
double *pdblTmp = NULL;
|
||||
|
||||
/* Scilab value must be a double vector */
|
||||
sciErr = getVarAddressFromPosition(pvApiCtx, $input, &piAddrVar);
|
||||
if (sciErr.iErr) {
|
||||
printError(&sciErr, 0);
|
||||
return SWIG_ERROR;
|
||||
}
|
||||
|
||||
if (isDoubleType(pvApiCtx, piAddrVar) && !isVarComplex(pvApiCtx, piAddrVar)) {
|
||||
sciErr = getMatrixOfDouble(pvApiCtx, piAddrVar, &iRows, &iCols, &pdblTmp);
|
||||
if (sciErr.iErr) {
|
||||
printError(&sciErr, 0);
|
||||
return SWIG_ERROR;
|
||||
}
|
||||
} else {
|
||||
Scierror(999, _("%s: Wrong type for input argument #%d: A real vector expected.\n"), fname, $input);
|
||||
return SWIG_ERROR;
|
||||
}
|
||||
|
||||
if ((iRows!=1) && (iCols!=1)) {
|
||||
Scierror(999, _("%s: Wrong size for input argument #%d: A real vector expected.\n"), fname, $input);
|
||||
return SWIG_ERROR;
|
||||
}
|
||||
/* Copy vector contents into new allocated std::vector<double> */
|
||||
arrayv = std::vector<double>(iRows*iCols);
|
||||
$1 = &arrayv;
|
||||
{
|
||||
int arr_i = 0;
|
||||
for (arr_i = 0; arr_i < iRows*iCols; ++arr_i)
|
||||
arrayv[arr_i] = pdblTmp[arr_i];
|
||||
}
|
||||
}
|
||||
}
|
||||
%typemap(freearg)
|
||||
const std::vector<double> &
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
// Typemap for return values of type std::vector<double>
|
||||
%typemap(out) std::vector<double>
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
|
@ -1,18 +1,15 @@
|
|||
// Based on Python implementation
|
||||
|
||||
%include <std/std_except.i>
|
||||
%include <scistdcommon.swg>
|
||||
|
||||
/*
|
||||
Generate the traits for a 'primitive' type, such as 'double',
|
||||
for which the SWIG_AsVal and SWIG_From methods are already defined.
|
||||
*/
|
||||
|
||||
// Generate the traits for a 'primitive' type, such as 'double',
|
||||
// for which the SWIG_AsVal and SWIG_From methods are already defined.
|
||||
|
||||
%define %traits_ptypen(Type...)
|
||||
%fragment(SWIG_Traits_frag(Type),"header",
|
||||
fragment=SWIG_AsVal_frag(Type),
|
||||
fragment=SWIG_From_frag(Type),
|
||||
fragment="StdTraits") {
|
||||
fragment=SWIG_AsVal_frag(Type),
|
||||
fragment=SWIG_From_frag(Type),
|
||||
fragment="StdTraits") {
|
||||
namespace swig {
|
||||
template <> struct traits<Type > {
|
||||
typedef value_category category;
|
||||
|
|
@ -34,8 +31,38 @@ namespace swig {
|
|||
}
|
||||
%enddef
|
||||
|
||||
/* Traits for enums. This is bit of a sneaky trick needed because a generic template specialization of enums
|
||||
is not possible (unless using template meta-programming which SWIG doesn't support because of the explicit
|
||||
instantiations required using %template). The STL containers define the 'front' method and the typemap
|
||||
below is used whenever the front method is wrapped returning an enum. This typemap simply picks up the
|
||||
standard enum typemap, but additionally drags in a fragment containing the traits_asval and traits_from
|
||||
required in the generated code for enums. */
|
||||
|
||||
%include <std/std_common.i>
|
||||
%define %traits_enum(Type...)
|
||||
%fragment("SWIG_Traits_enum_"{Type},"header",
|
||||
fragment=SWIG_AsVal_frag(int),
|
||||
fragment=SWIG_From_frag(int),
|
||||
fragment="StdTraits") {
|
||||
namespace swig {
|
||||
template <> struct traits_asval<Type > {
|
||||
typedef Type value_type;
|
||||
static int asval(SciObject obj, value_type *val) {
|
||||
return SWIG_AsVal(int)(obj, (int *)val);
|
||||
}
|
||||
};
|
||||
template <> struct traits_from<Type > {
|
||||
typedef Type value_type;
|
||||
static SciObject from(const value_type& val) {
|
||||
return SWIG_From(int)((int)val);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
%typemap(out, fragment="SWIG_Traits_enum_"{Type}) const enum SWIGTYPE& front %{$typemap(out, const enum SWIGTYPE&)%}
|
||||
%enddef
|
||||
|
||||
|
||||
%include <std/std_common.i>
|
||||
|
||||
//
|
||||
// Generates the traits for all the known primitive
|
||||
|
|
|
|||
|
|
@ -1,10 +1,88 @@
|
|||
// Vectors
|
||||
|
||||
%fragment("StdVectorTraits","header")
|
||||
/*
|
||||
Vectors
|
||||
*/
|
||||
%fragment("StdVectorTraits","header",fragment="StdSequenceTraits")
|
||||
%{
|
||||
namespace swig {
|
||||
template <class T>
|
||||
struct traits_asptr<std::vector<T> > {
|
||||
static int asptr(SciObject *obj, std::vector<T> **vec) {
|
||||
return traits_asptr_stdseq<std::vector<T> >::asptr(obj, vec);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct traits_from<std::vector<T> > {
|
||||
static SciObject *from(const std::vector<T>& vec) {
|
||||
return traits_from_stdseq<std::vector<T> >::from(vec);
|
||||
}
|
||||
};
|
||||
}
|
||||
%}
|
||||
|
||||
#define %swig_vector_methods(Type...) %swig_sequence_methods(Type)
|
||||
#define %swig_vector_methods_val(Type...) %swig_sequence_methods_val(Type);
|
||||
|
||||
// Typemap for input arguments of type const std::vector<double> &
|
||||
%typecheck(SWIG_TYPECHECK_POINTER)
|
||||
const std::vector<double> &
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
%typemap(in)
|
||||
const std::vector<double> &
|
||||
(int is_new_object=0, std::vector<double> arrayv)
|
||||
{
|
||||
{
|
||||
SciErr sciErr;
|
||||
int iRows = 0;
|
||||
int iCols = 0;
|
||||
int *piAddrVar = NULL;
|
||||
double *pdblTmp = NULL;
|
||||
|
||||
/* Scilab value must be a double vector */
|
||||
sciErr = getVarAddressFromPosition(pvApiCtx, $input, &piAddrVar);
|
||||
if (sciErr.iErr) {
|
||||
printError(&sciErr, 0);
|
||||
return SWIG_ERROR;
|
||||
}
|
||||
|
||||
if (isDoubleType(pvApiCtx, piAddrVar) && !isVarComplex(pvApiCtx, piAddrVar)) {
|
||||
sciErr = getMatrixOfDouble(pvApiCtx, piAddrVar, &iRows, &iCols, &pdblTmp);
|
||||
if (sciErr.iErr) {
|
||||
printError(&sciErr, 0);
|
||||
return SWIG_ERROR;
|
||||
}
|
||||
} else {
|
||||
Scierror(999, _("%s: Wrong type for input argument #%d: A real vector expected.\n"), fname, $input);
|
||||
return SWIG_ERROR;
|
||||
}
|
||||
|
||||
if ((iRows!=1) && (iCols!=1)) {
|
||||
Scierror(999, _("%s: Wrong size for input argument #%d: A real vector expected.\n"), fname, $input);
|
||||
return SWIG_ERROR;
|
||||
}
|
||||
/* Copy vector contents into new allocated std::vector<double> */
|
||||
arrayv = std::vector<double>(iRows*iCols);
|
||||
$1 = &arrayv;
|
||||
{
|
||||
int arr_i = 0;
|
||||
for (arr_i = 0; arr_i < iRows*iCols; ++arr_i)
|
||||
arrayv[arr_i] = pdblTmp[arr_i];
|
||||
}
|
||||
}
|
||||
}
|
||||
%typemap(freearg)
|
||||
const std::vector<double> &
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
// Typemap for return values of type std::vector<double>
|
||||
%typemap(out) std::vector<double>
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
%include <std/std_vector.i>
|
||||
|
||||
|
|
|
|||
|
|
@ -207,3 +207,4 @@ do this :
|
|||
%typemap(in) signed char *INOUT = signed char *OUTPUT;
|
||||
%typemap(in) float *INOUT = float *OUTPUT;
|
||||
%typemap(in) double *INOUT = double *OUTPUT;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue