





#
# Sort large text files in a minimum amount of memory
#
import argparse
import os

class 	__snake_case					:






    '''simple docstring'''
    _lowerCAmelCase  =						"""block_{0}.dat"""





    def __init__( self    :		Union[str, Any]      ,    snake_case    :		Dict				):

      """simple docstring"""





      __lowerCAmelCase								=					filename
      __lowerCAmelCase								=					[]





    def 						A		( self    :		List[Any]      ,    snake_case    :		List[str]      ,    snake_case    :		Any				):

      """simple docstring"""





      __lowerCAmelCase								=					self.BLOCK_FILENAME_FORMAT.format(snake_case				)
      with open(snake_case      ,    '''w'''				) as file:
        file.write(snake_case				)
      self.block_filenames.append(snake_case				)





    def 						A		( self    :		int				):

      """simple docstring"""





      return self.block_filenames





    def 						A		( self    :		str      ,    snake_case    :		Any      ,    snake_case    :		Tuple=None				):

      """simple docstring"""





      __lowerCAmelCase								=					0
      with open(self.filename				) as file:
        while True:
          __lowerCAmelCase								=					file.readlines(snake_case				)

          if lines == []:
            break

          if sort_key is None:
            lines.sort()
          else:
            lines.sort(key=snake_case				)

          self.write_block(''''''.join(snake_case				)      ,    snake_case				)
          i += 1





    def 						A		( self    :		Any				):

      """simple docstring"""





      map(os.remove      ,    self.block_filenames				)


class 	__snake_case					:






    '''simple docstring'''





    def 						A		( self    :		Union[str, Any]      ,    snake_case    :		Tuple				):

      """simple docstring"""





      __lowerCAmelCase								=					-1
      __lowerCAmelCase								=					None

      for i in range(len(snake_case				)				):
        if min_str is None or choices[i] < min_str:
          __lowerCAmelCase								=					i

      return min_index


class 	__snake_case					:






    '''simple docstring'''





    def __init__( self    :		Dict      ,    snake_case    :		Any				):

      """simple docstring"""





      __lowerCAmelCase								=					files
      __lowerCAmelCase								=					set()
      __lowerCAmelCase								=					len(snake_case				)
      __lowerCAmelCase								=					{i: None for i in range(self.num_buffers				)}





    def 						A		( self    :		Tuple				):

      """simple docstring"""





      return {
          i: self.buffers[i] for i in range(self.num_buffers				) if i not in self.empty
      }





    def 						A		( self    :		List[Any]				):

      """simple docstring"""





      for i in range(self.num_buffers				):
        if self.buffers[i] is None and i not in self.empty:
          __lowerCAmelCase								=					self.files[i].readline()

          if self.buffers[i] == "":
            self.empty.add(snake_case				)
            self.files[i].close()

      if len(self.empty				) == self.num_buffers:
        return False

      return True





    def 						A		( self    :		Any      ,    snake_case    :		str				):

      """simple docstring"""





      __lowerCAmelCase								=					self.buffers[index]
      __lowerCAmelCase								=					None

      return value


class 	__snake_case					:






    '''simple docstring'''





    def __init__( self    :		int      ,    snake_case    :		Optional[Any]				):

      """simple docstring"""





      __lowerCAmelCase								=					merge_strategy





    def 						A		( self    :		Optional[Any]      ,    snake_case    :		Union[str, Any]      ,    snake_case    :		List[Any]      ,    snake_case    :		Dict				):

      """simple docstring"""





      __lowerCAmelCase								=					FilesArray(self.get_file_handles(snake_case      ,    snake_case				)				)
      with open(snake_case      ,    '''w'''      ,    snake_case				) as outfile:
        while buffers.refresh():
          __lowerCAmelCase								=					self.merge_strategy.select(buffers.get_dict()				)
          outfile.write(buffers.unshift(snake_case				)				)





    def 						A		( self    :		List[str]      ,    snake_case    :		str      ,    snake_case    :		Tuple				):

      """simple docstring"""





      __lowerCAmelCase								=					{}

      for i in range(len(snake_case				)				):
        __lowerCAmelCase								=					open(filenames[i]      ,    '''r'''      ,    snake_case				)  # noqa: UP015

      return files


class 	__snake_case					:






    '''simple docstring'''





    def __init__( self    :		Optional[int]      ,    snake_case    :		Dict				):

      """simple docstring"""





      __lowerCAmelCase								=					block_size





    def 						A		( self    :		Dict      ,    snake_case    :		Any      ,    snake_case    :		List[str]=None				):

      """simple docstring"""





      __lowerCAmelCase								=					self.get_number_blocks(snake_case      ,    self.block_size				)
      __lowerCAmelCase								=					FileSplitter(snake_case				)
      splitter.split(self.block_size      ,    snake_case				)

      __lowerCAmelCase								=					FileMerger(NWayMerge()				)
      __lowerCAmelCase								=					self.block_size / (num_blocks + 1)
      merger.merge(splitter.get_block_filenames()      ,    filename + '''.out'''      ,    snake_case				)

      splitter.cleanup()





    def 						A		( self    :		Dict      ,    snake_case    :		Optional[int]      ,    snake_case    :		Optional[Any]				):

      """simple docstring"""





      return (os.stat(snake_case				).st_size / block_size) + 1


def        __SCREAMING_SNAKE_CASE	(				__lowercase:		Tuple):



  '''simple docstring'''






  if string[-1].lower() == "k":
    return int(string[:-1]) * 10_24
  elif string[-1].lower() == "m":
    return int(string[:-1]) * 10_24 * 10_24
  elif string[-1].lower() == "g":
    return int(string[:-1]) * 10_24 * 10_24 * 10_24
  else:
    return int(__lowercase)


def        __SCREAMING_SNAKE_CASE	(				):



  '''simple docstring'''






  __lowerCAmelCase								=					argparse.ArgumentParser()
  parser.add_argument(
      '''-m'''  ,				'''--mem'''  ,				help='''amount of memory to use for sorting'''  ,				default='''100M''')
  parser.add_argument(
      '''filename'''  ,				metavar='''<filename>'''  ,				nargs=1  ,				help='''name of file to sort''')
  __lowerCAmelCase								=					parser.parse_args()

  __lowerCAmelCase								=					ExternalSort(parse_memory(args.mem))
  sorter.sort(args.filename[0])


if __name__ == "__main__":
      main()







def        __SCREAMING_SNAKE_CASE	(				__lowercase:		int):



  '''simple docstring'''






  if not isinstance(__lowercase  ,				__lowercase):
    __lowerCAmelCase								=					F'''Input value of [number={number}] must be an integer'''
    raise TypeError(__lowercase)
  if number < 0 or number % 2 == 1:
    return False
  __lowerCAmelCase								=					int(number**0.5)
  return number == number_sqrt * (number_sqrt + 1)


if __name__ == "__main__":
      import doctest

      doctest.testmod()
