summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2007-10-12 18:10:06 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2007-10-12 18:10:06 (GMT)
commited6d3879f55e8ebf6d0f58c15d62befe848d84e5 (patch)
tree4abd38fb06eba7dd523931904d73927f752d06e5
parent2540bb686630c8e7e1993747848b5ae52dcd8740 (diff)
downloadpbn-ed6d3879f55e8ebf6d0f58c15d62befe848d84e5.zip
pbn-ed6d3879f55e8ebf6d0f58c15d62befe848d84e5.tar.gz
pbn-ed6d3879f55e8ebf6d0f58c15d62befe848d84e5.tar.bz2
pbn-ed6d3879f55e8ebf6d0f58c15d62befe848d84e5.tar.xz
Add pbn_shl() and pbn_shr()
Shift operations
-rw-r--r--pbn_shift.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/pbn_shift.c b/pbn_shift.c
new file mode 100644
index 0000000..67a78ce
--- /dev/null
+++ b/pbn_shift.c
@@ -0,0 +1,98 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, Inc.,
+ * 59 Temple Place Ste 330, Boston MA 02111-1307, USA; version 2.1,
+ * incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * pbn_shift.c
+ */
+
+#include <string.h>
+#include "pbn.h"
+
+struct pbn *pbn_shl(struct pbn *src, int shift)
+{
+ int bits, len;
+ pbn_atom_t b, c;
+ int i;
+ int sw, sb;
+
+ if (src->bits == 0 || shift == 0)
+ return src; /* Source was zero or shift was zero */
+
+ if (shift < 0)
+ return pbn_shr(src, -shift);
+
+ bits = src->bits + shift;
+ len = (bits+PBN_ATOM_BITS-1)/PBN_ATOM_BITS;
+
+ dst = src_cow(src, len);
+
+ sw = shift / PBN_ATOM_BITS;
+ sb = shift % PBN_ATOM_BITS;
+
+ if (sb == 0) {
+ /* Particularly simple case... */
+ memmove(&dst->num[sw], &dst->num[0], len-sw);
+ } else {
+ b = dst->num[len-sw-1];
+ for (i = len-sw-1; i > 0; i--) {
+ /* b == dst->num[i] */
+ c = dst->num[i-1];
+ dst->num[i+sw] = (b << sb) | (c >> (PBN_ATOM_BITS-sb));
+ b = c;
+ }
+ dst->num[sw] = b << sb;
+ }
+
+ if (sw)
+ memset(&dst->num[0], 0, sw*sizeof(pbn_atom_t));
+
+ return dst;
+}
+
+struct pbn *pbn_shr(struct pbn *src, int shift)
+{
+ int len;
+ pbn_atom_t b, c;
+ int i;
+ int sw, sb;
+
+ if (src->bits == 0 || shift == 0)
+ return src; /* Source was zero or shift was zero */
+
+ if (shift < 0)
+ return pbn_shl(src, -shift);
+
+ len = src->len;
+ dst = src_cow(src, len); /* Leave at its old size */
+
+ sw = shift / PBN_ATOM_BITS;
+ sb = shift % PBN_ATOM_BITS;
+
+ if (sb == 0) {
+ /* Particularly simple case... */
+ memmove(&dst->num[0], &dst->num[sw], len-sw);
+ } else {
+ c = dst->num[sw];
+ for (i = sw; i < len-1; i++) {
+ /* c == dst->num[i] */
+ b = dst->num[i+1];
+ dst->num[i-sw] = (c >> sb) | (b << (PBN_ATOM_BITS-sb));
+ c = b;
+ }
+ dst->num[len-sw] = c >> sb;
+ }
+
+ if (sw)
+ memset(&dst->num[len-sw], 0, sw*sizeof(pbn_atom_t));
+
+ return dst;
+}