#cython: language_level = 3
from cython.parallel import parallel
from libc.stdio cimport printf
"""
    GOAL: implement nogil option in cdef class (extension types)
    and native memory manager (refcount based) that does not
    depend on cpython's memory manager and that does not require GIL.
    
    HINT: look at C++ standard library (that works very nicely with Cython)

    Cython documentation if here: http://docs.cython.org/en/latest/
    
    Basic usage: http://docs.cython.org/en/latest/src/quickstart/build.html
    
    Tutorial: http://docs.cython.org/en/latest/src/tutorial/cython_tutorial.html
    
    Language: http://docs.cython.org/en/latest/src/userguide/language_basics.html
    
    Extension types: http://docs.cython.org/en/latest/src/userguide/extension_types.html
        
        Extension Types are the "pure cython" classes that I want to be able to
        use without depending on cpython GIL (and in essence runtime, memory manager, etc.)
        
    Cython memory allocation: http://docs.cython.org/en/latest/src/tutorial/memory_allocation.html
    
    Parallelism: http://docs.cython.org/en/latest/src/userguide/parallelism.html
    
        Explains how nogil is posisble in cython for anything that
        only relies on C libraries that are multi-threaded
"""



# cdef class SomeMemory:
cdef class SomeMemory nogil:
  """
  This is a cdef class which is also called
  a extensino type. It is a kind of C struct
  that also acts as a python object.
  
  We would like to be able to define "nogil"
  extension types:
  
  cdef class SomeMemory nogil:
  
  where all methods are "nogil" and memory
  allocation does not depend on python runtime
  """
  cdef double a;
  cdef double b;
    
  cdef void foo(self) nogil:
    """
    It is possible to define native C/Cython methods
    that release the GIL (cool...)
    """
    while 1:
      self.a += 1
    
  # Not allowed to define pure Python function in the extension type with nogil option now
  # since we want this extension type is CPython free
  # def baz(self):
  #  """
  #  It is also possible to define standard python
  #  methods
  #  """
  #  pass
    
    
# cdef bar(): # it is currently impossible to release GIL
cdef double bar() nogil: # yet this is what we would like to
    """
    This is a pure "cython method" which we would like to
    be able to declare with nogil option but this requires
    to first introduce the concept of nogil in cdef class
    """
    # cdef SomeMemory o = SomeMemory(42.0, 3.14) # for this we need class allocation to handle memory without libpython
    cdef SomeMemory o1 = SomeMemory(1, 1.0)
    cdef SomeMemory o2 = SomeMemory(2, 2.0)
    with nogil, parallel():
      o1.foo()
      o2.foo()
    # o.foo() # and we need method selection to be independent of libpython
    # o.foo1(2)
    # o.a = 2.732
    # o.fact(100)
    
    return o1.a
    
cpdef baz():
    """
    This method is both callable from python and pure "cython".
    It can call both cdef methods and usual python functions
    """
    return bar()
    
def bag():
    return str(baz())
    
# We call here a cpdef function, which calls a def function
# which then allocates cdef class SomeMemory
print(bag())
print("done")
