• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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#      https://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
19from __future__ import absolute_import
20
21import itertools
22import sys
23from struct import pack
24
25MAX_INT = sys.maxsize
26MAX_INT64 = (1 << 63) - 1
27MAX_INT32 = (1 << 31) - 1
28MAX_INT16 = (1 << 15) - 1
29
30PY2 = sys.version_info[0] == 2
31
32# Determine the word size of the processor.
33if MAX_INT == MAX_INT64:
34    # 64-bit processor.
35    MACHINE_WORD_SIZE = 64
36elif MAX_INT == MAX_INT32:
37    # 32-bit processor.
38    MACHINE_WORD_SIZE = 32
39else:
40    # Else we just assume 64-bit processor keeping up with modern times.
41    MACHINE_WORD_SIZE = 64
42
43if PY2:
44    integer_types = (int, long)
45    range = xrange
46    zip = itertools.izip
47else:
48    integer_types = (int, )
49    range = range
50    zip = zip
51
52
53def write_to_stdout(data):
54    """Writes bytes to stdout
55
56    :type data: bytes
57    """
58    if PY2:
59        sys.stdout.write(data)
60    else:
61        # On Py3 we must use the buffer interface to write bytes.
62        sys.stdout.buffer.write(data)
63
64
65def is_bytes(obj):
66    """
67    Determines whether the given value is a byte string.
68
69    :param obj:
70        The value to test.
71    :returns:
72        ``True`` if ``value`` is a byte string; ``False`` otherwise.
73    """
74    return isinstance(obj, bytes)
75
76
77def is_integer(obj):
78    """
79    Determines whether the given value is an integer.
80
81    :param obj:
82        The value to test.
83    :returns:
84        ``True`` if ``value`` is an integer; ``False`` otherwise.
85    """
86    return isinstance(obj, integer_types)
87
88
89def byte(num):
90    """
91    Converts a number between 0 and 255 (both inclusive) to a base-256 (byte)
92    representation.
93
94    Use it as a replacement for ``chr`` where you are expecting a byte
95    because this will work on all current versions of Python::
96
97    :param num:
98        An unsigned integer between 0 and 255 (both inclusive).
99    :returns:
100        A single byte.
101    """
102    return pack("B", num)
103
104
105def xor_bytes(b1, b2):
106    """
107    Returns the bitwise XOR result between two bytes objects, b1 ^ b2.
108
109    Bitwise XOR operation is commutative, so order of parameters doesn't
110    generate different results. If parameters have different length, extra
111    length of the largest one is ignored.
112
113    :param b1:
114        First bytes object.
115    :param b2:
116        Second bytes object.
117    :returns:
118        Bytes object, result of XOR operation.
119    """
120    if PY2:
121        return ''.join(byte(ord(x) ^ ord(y)) for x, y in zip(b1, b2))
122
123    return bytes(x ^ y for x, y in zip(b1, b2))
124
125
126def get_word_alignment(num, force_arch=64,
127                       _machine_word_size=MACHINE_WORD_SIZE):
128    """
129    Returns alignment details for the given number based on the platform
130    Python is running on.
131
132    :param num:
133        Unsigned integral number.
134    :param force_arch:
135        If you don't want to use 64-bit unsigned chunks, set this to
136        anything other than 64. 32-bit chunks will be preferred then.
137        Default 64 will be used when on a 64-bit machine.
138    :param _machine_word_size:
139        (Internal) The machine word size used for alignment.
140    :returns:
141        4-tuple::
142
143            (word_bits, word_bytes,
144             max_uint, packing_format_type)
145    """
146    max_uint64 = 0xffffffffffffffff
147    max_uint32 = 0xffffffff
148    max_uint16 = 0xffff
149    max_uint8 = 0xff
150
151    if force_arch == 64 and _machine_word_size >= 64 and num > max_uint32:
152        # 64-bit unsigned integer.
153        return 64, 8, max_uint64, "Q"
154    elif num > max_uint16:
155        # 32-bit unsigned integer
156        return 32, 4, max_uint32, "L"
157    elif num > max_uint8:
158        # 16-bit unsigned integer.
159        return 16, 2, max_uint16, "H"
160    else:
161        # 8-bit unsigned integer.
162        return 8, 1, max_uint8, "B"
163