static struct cl_attr * new_cl_attr(char *cl_name) { struct cl_attr *class, **class_ptr; if (cl_handle == -1) { cl_handle = ar_create(MALSIZ, sizeof (struct cl_attr), "package class"); if (cl_handle == -1) { progerr(gettext(ERR_MEMORY)); return (NULL); } } class_ptr = (struct cl_attr **)ar_next_avail(cl_handle); if (class_ptr == NULL || *class_ptr == NULL) { progerr(gettext(ERR_MEMORY)); return (NULL); } class = *class_ptr; strcpy(class->name, cl_name); class->inst_script = NULL; class->rem_script = NULL; class->src_verify = s_verify(cl_name); class->dst_verify = d_verify(cl_name); class->relpath_2_CAS = s_pathtype(cl_name); return (class); }
/* protected slot */ void int_range_steps_holder:: before_dtor( QObject * p_attached_object_about_to_be_destroyed) { QWidget * const p_attached_widget_about_to_be_destroyed = qobject_cast< QWidget * >( p_attached_object_about_to_be_destroyed); d_assert( p_attached_widget_about_to_be_destroyed); d_verify( 1 == attached_widgets_.removeAll( p_attached_widget_about_to_be_destroyed)); }
void int_range_steps_holder:: detach( QAbstractSlider * p_slider) { d_assert( p_slider); d_assert( is_valid( )); d_assert( attached_widgets_.contains( p_slider)); d_verify( disconnect( p_slider, SIGNAL( valueChanged( int)), this, SLOT( set_value( int)))); d_verify( disconnect( p_slider, SIGNAL( destroyed( QObject *)), this, SLOT( before_dtor( QObject *)))); d_verify( 1 == attached_widgets_.removeAll( p_slider)); d_assert( ! attached_widgets_.contains( p_slider)); d_assert( is_valid( )); }
/* ctor */ double_slide_holder:: double_slide_holder ( QObject * p_parent , value_type outer_init // = 0.0 , value_type outer_lo // = -1.0 , value_type outer_hi // = +1.0 ) : holder_base_type( p_parent) , p_inner_holder_ ( 0) , outer_lo_ ( 0) , inner_to_outer_ ( 0) , outer_to_inner_ ( 0) { setup_conversions( outer_lo, outer_hi); // Now that conversions are set up, create the inner holder. // Should we use the global lo/hi limits, or the calculated limits? We'll use the // calculated limits for now. p_inner_holder_ = new inner_holder_type ( this , convert_outer_to_inner( outer_init) , convert_outer_to_inner( outer_lo) , convert_outer_to_inner( outer_hi) ); d_assert( p_inner_holder_); // Relay all the signals from the inner holder. d_verify( connect( p_inner_holder_, SIGNAL( has_changed( )), this, SLOT( intercept__has_changed( )) )); d_verify( connect( p_inner_holder_, SIGNAL( has_changed( int)), this, SLOT( intercept__has_changed( int)) )); d_verify( connect( p_inner_holder_, SIGNAL( has_changed__range( int, int)), this, SLOT( intercept__has_changed__range( int, int)) )); d_verify( connect( p_inner_holder_, SIGNAL( has_changed__steps( int, int)), this, SLOT( intercept__has_changed__steps( int, int)) )); // Should always be true when outside class methods. d_assert( is_valid( )); }
void solver_type:: fix_severely_out_of_bounds_sheet( sheet_type & trg_sheet) // // This is like a sheet-transforming functor, and should probably be integrated into // the solvers so it can calculate off-thread (and maybe even in parallel). { // We need a way to do this in a worker thread (and ideally parallel) without // incrementing the generation count. So this either needs to be integrated into // the solvers, or we need to have a general way to queue worker-thread instructions. value_type const normal_min = -1; value_type const normal_max = +1; value_type const normal_mid = 0; // We don't flatten the sheet unless it gets out of this range (except in the // special case where the sheet is completely flat): value_type const out_of_bounds_min = -100; value_type const out_of_bounds_max = +100; // After we're done none of the sheet values should be outside this range: value_type const back_in_bounds_min = -50; value_type const back_in_bounds_max = +50; value_type min_value = 0; value_type max_value = 0; d_verify( trg_sheet.get_min_max_values( min_value, max_value)); d_assert( min_value <= max_value); // If the sheet is flat .. if ( min_value == max_value ) { // If the flat value is outside the normal range .. if ( (min_value < normal_min) || (max_value > normal_max) ) { trg_sheet.fill_sheet( normal_mid); } } else if ( min_value < out_of_bounds_min ) { trg_sheet.normalize( back_in_bounds_min, std::max( normal_mid, std::min( back_in_bounds_max, max_value))); } else if ( max_value > out_of_bounds_max ) { trg_sheet.normalize( std::min( normal_mid, std::max( back_in_bounds_min, min_value)), back_in_bounds_max); } }
/* * Create a list of all classes involved in this installation as well as * their attributes. */ int setlist(struct cl_attr ***plist, char *slist) { struct cl_attr **list, *struct_ptr; char *pt; int n; int i; int sn = -1; /* Initialize the environment scanners. */ (void) s_verify(NULL); (void) d_verify(NULL); (void) s_pathtype(NULL); n = 0; /* * This looks like a serious memory leak, however pkgmk depends on * this creating a second list and forgetting any prior ones. The * pkgmk utility does a reasonable job of keeping track of a prior * list constructed from the prototype file using addlist() above. * Perhaps this should be reviewed later, but I do not believe this * to be a problem from what I've seen. - JST */ cl_handle = -1; /* forget other lists */ /* Isolate the first token. */ pt = strtok(slist, " \t\n"); while (pt) { if (sn == -1 && strcmp(pt, "none") == 0) sn = n; /* Add new class to list. */ if ((struct_ptr = new_cl_attr(pt)) == NULL) quit(99); /* Next token. */ n++; pt = strtok(NULL, " \t\n"); if (pt && sn != -1) if (strcmp(pt, "none") == 0) pt = strtok(NULL, " \t\n"); } /* * According to the ABI, if there is a class "none", it will be * the first class to be installed. This insures that iff there * is a class "none", it will be the first to be installed. * If there is no class "none", nothing happens! */ new_order = 0; /* Get the head of the array. */ list = (struct cl_attr **)ar_get_head(cl_handle); if (sn > 0) { struct_ptr = list[sn]; for (i = sn; i > 0; i--) list[i] = list[i - 1]; list[0] = struct_ptr; new_order++; /* the order is different now */ } /* Point the passed pointer to the head of the list. */ *plist = list; return (n); }
/* main method */ void solver_type:: calc_next ( input_params_type const & input_params , sheet_params_type const & sheet_params ) // Instead of dealing with sheet_type this could start with these src/trg objects: // stride_range< src_iter_type, 1 > src_range // stride_range< trg_iter_type, 1 > trg_range // See swap_xy( range_xy) -> range_yx { // Initialize the output params. We will set them as we go along. output_params_.reset( ); sheet_type const & src_sheet = sheet_params.ref_src_sheet( ); sheet_type & trg_sheet = sheet_params.ref_trg_sheet( ); sheet_type & extra_sheet = sheet_params.ref_extra_sheet( ); // Interpret input_params and sheet_params as intuitive choices. bool const is_multi_pass = input_params.has_extra_passes( ) && ! input_params.are_extra_passes_disabled( ); bool const is_one_pass = ! is_multi_pass; bool const is_in_place_requested = sheet_params.are_src_trg_sheets_same( ); bool const is_in_place_possible = input_params.is_technique__ortho_interleave( ); bool const is_extra_pre_sized = sheet_params.is_extra_sheet_sized( ); bool const is_history_vital = input_params.is_saving_history_worth_sizing_extra( ); bool const is_history_nice = is_history_vital || input_params.is_saving_history_worth_extra_copy( ); bool const is_extra_vital_for_solve = is_multi_pass && ! is_in_place_possible; /* or is_in_place_requested and not possible */ bool const is_extra_vital_for_history = is_multi_pass || is_in_place_requested; bool const is_extra_vital = is_extra_vital_for_solve || (is_history_vital && is_extra_vital_for_history); bool const is_extra_nice = is_extra_vital || (is_history_nice && is_extra_vital_for_history); bool const is_extra_used = is_extra_vital || (is_extra_nice && is_extra_pre_sized); // The two sheets must be different (unless technique == e_ortho_interleave). // We could make in_place work for e_simultaneous_2d too (but not for e_wave_with_damping) // by using extra_sheet like this (one pass): // copy src -> extra // solve extra -> trg // For two passes: // solve src -> extra // solve extra -> trg // Three passes: // copy src -> extra // solve extra -> trg // solve trg -> extra // solve extra -> trg // In this scenario, extra_sheet always ends up with history. d_assert( implies( is_in_place_requested, is_in_place_possible)); if ( is_extra_vital && ! is_extra_pre_sized ) { // We need an extra trg sheet. Make sure it's properly sized. d_verify( sheet_params.maybe_size_extra_sheet( )); output_params_.set__was_extra_sized( ); } if ( is_extra_used ) { // Even if extra_sheet wasn't pre-sized, it's sized now. d_assert( sheet_params.is_extra_sheet_sized( )); output_params_.set__was_extra_used( ); } else if ( input_params.is_extra_sheet_to_be_reset_if_not_used( ) ) { extra_sheet.reset( ); } // If we are solving the wave equation using the extra sheet we have to set up history. // // We need the following assumtion because we are testing is_odd( extra_pass_count): // d_assert( extra_pass_count >= 0) // This is always true because size_type is unsigned. d_static_assert( boost::is_unsigned< size_type >::value); if ( is_multi_pass && input_params.is_technique__wave_with_damping( ) ) { d_assert( is_extra_used); if ( is_early_exit( ) ) return; // If we are wave solving we need to setup the extra sheet with values so we get // the history right. Remember with waves we have a kludge where trg_sheet also // holds the src-values from one generation back. if ( util::is_odd( input_params.get_extra_pass_count( )) ) { // If extra_pass_count is odd the solves will look like: // src -> extra -- first set (extra <- trg) so history is right // extra -> trg -- first set (trg <- src) so history is right // trg -> extra -- ok // extra -> trg -- ok extra_sheet = trg_sheet; trg_sheet = src_sheet; } else { // If extra_pass_count is even (and not zero) the solves look like this: // src -> trg -- ok // trg -> extra -- first set (extra <- src) so history is right // extra -> trg -- ok // trg -> extra -- ok // extra -> trg -- ok extra_sheet = src_sheet; } } // Solve repeatedly if extra solve passes are requested. // Alternatively solve to trg_sheet and extra_sheet, assuming extra_sheet is available. sheet_type const * p_src_sheet = & src_sheet; for ( size_type countdown = is_multi_pass ? input_params.get_extra_pass_count( ) : 0 ; countdown > 0 ; -- countdown ) { if ( is_early_exit( ) ) return; output_params_.inc_solve_count( ); bool const is_this_pass_targeting_extra = is_extra_used && util::is_odd( countdown); sheet_type & trg_sheet_this_pass = is_this_pass_targeting_extra ? extra_sheet : trg_sheet; calc_next_pass ( input_params.get_technique( ) , input_params.get_method( ) , input_params.is_method_parallel( ) , input_params.get_damping( ) , input_params.get_rate_x( ) , input_params.get_rate_y( ) , *p_src_sheet , trg_sheet_this_pass ); p_src_sheet = & trg_sheet_this_pass; } // We're about to do the last solve. The 2nd-to-last solution is in *p_src_sheet, which is: // src_sheet if this is not just the last solve, but also the only solve. // extra_sheet if we were using extra_sheet in the loop above. // trg_sheet if in_place solving is possible and history is not required. if ( is_one_pass ) { d_assert( (& src_sheet) == p_src_sheet); if ( is_in_place_requested ) { // There is one unusual case where we have to copy src_sheet to preserve history. if ( is_history_nice && is_extra_used ) { if ( is_early_exit( ) ) return; extra_sheet = src_sheet; output_params_.set__is_last_solve_saved_in_extra( ); } else { /* we are doing one in-place solve */ /* history is not saved */ } } else { output_params_.set__is_last_solve_saved_in_src( ); } } else if ( is_extra_used ) { // Multi-pass and we had the extra sheet available. In that case we always solve into it. // In this case history is always returned in extra_sheet, even if not requested. d_assert( (& extra_sheet) == p_src_sheet); output_params_.set__is_last_solve_saved_in_extra( ); } else { // Multi-pass and we don't have extra_sheet. We must be solving in-place. d_assert( (& trg_sheet) == p_src_sheet); d_assert( is_in_place_possible); d_assert( ! is_history_vital); d_assert( ! (is_history_nice && is_extra_pre_sized)); /* history is not saved */ } // Do the last-pass solve. // For the last pass we always solve into the trg_sheet. if ( is_early_exit( ) ) return; output_params_.inc_solve_count( ); calc_next_pass ( input_params.get_technique( ) , input_params.get_method( ) , input_params.is_method_parallel( ) , input_params.get_damping( ) , input_params.get_rate_x( ) , input_params.get_rate_y( ) , *p_src_sheet , trg_sheet ); }
void control_type:: calc_next ( sheet_type const & src_sheet , sheet_type & trg_sheet , sheet_type & extra_sheet , bool are_extra_passes_disabled ) { // Runs in the master thread. // The worker thread may not even be created yet. d_assert( QThread::currentThread( ) != p_worker_); // We should not be processing this message after we have exited. if ( is_going_down( ) ) { d_assert( false); return; } // We will be busy until we process the "finish" message from the worker thread. d_assert( not_busy( )); is_busy_ = true; // If p_worker_ is zero then we still have to create the worker thread object. if ( 0 == p_worker_ ) { // Create the thread. // We give the worker-thread object no parent (zero pointer) so that signals sent between // the master and worker threads are queued instead of dispatched. // The ctor for the worker thread runs in the master thread, during creation below. // And that ctor starts the worker thread and waits for it to settle. p_worker_ = new worker_thread_type( 0); // Worker is now running. d_assert( p_worker_ && p_worker_->isRunning( )); // The parent serves these purposes: // It auto-deletes the object at the end of its life. // When you send a message to an object, Qt has to decide in which thread the message should run. // If the target object has a parent, we use that thread that owns the target object. // If the target object has no parent, we use p_trg->thread( ), which is initially the thread // where the target was created. But we set it below. // // Since we want messages to p_worker_ to process in that thread, we have to create p_worker_ with // no parent (or set it to zero later) and then set the thread. // // Instead of setting the thread, we could try setting the worker-thread object to be its own parent. // It'd look like this: // p_worker_->setParent( p_worker_); // This compiles and runs, tho it's not clear what it means for auto-delete. // And this doesn't work, even if you follow it with: // p_worker_->moveToThread( p_worker_); // The messages to p_worker_ still get dispatched in the master thread. // Right now worker_->thread( ) is this (master) thread. And the parent is not set. d_assert( p_worker_->thread( ) == QThread::currentThread( )); d_assert( p_worker_->parent( ) == 0); // Change the thread. You MUST do this from the thread that currently owns the object (this master thread). // This will let the signal/slot mechanism work across threads. p_worker_->moveToThread( p_worker_); // This does not set the parent, so auto-delete is disabled. The worker thread does not delete itself // after we call p_worker_->quit( ). d_assert( p_worker_->parent( ) == 0); // Now messages sent to p_worker_ from the master thread are queued and processed in the worker thread. // The worker thread is now awaiting instructions. // We use the following 2 async connections, plus ->quit( ), to control it. // This is a Qt::QueuedConnection. It is sent from the master and processed in the worker thread. // The target (p_worker_ in this case) determines where the message is processed. d_verify( connect( p_worker_, SIGNAL( start__master_to_worker( )), p_worker_, SLOT( run__in_worker_thread( ))) ); // This is a Qt::QueuedConnection. It is sent from the worker to the master thread. d_verify( connect( p_worker_, SIGNAL( finished__worker_to_master( double)), this, SLOT( finished__from_worker_thread( double))) ); }