From c83609277bed4be4ef40ed306bf2c57fefa19519 Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Thu, 9 Apr 2020 19:36:37 -0700
Subject: Use exceptions for filter errors

---
 al/filter.cpp | 259 +++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 168 insertions(+), 91 deletions(-)

(limited to 'al/filter.cpp')

diff --git a/al/filter.cpp b/al/filter.cpp
index 3746c1be..88aa3ce9 100644
--- a/al/filter.cpp
+++ b/al/filter.cpp
@@ -24,6 +24,7 @@
 
 #include <algorithm>
 #include <cstdint>
+#include <cstdio>
 #include <iterator>
 #include <memory>
 #include <mutex>
@@ -45,41 +46,81 @@
 
 namespace {
 
+class filter_exception final : public std::exception {
+    std::string mMessage;
+    ALenum mErrorCode;
+
+public:
+    filter_exception(ALenum code, const char *msg, ...) ALEXCPT_FORMAT(printf, 3,4);
+
+    const char *what() const noexcept override { return mMessage.c_str(); }
+    ALenum errorCode() const noexcept { return mErrorCode; }
+};
+
+filter_exception::filter_exception(ALenum code, const char *msg, ...) : mErrorCode{code}
+{
+    va_list args, args2;
+    va_start(args, msg);
+    va_copy(args2, args);
+    int msglen{std::vsnprintf(nullptr, 0, msg, args)};
+    if LIKELY(msglen > 0)
+    {
+        mMessage.resize(static_cast<size_t>(msglen)+1);
+        std::vsnprintf(&mMessage[0], mMessage.length(), msg, args2);
+        mMessage.pop_back();
+    }
+    va_end(args2);
+    va_end(args);
+}
+
+
 #define FILTER_MIN_GAIN 0.0f
 #define FILTER_MAX_GAIN 4.0f /* +12dB */
 
-void ALlowpass_setParami(ALfilter*, ALCcontext *context, ALenum param, int)
-{ context->setError(AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); }
-void ALlowpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); }
-void ALlowpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, float val)
+#define DEFINE_ALFILTER_VTABLE(T)                                  \
+const ALfilter::Vtable T##_vtable = {                              \
+    T##_setParami, T##_setParamiv, T##_setParamf, T##_setParamfv,  \
+    T##_getParami, T##_getParamiv, T##_getParamf, T##_getParamfv,  \
+}
+
+void ALlowpass_setParami(ALfilter*, ALenum param, int)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
+void ALlowpass_setParamiv(ALfilter*, ALenum param, const int*)
+{
+    throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x",
+        param};
+}
+void ALlowpass_setParamf(ALfilter *filter, ALenum param, float val)
 {
     switch(param)
     {
     case AL_LOWPASS_GAIN:
         if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
-            SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gain %f out of range", val);
+            throw filter_exception{AL_INVALID_VALUE, "Low-pass gain %f out of range", val};
         filter->Gain = val;
         break;
 
     case AL_LOWPASS_GAINHF:
         if(!(val >= AL_LOWPASS_MIN_GAINHF && val <= AL_LOWPASS_MAX_GAINHF))
-            SETERR_RETURN(context, AL_INVALID_VALUE,, "Low-pass gainhf %f out of range", val);
+            throw filter_exception{AL_INVALID_VALUE, "Low-pass gainhf %f out of range", val};
         filter->GainHF = val;
         break;
 
     default:
-        context->setError(AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
+        throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
     }
 }
-void ALlowpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const float *vals)
-{ ALlowpass_setParamf(filter, context, param, vals[0]); }
-
-void ALlowpass_getParami(const ALfilter*, ALCcontext *context, ALenum param, int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param); }
-void ALlowpass_getParamiv(const ALfilter*, ALCcontext *context, ALenum param, int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x", param); }
-void ALlowpass_getParamf(const ALfilter *filter, ALCcontext *context, ALenum param, float *val)
+void ALlowpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
+{ ALlowpass_setParamf(filter, param, vals[0]); }
+
+void ALlowpass_getParami(const ALfilter*, ALenum param, int*)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer property 0x%04x", param}; }
+void ALlowpass_getParamiv(const ALfilter*, ALenum param, int*)
+{
+    throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass integer-vector property 0x%04x",
+        param};
+}
+void ALlowpass_getParamf(const ALfilter *filter, ALenum param, float *val)
 {
     switch(param)
     {
@@ -92,47 +133,53 @@ void ALlowpass_getParamf(const ALfilter *filter, ALCcontext *context, ALenum par
         break;
 
     default:
-        context->setError(AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param);
+        throw filter_exception{AL_INVALID_ENUM, "Invalid low-pass float property 0x%04x", param};
     }
 }
-void ALlowpass_getParamfv(const ALfilter *filter, ALCcontext *context, ALenum param, float *vals)
-{ ALlowpass_getParamf(filter, context, param, vals); }
+void ALlowpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
+{ ALlowpass_getParamf(filter, param, vals); }
 
 DEFINE_ALFILTER_VTABLE(ALlowpass);
 
 
-void ALhighpass_setParami(ALfilter*, ALCcontext *context, ALenum param, int)
-{ context->setError(AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); }
-void ALhighpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); }
-void ALhighpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, float val)
+void ALhighpass_setParami(ALfilter*, ALenum param, int)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
+void ALhighpass_setParamiv(ALfilter*, ALenum param, const int*)
+{
+    throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x",
+        param};
+}
+void ALhighpass_setParamf(ALfilter *filter, ALenum param, float val)
 {
     switch(param)
     {
     case AL_HIGHPASS_GAIN:
         if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
-            SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gain out of range");
+            throw filter_exception{AL_INVALID_VALUE, "High-pass gain out of range"};
         filter->Gain = val;
         break;
 
     case AL_HIGHPASS_GAINLF:
         if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
-            SETERR_RETURN(context, AL_INVALID_VALUE,, "High-pass gainlf out of range");
+            throw filter_exception{AL_INVALID_VALUE, "High-pass gainlf out of range"};
         filter->GainLF = val;
         break;
 
     default:
-        context->setError(AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
+        throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
     }
 }
-void ALhighpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const float *vals)
-{ ALhighpass_setParamf(filter, context, param, vals[0]); }
-
-void ALhighpass_getParami(const ALfilter*, ALCcontext *context, ALenum param, int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param); }
-void ALhighpass_getParamiv(const ALfilter*, ALCcontext *context, ALenum param, int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x", param); }
-void ALhighpass_getParamf(const ALfilter *filter, ALCcontext *context, ALenum param, float *val)
+void ALhighpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
+{ ALhighpass_setParamf(filter, param, vals[0]); }
+
+void ALhighpass_getParami(const ALfilter*, ALenum param, int*)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer property 0x%04x", param}; }
+void ALhighpass_getParamiv(const ALfilter*, ALenum param, int*)
+{
+    throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass integer-vector property 0x%04x",
+        param};
+}
+void ALhighpass_getParamf(const ALfilter *filter, ALenum param, float *val)
 {
     switch(param)
     {
@@ -145,53 +192,59 @@ void ALhighpass_getParamf(const ALfilter *filter, ALCcontext *context, ALenum pa
         break;
 
     default:
-        context->setError(AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param);
+        throw filter_exception{AL_INVALID_ENUM, "Invalid high-pass float property 0x%04x", param};
     }
 }
-void ALhighpass_getParamfv(const ALfilter *filter, ALCcontext *context, ALenum param, float *vals)
-{ ALhighpass_getParamf(filter, context, param, vals); }
+void ALhighpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
+{ ALhighpass_getParamf(filter, param, vals); }
 
 DEFINE_ALFILTER_VTABLE(ALhighpass);
 
 
-void ALbandpass_setParami(ALfilter*, ALCcontext *context, ALenum param, int)
-{ context->setError(AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); }
-void ALbandpass_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); }
-void ALbandpass_setParamf(ALfilter *filter, ALCcontext *context, ALenum param, float val)
+void ALbandpass_setParami(ALfilter*, ALenum param, int)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
+void ALbandpass_setParamiv(ALfilter*, ALenum param, const int*)
+{
+    throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x",
+        param};
+}
+void ALbandpass_setParamf(ALfilter *filter, ALenum param, float val)
 {
     switch(param)
     {
     case AL_BANDPASS_GAIN:
         if(!(val >= FILTER_MIN_GAIN && val <= FILTER_MAX_GAIN))
-            SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gain out of range");
+            throw filter_exception{AL_INVALID_VALUE, "Band-pass gain out of range"};
         filter->Gain = val;
         break;
 
     case AL_BANDPASS_GAINHF:
         if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
-            SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainhf out of range");
+            throw filter_exception{AL_INVALID_VALUE, "Band-pass gainhf out of range"};
         filter->GainHF = val;
         break;
 
     case AL_BANDPASS_GAINLF:
         if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
-            SETERR_RETURN(context, AL_INVALID_VALUE,, "Band-pass gainlf out of range");
+            throw filter_exception{AL_INVALID_VALUE, "Band-pass gainlf out of range"};
         filter->GainLF = val;
         break;
 
     default:
-        context->setError(AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
+        throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
     }
 }
-void ALbandpass_setParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const float *vals)
-{ ALbandpass_setParamf(filter, context, param, vals[0]); }
-
-void ALbandpass_getParami(const ALfilter*, ALCcontext *context, ALenum param, int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param); }
-void ALbandpass_getParamiv(const ALfilter*, ALCcontext *context, ALenum param, int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x", param); }
-void ALbandpass_getParamf(const ALfilter *filter, ALCcontext *context, ALenum param, float *val)
+void ALbandpass_setParamfv(ALfilter *filter, ALenum param, const float *vals)
+{ ALbandpass_setParamf(filter, param, vals[0]); }
+
+void ALbandpass_getParami(const ALfilter*, ALenum param, int*)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer property 0x%04x", param}; }
+void ALbandpass_getParamiv(const ALfilter*, ALenum param, int*)
+{
+    throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass integer-vector property 0x%04x",
+        param};
+}
+void ALbandpass_getParamf(const ALfilter *filter, ALenum param, float *val)
 {
     switch(param)
     {
@@ -208,32 +261,32 @@ void ALbandpass_getParamf(const ALfilter *filter, ALCcontext *context, ALenum pa
         break;
 
     default:
-        context->setError(AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param);
+        throw filter_exception{AL_INVALID_ENUM, "Invalid band-pass float property 0x%04x", param};
     }
 }
-void ALbandpass_getParamfv(const ALfilter *filter, ALCcontext *context, ALenum param, float *vals)
-{ ALbandpass_getParamf(filter, context, param, vals); }
+void ALbandpass_getParamfv(const ALfilter *filter, ALenum param, float *vals)
+{ ALbandpass_getParamf(filter, param, vals); }
 
 DEFINE_ALFILTER_VTABLE(ALbandpass);
 
 
-void ALnullfilter_setParami(ALfilter*, ALCcontext *context, ALenum param, int)
-{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
-void ALnullfilter_setParamiv(ALfilter*, ALCcontext *context, ALenum param, const int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
-void ALnullfilter_setParamf(ALfilter*, ALCcontext *context, ALenum param, float)
-{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
-void ALnullfilter_setParamfv(ALfilter*, ALCcontext *context, ALenum param, const float*)
-{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
-
-void ALnullfilter_getParami(const ALfilter*, ALCcontext *context, ALenum param, int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
-void ALnullfilter_getParamiv(const ALfilter*, ALCcontext *context, ALenum param, int*)
-{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
-void ALnullfilter_getParamf(const ALfilter*, ALCcontext *context, ALenum param, float*)
-{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
-void ALnullfilter_getParamfv(const ALfilter*, ALCcontext *context, ALenum param, float*)
-{ context->setError(AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param); }
+void ALnullfilter_setParami(ALfilter*, ALenum param, int)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
+void ALnullfilter_setParamiv(ALfilter*, ALenum param, const int*)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
+void ALnullfilter_setParamf(ALfilter*, ALenum param, float)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
+void ALnullfilter_setParamfv(ALfilter*, ALenum param, const float*)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
+
+void ALnullfilter_getParami(const ALfilter*, ALenum param, int*)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
+void ALnullfilter_getParamiv(const ALfilter*, ALenum param, int*)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
+void ALnullfilter_getParamf(const ALfilter*, ALenum param, float*)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
+void ALnullfilter_getParamfv(const ALfilter*, ALenum param, float*)
+{ throw filter_exception{AL_INVALID_ENUM, "Invalid null filter property 0x%04x", param}; }
 
 DEFINE_ALFILTER_VTABLE(ALnullfilter);
 
@@ -466,10 +519,13 @@ START_API_FUNC
             else
                 context->setError(AL_INVALID_VALUE, "Invalid filter type 0x%04x", value);
         }
-        else
+        else try
         {
             /* Call the appropriate handler */
-            alfilt->setParami(context.get(), param, value);
+            alfilt->setParami(param, value);
+        }
+        catch(filter_exception &e) {
+            context->setError(e.errorCode(), "%s", e.what());
         }
     }
 }
@@ -494,10 +550,13 @@ START_API_FUNC
     ALfilter *alfilt{LookupFilter(device, filter)};
     if UNLIKELY(!alfilt)
         context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
-    else
+    else try
     {
         /* Call the appropriate handler */
-        alfilt->setParamiv(context.get(), param, values);
+        alfilt->setParamiv(param, values);
+    }
+    catch(filter_exception &e) {
+        context->setError(e.errorCode(), "%s", e.what());
     }
 }
 END_API_FUNC
@@ -514,10 +573,13 @@ START_API_FUNC
     ALfilter *alfilt{LookupFilter(device, filter)};
     if UNLIKELY(!alfilt)
         context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
-    else
+    else try
     {
         /* Call the appropriate handler */
-        alfilt->setParamf(context.get(), param, value);
+        alfilt->setParamf(param, value);
+    }
+    catch(filter_exception &e) {
+        context->setError(e.errorCode(), "%s", e.what());
     }
 }
 END_API_FUNC
@@ -534,10 +596,13 @@ START_API_FUNC
     ALfilter *alfilt{LookupFilter(device, filter)};
     if UNLIKELY(!alfilt)
         context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
-    else
+    else try
     {
         /* Call the appropriate handler */
-        alfilt->setParamfv(context.get(), param, values);
+        alfilt->setParamfv(param, values);
+    }
+    catch(filter_exception &e) {
+        context->setError(e.errorCode(), "%s", e.what());
     }
 }
 END_API_FUNC
@@ -558,10 +623,13 @@ START_API_FUNC
     {
         if(param == AL_FILTER_TYPE)
             *value = alfilt->type;
-        else
+        else try
         {
             /* Call the appropriate handler */
-            alfilt->getParami(context.get(), param, value);
+            alfilt->getParami(param, value);
+        }
+        catch(filter_exception &e) {
+            context->setError(e.errorCode(), "%s", e.what());
         }
     }
 }
@@ -586,10 +654,13 @@ START_API_FUNC
     const ALfilter *alfilt{LookupFilter(device, filter)};
     if UNLIKELY(!alfilt)
         context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
-    else
+    else try
     {
         /* Call the appropriate handler */
-        alfilt->getParamiv(context.get(), param, values);
+        alfilt->getParamiv(param, values);
+    }
+    catch(filter_exception &e) {
+        context->setError(e.errorCode(), "%s", e.what());
     }
 }
 END_API_FUNC
@@ -606,10 +677,13 @@ START_API_FUNC
     const ALfilter *alfilt{LookupFilter(device, filter)};
     if UNLIKELY(!alfilt)
         context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
-    else
+    else try
     {
         /* Call the appropriate handler */
-        alfilt->getParamf(context.get(), param, value);
+        alfilt->getParamf(param, value);
+    }
+    catch(filter_exception &e) {
+        context->setError(e.errorCode(), "%s", e.what());
     }
 }
 END_API_FUNC
@@ -626,10 +700,13 @@ START_API_FUNC
     const ALfilter *alfilt{LookupFilter(device, filter)};
     if UNLIKELY(!alfilt)
         context->setError(AL_INVALID_NAME, "Invalid filter ID %u", filter);
-    else
+    else try
     {
         /* Call the appropriate handler */
-        alfilt->getParamfv(context.get(), param, values);
+        alfilt->getParamfv(param, values);
+    }
+    catch(filter_exception &e) {
+        context->setError(e.errorCode(), "%s", e.what());
     }
 }
 END_API_FUNC
-- 
cgit v1.2.3