Skip to content

Commit

Permalink
Allow SGIO to throw custom exception types (#4331)
Browse files Browse the repository at this point in the history
Allow SGIO to throw custom exception types
  • Loading branch information
vinx13 authored and vigsterkr committed Jun 8, 2018
1 parent 7039d3a commit f211b65
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 73 deletions.
1 change: 1 addition & 0 deletions src/interfaces/swig/SGBase.i
Expand Up @@ -295,6 +295,7 @@ public void readExternal(java.io.ObjectInput in) throws java.io.IOException, jav
SWIG_fail;
#endif
}
SWIG_CATCH_STDEXCEPT
}

%ignore NUM_LOG_LEVELS;
Expand Down
124 changes: 61 additions & 63 deletions src/shogun/io/SGIO.cpp
Expand Up @@ -65,71 +65,74 @@ SGIO::SGIO(const SGIO& orig)
m_refcount = new RefCount();
}

void SGIO::message(EMessageType prio, const char* function, const char* file,
int32_t line, const char *fmt, ... ) const
std::string SGIO::format(
EMessageType prio, const char* function, const char* file, int32_t line,
const char* fmt, ...) const
{
const char* msg_intro=get_msg_intro(prio);

if (msg_intro)
{
char str[4096];
snprintf(str, sizeof(str), "%s", msg_intro);
int len=strlen(msg_intro);
char* s=str+len;
char str[4096];
snprintf(str, sizeof(str), "%s", msg_intro);
int len = strlen(msg_intro);
char* s = str + len;

/* file and line are shown for warnings and worse */
if (location_info==MSG_LINE_AND_FILE || prio==MSG_WARN || prio==MSG_ERROR)
{
snprintf(s, sizeof(str)-len, "In file %s line %d: ", file, line);
len=strlen(str);
s=str+len;
}
else if (location_info==MSG_FUNCTION)
{
snprintf(s, sizeof(str)-len, "%s: ", function);
len=strlen(str);
s=str+len;
}
else if (location_info==MSG_NONE)
{
;
}
/* file and line are shown for warnings and worse */
if (location_info == MSG_LINE_AND_FILE || prio == MSG_WARN ||
prio == MSG_ERROR)
{
snprintf(s, sizeof(str) - len, "In file %s line %d: ", file, line);
len = strlen(str);
s = str + len;
}
else if (location_info == MSG_FUNCTION)
{
snprintf(s, sizeof(str) - len, "%s: ", function);
len = strlen(str);
s = str + len;
}
else if (location_info == MSG_NONE)
{
;
}

va_list list;
va_start(list,fmt);
vsnprintf(s, sizeof(str)-len, fmt, list);
va_end(list);
va_list list;
va_start(list, fmt);
vsnprintf(s, sizeof(str) - len, fmt, list);
va_end(list);

switch (prio)
{
case MSG_GCDEBUG:
case MSG_DEBUG:
case MSG_INFO:
case MSG_NOTICE:
case MSG_MESSAGEONLY:
if (sg_print_message)
sg_print_message(target, str);
break;

case MSG_WARN:
if (sg_print_warning)
sg_print_warning(target, str);
break;

case MSG_ERROR:
case MSG_CRITICAL:
case MSG_ALERT:
case MSG_EMERGENCY:
if (sg_print_error)
sg_print_error(target, str);
throw ShogunException(str);
break;
default:
break;
}
return std::string(str);
}

fflush(target);
void SGIO::print(EMessageType prio, const std::string& msg) const
{
switch (prio)
{
case MSG_GCDEBUG:
case MSG_DEBUG:
case MSG_INFO:
case MSG_NOTICE:
case MSG_MESSAGEONLY:
if (sg_print_message)
sg_print_message(target, msg.c_str());
break;

case MSG_WARN:
if (sg_print_warning)
sg_print_warning(target, msg.c_str());
break;

case MSG_ERROR:
case MSG_CRITICAL:
case MSG_ALERT:
case MSG_EMERGENCY:
if (sg_print_error)
sg_print_error(target, msg.c_str());
break;
default:
break;
}

fflush(target);
}

void SGIO::buffered_message(EMessageType prio, const char *fmt, ... ) const
Expand Down Expand Up @@ -202,11 +205,6 @@ const char* SGIO::get_msg_intro(EMessageType prio) const
{
for (int32_t i=NUM_LOG_LEVELS-1; i>=0; i--)
{
// ignore msg if prio's level is under loglevel,
// but not if prio's level higher than MSG_WARN
if (levels[i]<loglevel && prio<=MSG_WARN)
return NULL;

if (levels[i]==prio)
{
if (syntax_highlight)
Expand All @@ -216,7 +214,7 @@ const char* SGIO::get_msg_intro(EMessageType prio) const
}
}

return NULL;
return nullptr; // unreachable
}

char* SGIO::c_string_of_substring(substring s)
Expand Down
88 changes: 78 additions & 10 deletions src/shogun/io/SGIO.h
Expand Up @@ -10,8 +10,9 @@
#ifndef __SGIO_H__
#define __SGIO_H__

#include <shogun/lib/config.h>
#include <shogun/lib/ShogunException.h>
#include <shogun/lib/common.h>
#include <shogun/lib/config.h>

#include <dirent.h>
#include <string.h>
Expand Down Expand Up @@ -122,9 +123,22 @@ enum EMessageLocation
}

#define SG_WARNING(...) { io->message(MSG_WARN, __PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); }
#define SG_ERROR(...) { io->message(MSG_ERROR, __PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); }
#define SG_OBJ_ERROR(o, ...) { o->io->message(MSG_ERROR, __PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); }
#define SG_CLASS_ERROR(c, ...) { c::io->message(MSG_ERROR, __PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); }
#define SG_THROW(ExceptionType, ...) \
{ \
io->template error<ExceptionType>( \
MSG_ERROR, __PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); \
}
#define SG_ERROR(...) SG_THROW(ShogunException, __VA_ARGS__)
#define SG_OBJ_ERROR(o, ...) \
{ \
o->io->template error<ShogunException>( \
MSG_ERROR, __PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); \
}
#define SG_CLASS_ERROR(c, ...) \
{ \
c::io->template error<ShogunException>( \
MSG_ERROR, __PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); \
}
#define SG_UNSTABLE(func, ...) { io->message(MSG_WARN, __PRETTY_FUNCTION__, __FILE__, __LINE__, \
__FILE__ ":" func ": Unstable method! Please report if it seems to " \
"work or not to the Shogun mailing list. Thanking you in " \
Expand Down Expand Up @@ -157,7 +171,12 @@ __FILE__ ":" func ": Unstable method! Please report if it seems to " \
}

#define SG_SWARNING(...) { sg_io->message(MSG_WARN,__PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); }
#define SG_SERROR(...) { sg_io->message(MSG_ERROR,__PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); }
#define SG_STHROW(Exception, ...) \
{ \
sg_io->template error<Exception>( \
MSG_ERROR, __PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); \
}
#define SG_SERROR(...) SG_STHROW(ShogunException, __VA_ARGS__)
#define SG_SPRINT(...) { sg_io->message(MSG_MESSAGEONLY,__PRETTY_FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); }

#define SG_SDONE() { \
Expand All @@ -178,6 +197,12 @@ __FILE__ ":" func ": Unstable method! Please report if it seems to " \
SG_SERROR(__VA_ARGS__) \
}

#define REQUIRE_E(x, Exception, ...) \
{ \
if (SG_UNLIKELY(!(x))) \
SG_STHROW(Exception, __VA_ARGS__) \
}

/* help clang static analyzer to identify custom assertation functions */
#ifdef __clang_analyzer__
void _clang_fail(void) __attribute__((analyzer_noreturn));
Expand Down Expand Up @@ -268,7 +293,7 @@ class SGIO
return syntax_highlight;
}

/** print a message
/** format a message
*
* optionally prefixed with file name and line number
* from (use -1 in line to disable this)
Expand All @@ -279,8 +304,31 @@ class SGIO
* @param line line number from where the message is called
* @param fmt format string
*/
void message(EMessageType prio, const char* function, const char* file,
int32_t line, const char *fmt, ... ) const;
std::string format(
EMessageType prio, const char* function, const char* file,
int32_t line, const char* fmt, ...) const;

/** format and print a message
* @param prio message priority
* @param args arguments for formatting message
*/
template <typename... Args>
void message(EMessageType prio, Args&&... args) const;

/** format and print a message, and then throw an exception
* @tparam ExceptionType type of the exception to throw
* @param prio message priority
* @param args arguments for formatting message
*/
template <typename Exception, typename... Args>
void error(EMessageType prio, Args&&... args) const;

/** print a message with the print function decided by priority
*
* @param prio message priority
* @param msg message
*/
void print(EMessageType prio, const std::string& msg) const;

/** print 'done' with priority INFO,
* but only if progress bar is enabled
Expand All @@ -291,13 +339,18 @@ class SGIO
/** print error message 'not implemented' */
inline void not_implemented(const char* function, const char* file, int32_t line) const
{
message(MSG_ERROR, function, file, line, "Sorry, not yet implemented .\n");
error<ShogunException>(
MSG_ERROR, function, file, line,
"Sorry, not yet implemented .\n");
}

/** print error message 'Only available with GPL parts.' */
inline void gpl_only(const char* function, const char* file, int32_t line) const
{
message(MSG_ERROR, function, file, line, "This feature is only available if Shogun is built with GPL codes.\n");
error<ShogunException>(
MSG_ERROR, function, file, line, "This feature is only "
"available if Shogun is built "
"with GPL codes.\n");
}

/** print warning message 'function deprecated' */
Expand Down Expand Up @@ -536,5 +589,20 @@ class SGIO
private:
RefCount* m_refcount;
};

template <typename... Args>
void SGIO::message(EMessageType prio, Args&&... args) const
{
const auto& msg = format(prio, std::forward<Args>(args)...);
print(prio, msg);
}

template <typename ExceptionType, typename... Args>
void SGIO::error(EMessageType prio, Args&&... args) const
{
const auto& msg = format(prio, std::forward<Args>(args)...);
print(prio, msg);
throw ExceptionType(msg);
}
}
#endif // __SGIO_H__
15 changes: 15 additions & 0 deletions tests/unit/io/SGIO_unittest.cc
@@ -0,0 +1,15 @@
#include <gtest/gtest.h>
#include <shogun/io/SGIO.h>
#include <stdexcept>

using namespace shogun;

TEST(SGIO, exception)
{
EXPECT_THROW(SG_SERROR("Error"), ShogunException);
EXPECT_THROW(
SG_STHROW(std::invalid_argument, "Error"), std::invalid_argument);
EXPECT_THROW(REQUIRE(0, "Error"), ShogunException);
EXPECT_THROW(
REQUIRE_E(0, std::invalid_argument, "Error"), std::invalid_argument);
}

0 comments on commit f211b65

Please sign in to comment.