Commit 801dec8c authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #504 from kmod/pr492

delete capi/float.cpp
parents 0defcec2 8aa08824
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#define SIZEOF_INT 4 #define SIZEOF_INT 4
#define SIZEOF_LONG 8 #define SIZEOF_LONG 8
#define SIZEOF_LONG_LONG 8 #define SIZEOF_LONG_LONG 8
#define SIZEOF_DOUBLE 8
#define SIZEOF_FLOAT 4
#define SIZEOF_OFF_T 8 #define SIZEOF_OFF_T 8
#define SIZEOF_PTHREAD_T 8 #define SIZEOF_PTHREAD_T 8
#define HAVE_COPYSIGN 1 #define HAVE_COPYSIGN 1
......
...@@ -55,7 +55,9 @@ typedef struct BLOCK { ...@@ -55,7 +55,9 @@ typedef struct BLOCK {
struct BLOCK *leftlink; struct BLOCK *leftlink;
} block; } block;
#define MAXFREEBLOCKS 10 // Pyston change: disable free block cache
// #define MAXFREEBLOCKS 10
#define MAXFREEBLOCKS 0
static Py_ssize_t numfreeblocks = 0; static Py_ssize_t numfreeblocks = 0;
static block *freeblocks[MAXFREEBLOCKS]; static block *freeblocks[MAXFREEBLOCKS];
......
...@@ -30,7 +30,6 @@ add_library(PYSTON_OBJECTS OBJECT ${OPTIONAL_SRCS} ...@@ -30,7 +30,6 @@ add_library(PYSTON_OBJECTS OBJECT ${OPTIONAL_SRCS}
capi/codecs.cpp capi/codecs.cpp
capi/descrobject.cpp capi/descrobject.cpp
capi/errors.cpp capi/errors.cpp
capi/float.cpp
capi/modsupport.cpp capi/modsupport.cpp
capi/object.cpp capi/object.cpp
capi/typeobject.cpp capi/typeobject.cpp
......
...@@ -557,8 +557,29 @@ extern "C" int PyObject_CheckReadBuffer(PyObject* obj) noexcept { ...@@ -557,8 +557,29 @@ extern "C" int PyObject_CheckReadBuffer(PyObject* obj) noexcept {
} }
extern "C" int PyObject_AsReadBuffer(PyObject* obj, const void** buffer, Py_ssize_t* buffer_len) noexcept { extern "C" int PyObject_AsReadBuffer(PyObject* obj, const void** buffer, Py_ssize_t* buffer_len) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented"); PyBufferProcs* pb;
void* pp;
Py_ssize_t len;
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
null_error();
return -1;
}
pb = obj->cls->tp_as_buffer;
if (pb == NULL || pb->bf_getreadbuffer == NULL || pb->bf_getsegcount == NULL) {
PyErr_SetString(PyExc_TypeError, "expected a readable buffer object");
return -1;
}
if ((*pb->bf_getsegcount)(obj, NULL) != 1) {
PyErr_SetString(PyExc_TypeError, "expected a single-segment buffer object");
return -1;
}
len = (*pb->bf_getreadbuffer)(obj, 0, &pp);
if (len < 0)
return -1; return -1;
*buffer = pp;
*buffer_len = len;
return 0;
} }
static PyObject* call_function_tail(PyObject* callable, PyObject* args) { static PyObject* call_function_tail(PyObject* callable, PyObject* args) {
...@@ -1818,6 +1839,21 @@ extern "C" PyObject* PyNumber_Long(PyObject* o) noexcept { ...@@ -1818,6 +1839,21 @@ extern "C" PyObject* PyNumber_Long(PyObject* o) noexcept {
} }
extern "C" PyObject* PyNumber_Float(PyObject* o) noexcept { extern "C" PyObject* PyNumber_Float(PyObject* o) noexcept {
if (o == NULL)
return null_error();
if (o->cls == float_cls)
return o;
if (PyInt_Check(o))
return boxFloat(((BoxedInt*)o)->n);
else if (PyLong_Check(o)) {
double result = PyLong_AsDouble(o);
if (result == -1.0 && PyErr_Occurred())
return NULL;
return boxFloat(result);
}
fatalOrError(PyExc_NotImplementedError, "unimplemented"); fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr; return nullptr;
} }
......
// Copyright (c) 2014-2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file is mostly copied from CPython
#include "Python.h"
#include "core/types.h"
#include "runtime/types.h"
namespace pyston {
extern "C" {
typedef enum { unknown_format, ieee_big_endian_format, ieee_little_endian_format } float_format_type;
static float_format_type double_format, float_format;
static float_format_type detected_double_format, detected_float_format;
static PyObject* float_getformat(PyTypeObject* v, PyObject* arg) noexcept {
float_format_type r;
BoxedString* str = static_cast<BoxedString*>(arg);
if (!PyString_Check(arg)) {
PyErr_Format(PyExc_TypeError, "__getformat__() argument must be string, not %.500s", Py_TYPE(arg)->tp_name);
return NULL;
}
if (str->s == "double") {
r = double_format;
} else if (str->s == "float") {
r = float_format;
} else {
PyErr_SetString(PyExc_ValueError, "__getformat__() argument 1 must be "
"'double' or 'float'");
return NULL;
}
switch (r) {
case unknown_format:
return static_cast<PyObject*>(boxStrConstant("unknown"));
case ieee_little_endian_format:
return static_cast<PyObject*>(boxStrConstant("IEEE, little-endian"));
case ieee_big_endian_format:
return static_cast<PyObject*>(boxStrConstant("IEEE, big-endian"));
default:
Py_FatalError("insane float_format or double_format");
return NULL;
}
}
PyDoc_STRVAR(float_getformat_doc, "float.__getformat__(typestr) -> string\n"
"\n"
"You probably don't want to use this function. It exists mainly to be\n"
"used in Python's test suite.\n"
"\n"
"typestr must be 'double' or 'float'. This function returns whichever of\n"
"'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n"
"format of floating point numbers used by the C type named by typestr.");
static PyObject* float_setformat(PyTypeObject* v, PyObject* args) noexcept {
char* typestr;
char* format;
float_format_type f;
float_format_type detected;
float_format_type* p;
if (!PyArg_ParseTuple(args, "ss:__setformat__", &typestr, &format))
return NULL;
if (strcmp(typestr, "double") == 0) {
p = &double_format;
detected = detected_double_format;
} else if (strcmp(typestr, "float") == 0) {
p = &float_format;
detected = detected_float_format;
} else {
PyErr_SetString(PyExc_ValueError, "__setformat__() argument 1 must "
"be 'double' or 'float'");
return NULL;
}
if (strcmp(format, "unknown") == 0) {
f = unknown_format;
} else if (strcmp(format, "IEEE, little-endian") == 0) {
f = ieee_little_endian_format;
} else if (strcmp(format, "IEEE, big-endian") == 0) {
f = ieee_big_endian_format;
} else {
PyErr_SetString(PyExc_ValueError, "__setformat__() argument 2 must be "
"'unknown', 'IEEE, little-endian' or "
"'IEEE, big-endian'");
return NULL;
}
if (f != unknown_format && f != detected) {
PyErr_Format(PyExc_ValueError, "can only set %s format to 'unknown' or the "
"detected platform value",
typestr);
return NULL;
}
*p = f;
Py_RETURN_NONE;
}
/*----------------------------------------------------------------------------
* _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h.
*/
extern "C" int _PyFloat_Pack4(double x, unsigned char* p, int le) noexcept {
if (float_format == unknown_format) {
unsigned char sign;
int e;
double f;
unsigned int fbits;
int incr = 1;
if (le) {
p += 3;
incr = -1;
}
if (x < 0) {
sign = 1;
x = -x;
} else
sign = 0;
f = frexp(x, &e);
/* Normalize f to be in the range [1.0, 2.0) */
if (0.5 <= f && f < 1.0) {
f *= 2.0;
e--;
} else if (f == 0.0)
e = 0;
else {
PyErr_SetString(PyExc_SystemError, "frexp() result out of range");
return -1;
}
if (e >= 128)
goto Overflow;
else if (e < -126) {
/* Gradual underflow */
f = ldexp(f, 126 + e);
e = 0;
} else if (!(e == 0 && f == 0.0)) {
e += 127;
f -= 1.0; /* Get rid of leading 1 */
}
f *= 8388608.0; /* 2**23 */
fbits = (unsigned int)(f + 0.5); /* Round */
assert(fbits <= 8388608);
if (fbits >> 23) {
/* The carry propagated out of a string of 23 1 bits. */
fbits = 0;
++e;
if (e >= 255)
goto Overflow;
}
/* First byte */
*p = (sign << 7) | (e >> 1);
p += incr;
/* Second byte */
*p = (char)(((e & 1) << 7) | (fbits >> 16));
p += incr;
/* Third byte */
*p = (fbits >> 8) & 0xFF;
p += incr;
/* Fourth byte */
*p = fbits & 0xFF;
/* Done */
return 0;
} else {
float y = (float)x;
const char* s = (char*)&y;
int i, incr = 1;
if (Py_IS_INFINITY(y) && !Py_IS_INFINITY(x))
goto Overflow;
if ((float_format == ieee_little_endian_format && !le) || (float_format == ieee_big_endian_format && le)) {
p += 3;
incr = -1;
}
for (i = 0; i < 4; i++) {
*p = *s++;
p += incr;
}
return 0;
}
Overflow:
PyErr_SetString(PyExc_OverflowError, "float too large to pack with f format");
return -1;
}
extern "C" int _PyFloat_Pack8(double x, unsigned char* p, int le) noexcept {
if (double_format == unknown_format) {
unsigned char sign;
int e;
double f;
unsigned int fhi, flo;
int incr = 1;
if (le) {
p += 7;
incr = -1;
}
if (x < 0) {
sign = 1;
x = -x;
} else
sign = 0;
f = frexp(x, &e);
/* Normalize f to be in the range [1.0, 2.0) */
if (0.5 <= f && f < 1.0) {
f *= 2.0;
e--;
} else if (f == 0.0)
e = 0;
else {
PyErr_SetString(PyExc_SystemError, "frexp() result out of range");
return -1;
}
if (e >= 1024)
goto Overflow;
else if (e < -1022) {
/* Gradual underflow */
f = ldexp(f, 1022 + e);
e = 0;
} else if (!(e == 0 && f == 0.0)) {
e += 1023;
f -= 1.0; /* Get rid of leading 1 */
}
/* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */
f *= 268435456.0; /* 2**28 */
fhi = (unsigned int)f; /* Truncate */
assert(fhi < 268435456);
f -= (double)fhi;
f *= 16777216.0; /* 2**24 */
flo = (unsigned int)(f + 0.5); /* Round */
assert(flo <= 16777216);
if (flo >> 24) {
/* The carry propagated out of a string of 24 1 bits. */
flo = 0;
++fhi;
if (fhi >> 28) {
/* And it also progagated out of the next 28 bits. */
fhi = 0;
++e;
if (e >= 2047)
goto Overflow;
}
}
/* First byte */
*p = (sign << 7) | (e >> 4);
p += incr;
/* Second byte */
*p = (unsigned char)(((e & 0xF) << 4) | (fhi >> 24));
p += incr;
/* Third byte */
*p = (fhi >> 16) & 0xFF;
p += incr;
/* Fourth byte */
*p = (fhi >> 8) & 0xFF;
p += incr;
/* Fifth byte */
*p = fhi & 0xFF;
p += incr;
/* Sixth byte */
*p = (flo >> 16) & 0xFF;
p += incr;
/* Seventh byte */
*p = (flo >> 8) & 0xFF;
p += incr;
/* Eighth byte */
*p = flo & 0xFF;
/* p += incr; Unneeded (for now) */
/* Done */
return 0;
Overflow:
PyErr_SetString(PyExc_OverflowError, "float too large to pack with d format");
return -1;
} else {
const char* s = (char*)&x;
int i, incr = 1;
if ((double_format == ieee_little_endian_format && !le) || (double_format == ieee_big_endian_format && le)) {
p += 7;
incr = -1;
}
for (i = 0; i < 8; i++) {
*p = *s++;
p += incr;
}
return 0;
}
}
double _PyFloat_Unpack4(const unsigned char* p, int le) noexcept {
if (float_format == unknown_format) {
unsigned char sign;
int e;
unsigned int f;
double x;
int incr = 1;
if (le) {
p += 3;
incr = -1;
}
/* First byte */
sign = (*p >> 7) & 1;
e = (*p & 0x7F) << 1;
p += incr;
/* Second byte */
e |= (*p >> 7) & 1;
f = (*p & 0x7F) << 16;
p += incr;
if (e == 255) {
PyErr_SetString(PyExc_ValueError, "can't unpack IEEE 754 special value "
"on non-IEEE platform");
return -1;
}
/* Third byte */
f |= *p << 8;
p += incr;
/* Fourth byte */
f |= *p;
x = (double)f / 8388608.0;
/* XXX This sadly ignores Inf/NaN issues */
if (e == 0)
e = -126;
else {
x += 1.0;
e -= 127;
}
x = ldexp(x, e);
if (sign)
x = -x;
return x;
} else {
float x;
if ((float_format == ieee_little_endian_format && !le) || (float_format == ieee_big_endian_format && le)) {
char buf[4];
char* d = &buf[3];
int i;
for (i = 0; i < 4; i++) {
*d-- = *p++;
}
memcpy(&x, buf, 4);
} else {
memcpy(&x, p, 4);
}
return x;
}
}
double _PyFloat_Unpack8(const unsigned char* p, int le) noexcept {
if (double_format == unknown_format) {
unsigned char sign;
int e;
unsigned int fhi, flo;
double x;
int incr = 1;
if (le) {
p += 7;
incr = -1;
}
/* First byte */
sign = (*p >> 7) & 1;
e = (*p & 0x7F) << 4;
p += incr;
/* Second byte */
e |= (*p >> 4) & 0xF;
fhi = (*p & 0xF) << 24;
p += incr;
if (e == 2047) {
PyErr_SetString(PyExc_ValueError, "can't unpack IEEE 754 special value "
"on non-IEEE platform");
return -1.0;
}
/* Third byte */
fhi |= *p << 16;
p += incr;
/* Fourth byte */
fhi |= *p << 8;
p += incr;
/* Fifth byte */
fhi |= *p;
p += incr;
/* Sixth byte */
flo = *p << 16;
p += incr;
/* Seventh byte */
flo |= *p << 8;
p += incr;
/* Eighth byte */
flo |= *p;
x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */
x /= 268435456.0; /* 2**28 */
if (e == 0)
e = -1022;
else {
x += 1.0;
e -= 1023;
}
x = ldexp(x, e);
if (sign)
x = -x;
return x;
} else {
double x;
if ((double_format == ieee_little_endian_format && !le) || (double_format == ieee_big_endian_format && le)) {
char buf[8];
char* d = &buf[7];
int i;
for (i = 0; i < 8; i++) {
*d-- = *p++;
}
memcpy(&x, buf, 8);
} else {
memcpy(&x, p, 8);
}
return x;
}
}
}
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include <algorithm> #include <algorithm>
#include <cfloat>
#include <cstddef> #include <cstddef>
#include <err.h> #include <err.h>
...@@ -375,6 +376,14 @@ Box* issubclass_func(Box* child, Box* parent) { ...@@ -375,6 +376,14 @@ Box* issubclass_func(Box* child, Box* parent) {
return boxBool(rtn); return boxBool(rtn);
} }
Box* intern_func(Box* str) {
if (!PyString_CheckExact(str)) // have to use exact check!
raiseExcHelper(TypeError, "can't intern subclass of string");
PyString_InternInPlace(&str);
checkAndThrowCAPIException();
return str;
}
Box* bltinImport(Box* name, Box* globals, Box* locals, Box** args) { Box* bltinImport(Box* name, Box* globals, Box* locals, Box** args) {
Box* fromlist = args[0]; Box* fromlist = args[0];
Box* level = args[1]; Box* level = args[1];
...@@ -590,7 +599,6 @@ public: ...@@ -590,7 +599,6 @@ public:
static Box* __reduce__(Box* self) { static Box* __reduce__(Box* self) {
RELEASE_ASSERT(isSubclass(self->cls, BaseException), ""); RELEASE_ASSERT(isSubclass(self->cls, BaseException), "");
BoxedException* exc = static_cast<BoxedException*>(self); BoxedException* exc = static_cast<BoxedException*>(self);
return BoxedTuple::create({ self->cls, EmptyTuple, self->getAttrWrapper() }); return BoxedTuple::create({ self->cls, EmptyTuple, self->getAttrWrapper() });
} }
}; };
...@@ -967,16 +975,38 @@ Box* builtinRound(Box* _number, Box* _ndigits) { ...@@ -967,16 +975,38 @@ Box* builtinRound(Box* _number, Box* _ndigits) {
raiseExcHelper(TypeError, "a float is required"); raiseExcHelper(TypeError, "a float is required");
BoxedFloat* number = (BoxedFloat*)_number; BoxedFloat* number = (BoxedFloat*)_number;
double x = number->d;
if (isSubclass(_ndigits->cls, int_cls)) { /* interpret 2nd argument as a Py_ssize_t; clip on overflow */
BoxedInt* ndigits = (BoxedInt*)_ndigits; Py_ssize_t ndigits = PyNumber_AsSsize_t(_ndigits, NULL);
if (ndigits == -1 && PyErr_Occurred())
if (ndigits->n == 0) throwCAPIException();
return boxFloat(round(number->d));
}
fatalOrError(PyExc_NotImplementedError, "unimplemented"); /* nans, infinities and zeros round to themselves */
if (!std::isfinite(x) || x == 0.0)
return boxFloat(x);
/* Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x
always rounds to itself. For ndigits < NDIGITS_MIN, x always
rounds to +-0.0. Here 0.30103 is an upper bound for log10(2). */
#define NDIGITS_MAX ((int)((DBL_MANT_DIG - DBL_MIN_EXP) * 0.30103))
#define NDIGITS_MIN (-(int)((DBL_MAX_EXP + 1) * 0.30103))
if (ndigits > NDIGITS_MAX)
/* return x */
return boxFloat(x);
else if (ndigits < NDIGITS_MIN)
/* return 0.0, but with sign of x */
return boxFloat(0.0 * x);
else {
/* finite x, and ndigits is not unreasonably large */
/* _Py_double_round is defined in floatobject.c */
Box* rtn = _Py_double_round(x, (int)ndigits);
if (!rtn)
throwCAPIException(); throwCAPIException();
return rtn;
}
#undef NDIGITS_MAX
#undef NDIGITS_MIN
} }
Box* builtinCmp(Box* a, Box* b) { Box* builtinCmp(Box* a, Box* b) {
...@@ -1103,6 +1133,9 @@ void setupBuiltins() { ...@@ -1103,6 +1133,9 @@ void setupBuiltins() {
= new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)issubclass_func, BOXED_BOOL, 2), "issubclass"); = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)issubclass_func, BOXED_BOOL, 2), "issubclass");
builtins_module->giveAttr("issubclass", issubclass_obj); builtins_module->giveAttr("issubclass", issubclass_obj);
Box* intern_obj = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)intern_func, UNKNOWN, 1), "intern");
builtins_module->giveAttr("intern", intern_obj);
CLFunction* import_func = boxRTFunction((void*)bltinImport, UNKNOWN, 5, 4, false, false, CLFunction* import_func = boxRTFunction((void*)bltinImport, UNKNOWN, 5, 4, false, false,
ParamNames({ "name", "globals", "locals", "fromlist", "level" }, "", "")); ParamNames({ "name", "globals", "locals", "fromlist", "level" }, "", ""));
builtins_module->giveAttr("__import__", new BoxedBuiltinFunctionOrMethod(import_func, "__import__", builtins_module->giveAttr("__import__", new BoxedBuiltinFunctionOrMethod(import_func, "__import__",
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <cfloat>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
...@@ -833,6 +834,568 @@ const char* floatGetFormatDoc = "float.__getformat__(typestr) -> string\n" ...@@ -833,6 +834,568 @@ const char* floatGetFormatDoc = "float.__getformat__(typestr) -> string\n"
"'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n" "'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n"
"format of floating point numbers used by the C type named by typestr."; "format of floating point numbers used by the C type named by typestr.";
static PyObject* float_setformat(PyTypeObject* v, PyObject* args) noexcept {
char* typestr;
char* format;
float_format_type f;
float_format_type detected;
float_format_type* p;
if (!PyArg_ParseTuple(args, "ss:__setformat__", &typestr, &format))
return NULL;
if (strcmp(typestr, "double") == 0) {
p = &double_format;
detected = detected_double_format;
} else if (strcmp(typestr, "float") == 0) {
p = &float_format;
detected = detected_float_format;
} else {
PyErr_SetString(PyExc_ValueError, "__setformat__() argument 1 must "
"be 'double' or 'float'");
return NULL;
}
if (strcmp(format, "unknown") == 0) {
f = unknown_format;
} else if (strcmp(format, "IEEE, little-endian") == 0) {
f = ieee_little_endian_format;
} else if (strcmp(format, "IEEE, big-endian") == 0) {
f = ieee_big_endian_format;
} else {
PyErr_SetString(PyExc_ValueError, "__setformat__() argument 2 must be "
"'unknown', 'IEEE, little-endian' or "
"'IEEE, big-endian'");
return NULL;
}
if (f != unknown_format && f != detected) {
PyErr_Format(PyExc_ValueError, "can only set %s format to 'unknown' or the "
"detected platform value",
typestr);
return NULL;
}
*p = f;
Py_RETURN_NONE;
}
/*----------------------------------------------------------------------------
* _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h.
*/
extern "C" int _PyFloat_Pack4(double x, unsigned char* p, int le) noexcept {
if (float_format == unknown_format) {
unsigned char sign;
int e;
double f;
unsigned int fbits;
int incr = 1;
if (le) {
p += 3;
incr = -1;
}
if (x < 0) {
sign = 1;
x = -x;
} else
sign = 0;
f = frexp(x, &e);
/* Normalize f to be in the range [1.0, 2.0) */
if (0.5 <= f && f < 1.0) {
f *= 2.0;
e--;
} else if (f == 0.0)
e = 0;
else {
PyErr_SetString(PyExc_SystemError, "frexp() result out of range");
return -1;
}
if (e >= 128)
goto Overflow;
else if (e < -126) {
/* Gradual underflow */
f = ldexp(f, 126 + e);
e = 0;
} else if (!(e == 0 && f == 0.0)) {
e += 127;
f -= 1.0; /* Get rid of leading 1 */
}
f *= 8388608.0; /* 2**23 */
fbits = (unsigned int)(f + 0.5); /* Round */
assert(fbits <= 8388608);
if (fbits >> 23) {
/* The carry propagated out of a string of 23 1 bits. */
fbits = 0;
++e;
if (e >= 255)
goto Overflow;
}
/* First byte */
*p = (sign << 7) | (e >> 1);
p += incr;
/* Second byte */
*p = (char)(((e & 1) << 7) | (fbits >> 16));
p += incr;
/* Third byte */
*p = (fbits >> 8) & 0xFF;
p += incr;
/* Fourth byte */
*p = fbits & 0xFF;
/* Done */
return 0;
} else {
float y = (float)x;
const char* s = (char*)&y;
int i, incr = 1;
if (Py_IS_INFINITY(y) && !Py_IS_INFINITY(x))
goto Overflow;
if ((float_format == ieee_little_endian_format && !le) || (float_format == ieee_big_endian_format && le)) {
p += 3;
incr = -1;
}
for (i = 0; i < 4; i++) {
*p = *s++;
p += incr;
}
return 0;
}
Overflow:
PyErr_SetString(PyExc_OverflowError, "float too large to pack with f format");
return -1;
}
extern "C" int _PyFloat_Pack8(double x, unsigned char* p, int le) noexcept {
if (double_format == unknown_format) {
unsigned char sign;
int e;
double f;
unsigned int fhi, flo;
int incr = 1;
if (le) {
p += 7;
incr = -1;
}
if (x < 0) {
sign = 1;
x = -x;
} else
sign = 0;
f = frexp(x, &e);
/* Normalize f to be in the range [1.0, 2.0) */
if (0.5 <= f && f < 1.0) {
f *= 2.0;
e--;
} else if (f == 0.0)
e = 0;
else {
PyErr_SetString(PyExc_SystemError, "frexp() result out of range");
return -1;
}
if (e >= 1024)
goto Overflow;
else if (e < -1022) {
/* Gradual underflow */
f = ldexp(f, 1022 + e);
e = 0;
} else if (!(e == 0 && f == 0.0)) {
e += 1023;
f -= 1.0; /* Get rid of leading 1 */
}
/* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */
f *= 268435456.0; /* 2**28 */
fhi = (unsigned int)f; /* Truncate */
assert(fhi < 268435456);
f -= (double)fhi;
f *= 16777216.0; /* 2**24 */
flo = (unsigned int)(f + 0.5); /* Round */
assert(flo <= 16777216);
if (flo >> 24) {
/* The carry propagated out of a string of 24 1 bits. */
flo = 0;
++fhi;
if (fhi >> 28) {
/* And it also progagated out of the next 28 bits. */
fhi = 0;
++e;
if (e >= 2047)
goto Overflow;
}
}
/* First byte */
*p = (sign << 7) | (e >> 4);
p += incr;
/* Second byte */
*p = (unsigned char)(((e & 0xF) << 4) | (fhi >> 24));
p += incr;
/* Third byte */
*p = (fhi >> 16) & 0xFF;
p += incr;
/* Fourth byte */
*p = (fhi >> 8) & 0xFF;
p += incr;
/* Fifth byte */
*p = fhi & 0xFF;
p += incr;
/* Sixth byte */
*p = (flo >> 16) & 0xFF;
p += incr;
/* Seventh byte */
*p = (flo >> 8) & 0xFF;
p += incr;
/* Eighth byte */
*p = flo & 0xFF;
/* p += incr; Unneeded (for now) */
/* Done */
return 0;
Overflow:
PyErr_SetString(PyExc_OverflowError, "float too large to pack with d format");
return -1;
} else {
const char* s = (char*)&x;
int i, incr = 1;
if ((double_format == ieee_little_endian_format && !le) || (double_format == ieee_big_endian_format && le)) {
p += 7;
incr = -1;
}
for (i = 0; i < 8; i++) {
*p = *s++;
p += incr;
}
return 0;
}
}
extern "C" double _PyFloat_Unpack4(const unsigned char* p, int le) noexcept {
if (float_format == unknown_format) {
unsigned char sign;
int e;
unsigned int f;
double x;
int incr = 1;
if (le) {
p += 3;
incr = -1;
}
/* First byte */
sign = (*p >> 7) & 1;
e = (*p & 0x7F) << 1;
p += incr;
/* Second byte */
e |= (*p >> 7) & 1;
f = (*p & 0x7F) << 16;
p += incr;
if (e == 255) {
PyErr_SetString(PyExc_ValueError, "can't unpack IEEE 754 special value "
"on non-IEEE platform");
return -1;
}
/* Third byte */
f |= *p << 8;
p += incr;
/* Fourth byte */
f |= *p;
x = (double)f / 8388608.0;
/* XXX This sadly ignores Inf/NaN issues */
if (e == 0)
e = -126;
else {
x += 1.0;
e -= 127;
}
x = ldexp(x, e);
if (sign)
x = -x;
return x;
} else {
float x;
if ((float_format == ieee_little_endian_format && !le) || (float_format == ieee_big_endian_format && le)) {
char buf[4];
char* d = &buf[3];
int i;
for (i = 0; i < 4; i++) {
*d-- = *p++;
}
memcpy(&x, buf, 4);
} else {
memcpy(&x, p, 4);
}
return x;
}
}
extern "C" double _PyFloat_Unpack8(const unsigned char* p, int le) noexcept {
if (double_format == unknown_format) {
unsigned char sign;
int e;
unsigned int fhi, flo;
double x;
int incr = 1;
if (le) {
p += 7;
incr = -1;
}
/* First byte */
sign = (*p >> 7) & 1;
e = (*p & 0x7F) << 4;
p += incr;
/* Second byte */
e |= (*p >> 4) & 0xF;
fhi = (*p & 0xF) << 24;
p += incr;
if (e == 2047) {
PyErr_SetString(PyExc_ValueError, "can't unpack IEEE 754 special value "
"on non-IEEE platform");
return -1.0;
}
/* Third byte */
fhi |= *p << 16;
p += incr;
/* Fourth byte */
fhi |= *p << 8;
p += incr;
/* Fifth byte */
fhi |= *p;
p += incr;
/* Sixth byte */
flo = *p << 16;
p += incr;
/* Seventh byte */
flo |= *p << 8;
p += incr;
/* Eighth byte */
flo |= *p;
x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */
x /= 268435456.0; /* 2**28 */
if (e == 0)
e = -1022;
else {
x += 1.0;
e -= 1023;
}
x = ldexp(x, e);
if (sign)
x = -x;
return x;
} else {
double x;
if ((double_format == ieee_little_endian_format && !le) || (double_format == ieee_big_endian_format && le)) {
char buf[8];
char* d = &buf[7];
int i;
for (i = 0; i < 8; i++) {
*d-- = *p++;
}
memcpy(&x, buf, 8);
} else {
memcpy(&x, p, 8);
}
return x;
}
}
#if DBL_MANT_DIG == 53
#define FIVE_POW_LIMIT 22
#else
#error "C doubles do not appear to be IEEE 754 binary64 format"
#endif
extern "C" PyObject* _Py_double_round(double x, int ndigits) noexcept {
double rounded, m;
Py_ssize_t buflen, mybuflen = 100;
char* buf, *buf_end, shortbuf[100], * mybuf = shortbuf;
int decpt, sign, val, halfway_case;
PyObject* result = NULL;
_Py_SET_53BIT_PRECISION_HEADER;
/* Easy path for the common case ndigits == 0. */
if (ndigits == 0) {
rounded = round(x);
if (fabs(rounded - x) == 0.5)
/* halfway between two integers; use round-away-from-zero */
rounded = x + (x > 0.0 ? 0.5 : -0.5);
return PyFloat_FromDouble(rounded);
}
/* The basic idea is very simple: convert and round the double to a
decimal string using _Py_dg_dtoa, then convert that decimal string
back to a double with _Py_dg_strtod. There's one minor difficulty:
Python 2.x expects round to do round-half-away-from-zero, while
_Py_dg_dtoa does round-half-to-even. So we need some way to detect
and correct the halfway cases.
Detection: a halfway value has the form k * 0.5 * 10**-ndigits for
some odd integer k. Or in other words, a rational number x is
exactly halfway between two multiples of 10**-ndigits if its
2-valuation is exactly -ndigits-1 and its 5-valuation is at least
-ndigits. For ndigits >= 0 the latter condition is automatically
satisfied for a binary float x, since any such float has
nonnegative 5-valuation. For 0 > ndigits >= -22, x needs to be an
integral multiple of 5**-ndigits; we can check this using fmod.
For -22 > ndigits, there are no halfway cases: 5**23 takes 54 bits
to represent exactly, so any odd multiple of 0.5 * 10**n for n >=
23 takes at least 54 bits of precision to represent exactly.
Correction: a simple strategy for dealing with halfway cases is to
(for the halfway cases only) call _Py_dg_dtoa with an argument of
ndigits+1 instead of ndigits (thus doing an exact conversion to
decimal), round the resulting string manually, and then convert
back using _Py_dg_strtod.
*/
/* nans, infinities and zeros should have already been dealt
with by the caller (in this case, builtin_round) */
assert(std::isfinite(x) && x != 0.0);
/* find 2-valuation val of x */
m = frexp(x, &val);
while (m != floor(m)) {
m *= 2.0;
val--;
}
/* determine whether this is a halfway case */
if (val == -ndigits - 1) {
if (ndigits >= 0)
halfway_case = 1;
else if (ndigits >= -FIVE_POW_LIMIT) {
double five_pow = 1.0;
int i;
for (i = 0; i < -ndigits; i++)
five_pow *= 5.0;
halfway_case = fmod(x, five_pow) == 0.0;
} else
halfway_case = 0;
} else
halfway_case = 0;
/* round to a decimal string; use an extra place for halfway case */
_Py_SET_53BIT_PRECISION_START;
buf = _Py_dg_dtoa(x, 3, ndigits + halfway_case, &decpt, &sign, &buf_end);
_Py_SET_53BIT_PRECISION_END;
if (buf == NULL) {
PyErr_NoMemory();
return NULL;
}
buflen = buf_end - buf;
/* in halfway case, do the round-half-away-from-zero manually */
if (halfway_case) {
int i, carry;
/* sanity check: _Py_dg_dtoa should not have stripped
any zeros from the result: there should be exactly
ndigits+1 places following the decimal point, and
the last digit in the buffer should be a '5'.*/
assert(buflen - decpt == ndigits + 1);
assert(buf[buflen - 1] == '5');
/* increment and shift right at the same time. */
decpt += 1;
carry = 1;
for (i = buflen - 1; i-- > 0;) {
carry += buf[i] - '0';
buf[i + 1] = carry % 10 + '0';
carry /= 10;
}
buf[0] = carry + '0';
}
/* Get new buffer if shortbuf is too small. Space needed <= buf_end -
buf + 8: (1 extra for '0', 1 for sign, 5 for exp, 1 for '\0'). */
if (buflen + 8 > mybuflen) {
mybuflen = buflen + 8;
mybuf = (char*)PyMem_Malloc(mybuflen);
if (mybuf == NULL) {
PyErr_NoMemory();
goto exit;
}
}
/* copy buf to mybuf, adding exponent, sign and leading 0 */
PyOS_snprintf(mybuf, mybuflen, "%s0%se%d", (sign ? "-" : ""), buf, decpt - (int)buflen);
/* and convert the resulting string back to a double */
errno = 0;
_Py_SET_53BIT_PRECISION_START;
rounded = _Py_dg_strtod(mybuf, NULL);
_Py_SET_53BIT_PRECISION_END;
if (errno == ERANGE && fabs(rounded) >= 1.)
PyErr_SetString(PyExc_OverflowError, "rounded value too large to represent");
else
result = PyFloat_FromDouble(rounded);
/* done computing value; now clean up */
if (mybuf != shortbuf)
PyMem_Free(mybuf);
exit:
_Py_dg_freedtoa(buf);
return result;
}
void setupFloat() { void setupFloat() {
_addFunc("__add__", BOXED_FLOAT, (void*)floatAddFloat, (void*)floatAddInt, (void*)floatAdd); _addFunc("__add__", BOXED_FLOAT, (void*)floatAddFloat, (void*)floatAddInt, (void*)floatAdd);
float_cls->giveAttr("__radd__", float_cls->getattr("__add__")); float_cls->giveAttr("__radd__", float_cls->getattr("__add__"));
......
...@@ -200,7 +200,7 @@ extern "C" PyObject* PyInt_FromString(const char* s, char** pend, int base) noex ...@@ -200,7 +200,7 @@ extern "C" PyObject* PyInt_FromString(const char* s, char** pend, int base) noex
if (x < 0) if (x < 0)
return PyLong_FromString(s, pend, base); return PyLong_FromString(s, pend, base);
} else } else
x = strtoul(s, &end, base); x = strtol(s, &end, base);
if (end == s || !isalnum(Py_CHARMASK(end[-1]))) if (end == s || !isalnum(Py_CHARMASK(end[-1])))
goto bad; goto bad;
while (*end && isspace(Py_CHARMASK(*end))) while (*end && isspace(Py_CHARMASK(*end)))
...@@ -672,8 +672,13 @@ extern "C" Box* intLShiftInt(BoxedInt* lhs, BoxedInt* rhs) { ...@@ -672,8 +672,13 @@ extern "C" Box* intLShiftInt(BoxedInt* lhs, BoxedInt* rhs) {
if (rhs->n < 0) if (rhs->n < 0)
raiseExcHelper(ValueError, "negative shift count"); raiseExcHelper(ValueError, "negative shift count");
// TODO overflow? bool undefined = rhs->n >= sizeof(rhs->n) * 8;
if (!undefined) {
int64_t res = lhs->n << rhs->n;
if ((res >> rhs->n) == lhs->n)
return boxInt(lhs->n << rhs->n); return boxInt(lhs->n << rhs->n);
}
return longLshift(boxLong(lhs->n), rhs);
} }
extern "C" Box* intLShift(BoxedInt* lhs, Box* rhs) { extern "C" Box* intLShift(BoxedInt* lhs, Box* rhs) {
......
...@@ -109,7 +109,7 @@ Box* seqiterNext(Box* s) { ...@@ -109,7 +109,7 @@ Box* seqiterNext(Box* s) {
} }
static void seqiterGCVisit(GCVisitor* v, Box* b) { static void seqiterGCVisit(GCVisitor* v, Box* b) {
assert(b->cls == seqiter_cls); assert(b->cls == seqiter_cls || b->cls == seqreviter_cls);
boxGCHandler(v, b); boxGCHandler(v, b);
BoxedSeqIter* si = static_cast<BoxedSeqIter*>(b); BoxedSeqIter* si = static_cast<BoxedSeqIter*>(b);
...@@ -182,7 +182,8 @@ void setupIter() { ...@@ -182,7 +182,8 @@ void setupIter() {
seqiter_cls->freeze(); seqiter_cls->freeze();
seqiter_cls->tpp_hasnext = seqiterHasnextUnboxed; seqiter_cls->tpp_hasnext = seqiterHasnextUnboxed;
seqreviter_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedSeqIter), false, "reversed"); seqreviter_cls
= BoxedHeapClass::create(type_cls, object_cls, seqiterGCVisit, 0, 0, sizeof(BoxedSeqIter), false, "reversed");
seqreviter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1))); seqreviter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1)));
seqreviter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqreviterHasnext, BOXED_BOOL, 1))); seqreviter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqreviterHasnext, BOXED_BOOL, 1)));
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "core/stats.h" #include "core/stats.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "gc/roots.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
...@@ -423,23 +424,21 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) { ...@@ -423,23 +424,21 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
size_t v_size; size_t v_size;
Box** v_elts; Box** v_elts;
RootedBox v_as_seq((Box*)nullptr);
if (!v) { if (!v) {
v_size = 0; v_size = 0;
v_elts = NULL; v_elts = NULL;
} else if (v->cls == list_cls || isSubclass(v->cls, list_cls)) { } else {
BoxedList* lv = static_cast<BoxedList*>(v); v_as_seq = RootedBox(PySequence_Fast(v, "can only assign an iterable"));
v_size = lv->size; if (v_as_seq == NULL)
throwCAPIException();
v_size = PySequence_Fast_GET_SIZE(v_as_seq);
// If lv->size is 0, lv->elts->elts is garbage // If lv->size is 0, lv->elts->elts is garbage
if (v_size) if (v_size)
v_elts = lv->elts->elts; v_elts = PySequence_Fast_ITEMS(v_as_seq);
else else
v_elts = NULL; v_elts = NULL;
} else if (v->cls == tuple_cls || isSubclass(v->cls, tuple_cls)) {
BoxedTuple* tv = static_cast<BoxedTuple*>(v);
v_size = tv->size();
v_elts = &tv->elts[0];
} else {
RELEASE_ASSERT(0, "unsupported type for list slice assignment: '%s'", getTypeName(v));
} }
// If self->size is 0, self->elts->elts is garbage // If self->size is 0, self->elts->elts is garbage
......
...@@ -116,7 +116,48 @@ extern "C" unsigned PY_LONG_LONG PyLong_AsUnsignedLongLongMask(PyObject* vv) noe ...@@ -116,7 +116,48 @@ extern "C" unsigned PY_LONG_LONG PyLong_AsUnsignedLongLongMask(PyObject* vv) noe
} }
extern "C" PY_LONG_LONG PyLong_AsLongLong(PyObject* vv) noexcept { extern "C" PY_LONG_LONG PyLong_AsLongLong(PyObject* vv) noexcept {
Py_FatalError("unimplemented"); PY_LONG_LONG bytes;
int one = 1;
int res;
if (vv == NULL) {
PyErr_BadInternalCall();
return -1;
}
if (!PyLong_Check(vv)) {
PyNumberMethods* nb;
PyObject* io;
if (PyInt_Check(vv))
return (PY_LONG_LONG)PyInt_AsLong(vv);
if ((nb = vv->cls->tp_as_number) == NULL || nb->nb_int == NULL) {
PyErr_SetString(PyExc_TypeError, "an integer is required");
return -1;
}
io = (*nb->nb_int)(vv);
if (io == NULL)
return -1;
if (PyInt_Check(io)) {
bytes = PyInt_AsLong(io);
Py_DECREF(io);
return bytes;
}
if (PyLong_Check(io)) {
bytes = PyLong_AsLongLong(io);
Py_DECREF(io);
return bytes;
}
Py_DECREF(io);
PyErr_SetString(PyExc_TypeError, "integer conversion failed");
return -1;
}
res = _PyLong_AsByteArray((PyLongObject*)vv, (unsigned char*)&bytes, SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 1);
/* Plan 9 can't handle PY_LONG_LONG in ? : expressions */
if (res < 0)
return (PY_LONG_LONG)-1;
else
return bytes;
} }
extern "C" PY_LONG_LONG PyLong_AsLongLongAndOverflow(PyObject* obj, int* overflow) noexcept { extern "C" PY_LONG_LONG PyLong_AsLongLongAndOverflow(PyObject* obj, int* overflow) noexcept {
...@@ -442,7 +483,12 @@ extern "C" void* PyLong_AsVoidPtr(PyObject* vv) noexcept { ...@@ -442,7 +483,12 @@ extern "C" void* PyLong_AsVoidPtr(PyObject* vv) noexcept {
extern "C" int _PyLong_AsByteArray(PyLongObject* v, unsigned char* bytes, size_t n, int little_endian, extern "C" int _PyLong_AsByteArray(PyLongObject* v, unsigned char* bytes, size_t n, int little_endian,
int is_signed) noexcept { int is_signed) noexcept {
Py_FatalError("unimplemented"); RELEASE_ASSERT(little_endian == 1, "not implemented");
RELEASE_ASSERT(n == 8, "did not yet check if the behaviour is correct for sizes other than 8");
size_t count = 0;
mpz_export(bytes, &count, -1, n, 0, 0, ((BoxedLong*)v)->n);
RELEASE_ASSERT(count <= n, "overflow handling is not yet implemented");
return 0;
} }
extern "C" PyObject* _PyLong_FromByteArray(const unsigned char* bytes, size_t n, int little_endian, extern "C" PyObject* _PyLong_FromByteArray(const unsigned char* bytes, size_t n, int little_endian,
......
...@@ -2305,8 +2305,17 @@ extern "C" PyObject* PyString_FromStringAndSize(const char* s, ssize_t n) noexce ...@@ -2305,8 +2305,17 @@ extern "C" PyObject* PyString_FromStringAndSize(const char* s, ssize_t n) noexce
return boxStrConstantSize(s, n); return boxStrConstantSize(s, n);
} }
static /*const*/ char* string_getbuffer(register PyObject* op) noexcept {
char* s;
Py_ssize_t len;
if (PyString_AsStringAndSize(op, &s, &len))
return NULL;
return s;
}
extern "C" char* PyString_AsString(PyObject* o) noexcept { extern "C" char* PyString_AsString(PyObject* o) noexcept {
RELEASE_ASSERT(isSubclass(o->cls, str_cls), ""); if (!PyString_Check(o))
return string_getbuffer(o);
BoxedString* s = static_cast<BoxedString*>(o); BoxedString* s = static_cast<BoxedString*>(o);
return getWriteableStringContents(s); return getWriteableStringContents(s);
......
...@@ -978,7 +978,39 @@ Box* sliceRepr(BoxedSlice* self) { ...@@ -978,7 +978,39 @@ Box* sliceRepr(BoxedSlice* self) {
extern "C" int PySlice_GetIndices(PySliceObject* r, Py_ssize_t length, Py_ssize_t* start, Py_ssize_t* stop, extern "C" int PySlice_GetIndices(PySliceObject* r, Py_ssize_t length, Py_ssize_t* start, Py_ssize_t* stop,
Py_ssize_t* step) noexcept { Py_ssize_t* step) noexcept {
Py_FatalError("unimplemented"); /* XXX support long ints */
if (r->step == Py_None) {
*step = 1;
} else {
if (!PyInt_Check(r->step) && !PyLong_Check(r->step))
return -1;
*step = PyInt_AsSsize_t(r->step);
}
if (r->start == Py_None) {
*start = *step < 0 ? length - 1 : 0;
} else {
if (!PyInt_Check(r->start) && !PyLong_Check(r->step))
return -1;
*start = PyInt_AsSsize_t(r->start);
if (*start < 0)
*start += length;
}
if (r->stop == Py_None) {
*stop = *step < 0 ? -1 : length;
} else {
if (!PyInt_Check(r->stop) && !PyLong_Check(r->step))
return -1;
*stop = PyInt_AsSsize_t(r->stop);
if (*stop < 0)
*stop += length;
}
if (*stop > length)
return -1;
if (*start >= length)
return -1;
if (*step == 0)
return -1;
return 0;
} }
extern "C" int PySlice_GetIndicesEx(PySliceObject* _r, Py_ssize_t length, Py_ssize_t* start, Py_ssize_t* stop, extern "C" int PySlice_GetIndicesEx(PySliceObject* _r, Py_ssize_t length, Py_ssize_t* start, Py_ssize_t* stop,
......
...@@ -105,8 +105,8 @@ print callable(lambda: 1) ...@@ -105,8 +105,8 @@ print callable(lambda: 1)
print range(5L, 7L) print range(5L, 7L)
print round(-1.1), round(-1.9) for n in [0, 1, 2, 3, 4, 5]:
print round(0.5), round(-0.5) print round(-1.1, n), round(-1.9, n), round(0.5, n), round(-0.5, n), round(-0.123456789, n)
print list(iter(xrange(100).__iter__().next, 20)) print list(iter(xrange(100).__iter__().next, 20))
......
...@@ -66,6 +66,9 @@ class L(object): ...@@ -66,6 +66,9 @@ class L(object):
print type(int(L())) print type(int(L()))
print int(u'123') print int(u'123')
print int("9223372036854775808", 0)
print 1 << 63, 1 << 64, -1 << 63, -1 << 64, 2 << 63
print type(1 << 63), type(1 << 64), type(-1 << 63), type(-1 << 64), type(2 << 63)
for b in range(26): for b in range(26):
try: try:
......
...@@ -124,7 +124,13 @@ for i in xrange(3): ...@@ -124,7 +124,13 @@ for i in xrange(3):
l[j:k] = ["added"] l[j:k] = ["added"]
print i, j, k, l print i, j, k, l
def G():
yield "a"
yield "b"
yield "c"
l = [0, 1, 2, 3, 4, 5]
l[1:] = G()
print l
l = [1, 3, 5, 7, 2, 4] l = [1, 3, 5, 7, 2, 4]
print l.sort(key=lambda x:x%3) print l.sort(key=lambda x:x%3)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment