blib/lib/Thread/Queue/Queueable.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 1 | 3 | 33.3 |
branch | n/a | ||
condition | n/a | ||
subroutine | 1 | 1 | 100.0 |
pod | n/a | ||
total | 2 | 4 | 50.0 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | #/** | ||||||
2 | # Abstract base class defining the interfaces, and providing | ||||||
3 | # simple marshalling methods, for complex object to be passed | ||||||
4 | # across a Thread::Queue::Duplex | ||||||
5 | # queue. | ||||||
6 | #
|
||||||
7 | # Licensed under the Academic Free License version 2.1, as specified in the | ||||||
8 | # License.txt file included in this software package, or at | ||||||
9 | # OpenSource.org. | ||||||
10 | # | ||||||
11 | # @author D. Arnold | ||||||
12 | # @since 2005-12-01 | ||||||
13 | # @self $obj | ||||||
14 | #*/ | ||||||
15 | package Thread::Queue::Queueable; | ||||||
16 | # | ||||||
17 | # abstract class to permit an object to be | ||||||
18 | # marshalled in some way before pushing onto | ||||||
19 | # a Thread::Queue::Duplex queue | ||||||
20 | # | ||||||
21 | require 5.008; | ||||||
22 | |||||||
23 | 1 | 1 | 2293 | use threads; | |||
0 | |||||||
0 | |||||||
24 | use threads::shared; | ||||||
25 | |||||||
26 | use strict; | ||||||
27 | use warnings; | ||||||
28 | |||||||
29 | our $VERSION = '0.90'; | ||||||
30 | |||||||
31 | #/** | ||||||
32 | # Marshal an object for queueing to a Thread::Queue::Duplex | ||||||
33 | # queue. Called by any of TQD's enqueue() methods, | ||||||
34 | # as well as respond() method. | ||||||
35 | #
|
||||||
36 | # The default implementation the input | ||||||
37 | # object into either a shared array or shared hash (depending on the base structure | ||||||
38 | # of the object), and returns a list consisting of the object's class name, and the cursed object. | ||||||
39 | # | ||||||
40 | # @returnlist list of (object's class, object's marshalled representation) | ||||||
41 | #*/ | ||||||
42 | sub onEnqueue { | ||||||
43 | my $obj = shift; | ||||||
44 | # | ||||||
45 | # capture class name, and create cursed | ||||||
46 | # version of object | ||||||
47 | # | ||||||
48 | return (ref $obj, $obj->curse()); | ||||||
49 | } | ||||||
50 | |||||||
51 | #/** | ||||||
52 | # Unmarshall an object after being dequeued. Called by any of TQD's | ||||||
53 | # dequeue() methods, | ||||||
54 | # as well as the various request side dequeueing | ||||||
55 | # methods (e.g., wait()). | ||||||
56 | #
|
||||||
57 | # The default implementation redeem()'s the input object | ||||||
58 | # to copy the input shared arrayref or hashref into a nonshared equivalent, then | ||||||
59 | # blessing it into the specified class, returning the redeemed object. | ||||||
60 | # | ||||||
61 | # @param $object the marshalled representation of the object | ||||||
62 | # @return the unmarshalled aka "redeemed" object | ||||||
63 | #*/ | ||||||
64 | sub onDequeue { | ||||||
65 | my ($class, $obj) = @_; | ||||||
66 | # | ||||||
67 | # reconstruct as non-shared by redeeming | ||||||
68 | # | ||||||
69 | return $class->redeem($obj); | ||||||
70 | } | ||||||
71 | |||||||
72 | #/** | ||||||
73 | # Pure virtual function to apply any object-specific cancel processing. Called by TQD's | ||||||
74 | # respond() method | ||||||
76 | # when a cancelled operation is detected. | ||||||
77 | # | ||||||
78 | # @return 1 | ||||||
79 | #*/ | ||||||
80 | sub onCancel { | ||||||
81 | my $obj = shift; | ||||||
82 | return 1; | ||||||
83 | } | ||||||
84 | #/** | ||||||
85 | # Marshal an object into a value that can be passed via | ||||||
86 | # a Thread::Queue::Duplex object. | ||||||
87 | #
|
||||||
88 | # Called by TQD's various enqueue() and | ||||||
89 | # respond() methods | ||||||
90 | # when the TQQ object is being enqueue'd. Should return an unblessed, | ||||||
91 | # shared version of the input object. | ||||||
92 | #
|
||||||
93 | # Default returns a shared | ||||||
94 | # arrayref or hashref, depending on the object's base structure, with | ||||||
95 | # copies of all scalar members. | ||||||
96 | #
|
||||||
97 | # Note that objects with more complex members will need to | ||||||
98 | # implement an object specific curse() to do any deepcopying, |
||||||
99 | # including curse()ing any subordinate objects. | ||||||
100 | # | ||||||
101 | # @return marshalled version of the object | ||||||
102 | #*/ | ||||||
103 | sub curse { | ||||||
104 | my $obj = shift; | ||||||
105 | # | ||||||
106 | # if we're already shared, don't share again | ||||||
107 | # | ||||||
108 | return $obj if threads::shared::_id($obj); | ||||||
109 | |||||||
110 | if ($obj->isa('HASH')) { | ||||||
111 | my %cursed : shared = (); | ||||||
112 | $cursed{$_} = $obj->{$_} | ||||||
113 | foreach (keys %$obj); | ||||||
114 | return \%cursed; | ||||||
115 | } | ||||||
116 | |||||||
117 | my @cursed : shared = (); | ||||||
118 | $cursed[$_] = $obj->[$_] | ||||||
119 | foreach (0..$#$obj); | ||||||
120 | return \@cursed; | ||||||
121 | } | ||||||
122 | #/** | ||||||
123 | # Unmarshall an object back into its blessed form. | ||||||
124 | #
|
||||||
125 | # Called by TQD's various dequeue() and | ||||||
126 | # wait methods to | ||||||
127 | # "redeem" (i.e., rebless) the object into its original class. | ||||||
128 | #
|
||||||
129 | # Default creates non-shared copy of the input object structure, | ||||||
130 | # copying its scalar contents, and blessing it into the specified class. | ||||||
131 | #
|
||||||
132 | # Note that objects with complex members need to implement | ||||||
133 | # an object specific redeem() , possibly recursively |
||||||
134 | # redeem()ing subordinate objects (be careful | ||||||
135 | # of circular references!) | ||||||
136 | # | ||||||
137 | # @param $object marshalled aka "cursed" version of the object | ||||||
138 | # | ||||||
139 | # @return unmarshalled, blessed version of the object | ||||||
140 | #*/ | ||||||
141 | sub redeem { | ||||||
142 | my ($class, $obj) = @_; | ||||||
143 | # | ||||||
144 | # if object is already shared, just rebless it | ||||||
145 | # NOTE: we can only do this when threads::shared::_id() is defined | ||||||
146 | # | ||||||
147 | return bless $obj, $class | ||||||
148 | if threads::shared->can('_id') && threads::shared::_id($obj); | ||||||
149 | # | ||||||
150 | # we *could* just return the blessed object, | ||||||
151 | # which would be shared...but that might | ||||||
152 | # not be the expected behavior... | ||||||
153 | # | ||||||
154 | if (ref $obj eq 'HASH') { | ||||||
155 | my $redeemed = {}; | ||||||
156 | $redeemed->{$_} = $obj->{$_} | ||||||
157 | foreach (keys %$obj); | ||||||
158 | return bless $redeemed, $class; | ||||||
159 | } | ||||||
160 | |||||||
161 | my $redeemed = []; | ||||||
162 | $redeemed->[$_] = $obj->[$_] | ||||||
163 | foreach (0..$#$obj); | ||||||
164 | return bless $redeemed, $class; | ||||||
165 | } | ||||||
166 | |||||||
167 | 1; |