From 4e2dde17464a8dda5dd5b644d1ccd83633fbcac9 Mon Sep 17 00:00:00 2001 From: Mike Dirolf Date: Tue, 1 Dec 2009 11:37:12 -0500 Subject: [PATCH] minor: refactor C time helpers out to a new file --- pymongo/_cbsonmodule.c | 172 +---------------------------------------- pymongo/time_helpers.c | 163 ++++++++++++++++++++++++++++++++++++++ pymongo/time_helpers.h | 40 ++++++++++ setup.py | 5 +- 4 files changed, 209 insertions(+), 171 deletions(-) create mode 100644 pymongo/time_helpers.c create mode 100644 pymongo/time_helpers.h diff --git a/pymongo/_cbsonmodule.c b/pymongo/_cbsonmodule.c index fdd61a117..f066bea2c 100644 --- a/pymongo/_cbsonmodule.c +++ b/pymongo/_cbsonmodule.c @@ -30,6 +30,8 @@ #include #include +#include "time_helpers.h" + static PyObject* InvalidName; static PyObject* InvalidDocument; static PyObject* InvalidStringData; @@ -52,172 +54,7 @@ typedef int Py_ssize_t; /* Maximum number of regex flags */ #define FLAGS_SIZE 7 - -/* TODO we ought to check that the malloc or asprintf was successful - * and raise an exception if not. */ #if defined(WIN32) || defined(_MSC_VER) - -/* no mkgmtime on MSVC before VS 2005. this is terribly gross */ -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define GMTIME_INVERSE(time_struct) _mkgmtime64(time_struct) -#else -/* Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The name "Carnegie Mellon University" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For permission or any other legal - * details, please contact - * Office of Technology Transfer - * Carnegie Mellon University - * 5000 Forbes Avenue - * Pittsburgh, PA 15213-3890 - * (412) 268-4387, fax: (412) 268-7395 - * tech-transfer@andrew.cmu.edu - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Computing Services - * at Carnegie Mellon University (http://www.cmu.edu/computing/)." - * - * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * - */ -/* - * Copyright (c) 1987, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Arthur David Olson of the National Cancer Institute. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* -** Adapted from code provided by Robert Elz, who writes: -** The "best" way to do mktime I think is based on an idea of Bob -** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). -** It does a binary search of the time_t space. Since time_t's are -** just 32 bits, its a max of 32 iterations (even at 64 bits it -** would still be very reasonable). -*/ -#ifndef WRONG -#define WRONG (-1) -#endif /* !defined WRONG */ - -static int tmcomp(atmp, btmp) - register const struct tm * const atmp; - register const struct tm * const btmp; -{ - register int result; - - if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && - (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && - (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && - (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && - (result = (atmp->tm_min - btmp->tm_min)) == 0) - result = atmp->tm_sec - btmp->tm_sec; - return result; -} - -time_t mkgmtime(tmp) -struct tm * const tmp; -{ - register int dir; - register int bits; - register int saved_seconds; - time_t t; - struct tm yourtm, *mytm; - - yourtm = *tmp; - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = 0; - - /* - ** Calculate the number of magnitude bits in a time_t - ** (this works regardless of whether time_t is - ** signed or unsigned, though lint complains if unsigned). - */ - for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) - ; - /* - ** If time_t is signed, then 0 is the median value, - ** if time_t is unsigned, then 1 << bits is median. - */ - t = (t < 0) ? 0 : ((time_t) 1 << bits); - - /* Some gmtime() implementations are broken and will return - * NULL for time_ts larger than 40 bits even on 64-bit platforms - * so we'll just cap it at 40 bits */ - if(bits > 40) bits = 40; - - for ( ; ; ) { - mytm = gmtime(&t); - - if(!mytm) return WRONG; - - dir = tmcomp(mytm, &yourtm); - if (dir != 0) { - if (bits-- < 0) - return WRONG; - if (bits < 0) - --t; - else if (dir > 0) - t -= (time_t) 1 << bits; - else t += (time_t) 1 << bits; - continue; - } - break; - } - t += saved_seconds; - return t; -} -#define GMTIME_INVERSE(time_struct) mkgmtime((time_struct)) -#endif /* This macro is basically an implementation of asprintf for win32 * We get the length of the int as string and malloc a buffer for it, * returning -1 if that malloc fails. We then actually print to the @@ -234,14 +71,9 @@ struct tm * const tmp; "%d", \ (i))) #define STRCAT(dest, n, src) strcat_s((dest), (n), (src)) -#define GMTIME(timeinfo, seconds) gmtime_s((timeinfo), (seconds)) -#define LOCALTIME(timeinfo, seconds) localtime_s((timeinfo), (seconds)) #else -#define GMTIME_INVERSE(time_struct) timegm((time_struct)) #define INT2STRING(buffer, i) asprintf((buffer), "%d", (i)) #define STRCAT(dest, n, src) strcat((dest), (src)) -#define GMTIME(timeinfo, seconds) gmtime_r((seconds), (timeinfo)), 0 -#define LOCALTIME(timeinfo, seconds) localtime_r((seconds), (timeinfo)), 0 #endif /* A buffer representing some data being encoded to BSON. */ diff --git a/pymongo/time_helpers.c b/pymongo/time_helpers.c new file mode 100644 index 000000000..ec815fde3 --- /dev/null +++ b/pymongo/time_helpers.c @@ -0,0 +1,163 @@ +/* Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any other legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * + */ +/* + * Copyright (c) 1987, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Arthur David Olson of the National Cancer Institute. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* +** Adapted from code provided by Robert Elz, who writes: +** The "best" way to do mktime I think is based on an idea of Bob +** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). +** It does a binary search of the time_t space. Since time_t's are +** just 32 bits, its a max of 32 iterations (even at 64 bits it +** would still be very reasonable). +*/ + +/* This hack is just for MSVC before VS 2005. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + +#include + +#ifndef WRONG +#define WRONG (-1) +#endif /* !defined WRONG */ + +static int tmcomp(atmp, btmp) + register const struct tm * const atmp; + register const struct tm * const btmp; +{ + register int result; + + if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && + (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && + (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && + (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && + (result = (atmp->tm_min - btmp->tm_min)) == 0) + result = atmp->tm_sec - btmp->tm_sec; + return result; +} + +time_t mkgmtime(tmp) +struct tm * const tmp; +{ + register int dir; + register int bits; + register int saved_seconds; + time_t t; + struct tm yourtm, *mytm; + + yourtm = *tmp; + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = 0; + + /* + ** Calculate the number of magnitude bits in a time_t + ** (this works regardless of whether time_t is + ** signed or unsigned, though lint complains if unsigned). + */ + for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) + ; + /* + ** If time_t is signed, then 0 is the median value, + ** if time_t is unsigned, then 1 << bits is median. + */ + t = (t < 0) ? 0 : ((time_t) 1 << bits); + + /* Some gmtime() implementations are broken and will return + * NULL for time_ts larger than 40 bits even on 64-bit platforms + * so we'll just cap it at 40 bits */ + if(bits > 40) bits = 40; + + for ( ; ; ) { + mytm = gmtime(&t); + + if(!mytm) return WRONG; + + dir = tmcomp(mytm, &yourtm); + if (dir != 0) { + if (bits-- < 0) + return WRONG; + if (bits < 0) + --t; + else if (dir > 0) + t -= (time_t) 1 << bits; + else t += (time_t) 1 << bits; + continue; + } + break; + } + t += saved_seconds; + return t; +} + +#endif diff --git a/pymongo/time_helpers.h b/pymongo/time_helpers.h new file mode 100644 index 000000000..786a2c7d9 --- /dev/null +++ b/pymongo/time_helpers.h @@ -0,0 +1,40 @@ +/* + * Copyright 2009 10gen, 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. + */ + +#ifndef TIME_HELPERS_H +#define TIME_HELPERS_H + +#include + +/* + * Some helpers for dealing with time stuff in a cross platform way. + */ +#if defined(WIN32) || defined(_MSC_VER) +/* No mkgmtime on MSVC before VS 2005. + * This is terribly gross (see time_helpers.c). */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define GMTIME_INVERSE(time_struct) _mkgmtime64(time_struct) +#else +#define GMTIME_INVERSE(time_struct) mkgmtime((time_struct)) +#define GMTIME(timeinfo, seconds) gmtime_s((timeinfo), (seconds)) +#define LOCALTIME(timeinfo, seconds) localtime_s((timeinfo), (seconds)) +#endif +#define GMTIME_INVERSE(time_struct) timegm((time_struct)) +#define GMTIME(timeinfo, seconds) gmtime_r((seconds), (timeinfo)), 0 +#define LOCALTIME(timeinfo, seconds) localtime_r((seconds), (timeinfo)), 0 +#endif + +#endif diff --git a/setup.py b/setup.py index b2f142a03..1a780aa09 100755 --- a/setup.py +++ b/setup.py @@ -117,7 +117,10 @@ although they do result in significant speed improvements. c_ext = Feature( "optional C extension", standard=True, - ext_modules=[Extension('pymongo._cbson', ['pymongo/_cbsonmodule.c'])]) + ext_modules=[Extension('pymongo._cbson', + include_dirs=['pymongo'], + sources=['pymongo/_cbsonmodule.c', + 'pymongo/time_helpers.c'])]) if "--no_ext" in sys.argv: sys.argv = [x for x in sys.argv if x != "--no_ext"]