@@ -17,7 +17,7 @@ from tslib cimport _to_i8
1717
1818from hashtable cimport HashTable
1919
20- from pandas._libs import algos, hashtable as _hash
20+ from pandas._libs import algos, period as periodlib, hashtable as _hash
2121from pandas._libs.tslib import Timestamp, Timedelta
2222from datetime import datetime, timedelta
2323
@@ -270,13 +270,16 @@ cdef class IndexEngine:
270270
271271 values = self ._get_index_values()
272272 self .mapping = self ._make_hash_table(len (values))
273- self .mapping.map_locations (values)
273+ self ._call_map_locations (values)
274274
275275 if len (self .mapping) == len (values):
276276 self .unique = 1
277277
278278 self .need_unique_check = 0
279279
280+ cpdef _call_map_locations(self , values):
281+ self .mapping.map_locations(values)
282+
280283 def clear_mapping (self ):
281284 self .mapping = None
282285 self .need_monotonic_check = 1
@@ -491,6 +494,76 @@ cdef class TimedeltaEngine(DatetimeEngine):
491494 cdef _get_box_dtype(self ):
492495 return ' m8[ns]'
493496
497+
498+ cdef class PeriodEngine(Int64Engine):
499+
500+ cdef _get_index_values(self ):
501+ return self .vgetter()
502+
503+ cpdef _call_map_locations(self , values):
504+ super (PeriodEngine, self )._call_map_locations(values.view(' i8' ))
505+
506+ def _call_monotonic (self , values ):
507+ return super (PeriodEngine, self )._call_monotonic(values.view(' i8' ))
508+
509+ cdef _maybe_get_bool_indexer(self , object val):
510+ cdef:
511+ ndarray[uint8_t, cast= True ] indexer
512+ ndarray[int64_t] values
513+ int count = 0
514+ Py_ssize_t i, n
515+ int last_true
516+
517+ if not util.is_integer_object(val):
518+ raise KeyError (val)
519+
520+ values = self ._get_index_values().view(' i8' )
521+ n = len (values)
522+
523+ result = np.empty(n, dtype = bool )
524+ indexer = result.view(np.uint8)
525+
526+ for i in range (n):
527+ if values[i] == val:
528+ count += 1
529+ indexer[i] = 1
530+ last_true = i
531+ else :
532+ indexer[i] = 0
533+
534+ if count == 0 :
535+ raise KeyError (val)
536+ if count == 1 :
537+ return last_true
538+
539+ return result
540+
541+ def get_indexer (self , values ):
542+ cdef ndarray[int64_t, ndim= 1 ] ordinals
543+
544+ self ._ensure_mapping_populated()
545+ ordinals = periodlib.extract_ordinals(values, self .vgetter().freq)
546+ return self .mapping.lookup(ordinals)
547+
548+ def get_pad_indexer (self , other , limit = None ):
549+ ordinal = periodlib.extract_ordinals(other, self .vgetter().freq)
550+
551+ return algos.pad_int64(self ._get_index_values(),
552+ np.asarray(ordinal), limit = limit)
553+
554+ def get_backfill_indexer (self , other , limit = None ):
555+ ordinal = periodlib.extract_ordinals(other, self .vgetter().freq)
556+
557+ return algos.backfill_int64(self ._get_index_values(),
558+ np.asarray(ordinal), limit = limit)
559+
560+ def get_indexer_non_unique (self , targets ):
561+ ordinal = periodlib.extract_ordinals(targets, self .vgetter().freq)
562+ ordinal_array = np.asarray(ordinal)
563+
564+ return super (PeriodEngine, self ).get_indexer_non_unique(ordinal_array)
565+
566+
494567cpdef convert_scalar(ndarray arr, object value):
495568 # we don't turn integers
496569 # into datetimes/timedeltas
0 commit comments