ARB
insdel.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : insdel.cxx //
4 // Purpose : insert/delete columns //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 // AISC_MKPT_PROMOTE:#ifndef ARBDB_BASE_H
12 // AISC_MKPT_PROMOTE:#include <arbdb_base.h>
13 // AISC_MKPT_PROMOTE:#endif
14 
15 #include "insdel.h"
16 #include <RangeList.h>
17 
18 #include <arbdbt.h>
19 #include <adGene.h>
20 #include <arb_progress.h>
21 #include <arb_defs.h>
22 #include <arb_diff.h>
23 #include <algorithm>
24 
25 using namespace std;
26 
27 #define id_assert(cond) arb_assert(cond)
28 
29 // --------------------------------------------------------------------------------
30 // helper to hold any kind of unit (char, int, float)
31 
32 class UnitPtr {
33  const void *ptr;
34 public:
35  UnitPtr() : ptr(NULp) {}
36  UnitPtr(const void *ptr_)
37  : ptr(ptr_)
38  {
39  id_assert(ptr);
40  }
41 
42  void set_pointer(const void *ptr_) {
43  id_assert(!ptr);
44  ptr = ptr_;
45  }
46  const void *get_pointer() const { return ptr; }
47  const void *expect_pointer() const { id_assert(ptr); return ptr; }
48 };
49 struct UnitPair {
50  UnitPtr left, right;
51 };
52 
53 template <typename T>
54 inline int compare_type(const T& t1, const T& t2) {
55  return t1<t2 ? -1 : (t1>t2 ? 1 : 0);
56 }
57 
58 // --------------------------------------------------------------------------------
59 
60 class AliData;
62 
63 // --------------------------------------------------------------------------------
64 
65 class AliData {
66  size_t size;
67  static GB_ERROR op_error;
68 
69 public:
70  AliData(size_t size_) : size(size_) {}
71  virtual ~AliData() {}
72 
73  virtual size_t unitsize() const = 0;
74  virtual bool has_slice() const = 0;
75 
76  enum memop {
77  COPY_TO, // always returns 0
78  COMPARE_WITH, // returns compare value
79  CHECK_DELETE, // return 0 if ok to delete, otherwise op_error is set
80  };
81 
82  void clear_error() const { op_error = NULp; }
83  void set_error(GB_ERROR error) const {
84  id_assert(error);
85  id_assert(!op_error);
86  op_error = error;
87  }
88 
89  virtual int operate_on_mem(void *mem, size_t start, size_t count, memop op) const = 0;
90  virtual int cmp_data(size_t start, const AliData& other, size_t ostart, size_t count) const = 0;
91 
92  void copyPartTo(void *mem, size_t start, size_t count) const { operate_on_mem(mem, start, count, COPY_TO); }
93  int cmpPartWith(const void *mem, size_t start, size_t count) const {
94  id_assert(is_valid_part(start, count));
95  return operate_on_mem(const_cast<void*>(mem), start, count, COMPARE_WITH); // COMPARE_WITH does not modify
96  }
97  GB_ERROR check_delete_allowed(size_t start, size_t count) const {
98  op_error = NULp;
99  id_assert(start <= size);
100  IF_ASSERTION_USED(int forbidden =) operate_on_mem(NULp, start, std::min(count, size-start), CHECK_DELETE);
101  id_assert(correlated(forbidden, op_error));
102  return op_error;
103  }
104 
105  virtual UnitPtr unit_left_of(size_t pos) const = 0;
106  virtual UnitPtr unit_right_of(size_t pos) const = 0;
107 
108  virtual AliDataPtr create_gap(size_t gapsize, const UnitPair& gapinfo) const = 0;
109  virtual AliDataPtr slice_down(size_t start, size_t count) const = 0;
110 
111  size_t elems() const { return size; }
112  size_t memsize() const { return unitsize()*elems(); }
113  void copyTo(void *mem) const { copyPartTo(mem, 0, elems()); }
114  bool empty() const { return !elems(); }
115 
116  int cmp_whole_data(const AliData& other) const {
117  int cmp = cmp_data(0, other, 0, std::min(elems(), other.elems()));
118  if (cmp == 0) { // prefixes are equal
119  return compare_type(elems(), other.elems());
120  }
121  return cmp;
122  }
123 
124  bool equals(const AliData& other) const {
125  if (&other == this) return true;
126  if (elems() != other.elems()) return false;
127 
128  return cmp_whole_data(other) == 0;
129  }
130  bool differs_from(const AliData& other) const { return !equals(other); }
131 
132  bool is_valid_pos(size_t pos) const { return pos < elems(); }
133  bool is_valid_between(size_t pos) const { return pos <= elems(); } // pos == 0 -> before first base; pos == elems() -> after last base
134 
135  bool is_valid_part(size_t start, size_t count) const {
136  return is_valid_between(start) && is_valid_between(start+count);
137  }
138 };
139 
140 GB_ERROR AliData::op_error = NULp;
141 
142 // --------------------------------------------------------------------------------
143 
144 class AliDataSlice : public AliData {
145  AliDataPtr from;
146  size_t offset;
147 
148  static int fix_amount(AliDataPtr from, size_t offset, size_t amount) {
149  if (amount) {
150  size_t from_size = from->elems();
151  if (offset>from_size) {
152  amount = 0;
153  }
154  else {
155  size_t last_pos = offset+amount-1;
156  size_t last_from = from->elems()-1;
157 
158  if (last_pos > last_from) {
159  id_assert(last_from >= offset);
160  amount = last_from-offset+1;
161  }
162  }
163  }
164  return amount;
165  }
166 
167  AliDataSlice(AliDataPtr from_, size_t offset_, size_t amount_)
168  : AliData(fix_amount(from_, offset_, amount_)),
169  from(from_),
170  offset(offset_)
171  {
172  id_assert(!from->has_slice()); // do not double-slice
173  }
174 
175 public:
176  static AliDataPtr make(AliDataPtr from, size_t offset, size_t amount) {
177  return (offset == 0 && amount >= from->elems())
178  ? from
179  : (from->has_slice()
180  ? from->slice_down(offset, amount)
181  : new AliDataSlice(from, offset, amount));
182  }
183 
184  size_t unitsize() const OVERRIDE { return from->unitsize(); }
185  bool has_slice() const OVERRIDE { return true; }
186 
187  AliDataPtr create_gap(size_t gapsize, const UnitPair& gapinfo) const OVERRIDE {
188  return from->create_gap(gapsize, gapinfo);
189  }
190  AliDataPtr slice_down(size_t start, size_t count) const OVERRIDE {
191  return new AliDataSlice(from, offset+start, std::min(count, elems()));
192  }
193  int operate_on_mem(void *mem, size_t start, size_t count, memop op) const OVERRIDE {
194  id_assert(is_valid_part(start, count));
195  return from->operate_on_mem(mem, start+offset, count, op);
196  }
197  UnitPtr unit_left_of(size_t pos) const OVERRIDE {
198  id_assert(is_valid_between(pos));
199  return from->unit_left_of(pos+offset);
200  }
201  UnitPtr unit_right_of(size_t pos) const OVERRIDE {
202  id_assert(is_valid_between(pos));
203  return from->unit_right_of(pos+offset);
204  }
205  int cmp_data(size_t start, const AliData& other, size_t ostart, size_t count) const OVERRIDE {
206  id_assert(is_valid_part(start, count));
207  id_assert(other.is_valid_part(ostart, count));
208 
209  return from->cmp_data(start+offset, other, ostart, count);
210  }
211 };
212 
213 class ComposedAliData FINAL_TYPE : public AliData {
214  AliDataPtr left, right;
215  bool hasSlice;
216 
217  ComposedAliData(AliDataPtr l, AliDataPtr r)
218  : AliData(l->elems()+r->elems()),
219  left(l),
220  right(r),
221  hasSlice(left->has_slice() || right->has_slice())
222  {
223  id_assert(l->unitsize() == r->unitsize());
224  id_assert(l->elems());
225  id_assert(r->elems());
226  }
227  friend AliDataPtr concat(AliDataPtr left, AliDataPtr right); // for above ctor
228 
229  void *inc_by_units(void *mem, size_t units) const { return reinterpret_cast<char*>(mem)+units*unitsize(); }
230 
231 public:
232  size_t unitsize() const OVERRIDE { return left->unitsize(); }
233  bool has_slice() const OVERRIDE { return hasSlice; }
234 
235  AliDataPtr create_gap(size_t gapsize, const UnitPair& gapinfo) const OVERRIDE {
236  return left->create_gap(gapsize, gapinfo);
237  }
238  AliDataPtr slice_down(size_t start, size_t count) const OVERRIDE {
239  size_t left_elems = left->elems();
240 
241  if (left_elems <= start) { // left is before slice
242  return AliDataSlice::make(right, start-left_elems, count);
243  }
244 
245  size_t pos_behind = start+count;
246  if (left_elems >= pos_behind) { // right is behind slice
247  return AliDataSlice::make(left, start, min(count, left_elems));
248  }
249 
250  size_t take_left = left_elems-start;
251  size_t take_right = count-take_left;
252 
253  return new ComposedAliData(
254  AliDataSlice::make(left, start, take_left),
255  AliDataSlice::make(right, 0, take_right)
256  );
257  }
258  int operate_on_mem(void *mem, size_t start, size_t count, memop op) const OVERRIDE {
259  size_t left_elems = left->elems();
260  size_t take_left = 0;
261  int res = 0;
262  if (start<left_elems) {
263  take_left = min(count, left_elems-start);
264  res = left->operate_on_mem(mem, start, take_left, op);
265  }
266 
267  if (res == 0) {
268  size_t take_right = count-take_left;
269  if (take_right) {
270  size_t rstart = start>left_elems ? start-left_elems : 0;
271  id_assert(right->is_valid_part(rstart, take_right));
272  res = right->operate_on_mem(inc_by_units(mem, take_left), rstart, take_right, op);
273  }
274  }
275  return res;
276  }
277  int cmp_data(size_t start, const AliData& other, size_t ostart, size_t count) const OVERRIDE {
278  size_t left_elems = left->elems();
279  size_t take_left = 0;
280  int cmp = 0;
281  if (start<left_elems) {
282  take_left = min(count, left_elems-start);
283  cmp = left->cmp_data(start, other, ostart, take_left);
284  }
285 
286  if (cmp == 0) {
287  size_t take_right = count-take_left;
288  if (take_right) {
289  size_t rstart = start>left_elems ? start-left_elems : 0;
290  size_t rostart = ostart+take_left;
291 
292  id_assert(is_valid_part(rstart, take_right));
293  id_assert(other.is_valid_part(rostart, take_right));
294 
295  cmp = right->cmp_data(rstart, other, rostart, take_right);
296  }
297  }
298  return cmp;
299  }
300 
301  UnitPtr unit_left_of(size_t pos) const OVERRIDE {
302  id_assert(is_valid_between(pos));
303  if (left->elems() == pos) { // split between left and right
304  id_assert(pos >= 1);
305  return left->unit_right_of(pos-1);
306  }
307  else if (left->elems() < pos) { // split inside or behind 'right'
308  return right->unit_left_of(pos-left->elems());
309  }
310  else { // split inside or frontof 'left'
311  return left->unit_left_of(pos);
312  }
313  }
314  UnitPtr unit_right_of(size_t pos) const OVERRIDE {
315  id_assert(is_valid_between(pos));
316  if (left->elems() == pos) { // split between left and right
317  id_assert(pos >= 1);
318  return right->unit_left_of(0);
319  }
320  else if (left->elems() < pos) { // split inside or behind 'right'
321  return right->unit_right_of(pos-left->elems());
322  }
323  else { // split inside or frontof 'left'
324  return left->unit_right_of(pos);
325  }
326  }
327 };
328 
329 // --------------------------------------------------------------------------------
330 
331 class Deletable { // define characters allowed to delete (only applicable to TypedAliData<char>)
332  bool deletable[256];
333 
334  void init(bool val) {
335  for (int i = 0; i<256; ++i) {
336  deletable[i] = val;
337  }
338  }
339 
340 public:
341  enum DeleteWhat { NOTHING, ANYTHING };
342  explicit Deletable(DeleteWhat what) {
343  switch (what) {
344  case ANYTHING: init(true); break;
345  case NOTHING: init(false); break;
346  }
347  }
348  explicit Deletable(const char *allowed) {
349  init(false);
350  for (int i = 0; allowed[i]; ++i) {
351  deletable[safeCharIndex(allowed[i])] = true;
352  }
353  }
354 
355  GB_ERROR get_delete_error(const char *data, size_t start, size_t count) const {
356  GB_ERROR error = NULp;
357  id_assert(count > 0);
358  size_t end = start+count-1;
359  for (size_t col = start; col <= end && !error; ++col) {
360  if (!deletable[safeCharIndex(data[col])]) {
361  error = GBS_global_string("You tried to delete '%c' at position %zu -> Operation aborted", data[col], col);
362  }
363  }
364  return error;
365  }
366 };
367 
368 // --------------------------------------------------------------------------------
369 
370 template<typename T>
371 class TypedAliData : public AliData {
372  T gap;
373 
374 protected:
375  static const T *typed_ptr(const UnitPtr& uptr) { return (const T*)uptr.get_pointer(); }
376  const T* std_gap_ptr() const { return &gap; }
377 
378 public:
379  TypedAliData(size_t size_, T gap_)
380  : AliData(size_),
381  gap(gap_)
382  {}
383 
384  const T& std_gap() const { return gap; }
385 
386  size_t unitsize() const OVERRIDE { return sizeof(T); }
387  bool has_slice() const OVERRIDE { return false; }
388 
389  virtual UnitPtr at_ptr(size_t pos) const = 0;
390  AliDataPtr create_gap(size_t gapsize, const UnitPair& /*gapinfo*/) const OVERRIDE;
391  __ATTR__NORETURN AliDataPtr slice_down(size_t /*start*/, size_t /*count*/) const OVERRIDE {
392  GBK_terminate("logic error: slice_down called for explicit TypedAliData");
393  }
394  UnitPtr unit_left_of(size_t pos) const OVERRIDE {
395  id_assert(is_valid_between(pos));
396  return at_ptr(pos-1);
397  }
398  UnitPtr unit_right_of(size_t pos) const OVERRIDE {
399  id_assert(is_valid_between(pos));
400  return at_ptr(pos);
401  }
402 };
403 
404 template<typename T>
405 struct SpecificGap : public TypedAliData<T> {
407 
408  SpecificGap(size_t gapsize, const T& gap_)
409  : BaseType(gapsize, gap_)
410  {}
411  int operate_on_mem(void *mem, size_t IF_ASSERTION_USED(start), size_t count, AliData::memop op) const OVERRIDE {
412  id_assert(BaseType::is_valid_part(start, count));
413  switch (op) {
414  case AliData::COPY_TO: {
415  T *typedMem = (T*)mem;
416  for (size_t a = 0; a<count; ++a) { // LOOP_VECTORIZED=3
417  typedMem[a] = BaseType::std_gap();
418  }
419  break;
420  }
421  case AliData::COMPARE_WITH: {
422  const T *typedMem = (const T*)mem;
423  for (size_t a = 0; a<count; ++a) {
424  int cmp = compare_type(BaseType::std_gap(), typedMem[a]);
425  if (cmp) return cmp;
426  }
427  break;
428  }
429  case AliData::CHECK_DELETE: {
430  break; // deleting an inserted gap is always permitted
431  }
432  }
433  return 0;
434  }
435  int cmp_data(size_t start, const AliData& other, size_t ostart, size_t count) const OVERRIDE {
436  const SpecificGap<T> *other_is_gap = dynamic_cast<const SpecificGap<T>*>(&other);
437  if (other_is_gap) {
438  return compare_type(BaseType::std_gap(), other_is_gap->std_gap());
439  }
440  return -other.cmp_data(ostart, *this, start, count);
441  }
442  UnitPtr at_ptr(size_t pos) const OVERRIDE {
443  if (pos<BaseType::elems()) return UnitPtr(BaseType::std_gap_ptr());
444  return UnitPtr();
445  }
446 };
447 
448 template <typename T>
449 AliDataPtr TypedAliData<T>::create_gap(size_t gapsize, const UnitPair& /*gapinfo*/) const {
450  return new SpecificGap<T>(gapsize, std_gap());
451 }
452 
454  bool allows_oversize;
455  size_t org_ali_size;
456 public:
457  SizeAwarable(bool allows_oversize_, size_t ali_size_)
458  : allows_oversize(allows_oversize_),
459  org_ali_size(ali_size_)
460  {}
461 
462  size_t get_allowed_size(size_t term_size, size_t new_ali_size) const {
463  size_t allowed_size = new_ali_size;
464  if (allows_oversize && term_size>org_ali_size) {
465  size_t oversize = term_size-org_ali_size;
466  allowed_size = new_ali_size+oversize;
467  }
468  return allowed_size;
469  }
470 };
471 inline SizeAwarable dontAllowOversize(size_t ali_size) { return SizeAwarable(false, ali_size); }
472 
473 template<typename T>
474 inline GB_ERROR check_delete_allowed(const T *, size_t, size_t , const Deletable& ) {
475  return NULp; // for non-char deleting is always allowed
476 }
477 template<>
478 inline GB_ERROR check_delete_allowed(const char *data, size_t start, size_t count, const Deletable& deletable) {
479  return deletable.get_delete_error(data, start, count);
480 }
481 
482 template<typename T>
483 class SpecificAliData : public TypedAliData<T>, public SizeAwarable, virtual Noncopyable {
484  const T *data;
485  Deletable deletable;
486 
487 public:
489 
490  SpecificAliData(const T *static_data, size_t elements, const T& gap_, const SizeAwarable& sizeAware, const Deletable& deletable_)
491  : BaseType(elements, gap_),
492  SizeAwarable(sizeAware),
493  data(static_data),
494  deletable(deletable_)
495  {}
496 
497  int operate_on_mem(void *mem, size_t start, size_t count, AliData::memop op) const OVERRIDE {
498  if (count>0) {
499  id_assert(BaseType::is_valid_part(start, count));
500  switch (op) {
501  case AliData::COPY_TO: {
502  size_t msize = BaseType::unitsize()*count;
503  id_assert(msize>0);
504  memcpy(mem, data+start, msize);
505  break;
506  }
507  case AliData::COMPARE_WITH: {
508  const T *typedMem = (const T*)mem;
509  for (size_t a = 0; a<count; ++a) {
510  int cmp = compare_type(data[start+a], typedMem[a]);
511  if (cmp) return cmp;
512  }
513  break;
514  }
515  case AliData::CHECK_DELETE: {
516  const T *typedMem = (const T*)data;
517  GB_ERROR error = check_delete_allowed<T>(typedMem, start, count, deletable);
518  if (error) {
519  BaseType::set_error(error);
520  return 1;
521  }
522  break;
523  }
524  }
525  }
526  return 0;
527  }
528  int cmp_data(size_t start, const AliData& other, size_t ostart, size_t count) const OVERRIDE {
529  id_assert(BaseType::is_valid_part(start, count));
530  id_assert(other.is_valid_part(ostart, count));
531 
532  // if (&other == this && start == ostart) return true; // @@@ why does this fail tests?
533  return -other.cmpPartWith(data+start, ostart, count);
534  }
535  UnitPtr at_ptr(size_t pos) const OVERRIDE {
536  if (pos<BaseType::elems()) return UnitPtr(&data[pos]);
537  return UnitPtr();
538  }
539  const T *get_data() const { return data; }
540 };
541 
542 class SequenceAliData : public SpecificAliData<char> {
543  char dot;
544 
545  char preferred_gap(const char *s1, const char *s2) const {
546  if (s1 && s2) {
547  if (*s1 == std_gap() || *s2 == std_gap()) {
548  return std_gap();
549  }
550  if (*s1 == dot || *s2 == dot) {
551  return dot;
552  }
553  return std_gap();
554  }
555  else if (s1) {
556  id_assert(!s2);
557  return *s1 == std_gap() ? std_gap() : dot;
558  }
559  else if (s2) {
560  id_assert(!s1);
561  return *s2 == std_gap() ? std_gap() : dot;
562  }
563  else {
564  id_assert(!s1 && !s2);
565  return dot;
566  }
567  }
568 
569 public:
570  SequenceAliData(const char* static_data, size_t elements, char stdgap, char dotgap, const SizeAwarable& sizeAware, const Deletable& deletable_)
571  : SpecificAliData<char>(static_data, elements, stdgap, sizeAware, deletable_),
572  dot(dotgap)
573  {}
574 
575  AliDataPtr create_gap(size_t gapsize, const UnitPair& gapinfo) const OVERRIDE {
576  char use = preferred_gap(typed_ptr(gapinfo.left), typed_ptr(gapinfo.right));
577  return new SpecificGap<char>(gapsize, use);
578  }
579 };
580 
581 // --------------------------------------------------------------------------------
582 // @@@ move things below into a class ?
583 
584 inline AliDataPtr concat(AliDataPtr left, AliDataPtr right) {
585  return left->empty() ? right : (right->empty() ? left : new ComposedAliData(left, right));
586 }
588  return concat(left, concat(mid, right));
589 }
590 
591 inline AliDataPtr partof(AliDataPtr data, size_t pos, size_t amount) { return AliDataSlice::make(data, pos, amount); }
592 inline AliDataPtr before(AliDataPtr data, size_t pos) { return partof(data, 0, pos); }
593 inline AliDataPtr after(AliDataPtr data, size_t pos) { return partof(data, pos+1, data->elems()-pos-1); }
594 
595 inline AliDataPtr delete_from(AliDataPtr from, size_t pos, size_t amount, GB_ERROR& error) {
596  error = from->check_delete_allowed(pos, amount);
597  return concat(before(from, pos), after(from, pos+amount-1));
598 }
599 inline AliDataPtr insert_at(AliDataPtr dest, size_t pos, AliDataPtr src) {
600  return concat(before(dest, pos), src, after(dest, pos-1));
601 }
602 
603 inline AliDataPtr insert_gap(AliDataPtr data, size_t pos, size_t count) {
604  UnitPair gapinfo;
605 
606  id_assert(data->unitsize() <= sizeof(gapinfo.left));
607 
608  gapinfo.left = data->unit_left_of(pos); // @@@ do not perform ALWAYS (put into an object and lazy eval)
609  gapinfo.right = data->unit_right_of(pos);
610 
611  AliDataPtr gap = data->create_gap(count, gapinfo);
612  return insert_at(data, pos, gap);
613 }
614 
615 inline AliDataPtr format(AliDataPtr data, const size_t wanted_len, GB_ERROR& error) {
616  size_t curr_len = data->elems();
617  if (curr_len < wanted_len) {
618  data = insert_gap(data, curr_len, wanted_len-curr_len);
619  }
620  else if (curr_len > wanted_len) {
621  data = delete_from(data, wanted_len, curr_len-wanted_len, error);
622  }
623  id_assert(data->elems() == wanted_len);
624  return data;
625 }
626 
627 
628 template<typename T> inline AliDataPtr makeAliData(T*& allocated_data, size_t elems, const T& gap) {
629  return new SpecificAliData<T>(allocated_data, elems, gap, dontAllowOversize(elems), Deletable(Deletable::ANYTHING));
630 }
631 inline AliDataPtr makeAliSeqData(char*& allocated_data, size_t elems, char gap, char dot) {
632  return new SequenceAliData(allocated_data, elems, gap, dot, dontAllowOversize(elems), Deletable(Deletable::ANYTHING));
633 }
634 
635 // --------------------------------------------------------------------------------
636 
637 #ifdef UNIT_TESTS
638 #ifndef TEST_UNIT_H
639 #include <test_unit.h>
640 #endif
641 
642 template<typename T>
643 inline T*& copyof(const T* const_data, size_t elemsize, size_t elements) { // @@@ elemsize should be derived from type here (if possible)
644  static T *copy = NULp;
645 
646  size_t memsize = elemsize*elements;
647  id_assert(!copy);
648  copy = (T*)ARB_alloc<char>(memsize);
649  id_assert(copy);
650  memcpy(copy, const_data, memsize);
651  return copy;
652 }
653 
654 #define COPYOF(typedarray) copyof(typedarray, sizeof(*(typedarray)), ARRAY_ELEMS(typedarray))
655 #define SIZEOF(typedarray) (sizeof(*(typedarray))*ARRAY_ELEMS(typedarray))
656 
657 #define TEST_EXPECT_COPIES_EQUAL(d1,d2) do{ \
658  size_t s1 = (d1)->memsize(); \
659  size_t s2 = (d2)->memsize(); \
660  TEST_EXPECT_EQUAL(s1, s2); \
661  void *copy1 = ARB_alloc<char>(s1+s2); \
662  void *copy2 = reinterpret_cast<char*>(copy1)+s1; \
663  (d1)->copyTo(copy1); \
664  (d2)->copyTo(copy2); \
665  TEST_EXPECT_MEM_EQUAL(copy1, copy2, s1); \
666  free(copy1); \
667  }while(0)
668 
669 #define TEST_EXPECT_COPY_EQUALS_ARRAY(adp,typedarray,asize) do{ \
670  size_t size = (adp)->memsize(); \
671  TEST_EXPECT_EQUAL(size, asize); \
672  void *ad_copy = ARB_alloc<char*>(size); \
673  (adp)->copyTo(ad_copy); \
674  TEST_EXPECT_MEM_EQUAL(ad_copy, typedarray, size); \
675  free(ad_copy); \
676  }while(0)
677 
678 #define TEST_EXPECT_COPY_EQUALS_STRING(adp,str) do{ \
679  size_t size = (adp)->memsize(); \
680  char *ad_copy = ARB_alloc<char>(size+1); \
681  (adp)->copyTo(ad_copy); \
682  ad_copy[size] = 0; \
683  TEST_EXPECT_EQUAL(ad_copy, str); \
684  free(ad_copy); \
685  }while(0)
686 
687 #if defined(ENABLE_CRASH_TESTS) && defined(ASSERTION_USED)
688 static void illegal_alidata_composition() {
689  const int ELEMS = 5;
690 
691  int *i = ARB_alloc<int> (ELEMS);
692  char *c = ARB_alloc<char>(ELEMS);
693 
694  concat(makeAliData(i, ELEMS, 0), makeAliData(c, ELEMS, '-'));
695 }
696 #endif
697 
698 void TEST_illegal_alidata__crashtest() {
699  TEST_EXPECT_CODE_ASSERTION_FAILS(illegal_alidata_composition);
700 }
701 
702 template <typename T>
703 inline T *makeCopy(AliDataPtr d) {
704  TEST_EXPECT_EQUAL(d->unitsize(), sizeof(T));
705  size_t size = d->memsize();
706  T *copy = (T*)ARB_alloc<char>(size);
707  d->copyTo(copy);
708  return copy;
709 }
710 
711 template <typename T>
712 static arb_test::match_expectation compare_works(AliDataPtr d1, AliDataPtr d2, int expected_cmp) {
713  int brute_force_compare = 0;
714  {
715  int minSize = std::min(d1->elems(), d2->elems());
716 
717  T *copy1 = makeCopy<T>(d1);
718  T *copy2 = makeCopy<T>(d2);
719 
720  for (int i = 0; i < minSize && brute_force_compare == 0; ++i) { // compare inclusive terminal zero-element
721  brute_force_compare = compare_type(copy1[i], copy2[i]);
722  }
723 
724  if (brute_force_compare == 0) {
725  brute_force_compare = compare_type(d1->elems(), d2->elems());
726  }
727 
728  free(copy2);
729  free(copy1);
730  }
731 
732  int smart_forward_compare = d1->cmp_whole_data(*d2);
733  int smart_backward_compare = d2->cmp_whole_data(*d1);
734 
735  using namespace arb_test;
736  expectation_group expected;
737 
738  expected.add(that(brute_force_compare).is_equal_to(expected_cmp));
739  expected.add(that(smart_forward_compare).is_equal_to(expected_cmp));
740  expected.add(that(smart_backward_compare).is_equal_to(-expected_cmp));
741 
742  return all().ofgroup(expected);
743 }
744 
745 #define TEST_COMPARE_WORKS(d1,d2,expected) TEST_EXPECTATION(compare_works<char>(d1,d2,expected))
746 
747 #define TEST_COMPARE_WORKS_ALL_TYPES(tid,d1,d2,expected) \
748  switch (tid) { \
749  case 0: TEST_EXPECTATION(compare_works<char>(d1,d2,expected)); break; \
750  case 1: TEST_EXPECTATION(compare_works<GB_UINT4>(d1,d2,expected)); break; \
751  case 2: TEST_EXPECTATION(compare_works<float>(d1,d2,expected)); break; \
752  }
753 
754 #if !defined(ENABLE_CRASH_TESTS)
755 static void avoid_INVALID_testExport() { avoid_INVALID_testExport(); } // avoids weird symbol-export-bug with stabs + !ENABLE_CRASH_TESTS (encountered with gcc 4.4.3)
756 #endif
757 
758 __ATTR__REDUCED_OPTIMIZE void TEST_AliData() {
759 #define SEQDATA "CGCAC-C-GG-C-GG.A.-C------GG-.C..UCAGU"
760  char chr_src[] = SEQDATA; // also contains trailing 0-byte!
761  GB_CUINT4 int_src[] = { 0x01, 0x1213, 0x242526, 0x37383930, 0xffffffff };
762  float flt_src[] = { 0.0, 0.5, 1.0, -5.0, 20.1 };
763 
764  AliDataPtr type[] = {
765  makeAliSeqData(COPYOF(chr_src), ARRAY_ELEMS(chr_src)-1, '-', '.'),
766  makeAliData(COPYOF(int_src), ARRAY_ELEMS(int_src), 0U),
767  makeAliData(COPYOF(flt_src), ARRAY_ELEMS(flt_src), 0.0F)
768  };
769  TEST_EXPECT_COPY_EQUALS_ARRAY(type[0], chr_src, SIZEOF(chr_src)-1);
770  TEST_EXPECT_COPY_EQUALS_STRING(type[0], chr_src);
771  TEST_EXPECT_COPY_EQUALS_ARRAY(type[1], int_src, SIZEOF(int_src));
772  TEST_EXPECT_COPY_EQUALS_ARRAY(type[2], flt_src, SIZEOF(flt_src));
773 
774  for (size_t t = 0; t<ARRAY_ELEMS(type); ++t) {
775  AliDataPtr data = type[t];
776  AliDataPtr dup = concat(data, data);
777  TEST_EXPECT_EQUAL(dup->elems(), 2*data->elems());
778 
779  AliDataPtr start = before(data, 3);
780  TEST_EXPECT_EQUAL(start->elems(), 3U);
781 
782  AliDataPtr end = after(data, 3);
783  TEST_EXPECT_EQUAL(end->elems(), data->elems()-4);
784 
785  AliDataPtr mid = partof(data, 3, 1);
786  TEST_EXPECT_COPIES_EQUAL(concat(start, mid, end), data);
787 
788  GB_ERROR error = NULp;
789  AliDataPtr del = delete_from(data, 3, 1, error);
790  TEST_EXPECT_NO_ERROR(error);
791  TEST_EXPECT_EQUAL(del->elems(), data->elems()-1);
792  TEST_EXPECT_COPIES_EQUAL(concat(start, end), del);
793 
794  AliDataPtr empty = before(data, 0);
795  TEST_EXPECT_EQUAL(empty->elems(), 0U);
796 
797  TEST_EXPECT_COPIES_EQUAL(data, concat(data, empty));
798  TEST_EXPECT_COPIES_EQUAL(data, concat(empty, data));
799  TEST_EXPECT_COPIES_EQUAL(empty, concat(empty, empty));
800 
801  AliDataPtr del_rest = delete_from(data, 3, 999, error);
802  TEST_EXPECT_NO_ERROR(error);
803  TEST_EXPECT_COPIES_EQUAL(start, del_rest);
804 
805  AliDataPtr ins = insert_at(del, 3, mid);
806  TEST_EXPECT_COPIES_EQUAL(data, ins);
807  TEST_EXPECT_COPIES_EQUAL(del, delete_from(ins, 3, 1, error));
808  TEST_EXPECT_NO_ERROR(error);
809 
810  TEST_EXPECT_COPIES_EQUAL(insert_at(del, 3, empty), del);
811  TEST_EXPECT_COPIES_EQUAL(insert_at(del, 777, empty), del); // append via insert_at
812  TEST_EXPECT_COPIES_EQUAL(insert_at(start, 777, end), del); // append via insert_at
813 
814  AliDataPtr ins_gap = insert_gap(del, 4, 5);
815  TEST_EXPECT_EQUAL(ins_gap->elems(), del->elems()+5);
816 
817  AliDataPtr gap_iseq = partof(ins_gap, 4, 5);
818 
819  TEST_EXPECT_COPIES_EQUAL(ins_gap, insert_gap(ins_gap, 7, 0)); // insert empty gap
820 
821  AliDataPtr start_gap1 = insert_gap(ins_gap, 0, 1); // insert gap at start
822  AliDataPtr start_gap3 = insert_gap(ins_gap, 0, 3); // insert gap at start
823 
824  AliDataPtr gap_iempty = insert_gap(empty, 0, 5);
825  TEST_EXPECT_EQUAL(gap_iempty->elems(), 5U);
826 
827  AliDataPtr gap_in_gap = insert_gap(gap_iempty, 3, 2);
828  TEST_EXPECT_EQUAL(gap_in_gap->elems(), 7U);
829 
830  AliDataPtr end_gap1 = insert_gap(mid, 1, 1);
831  TEST_EXPECT_EQUAL(end_gap1->elems(), 2U);
832 
833  if (t == 0) {
834  AliDataPtr end_gap2 = insert_gap(end, 34, 2);
835 
836  TEST_EXPECT_COPY_EQUALS_STRING(start, "CGC");
837  TEST_EXPECT_COPY_EQUALS_STRING(end, "C-C-GG-C-GG.A.-C------GG-.C..UCAGU");
838  TEST_EXPECT_COPY_EQUALS_STRING(end_gap2, "C-C-GG-C-GG.A.-C------GG-.C..UCAGU..");
839  TEST_EXPECT_COPY_EQUALS_STRING(mid, "A");
840  TEST_EXPECT_COPY_EQUALS_STRING(end_gap1, "A-"); // '-' is ok, since before there was a C behind (but correct would be '.')
841  TEST_EXPECT_COPY_EQUALS_STRING(del, "CGCC-C-GG-C-GG.A.-C------GG-.C..UCAGU");
842  TEST_EXPECT_COPY_EQUALS_STRING(del_rest, "CGC");
843  TEST_EXPECT_COPY_EQUALS_STRING(ins, "CGCAC-C-GG-C-GG.A.-C------GG-.C..UCAGU");
844  TEST_EXPECT_COPY_EQUALS_STRING(gap_iseq, "-----"); // inserted between bases
845  TEST_EXPECT_COPY_EQUALS_STRING(gap_iempty, "....."); // inserted in empty sequence
846  TEST_EXPECT_COPY_EQUALS_STRING(gap_in_gap, "......."); // inserted gap in gap
847  TEST_EXPECT_COPY_EQUALS_STRING(ins_gap, "CGCC------C-GG-C-GG.A.-C------GG-.C..UCAGU");
848  TEST_EXPECT_COPY_EQUALS_STRING(start_gap1, ".CGCC------C-GG-C-GG.A.-C------GG-.C..UCAGU");
849  TEST_EXPECT_COPY_EQUALS_STRING(start_gap3, "...CGCC------C-GG-C-GG.A.-C------GG-.C..UCAGU");
850 
851  AliDataPtr bef_dot = insert_gap(ins, 15, 2);
852  AliDataPtr aft_dot = insert_gap(ins, 16, 2);
853  AliDataPtr bet_dots = insert_gap(ins, 32, 2);
854  AliDataPtr bet_dashes = insert_gap(ins, 23, 2);
855  AliDataPtr bet_dashdot = insert_gap(ins, 29, 2);
856  AliDataPtr bet_dotdash = insert_gap(ins, 18, 2);
857 
858  TEST_EXPECT_COPY_EQUALS_STRING(ins, "CGCAC-C-GG-C-GG.A.-C------GG-.C..UCAGU");
859  TEST_EXPECT_COPY_EQUALS_STRING(bef_dot, "CGCAC-C-GG-C-GG...A.-C------GG-.C..UCAGU");
860  TEST_EXPECT_COPY_EQUALS_STRING(aft_dot, "CGCAC-C-GG-C-GG...A.-C------GG-.C..UCAGU");
861  TEST_EXPECT_COPY_EQUALS_STRING(bet_dots, "CGCAC-C-GG-C-GG.A.-C------GG-.C....UCAGU");
862  TEST_EXPECT_COPY_EQUALS_STRING(bet_dashes, "CGCAC-C-GG-C-GG.A.-C--------GG-.C..UCAGU");
863  TEST_EXPECT_COPY_EQUALS_STRING(bet_dashdot,"CGCAC-C-GG-C-GG.A.-C------GG---.C..UCAGU");
864  TEST_EXPECT_COPY_EQUALS_STRING(bet_dotdash,"CGCAC-C-GG-C-GG.A.---C------GG-.C..UCAGU");
865 
866  {
867  // test comparability of AliData
868 
869  AliDataPtr same_as_start_gap1 = after(start_gap3, 1);
870 
871  TEST_COMPARE_WORKS(start_gap1, same_as_start_gap1, 0);
872 
873  TEST_EXPECT(start_gap1->differs_from(*start_gap3));
874  // TEST_EXPECT_EQUAL(strcmp(".CGCC------C-GG-C-GG.A.-C------GG-.C..UCAGU", // start_gap1
875  // "...CGCC------C-GG-C-GG.A.-C------GG-.C..UCAGU"), 1); // start_gap3
876 
877  TEST_EXPECT_EQUAL(start_gap1->cmp_whole_data(*start_gap3), 1);
878  TEST_EXPECT_EQUAL(start_gap3->cmp_whole_data(*start_gap1), -1);
879 
880  TEST_COMPARE_WORKS(end, end_gap2, -1);
881  }
882  }
883 
884  {
885  // test comparability of AliData (for all types)
886 
887  TEST_COMPARE_WORKS_ALL_TYPES(t, start_gap1, start_gap3, 1);
888  TEST_COMPARE_WORKS_ALL_TYPES(t, gap_iempty, gap_in_gap, -1);
889  TEST_COMPARE_WORKS_ALL_TYPES(t, del, ins, 1);
890  TEST_COMPARE_WORKS_ALL_TYPES(t, partof(ins_gap, 0, 17), partof(start_gap3, 3, 17), 0);
891  TEST_COMPARE_WORKS_ALL_TYPES(t, start_gap3, start_gap3, 0);
892  }
893  }
894 
895 }
896 
897 #endif // UNIT_TESTS
898 
899 // --------------------------------------------------------------------------------
900 
905 };
906 
908  "Species",
909  "SAI",
910  "SeceditStruct",
911 };
912 
913 class Alignment {
914  SmartCharPtr name; // name of alignment
915  size_t len; // length of alignment
916 public:
917  Alignment(const char *name_, size_t len_) : name(strdup(name_)), len(len_) {}
918 
919  const char *get_name() const { return &*name; }
920  size_t get_len() const { return len; }
921 };
922 
923 // --------------------------------------------------------------------------------
924 
925 class AliApplicable { // something that can be appied to the whole alignment
926  virtual GB_ERROR apply_to_terminal(GBDATA *gb_data, TerminalType term_type, const char *item_name, const Alignment& ali) const = 0;
927 
928  GB_ERROR apply_recursive(GBDATA *gb_data, TerminalType term_type, const char *item_name, const Alignment& ali) const;
929  GB_ERROR apply_to_childs_named(GBDATA *gb_item_data, const char *item_field, TerminalType term_type, const Alignment& ali) const;
930  GB_ERROR apply_to_secstructs(GBDATA *gb_secstructs, const Alignment& ali) const;
931 
932 public:
934  virtual ~AliApplicable() {}
935 
936  GB_ERROR apply_to_alignment(GBDATA *gb_main, const Alignment& ali) const;
937 };
938 
939 GB_ERROR AliApplicable::apply_recursive(GBDATA *gb_data, TerminalType term_type, const char *item_name, const Alignment& ali) const {
940  GB_ERROR error = NULp;
941  GB_TYPES type = GB_read_type(gb_data);
942 
943  if (type == GB_DB) {
944  GBDATA *gb_child;
945  for (gb_child = GB_child(gb_data); gb_child && !error; gb_child = GB_nextChild(gb_child)) {
946  error = apply_recursive(gb_child, term_type, item_name, ali);
947  }
948  }
949  else {
950  error = apply_to_terminal(gb_data, term_type, item_name, ali);
951  }
952 
953  return error;
954 }
955 GB_ERROR AliApplicable::apply_to_childs_named(GBDATA *gb_item_data, const char *item_field, TerminalType term_type, const Alignment& ali) const {
956  GBDATA *gb_item;
957  GB_ERROR error = NULp;
958  long item_count = GB_number_of_subentries(gb_item_data);
959 
960  if (item_count) {
961  for (gb_item = GB_entry(gb_item_data, item_field);
962  gb_item && !error;
963  gb_item = GB_nextEntry(gb_item))
964  {
965  GBDATA *gb_ali = GB_entry(gb_item, ali.get_name());
966  if (gb_ali) {
967  char *item_name = ARB_strdup(GBT_get_name_or_description(gb_item));
968  error = apply_recursive(gb_ali, term_type, item_name, ali);
969  if (error) error = GBS_global_string("%s '%s': %s", targetTypeName[term_type], item_name, error);
970  free(item_name);
971  }
972  }
973  }
974  return error;
975 }
976 GB_ERROR AliApplicable::apply_to_secstructs(GBDATA *gb_secstructs, const Alignment& ali) const {
977  GB_ERROR error = NULp;
978  GBDATA *gb_ali = GB_entry(gb_secstructs, ali.get_name());
979 
980  if (gb_ali) {
981  long item_count = GB_number_of_subentries(gb_ali)-1;
982  if (item_count<1) item_count = 1;
983 
984  GBDATA *gb_item;
985  for (gb_item = GB_entry(gb_ali, "struct");
986  gb_item && !error;
987  gb_item = GB_nextEntry(gb_item))
988  {
989  GBDATA *gb_ref = GB_entry(gb_item, "ref");
990  if (gb_ref) {
991  error = apply_recursive(gb_ref, IDT_SECSTRUCT, "ref", ali);
992  if (error) {
993  const char *item_name = GBT_get_name_or_description(gb_item);
994  error = GBS_global_string("%s '%s': %s", targetTypeName[IDT_SECSTRUCT], item_name, error);
995  }
996  }
997  }
998  }
999  return error;
1000 }
1001 
1003  GB_ERROR error = apply_to_childs_named(GBT_find_or_create(gb_main, "extended_data", 7), "extended", IDT_SAI, ali);
1004  if (!error) error = apply_to_secstructs(GB_search(gb_main, "secedit/structs", GB_CREATE_CONTAINER), ali);
1005  if (!error) error = apply_to_childs_named(GBT_find_or_create(gb_main, "species_data", 7), "species", IDT_SPECIES, ali);
1006  return error;
1007 }
1008 
1009 // --------------------------------------------------------------------------------
1010 
1012  mutable size_t count;
1013  GB_ERROR apply_to_terminal(GBDATA *, TerminalType, const char *, const Alignment&) const OVERRIDE { count++; return NULp; }
1014 public:
1015  AliEntryCounter() : count(0) {}
1016  size_t get_entry_count() const { return count; }
1017 };
1018 
1019 // --------------------------------------------------------------------------------
1020 
1022  virtual ~AliEditCommand() {}
1023  virtual AliDataPtr apply(AliDataPtr to, GB_ERROR& error) const = 0;
1024  virtual GB_ERROR check_applicable_to(const Alignment& ali, size_t& resulting_ali_length) const = 0;
1025 };
1026 
1028  size_t pos; // inserts in front of pos
1029  size_t amount;
1030 public:
1031  AliInsertCommand(size_t pos_, size_t amount_) : pos(pos_), amount(amount_) {}
1032  AliDataPtr apply(AliDataPtr to, GB_ERROR& /*error*/) const OVERRIDE { return insert_gap(to, pos, amount); }
1033  GB_ERROR check_applicable_to(const Alignment& ali, size_t& resulting_ali_length) const OVERRIDE {
1034  size_t len = ali.get_len();
1035  if (pos>len) {
1036  return GBS_global_string("Can't insert at position %zu (exceeds length %zu of alignment '%s')",
1037  pos, len, ali.get_name());
1038  }
1039  resulting_ali_length = len+amount;
1040  return NULp;
1041  }
1042 };
1043 
1045  size_t pos;
1046  size_t amount;
1047 public:
1048  AliDeleteCommand(size_t pos_, size_t amount_)
1049  : pos(pos_),
1050  amount(amount_)
1051  {}
1052  AliDataPtr apply(AliDataPtr to, GB_ERROR& error) const OVERRIDE { return delete_from(to, pos, amount, error); }
1053  GB_ERROR check_applicable_to(const Alignment& ali, size_t& resulting_ali_length) const OVERRIDE {
1054  size_t len = ali.get_len();
1055  size_t end_pos = pos+amount-1;
1056  if (end_pos >= len) {
1057  return GBS_global_string("Can't delete positions %zu-%zu (exceeds max. position %zu of alignment '%s')",
1058  pos, end_pos, len-1, ali.get_name());
1059  }
1060  resulting_ali_length = len-amount;
1061  return NULp;
1062  }
1063 };
1064 
1065 class AliFormatCommand FINAL_TYPE : public AliEditCommand {
1066  size_t wanted_len;
1067 
1068 public:
1069  AliFormatCommand(size_t wanted_len_) : wanted_len(wanted_len_) {}
1071  SizeAwarable *knows_size = dynamic_cast<SizeAwarable*>(&*to);
1072 
1073  id_assert(knows_size); // format can only be applied to SpecificAliData
1074  // i.e. AliFormatCommand has to be the FIRST of a series of applied commands!
1075 
1076  int allowed_size = knows_size->get_allowed_size(to->elems(), wanted_len);
1077  return format(to, allowed_size, error);
1078  }
1079  GB_ERROR check_applicable_to(const Alignment& IF_ASSERTION_USED(ali), size_t& resulting_ali_length) const OVERRIDE {
1080  id_assert(ali.get_len() == wanted_len);
1081  resulting_ali_length = wanted_len;
1082  return NULp;
1083  }
1084 };
1085 
1087  mutable SmartPtr<AliFormatCommand> cmd;
1088 public:
1090  return cmd->apply(to, error);
1091  }
1092  GB_ERROR check_applicable_to(const Alignment& ali, size_t& resulting_ali_length) const OVERRIDE {
1093  cmd = new AliFormatCommand(ali.get_len()); // late decision on length to format
1094  return cmd->check_applicable_to(ali, resulting_ali_length);
1095  }
1096 };
1097 
1099  AliEditCommand *first;
1100  AliEditCommand *second;
1101 public:
1102  AliCompositeCommand(AliEditCommand *cmd1_, AliEditCommand *cmd2_) // takes ownership of commands
1103  : first(cmd1_),
1104  second(cmd2_)
1105  {}
1106  ~AliCompositeCommand() OVERRIDE { delete second; delete first; }
1108  AliDataPtr tmp = first->apply(to, error);
1109  if (!error) tmp = second->apply(tmp, error);
1110  return tmp;
1111  }
1112  GB_ERROR check_applicable_to(const Alignment& ali, size_t& resulting_ali_length) const OVERRIDE {
1113  GB_ERROR error = first->check_applicable_to(ali, resulting_ali_length);
1114  if (!error) {
1115  Alignment tmp_ali(ali.get_name(), resulting_ali_length);
1116  error = second->check_applicable_to(tmp_ali, resulting_ali_length);
1117  }
1118  return error;
1119  }
1120 };
1121 
1122 // --------------------------------------------------------------------------------
1123 
1124 class AliEditor : public AliApplicable {
1125  const AliEditCommand& cmd;
1126  Deletable deletable;
1127 
1128  mutable arb_progress progress;
1129  mutable size_t modified_counter;
1130 
1131  GB_ERROR apply_to_terminal(GBDATA *gb_data, TerminalType term_type, const char *item_name, const Alignment& ali) const OVERRIDE;
1132 
1133  bool shall_edit(GBDATA *gb_data, TerminalType term_type) const {
1134  // defines whether specific DB-elements shall be edited by any AliEditor
1135  // (true for all data, that contains alignment position specific data)
1136 
1137  const char *key = GB_read_key_pntr(gb_data);
1138  bool shall = key[0] != '_'; // general case: don't apply to keys starting with '_'
1139  if (!shall) shall = term_type == IDT_SAI && strcmp(key, "_REF") == 0; // exception (SAI:_REF needs editing)
1140  return shall;
1141  }
1142 
1143 public:
1144  AliEditor(const AliEditCommand& cmd_, const Deletable& deletable_, const char *progress_title, size_t progress_count)
1145  : cmd(cmd_),
1146  deletable(deletable_),
1147  progress(progress_title, progress_count),
1148  modified_counter(0)
1149  {}
1150  ~AliEditor() OVERRIDE {
1151  progress.done();
1152  }
1153 
1154  const AliEditCommand& edit_command() const { return cmd; }
1155 };
1156 
1157 // --------------------------------------------------------------------------------
1158 
1159 static char *insDelBuffer = NULp;
1160 static size_t insDelBuffer_size;
1161 
1162 inline void free_insDelBuffer() {
1163  freenull(insDelBuffer);
1164 }
1165 inline char *provide_insDelBuffer(size_t neededSpace) {
1166  if (insDelBuffer && insDelBuffer_size<neededSpace) free_insDelBuffer();
1167  if (!insDelBuffer) {
1168  insDelBuffer_size = neededSpace+10;
1169  insDelBuffer = ARB_alloc<char>(insDelBuffer_size);
1170  }
1171  return insDelBuffer;
1172 }
1173 
1174 inline GB_CSTR alidata2buffer(const AliData& data) { // @@@ DRY vs copying code (above in this file)
1175  char *buffer = provide_insDelBuffer(data.memsize()+1);
1176 
1177  data.copyTo(buffer);
1178  buffer[data.memsize()] = 0; // only needed for strings but does not harm otherwise
1179 
1180  return buffer;
1181 }
1182 
1183 // --------------------------------------------------------------------------------
1184 
1185 class EditedTerminal;
1186 
1187 class LazyAliData : public AliData, public SizeAwarable, virtual Noncopyable {
1188  // internally transforms into SpecificAliData as soon as somebody tries to access the data.
1189  // (implements lazy loading of sequence data, esp. useful when applying AliFormatCommand; see #702)
1190 
1191  TerminalType term_type;
1192  EditedTerminal& terminal;
1193  mutable AliDataPtr loaded; // always is TypedAliData<T>
1194 
1195  AliDataPtr loaded_data() const {
1196  if (loaded.isNull()) load_data();
1197  return loaded;
1198  }
1199 
1200 public:
1201  LazyAliData(const SizeAwarable& oversizable, size_t size_, TerminalType term_type_, EditedTerminal& terminal_)
1202  : AliData(size_),
1203  SizeAwarable(oversizable),
1204  term_type(term_type_),
1205  terminal(terminal_)
1206  {}
1207 
1208  size_t unitsize() const OVERRIDE {
1209  // Note: information also known by EditedTerminal (only depends on data-type)
1210  // No need to load data (doesnt harm atm as data is always used for more atm)
1211  return loaded_data()->unitsize();
1212  }
1213  bool has_slice() const OVERRIDE {
1214  id_assert(loaded_data()->has_slice() == false); // TypedAliData<T> never has_slice()!
1215  return false;
1216  }
1217 
1218  int operate_on_mem(void *mem, size_t start, size_t count, memop op) const OVERRIDE { return loaded_data()->operate_on_mem(mem, start, count, op); }
1219  int cmp_data(size_t start, const AliData& other, size_t ostart, size_t count) const OVERRIDE { return loaded_data()->cmp_data(start, other, ostart, count); }
1220 
1221  UnitPtr unit_left_of(size_t pos) const OVERRIDE { return loaded_data()->unit_left_of(pos); }
1222  UnitPtr unit_right_of(size_t pos) const OVERRIDE { return loaded_data()->unit_right_of(pos); }
1223 
1224  AliDataPtr create_gap(size_t gapsize, const UnitPair& gapinfo) const OVERRIDE { return loaded_data()->create_gap(gapsize, gapinfo); }
1225  __ATTR__NORETURN AliDataPtr slice_down(size_t /*start*/, size_t /*count*/) const OVERRIDE {
1226  GBK_terminate("logic error: slice_down called for explicit LazyAliData");
1227  }
1228 
1229  void load_data() const; // has to be public to be a friend of EditedTerminal
1230 };
1231 
1232 // --------------------------------------------------------------------------------
1233 
1234 class EditedTerminal : virtual Noncopyable {
1235  GBDATA *gb_data;
1236  GB_TYPES type;
1237  const char *item_name; // name of SAI/species etc
1238  AliDataPtr data;
1239  Deletable deletable;
1240  GB_ERROR error;
1241 
1242  bool has_key(const char *expected_key) const {
1243  return strcmp(GB_read_key_pntr(gb_data), expected_key) == 0;
1244  }
1245  bool has_name(const char *expected_name) const {
1246  return strcmp(item_name, expected_name) == 0;
1247  }
1248 
1249  bool is_ref(TerminalType term_type) const {
1250  return
1251  type == GB_STRING &&
1252  ((term_type == IDT_SECSTRUCT && has_key("ref")) ||
1253  (term_type == IDT_SAI && has_key("_REF")));
1254  }
1255  bool is_helix(TerminalType term_type) const {
1256  return
1257  type == GB_STRING &&
1258  term_type == IDT_SAI &&
1259  (has_name("HELIX") || has_name("HELIX_NR")) &&
1260  has_key("data");
1261  }
1262 
1263  bool does_allow_oversize(TerminalType term_type) const { return is_ref(term_type); }
1264  char get_std_string_gaptype(TerminalType term_type) const {
1265  bool prefers_dots = is_ref(term_type) || is_helix(term_type);
1266  return prefers_dots ? '.' : '-';
1267  }
1268 
1269  AliDataPtr load_data(const SizeAwarable& oversizable, size_t size_, TerminalType term_type) {
1270  switch(type) {
1271  case GB_STRING: {
1272  const char *s = GB_read_char_pntr(gb_data);
1273  if (!s) error = GB_await_error();
1274  else {
1275  char stdgap = get_std_string_gaptype(term_type);
1276  if (stdgap == '.') data = new SpecificAliData<char>(s, size_, '.', oversizable, deletable);
1277  else data = new SequenceAliData(s, size_, stdgap, '.', oversizable, deletable);
1278  }
1279  break;
1280  }
1281  case GB_BITS: {
1282  const char *b = GB_read_bits_pntr(gb_data, '-', '+');
1283  if (!b) error = GB_await_error();
1284  else data = new SpecificAliData<char>(b, size_, '-', oversizable, deletable);
1285  break;
1286  }
1287  case GB_BYTES: {
1288  const char *b = GB_read_bytes_pntr(gb_data);
1289  if (!b) error = GB_await_error();
1290  else data = new SpecificAliData<char>(b, size_, 0, oversizable, deletable);
1291  break;
1292  }
1293  case GB_INTS: {
1294  const GB_UINT4 *ui = GB_read_ints_pntr(gb_data);
1295  if (!ui) error = GB_await_error();
1296  else data = new SpecificAliData<GB_UINT4>(ui, size_, 0, oversizable, deletable);
1297  break;
1298  }
1299  case GB_FLOATS: {
1300  const float *f = GB_read_floats_pntr(gb_data);
1301  if (!f) error = GB_await_error();
1302  else data = new SpecificAliData<float>(f, size_, 0.0, oversizable, deletable);
1303  break;
1304  }
1305 
1306  default:
1307  error = GBS_global_string("Unhandled type '%i'", type);
1308  id_assert(0);
1309  break;
1310  }
1311 
1312  id_assert(implicated(!error, size_ == data->elems()));
1313  return data;
1314  }
1315 
1316  friend void LazyAliData::load_data() const;
1317 
1318 public:
1319  EditedTerminal(GBDATA *gb_data_, GB_TYPES type_, const char *item_name_, size_t size_, TerminalType term_type, const Alignment& ali, const Deletable& deletable_)
1320  : gb_data(gb_data_),
1321  type(type_),
1322  item_name(item_name_),
1323  deletable(deletable_),
1324  error(NULp)
1325  {
1326  SizeAwarable oversizable(does_allow_oversize(term_type), ali.get_len());
1327  data = new LazyAliData(oversizable, size_, term_type, *this);
1328  }
1329 
1330  GB_ERROR apply(const AliEditCommand& cmd, bool& did_modify) {
1331  did_modify = false;
1332  if (!error) {
1333  AliDataPtr modified_data = cmd.apply(data, error);
1334 
1335  if (!error && modified_data->differs_from(*data)) {
1336  GB_CSTR modified = alidata2buffer(*modified_data);
1337  size_t modified_elems = modified_data->elems();
1338 
1339  switch (type) {
1340  case GB_STRING: {
1341  id_assert(strlen(modified) == modified_elems);
1342  error = GB_write_string(gb_data, modified);
1343  break;
1344  }
1345  case GB_BITS: error = GB_write_bits (gb_data, modified, modified_elems, "-"); break;
1346  case GB_BYTES: error = GB_write_bytes (gb_data, modified, modified_elems); break;
1347  case GB_INTS: error = GB_write_ints (gb_data, (GB_UINT4*)modified, modified_elems); break;
1348  case GB_FLOATS: error = GB_write_floats(gb_data, (float*)modified, modified_elems); break;
1349 
1350  default: id_assert(0); break;
1351  }
1352 
1353  if (!error) did_modify = true;
1354  }
1355  }
1356  return error;
1357  }
1358 };
1359 
1361  loaded = terminal.load_data(*this, elems(), term_type);
1362 }
1363 
1364 GB_ERROR AliEditor::apply_to_terminal(GBDATA *gb_data, TerminalType term_type, const char *item_name, const Alignment& ali) const {
1365  GB_TYPES gbtype = GB_read_type(gb_data);
1366  GB_ERROR error = NULp;
1367  if (gbtype >= GB_BITS && gbtype != GB_OBSOLETE) {
1368  if (shall_edit(gb_data, term_type)) {
1369  EditedTerminal edited(gb_data, gbtype, item_name, GB_read_count(gb_data), term_type, ali, deletable);
1370 
1371  bool terminal_was_modified;
1372  error = edited.apply(edit_command(), terminal_was_modified);
1373  if (terminal_was_modified) {
1374  progress.subtitle(GBS_global_string("modified: %zu", ++modified_counter));
1375  }
1376  }
1377  }
1378  progress.inc_and_check_user_abort(error);
1379  return error;
1380 }
1381 
1382 // --------------------------------------------------------------------------------
1383 
1384 static size_t countAffectedEntries(GBDATA *Main, const Alignment& ali) {
1386  counter.apply_to_alignment(Main, ali);
1387  return counter.get_entry_count();
1388 }
1389 
1390 static GB_ERROR apply_command_to_alignment(const AliEditCommand& cmd, const char *cmd_description, GBDATA *Main, const char *alignment_name, const char *deletable_chars) {
1391  // applies 'cmd' to one or all alignments
1392  // (if 'alignment_name' is NULp, all alignments are affected - probably useless case)
1393  //
1394  // 'deletable_chars' is either
1395  // - NULp -> nothing may be deleted
1396  // - "%" -> anything may be deleted
1397  // - or a string containing all deletable characters
1398 
1399  Deletable deletable =
1400  deletable_chars
1401  ? ( strchr(deletable_chars, '%')
1403  : Deletable(deletable_chars))
1404  : Deletable(Deletable::NOTHING);
1405 
1406  GB_ERROR error = NULp;
1407  GBDATA *gb_presets = GBT_get_presets(Main);
1408 
1409  for (GBDATA *gb_ali = GB_entry(gb_presets, "alignment");
1410  gb_ali && !error;
1411  gb_ali = GB_nextEntry(gb_ali))
1412  {
1413  GBDATA *gb_name = GB_find_string(gb_ali, "alignment_name", alignment_name, GB_IGNORE_CASE, SEARCH_CHILD);
1414 
1415  if (gb_name) {
1416  GBDATA *gb_len = GB_entry(gb_ali, "alignment_len");
1417  Alignment ali(GB_read_char_pntr(gb_name), GB_read_int(gb_len));
1418 
1419  size_t resulting_ali_length;
1420  error = cmd.check_applicable_to(ali, resulting_ali_length);
1421 
1422  if (!error) error = AliEditor(cmd, deletable, cmd_description, countAffectedEntries(Main, ali)).apply_to_alignment(Main, ali);
1423  if (!error) error = GB_write_int(gb_len, resulting_ali_length);
1424  }
1425  }
1426 
1428 
1429  if (!error) GB_disable_quicksave(Main, "a lot of sequences changed"); // @@@ only disable if a reasonable amount of sequences has changed!
1430 
1431  return error;
1432 }
1433 
1434 static GB_ERROR format_to_alilen(GBDATA *Main, const char *alignment_name) { // @@@ inline
1435  AliAutoFormatCommand fcmd;
1436  return apply_command_to_alignment(fcmd, "Formatting alignment", Main, alignment_name, "-.");
1437 }
1438 
1440  GB_ERROR err = NULp;
1441 
1442  if (strcmp(alignment_name, GENOM_ALIGNMENT) != 0) { // NEVER EVER format 'ali_genom'
1443  err = GBT_check_data(Main, alignment_name); // detect max. length
1444  if (!err) err = format_to_alilen(Main, alignment_name); // format sequences in alignment
1445  if (!err) err = GBT_check_data(Main, alignment_name); // sets state to "formatted"
1446  }
1447  else {
1448  err = "It's forbidden to format '" GENOM_ALIGNMENT "'!";
1449  }
1450  return err;
1451 }
1452 
1453 GB_ERROR ARB_insdel_columns(GBDATA *Main, const char *alignment_name, long pos, long count, const char *deletable_chars) {
1454  /* if count > 0 insert 'count' characters at pos
1455  * if count < 0 delete pos to pos+|count|
1456  *
1457  * Note: deleting is only performed, if found characters in deleted range are listed in 'deletable_chars'
1458  * otherwise function returns with an error.
1459  * (if 'deletable_chars' contains a '%', any character will be deleted)
1460  *
1461  * This affects all species' and SAIs having data in given 'alignment_name' and
1462  * modifies several data entries found there
1463  * (see shall_edit() for details which fields are affected).
1464  */
1465 
1466  GB_ERROR error = NULp;
1467 
1468  if (pos<0) {
1469  error = GBS_global_string("Illegal sequence position %li", pos);
1470  }
1471  else {
1472  const char *description = NULp;
1473 
1475  if (count<0) {
1476  idcmd = new AliDeleteCommand(pos, -count);
1477  description = "Deleting columns";
1478  }
1479  else {
1480  idcmd = new AliInsertCommand(pos, count);
1481  description = "Inserting columns";
1482  }
1483 
1484  error = apply_command_to_alignment(*idcmd, description, Main, alignment_name, deletable_chars);
1485  }
1486  return error;
1487 }
1488 
1489 // AISC_MKPT_PROMOTE:class RangeList;
1490 // AISC_MKPT_PROMOTE:enum UseRange { RANGES, SINGLE_COLUMNS };
1491 // AISC_MKPT_PROMOTE:enum InsertWhere { INFRONTOF, BEHIND };
1492 
1493 GB_ERROR ARB_delete_columns_using_SAI(GBDATA *Main, const char *alignment_name, const RangeList& ranges, const char *deletable_chars) {
1494  // Deletes all columns defined by 'ranges'
1495  // from all members (SAIs, seqs, ..) of alignment named 'alignment_name'.
1496 
1497  GB_ERROR error;
1498  if (ranges.empty()) {
1499  error = "Done with deleting nothing :)";
1500  }
1501  else {
1502  AliEditCommand *cmd = new AliAutoFormatCommand; // @@@ use SmartPtr (here and in AliCompositeCommand)
1503  for (RangeList::reverse_iterator r = ranges.rbegin(); r != ranges.rend(); ++r) {
1504  cmd = new AliCompositeCommand(cmd, new AliDeleteCommand(r->start(), r->size()));
1505  }
1506  error = apply_command_to_alignment(*cmd, "Deleting columns using SAI", Main, alignment_name, deletable_chars);
1507  delete cmd;
1508  }
1509  return error;
1510 }
1511 
1512 GB_ERROR ARB_insert_columns_using_SAI(GBDATA *Main, const char *alignment_name, const RangeList& ranges, UseRange units, InsertWhere where, size_t amount) {
1513  // Insert 'amount' columns into all members of the alignment named 'alignment_name'.
1514  //
1515  // If units is
1516  // - RANGES, each range
1517  // - SINGLE_COLUMNS, each column of each range
1518  // is handled as a unit.
1519  //
1520  // InsertWhere specifies whether the insertion happens INFRONTOF or BEHIND
1521 
1522  GB_ERROR error;
1523  if (!amount || ranges.empty()) {
1524  error = "Done with inserting no gaps :)";
1525  }
1526  else {
1527  AliEditCommand *cmd = new AliAutoFormatCommand; // @@@ use SmartPtr (here and in AliCompositeCommand)
1528  for (RangeList::reverse_iterator r = ranges.rbegin(); r != ranges.rend(); ++r) {
1529  switch (units) {
1530  case RANGES: {
1531  int pos = 0;
1532  switch (where) {
1533  case INFRONTOF: pos = r->start(); break;
1534  case BEHIND: pos = r->end()+1; break;
1535  }
1536  cmd = new AliCompositeCommand(cmd, new AliInsertCommand(pos, amount));
1537  break;
1538  }
1539  case SINGLE_COLUMNS: {
1540  for (int pos = r->end(); pos >= r->start(); --pos) {
1541  cmd = new AliCompositeCommand(cmd, new AliInsertCommand(where == INFRONTOF ? pos : pos+1, amount));
1542  }
1543  break;
1544  }
1545  }
1546  }
1547  error = apply_command_to_alignment(*cmd, "Inserting columns using SAI", Main, alignment_name, NULp);
1548  delete cmd;
1549  }
1550  return error;
1551 }
1552 
1553 // --------------------------------------------------------------------------------
1554 
1555 #ifdef UNIT_TESTS
1556 #ifndef TEST_UNIT_H
1557 #include <test_unit.h>
1558 #endif
1559 #include <arb_unit_test.h>
1560 
1561 #define PLAIN_APPLY_CMD(str,cmd) \
1562  size_t str_len = strlen(str); \
1563  AliDataPtr data = new SequenceAliData(str, str_len, '-', '.', dontAllowOversize(str_len), Deletable("-.")); \
1564  GB_ERROR error = NULp; \
1565  AliDataPtr mod = cmd.apply(data, error)
1566 
1567 #define APPLY_CMD(str,cmd) \
1568  PLAIN_APPLY_CMD(str, cmd); \
1569  TEST_EXPECT_NO_ERROR(error); \
1570  GB_CSTR res = mod->differs_from(*data) ? alidata2buffer(*mod) : NULp
1571 
1572 #define DO_FORMAT(str,wanted_len) \
1573  AliFormatCommand cmd(wanted_len); \
1574  APPLY_CMD(str, cmd)
1575 
1576 #define DO_INSERT(str,pos,amount) \
1577  AliInsertCommand cmd(pos, amount); \
1578  APPLY_CMD(str, cmd)
1579 
1580 #define DO_FORMAT_AND_INSERT(str,wanted_len,pos,amount) \
1581  AliCompositeCommand cmd(new AliFormatCommand(wanted_len), \
1582  new AliInsertCommand(pos,amount)); \
1583  APPLY_CMD(str, cmd)
1584 
1585 #define DO_DELETE(str,pos,amount) \
1586  AliDeleteCommand cmd(pos, amount); \
1587  APPLY_CMD(str, cmd)
1588 
1589 #define TEST_FORMAT(str,wanted_alilen,expected) do { DO_FORMAT(str,wanted_alilen); TEST_EXPECT_EQUAL(res, expected); } while(0)
1590 #define TEST_FORMAT__BROKEN(str,wanted_alilen,expected) do { DO_FORMAT(str,wanted_alilen); TEST_EXPECT_EQUAL__BROKEN(res, expected); } while(0)
1591 
1592 #define TEST_INSERT(str,pos,amount,expected) do { DO_INSERT(str,pos,amount); TEST_EXPECT_EQUAL(res, expected); } while(0)
1593 #define TEST_INSERT__BROKEN(str,pos,amount,expected) do { DO_INSERT(str,pos,amount); TEST_EXPECT_EQUAL__BROKEN(res, expected); } while(0)
1594 
1595 #define TEST_DELETE(str,pos,amount,expected) do { DO_DELETE(str,pos,amount); TEST_EXPECT_EQUAL(res, expected); } while(0)
1596 #define TEST_DELETE__BROKEN(str,pos,amount,expected) do { DO_DELETE(str,pos,amount); TEST_EXPECT_EQUAL__BROKEN(res, expected); } while(0)
1597 
1598 #define TEST_FORMAT_AND_INSERT(str,wanted_alilen,pos,amount,expected) do { DO_FORMAT_AND_INSERT(str,wanted_alilen,pos,amount); TEST_EXPECT_EQUAL(res, expected); } while(0)
1599 #define TEST_FORMAT_AND_INSERT__BROKEN(str,wanted_alilen,pos,amount,expected) do { DO_FORMAT_AND_INSERT(str,wanted_alilen,pos,amount); TEST_EXPECT_EQUAL__BROKEN(res, expected); } while(0)
1600 
1601 #define TEST_FORMAT_ERROR(str,wanted_alilen,exp_err) do { \
1602  AliFormatCommand cmd(wanted_alilen); \
1603  PLAIN_APPLY_CMD(str, cmd); \
1604  TEST_EXPECT_ERROR_CONTAINS(error, exp_err); \
1605  } while(0)
1606 
1607 #define TEST_DELETE_ERROR(str,pos,amount,exp_err) do { \
1608  AliDeleteCommand cmd(pos, amount); \
1609  PLAIN_APPLY_CMD(str, cmd); \
1610  TEST_EXPECT_ERROR_CONTAINS(error, exp_err); \
1611  } while(0)
1612 
1613 
1614 // --------------------------------------------------------------------------------
1615 
1616 void TEST_format_insert_delete() {
1617  // this test is a bit weird.
1618  //
1619  // originally it was used to test the function gbt_insert_delete, which is gone now.
1620  // now it tests AliFormatCommand, AliInsertCommand, AliDeleteCommand and AliCompositeCommand (but quite implicit).
1621 
1622  const char *UNMODIFIED = NULp;
1623 
1624  TEST_FORMAT("xxx", 5, "xxx..");
1625  TEST_FORMAT(".x.", 5, ".x...");
1626  TEST_FORMAT(".x..", 5, ".x...");
1627  TEST_FORMAT(".x...", 5, UNMODIFIED);
1628 
1629  TEST_FORMAT("xxx--", 3, "xxx");
1630  TEST_FORMAT("xxx..", 3, "xxx");
1631  TEST_FORMAT_ERROR("xxxxx", 3, "You tried to delete 'x' at position 3 -> Operation aborted");
1632  TEST_FORMAT_ERROR("xxx", 0, "You tried to delete 'x' at position 0 -> Operation aborted");
1633 
1634  // insert/delete in the middle
1635  TEST_INSERT("abcde", 3, 0, UNMODIFIED);
1636  TEST_INSERT("abcde", 3, 1, "abc-de");
1637  TEST_INSERT("abcde", 3, 2, "abc--de");
1638 
1639  TEST_DELETE("abcde", 3, 0, UNMODIFIED);
1640  TEST_DELETE("abc-de", 3, 1, "abcde");
1641  TEST_DELETE("abc--de", 3, 2, "abcde");
1642  TEST_DELETE_ERROR("abc-xde", 3, 2, "You tried to delete 'x' at position 4 -> Operation aborted");
1643 
1644  // insert/delete at end
1645  TEST_INSERT("abcde", 5, 1, "abcde.");
1646  TEST_INSERT("abcde", 5, 4, "abcde....");
1647 
1648  TEST_DELETE("abcde-", 5, 1, "abcde");
1649  TEST_DELETE("abcde----", 5, 4, "abcde");
1650 
1651  // insert/delete at start
1652  TEST_INSERT("abcde", 0, 1, ".abcde");
1653  TEST_INSERT("abcde", 0, 4, "....abcde");
1654 
1655  TEST_DELETE("-abcde", 0, 1, "abcde");
1656  TEST_DELETE("----abcde", 0, 4, "abcde");
1657 
1658  // insert behind end
1659  TEST_FORMAT_AND_INSERT("abcde", 10, 8, 1, "abcde......");
1660  TEST_FORMAT_AND_INSERT("abcde", 10, 8, 4, "abcde.........");
1661 
1662  // insert/delete all
1663  TEST_INSERT("", 0, 3, "...");
1664  TEST_DELETE("---", 0, 3, "");
1665 
1667 }
1668 
1669 // ------------------------------
1670 
1671 static struct arb_unit_test::test_alignment_data TADinsdel[] = {
1672  { 1, "MtnK1722", "...G-GGC-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUCACCUCC....." },
1673  { 1, "MhnFormi", "---A-CGA-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUCACCUCCU....." },
1674  { 1, "MhnT1916", "...A-CGA-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUCACCUCCU----" },
1675 };
1676 
1677 static struct arb_unit_test::test_alignment_data EXTinsdel[] = {
1678  { 0, "ECOLI", "---U-GCC-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCCCACCUGA...." },
1679  { 0, "HELIX", ".....[<[.........[..[..[<<.[..].>>]....]..]....].>......]" },
1680  { 0, "HELIX_NR", ".....1.1.........25.25.34..34.34..34...25.25...1........1" },
1681 };
1682 
1683 #define HELIX_REF ".....x..x........x...x.x....x.x....x...x...x...x.........x"
1684 #define HELIX_STRUCT "VERSION=3\nLOOP={etc.pp\n}\n"
1685 
1686 static const char *read_item_entry(GBDATA *gb_item, const char *ali_name, const char *entry_name) {
1687  const char *result = NULp;
1688  if (gb_item) {
1689  GBDATA *gb_ali = GB_find(gb_item, ali_name, SEARCH_CHILD);
1690  if (gb_ali) {
1691  GBDATA *gb_entry = GB_entry(gb_ali, entry_name);
1692  if (gb_entry) {
1693  result = GB_read_char_pntr(gb_entry);
1694  }
1695  }
1696  }
1697  if (!result) TEST_EXPECT_NO_ERROR(GB_await_error());
1698  return result;
1699 }
1700 static char *ints2string(const GB_UINT4 *ints, size_t count) {
1701  char *str = ARB_alloc<char>(count+1);
1702  for (size_t c = 0; c<count; ++c) { // IRRELEVANT_LOOP
1703  str[c] = (ints[c]<10) ? ints[c]+'0' : '?';
1704  }
1705  str[count] = 0;
1706  return str;
1707 }
1708 static GB_UINT4 *string2ints(const char *str, size_t count) {
1709  GB_UINT4 *ints = ARB_alloc<GB_UINT4>(count);
1710  for (size_t c = 0; c<count; ++c) { // IRRELEVANT_LOOP
1711  ints[c] = int(str[c]-'0');
1712  }
1713  return ints;
1714 }
1715 static char *floats2string(const float *floats, size_t count) {
1716  char *str = ARB_alloc<char>(count+1);
1717  for (size_t c = 0; c<count; ++c) { // IRRELEVANT_LOOP
1718  str[c] = char(floats[c]*64.0+0.5)+' '+1;
1719  }
1720  str[count] = 0;
1721  return str;
1722 }
1723 static float *string2floats(const char *str, size_t count) {
1724  float *floats = ARB_alloc<float>(count);
1725  for (size_t c = 0; c<count; ++c) { // IRRELEVANT_LOOP
1726  floats[c] = float(str[c]-' '-1)/64.0;
1727  }
1728  return floats;
1729 }
1730 
1731 static GBDATA *get_ali_entry(GBDATA *gb_item, const char *ali_name, const char *entry_name) {
1732  GBDATA *gb_entry = NULp;
1733  if (gb_item) {
1734  GBDATA *gb_ali = GB_find(gb_item, ali_name, SEARCH_CHILD);
1735  if (gb_ali) gb_entry = GB_entry(gb_ali, entry_name);
1736  }
1737  return gb_entry;
1738 }
1739 
1740 static char *read_item_ints_entry_as_string(GBDATA *gb_item, const char *ali_name, const char *entry_name) {
1741  char *result = NULp;
1742  GBDATA *gb_entry = get_ali_entry(gb_item, ali_name, entry_name);
1743  if (gb_entry) {
1744  GB_UINT4 *ints = GB_read_ints(gb_entry);
1745  result = ints2string(ints, GB_read_count(gb_entry));
1746  free(ints);
1747  }
1748  if (!result) TEST_EXPECT_NO_ERROR(GB_await_error());
1749  return result;
1750 }
1751 static char *read_item_floats_entry_as_string(GBDATA *gb_item, const char *ali_name, const char *entry_name) {
1752  char *result = NULp;
1753  GBDATA *gb_entry = get_ali_entry(gb_item, ali_name, entry_name);
1754  if (gb_entry) {
1755  float *floats = GB_read_floats(gb_entry);
1756  result = floats2string(floats, GB_read_count(gb_entry));
1757  free(floats);
1758  }
1759  if (!result) TEST_EXPECT_NO_ERROR(GB_await_error());
1760  return result;
1761 }
1762 
1763 #define TEST_ITEM_HAS_ENTRY(find,name,ename,expected) \
1764  TEST_EXPECT_EQUAL(read_item_entry(find(gb_main, name), ali_name, ename), expected)
1765 
1766 #define TEST_ITEM_HAS_INTSENTRY(find,name,ename,expected) \
1767  TEST_EXPECT_EQUAL(&*SmartCharPtr(read_item_ints_entry_as_string(find(gb_main, name), ali_name, ename)), expected)
1768 
1769 #define TEST_ITEM_HAS_FLOATSENTRY(find,name,ename,expected) \
1770  TEST_EXPECT_EQUAL(&*SmartCharPtr(read_item_floats_entry_as_string(find(gb_main, name), ali_name, ename)), expected)
1771 
1772 #define TEST_ITEM_HAS_DATA(find,name,expected) TEST_ITEM_HAS_ENTRY(find,name,"data",expected)
1773 
1774 #define TEST_SPECIES_HAS_DATA(ad,sd) TEST_ITEM_HAS_DATA(GBT_find_species,ad.name,sd)
1775 #define TEST_SAI_HAS_DATA(ad,sd) TEST_ITEM_HAS_DATA(GBT_find_SAI,ad.name,sd)
1776 #define TEST_SAI_HAS_ENTRY(ad,ename,sd) TEST_ITEM_HAS_ENTRY(GBT_find_SAI,ad.name,ename,sd)
1777 
1778 #define TEST_SPECIES_HAS_INTS(ad,id) TEST_ITEM_HAS_INTSENTRY(GBT_find_species,ad.name,"NN",id)
1779 #define TEST_SPECIES_HAS_FLOATS(ad,fd) TEST_ITEM_HAS_FLOATSENTRY(GBT_find_species,ad.name,"FF",fd)
1780 
1781 #define TEST_DATA(sd0,sd1,sd2,ed0,ed1,ed2,ref,ints,floats,struct) do { \
1782  TEST_SPECIES_HAS_DATA(TADinsdel[0], sd0); \
1783  TEST_SPECIES_HAS_DATA(TADinsdel[1], sd1); \
1784  TEST_SPECIES_HAS_DATA(TADinsdel[2], sd2); \
1785  TEST_SAI_HAS_DATA(EXTinsdel[0], ed0); \
1786  TEST_SAI_HAS_DATA(EXTinsdel[1], ed1); \
1787  TEST_SAI_HAS_DATA(EXTinsdel[2], ed2); \
1788  TEST_SAI_HAS_ENTRY(EXTinsdel[1], "_REF", ref); \
1789  GBDATA *gb_ref = GB_search(gb_main, "secedit/structs/ali_mini/struct/ref", GB_FIND); \
1790  TEST_EXPECT_EQUAL(GB_read_char_pntr(gb_ref), ref); \
1791  TEST_SPECIES_HAS_INTS(TADinsdel[0], ints); \
1792  TEST_SPECIES_HAS_FLOATS(TADinsdel[0], floats); \
1793  TEST_SAI_HAS_ENTRY(EXTinsdel[1], "_STRUCT", struct); \
1794  } while(0)
1795 
1796 static int get_alignment_aligned(GBDATA *gb_main, const char *aliname) { // former GBT_get_alignment_aligned
1797  GBDATA *gb_alignment = GBT_get_alignment(gb_main, aliname);
1798  return gb_alignment ? *GBT_read_int(gb_alignment, "aligned") : -1;
1799 }
1800 
1801 #define TEST_ALI_LEN_ALIGNED(len,aligned) do { \
1802  TEST_EXPECT_EQUAL(GBT_get_alignment_len(gb_main, ali_name), len); \
1803  TEST_EXPECT_EQUAL(get_alignment_aligned(gb_main, ali_name), aligned); \
1804  } while(0)
1805 
1806 static ARB_ERROR add_some_SAIs(GBDATA *gb_main, const char *ali_name) {
1807  ARB_ERROR error;
1808  GB_transaction ta(gb_main);
1809  TEST_DB_INSERT_SAI(gb_main, error, ali_name, EXTinsdel);
1810 
1811  // add secondary structure to "HELIX"
1812  GBDATA *gb_helix = GBT_find_SAI(gb_main, "HELIX");
1813  if (!gb_helix) error = GB_await_error();
1814  else {
1815  GBDATA *gb_struct = GBT_add_data(gb_helix, ali_name, "_STRUCT", GB_STRING);
1816  if (!gb_struct) error = GB_await_error();
1817  else error = GB_write_string(gb_struct, HELIX_STRUCT);
1818 
1819  GBDATA *gb_struct_ref = GBT_add_data(gb_helix, ali_name, "_REF", GB_STRING);
1820  if (!gb_struct_ref) error = GB_await_error();
1821  else error = GB_write_string(gb_struct_ref, HELIX_REF);
1822  }
1823 
1824  // add stored secondary structure
1825  GBDATA *gb_ref = GB_search(gb_main, "secedit/structs/ali_mini/struct/ref", GB_STRING);
1826  if (!gb_ref) error = GB_await_error();
1827  else error = GB_write_string(gb_ref, HELIX_REF);
1828 
1829  // create one INTS and one FLOATS entry for first species
1830  GBDATA *gb_spec = GBT_find_species(gb_main, TADinsdel[0].name);
1831  {
1832  GBDATA *gb_ints = GBT_add_data(gb_spec, ali_name, "NN", GB_INTS);
1833  const char *intsAsStr = "9346740960354855652100942568200611650200211394358998513";
1834  size_t len = strlen(intsAsStr);
1835  GB_UINT4 *ints = string2ints(intsAsStr, len);
1836  {
1837  char *asStr = ints2string(ints, len);
1838  TEST_EXPECT_EQUAL(intsAsStr, asStr);
1839  free(asStr);
1840  }
1841  error = GB_write_ints(gb_ints, ints, len);
1842  free(ints);
1843  }
1844  {
1845  GBDATA *gb_ints = GBT_add_data(gb_spec, ali_name, "FF", GB_FLOATS);
1846  const char *floatsAsStr = "ODu8EJh60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uCLDoHlWV59DW";
1847  size_t len = strlen(floatsAsStr);
1848  float *floats = string2floats(floatsAsStr, len);
1849  {
1850  char *asStr = floats2string(floats, len);
1851  TEST_EXPECT_EQUAL(floatsAsStr, asStr);
1852  free(asStr);
1853  }
1854  error = GB_write_floats(gb_ints, floats, len);
1855  free(floats);
1856  }
1857  return error;
1858 }
1859 
1860 __ATTR__REDUCED_OPTIMIZE__NO_GCSE static void test_insert_delete_DB() {
1861  GB_shell shell;
1862  ARB_ERROR error;
1863  const char *ali_name = "ali_mini";
1864  GBDATA *gb_main = TEST_CREATE_DB(error, ali_name, TADinsdel, false);
1865 
1866  arb_suppress_progress noProgress;
1867 
1868  if (!error) error = add_some_SAIs(gb_main, ali_name);
1869  if (!error) {
1870  GB_transaction ta(gb_main);
1871 
1872  for (int pass = 1; pass <= 2; ++pass) {
1873  if (pass == 1) TEST_ALI_LEN_ALIGNED(56, 1);
1874  if (pass == 2) TEST_ALI_LEN_ALIGNED(57, 0); // was marked as "not aligned"
1875 
1876  TEST_DATA("...G-GGC-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUCACCUCC.....",
1877  "---A-CGA-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUCACCUCCU.....",
1878  "...A-CGA-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUCACCUCCU----",
1879  "---U-GCC-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCCCACCUGA....",
1880  ".....[<[.........[..[..[<<.[..].>>]....]..]....].>......]",
1881  ".....1.1.........25.25.34..34.34..34...25.25...1........1",
1882  ".....x..x........x...x.x....x.x....x...x...x...x.........x",
1883  "9346740960354855652100942568200611650200211394358998513", // a INTS entry
1884  "ODu8EJh60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uCLDoHlWV59DW", // a FLOATS entry
1885  HELIX_STRUCT);
1886 
1887  if (pass == 1) TEST_EXPECT_NO_ERROR(GBT_check_data(gb_main, ali_name));
1888  }
1889 
1890  TEST_EXPECT_NO_ERROR(ARB_format_alignment(gb_main, ali_name));
1891  TEST_ALI_LEN_ALIGNED(57, 1);
1892  TEST_DATA("...G-GGC-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUCACCUCC......",
1893  "---A-CGA-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUCACCUCCU.....",
1894  "...A-CGA-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUCACCUCCU-----", // @@@ <- should convert '-' to '.'
1895  "---U-GCC-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCCCACCUGA.....",
1896  ".....[<[.........[..[..[<<.[..].>>]....]..]....].>......]",
1897  ".....1.1.........25.25.34..34.34..34...25.25...1........1",
1898  ".....x..x........x...x.x....x.x....x...x...x...x.........x",
1899  "934674096035485565210094256820061165020021139435899851300",
1900  "ODu8EJh60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uCLDoHlWV59DW!",
1901  HELIX_STRUCT);
1902 
1903 // text-editor column -> alignment column
1904 #define COL(col) ((col)-19)
1905 
1906  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(64), 2, "")); // insert in middle
1907  TEST_ALI_LEN_ALIGNED(59, 1);
1908  TEST_DATA("...G-GGC-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCC......",
1909  "---A-CGA-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU.....",
1910  "...A-CGA-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU-----",
1911  "---U-GCC-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCC--CACCUGA.....",
1912  ".....[<[.........[..[..[<<.[..].>>]....]..]......].>......]",
1913  ".....1.1.........25.25.34..34.34..34...25.25.....1........1",
1914  ".....x..x........x...x.x....x.x....x...x...x.....x.........x",
1915  "93467409603548556521009425682006116502002113900435899851300",
1916  "ODu8EJh60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uC!!LDoHlWV59DW!",
1917  HELIX_STRUCT);
1918 
1919  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(75), 2, "")); // insert near end
1920  TEST_ALI_LEN_ALIGNED(61, 1);
1921  TEST_DATA("...G-GGC-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCC........",
1922  "---A-CGA-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU.......",
1923  "...A-CGA-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU-------",
1924  "---U-GCC-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCC--CACCUGA.......",
1925  ".....[<[.........[..[..[<<.[..].>>]....]..]......].>........]",
1926  ".....1.1.........25.25.34..34.34..34...25.25.....1..........1",
1927  ".....x..x........x...x.x....x.x....x...x...x.....x...........x",
1928  "9346740960354855652100942568200611650200211390043589985100300",
1929  "ODu8EJh60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uC!!LDoHlWV59!!DW!",
1930  HELIX_STRUCT);
1931 
1932  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(20), 2, "")); // insert near start
1933  TEST_ALI_LEN_ALIGNED(63, 1);
1934  TEST_DATA(".....G-GGC-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCC........",
1935  "-----A-CGA-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU.......",
1936  ".....A-CGA-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU-------",
1937  "-----U-GCC-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCC--CACCUGA.......",
1938  ".......[<[.........[..[..[<<.[..].>>]....]..]......].>........]",
1939  ".......1.1.........25.25.34..34.34..34...25.25.....1..........1",
1940  ".......x..x........x...x.x....x.x....x...x...x.....x...........x",
1941  "900346740960354855652100942568200611650200211390043589985100300",
1942  "O!!Du8EJh60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uC!!LDoHlWV59!!DW!",
1943  HELIX_STRUCT);
1944 
1945 
1946  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(26), 2, "")); // insert at left helix start
1947  TEST_ALI_LEN_ALIGNED(65, 1);
1948  TEST_DATA(".....G---GGC-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCC........",
1949  "-----A---CGA-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU.......",
1950  ".....A---CGA-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU-------",
1951  "-----U---GCC-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCC--CACCUGA.......",
1952  ".........[<[.........[..[..[<<.[..].>>]....]..]......].>........]",
1953  ".........1.1.........25.25.34..34.34..34...25.25.....1..........1",
1954  ".........x..x........x...x.x....x.x....x...x...x.....x...........x",
1955  "90034670040960354855652100942568200611650200211390043589985100300",
1956  "O!!Du8E!!Jh60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uC!!LDoHlWV59!!DW!",
1957  HELIX_STRUCT);
1958 
1959  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(29), 2, "")); // insert behind left helix start
1960  TEST_ALI_LEN_ALIGNED(67, 1);
1961  TEST_DATA(".....G---G--GC-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCC........",
1962  "-----A---C--GA-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU.......",
1963  ".....A---C--GA-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU-------",
1964  "-----U---G--CC-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCC--CACCUGA.......",
1965  ".........[..<[.........[..[..[<<.[..].>>]....]..]......].>........]",
1966  ".........1...1.........25.25.34..34.34..34...25.25.....1..........1",
1967  ".........x....x........x...x.x....x.x....x...x...x.....x...........x",
1968  "9003467004000960354855652100942568200611650200211390043589985100300",
1969  "O!!Du8E!!J!!h60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uC!!LDoHlWV59!!DW!",
1970  HELIX_STRUCT);
1971 
1972  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(32), 2, "")); // insert at left helix end
1973  TEST_ALI_LEN_ALIGNED(69, 1);
1974  TEST_DATA(".....G---G--G--C-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCC........",
1975  "-----A---C--G--A-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU.......",
1976  ".....A---C--G--A-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU-------",
1977  "-----U---G--C--C-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCC--CACCUGA.......",
1978  ".........[..<..[.........[..[..[<<.[..].>>]....]..]......].>........]",
1979  ".........1.....1.........25.25.34..34.34..34...25.25.....1..........1",
1980  ".........x......x........x...x.x....x.x....x...x...x.....x...........x",
1981  "900346700400000960354855652100942568200611650200211390043589985100300",
1982  "O!!Du8E!!J!!h!!60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uC!!LDoHlWV59!!DW!",
1983  HELIX_STRUCT);
1984 
1985  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(35), 2, "")); // insert behind left helix end
1986  TEST_ALI_LEN_ALIGNED(71, 1);
1987  TEST_DATA(".....G---G--G--C---C-G...--A--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCC........",
1988  "-----A---C--G--A---U-C-----C--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU.......",
1989  ".....A---C--G--A---A-C.....G--G--GAA-CCUG-CGGC-UGG--AUC--ACCUCCU-------",
1990  "-----U---G--C--C---U-G-----G--C--CCU-UAGC-GCGG-UGG--UCC--CACCUGA.......",
1991  ".........[..<..[...........[..[..[<<.[..].>>]....]..]......].>........]",
1992  ".........1.....1...........25.25.34..34.34..34...25.25.....1..........1",
1993  ".........x........x........x...x.x....x.x....x...x...x.....x...........x", // @@@ _REF gets destroyed here! (see #159)
1994  // ^ ^
1995  "90034670040000090060354855652100942568200611650200211390043589985100300",
1996  "O!!Du8E!!J!!h!!6!!0e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uC!!LDoHlWV59!!DW!",
1997  HELIX_STRUCT);
1998 
1999 
2000  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(59), 2, "")); // insert at right helix start
2001  TEST_ALI_LEN_ALIGNED(73, 1);
2002  TEST_DATA(".....G---G--G--C---C-G...--A--G--GAA-CCU--G-CGGC-UGG--AUC--ACCUCC........",
2003  "-----A---C--G--A---U-C-----C--G--GAA-CCU--G-CGGC-UGG--AUC--ACCUCCU.......",
2004  ".....A---C--G--A---A-C.....G--G--GAA-CCU--G-CGGC-UGG--AUC--ACCUCCU-------",
2005  "-----U---G--C--C---U-G-----G--C--CCU-UAG--C-GCGG-UGG--UCC--CACCUGA.......",
2006  ".........[..<..[...........[..[..[<<.[....].>>]....]..]......].>........]",
2007  ".........1.....1...........25.25.34..34...34..34...25.25.....1..........1",
2008  ".........x........x........x...x.x....x...x....x...x...x.....x...........x",
2009  "9003467004000009006035485565210094256820000611650200211390043589985100300",
2010  "O!!Du8E!!J!!h!!6!!0e1XYLgxvzrqmeMiMAjB5E!!JxT6JPiCvQrq4uC!!LDoHlWV59!!DW!",
2011  HELIX_STRUCT);
2012 
2013  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(62), 2, "")); // insert behind right helix start
2014  TEST_ALI_LEN_ALIGNED(75, 1);
2015  TEST_DATA(".....G---G--G--C---C-G...--A--G--GAA-CCU--G---CGGC-UGG--AUC--ACCUCC........",
2016  "-----A---C--G--A---U-C-----C--G--GAA-CCU--G---CGGC-UGG--AUC--ACCUCCU.......",
2017  ".....A---C--G--A---A-C.....G--G--GAA-CCU--G---CGGC-UGG--AUC--ACCUCCU-------",
2018  "-----U---G--C--C---U-G-----G--C--CCU-UAG--C---GCGG-UGG--UCC--CACCUGA.......",
2019  ".........[..<..[...........[..[..[<<.[....]...>>]....]..]......].>........]",
2020  ".........1.....1...........25.25.34..34...3..4..34...25.25.....1..........1", // @@@ <- helix nr destroyed
2021  // ^^^^
2022  ".........x........x........x...x.x....x...x......x...x...x.....x...........x",
2023  "900346700400000900603548556521009425682000000611650200211390043589985100300",
2024  "O!!Du8E!!J!!h!!6!!0e1XYLgxvzrqmeMiMAjB5E!!J!!xT6JPiCvQrq4uC!!LDoHlWV59!!DW!",
2025  HELIX_STRUCT);
2026 
2027  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(67), 2, "")); // insert at right helix end
2028  TEST_ALI_LEN_ALIGNED(77, 1);
2029  TEST_DATA(".....G---G--G--C---C-G...--A--G--GAA-CCU--G---CG--GC-UGG--AUC--ACCUCC........",
2030  "-----A---C--G--A---U-C-----C--G--GAA-CCU--G---CG--GC-UGG--AUC--ACCUCCU.......",
2031  ".....A---C--G--A---A-C.....G--G--GAA-CCU--G---CG--GC-UGG--AUC--ACCUCCU-------",
2032  "-----U---G--C--C---U-G-----G--C--CCU-UAG--C---GC--GG-UGG--UCC--CACCUGA.......",
2033  ".........[..<..[...........[..[..[<<.[....]...>>..]....]..]......].>........]",
2034  ".........1.....1...........25.25.34..34...3..4....34...25.25.....1..........1",
2035  ".........x........x........x...x.x....x...x........x...x...x.....x...........x",
2036  "90034670040000090060354855652100942568200000061100650200211390043589985100300",
2037  "O!!Du8E!!J!!h!!6!!0e1XYLgxvzrqmeMiMAjB5E!!J!!xT6!!JPiCvQrq4uC!!LDoHlWV59!!DW!",
2038  HELIX_STRUCT);
2039 
2040  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(70), 2, "")); // insert behind right helix end
2041  TEST_ALI_LEN_ALIGNED(79, 1);
2042  TEST_DATA(".....G---G--G--C---C-G...--A--G--GAA-CCU--G---CG--G--C-UGG--AUC--ACCUCC........",
2043  "-----A---C--G--A---U-C-----C--G--GAA-CCU--G---CG--G--C-UGG--AUC--ACCUCCU.......",
2044  ".....A---C--G--A---A-C.....G--G--GAA-CCU--G---CG--G--C-UGG--AUC--ACCUCCU-------",
2045  "-----U---G--C--C---U-G-----G--C--CCU-UAG--C---GC--G--G-UGG--UCC--CACCUGA.......",
2046  ".........[..<..[...........[..[..[<<.[....]...>>..]......]..]......].>........]",
2047  ".........1.....1...........25.25.34..34...3..4....3..4...25.25.....1..........1", // @@@ <- helix nr destroyed
2048  ".........x........x........x...x.x....x...x..........x...x...x.....x...........x", // @@@ _REF gets destroyed here! (see #159)
2049  "9003467004000009006035485565210094256820000006110060050200211390043589985100300",
2050  "O!!Du8E!!J!!h!!6!!0e1XYLgxvzrqmeMiMAjB5E!!J!!xT6!!J!!PiCvQrq4uC!!LDoHlWV59!!DW!",
2051  HELIX_STRUCT);
2052 
2053 
2054 
2055  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(44), 2, "")); // insert at gap border (between different gap types)
2056  TEST_ALI_LEN_ALIGNED(81, 1);
2057  TEST_DATA(".....G---G--G--C---C-G...----A--G--GAA-CCU--G---CG--G--C-UGG--AUC--ACCUCC........", // now prefers '-' here
2058  "-----A---C--G--A---U-C-------C--G--GAA-CCU--G---CG--G--C-UGG--AUC--ACCUCCU.......",
2059  ".....A---C--G--A---A-C.......G--G--GAA-CCU--G---CG--G--C-UGG--AUC--ACCUCCU-------",
2060  "-----U---G--C--C---U-G-------G--C--CCU-UAG--C---GC--G--G-UGG--UCC--CACCUGA.......",
2061  ".........[..<..[.............[..[..[<<.[....]...>>..]......]..]......].>........]",
2062  ".........1.....1.............25.25.34..34...3..4....3..4...25.25.....1..........1",
2063  ".........x........x..........x...x.x....x...x..........x...x...x.....x...........x",
2064  "900346700400000900603548500565210094256820000006110060050200211390043589985100300",
2065  "O!!Du8E!!J!!h!!6!!0e1XYLg!!xvzrqmeMiMAjB5E!!J!!xT6!!J!!PiCvQrq4uC!!LDoHlWV59!!DW!",
2066  HELIX_STRUCT);
2067 
2068 
2069  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(42), -6, "-.")); // delete gaps
2070  TEST_ALI_LEN_ALIGNED(75, 1);
2071  TEST_DATA(".....G---G--G--C---C-G.A--G--GAA-CCU--G---CG--G--C-UGG--AUC--ACCUCC........",
2072  "-----A---C--G--A---U-C-C--G--GAA-CCU--G---CG--G--C-UGG--AUC--ACCUCCU.......",
2073  ".....A---C--G--A---A-C.G--G--GAA-CCU--G---CG--G--C-UGG--AUC--ACCUCCU-------",
2074  "-----U---G--C--C---U-G-G--C--CCU-UAG--C---GC--G--G-UGG--UCC--CACCUGA.......",
2075  ".........[..<..[.......[..[..[<<.[....]...>>..]......]..]......].>........]",
2076  ".........1.....1.......25.25.34..34...3..4....3..4...25.25.....1..........1",
2077  ".........x........x....x...x.x....x...x..........x...x...x.....x...........x",
2078  "900346700400000900603545210094256820000006110060050200211390043589985100300",
2079  "O!!Du8E!!J!!h!!6!!0e1XYzrqmeMiMAjB5E!!J!!xT6!!J!!PiCvQrq4uC!!LDoHlWV59!!DW!",
2080  HELIX_STRUCT);
2081 
2082  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(74), -1, "-.")); // delete gap inside helix destroying helix nrs
2083  TEST_ALI_LEN_ALIGNED(74, 1);
2084  TEST_DATA(".....G---G--G--C---C-G.A--G--GAA-CCU--G---CG--G--C-UGG-AUC--ACCUCC........",
2085  "-----A---C--G--A---U-C-C--G--GAA-CCU--G---CG--G--C-UGG-AUC--ACCUCCU.......",
2086  ".....A---C--G--A---A-C.G--G--GAA-CCU--G---CG--G--C-UGG-AUC--ACCUCCU-------",
2087  "-----U---G--C--C---U-G-G--C--CCU-UAG--C---GC--G--G-UGG-UCC--CACCUGA.......",
2088  ".........[..<..[.......[..[..[<<.[....]...>>..]......].]......].>........]",
2089  ".........1.....1.......25.25.34..34...3..4....3..4...2525.....1..........1", // @@@ helix nr destroyed ('25.25' -> '2525')
2090  ".........x........x....x...x.x....x...x..........x...x..x.....x...........x",
2091  "90034670040000090060354521009425682000000611006005020021390043589985100300",
2092  "O!!Du8E!!J!!h!!6!!0e1XYzrqmeMiMAjB5E!!J!!xT6!!J!!PiCvQr4uC!!LDoHlWV59!!DW!",
2093  HELIX_STRUCT);
2094 
2095 
2096  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(47), -1, "-.")); // delete gap between helices destroying helix nrs
2097  TEST_ALI_LEN_ALIGNED(73, 1);
2098  TEST_DATA(".....G---G--G--C---C-G.A--G-GAA-CCU--G---CG--G--C-UGG-AUC--ACCUCC........",
2099  "-----A---C--G--A---U-C-C--G-GAA-CCU--G---CG--G--C-UGG-AUC--ACCUCCU.......",
2100  ".....A---C--G--A---A-C.G--G-GAA-CCU--G---CG--G--C-UGG-AUC--ACCUCCU-------",
2101  "-----U---G--C--C---U-G-G--C-CCU-UAG--C---GC--G--G-UGG-UCC--CACCUGA.......",
2102  ".........[..<..[.......[..[.[<<.[....]...>>..]......].]......].>........]",
2103  ".........1.....1.......25.2534..34...3..4....3..4...2525.....1..........1", // @@@ helix nr destroyed ('25.34' -> '2534')
2104  ".........x........x....x...xx....x...x..........x...x..x.....x...........x",
2105  "9003467004000009006035452100425682000000611006005020021390043589985100300",
2106  "O!!Du8E!!J!!h!!6!!0e1XYzrqmeiMAjB5E!!J!!xT6!!J!!PiCvQr4uC!!LDoHlWV59!!DW!",
2107  HELIX_STRUCT);
2108 
2109 
2110  TEST_EXPECT_NO_ERROR(ARB_insdel_columns(gb_main, ali_name, COL(72), -5, "%")); // delete anything
2111  TEST_ALI_LEN_ALIGNED(68, 1);
2112  TEST_DATA(".....G---G--G--C---C-G.A--G-GAA-CCU--G---CG--G--C-UGG-ACCUCC........",
2113  "-----A---C--G--A---U-C-C--G-GAA-CCU--G---CG--G--C-UGG-ACCUCCU.......",
2114  ".....A---C--G--A---A-C.G--G-GAA-CCU--G---CG--G--C-UGG-ACCUCCU-------",
2115  "-----U---G--C--C---U-G-G--C-CCU-UAG--C---GC--G--G-UGG-CACCUGA.......",
2116  ".........[..<..[.......[..[.[<<.[....]...>>..]......]...].>........]",
2117  ".........1.....1.......25.2534..34...3..4....3..4...2...1..........1",
2118  ".........x........x....x...xx....x...x..........x...x...x...........x",
2119  "90034670040000090060354521004256820000006110060050200043589985100300",
2120  "O!!Du8E!!J!!h!!6!!0e1XYzrqmeiMAjB5E!!J!!xT6!!J!!PiCvQ!LDoHlWV59!!DW!",
2121  HELIX_STRUCT);
2122 
2123  }
2124 
2125  if (!error) {
2126  {
2127  GB_transaction ta(gb_main);
2128  TEST_EXPECT_EQUAL(ARB_insdel_columns(gb_main, ali_name, COL(35), -3, "-."), // illegal delete
2129  "SAI 'HELIX': You tried to delete 'x' at position 18 -> Operation aborted");
2130  ta.close("xxx");
2131  }
2132  {
2133  GB_transaction ta(gb_main);
2134  TEST_EXPECT_EQUAL(ARB_insdel_columns(gb_main, ali_name, COL(57), -3, "-."), // illegal delete
2135  "SAI 'HELIX_NR': You tried to delete '4' at position 40 -> Operation aborted");
2136  ta.close("xxx");
2137  }
2138  {
2139  GB_transaction ta(gb_main);
2140  TEST_EXPECT_EQUAL(ARB_insdel_columns(gb_main, ali_name, 4711, 3, "-."), // illegal insert
2141  "Can't insert at position 4711 (exceeds length 68 of alignment 'ali_mini')");
2142  ta.close("xxx");
2143  }
2144  {
2145  GB_transaction ta(gb_main);
2146  TEST_EXPECT_EQUAL(ARB_insdel_columns(gb_main, ali_name, 66, -3, "-."), // illegal delete
2147  "Can't delete positions 66-68 (exceeds max. position 67 of alignment 'ali_mini')");
2148  ta.close("xxx");
2149  }
2150  {
2151  GB_transaction ta(gb_main);
2152  TEST_EXPECT_EQUAL(ARB_insdel_columns(gb_main, ali_name, -1, 3, "-."), // illegal insert
2153  "Illegal sequence position -1");
2154  ta.close("xxx");
2155  }
2156  }
2157  if (!error) {
2158  GB_transaction ta(gb_main);
2159  TEST_DATA(".....G---G--G--C---C-G.A--G-GAA-CCU--G---CG--G--C-UGG-ACCUCC........",
2160  "-----A---C--G--A---U-C-C--G-GAA-CCU--G---CG--G--C-UGG-ACCUCCU.......",
2161  ".....A---C--G--A---A-C.G--G-GAA-CCU--G---CG--G--C-UGG-ACCUCCU-------",
2162  "-----U---G--C--C---U-G-G--C-CCU-UAG--C---GC--G--G-UGG-CACCUGA.......",
2163  ".........[..<..[.......[..[.[<<.[....]...>>..]......]...].>........]",
2164  ".........1.....1.......25.2534..34...3..4....3..4...2...1..........1",
2165  ".........x........x....x...xx....x...x..........x...x...x...........x",
2166  "90034670040000090060354521004256820000006110060050200043589985100300",
2167  "O!!Du8E!!J!!h!!6!!0e1XYzrqmeiMAjB5E!!J!!xT6!!J!!PiCvQ!LDoHlWV59!!DW!",
2168  HELIX_STRUCT);
2169  }
2170 
2171  GB_close(gb_main);
2172  TEST_EXPECT_NO_ERROR(error.deliver());
2173 }
2174 void TEST_insert_delete_DB() {
2175  test_insert_delete_DB(); // wrap test code in subroutine (otherwise nm 2.24 fails to provide source-location, even if TEST_PUBLISH is used)
2176 }
2177 
2178 __ATTR__REDUCED_OPTIMIZE void TEST_insert_delete_DB_using_SAI() {
2179  GB_shell shell;
2180  ARB_ERROR error;
2181  const char *ali_name = "ali_mini";
2182  GBDATA *gb_main = TEST_CREATE_DB(error, ali_name, TADinsdel, false);
2183 
2184  arb_suppress_progress noProgress;
2185 
2186  if (!error) error = add_some_SAIs(gb_main, ali_name);
2187  if (!error) {
2188  GB_transaction ta(gb_main);
2189 
2190  // test here is just a duplicate from TEST_insert_delete_DB() - just here to show the data
2191  TEST_EXPECT_NO_ERROR(ARB_format_alignment(gb_main, ali_name));
2192  int alilen_exp = 57;
2193  TEST_ALI_LEN_ALIGNED(alilen_exp, 1);
2194  TEST_DATA("...G-GGC-C-G...--A--G--GAA-CCUG-CGGC-UGG--AUCACCUCC......",
2195  "---A-CGA-U-C-----C--G--GAA-CCUG-CGGC-UGG--AUCACCUCCU.....",
2196  "...A-CGA-A-C.....G--G--GAA-CCUG-CGGC-UGG--AUCACCUCCU-----",
2197  "---U-GCC-U-G-----G--C--CCU-UAGC-GCGG-UGG--UCCCACCUGA.....",
2198  ".....[<[.........[..[..[<<.[..].>>]....]..]....].>......]",
2199  ".....1.1.........25.25.34..34.34..34...25.25...1........1",
2200  ".....x..x........x...x.x....x.x....x...x...x...x.........x",
2201  "934674096035485565210094256820061165020021139435899851300",
2202  "ODu8EJh60e1XYLgxvzrqmeMiMAjB5EJxT6JPiCvQrq4uCLDoHlWV59DW!",
2203  HELIX_STRUCT);
2204 
2206  /* */ "xxx-------x-x-xxx---------x---------x---------------xxxx-",
2207  "x", false);
2208  TEST_EXPECT_NO_ERROR(ARB_delete_columns_using_SAI(gb_main, ali_name, delRanges, ".-"));
2209  alilen_exp -= 14;
2210  TEST_ALI_LEN_ALIGNED(alilen_exp, 1);
2211  TEST_DATA("G-GGC-CG.A--G--GAACCUG-CGGCUGG--AUCACCUCC..",
2212  "A-CGA-UC-C--G--GAACCUG-CGGCUGG--AUCACCUCCU.",
2213  "A-CGA-AC.G--G--GAACCUG-CGGCUGG--AUCACCUCCU-",
2214  "U-GCC-UG-G--C--CCUUAGC-GCGGUGG--UCCCACCUGA.",
2215  "..[<[....[..[..[<<[..].>>]...]..]....].>..]",
2216  "..1.1....25.25.34.34.34..34..25.25...1....1",
2217  "..x..x...x...x.x...x.x....x..x...x...x.....x",
2218  "6740960585210094258200611652002113943589980",
2219  "8EJh60eXLzrqmeMiMAB5EJxT6JPCvQrq4uCLDoHlWV!",
2220  HELIX_STRUCT);
2221 
2222  // insert INFRONTOF each range
2224  /* */ "---xx---xxxxxxxx---------xxxx--------------",
2225  "x", false);
2226  TEST_EXPECT_NO_ERROR(ARB_insert_columns_using_SAI(gb_main, ali_name, insRanges, RANGES, INFRONTOF, 2));
2227  alilen_exp += 3*2;
2228  TEST_ALI_LEN_ALIGNED(alilen_exp, 1);
2229  TEST_DATA("G-G--GC-CG...A--G--GAACCUG-CG--GCUGG--AUCACCUCC..",
2230  "A-C--GA-UC---C--G--GAACCUG-CG--GCUGG--AUCACCUCCU.",
2231  "A-C--GA-AC...G--G--GAACCUG-CG--GCUGG--AUCACCUCCU-",
2232  "U-G--CC-UG---G--C--CCUUAGC-GC--GGUGG--UCCCACCUGA.",
2233  "..[..<[......[..[..[<<[..].>>..]...]..]....].>..]",
2234  "..1...1......25.25.34.34.34....34..25.25...1....1",
2235  "..x....x.....x...x.x...x.x......x..x...x...x.....x",
2236  "6740009605008521009425820061100652002113943589980",
2237  "8EJ!!h60eX!!LzrqmeMiMAB5EJxT6!!JPCvQrq4uCLDoHlWV!",
2238  HELIX_STRUCT);
2239 
2240  // insert BEHIND each range
2241  insRanges = build_RangeList_from_string(
2242  /* */ "-----------xx-x------------xxxxxx---------------x",
2243  "x", false);
2244  TEST_EXPECT_NO_ERROR(ARB_insert_columns_using_SAI(gb_main, ali_name, insRanges, RANGES, BEHIND, 4));
2245  alilen_exp += 4*4;
2246  TEST_ALI_LEN_ALIGNED(alilen_exp, 1);
2247  TEST_DATA("G-G--GC-CG.......A------G--GAACCUG-CG--GC----UGG--AUCACCUCC......",
2248  "A-C--GA-UC-------C------G--GAACCUG-CG--GC----UGG--AUCACCUCCU.....",
2249  "A-C--GA-AC.......G------G--GAACCUG-CG--GC----UGG--AUCACCUCCU-----",
2250  "U-G--CC-UG-------G------C--CCUUAGC-GC--GG----UGG--UCCCACCUGA.....",
2251  "..[..<[..........[......[..[<<[..].>>..].......]..]....].>..]....",
2252  "..1...1..........25.....25.34.34.34....34......25.25...1....1....",
2253  "..x....x.........x.......x.x...x.x......x......x...x...x.........x", // @@@ ref gets destroyed here
2254  "67400096050080000520000100942582006110065000020021139435899800000",
2255  "8EJ!!h60eX!!L!!!!zr!!!!qmeMiMAB5EJxT6!!JP!!!!CvQrq4uCLDoHlWV!!!!!",
2256  HELIX_STRUCT);
2257 
2258  // insert INFRONTOF each column
2259  insRanges = build_RangeList_from_string(
2260  /* */ "x----xx--------------------------------------xxx----xxxx--------x",
2261  "x", false);
2262  TEST_EXPECT_NO_ERROR(ARB_insert_columns_using_SAI(gb_main, ali_name, insRanges, SINGLE_COLUMNS, INFRONTOF, 1));
2263  alilen_exp += 11*1;
2264  TEST_ALI_LEN_ALIGNED(alilen_exp, 1);
2265  TEST_DATA(".G-G---G-C-CG.......A------G--GAACCUG-CG--GC-----U-G-G--AU-C-A-C-CUCC.......",
2266  ".A-C---G-A-UC-------C------G--GAACCUG-CG--GC-----U-G-G--AU-C-A-C-CUCCU......",
2267  ".A-C---G-A-AC.......G------G--GAACCUG-CG--GC-----U-G-G--AU-C-A-C-CUCCU------",
2268  ".U-G---C-C-UG-------G------C--CCUUAGC-GC--GG-----U-G-G--UC-C-C-A-CCUGA......",
2269  "...[...<.[..........[......[..[<<[..].>>..]..........]..]........].>..].....",
2270  "...1.....1..........25.....25.34.34.34....34.........25.25.......1....1.....",
2271  "...x......x.........x.......x.x...x.x......x.........x...x.......x..........x",
2272  "0674000009605008000052000010094258200611006500000200002113090403058998000000",
2273  "!8EJ!!!h!60eX!!L!!!!zr!!!!qmeMiMAB5EJxT6!!JP!!!!!C!v!Qrq4u!C!L!D!oHlWV!!!!!!",
2274  HELIX_STRUCT);
2275 
2276  // insert BEHIND each column
2277  insRanges = build_RangeList_from_string(
2278  /* */ "------------------------------xxxxxxx----------------------------xxxxxx-----",
2279  "x", false);
2280  TEST_EXPECT_NO_ERROR(ARB_insert_columns_using_SAI(gb_main, ali_name, insRanges, SINGLE_COLUMNS, BEHIND, 2));
2281  alilen_exp += 13*2;
2282  TEST_ALI_LEN_ALIGNED(alilen_exp, 1);
2283  TEST_DATA(".G-G---G-C-CG.......A------G--G--A--A--C--C--U--G---CG--GC-----U-G-G--AU-C-A-C-C--U--C--C.............",
2284  ".A-C---G-A-UC-------C------G--G--A--A--C--C--U--G---CG--GC-----U-G-G--AU-C-A-C-C--U--C--C--U..........",
2285  ".A-C---G-A-AC.......G------G--G--A--A--C--C--U--G---CG--GC-----U-G-G--AU-C-A-C-C--U--C--C--U----------",
2286  ".U-G---C-C-UG-------G------C--C--C--U--U--A--G--C---GC--GG-----U-G-G--UC-C-C-A-C--C--U--G--A..........",
2287  "...[...<.[..........[......[..[..<..<..[........]...>>..]..........]..]........].....>........].......",
2288  "...1.....1..........25.....25.3..4.....3..4.....3..4....34.........25.25.......1..............1.......", // @@@ helix nrs destroyed
2289  "...x......x.........x.......x.x...........x.....x........x.........x...x.......x......................x", // @@@ ref destroyed further
2290  "067400000960500800005200001009400200500800200000000611006500000200002113090403050080090090080000000000",
2291  "!8EJ!!!h!60eX!!L!!!!zr!!!!qmeMi!!M!!A!!B!!5!!E!!J!!xT6!!JP!!!!!C!v!Qrq4u!C!L!D!o!!H!!l!!W!!V!!!!!!!!!!",
2292  HELIX_STRUCT);
2293  }
2294 
2295  GB_close(gb_main);
2296  TEST_EXPECT_NO_ERROR(error.deliver());
2297 }
2298 TEST_PUBLISH(TEST_insert_delete_DB_using_SAI);
2299 
2300 #endif // UNIT_TESTS
2301 
size_t get_len() const
Definition: insdel.cxx:920
virtual bool has_slice() const =0
const char * GB_ERROR
Definition: arb_core.h:25
GB_ERROR GB_write_bits(GBDATA *gbd, const char *bits, long size, const char *c_0)
Definition: arbdb.cxx:1392
string result
GB_TYPES type
float * GB_read_floats(GBDATA *gbd)
Definition: arbdb.cxx:1023
AliDataPtr apply(AliDataPtr to, GB_ERROR &error) const OVERRIDE
Definition: insdel.cxx:1107
group_matcher all()
Definition: test_unit.h:1000
AliDataPtr slice_down(size_t start, size_t count) const OVERRIDE
Definition: insdel.cxx:190
TypedAliData< T > BaseType
Definition: insdel.cxx:406
bool has_slice() const OVERRIDE
Definition: insdel.cxx:387
AliDataPtr format(AliDataPtr data, const size_t wanted_len, GB_ERROR &error)
Definition: insdel.cxx:615
void load_data() const
Definition: insdel.cxx:1360
long GB_read_int(GBDATA *gbd)
Definition: arbdb.cxx:699
GBDATA * GB_child(GBDATA *father)
Definition: adquery.cxx:322
#define implicated(hypothesis, conclusion)
Definition: arb_assert.h:289
GB_ERROR GB_write_bytes(GBDATA *gbd, const char *s, long size)
Definition: arbdb.cxx:1408
virtual AliDataPtr apply(AliDataPtr to, GB_ERROR &error) const =0
AliDataPtr delete_from(AliDataPtr from, size_t pos, size_t amount, GB_ERROR &error)
Definition: insdel.cxx:595
Definition: ali.h:11
virtual size_t unitsize() const =0
Definition: arbdb.h:69
static void dot(double **i, double **j, double **k)
Definition: trnsprob.cxx:59
AliDataPtr apply(AliDataPtr to, GB_ERROR &error) const OVERRIDE
Definition: insdel.cxx:1089
CONSTEXPR_INLINE unsigned char safeCharIndex(char c)
Definition: dupstr.h:73
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
Definition: arbdb.cxx:1361
static GB_ERROR apply_command_to_alignment(const AliEditCommand &cmd, const char *cmd_description, GBDATA *Main, const char *alignment_name, const char *deletable_chars)
Definition: insdel.cxx:1390
GBDATA * GB_find(GBDATA *gbd, const char *key, GB_SEARCH_TYPE gbs)
Definition: adquery.cxx:295
bool has_slice() const OVERRIDE
Definition: insdel.cxx:1213
int operate_on_mem(void *mem, size_t start, size_t count, AliData::memop op) const OVERRIDE
Definition: insdel.cxx:497
TypedAliData< T > BaseType
Definition: insdel.cxx:488
GB_ERROR check_applicable_to(const Alignment &ali, size_t &resulting_ali_length) const OVERRIDE
Definition: insdel.cxx:1053
GBDATA * GB_nextEntry(GBDATA *entry)
Definition: adquery.cxx:339
TypedAliData(size_t size_, T gap_)
Definition: insdel.cxx:379
GBDATA * GBT_get_alignment(GBDATA *gb_main, const char *aliname)
Definition: adali.cxx:684
void GB_disable_quicksave(GBDATA *gbd, const char *reason)
Definition: arbdb.cxx:2611
virtual GB_ERROR check_applicable_to(const Alignment &ali, size_t &resulting_ali_length) const =0
TerminalType
Definition: insdel.cxx:901
UnitPtr unit_left_of(size_t pos) const OVERRIDE
Definition: insdel.cxx:394
#define id_assert(cond)
Definition: insdel.cxx:27
const AliEditCommand & edit_command() const
Definition: insdel.cxx:1154
UseRange
Definition: insdel.h:19
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
const T * std_gap_ptr() const
Definition: insdel.cxx:376
UnitPtr unit_left_of(size_t pos) const OVERRIDE
Definition: insdel.cxx:197
UnitPtr()
Definition: insdel.cxx:35
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
int get_len(int idx) const
Definition: ali.h:18
SizeAwarable(bool allows_oversize_, size_t ali_size_)
Definition: insdel.cxx:457
static char * alignment_name
const char * get_name() const
Definition: insdel.cxx:919
STL namespace.
int cmp_data(size_t start, const AliData &other, size_t ostart, size_t count) const OVERRIDE
Definition: insdel.cxx:1219
AliDataPtr slice_down(size_t start, size_t count) const OVERRIDE
Definition: insdel.cxx:238
UnitPtr unit_left_of(size_t pos) const OVERRIDE
Definition: insdel.cxx:301
bool isNull() const
test if SmartPtr is NULp
Definition: smartptr.h:248
GB_ERROR ARB_insdel_columns(GBDATA *Main, const char *alignment_name, long pos, long count, const char *deletable_chars)
Definition: insdel.cxx:1453
SpecificAliData(const T *static_data, size_t elements, const T &gap_, const SizeAwarable &sizeAware, const Deletable &deletable_)
Definition: insdel.cxx:490
InsertWhere
Definition: insdel.h:20
AliDataPtr create_gap(size_t gapsize, const UnitPair &gapinfo) const OVERRIDE
Definition: insdel.cxx:187
static GB_CSTR targetTypeName[]
Definition: insdel.cxx:907
EditedTerminal(GBDATA *gb_data_, GB_TYPES type_, const char *item_name_, size_t size_, TerminalType term_type, const Alignment &ali, const Deletable &deletable_)
Definition: insdel.cxx:1319
UnitPtr unit_right_of(size_t pos) const OVERRIDE
Definition: insdel.cxx:398
static size_t countAffectedEntries(GBDATA *Main, const Alignment &ali)
Definition: insdel.cxx:1384
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
AliDataPtr partof(AliDataPtr data, size_t pos, size_t amount)
Definition: insdel.cxx:591
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
Definition: insdel.h:19
static GB_ERROR format_to_alilen(GBDATA *Main, const char *alignment_name)
Definition: insdel.cxx:1434
static size_t insDelBuffer_size
Definition: insdel.cxx:1160
GB_ERROR ARB_delete_columns_using_SAI(GBDATA *Main, const char *alignment_name, const RangeList &ranges, const char *deletable_chars)
Definition: insdel.cxx:1493
bool empty() const
Definition: RangeList.h:59
const void * expect_pointer() const
Definition: insdel.cxx:47
AliDataPtr insert_at(AliDataPtr dest, size_t pos, AliDataPtr src)
Definition: insdel.cxx:599
static HelixNrInfo * start
int operate_on_mem(void *mem, size_t start, size_t count, memop op) const OVERRIDE
Definition: insdel.cxx:258
LazyAliData(const SizeAwarable &oversizable, size_t size_, TerminalType term_type_, EditedTerminal &terminal_)
Definition: insdel.cxx:1201
#define TEST_PUBLISH(testfunction)
Definition: test_unit.h:1484
GBDATA * GBT_find_SAI(GBDATA *gb_main, const char *name)
Definition: aditem.cxx:172
unsigned int GB_UINT4
Definition: arbdb_base.h:37
NOT4PERL GBDATA * GBT_add_data(GBDATA *species, const char *ali_name, const char *key, GB_TYPES type) __ATTR__DEPRECATED_TODO("better use GBT_create_sequence_data()")
Definition: adali.cxx:559
UnitPtr at_ptr(size_t pos) const OVERRIDE
Definition: insdel.cxx:442
GB_CSTR GB_read_bytes_pntr(GBDATA *gbd)
Definition: arbdb.cxx:934
void free_insDelBuffer()
Definition: insdel.cxx:1162
GB_ERROR ARB_insert_columns_using_SAI(GBDATA *Main, const char *alignment_name, const RangeList &ranges, UseRange units, InsertWhere where, size_t amount)
Definition: insdel.cxx:1512
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:353
AliDataPtr after(AliDataPtr data, size_t pos)
Definition: insdel.cxx:593
NOT4PERL long * GBT_read_int(GBDATA *gb_container, const char *fieldpath)
Definition: adtools.cxx:327
#define TEST_EXPECT(cond)
Definition: test_unit.h:1312
GB_ERROR ARB_format_alignment(GBDATA *Main, const char *alignment_name)
Definition: insdel.cxx:1439
long GB_read_count(GBDATA *gbd)
Definition: arbdb.cxx:728
GB_ERROR apply_to_alignment(GBDATA *gb_main, const Alignment &ali) const
Definition: insdel.cxx:1002
Definition: arbdb.h:78
const T * get_data() const
Definition: insdel.cxx:539
GB_TYPES GB_read_type(GBDATA *gbd)
Definition: arbdb.cxx:1617
GB_ERROR deliver() const
Definition: arb_error.h:114
size_t get_entry_count() const
Definition: insdel.cxx:1016
GB_CSTR GB_read_key_pntr(GBDATA *gbd)
Definition: arbdb.cxx:1630
AliDataPtr concat(AliDataPtr left, AliDataPtr right)
Definition: insdel.cxx:584
bool differs_from(const AliData &other) const
Definition: insdel.cxx:130
const T & std_gap() const
Definition: insdel.cxx:384
AliDataPtr apply(AliDataPtr to, GB_ERROR &) const OVERRIDE
Definition: insdel.cxx:1032
void set_pointer(const void *ptr_)
Definition: insdel.cxx:42
long GB_number_of_subentries(GBDATA *gbd)
Definition: arbdb.cxx:2856
size_t elems() const
Definition: insdel.cxx:111
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:463
~AliCompositeCommand() OVERRIDE
Definition: insdel.cxx:1106
virtual ~AliApplicable()
Definition: insdel.cxx:934
int cmp_data(size_t start, const AliData &other, size_t ostart, size_t count) const OVERRIDE
Definition: insdel.cxx:435
reverse_iterator rend() const
Definition: RangeList.h:55
AliData(size_t size_)
Definition: insdel.cxx:70
virtual ~AliEditCommand()
Definition: insdel.cxx:1022
int cmp_whole_data(const AliData &other) const
Definition: insdel.cxx:116
int cmp_data(size_t start, const AliData &other, size_t ostart, size_t count) const OVERRIDE
Definition: insdel.cxx:205
UnitPtr unit_right_of(size_t pos) const OVERRIDE
Definition: insdel.cxx:201
GB_ERROR check_applicable_to(const Alignment &ali, size_t &resulting_ali_length) const OVERRIDE
Definition: insdel.cxx:1079
UnitPtr unit_right_of(size_t pos) const OVERRIDE
Definition: insdel.cxx:314
static void error(const char *msg)
Definition: mkptypes.cxx:96
int cmpPartWith(const void *mem, size_t start, size_t count) const
Definition: insdel.cxx:93
int operate_on_mem(void *mem, size_t start, size_t count, memop op) const OVERRIDE
Definition: insdel.cxx:1218
UnitPtr unit_right_of(size_t pos) const OVERRIDE
Definition: insdel.cxx:1222
GB_ERROR check_applicable_to(const Alignment &ali, size_t &resulting_ali_length) const OVERRIDE
Definition: insdel.cxx:1033
expectation_group & add(const expectation &e)
Definition: test_unit.h:801
char * str
Definition: defines.h:20
Deletable(const char *allowed)
Definition: insdel.cxx:348
#define that(thing)
Definition: test_unit.h:1032
AliDeleteCommand(size_t pos_, size_t amount_)
Definition: insdel.cxx:1048
bool is_valid_pos(size_t pos) const
Definition: insdel.cxx:132
SpecificGap(size_t gapsize, const T &gap_)
Definition: insdel.cxx:408
Definition: insdel.h:20
int cmp_data(size_t start, const AliData &other, size_t ostart, size_t count) const OVERRIDE
Definition: insdel.cxx:528
AliDataPtr create_gap(size_t gapsize, const UnitPair &gapinfo) const OVERRIDE
Definition: insdel.cxx:235
size_t unitsize() const OVERRIDE
Definition: insdel.cxx:1208
GB_UINT4 * GB_read_ints(GBDATA *gbd)
Definition: arbdb.cxx:983
GB_CSTR alidata2buffer(const AliData &data)
Definition: insdel.cxx:1174
UnitPtr right
Definition: insdel.cxx:50
#define cmp(h1, h2)
Definition: admap.cxx:50
AliCompositeCommand(AliEditCommand *cmd1_, AliEditCommand *cmd2_)
Definition: insdel.cxx:1102
void copyTo(void *mem) const
Definition: insdel.cxx:113
bool is_valid_part(size_t start, size_t count) const
Definition: insdel.cxx:135
const void * get_pointer() const
Definition: insdel.cxx:46
GB_ERROR check_delete_allowed(const T *, size_t, size_t, const Deletable &)
Definition: insdel.cxx:474
__ATTR__NORETURN AliDataPtr slice_down(size_t, size_t) const OVERRIDE
Definition: insdel.cxx:1225
#define GENOM_ALIGNMENT
Definition: adGene.h:19
GB_CUINT4 * GB_read_ints_pntr(GBDATA *gbd)
Definition: arbdb.cxx:949
AliDataPtr apply(AliDataPtr to, GB_ERROR &error) const OVERRIDE
Definition: insdel.cxx:1070
int compare_type(const T &t1, const T &t2)
Definition: insdel.cxx:54
AliDataPtr before(AliDataPtr data, size_t pos)
Definition: insdel.cxx:592
GB_ERROR GB_write_int(GBDATA *gbd, long i)
Definition: arbdb.cxx:1220
virtual AliDataPtr slice_down(size_t start, size_t count) const =0
#define is_equal_to(val)
Definition: test_unit.h:1014
#define __ATTR__REDUCED_OPTIMIZE
Definition: test_unit.h:83
bool empty() const
Definition: insdel.cxx:114
~AliEditor() OVERRIDE
Definition: insdel.cxx:1150
size_t get_allowed_size(size_t term_size, size_t new_ali_size) const
Definition: insdel.cxx:462
Definition: arbdb.h:72
UnitPtr left
Definition: insdel.cxx:50
void clear_error() const
Definition: insdel.cxx:82
static void copy(double **i, double **j)
Definition: trnsprob.cxx:32
#define IF_ASSERTION_USED(x)
Definition: arb_assert.h:308
reverse_iterator rbegin() const
Definition: RangeList.h:54
xml element
GB_ERROR close(GB_ERROR error)
Definition: arbdbpp.cxx:32
UnitPtr at_ptr(size_t pos) const OVERRIDE
Definition: insdel.cxx:535
AliFormatCommand(size_t wanted_len_)
Definition: insdel.cxx:1069
#define TEST_EXPECT_CODE_ASSERTION_FAILS(cb)
Definition: test_unit.h:1241
static AliDataPtr make(AliDataPtr from, size_t offset, size_t amount)
Definition: insdel.cxx:176
UnitPtr unit_left_of(size_t pos) const OVERRIDE
Definition: insdel.cxx:1221
bool equals(const AliData &other) const
Definition: insdel.cxx:124
bool equals(const copy< T > &t1, const copy< T > &t2)
Definition: test_unit.h:633
#define OVERRIDE
Definition: cxxforward.h:93
virtual int operate_on_mem(void *mem, size_t start, size_t count, memop op) const =0
char * provide_insDelBuffer(size_t neededSpace)
Definition: insdel.cxx:1165
int operate_on_mem(void *mem, size_t start, size_t count, AliData::memop op) const OVERRIDE
Definition: insdel.cxx:411
GB_ERROR GB_write_ints(GBDATA *gbd, const GB_UINT4 *i, long size)
Definition: arbdb.cxx:1413
SmartPtr< AliData > AliDataPtr
Definition: insdel.cxx:60
AliDataPtr create_gap(size_t gapsize, const UnitPair &) const OVERRIDE
Definition: insdel.cxx:449
static char * insDelBuffer
Definition: insdel.cxx:1159
GBDATA * GBT_find_or_create(GBDATA *father, const char *key, long delete_level)
Definition: adtools.cxx:42
AliDataPtr insert_gap(AliDataPtr data, size_t pos, size_t count)
Definition: insdel.cxx:603
size_t unitsize() const OVERRIDE
Definition: insdel.cxx:386
size_t memsize() const
Definition: insdel.cxx:112
RangeList build_RangeList_from_string(const char *SAI_data, const char *set_bytes, bool invert)
Definition: RangeList.cxx:32
GB_ERROR get_delete_error(const char *data, size_t start, size_t count) const
Definition: insdel.cxx:355
AliDataPtr create_gap(size_t gapsize, const UnitPair &gapinfo) const OVERRIDE
Definition: insdel.cxx:575
GB_ERROR check_delete_allowed(size_t start, size_t count) const
Definition: insdel.cxx:97
static ARB_init_perl_interface init
Definition: ARB_ext.c:101
#define TEST_EXPECT_NO_ERROR(call)
Definition: test_unit.h:1107
GBDATA * GB_find_string(GBDATA *gbd, const char *key, const char *str, GB_CASE case_sens, GB_SEARCH_TYPE gbs)
Definition: adquery.cxx:302
SequenceAliData(const char *static_data, size_t elements, char stdgap, char dotgap, const SizeAwarable &sizeAware, const Deletable &deletable_)
Definition: insdel.cxx:570
int operate_on_mem(void *mem, size_t start, size_t count, memop op) const OVERRIDE
Definition: insdel.cxx:193
GB_ERROR GB_write_floats(GBDATA *gbd, const float *f, long size)
Definition: arbdb.cxx:1431
#define NULp
Definition: cxxforward.h:97
virtual UnitPtr unit_left_of(size_t pos) const =0
GB_CSTR GB_read_bits_pntr(GBDATA *gbd, char c_0, char c_1)
Definition: arbdb.cxx:896
GBDATA * GBT_find_species(GBDATA *gb_main, const char *name)
Definition: aditem.cxx:136
virtual AliDataPtr create_gap(size_t gapsize, const UnitPair &gapinfo) const =0
Alignment(const char *name_, size_t len_)
Definition: insdel.cxx:917
#define __ATTR__NORETURN
Definition: attributes.h:56
#define __ATTR__REDUCED_OPTIMIZE__NO_GCSE
Definition: test_unit.h:88
int cmp_data(size_t start, const AliData &other, size_t ostart, size_t count) const OVERRIDE
Definition: insdel.cxx:277
virtual UnitPtr unit_right_of(size_t pos) const =0
#define offset(field)
Definition: GLwDrawA.c:73
void set_error(GB_ERROR error) const
Definition: insdel.cxx:83
GB_TYPES
Definition: arbdb.h:62
Definition: trnsprob.h:20
GBDATA * GB_nextChild(GBDATA *child)
Definition: adquery.cxx:326
void copyPartTo(void *mem, size_t start, size_t count) const
Definition: insdel.cxx:92
GB_CFLOAT * GB_read_floats_pntr(GBDATA *gbd)
Definition: arbdb.cxx:989
bool has_slice() const OVERRIDE
Definition: insdel.cxx:185
GB_transaction ta(gb_var)
AliDataPtr create_gap(size_t gapsize, const UnitPair &gapinfo) const OVERRIDE
Definition: insdel.cxx:1224
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
Definition: arbdb.cxx:874
GBDATA * gb_main
Definition: adname.cxx:33
AliDataPtr apply(AliDataPtr to, GB_ERROR &error) const OVERRIDE
Definition: insdel.cxx:1052
Definition: arbdb.h:71
static const T * typed_ptr(const UnitPtr &uptr)
Definition: insdel.cxx:375
GB_ERROR GBT_check_data(GBDATA *Main, const char *alignment_name)
Definition: adali.cxx:217
GBDATA * GBT_get_presets(GBDATA *gb_main)
Definition: adali.cxx:29
UnitPtr(const void *ptr_)
Definition: insdel.cxx:36
GB_ERROR apply(const AliEditCommand &cmd, bool &did_modify)
Definition: insdel.cxx:1330
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
range_set::const_reverse_iterator reverse_iterator
Definition: RangeList.h:47
GB_CSTR GBT_get_name_or_description(GBDATA *gb_item)
Definition: aditem.cxx:437
virtual int cmp_data(size_t start, const AliData &other, size_t ostart, size_t count) const =0
virtual ~AliData()
Definition: insdel.cxx:71
GB_ERROR check_applicable_to(const Alignment &ali, size_t &resulting_ali_length) const OVERRIDE
Definition: insdel.cxx:1112
const unsigned int GB_CUINT4
Definition: arbdb_base.h:40
#define min(a, b)
Definition: f2c.h:153
bool has_slice() const OVERRIDE
Definition: insdel.cxx:233
AliDataPtr makeAliSeqData(char *&allocated_data, size_t elems, char gap, char dot)
Definition: insdel.cxx:631
const char * GB_CSTR
Definition: arbdb_base.h:25
AliInsertCommand(size_t pos_, size_t amount_)
Definition: insdel.cxx:1031
size_t unitsize() const OVERRIDE
Definition: insdel.cxx:232
AliEditor(const AliEditCommand &cmd_, const Deletable &deletable_, const char *progress_title, size_t progress_count)
Definition: insdel.cxx:1144
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1283
GB_ERROR mid(GBL_command_arguments *args, int start_index)
Definition: adlang1.cxx:906
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
bool is_valid_between(size_t pos) const
Definition: insdel.cxx:133
GB_ERROR check_applicable_to(const Alignment &ali, size_t &resulting_ali_length) const OVERRIDE
Definition: insdel.cxx:1092
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:625
static Score ** U
Definition: align.cxx:67
Deletable(DeleteWhat what)
Definition: insdel.cxx:342
SizeAwarable dontAllowOversize(size_t ali_size)
Definition: insdel.cxx:471
size_t unitsize() const OVERRIDE
Definition: insdel.cxx:184
AliDataPtr makeAliData(T *&allocated_data, size_t elems, const T &gap)
Definition: insdel.cxx:628
GB_write_int const char s
Definition: AW_awar.cxx:156