[1012] in BarnOwl Developers

home help back first fref pref prev next nref lref last post

[D-O-H] r997 - branches/barnowl_sqlite/owl

daemon@ATHENA.MIT.EDU (nelhage@MIT.EDU)
Thu Oct 29 18:12:07 2009

Resent-From: nelhage@mit.edu
Resent-To: barnowl-dev-mtg@charon.mit.edu
X-Original-To: nelhage@nelhage.com
To: dirty-owl-hackers@MIT.EDU
From: nelhage@MIT.EDU
Reply-to: dirty-owl-hackers@MIT.EDU
Date: Sat, 29 Mar 2008 20:48:00 -0400 (EDT)

Author: nelhage
Date: 2008-03-29 20:48:00 -0400 (Sat, 29 Mar 2008)
New Revision: 997

Modified:
   branches/barnowl_sqlite/owl/global.c
   branches/barnowl_sqlite/owl/owl.c
   branches/barnowl_sqlite/owl/owl.h
   branches/barnowl_sqlite/owl/perlwrap.pm
   branches/barnowl_sqlite/owl/view.c
Log:
Move views and view iterators into perl code


Modified: branches/barnowl_sqlite/owl/global.c
===================================================================
--- branches/barnowl_sqlite/owl/global.c	2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/global.c	2008-03-30 00:48:00 UTC (rev 997)
@@ -55,8 +55,6 @@
   owl_list_create(&(g->messagequeue));
   owl_dict_create(&(g->styledict));
   g->curmsg_vert_offset=0;
-  g->curmsg = owl_view_iterator_new();
-  g->topmsg = owl_view_iterator_new();
   g->resizepending=0;
   g->typwinactive=0;
   g->direction=OWL_DIRECTION_DOWNWARDS;
@@ -93,7 +91,6 @@
   owl_global_set_confdir(g, cd);
   owl_free(cd);
 
-  owl_mainwin_init(&(g->mw));
   owl_popwin_init(&(g->pw));
 
   g->aim_screenname=NULL;
@@ -121,6 +118,15 @@
   g->fmtext_seq = 0;
 }
 
+/* Called once perl has been initialized */
+void owl_global_complete_setup(owl_global *g)
+{
+  owl_mainwin_init(&(g->mw));
+  g->msglist = owl_messagelist_new();
+  g->curmsg = owl_view_iterator_new();
+  g->topmsg = owl_view_iterator_new();
+}
+
 void _owl_global_setup_windows(owl_global *g) {
   int cols, typwin_lines;
 

Modified: branches/barnowl_sqlite/owl/owl.c
===================================================================
--- branches/barnowl_sqlite/owl/owl.c	2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/owl.c	2008-03-30 00:48:00 UTC (rev 997)
@@ -264,8 +264,7 @@
     exit(1);
   }
 
-  /* Now that we have perl, we can initialize the msssage list*/
-  g.msglist = owl_messagelist_new();
+  owl_global_complete_setup(&g);
 
   /* setup the built-in styles */
   owl_function_debugmsg("startup: creating built-in styles");

Modified: branches/barnowl_sqlite/owl/owl.h
===================================================================
--- branches/barnowl_sqlite/owl/owl.h	2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/owl.h	2008-03-30 00:48:00 UTC (rev 997)
@@ -418,7 +418,7 @@
   int cachedmsgid;  /* cached msgid: should move into view eventually */
 } owl_filter;
 
-typedef struct _owl_view {
+/* typedef struct _owl_view {
   char *name;
   char *filtname;
   owl_list messages;
@@ -427,8 +427,11 @@
 typedef struct _owl_view_iterator {
   owl_view *view;
   int index;
-} owl_view_iterator;
+  } owl_view_iterator; */
 
+typedef SV owl_view;
+typedef SV owl_view_iterator;
+
 typedef struct _owl_mainwin {
   int curtruncated;
   int lasttruncated;

Modified: branches/barnowl_sqlite/owl/perlwrap.pm
===================================================================
--- branches/barnowl_sqlite/owl/perlwrap.pm	2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/perlwrap.pm	2008-03-30 00:48:00 UTC (rev 997)
@@ -380,6 +380,175 @@
 #####################################################################
 #####################################################################
 
+package BarnOwl::View;
+
+sub get_name   {return shift->{name}};
+sub messages   {return shift->{messages}};
+sub get_filter {return shift->{filter}};
+
+sub new {
+    my $class = shift;
+    my $name = shift;
+    my $filter = shift;
+    my $self  = {messages  => [],
+                 name      => $name,
+                 filter    => $filter};
+    bless $self, $class;
+    $self->recalculate;
+    return $self;
+}
+
+sub consider_message {
+    my $self = shift;
+    my $msg  = shift;
+    if(BarnOwl::filter_message_match($self->get_filter, $msg)) {
+        push @{$self->messages}, $msg;
+    }
+}
+
+sub recalculate {
+    my $self = shift;
+    my $ml   = BarnOwl::message_list();
+    $ml->start_iterate;
+    $self->{messages} = [];
+    while(my $msg = $ml->iterate_next) {
+        $self->consider_message($msg);
+    }
+}
+
+sub new_filter {
+    my $self = shift;
+    my $filter = shift;
+    $self->{filter} = $filter;
+    $self->recalculate;
+}
+
+sub is_empty {
+    my $self = shift;
+    return $self->_size == 0;
+}
+
+sub _size {
+    my $self = shift;
+    return scalar @{$self->messages};
+}
+
+#####################################################################
+#####################################################################
+
+package BarnOwl::View::Iterator;
+
+sub view {return shift->{view}}
+sub index {return shift->{index}}
+
+sub new {
+    my $class = shift;
+    my $self = {
+        view  => undef,
+        index => undef
+       };
+    return bless $self, $class;
+}
+
+sub invalidate {
+    my $self = shift;
+    $self->{view} = undef;
+    $self->{index} = undef;
+}
+
+sub initialize_at_start {
+    my $self = shift;
+    my $view = shift;
+    $self->{view}  = $view;
+    $self->{index} = 0;
+}
+
+sub initialize_at_end {
+    my $self = shift;
+    my $view = shift;
+    $self->{view}  = $view;
+    $self->{index} = $self->view->_size - 1;
+}
+
+sub initialize_at_id {
+    my $self = shift;
+    my $view = shift;
+    my $id   = shift;
+    $self->{view} = $view;
+    my $list = $self->view->messages;
+    my $left = 0;
+    my $right = scalar @{$list} - 1;
+    my $mid;
+    while($left <= $right) {
+        $mid = ($left + $right)/2;
+        if($list->[$mid]->id < $id) {
+            $left = $mid + 1;
+        } else {
+            $right = $mid - 1;
+        }
+    }
+    $self->{index} = $mid;
+}
+
+sub clone {
+    my $self = shift;
+    my $other = shift;
+    $self->{view} = $other->{view};
+    $self->{index} = $other->{index};
+}
+
+sub has_prev {
+    my $self = shift;
+    return $self->index > 0;
+}
+
+sub has_next {
+    my $self = shift;
+    return $self->index < $self->view->_size - 1;
+}
+
+sub at_start {
+    my $self = shift;
+    return $self->index < 0;
+}
+
+sub at_end {
+    my $self = shift;
+    return $self->index >= $self->view->_size;
+}
+
+
+sub valid {
+    my $self = shift;
+    return defined($self->view) &&
+            !$self->at_start &&
+            !$self->at_end;
+}
+
+sub prev {
+    my $self = shift;
+    $self->{index}-- unless $self->at_start
+}
+
+sub next {
+    my $self = shift;
+    $self->{index}++ unless $self->at_end
+}
+
+sub get_message {
+    my $self = shift;
+    return $self->view->messages->[$self->index];
+}
+
+sub cmp {
+    my $self = shift;
+    my $other = shift;
+    return $self->index - $other->index;
+}
+
+#####################################################################
+#####################################################################
+
 package BarnOwl::Message;
 use POSIX qw(ctime);
 

Modified: branches/barnowl_sqlite/owl/view.c
===================================================================
--- branches/barnowl_sqlite/owl/view.c	2008-03-29 21:16:07 UTC (rev 996)
+++ branches/barnowl_sqlite/owl/view.c	2008-03-30 00:48:00 UTC (rev 997)
@@ -1,35 +1,41 @@
 #include <stdlib.h>
+#define OWL_PERL
 #include "owl.h"
 
 static const char fileIdent[] = "$Id$";
 
-owl_view* owl_view_new(char *name, char *filtname)
+owl_view_iterator* owl_view_new(char *name, char *filtname)
 {
-  owl_view *v = owl_malloc(sizeof(owl_view));
-  v->name=owl_strdup(name);
-  v->filtname=owl_strdup(filtname);
-  owl_list_create(&(v->messages));
-  owl_view_recalculate(v);
-  return v;
+  char *args[] = {name, filtname};
+  return owl_perl_new_argv("BarnOwl::View", args, 2);
 }
 
 char *owl_view_get_name(owl_view *v)
 {
-  return(v->name);
+  SV *name;
+  OWL_PERL_CALL_METHOD(v, "get_name",
+                       /* no args */,
+                       /* error message */
+                       "Error in get_name: %s",
+                       1 /* fatal errors */,
+                       name = SvREFCNT_inc(POPs););
+  sv_2mortal(name);
+  return SvPV_nolen(name);
 }
 
 owl_filter * owl_view_get_filter(owl_view *v)
 {
-  return owl_global_get_filter(&g, v->filtname);
+  return owl_global_get_filter(&g, owl_view_get_filtname(v));
 }
 
 /* if the message matches the filter then add to view */
 void owl_view_consider_message(owl_view *v, owl_message *m)
 {
-  if (owl_filter_message_match(owl_view_get_filter(v), m)) {
-    owl_list_append_element(&(v->messages),
-                            (void*)owl_message_get_id(m));
-  }
+  OWL_PERL_CALL_METHOD(v, "consider_message",
+                       XPUSHs((SV*)m);,
+                       "Error in consider_message: %s",
+                       /* fatal */ 1,
+                       OWL_PERL_VOID_CALL);
 }
 
 /* remove all messages, add all the global messages that match the
@@ -37,84 +43,33 @@
  */
 void owl_view_recalculate(owl_view *v)
 {
-  owl_messagelist *gml;
-  owl_list *ml;
-  owl_message *m;
-  owl_filter *f;
-
-  gml=owl_global_get_msglist(&g);
-  ml=&(v->messages);
-
-  /* nuke the old list */
-  owl_list_free_simple(ml);
-  owl_list_create(ml);
-
-  /* find all the messages we want */
-  owl_messagelist_start_iterate(gml);
-  f = owl_view_get_filter(v);
-  while((m = owl_messagelist_iterate_next(gml)) != NULL) {
-    if (owl_filter_message_match(f, m)) {
-      owl_list_append_element(ml, (void*)owl_message_get_id(m));
-    }
-  }
+  OWL_PERL_CALL_METHOD(v, "recalculate",
+                       /* no args */,
+                       "Error in recalculate: %s",
+                       /* fatal */ 1,
+                       OWL_PERL_VOID_CALL);
 }
 
 void owl_view_new_filter(owl_view *v, char *filtname)
 {
-  owl_free(v->filtname);
-  v->filtname = owl_strdup(filtname);
-  owl_view_recalculate(v);
+  OWL_PERL_CALL_METHOD(v, "new_filter",
+                       mXPUSHp(filtname, strlen(filtname));,
+                       "Error in new_filter: %s",
+                       /* fatal */ 1,
+                       OWL_PERL_VOID_CALL);
 }
 
-owl_message *_owl_view_get_element(owl_view *v, int index)
-{
-  if(index < 0 || index >= _owl_view_get_size(v))
-    return NULL;
-  int id = (int)owl_list_get_element(&(v->messages), index);
-  return owl_messagelist_get_by_id(owl_global_get_msglist(&g), id);
-}
-
 int owl_view_is_empty(owl_view *v)
 {
-  return owl_list_get_size(&(v->messages)) == 0;
+  int empty;
+  OWL_PERL_CALL_METHOD(v, "is_empty",
+                       /* no args */,
+                       "Error: is_empty: %s",
+                       /* fatal */ 1,
+                       empty = POPi);
+  return empty;
 }
 
-int _owl_view_get_size(owl_view *v)
-{
-  return(owl_list_get_size(&(v->messages)));
-}
-
-/* Returns the position in the view with a message closest 
- * to the passed msgid. */
-int _owl_view_get_nearest_to_msgid(owl_view *v, int targetid)
-{
-  int first, last, mid = 0, max, bestdist, curid = 0;
-
-  first = 0;
-  last = max = _owl_view_get_size(v) - 1;
-  while (first <= last) {
-    mid = (first + last) / 2;
-    curid = (int)owl_list_get_element(&(v->messages), mid);
-    if (curid == targetid) {
-      return(mid);
-    } else if (curid < targetid) {
-      first = mid + 1;
-    } else {
-      last = mid - 1;
-    }
-  }
-  bestdist = abs(targetid-curid);
-  if (curid < targetid && mid+1 < max) {
-    curid = (int)owl_list_get_element(&(v->messages), mid+1);
-    mid = (bestdist < abs(targetid-curid)) ? mid : mid+1;
-  }
-  else if (curid > targetid && mid-1 >= 0) {
-    curid = (int)owl_list_get_element(&(v->messages), mid-1);
-    mid = (bestdist < abs(targetid-curid)) ? mid : mid-1;
-  }
-  return mid;
-}
-
 /* saves the current message position in the filter so it can 
  * be restored later if we switch back to this filter. */
 void owl_view_save_curmsgid(owl_view *v, int curid)
@@ -126,121 +81,187 @@
 void owl_view_to_fmtext(owl_view *v, owl_fmtext *fm)
 {
   owl_fmtext_append_normal(fm, "Name: ");
-  owl_fmtext_append_normal(fm, v->name);
+  owl_fmtext_append_normal(fm, owl_view_get_name(v));
   owl_fmtext_append_normal(fm, "\n");
 
   owl_fmtext_append_normal(fm, "Filter: ");
   owl_fmtext_append_normal(fm, owl_view_get_filtname(v));
   owl_fmtext_append_normal(fm, "\n");
-
-  /* owl_fmtext_append_normal(fm, "Style: ");
-  owl_fmtext_append_normal(fm, owl_style_get_name(v->style));
-  owl_fmtext_append_normal(fm, "\n"); */
 }
 
 char *owl_view_get_filtname(owl_view *v)
 {
-  return v->filtname;
+  SV *name;
+  OWL_PERL_CALL_METHOD(v, "get_filter",
+                       /* no args */,
+                       "Error: get_filter: %s",
+                       1 /* fatal errors */,
+                       name = SvREFCNT_inc(POPs));
+  sv_2mortal(name);
+  return SvPV_nolen(name);
 }
 
 void owl_view_free(owl_view *v)
 {
-  owl_list_free_simple(&(v->messages));
-  if (v->name) owl_free(v->name);
-  if (v->filtname) owl_free(v->filtname);
+  SvREFCNT_dec((SV*)v);
 }
 
-/* View Iterators */
+/********************************************************************
+ * View iterators
+ *
+ * The only supported way to access the elements of a view are through
+ * the view iterator API presented here.
+ *
+ * There are three ways to initialize an iterator:
+ * * At the first of the view's messages
+ * * Given an ID, at the message in the view closest to that ID
+ * * At the last of the view's messages
+ *
+ * In addition to pointing at a message, an iterator may point at two
+ * special positions, before the first message in the list, and after
+ * the last message in the list
+ *
+ * The predicates is_at_start and is_at_end test for these special
+ * iterators.
+ *
+ * The predicates has_next and has_prev test whether an iterator
+ * points to the first or last message in the view
+ *
+ * _prev and _next, if applied to the special "start" or "end"
+ * iterators respectively, are no-ops.
+ */
 
-owl_view_iterator* owl_view_iterator_new()
+#define CALL_BOOL(it, method)                           \
+  int _rv;                                              \
+  OWL_PERL_CALL_METHOD(it, method,                      \
+                       /* No args */,                   \
+                       "Error: " #method ": %s",        \
+                       /* fatal */ 1,                   \
+                       _rv = POPi);                     \
+  return _rv;
+
+#define CALL_VOID(it, method)                           \
+  OWL_PERL_CALL_METHOD(it, method,                      \
+                       /* No args */,                   \
+                       "Error: " #method ": %s",        \
+                       /* fatal */ 1,                   \
+                       OWL_PERL_VOID_CALL);             \
+
+owl_view_iterator * owl_view_iterator_new()
 {
-  return owl_malloc(sizeof(owl_view_iterator));
+  return owl_perl_new("BarnOwl::View::Iterator");
 }
 
 void owl_view_iterator_invalidate(owl_view_iterator *it)
 {
-  it->index = -1;
-  it->view = NULL;
+  CALL_VOID(it, "invalidate");
 }
 
 void owl_view_iterator_init_id(owl_view_iterator *it, owl_view *v, int message_id)
 {
-  it->view = v;
-  it->index = _owl_view_get_nearest_to_msgid(v, message_id);
+  OWL_PERL_CALL_METHOD(it, "initialize_at_id",
+                       /* args */
+                       XPUSHs(v);
+                       mXPUSHi(message_id);,
+                       "Error: initialize at id: %s",
+                       /* fatal */ 1,
+                       OWL_PERL_VOID_CALL);
 }
 
 void owl_view_iterator_init_start(owl_view_iterator *it, owl_view *v)
 {
-  it->view = v;
-  it->index = 0;
+  OWL_PERL_CALL_METHOD(it, "initialize_at_start",
+                       /* args */
+                       XPUSHs(v);,
+                       "Error: initialize at start: %s",
+                       /* fatal */ 1,
+                       OWL_PERL_VOID_CALL);
 }
 
 void owl_view_iterator_init_end(owl_view_iterator *it, owl_view *v)
 {
-  it->view = v;
-  it->index = _owl_view_get_size(v) - 1;
+  OWL_PERL_CALL_METHOD(it, "initialize_at_end",
+                       /* args */
+                       XPUSHs(v);,
+                       "Error: initialize at end: %s",
+                       /* fatal */ 1,
+                       OWL_PERL_VOID_CALL);
 }
 
 void owl_view_iterator_clone(owl_view_iterator *dst, owl_view_iterator *src)
 {
-  dst->view  = src->view;
-  dst->index = src->index;
+  OWL_PERL_CALL_METHOD(dst, "clone",
+                       XPUSHs(src);,
+                       "Error: clone: %s",
+                       /* fatal */ 1,
+                       OWL_PERL_VOID_CALL);
 }
 
 int owl_view_iterator_has_prev(owl_view_iterator *it)
 {
-  return it->index > 0;
+  CALL_BOOL(it, "has_prev");
 }
 
 int owl_view_iterator_has_next(owl_view_iterator *it)
 {
-  return it->index < _owl_view_get_size(it->view) - 1;
+  CALL_BOOL(it, "has_next");
 }
 
 int owl_view_iterator_is_at_end(owl_view_iterator *it)
 {
-  return it->index >= _owl_view_get_size(it->view);
+  CALL_BOOL(it, "at_end");
 }
 
 int owl_view_iterator_is_at_start(owl_view_iterator *it)
 {
-  return it->index < 0;
+  CALL_BOOL(it, "at_start");
 }
 
 int owl_view_iterator_is_valid(owl_view_iterator *it)
 {
-  return it->view != NULL && it->index >= 0 && it->index < _owl_view_get_size(it->view);
+  CALL_BOOL(it, "valid");
 }
 
 void owl_view_iterator_prev(owl_view_iterator *it)
 {
-  if(!owl_view_iterator_is_at_start(it))
-    it->index--;
+  CALL_VOID(it, "prev");
 }
 
 void owl_view_iterator_next(owl_view_iterator *it)
 {
-  if(!owl_view_iterator_is_at_end(it))
-    it->index++;
+  CALL_VOID(it, "next");
 }
 
-owl_message * owl_view_iterator_get_message(owl_view_iterator *it)
+owl_message* owl_view_iterator_get_message(owl_view_iterator *it)
 {
-  return _owl_view_get_element(it->view, it->index);
+  SV *msg;
+  OWL_PERL_CALL_METHOD(it, "get_message",
+                       /* no args */,
+                       "Error: get_message: %s",
+                       /* fatal errors */ 1,
+                       msg = POPs;
+                       if(SvROK(msg)) SvREFCNT_inc(msg);
+                       );
+  return SvROK(msg) ? sv_2mortal(msg) : NULL;
 }
 
 int owl_view_iterator_cmp(owl_view_iterator *it1, owl_view_iterator *it2)
 {
-  return it1->index - it2->index;
+  int cmp;
+  OWL_PERL_CALL_METHOD(it1, "cmp",
+                       XPUSHs(it2);,
+                       "Error: cmp: %s",
+                       /* fatal */ 1,
+                       cmp = POPi);
+  return cmp;
 }
 
 void owl_view_iterator_free(owl_view_iterator *it)
 {
-  owl_free(it);
+  SvREFCNT_dec(it);
 }
 
 owl_view_iterator* owl_view_iterator_free_later(owl_view_iterator *it)
 {
-  /* do-de-doo, leaking da memory... */
-  return it;
+  return sv_2mortal(it);
 }


home help back first fref pref prev next nref lref last post