1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 
27 #ifndef _hpp_seq_ranges_
28 #define _hpp_seq_ranges_
29 
30 #include <list>
31 
32 namespace seq_ranges {
33 
34 enum e_range_relation {
35 	rr_before,
36 	rr_begin,
37 	rr_span,
38 	rr_inside,
39 	rr_end,
40 	rr_after
41 };
42 
43 
44 /* -----------------------------------------------------------------------
45 	range-relations:
46 
47 	A            |-------------|
48 	B   |-----|
49 	A.range_rel( B ) = rr_before
50 
51 	A      |-------------|
52 	B   |-----|
53 	A.range_rel( B ) = rr_begin
54 
55 	A      |-------------|
56 	B   |-------------------|
57 	A.range_rel( B ) = rr_span
58 
59 	A      |-------------|
60 	B           |-----|
61 	A.range_rel( B ) = rr_inside
62 
63 	A   |-------------|
64 	B              |-----|
65 	A.range_rel( B ) = rr_end
66 
67 	A   |-------------|
68 	B                    |-----|
69 	A.range_rel( B ) = rr_after
70 
71    ----------------------------------------------------------------------- */
72 
73 class range
74 {
75 	private :
76 		long start;
77 		long end;
78 
79 	public :
range(void)80 		range( void ) : start( 0 ), end( 0 ) { }
range(long start_,long end_)81 		range( long start_, long end_ ) : start( start_ ), end( end_ ) { }
range(const range & other)82 		range( const range &other ) : start( other.start ), end( other.end ) { }
83 
range(const std::string & start_,const std::string & end_)84 		range( const std::string &start_, const std::string &end_ ) : start( 0 ), end( 0 )
85 		{
86 			bool valid = ( convert_value( start_, start ) && convert_value( end_, end ) );
87 			if ( !valid ) set( 0, 0 );
88 		}
89 
operator =(const range & other)90 		range& operator= ( const range &other )
91 		{
92 			if ( this == &other ) return *this;
93 			start = other.start;
94 			end = other.end;
95 			return *this;
96 		}
97 
set(long start_,long end_)98 		void set( long start_, long end_ ) { start = start_; end = end_; }
99 
convert_value(const std::string value_,long & value)100 		static bool convert_value( const std::string value_, long &value )
101 		{
102 			bool res = true;
103 			std::istringstream ( value_ ) >> value;
104 			if ( value < 1 )
105 				res = false;
106 			return res;
107 		}
108 
109 		/* does this range end before the other range starts ? */
ends_before(const range & other) const110 		bool ends_before( const range &other ) const { return ( end < other.start ); }
111 
112 		/* does this range start after the other range ends ? */
starts_after(const range & other) const113 		bool starts_after( const range &other ) const { return ( start > other.end ); }
114 
intersect(const range & other) const115 		bool intersect( const range &other ) const
116 		{
117 			e_range_relation rr = range_relation( other );
118 			return ( rr == rr_begin || rr == rr_span || rr == rr_inside || rr == rr_end );
119 		}
120 
intersect(const long value) const121 		bool intersect( const long value ) const
122 		{ return ( value >= start && value <= end ); }
123 
include(const range & other)124 		void include( const range &other )
125 		{
126 			if ( other.start < start ) start = other.start;
127 			if ( other.end > end ) end = other.end;
128 		}
129 
merge(const range & other)130 		bool merge( const range &other )
131 		{
132 			bool res = intersect( other );
133 			if ( res ) include( other );
134 			return res;
135 		}
136 
range_relation(const range & other) const137 		enum e_range_relation range_relation( const range &other ) const
138 		{
139 			enum e_range_relation res;
140 			if ( other.start < start )
141 			{
142 				if ( other.end < start )
143 					res = rr_before;
144 				else if ( other.end <= end )
145 					res = rr_begin;
146 				else
147 					res = rr_span;
148 			}
149 			else
150 			{
151 				if ( other.start <= end )
152 				{
153 					if ( other.end <= end )
154 						res = rr_inside;
155 					else
156 						res = rr_end;
157 				}
158 				else
159 					res = rr_after;
160 			}
161 
162 			return res;
163 		}
164 
get_start(void) const165 		long get_start( void ) const { return start; }
get_end(void) const166 		long get_end( void ) const { return end; }
empty(void) const167 		bool empty( void ) const { return ( start == 0 && end == 0 ); }
168 
print(std::ostream & stream) const169 		void print( std::ostream &stream ) const { stream << "[ " << start << " .. " << end << " ]"; }
170 
operator <<(std::ostream & stream,const range & other)171 		friend std::ostream& operator<< ( std::ostream &stream, const range &other )
172 		{
173 			other.print( stream );
174 			return stream;
175 		}
176 
range_relation_2_str(enum e_range_relation rr)177 		static std::string range_relation_2_str( enum e_range_relation rr )
178 		{
179 			switch ( rr )
180 			{
181 				case rr_before : return std::string( "before" ); break;
182 				case rr_begin  : return std::string( "begin" ); break;
183 				case rr_span   : return std::string( "span" ); break;
184 				case rr_inside : return std::string( "inside" ); break;
185 				case rr_end    : return std::string( "end" ); break;
186 				case rr_after  : return std::string( "after" ); break;
187 			}
188 			return std::string( "unknown" );
189 		}
190 
191 };
192 
193 
compare_ranges(const range * first,const range * second)194 bool compare_ranges ( const range * first, const range * second )
195 {
196 	return ( first -> get_start() < second -> get_start() );
197 }
198 
199 
200 struct ranges_relation
201 {
202 	bool has_inside;
203 	bool has_partial;
204 
clearseq_ranges::ranges_relation205 	void clear( void ) { has_inside = has_partial = false; }
206 
printseq_ranges::ranges_relation207 	void print( std::ostream &stream ) const { stream << "inside: " << has_inside << ", partial: " << has_partial; }
208 
operator <<(std::ostream & stream,const ranges_relation & other)209 	friend std::ostream& operator<< ( std::ostream &stream, const ranges_relation &other )
210 	{
211 		other.print( stream );
212 		return stream;
213 	}
214 };
215 
216 
217 class ranges
218 {
219 	private :
220 		std::list< range * > range_list;
221 		long count;
222 
223 	public :
ranges(void)224 		ranges( void ) : count( 0 ) {}
~ranges(void)225 		~ranges( void ) { clear(); }
226 
clear(void)227 		void clear( void )
228 		{
229 			while ( !range_list.empty() )
230 			{
231 				range * r = range_list.front();
232 				range_list.pop_front();
233 				if ( r != NULL ) delete r;
234 			}
235 			count = 0;
236 		}
237 
add(range * r)238 		void add( range * r ){ if ( r != NULL ) { range_list.push_back( r ); count++; } }
add(const range & r)239 		void add( const range &r ){ add( new range( r ) ); }
240 
merge(const range & r1)241 		void merge( const range &r1 )
242 		{
243 			bool merged = false;
244 			std::list< range * >::iterator it;
245 			for ( it = range_list.begin(); it != range_list.end() && !merged; ++it )
246 			{
247 				range * r = *it;
248 				if ( r != NULL )
249 					merged = r -> merge( r1 );
250 			}
251 			if ( !merged ) add( r1 );
252 		}
253 
sort(void)254 		void sort( void ) { range_list.sort( compare_ranges ); }
get_count(void)255 		long get_count( void ) { return count; }
256 
compare_sample(const ranges & sample,ranges_relation & res) const257 		void compare_sample( const ranges &sample, ranges_relation &res ) const
258 		{
259 			res.clear();
260 			bool done = false;
261 
262 			// we take each range of the sample and compare it against each range of self
263 			std::list< range * >::const_iterator sample_it;
264 			for ( sample_it = sample.range_list.begin(); sample_it != sample.range_list.end() && !done; ++sample_it )
265 			{
266 				const range * sample_range = *sample_it;
267 				std::list< range * >::const_iterator pattern_it;
268 				for ( pattern_it = range_list.begin(); pattern_it != range_list.end() && !done; ++pattern_it )
269 				{
270 					const range * pattern_range( *pattern_it );
271 					enum e_range_relation rr = pattern_range -> range_relation( *sample_range );
272 					switch( rr )
273 					{
274 						case rr_before 	: break;
275 						case rr_begin	: res.has_partial = true; break;
276 						case rr_span	: res.has_partial = true; break;
277 						case rr_inside 	: res.has_inside = true; break;
278 						case rr_end		: res.has_partial = true; break;
279 						case rr_after	: break;
280 					}
281 					done = ( res.has_partial && res.has_inside );
282 				}
283 			}
284 		}
285 
print(std::ostream & stream) const286 		void print( std::ostream &stream ) const
287 		{
288 			std::list< range * >::const_iterator it;
289 			for ( it = range_list.begin(); it != range_list.end(); ++it )
290 			{
291 				range * r = *it;
292 				if ( r != NULL ) stream << *r << " ";
293 			}
294 		}
295 
operator <<(std::ostream & stream,const ranges & other)296 		friend std::ostream& operator<< ( std::ostream &stream, const ranges &other )
297 		{
298 			other.print( stream );
299 			return stream;
300 		}
301 
302 };
303 
304 };  // namespace seq_ranges
305 
306 #endif // _hpp_seq_ranges_
307 
308