1# -*- coding: utf-8 -*- 2# 3# Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu> 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Python compatibility wrappers.""" 18 19 20from __future__ import absolute_import 21 22import sys 23from struct import pack 24 25try: 26 MAX_INT = sys.maxsize 27except AttributeError: 28 MAX_INT = sys.maxint 29 30MAX_INT64 = (1 << 63) - 1 31MAX_INT32 = (1 << 31) - 1 32MAX_INT16 = (1 << 15) - 1 33 34# Determine the word size of the processor. 35if MAX_INT == MAX_INT64: 36 # 64-bit processor. 37 MACHINE_WORD_SIZE = 64 38elif MAX_INT == MAX_INT32: 39 # 32-bit processor. 40 MACHINE_WORD_SIZE = 32 41else: 42 # Else we just assume 64-bit processor keeping up with modern times. 43 MACHINE_WORD_SIZE = 64 44 45 46try: 47 # < Python3 48 unicode_type = unicode 49 have_python3 = False 50except NameError: 51 # Python3. 52 unicode_type = str 53 have_python3 = True 54 55# Fake byte literals. 56if str is unicode_type: 57 def byte_literal(s): 58 return s.encode('latin1') 59else: 60 def byte_literal(s): 61 return s 62 63# ``long`` is no more. Do type detection using this instead. 64try: 65 integer_types = (int, long) 66except NameError: 67 integer_types = (int,) 68 69b = byte_literal 70 71try: 72 # Python 2.6 or higher. 73 bytes_type = bytes 74except NameError: 75 # Python 2.5 76 bytes_type = str 77 78 79# To avoid calling b() multiple times in tight loops. 80ZERO_BYTE = b('\x00') 81EMPTY_BYTE = b('') 82 83 84def is_bytes(obj): 85 """ 86 Determines whether the given value is a byte string. 87 88 :param obj: 89 The value to test. 90 :returns: 91 ``True`` if ``value`` is a byte string; ``False`` otherwise. 92 """ 93 return isinstance(obj, bytes_type) 94 95 96def is_integer(obj): 97 """ 98 Determines whether the given value is an integer. 99 100 :param obj: 101 The value to test. 102 :returns: 103 ``True`` if ``value`` is an integer; ``False`` otherwise. 104 """ 105 return isinstance(obj, integer_types) 106 107 108def byte(num): 109 """ 110 Converts a number between 0 and 255 (both inclusive) to a base-256 (byte) 111 representation. 112 113 Use it as a replacement for ``chr`` where you are expecting a byte 114 because this will work on all current versions of Python:: 115 116 :param num: 117 An unsigned integer between 0 and 255 (both inclusive). 118 :returns: 119 A single byte. 120 """ 121 return pack("B", num) 122 123 124def get_word_alignment(num, force_arch=64, 125 _machine_word_size=MACHINE_WORD_SIZE): 126 """ 127 Returns alignment details for the given number based on the platform 128 Python is running on. 129 130 :param num: 131 Unsigned integral number. 132 :param force_arch: 133 If you don't want to use 64-bit unsigned chunks, set this to 134 anything other than 64. 32-bit chunks will be preferred then. 135 Default 64 will be used when on a 64-bit machine. 136 :param _machine_word_size: 137 (Internal) The machine word size used for alignment. 138 :returns: 139 4-tuple:: 140 141 (word_bits, word_bytes, 142 max_uint, packing_format_type) 143 """ 144 max_uint64 = 0xffffffffffffffff 145 max_uint32 = 0xffffffff 146 max_uint16 = 0xffff 147 max_uint8 = 0xff 148 149 if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32: 150 # 64-bit unsigned integer. 151 return 64, 8, max_uint64, "Q" 152 elif num > max_uint16: 153 # 32-bit unsigned integer 154 return 32, 4, max_uint32, "L" 155 elif num > max_uint8: 156 # 16-bit unsigned integer. 157 return 16, 2, max_uint16, "H" 158 else: 159 # 8-bit unsigned integer. 160 return 8, 1, max_uint8, "B" 161