{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%load_ext cython"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Regular class vs extensions class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "warning: /home/nikratio/.cache/ipython/cython/_cython_magic_f3365cad4f189403d0322b37c637671e.pyx:8:5: freelists cannot be used on subtypes, only the base class can manage them\n"
     ]
    }
   ],
   "source": [
    "%%cython\n",
    "cimport cython\n",
    "\n",
    "cdef class FUSEErrorExt(Exception):\n",
    "    '''\n",
    "    This exception may be raised by request handlers to indicate that\n",
    "    the requested operation could not be carried out. The system call\n",
    "    that resulted in the request (if any) will then fail with error\n",
    "    code *errno_*.\n",
    "    '''\n",
    "\n",
    "    # If we call this variable \"errno\", we will get syntax errors\n",
    "    # during C compilation (maybe something else declares errno as\n",
    "    # a macro?)\n",
    "    cdef int errno_\n",
    "\n",
    "    property errno:\n",
    "        '''Error code to return to client process'''\n",
    "        def __get__(self):\n",
    "            return self.errno_\n",
    "        def __set__(self, val):\n",
    "            self.errno_ = val\n",
    "\n",
    "    def __init__(self, errno):\n",
    "        self.errno_ = errno"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class FUSEErrorInt(Exception):\n",
    "    def __init__(self, errno):\n",
    "        self.errno = errno"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def test_ext():\n",
    "    a = 0\n",
    "    for i in range(100):\n",
    "        try:\n",
    "            raise FUSEErrorExt(i)\n",
    "        except FUSEErrorExt as exc:\n",
    "            a += exc.errno\n",
    "        except:\n",
    "            print(\"This should not happen\")\n",
    "    return a\n",
    "\n",
    "\n",
    "def test_int():\n",
    "    a = 0\n",
    "    for i in range(100):\n",
    "        try:\n",
    "            raise FUSEErrorInt(i)\n",
    "        except FUSEErrorInt as exc:\n",
    "            a += exc.errno\n",
    "        except:\n",
    "            print(\"This should not happen\")\n",
    "    return a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The slowest run took 8.54 times longer than the fastest. This could mean that an intermediate result is being cached.\n",
      "10000 loops, best of 3: 36 µs per loop\n",
      "10000 loops, best of 3: 57.9 µs per loop\n"
     ]
    }
   ],
   "source": [
    "assert test_ext() == test_int()\n",
    "%timeit test_ext()\n",
    "%timeit test_int()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Instantiation vs Factory Function with Cache"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(Unfortunately we cannot use @cython.freelist for derived classes)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cache = dict()\n",
    "\n",
    "\n",
    "def getError(errno):\n",
    "    try:\n",
    "        return cache[errno]\n",
    "    except KeyError:\n",
    "        cache[errno] = FUSEErrorExt(errno)\n",
    "        return cache[errno]\n",
    "\n",
    "\n",
    "def test_ext_cached():\n",
    "    a = 0\n",
    "    for i in range(100):\n",
    "        try:\n",
    "            raise getError(i)\n",
    "        except FUSEErrorExt as exc:\n",
    "            a += exc.errno\n",
    "        except:\n",
    "            print(\"This should not happen\")\n",
    "    return a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10000 loops, best of 3: 32.7 µs per loop\n",
      "10000 loops, best of 3: 32.4 µs per loop\n"
     ]
    }
   ],
   "source": [
    "assert test_ext() == test_ext_cached()\n",
    "%timeit test_ext()\n",
    "%timeit test_ext_cached()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Catching Exception vs Ordinary Return"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def handler(i):\n",
    "    return getError(i)\n",
    "\n",
    "\n",
    "def test_ext_direct():\n",
    "    a = 0\n",
    "    for i in range(100):\n",
    "        res = handler(i)\n",
    "        if isinstance(res, FUSEErrorExt):\n",
    "            a += res.errno\n",
    "    return a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The slowest run took 5.52 times longer than the fastest. This could mean that an intermediate result is being cached.\n",
      "10000 loops, best of 3: 32.4 µs per loop\n",
      "10000 loops, best of 3: 28.4 µs per loop\n"
     ]
    }
   ],
   "source": [
    "assert test_ext_cached() == test_ext_direct()\n",
    "%timeit test_ext_cached()\n",
    "%timeit test_ext_direct()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
