"""Run-time calculation of offset into Python string structure

Does a scan to find the digits of pi in a string structure
in order to produce an offset that can be used to produce 
data-pointers from Python strings.

Porting note:
	
	Currently this uses id( str a ) to get the base address
	of the Python string.  Python implementations where id( a )
	is *not* the memory address of the string will not work!
"""
import ctypes
PI_DIGITS = '31415926535897931'

def calculateOffset( ):
	"""Calculates the data-pointer offset for strings
	
	This does a sequential scan for 100 bytes from the id
	of a string to find special data-value stored in the
	string (the digits of PI).  It produces a dataPointer
	function which adds that offset to the id of the 
	passed strings.
	"""
	finalOffset = None
	a = PI_DIGITS
	# XXX NOT portable across Python implmentations!!!
	initial = id(a)
	targetType = ctypes.POINTER( ctypes.c_char )
	for offset in range( 100 ):
		vector = ctypes.cast( initial+offset,targetType )
		allMatched = True
		for index,digit in enumerate( a ):
			if vector[index] != digit:
				allMatched = False
				break
		if allMatched:
			finalOffset = offset
			break
	if finalOffset is not None:
		def dataPointer( data ):
			"""Return the data-pointer from the array using calculated offset
			
			data -- a Python string
			
			Returns the raw data-pointer to the internal buffer of the passed string
			"""
			if not isinstance( data, str ):
				raise TypeError(
					"""This function can only handle Python strings!  Got %s"""%(
						type(data),
					)
				)
			return id(data) + finalOffset
		# just for later reference...
		dataPointer.offset = finalOffset 
		return dataPointer
	raise RuntimeError(
		"""Unable to determine dataPointer offset for strings!"""
	)

dataPointer = calculateOffset()

if __name__ == "__main__":
	a  = 'this'
	print id(a), dataPointer( a ), dataPointer(a) - id(a)
	
